Conversation
/dashboard sits behind auth against a hosted Supabase project, so a visual design review cannot reach it without creating an account or minting a session against production data. This renders the real dashboard against in-memory fixtures instead. Everything is gated behind NEXT_PUBLIC_QA_MOCK=1 and inert by default: - src/lib/trpc/qa-mock.ts: terminating tRPC link serving fixtures; ?qa=full|empty selects the scenario - src/lib/trpc/client.ts: swaps in the mock link when the flag is set - src/contexts/AuthContext.tsx: mounts a deterministic user when set - src/app/design-qa: renders DashboardShell against those fixtures - next.config.ts: X-Frame-Options SAMEORIGIN when the flag is set, so breakpoints can be measured in fixed-width iframes Note there is no auth bypass here. The proxy matcher only guards /dashboard/:path* and /auth/:path*, so a route outside those prefixes needs no change to auth at all; src/proxy.ts is untouched. With the flag off the route redirects to /, verified in a browser. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jSBatKis96LuECidvPYX3
The header wrapped its contents in max-w-xl (576px) while the body below used max-w-7xl (1280px). The two centred independently, so nothing lined up. Measured in the DOM at a 1440px viewport, before: header content 425 -> 1001 main column 89 -> 665 chat sidebar 689 -> 1069 page container 73 -> 1353 The logo sat 352px right of the first card, and 284px of container was dead space on the right — the header drifting one way while the content drifted the other. After: both offsets measure 0. The surface moves into DashboardShell so /dashboard and the design-QA route render one definition, and the width is declared once as a constant used by both the header and the content wrapper. The bug class here was two places independently declaring the page width, so the fix is to have only one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jSBatKis96LuECidvPYX3
--gp-bg and --gp-surface were both #ffffff, so the page and every card rendered the same colour and surfaces were distinguishable only by a 1px zinc-200 hairline. The light theme read as one flat sheet. design-system-foundation §1.4 specifies page = zinc-50, card = white. The card token was already correct; only the page token was wrong. This is user-reachable, not theoretical — settings ships a theme toggle. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jSBatKis96LuECidvPYX3
Today's progress hardcoded text-green-400 regardless of value, so a brand new user saw "0/0 done" in success green sitting beside a red score ring and a red SLACKING label — three contradictory signals in one card. A user at 1/3 got the same green. For a product built on adversarial honesty, green has to be earned. Implements the rules already specified in design-system-phase-3: - §2.4 progress colour: zero is neutral, partial is warming, only a full sweep is locked-green. Same rule applied to the weekly roast's completion rate, which had the identical problem. - §2.2 bad-week copy: a drop of 20+ now reads "Last week was a write-off. New week starts now." instead of quoting a bare red number back at someone. A small dip is still a number. - §2.3 zero streak: the numeral drops to muted rather than tier-red, and the caption becomes "Start one today". A zero streak is the absence of a result, not a result worth colouring. Also moves the delta and severity colours onto the success/error/tier tokens per §1, and pads the widget to p-5 as a featured card per foundation §3. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jSBatKis96LuECidvPYX3
The coach panel greeted an empty conversation with one generic sentence, which on desktop left the largest uninterrupted region of the dashboard (~700px) doing nothing. On a product whose differentiator is the AI coach, the coach's own panel was the emptiest thing on screen. Implements design-system-phase-3 §6.1: prompts are built from the user's real score, tier, streak, today's progress and goal count, then rendered as tappable chips. The branch set is deliberately exhaustive rather than edge-case only — a steady mid-week user gets "1/3 done today — what do I take next?" rather than falling through to the generic prompts. Fallbacks remain so the panel always has something to press, including before data loads. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jSBatKis96LuECidvPYX3
Focus states: ui/button and ui/input both carry focus-visible treatments, but hand-rolled buttons bypassed them — including the task complete/skip checkbox, which is the app's core action. A keyboard user could not see what was focused. The shared ring pattern is now applied to the checkbox, the per-task menu trigger, and the evening check-in's Done/Skipped, and the menu trigger gains an aria-label. Done vs Skipped were pixel-identical until clicked. Each now previews its own outcome on hover and focus, so the choice reads before it is made, without weighting one answer above the other. Task rows stated priority twice — a colour strip and a colour-coded badge. The badge is gone; the strip carries it, with an sr-only label so priority is not conveyed by colour alone. The due date is gone too: the Today view is by definition today, and the Week view already groups rows under day headers, so it was five identical stamps carrying no information. StoicQuote picks up the rest of phase-3 §3.2 — border-l-2 and the "Today's Reminder" wording. Its amber gradient wash is removed: it was decorative depth the surface language (foundation §5) has no slot for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jSBatKis96LuECidvPYX3
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The semantic tokens are dark-first at :root, but Tailwind's dark variant was gated on prefers-color-scheme. Those two disagreed for anyone on an OS set to light who had not picked a theme: the page rendered dark from the tokens while every `dark:` utility stayed switched off. The wordmark resolved to zinc-900 on a zinc-950 background and disappeared. Verified with the OS in light mode and no stored theme: before page rgb(9,9,11) logo oklch(0.21…) invisible after page rgb(9,9,11) logo oklch(0.985…) visible The variant now keys off "not explicitly light" rather than "OS is dark", which is what dark-first means. Two follow-ons: - The light opt-in has three spellings (.light, .gp-allow-light, [data-theme="light"]) and only .light was excluded before, so the other two would have rendered light tokens with dark utilities on an OS-dark machine. All three now disable the variant. - :root gains color-scheme: dark so scrollbars, form controls and autofill match the dark surface by default. .light still overrides it. Marketing and auth are unaffected — they force .marketing-dark, which the first branch of the variant already matched. Checked across all five theme states (unclassed, .dark, and each of the three light spellings) plus a marketing route: light mode is unchanged and the dashboard alignment and progress-colour fixes still measure as before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jSBatKis96LuECidvPYX3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the fixes from a design QA audit of
/dashboard, plus items that were specified indocs/design-system-phase-3.mdbut never built.Why
The dashboard's content is strong — hysteresis tiers, a roast that names the real failure pattern, an evening reality check. The shell was undercutting it: the page frame was misaligned, the light theme had no elevation, the largest region on desktop was empty, and on a common theme configuration the wordmark was invisible.
Measured before / after
Taken from the DOM at a 1440px viewport, not estimated from screenshots.
1/3 done0/0 done(new user)#ffffff#fafafa/#ffffff:focus-visible+ 3px ringoklch(0.21…)onrgb(9,9,11)— invisibleoklch(0.985…)— visibleWhat changed
Shell. The header wrapped its contents in
max-w-xlwhile the body usedmax-w-7xl; the two centred independently so nothing lined up. The surface moves intoDashboardShelland the width is declared once, used by both boxes — the bug class was two places independently declaring the page width.Signal honesty. Today's progress hardcoded
text-green-400regardless of value, so a new user saw0/0 donein success green beside a red ring and a red SLACKING label. Implements phase-3 §2.4 (progress colour), §2.2 (bad-week copy), §2.3 (zero-streak dampening), and moves one-off colours onto the status/tier tokens.Light mode.
--gp-bgand--gp-surfacewere both#ffffff, so cards were separated only by a hairline. Foundation §1.4 specifies page =zinc-50. User-reachable — settings ships a theme toggle.Dark variant vs tokens. The semantic tokens are dark-first at
:root, but Tailwind'sdark:variant was gated onprefers-color-scheme. The two disagreed for anyone on an OS set to light who hadn't picked a theme: the page rendered dark from the tokens while everydark:utility stayed off, so the wordmark resolved tozinc-900onzinc-950and disappeared. The variant now keys off "not explicitly light", which is what dark-first means. Two follow-ons came with it — the light opt-in has three spellings and only.lightwas excluded before, and:rootnow declarescolor-scheme: darkso native chrome matches the surface.Chat sidebar. ~700px of empty space held one generic sentence. Implements phase-3 §6.1: prompts built from real score, streak, progress and goal count. Branches are exhaustive rather than edge-case only, so a steady mid-week user gets
1/3 done today — what do I take next?instead of a fallback.Polish. Focus rings on the hand-rolled buttons that bypassed
ui/button's treatment (including the task checkbox — the core action). Done/Skipped now preview their outcome on hover instead of being pixel-identical. Priority stated once, not twice. Redundant per-row dates removed.Verification
Tab, not programmatic focus.dark, and each of the three light spellings — plus a marketing route, with the OS in light mode (the configuration that exposed the bug). Light mode unchanged; marketing unaffected because it forces.marketing-dark, which the variant's first branch already matched.tsc --noEmitclean · 298/298 tests pass · production build succeedsmainand outside the changed hunksNotes for review
dark:variant change is the one with reach beyond the dashboard: ~90dark:usages across 12 files. Most sit on marketing legal pages that were already correct via.marketing-dark; the ones this actually changes are settings, stats, offline and the sharedui/*primitives — i.e. the authenticated app. Worth a look on those surfaces.chore(qa)adds an env-gated fixture harness at/design-qaso this surface can be reviewed without a Supabase session. It is inert unlessNEXT_PUBLIC_QA_MOCK=1, and contains no auth bypass — the proxy matcher only covers/dashboard/:path*and/auth/:path*, sosrc/proxy.tsis untouched. Happy to drop this commit if you'd rather not carry it.🤖 Generated with Claude Code
https://claude.ai/code/session_015jSBatKis96LuECidvPYX3