From 954de0559bfe84d1f37ed7224088de7603544d0b Mon Sep 17 00:00:00 2001 From: Waleed Date: Fri, 26 Jun 2026 17:24:09 -0700 Subject: [PATCH] improvement(docs): align components with the platform design system (#5227) * improvement(docs): align components with the platform design system Bring the docs app's chrome in line with the main Sim design system, validated against the canonical emcn source in apps/sim. - ask-ai: fix undefined tokens (--text-base x6, --text-link) that broke the send-button fill and link/text colors; send button now matches the canonical primary fill (text-primary/text-inverse, dark:bg-white); use --shadow-medium and chip gap rhythm - not-found: replace the hand-rolled brand pill with and swap fumadocs tokens for platform tokens - search-trigger: compose the exported chip chrome constants instead of re-spelling them (single source of truth) - what-you-will-learn, video-chapters: fumadocs fd-* tokens -> platform tokens - workflow-preview: add --wp-highlight token; route the #33b4ff highlight, #ef4444 error dots, and toggle/slider green through tokens - video-placeholder: tokenize the status pill (bespoke illustration art intentionally left as-is) dropdown-menu, faq, theme-toggle, and page-type-badge were deliberately left at their canonical values (14px row icons, rounded-md badge) after validation showed those match the platform, not the chip-pill, standard. * improvement(docs): neutral primary chip for nav CTA + fix cluster spacing Align the docs navbar with the main app, which reserves green for accents/status and uses a neutral high-contrast CTA in nav. - add a canonical `primary` chip variant (inverse fill: dark in light mode, white in dark mode), mirroring the emcn chip's primary action - "Get started" and the 404 "Go home" now use variant='primary' instead of the green brand surface - retire the now-unused `brand` chip variant (no parallel path left behind) - fix navbar right-cluster spacing: gap-2 to match the landing navbar and drop the asymmetric ml-1 on the CTA --- apps/docs/app/[lang]/not-found.tsx | 15 +++++-------- apps/docs/app/global.css | 1 + apps/docs/components/ai/ask-ai.tsx | 22 +++++++++---------- apps/docs/components/navbar/navbar.tsx | 4 ++-- apps/docs/components/ui/chip.tsx | 17 ++++++++------ apps/docs/components/ui/search-trigger.tsx | 16 ++++++++++++-- apps/docs/components/ui/video-chapters.tsx | 11 ++++++---- apps/docs/components/ui/video-placeholder.tsx | 4 ++-- .../components/ui/what-you-will-learn.tsx | 13 +++++++---- .../workflow-preview/block-inspector.tsx | 4 ++-- .../workflow-preview/block-preview.tsx | 2 +- .../workflow-preview/output-bundle.tsx | 2 +- .../workflow-preview/preview-block-node.tsx | 4 ++-- .../workflow-preview/workflow-data.ts | 2 +- 14 files changed, 69 insertions(+), 48 deletions(-) diff --git a/apps/docs/app/[lang]/not-found.tsx b/apps/docs/app/[lang]/not-found.tsx index c28c765851..af647ec4cf 100644 --- a/apps/docs/app/[lang]/not-found.tsx +++ b/apps/docs/app/[lang]/not-found.tsx @@ -1,5 +1,5 @@ import { DocsPage } from 'fumadocs-ui/page' -import Link from 'next/link' +import { ChipLink } from '@/components/ui/chip' export const metadata = { title: 'Page Not Found', @@ -9,19 +9,16 @@ export default function NotFound() { return (
-

+

404

-

Page Not Found

-

+

Page Not Found

+

The page you're looking for doesn't exist or has been moved.

- + Go home - +
) diff --git a/apps/docs/app/global.css b/apps/docs/app/global.css index 4d0dcd81d3..2c24e2867e 100644 --- a/apps/docs/app/global.css +++ b/apps/docs/app/global.css @@ -1669,6 +1669,7 @@ main article blockquote { --wp-chip-text: var(--text-body); --wp-divider: #ededed; /* --divider */ --wp-edge: #e0e0e0; /* --workflow-edge */ + --wp-highlight: #33b4ff; /* traced edge / highlighted output node */ /* text */ --wp-text: var(--text-primary); diff --git a/apps/docs/components/ai/ask-ai.tsx b/apps/docs/components/ai/ask-ai.tsx index 1a5eb718a6..dca3886305 100644 --- a/apps/docs/components/ai/ask-ai.tsx +++ b/apps/docs/components/ai/ask-ai.tsx @@ -84,7 +84,7 @@ export function AskAI({ locale }: AskAIProps) { type='button' aria-label='Ask AI' onClick={() => setOpen(true)} - className='fixed right-4 bottom-4 z-50 flex h-11 items-center gap-2 rounded-full border border-[var(--border-1)] bg-[var(--surface-5)] px-4 font-season text-[var(--text-base)] text-sm shadow-lg transition-colors hover:bg-[var(--surface-active)] dark:bg-[var(--surface-4)]' + className='fixed right-4 bottom-4 z-50 flex h-11 items-center gap-1.5 rounded-full border border-[var(--border-1)] bg-[var(--surface-5)] px-4 font-season text-[var(--text-body)] text-sm shadow-[var(--shadow-medium)] transition-colors hover:bg-[var(--surface-active)] dark:bg-[var(--surface-4)]' > Ask AI @@ -92,9 +92,9 @@ export function AskAI({ locale }: AskAIProps) { )} {open && ( -
+
- + Ask AI @@ -105,7 +105,7 @@ export function AskAI({ locale }: AskAIProps) { stop() setOpen(false) }} - className='flex size-7 items-center justify-center rounded-md text-[var(--text-icon)] transition-colors hover:bg-[var(--surface-active)]' + className='flex size-7 items-center justify-center rounded-lg text-[var(--text-icon)] transition-colors hover:bg-[var(--surface-active)]' > @@ -132,13 +132,13 @@ export function AskAI({ locale }: AskAIProps) { )} > {message.role === 'user' ? ( -
+
{text}
) : ( -
+
{text ? ( - + {text} ) : isStreaming ? ( @@ -156,7 +156,7 @@ export function AskAI({ locale }: AskAIProps) { href={source.url} target='_blank' rel='noopener noreferrer' - className='rounded-md border border-[var(--border-1)] px-2 py-0.5 text-[var(--text-muted)] text-xs transition-colors hover:bg-[var(--surface-active)]' + className='rounded-lg border border-[var(--border-1)] px-2 py-0.5 text-[var(--text-muted)] text-xs transition-colors hover:bg-[var(--surface-active)]' > {source.title || source.url} @@ -189,7 +189,7 @@ export function AskAI({ locale }: AskAIProps) { }} rows={1} placeholder='Ask a question…' - className='max-h-32 flex-1 resize-none bg-transparent font-season text-[var(--text-base)] text-sm outline-none placeholder:text-[var(--text-muted)]' + className='max-h-32 flex-1 resize-none bg-transparent font-season text-[var(--text-body)] text-sm outline-none placeholder:text-[var(--text-muted)]' /> {isBusy ? ( ) : ( diff --git a/apps/docs/components/navbar/navbar.tsx b/apps/docs/components/navbar/navbar.tsx index 7717e66823..749742c0d6 100644 --- a/apps/docs/components/navbar/navbar.tsx +++ b/apps/docs/components/navbar/navbar.tsx @@ -52,10 +52,10 @@ export function Navbar() {
-
+
- + Get started
diff --git a/apps/docs/components/ui/chip.tsx b/apps/docs/components/ui/chip.tsx index d9c515690f..6a51533df1 100644 --- a/apps/docs/components/ui/chip.tsx +++ b/apps/docs/components/ui/chip.tsx @@ -26,6 +26,9 @@ export const chipContentIconClass = 'size-[16px] flex-shrink-0 text-[var(--text- export const chipContentLabelClass = 'min-w-0 truncate text-[var(--text-body)] text-sm' /** The filled FILL (surface only, no border) — `--surface-5` light / `--surface-4` dark. */ export const chipFilledFillTokens = 'bg-[var(--surface-5)] dark:bg-[var(--surface-4)]' +/** The inverse/primary FILL — dark surface + inverse text in light, white + `--bg` text in dark. */ +const chipPrimaryFillTokens = + 'bg-[var(--text-primary)] text-[var(--text-inverse)] dark:bg-white dark:text-[var(--bg)]' /** 1px `--border-1` border applied to chip triggers so they read as controls. */ export const TRIGGER_BORDER_CLASS = 'border border-[var(--border-1)]' @@ -34,8 +37,9 @@ export const TRIGGER_BORDER_CLASS = 'border border-[var(--border-1)]' * * @remarks * The implicit default variant is the bare pill — transparent, `--surface-active` - * on hover. `filled` adds the filled surface; `brand` is the green CTA surface - * (`--brand-accent`) used for the "Get started" link. + * on hover. `filled` adds the filled surface; `primary` is the canonical inverse + * CTA surface (dark in light mode, white in dark mode) used for the "Get started" + * link. */ const chipVariants = cva( `group cursor-pointer font-season ${chipGeometryClass} transition-colors disabled:cursor-not-allowed disabled:opacity-60`, @@ -44,8 +48,7 @@ const chipVariants = cva( variant: { default: 'hover:bg-[var(--surface-active)]', filled: `${chipFilledFillTokens} hover:bg-[var(--surface-active)]`, - brand: - 'bg-[var(--brand-accent)] text-white hover:bg-[var(--brand-accent-hover)] hover:text-white', + primary: `${chipPrimaryFillTokens} hover:bg-[var(--text-body)] dark:hover:bg-[var(--text-secondary)]`, }, fullWidth: { true: 'flex', false: 'inline-flex' }, }, @@ -66,7 +69,7 @@ interface ChipBaseProps extends VariantProps { } /** - * `brand` sets text color on the chip itself — its icon and label inherit via + * `primary` sets text color on the chip itself — its icon and label inherit via * `currentColor`. The default and `filled` chips use explicit icon * (`--text-icon`) and label (`--text-body`) colors. */ @@ -76,7 +79,7 @@ function ChipContent({ rightIcon: RightIcon, children, }: ChipBaseProps) { - const isInverse = variant === 'brand' + const isInverse = variant === 'primary' const iconClass = cn(chipContentIconClass, isInverse && 'text-current') const labelClass = cn(chipContentLabelClass, 'flex-1', isInverse && 'text-current') return ( @@ -121,7 +124,7 @@ interface ChipLinkProps ChipBaseProps {} /** - * @example Get started + * @example Get started */ const ChipLink = forwardRef(function ChipLink( { className, variant, fullWidth, leftIcon, rightIcon, children, ...props }, diff --git a/apps/docs/components/ui/search-trigger.tsx b/apps/docs/components/ui/search-trigger.tsx index c7ff350996..33a2913321 100644 --- a/apps/docs/components/ui/search-trigger.tsx +++ b/apps/docs/components/ui/search-trigger.tsx @@ -1,6 +1,13 @@ 'use client' import { Search } from 'lucide-react' +import { + chipContentIconClass, + chipFilledFillTokens, + chipGeometryClass, + TRIGGER_BORDER_CLASS, +} from '@/components/ui/chip' +import { cn } from '@/lib/utils' export function SearchTrigger() { const openSearchDialog = () => { @@ -16,10 +23,15 @@ export function SearchTrigger() {