Skip to content

refactor(chrome): one SSOT per chrome shape — Panel, BottomNav, nav-state - #251

Closed
catomean wants to merge 1 commit into
mainfrom
refactor/chrome-ssot
Closed

refactor(chrome): one SSOT per chrome shape — Panel, BottomNav, nav-state#251
catomean wants to merge 1 commit into
mainfrom
refactor/chrome-ssot

Conversation

@catomean

Copy link
Copy Markdown
Collaborator

Why

Header, footer, nav bars, and panels were following ~30 different hand-rolled patterns — the "everything is all over the place, no SSOT" problem. This makes every one of them follow one design + one code pattern, so retheming or fixing chrome is a single edit, not a codebase sweep.

Three subagent audits mapped every divergence first (sidebars/nav, panels, headers/heroes); this PR establishes the missing primitives and migrates the highest-value, lowest-risk duplications. Net −174 lines.

New SSOT primitives

File What it is Kills
lib/design/nav.tsNAV_STATE + navLinkClass() THE definition of active/inactive per nav shape (sidebar / bottomTab / pill) ring-action/20 vs /30 vs inline bg-action-muted text-action vs border-action … — 5 encodings of "current page"
components/ui/Panel.tsx Titled card-shell surface (title / subtitle / icon / action header slot) hand-rolled bg-surface-base rounded-lg border p-5 + bespoke <h2> (7 copies, each drifting on radius/border/shadow)
components/layout/BottomNav.tsx The mobile bottom-tab bar (neutral home — dashboard can't import app/admin/*) two byte-identical bars differing only by an accidental z-40/z-50 + border/border-subtle

Consolidations

  • Hero: folded the redundant ResponsiveHero into PageHero (its 1 consumer migrated) and deleted it — removes its inline-style dot-pattern, from-black/50 gradient, and per-color text-color ladder. The page now matches the other 23 PageHero pages.
  • Panels → <Panel>: ResultsPanel, VotingPanel, TeamTasks/TeamProtocols, Contributions, Needs.
  • Sidebars → <Card>: RequestSidebar (5× card-shell p-6), TimecardHistorySidebar (manual rounded-xl border …).
  • Bottom navs → <BottomNav>: admin + dashboard bars; dashboard sheet pills → navLinkClass('pill').
  • AdminSidebar: 4×-repeated nav item → navLinkClass('sidebar'); Hirn active-state drift harmonized. adminInteractive.navActive now re-exports NAV_STATE.sidebar.active (value lives in one place).
  • NavItem: consumes designPrimitive.focus (dropped a divergent inline focus ring).
  • Fixed duplicate-class border border typos in Contributions/Needs panels.

Docs (the "reflect this in CLAUDE.md" ask)

Added a "Chrome & Navigation — one primitive per shape (SSOT)" section to CLAUDE.md (decision table: which primitive for which shape) + audit greps for hand-rolled card shells / nav-active drift / deprecated bg-opacity-*.

Verification

  • typecheck clean · lint 0 errors · test:i18n 16/16.
  • ResponsiveHeroPageHero migration visually confirmed in light + dark (screenshots in the chat).
  • Class-equivalence-by-construction for the panel/nav swaps; the auth-gated admin/dashboard surfaces get final visual confirmation on this branch's production deploy (a Turbopack dev-only CSS-order artifact made responsive-visibility unreliable locally — prod build orders correctly).

Deliberately deferred to a focused follow-up PR

Higher-risk / subtler, kept out to keep this reviewable:

  • A shared <Drawer>/<Sheet> primitive (MessageSidebar + MobileMenu + dashboard sheet, with focus-trap + scroll-lock) — also fixes MessageSidebar's deprecated bg-opacity-50.
  • Neutralize AdminSectionHeaderSectionHeader and migrate TimecardHeader / RequestHeader / DecisionHeaderCard onto it.
  • Split the 410-line DecisionHeaderCard god-component.
  • BlogNavigationClient inline style={{ backgroundColor }} → CSS var; mono-eyebrow token sweep (10+ files).
  • A CI grep-gate to enforce the chrome-SSOT rules (currently doc-only greps).

🤖 Generated with Claude Code

…ate)

Header/footer/nav/panels now follow one design + code pattern instead of
~30 hand-rolled variants. Establishes three primitives and migrates the
highest-value duplications onto them.

New SSOT primitives:
- lib/design/nav.ts — NAV_STATE + navLinkClass(): the ONE definition of
  active/inactive per nav shape (sidebar/bottomTab/pill). Kills the
  ring-action/20-vs-/30-vs-inline fragmentation. admin-ui.navActive
  re-exports from it.
- components/ui/Panel.tsx — titled card-shell surface (title/subtitle/
  icon/action header slot). Replaces hand-rolled
  "bg-surface-base rounded-lg border p-5" + bespoke <h2>.
- components/layout/BottomNav.tsx — the byte-identical admin+dashboard
  mobile tab bar, in a neutral home (dashboard can't import app/admin).

Consolidations:
- Fold redundant ResponsiveHero into PageHero (1 consumer migrated; drops
  its inline-style dot-pattern, from-black gradient, color-ladder). Deleted.
- 6 panels -> <Panel>; RequestSidebar/TimecardHistorySidebar -> <Card>.
- Both bottom navs -> <BottomNav>; dashboard sheet pills -> navLinkClass('pill').
- AdminSidebar: 4x-repeated item -> navLinkClass('sidebar'); harmonize Hirn drift.
- NavItem: consume designPrimitive.focus (drop divergent inline ring).
- Fix duplicate-class "border border" typos in Contributions/Needs panels.

Docs: CLAUDE.md "Chrome & Navigation SSOT" section + audit greps.

Net -174 lines. verify green (typecheck, lint 0 err, i18n 16/16). Hero
migration visually confirmed light+dark.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@catomean

Copy link
Copy Markdown
Collaborator Author

Shipped to main via fast-forward (rebased). Chrome SSOT (Panel/BottomNav/nav-state + hero unify) is live on prod.

@catomean catomean closed this Jul 28, 2026
@catomean
catomean deleted the refactor/chrome-ssot branch July 28, 2026 09:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant