feat(ui): single source of truth for design tokens (landing ↔ app sync)#208
Merged
Conversation
Landing and app design tokens were hand-duplicated copies that drifted: landing's --accent was the amber brand color while the app's is a neutral hover surface (breaking @maple/ui hover states on landing), --chart-4 was red vs teal, CTAs were hand-rolled, and react-flow controls chrome differed. - Move the full token system (light + dark + @theme mapping + react-flow controls) to packages/ui/src/styles/tokens.css; both apps import it and their duplicated blocks are deleted. App-local styles stay app-local. - Landing stays dark-only by pinning class="dark" on <html> (Layout.astro and DocsLayout.astro). - Swap landing's brand-amber `*-accent` utilities to `*-primary` (same rendered color, correct semantics; `accent` is now the neutral hover surface everywhere). Rename landing's caret keyframe to mcp-caret-blink to avoid colliding with the shared caret-blink. - Migrate hero/feature-hero/navbar CTAs to @maple/ui buttonVariants; the drenched-amber bookend CTA stays bespoke on purpose. - Add scripts/check-token-drift.ts (bun run check:tokens), wired into CI, failing if an app re-declares a shared token name. - Correct DESIGN.md: light primary is amber as shipped, and document the token source-of-truth rule. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
|
Your Pullfrog Router balance is exhausted. You have a card on file but auto-reload is disabled, so runs paused once your balance went past the overdraft buffer. Top up balance → · Enable auto-reload →
|
… sweep The first accent→primary sweep only matched simple utility prefixes, missing directional borders (border-l-accent) and raw var(--accent) references in scoped <style> blocks (the /local page components, docs index, ComparisonTable, TraceVisualization). Under the shared tokens these resolved to the neutral hover gray instead of brand amber. Swap them all to primary. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Its animation referenced the global caret-blink name, which after the token consolidation resolves to the shared @theme keyframe (eased 70/20 rhythm) instead of the removed 50/50 terminal blink. Define lph-caret-blink locally in the component's scoped style, mirroring how docs/index.astro handles it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Users flagged the landing app examples as feeling fake / not matching the app. Rebuilt the hero AppMock against screenshots of the live product so every view uses the app's actual chrome and semantics: - Sidebar mirrors the app: org switcher (avatar + Organization sublabel), real nav order and grouping (Overview/Services/Service Map · Traces/Logs/ Metrics/Replays/Infrastructure · Errors/Alerts), user footer. - Topbar with collapse toggle, per-tab breadcrumb (CSS :has()-driven), and the amber Connect button. - Page headers use the product pattern: display title + muted subtitle and outlined toolbar buttons (production selector, Last N hours, Reload). - Severity tokens replace raw palette colors everywhere: INFO is green (severity-info) not blue, status chips 200/500 use severity tokens, method chips are blue GET / amber POST like the trace list. - Services view rebuilt to the real table: amber names + namespace subline, P50/P95/P99, red error-rate sparklines, env group header chip, filter rail with counts. - Traces view: two-line root span (method chip + path + timestamp), service chips with +N, underlined amber trace IDs, real filter rail (Duration p50/p95, Has Error, Root Traces Only, Environment, Namespace), "Showing 100 traces" footer. - Logs view: search + severity-dot filters with counts, stacked info/warn/error histogram, chevron + dot + colored level rows. - Overview: All clear alert strip, Services/Healthy/Degraded/Unhealthy health band, uppercase stat cards with vs-prev deltas, chart legends. - Service map: COLOR BY / Re-sort canvas chips, zoom controls, edge label chips (~calls err%), ~-prefixed rates, brand-colored REDIS/POSTGRES badges, product footer (hints + service legend + health legend). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
At the mock's scaled-down size the "~calls err%" chips render oversized relative to the nodes and crowd the links; the graph reads better bare. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

Why
Users reported the landing page UI not matching the app. Root cause: the design tokens were hand-duplicated between
apps/web/src/styles.cssandapps/landing/src/styles/global.csswith no shared source, and the copies had drifted:--accenton landing was the amber brand color (byte-identical to--primary, a semantic mislabel) vs the app's neutral hover gray — this was actively rendering amber hover fills on the@maple/uicomponents landing embeds (navigation menu, command palette, sheet).--chart-4: red on landing vs teal in the app (landing's red collided with--destructive/--severity-error).buttonVariants.What changed
packages/ui/src/styles/tokens.cssholds the full token system (:rootlight +.darkdark +@theme inlinemapping + shared react-flow controls chrome). Both apps@import "@maple/ui/styles/tokens.css"(must come after@import "tailwindcss"); their duplicated blocks are deleted. App-local styles stay app-local (web's Sugar High/boot splash, landing's marketing tokens--bg-elevatedetc.).class="dark"on<html>inLayout.astroandDocsLayout.astro;dark:utilities in shared components now render correctly there.*-accentutility usages that meant "brand amber" swapped to*-primary— zero visual change (same oklch value), correct semantics. Landing's caret keyframe renamed tomcp-caret-blinkto avoid colliding with the sharedcaret-blinkfrom the@themeblock.Hero.astro,FeatureHero.astro, andNavBar.tsxCTAs now usebuttonVariantsfrom@maple/ui(cva class strings work in.astrofrontmatter). The drenched-amber bookend CTA inQuickstart.astrointentionally stays bespoke — its inverted colors sit on an amber surface.bun run check:tokens(scripts/check-token-drift.ts) fails if either app re-declares a shared token name; wired into the CI TypeScript job.oklch(0.66 0.16 59)), not the stale blue; added a "Token source of truth" section.Reviewer notes
@maple/uihover surfaces are now neutral instead of amber, and the trace mock'schart-4spans render teal (matching the product) instead of red. Everything else is value-identical.--destructive-foregroundalso moves to the app's definition (red-400in dark) — its old copy was stale.Verification
bun run check:tokenspasses; verified it fails on a deliberate re-declaration.turbo typecheck(web/ui + deps) passes; landing Astro build (95 pages) passes — it compiles the.astrofrontmatterbuttonVariantsimports and resolves the new CSS export.🤖 Generated with Claude Code