From 609594dba46dd51e9ccd2af12779af64c0c7e989 Mon Sep 17 00:00:00 2001 From: Makisuo Date: Tue, 14 Jul 2026 18:22:38 +0200 Subject: [PATCH 1/5] =?UTF-8?q?feat(ui):=20single=20source=20of=20truth=20?= =?UTF-8?q?for=20design=20tokens=20(landing=20=E2=86=94=20app=20sync)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 (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 --- .github/workflows/ci.yml | 4 + DESIGN.md | 12 +- apps/landing/src/components/AppMock.astro | 60 ++-- .../src/components/ComparisonTable.astro | 6 +- apps/landing/src/components/FAQ.astro | 2 +- apps/landing/src/components/FeatureHero.astro | 7 +- apps/landing/src/components/Hero.astro | 5 +- .../src/components/LanguageSwitcher.astro | 2 +- .../src/components/MigrationSteps.astro | 4 +- apps/landing/src/components/NavBar.tsx | 26 +- apps/landing/src/components/PainPoints.astro | 4 +- .../components/PricingCalculatorSection.astro | 2 +- .../landing/src/components/PricingTable.astro | 4 +- .../src/components/PrivacyContent.astro | 2 +- .../src/components/QuickStartCode.astro | 6 +- .../src/components/RelatedComparisons.astro | 6 +- .../src/components/RelatedFeatures.astro | 6 +- .../src/components/RelatedIntegrations.astro | 6 +- .../landing/src/components/RoadmapBoard.astro | 4 +- apps/landing/src/components/StatsBanner.astro | 2 +- .../landing/src/components/TermsContent.astro | 2 +- .../src/components/TraceVisualization.tsx | 4 +- .../src/components/blog/PostCard.astro | 8 +- .../src/components/blog/PostCover.astro | 6 +- .../src/components/docs/AvailableSdks.astro | 4 +- .../src/components/docs/DocsCategoryNav.astro | 6 +- .../src/components/docs/DocsMobileNav.astro | 4 +- .../src/components/docs/DocsPrevNext.astro | 8 +- .../src/components/docs/DocsSidebar.astro | 8 +- .../src/components/docs/SdkSelector.astro | 6 +- apps/landing/src/layouts/DocsLayout.astro | 8 +- apps/landing/src/layouts/Layout.astro | 4 +- apps/landing/src/pages/404.astro | 2 +- ...best-open-source-observability-tools.astro | 18 +- apps/landing/src/pages/blog/[...slug].astro | 10 +- apps/landing/src/pages/blog/index.astro | 10 +- apps/landing/src/pages/compare/dash0.astro | 2 +- apps/landing/src/pages/compare/datadog.astro | 2 +- apps/landing/src/pages/compare/grafana.astro | 2 +- .../landing/src/pages/compare/new-relic.astro | 2 +- apps/landing/src/pages/docs/index.astro | 2 +- .../pages/features/ai-mcp-integration.astro | 18 +- .../src/pages/integrations/nextjs.astro | 12 +- .../src/pages/integrations/nodejs.astro | 12 +- .../src/pages/integrations/python.astro | 12 +- apps/landing/src/pages/ja/compare/dash0.astro | 2 +- .../src/pages/ja/compare/datadog.astro | 2 +- .../src/pages/ja/compare/grafana.astro | 2 +- .../src/pages/ja/compare/new-relic.astro | 2 +- .../ja/features/ai-mcp-integration.astro | 18 +- .../src/pages/ja/integrations/nextjs.astro | 12 +- .../src/pages/ja/integrations/nodejs.astro | 12 +- .../src/pages/ja/integrations/python.astro | 12 +- apps/landing/src/pages/ja/opentelemetry.astro | 8 +- .../pages/ja/use-cases/api-performance.astro | 18 +- .../use-cases/ecommerce-observability.astro | 14 +- .../use-cases/microservices-debugging.astro | 14 +- apps/landing/src/pages/ko/compare/dash0.astro | 2 +- .../src/pages/ko/compare/datadog.astro | 2 +- .../src/pages/ko/compare/grafana.astro | 2 +- .../src/pages/ko/compare/new-relic.astro | 2 +- .../ko/features/ai-mcp-integration.astro | 18 +- .../src/pages/ko/integrations/nextjs.astro | 12 +- .../src/pages/ko/integrations/nodejs.astro | 12 +- .../src/pages/ko/integrations/python.astro | 12 +- apps/landing/src/pages/ko/opentelemetry.astro | 8 +- apps/landing/src/pages/local.astro | 18 +- apps/landing/src/pages/observability.astro | 14 +- apps/landing/src/pages/opentelemetry.astro | 8 +- .../src/pages/use-cases/api-performance.astro | 18 +- .../use-cases/ecommerce-observability.astro | 14 +- .../use-cases/microservices-debugging.astro | 14 +- apps/landing/src/styles/global.css | 185 +--------- apps/web/src/styles.css | 311 +---------------- package.json | 1 + packages/ui/package.json | 1 + packages/ui/src/styles/tokens.css | 317 ++++++++++++++++++ scripts/check-token-drift.ts | 63 ++++ 78 files changed, 713 insertions(+), 779 deletions(-) create mode 100644 packages/ui/src/styles/tokens.css create mode 100644 scripts/check-token-drift.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4140f1c5c..05b52c625 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,6 +24,10 @@ jobs: - run: bun install --frozen-lockfile + # Shared design tokens live in packages/ui/src/styles/tokens.css; + # fails if an app re-declares one (landing ↔ web drift guard). + - run: bun run check:tokens + - run: bun turbo typecheck test build --filter='!@maple/ingest' knip: diff --git a/DESIGN.md b/DESIGN.md index 3d8b86056..141e73dca 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -4,8 +4,8 @@ description: Open-source OpenTelemetry observability platform — terminal-nativ colors: primary: "oklch(0.714 0.154 59)" primary-foreground: "oklch(0.207 0.008 67)" - primary-light: "oklch(0.59 0.14 242)" - primary-light-foreground: "oklch(0.98 0.01 237)" + primary-light: "oklch(0.66 0.16 59)" + primary-light-foreground: "oklch(0.21 0.008 67)" background: "oklch(0.207 0.008 67)" foreground: "oklch(0.91 0.016 74)" card: "oklch(0.224 0.009 75)" @@ -147,12 +147,16 @@ The shared visual posture is **Linear / Vercel / Axiom adjacent**: compact app s ## 2. Colors: The Operator Palette -The palette is **theme-divergent on purpose**. Light mode anchors on a vivid blue primary (`oklch(0.59 0.14 242)`); dark mode rebases on a warm amber-gold primary (`oklch(0.714 0.154 59)`). Both are correct — neither is the "true" Maple color. The dark theme is canonical for the frontmatter (matches ``); light tokens travel alongside in the `.dark` ↔ `:root` swap. +The palette is **theme-tuned, same hue**. Both themes anchor on Maple's warm amber (hue ~59): dark mode uses `oklch(0.714 0.154 59)`, light mode the same hue tuned slightly deeper (`oklch(0.66 0.16 59)`) so it reads on a white canvas. The dark theme is canonical for the frontmatter (matches ``); light tokens travel alongside in the `.dark` ↔ `:root` swap. + +### Token source of truth + +All shared design tokens (color, radius, fonts, severity/service/chart palettes, the `@theme inline` mapping) live in **`packages/ui/src/styles/tokens.css`** and are imported by both `apps/web` and `apps/landing` via `@import "@maple/ui/styles/tokens.css"` (after `@import "tailwindcss"`). Apps must never re-declare a shared token name — `bun run check:tokens` fails CI if they do. App-local tokens stay in the apps: web's Sugar High `--sh-*` set, landing's marketing set (`--bg-elevated`, `--bg-deep`, `--amber-deep`, `--amber-soft`). Landing is dark-only: it pins `class="dark"` on `` instead of maintaining its own token copy. The ReactFlow controls chrome (flat, square corners, `border-radius: 0`) is part of the shared file — the product rendering is the reference for landing mockups. ### Primary - **Amber Signal** (`oklch(0.714 0.154 59)`, dark canonical): the accent used on primary actions, the active sidebar item, `chart-1` / `chart-p95`, and severity-warn. Warm enough to read at low ambient light without burning. (Note: `chart-throughput` used to share this hue, but was split to purple — `oklch(0.66 0.14 290)` — so the built-in alert signal chips can distinguish throughput from p95.) -- **Blue Beacon** (`oklch(0.59 0.14 242)`, light counterpart): the same role under light theme. Vivid blue, full chroma at a mid-lightness — feels appropriate in daylight, would feel hostile in a dim room (hence the swap). +- **Amber Signal, daylight cut** (`oklch(0.66 0.16 59)`, light counterpart): the same role and hue under light theme, a touch deeper and more chromatic so it holds contrast on white. (An earlier draft used a blue light primary; it shipped briefly as stale shadcn tokens and was rebased to amber.) ### Secondary: Severity Ramp (the system's loudest semantic color) diff --git a/apps/landing/src/components/AppMock.astro b/apps/landing/src/components/AppMock.astro index f1a649c8c..e461dcfdd 100644 --- a/apps/landing/src/components/AppMock.astro +++ b/apps/landing/src/components/AppMock.astro @@ -134,8 +134,8 @@ const MAP_VIEW_H = 360;