diff --git a/README.md b/README.md index 717521e..c38be5d 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,36 @@ The browser only ever talks to this app. This app talks to Minnect server-side. That keeps your Minnect tokens off the browser entirely and avoids cross-origin restrictions. See `CLAUDE.md` and `docs/` (if present) for the design notes. +## Design system + +The redesign (obsidian, crimson, no gold) is specified in +[`docs/minnect-feed-redesign.spec.md`](docs/minnect-feed-redesign.spec.md). The +styling decisions are in +[`docs/adr/0001-redesign-styling-approach.md`](docs/adr/0001-redesign-styling-approach.md). +The handoff for the redesign is [`docs/handoff-redesign.md`](docs/handoff-redesign.md). + +- **Themes.** Dark is the default; light is a toggle. The choice is stored in + `localStorage` and applied by a small script in `src/app/layout.tsx` before + first paint (`src/lib/theme.ts`), so there is no flash. `src/lib/use-theme.ts` + is the hook the toggles use. +- **Tokens.** All colors are CSS custom properties in `src/app/globals.css`, one + set for dark and one for light. `--accent-text` is the readable crimson for + small text (4.5:1). Components use tokens only, never raw colors. +- **Stylesheets.** One file per component area in `src/styles/` (`buttons.css`, + `feed.css`, `post.css`, `mobile.css` and so on), loaded from `globals.css`. +- **Buttons.** Five styles plus a small icon button, all in + `src/components/Buttons.tsx`: Flip (the composer Post button), Grow (the + "new posts" pill), Sweep (outline actions: Try again, Cancel, expert search + chips), Depth (the Discover sheet rows), Sparkle (Sign in and the mobile dock + new-post button) and IconButton (refresh, comment send, delete confirm). Disabled buttons stay at full opacity. +- **Avatars.** `HexAvatar` (`src/components/HexAvatar.tsx`) is used for every + avatar: photo, or initials on a gradient, in a hexagon. +- **Breakpoints.** Container queries on the app root: 1181 and up (three + columns), 1001 to 1180 (narrower columns), 761 to 1000 (tablet), 760 and below + (full-screen snap feed with a bottom dock). +- **Dev previews.** `/dev/feed` (fixture feed, no login) and `/dev/buttons` (every + button style in both themes). Both return 404 in production builds. + ## Requirements - Node.js 20 or newer (built and tested on Node 22). diff --git a/docs/handoff-redesign.md b/docs/handoff-redesign.md new file mode 100644 index 0000000..03a85b7 --- /dev/null +++ b/docs/handoff-redesign.md @@ -0,0 +1,50 @@ +# Redesign handoff + +The Feed browser redesign (luxury business look, dark default plus light, desktop +bento layout, mobile immersive feed). Spec: `docs/minnect-feed-redesign.spec.md`. +Styling decisions: `docs/adr/0001-redesign-styling-approach.md`. CRM project +Minnect, module 2. + +## What shipped, per milestone + +All four build milestones are merged into `develop` with merge commits. + +| Milestone | PR | Merge commit | Shipped | +|---|---|---|---| +| Redesign mobilization | #1 | c0f4260 | Spec and original contract in the repo; styling ADR; formatting decision (no bold or italic, bullets insert a bullet character) | +| Redesign foundation | #2 | 9aeb9a3 | Dark and light tokens with persisted toggle; Manrope and Cormorant Garamond; HexAvatar; five button styles; sign-in screen | +| Desktop bento layout | #3 | 25fd360 | Viewport-fit grid where only the feed scrolls; post cards; composer; new-posts pill and motion; featured carousel; Trending and Find experts; tablet layout; refresh button | +| Mobile immersive feed | #4 | f3fd4b5 | Snap feed; sideways media swipe; double-tap like; featured slide; bottom dock; comments and composer sheets; Discover sheet; top bar and progress rail | +| Redesign finalization | #5 | pending | Acceptance pass, contrast and hover fixes, `legacy.css` removed, README and this handoff. The orchestrator merges it. | + +Promotion of `develop` to `main` is Cesar's. + +## Known gaps + +- The upload progress bar is an animated sweep, not real progress. Real progress + needs upload events from the proxy. New scope (change request), not built. +- NEEDS CESAR (from the acceptance pass, task 99puxwol5): + 1. Acceptance 2 with a real account, dark and light, at 1440, 1024, 820 and 390px: + reading and paging, like and unlike, comments, posting text, image and video, + deleting your own post, expert search and categories, featured experts, + trending playback. + 2. With real photos, check the 3-photo stack in mobile More. + 3. On a real phone (iOS Safari and Android Chrome): vertical swipe snaps one + post, sideways swipe moves the dots, a playing video pauses on swipe-away, + double-tap likes with the burst, the featured carousel rotates again after + a tap elsewhere. + 4. Lighthouse Accessibility on the feed, both themes, desktop and mobile; note + any contrast item below 4.5:1. + +## Run and verify + +```bash +npm install +npm run dev # http://localhost:3000, sign in with a Minnect account +npm run typecheck && npx eslint --no-eslintrc -c .eslintrc.json src tests +npm test && npm run build +``` + +Without an account: open `/dev/feed` (fixture feed) and `/dev/buttons` (button +styles). Use browser device mode at 1440, 1024, 820 and 390px and toggle the +theme. These routes 404 in production. diff --git a/src/app/globals.css b/src/app/globals.css index bbc11b1..f3c5b0f 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -16,6 +16,8 @@ --ink-2: #BFBDB8; --ink-3: #95938E; --accent: #C8141C; + /* Crimson for small text (like counts): plain crimson is 3.2:1 on the dark tiles. */ + --accent-text: color-mix(in srgb, #C8141C, white 40%); --danger: #FF6B70; --glass: rgba(18,18,21,.72); --shadow-pop: 0 10px 28px rgba(0,0,0,.5); @@ -41,6 +43,7 @@ --ink-2: #46484D; --ink-3: #686A70; --accent: #C8141C; + --accent-text: #C8141C; --danger: #B3121A; --glass: rgba(251,250,248,.74); --shadow-pop: 0 10px 28px rgba(26,28,31,.14); @@ -91,6 +94,8 @@ @layer reset { *, *::before, *::after { box-sizing: border-box; } body { margin: 0; } + /* Form controls take the page font instead of the UA's 13.33px Arial. */ + button, input, textarea, select { font: inherit; } } @layer base { diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 1d69a50..d1d6c4a 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -16,7 +16,6 @@ import "../styles/trending.css"; import "../styles/search.css"; import "../styles/mobile.css"; import "../styles/sheet.css"; -import "../styles/legacy.css"; const manrope = Manrope({ subsets: ["latin"], diff --git a/src/components/Composer.tsx b/src/components/Composer.tsx index ba84a0b..4f71b45 100644 --- a/src/components/Composer.tsx +++ b/src/components/Composer.tsx @@ -210,7 +210,7 @@ export function Composer({ value, busy, error, file = null, onChange, onFile, on ) : null} {error ? ( -
Publishing the post failed. Your text is still here.
+Publishing the post failed. Your text is still here.
) : null}The feed did not load.
- +The feed did not load.
- +