diff --git a/apps/website/src/app/global.css b/apps/website/src/app/global.css index 417bc6d4a..455f1f8fa 100644 --- a/apps/website/src/app/global.css +++ b/apps/website/src/app/global.css @@ -15,36 +15,6 @@ @import "../styles/marketing.css"; @import "../styles/pages.css"; -/* - * Local, non-token constants. - * - * These are deliberately NOT design tokens. Promoting them to - * @threadplane/design-tokens would imply the design system owns the syntax - * theme and the docs figure treatment. It does not. - * - * The --docs-code-* group is coupled to `rehypeOptions.theme` ('tokyo-night') - * in components/docs/MdxRenderer.tsx. Change the shiki theme and these must - * change with it. - * --docs-code-title-fg is here rather than on --color-text-muted for the same - * reason: it sits on a dark surface, where the light-theme muted token drops - * to 3.6:1 contrast. - */ -:root { - --docs-code-bg: #1a1b26; - --docs-code-title-fg: #8b8fa3; - --docs-code-border: rgba(0, 0, 0, 0.1); - --docs-code-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); - --docs-code-title-rule: rgba(255, 255, 255, 0.06); - --docs-figure-shadow: 0 4px 16px rgba(0, 32, 72, 0.1); - --docs-figure-shadow-bare: 0 4px 16px rgba(0, 32, 72, 0.08); - /* Accent tints in the 3.5–10% range, around --color-accent-surface (6%). - * Derived rather than hardcoded so they track the accent. */ - --docs-accent-tint-faint: color-mix(in srgb, var(--color-accent) 3.5%, transparent); - --docs-accent-tint-soft: color-mix(in srgb, var(--color-accent) 8%, transparent); - --docs-accent-tint-line: color-mix(in srgb, var(--color-accent) 10%, transparent); -} - - * { box-sizing: border-box; } @@ -95,222 +65,3 @@ h1, h2, h3, h4, h5, h6 { html { scroll-behavior: smooth; } - -/* Shiki code blocks — tokyo-night theme */ -.shiki { - padding: 1.5rem; - background: var(--docs-code-bg) !important; - overflow-x: auto; -} -.shiki code { - font-family: var(--font-mono), monospace; - font-size: 0.75rem; - line-height: 1.7; -} - -/* rehype-pretty-code — docs code blocks */ -.docs-prose [data-rehype-pretty-code-figure] { - margin: 1.5rem 0; - max-width: 100%; - overflow: hidden; -} - -.docs-prose [data-rehype-pretty-code-figure] pre { - padding: 1.25rem 1.5rem; - border-radius: 0.75rem; - border: 1px solid var(--docs-code-border); - box-shadow: var(--docs-code-shadow); - overflow-x: auto; - font-size: 0.8rem; - line-height: 1.7; -} - -.docs-prose [data-rehype-pretty-code-figure] code { - font-family: var(--font-mono), monospace; - font-size: inherit; - background: none !important; - padding: 0 !important; - border-radius: 0 !important; - color: inherit !important; -} - -.docs-prose [data-rehype-pretty-code-figure] [data-line] { - padding: 0 0.25rem; -} - -.docs-prose [data-rehype-pretty-code-figure] [data-rehype-pretty-code-title] { - font-family: var(--font-mono), monospace; - font-size: 0.7rem; - color: var(--docs-code-title-fg); - padding: 0.5rem 1.5rem; - background: var(--docs-code-bg); - border-bottom: 1px solid var(--docs-code-title-rule); - border-radius: 0.75rem 0.75rem 0 0; -} - -.docs-prose [data-rehype-pretty-code-figure]:has([data-rehype-pretty-code-title]) pre { - border-radius: 0 0 0.75rem 0.75rem; -} - -.docs-prose :not(pre) > code { - font-family: var(--font-mono), monospace; - font-size: 0.85em; - background: var(--color-accent-surface); - color: var(--color-accent); - padding: 0.15rem 0.4rem; - border-radius: 0.25rem; - font-weight: 400; -} - -.docs-prose { overflow-wrap: break-word; word-break: break-word; max-width: 100%; } -.docs-prose > * { max-width: 100%; } -.docs-prose h1 { font-size: 1.875rem; font-weight: 700; margin-top: 0; margin-bottom: 1rem; font-family: var(--font-garamond); } -.docs-prose h2 { font-size: 1.5rem; font-weight: 600; margin-top: 2.5rem; margin-bottom: 1rem; font-family: var(--font-garamond); } -.docs-prose h3 { font-size: 1.25rem; font-weight: 600; margin-top: 2rem; margin-bottom: 0.75rem; font-family: var(--font-garamond); } -.docs-prose p { line-height: 1.75; margin-bottom: 1.25rem; } -.docs-prose ul, .docs-prose ol { - margin-bottom: 1.25rem; - padding-left: 1.5rem; - list-style-position: outside; -} -/* Use longhand `list-style-type` to dodge Lightning CSS shorthand rewriting - `list-style: disc` to `list-style: outside` (which drops the bullet type - and lets Tailwind's `ol, ul, menu { list-style: none }` preflight win). */ -.docs-prose ul { list-style-type: disc; } -.docs-prose ol { list-style-type: decimal; } -.docs-prose li { margin-bottom: 0.5rem; line-height: 1.6; } -.docs-prose li > p { margin-bottom: 0.5rem; } -.docs-prose li::marker { color: var(--color-text-muted); } -.docs-prose ul ul, .docs-prose ol ol, .docs-prose ul ol, .docs-prose ol ul { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} - -/* Figures (screenshots + caption). - * Goal: lift the screenshot off the page so it reads as a distinct artifact - * rather than an inline asset. Tinted backdrop + soft shadow + clean caption. - * Scoped to image figures via :has(> img) so it doesn't collide with the - * code-block figures from rehype-pretty-code or component figures (e.g. - * AgUiArchDiagram). */ -.docs-prose figure:has(> img) { - margin: 2.5rem 0; - padding: 0.75rem 0.75rem 0; - background: var(--docs-accent-tint-faint); - border: 1px solid var(--docs-accent-tint-line); - border-radius: 0.75rem; -} -.docs-prose figure:has(> img) > img { - display: block; - width: 100%; - height: auto; - border-radius: 0.5rem; - box-shadow: var(--docs-figure-shadow); -} -.docs-prose figure:has(> img) > figcaption { - margin: 0; - padding: 0.875rem 0.5rem 0.625rem; - font-size: 0.875rem; - line-height: 1.5; - color: var(--color-text-muted); - text-align: center; - font-style: italic; -} -/* Bare images (no figure wrapper) — give them the same lift treatment. */ -.docs-prose > p > img, -.docs-prose > img { - display: block; - max-width: 100%; - height: auto; - margin: 2rem auto; - border-radius: 0.5rem; - box-shadow: var(--docs-figure-shadow-bare); -} - -/* Architecture diagrams are authored at exactly the width `.docs-prose` - * computes to (70ch = ~706px), so they render 1:1 and their labels stay at - * their authored size. Below that, scaling the whole figure down would take - * 11.5px labels under 5px, so the paragraph scrolls instead — the same - * treatment `.docs-table-scroll` gives a wide table. */ -.docs-prose > p:has(> .docs-diagram) { overflow-x: auto; } -.docs-prose > p > img.docs-diagram { max-width: none; } - -.docs-table-scroll { max-width: 100%; overflow-x: auto; margin: 1.5rem 0; } -.docs-prose table { width: 100%; border-collapse: collapse; font-size: 0.875rem; margin: 0; } -.docs-prose th { text-align: left; padding: 0.5rem 0.75rem; font-family: var(--font-mono); font-size: 0.75rem; text-transform: uppercase; color: var(--color-text-muted); border-bottom: 1px solid var(--color-accent-border); } -.docs-prose td { padding: 0.5rem 0.75rem; border-bottom: 1px solid var(--docs-accent-tint-soft); color: var(--color-text-secondary); } -.docs-prose td code { font-size: 0.8em; } - -/* AG-UI architecture diagram */ -.ag-ui-arch-grid { - display: grid; - grid-template-columns: 1fr auto 1fr auto 1fr; - align-items: stretch; - gap: 0; -} -@media (max-width: 720px) { - .ag-ui-arch-grid { - grid-template-columns: 1fr; - } - .ag-ui-arch-arrow { - transform: rotate(90deg); - padding: 12px 0; - margin: 4px auto; - } -} - -/* Docs — readable column max-width */ -.docs-prose { - max-width: 70ch; -} -@media (max-width: 768px) { - .docs-prose { - max-width: 100%; - } -} - -/* Docs — hash-anchor affordance on H2/H3 */ -.docs-prose h2, -.docs-prose h3 { - position: relative; -} -.docs-prose h2 .heading-anchor, -.docs-prose h3 .heading-anchor { - position: absolute; - left: -1.25em; - top: 0; - font-family: var(--font-mono); - font-weight: 400; - color: var(--color-text-muted); - opacity: 0; - text-decoration: none; - transition: opacity 120ms ease; -} -/* - * The `#` glyph is generated content, never a text node: that keeps it out of - * the heading's textContent so extracted headings ("Prerequisites") stay clean - * for search snippets, page outlines, and agents reading the DOM. - */ -.docs-prose h2 .heading-anchor::before, -.docs-prose h3 .heading-anchor::before { - content: '#'; -} -.docs-prose h2:hover .heading-anchor, -.docs-prose h3:hover .heading-anchor, -.docs-prose h2 .heading-anchor:focus-visible, -.docs-prose h3 .heading-anchor:focus-visible { - opacity: 0.6; -} -.docs-prose h2 .heading-anchor:hover, -.docs-prose h3 .heading-anchor:hover { - opacity: 1; - color: var(--color-accent); -} -@media (max-width: 768px) { - /* On narrow viewports, drop the absolute positioning so the hash doesn't overlap the page edge. */ - .docs-prose h2 .heading-anchor, - .docs-prose h3 .heading-anchor { - position: static; - margin-right: 6px; - display: none; - } -} diff --git a/apps/website/src/components/docs/AgUiArchDiagram.tsx b/apps/website/src/components/docs/AgUiArchDiagram.tsx index 3fbb056d6..2b8c1fdf2 100644 --- a/apps/website/src/components/docs/AgUiArchDiagram.tsx +++ b/apps/website/src/components/docs/AgUiArchDiagram.tsx @@ -1,5 +1,3 @@ -import { tokens } from '@threadplane/design-tokens'; - interface BoxProps { eyebrow: string; title: string; @@ -8,49 +6,15 @@ interface BoxProps { } function Box({ eyebrow, title, meta, tone = 'neutral' }: BoxProps) { - const isAccent = tone === 'accent'; return ( -
- +
+ {eyebrow} - + {title} - + {meta}
@@ -62,30 +26,11 @@ function ArrowLabel({ label, sub }: { label: string; sub: string }) {
- + {label} - + - + {sub}
@@ -104,13 +49,7 @@ function ArrowLabel({ label, sub }: { label: string; sub: string }) { export function AgUiArchDiagram() { return (
Backend speaks AG-UI over SSE → adapter exposes a signal-shaped Agent contract → chat UI renders.
diff --git a/apps/website/src/components/docs/ApiDocRenderer.tsx b/apps/website/src/components/docs/ApiDocRenderer.tsx index 7fbf775d1..723feedc2 100644 --- a/apps/website/src/components/docs/ApiDocRenderer.tsx +++ b/apps/website/src/components/docs/ApiDocRenderer.tsx @@ -1,5 +1,3 @@ -import { tokens } from '@threadplane/design-tokens'; - interface ApiParam { name: string; type: string; @@ -28,34 +26,26 @@ export interface ApiDocEntry { function KindBadge({ kind }: { kind: string }) { return ( - {kind} + {kind} ); } function ParamTable({ params }: { params: ApiParam[] }) { return ( - +
- + {['Parameter', 'Type', 'Description'].map((h) => ( - + ))} {params.map((p) => ( - - - - + + + + ))} @@ -65,57 +55,50 @@ function ParamTable({ params }: { params: ApiParam[] }) { export function ApiDocRenderer({ entry }: { entry: ApiDocEntry }) { return ( -
-
- {entry.name} +
+
+ {entry.name}
-

{entry.description}

+

{entry.description}

{entry.signature && ( -
-
+        
+
             {entry.signature}
           
)} {entry.params && entry.params.length > 0 && ( -
-

Parameters

+
+

Parameters

)} {entry.returns && ( -
-

Returns

- {entry.returns.type} +
+

Returns

+ {entry.returns.type}
)} {entry.properties && entry.properties.length > 0 && ( -
-

Properties

+
+

Properties

)} {entry.methods && entry.methods.length > 0 && ( -
-

Methods

+
+

Methods

{entry.methods.map((m) => ( -
- {m.signature} - {m.description &&

{m.description}

} +
+ {m.signature} + {m.description &&

{m.description}

} {m.params && m.params.length > 0 && }
))} @@ -124,10 +107,10 @@ export function ApiDocRenderer({ entry }: { entry: ApiDocEntry }) { {entry.examples && entry.examples.length > 0 && (
-

Examples

+

Examples

{entry.examples.map((ex, i) => ( -
-
+            
+
                 {ex.replace(/^```\w*\n?/, '').replace(/\n?```$/, '')}
               
diff --git a/apps/website/src/components/docs/ApiRefTable.tsx b/apps/website/src/components/docs/ApiRefTable.tsx index 5ff3b5cef..bc2839fa4 100644 --- a/apps/website/src/components/docs/ApiRefTable.tsx +++ b/apps/website/src/components/docs/ApiRefTable.tsx @@ -1,5 +1,3 @@ -import { tokens } from '@threadplane/design-tokens'; - export interface ApiEntry { name: string; type: string; @@ -13,34 +11,26 @@ export function ApiRefTable({ entries }: { entries: ApiEntry[] }) { {entries.map((entry) => (
+ className="p-6 rounded-lg api-ref-card">
+ className="font-mono font-bold text-base api-ref-name"> {entry.name} + className="font-mono text-xs api-ref-type"> {entry.type}
-

{entry.description}

+

{entry.description}

{entry.params && entry.params.length > 0 && ( -
{h}{h}
{p.name}{p.optional ? '?' : ''}{p.type}{p.description}
{p.name}{p.optional ? '?' : ''}{p.type}{p.description}
+
- + {['Parameter', 'Type', 'Description'].map((h) => ( ))} @@ -48,10 +38,10 @@ export function ApiRefTable({ entries }: { entries: ApiEntry[] }) { {entry.params.map((p) => ( - - - - + + + + ))} diff --git a/apps/website/src/components/docs/ArchFlowDiagram.tsx b/apps/website/src/components/docs/ArchFlowDiagram.tsx index 4f993844b..81ff98261 100644 --- a/apps/website/src/components/docs/ArchFlowDiagram.tsx +++ b/apps/website/src/components/docs/ArchFlowDiagram.tsx @@ -1,6 +1,5 @@ 'use client'; import { useState, useEffect, useRef } from 'react'; -import { tokens } from '@threadplane/design-tokens'; interface LogEntry { time: string; @@ -23,11 +22,11 @@ const SCENARIO: { delay: number; chatBubble?: { role: 'user' | 'assistant'; text { delay: 6000, log: { time: '2.12s', source: 'angular', message: 'Template re-rendered (OnPush) — 1 component' } }, ]; -const SOURCE_COLORS: Record = { - angular: { bg: 'rgba(221,0,49,0.08)', text: '#c62828', label: 'ANGULAR' }, - transport: { bg: 'rgba(100,80,200,0.08)', text: '#5e35b1', label: 'TRANSPORT' }, - langgraph: { bg: 'rgba(0,64,144,0.08)', text: '#004090', label: 'LANGGRAPH' }, - signal: { bg: 'rgba(16,185,129,0.08)', text: '#059669', label: 'SIGNAL' }, +const SOURCE_LABEL: Record = { + angular: 'ANGULAR', + transport: 'TRANSPORT', + langgraph: 'LANGGRAPH', + signal: 'SIGNAL', }; export function ArchFlowDiagram() { @@ -73,58 +72,32 @@ export function ArchFlowDiagram() { }, [cycle]); return ( -
+
{/* Header bar */} -
-
-
-
-
+
+
+
+
+
- injectAgent() — live architecture flow - localhost:4200 + injectAgent() — live architecture flow + localhost:4200
-
+
{/* Left: Chat simulation */} -
-
Chat Interface
+
+
Chat Interface
-
+
{bubbles.map((b, i) => ( -
+
{b.role === 'assistant' && ( -
AI
+
AI
)} -
+
{b.text} - {b.streaming && } + {b.streaming && }
))} @@ -132,37 +105,22 @@ export function ArchFlowDiagram() {
{/* Right: Console log */} -
-
Developer Console
+
+
Developer Console
- {logs.map((log, i) => { - const sc = SOURCE_COLORS[log.source]; - return ( -
- {log.time} - {sc.label} - {log.message} -
- ); - })} + {logs.map((log, i) => ( +
+ {log.time} + {SOURCE_LABEL[log.source]} + {log.message} +
+ ))} {logs.length === 0 && ( -
Waiting for interaction...
+
Waiting for interaction...
)}
- -
); } diff --git a/apps/website/src/components/docs/CopyButton.tsx b/apps/website/src/components/docs/CopyButton.tsx index 0c7124b18..8c70b64ef 100644 --- a/apps/website/src/components/docs/CopyButton.tsx +++ b/apps/website/src/components/docs/CopyButton.tsx @@ -1,6 +1,5 @@ 'use client'; import { useState } from 'react'; -import { tokens } from '@threadplane/design-tokens'; import { analyticsEvents } from '../../lib/analytics/events'; import { track } from '../../lib/analytics/client'; @@ -48,21 +47,8 @@ export function CopyButton({ text }: Props) { type="button" onClick={handleClick} aria-label={copied ? 'Copied' : 'Copy install command'} - style={{ - display: 'inline-flex', - alignItems: 'center', - justifyContent: 'center', - width: 28, - height: 28, - flex: '0 0 auto', - padding: 0, - border: `1px solid ${tokens.surfaces.border}`, - borderRadius: tokens.radius.sm, - background: tokens.surfaces.surface, - color: copied ? tokens.colors.accent : tokens.colors.textMuted, - cursor: 'pointer', - transition: 'color 0.15s, border-color 0.15s, background 0.15s', - }} + className="docs-copy-button" + data-copied={copied || undefined} > {copied ? : } diff --git a/apps/website/src/components/docs/CopyPromptButton.tsx b/apps/website/src/components/docs/CopyPromptButton.tsx index 4cfaf8415..31703d699 100644 --- a/apps/website/src/components/docs/CopyPromptButton.tsx +++ b/apps/website/src/components/docs/CopyPromptButton.tsx @@ -1,6 +1,5 @@ 'use client'; import { useState } from 'react'; -import { tokens } from '@threadplane/design-tokens'; import { analyticsEvents } from '../../lib/analytics/events'; import { track } from '../../lib/analytics/client'; @@ -27,35 +26,13 @@ export function CopyPromptButton({ prompt, variant = 'docs', label }: Props) { } }; - const isHero = variant === 'hero'; - return ( diff --git a/apps/website/src/components/docs/DocsBreadcrumb.tsx b/apps/website/src/components/docs/DocsBreadcrumb.tsx index 1f7e08ee0..9c0993e24 100644 --- a/apps/website/src/components/docs/DocsBreadcrumb.tsx +++ b/apps/website/src/components/docs/DocsBreadcrumb.tsx @@ -1,5 +1,4 @@ import Link from 'next/link'; -import { tokens } from '@threadplane/design-tokens'; import { getLibraryConfig, libraryIntroPath, type LibraryId } from '../../lib/docs-config'; interface Props { @@ -18,34 +17,22 @@ export function DocsBreadcrumb({ library, section, slug: _slug, title }: Props) const libraryTitle = libConfig?.title ?? library; const sectionTitle = libConfig?.sections.find((s) => s.id === section)?.title ?? humanize(section); - const crumb: React.CSSProperties = { - fontFamily: tokens.typography.fontSans, - fontSize: 13, - lineHeight: 1.5, - color: tokens.colors.textMuted, - textDecoration: 'none', - }; - const sep: React.CSSProperties = { - margin: '0 8px', - color: tokens.colors.textMuted, - }; - return ( -
+ className="text-left py-2 font-mono uppercase api-ref-table-head"> {h}
{p.name}{p.type}{p.desc}
{p.name}{p.type}{p.desc}