You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Make the landing experience Today-first: / shows today's macro summary (the stat panel pattern from /today), a quick-log path, and the halls (as the route into menus) — the halls list stops being the whole home page. Concretely:
/ becomes a dashboard: macros-so-far stats at top (device-local data, works signed-out), then the four halls as compact cards (keep favorite stars + their text-content contract — several specs read state from star text), then quick links to Rank/Favorites.
/today remains the full detail view (log entries, split bar, exports) — the home stats deep-link to it.
Navigation copy/order reflects the identity: Today's macros is primary, not one button among ten.
Constraints
Reuse the landed component classes and the /today stat markup patterns — no new CSS in app.css unless a genuinely new component is needed (then document it in the same comment style).
vertical-slice.spec.ts, favorites.spec.ts, shell.spec.ts, halls-menu.spec.ts navigate from / — update them coherently, never weaken assertions to make them pass; every changed spec needs fresh red evidence (mutation or write-first).
Data residency: all macro data on this page is device-local; zero new server calls.
Red-green TDD with pasted red evidence; PORT-isolated Playwright runs.
Acceptance criteria
/ renders macro stats from today's device-local log (empty state when nothing logged), halls reachable in one tap, favorite-star contract intact
New/updated specs each have documented red evidence
Full Playwright suite green, pnpm --filter web check clean, build clean, CI green
Implemented on branch ux/today-first-home, PR #69 (not merged — leaving for review).
Per-criterion results
/ renders macro stats from today's device-local log (empty state when nothing logged), halls reachable in one tap, favorite-star contract intact — DONE.
web/src/routes/+page.svelte reads today's entries via IndexedDbLogStorage.getEntriesForDate + computeDailyTotals (same as /today), renders the shared MacroStats component, or an .empty-state block ("Nothing logged yet today.") when entries.length === 0.
Halls render as the same <li class="card"> / favorite <button aria-label="favorite">★|☆</button> / <a href="/halls/{slug}"> markup as before — verbatim, unmoved except into a new <section>. aria-pressed and the ★/☆ text contract are untouched.
Zero new server calls: DINING_HALLS is a static array (no fetch), the macro read is IndexedDB-only. Covered by a dedicated test (home-dashboard.spec.ts) that asserts zero **/api/** requests fire on /.
New/updated specs each have documented red evidence — DONE, see below.
Full Playwright suite green, pnpm --filter web check clean, build clean, CI green — DONE (CI itself not observable from here; local lanes all green, see Verification).
Red evidence (before implementation)
PORT=4305 npx playwright test run with the specs written/modified but the app code unchanged — 5 failures, all expected:
1) home-dashboard.spec.ts › home shows an empty state when nothing is logged today...
Error: expect(locator).toBeVisible() failed
Locator: getByText('Nothing logged yet today.')
Error: element(s) not found
2) home-dashboard.spec.ts › logging a dish updates today's macro stats on the home dashboard itself
Error: expect(locator).toBeVisible() failed
Locator: getByText('Calories: 127')
Error: element(s) not found
3) shell.spec.ts › Today's macros precedes the Dining Halls home link in primary nav
Error: expect(received).toBeLessThan(expected)
Expected: < 0
Received: 1
4) vertical-slice.spec.ts › browse a hall's menu, log a dish, and see it reflected in today's macro totals
Error: expect(locator).toBeVisible() failed
Locator: getByText('Calories: 127')
Error: element(s) not found
5) home-dashboard.spec.ts › quick links reach Rank and Favorites without ambiguity against the primary nav
Test timeout of 30000ms exceeded.
waiting for getByRole('link', { name: 'Compare dishes' })
26 passed, 5 failed
(The 4th home-dashboard.spec.ts test — zero API requests — passed even pre-implementation, since the old home page also made no server calls; that's expected, not a gap.)
Green evidence (after implementation)
Running 31 tests using 4 workers
...
31 passed (19.0s)
Mutation evidence for the two modified pre-existing specs
shell.spec.ts nav-order assertion: reverted +layout.svelte's reorder (git stash on just that file) and re-ran the new test alone → red with the exact same "Expected: < 0, Received: 1" failure as the original red run. Restored, re-ran → green.
vertical-slice.spec.ts strengthened assertion: temporarily set style="display: none" on the home dashboard's macro-stats wrapper and re-ran → red:
pnpm --filter web build — clean (adapter-auto's "could not detect a production environment" notice is pre-existing/benign, unrelated to this change).
Notes for reviewers
favorites.spec.ts and halls-menu.spec.ts needed zero changes — deliberately, not an oversight. They depend only on the hall <li>/star/link markup, which was preserved verbatim just moved under a new <section>. Confirmed still green in the full run above.
Extracted web/src/lib/macroShares.ts (pure macroCalorieBreakdown) and web/src/lib/MacroStats.svelte (the 4-up stat grid, no card wrapper, no split bar) out of /today so / and /today share the same computation/markup instead of duplicating it — the "extraction to a shared $lib module" the issue flagged as in-scope if needed. /today's own split bar and card wrapper stayed put; ran today.spec.ts alone right after the extraction to prove it was behavior-neutral before touching anything else.
Quick-link labels are "Compare dishes" (→ /rank) and "Favorite dishes" (→ /favorites) rather than the nav's own "Rank dishes" / "Favorites" — chosen specifically to avoid Playwright's case-insensitive substring getByRole matching turning into a strict-mode ambiguity against the primary nav, which is always present in the DOM alongside these. Covered by home-dashboard.spec.ts's "quick links reach Rank and Favorites without ambiguity" test.
No new app.css classes — reused .card, .stat, .empty-state, .page-title, .section-title, .label-rule, .btn/.btn-secondary throughout.
Activity
TSVRN9 commentedon Aug 19, 2026
Implemented on branch
ux/today-first-home, PR #69 (not merged — leaving for review).Per-criterion results
/renders macro stats from today's device-local log (empty state when nothing logged), halls reachable in one tap, favorite-star contract intact — DONE.web/src/routes/+page.sveltereads today's entries viaIndexedDbLogStorage.getEntriesForDate+computeDailyTotals(same as/today), renders the sharedMacroStatscomponent, or an.empty-stateblock ("Nothing logged yet today.") whenentries.length === 0.<li class="card">/ favorite<button aria-label="favorite">★|☆</button>/<a href="/halls/{slug}">markup as before — verbatim, unmoved except into a new<section>.aria-pressedand the ★/☆ text contract are untouched.DINING_HALLSis a static array (no fetch), the macro read is IndexedDB-only. Covered by a dedicated test (home-dashboard.spec.ts) that asserts zero**/api/**requests fire on/.New/updated specs each have documented red evidence — DONE, see below.
Full Playwright suite green,
pnpm --filter web checkclean, build clean, CI green — DONE (CI itself not observable from here; local lanes all green, see Verification).Red evidence (before implementation)
PORT=4305 npx playwright testrun with the specs written/modified but the app code unchanged — 5 failures, all expected:(The 4th
home-dashboard.spec.tstest — zero API requests — passed even pre-implementation, since the old home page also made no server calls; that's expected, not a gap.)Green evidence (after implementation)
Mutation evidence for the two modified pre-existing specs
shell.spec.tsnav-order assertion: reverted+layout.svelte's reorder (git stashon just that file) and re-ran the new test alone → red with the exact same "Expected: < 0, Received: 1" failure as the original red run. Restored, re-ran → green.vertical-slice.spec.tsstrengthened assertion: temporarily setstyle="display: none"on the home dashboard's macro-stats wrapper and re-ran → red:Verification
PORT=4305 npx playwright test— 31/31 passed.pnpm --filter web check—COMPLETED 398 FILES 0 ERRORS 0 WARNINGS 0 FILES_WITH_PROBLEMS.pnpm --filter web build— clean (adapter-auto's "could not detect a production environment" notice is pre-existing/benign, unrelated to this change).Notes for reviewers
favorites.spec.tsandhalls-menu.spec.tsneeded zero changes — deliberately, not an oversight. They depend only on the hall<li>/star/link markup, which was preserved verbatim just moved under a new<section>. Confirmed still green in the full run above.web/src/lib/macroShares.ts(puremacroCalorieBreakdown) andweb/src/lib/MacroStats.svelte(the 4-up stat grid, no card wrapper, no split bar) out of/todayso/and/todayshare the same computation/markup instead of duplicating it — the "extraction to a shared $lib module" the issue flagged as in-scope if needed./today's own split bar and card wrapper stayed put; rantoday.spec.tsalone right after the extraction to prove it was behavior-neutral before touching anything else./rank) and "Favorite dishes" (→/favorites) rather than the nav's own "Rank dishes" / "Favorites" — chosen specifically to avoid Playwright's case-insensitive substringgetByRolematching turning into a strict-mode ambiguity against the primary nav, which is always present in the DOM alongside these. Covered byhome-dashboard.spec.ts's "quick links reach Rank and Favorites without ambiguity" test..card,.stat,.empty-state,.page-title,.section-title,.label-rule,.btn/.btn-secondarythroughout.mobile: port the design system + restyle all screens (#71)