diff --git a/SKILL.md b/SKILL.md index ad0e96d..8ac4036 100644 --- a/SKILL.md +++ b/SKILL.md @@ -56,7 +56,7 @@ import { foundationRegistry } from '@rubriclab/concrete/registry' This section is generated from `foundationRegistry`, `primitiveRegistry`, and `componentRegistry`. Run `bun run build:skill` after registry changes. -Concrete currently exposes 12 foundations, 82 primitives, and 33 components. +Concrete currently exposes 12 foundations, 84 primitives, and 34 components. ### Foundations @@ -148,7 +148,7 @@ Quiet texture grounds for diagrams, editorial frames, and educational examples. - Category: `foundation` - Pressure: `editorial`, `educational` - Guidance: Use texture as structure, never as decorative noise. -- Tokens: Tokens (3: `lattice`, `dots`, `lines`) +- Tokens: Tokens (4: `lattice`, `dots`, `lines`, `depth`) #### Iconography @@ -189,7 +189,7 @@ Primitives are the Concrete HTML vocabulary. They own DOM, scoped classes, schem - **Feedback** (8): Message shell (`message-shell`), Feedback Panel (`feedback-panel`), Reasoning panel (`reasoning-panel`), Spinner (`spinner`), Empty state (`empty-state`), Tooltip (`tooltip`), Skeleton (`skeleton`), Tool-call panel (`tool-call-panel`) - **Data** (13): Metric Shell (`metric-shell`), Data Card Header (`data-card-header`), Chart Surface (`chart-surface`), Chart Legend (`chart-legend`), Data Table Shell (`data-table-shell`), Data Table Control (`data-table-control`), Data Table Pagination (`data-table-pagination`), Progress (`progress`), Stat (`stat`), Delta (`delta`), Sparkline (`sparkline`), Distribution (`distribution`), Indicator (`indicator`) - **Media** (2): Upload item (`upload-item`), Avatar (`avatar`) -- **Surface** (2): Card (`card`), Bubble (`bubble`) +- **Surface** (4): Card (`card`), Bubble (`bubble`), TiltFrame (`tilt-frame`), ScaleFrame (`scale-frame`) - **Status** (3): Pill (`pill`), Badge (`badge`), Tag (`tag`) - **Layout** (4): Row (`row`), Preview Stage (`preview-stage`), Divider (`divider`), Frame (`frame`) - **Typography** (2): Code (`code`), Kbd (`kbd`) @@ -209,8 +209,8 @@ Components assemble primitives into reusable product behavior. They should not i - **Feedback** (3): Validation summary (`validation-summary`), Reasoning message (`reasoning-message`), Tool call message (`tool-call-message`) - **Media** (1): Image upload (`image-upload`) - **Data** (11): Metric card (`metric-card`), Meter (`meter`), Line chart (`line-chart`), Area chart (`area-chart`), Bar chart (`bar-chart`), Stacked bar chart (`stacked-bar-chart`), Donut chart (`donut-chart`), Heatmap (`heatmap`), Chart (`chart`), Data table (`data-table`), Flow diagram (`flow-diagram`) +- **Surface** (2): FeatureCard (`feature-card`), Message (`message`) - **Diagram** (1): Diagram canvas (`diagram-canvas`) -- **Surface** (1): Message (`message`) ## Usage Guide diff --git a/apps/docs/app/layout.tsx b/apps/docs/app/layout.tsx index 3f53daf..09af8f6 100644 --- a/apps/docs/app/layout.tsx +++ b/apps/docs/app/layout.tsx @@ -28,27 +28,27 @@ export default function RootLayout({ children }: Readonly<{ children: React.Reac Concrete @@ -59,17 +59,21 @@ export default function RootLayout({ children }: Readonly<{ children: React.Reac ) } -function NpmIcon() { +function NpmLogo() { return ( -

Concrete is a design system for labs that ship

-

- An editorial voice for serious tools: crisp type, soft controls, dense product surfaces, and - one primitive kit underneath every page. -

-
- npm - npm install @rubriclab/concrete -
-
- Concrete / 00 -

- Build the language -
- before the page. -

-
- type - color - density - motion - primitives -
-
- - -
- -

One language, many pressures.

-

- Foundations are strict enough for product density and expressive enough for published research. - Pressure is creative direction, not a universal primitive prop. -

+type HeroFeature = { + accent: 'ink' | 'sky' | 'terminal' | 'ultra' + description: string + icon: IconName + title: string +} - -
-
-

- Rubric is a lab -
- that ships -

-
-
- {homeTypeRows.map(([metric, sample, role, className]) => ( -
- {metric} - {renderHomeTypeSample(sample, className)} - {role} -
- ))} -
-
+type SystemLayer = { + description: string + href: string + items: readonly string[] + key: 'foundations' | 'primitives' | 'components' | 'applications' + title: string +} - -
- - -
- {signalStops.map(([label, color, role]) => ( -
- - {label} - {role} -
- ))} -
-
+const heroFeatures = [ + { + accent: 'ink', + description: 'Zod props, examples, states.', + icon: 'code', + title: 'Typed surface' + }, + { + accent: 'sky', + description: 'Same grid, four contexts.', + icon: 'sliders-horizontal', + title: 'Density aware' + }, + { + accent: 'terminal', + description: 'React and image URLs.', + icon: 'image', + title: 'Render routes' + }, + { + accent: 'ultra', + description: 'Specs machines can use.', + icon: 'zap', + title: 'Agent native' + } +] as const satisfies readonly HeroFeature[] - -
- {pressureRows.map(([title, description]) => ( -
- {title} - {description} - -
- ))} -
+const systemLayers = [ + { + description: 'The rules of the system.', + href: '/foundations', + items: ['Color', 'Type', 'Space', 'Surface', 'Radius', 'Texture'], + key: 'foundations', + title: 'Foundations' + }, + { + description: 'Low-level building blocks.', + href: '/primitives', + items: ['Button', 'Input', 'Badge', 'Switch', 'Checkbox', 'Tag'], + key: 'primitives', + title: 'Primitives' + }, + { + description: 'High-level composable UI.', + href: '/components', + items: ['Composer', 'Menu', 'Chart', 'Table', 'Trace'], + key: 'components', + title: 'Components' + }, + { + description: 'Interfaces that ship.', + href: '#library', + items: ['Dashboards', 'Docs', 'Agents', 'Generated UI'], + key: 'applications', + title: 'Applications' + } +] as const satisfies readonly SystemLayer[] - -
-
- {spaceRows.map(([label, size, role]) => ( - - {label} - {size} - {role} - - ))} -
-
- {radiusRows.map(([label, radius, role]) => ( -
- - {label} - {role} -
- ))} -
-
- Border - Raised - Floating - Overlay -
-
+const pressureModes = [ + { + body: 'Generous margins, long measures, open rhythm, and selected proof.', + mode: 'Hierarchy', + title: 'Editorial' + }, + { + body: 'High information density, efficient scanning, persistent tools, and visible states.', + mode: 'Compact', + title: 'Product' + }, + { + body: 'Focused flow, one useful output, progressive reveal, and inline artifacts.', + mode: 'Standard', + title: 'Generative' + }, + { + body: 'Simplified frames, clear annotations, mocked fidelity, and easy scanning.', + mode: 'Mocked', + title: 'Explainer' + } +] as const satisfies readonly { + body: string + mode: string + title: string +}[] - -
-
- Fade - Move - Reveal - Dismiss -
-
- - Selected chip - -
-
- - - +export default function HomeRoute() { + return ( +
+
+ +
+ Concrete +

+ The language layer for labs that ship. +

+

+ A rigorous React design system for research writing, dense products, generated interfaces, + agent workflows, and the strange space between them. +

+
+
- - -
-
- {iconRuleRows.map(([label, value]) => ( - - {label} - {value} - - ))} -
-
- {iconNames.map(name => ( - - - {name} - - ))} -
+
+
+ Composer + Product density +
+
{renderComponentExample('composer')}
+
{heroFeatures.map(renderHeroFeature)}
-
- + -

Small parts, clear roles.

-

- Each card shows a real exported primitive centered in a sunken stage. The full card opens the - typed primitive page with states, props, and render routes. -

-
- {primitiveRegistry.map(entry => ( -
- -
- {entry.name} - {entry.category} -
-
{renderPrimitiveExample(entry.slug)}
-
- ))} +
+
{systemLayers.map(renderSystemLayer)}
-
- + -

Components declare density.

-

- Components assemble primitive contracts into agentic interaction, AI-native transcript, and - form workflows. They can own deterministic local behavior, but product policy stays in the - application. -

+
{pressureModes.map(renderPressureMode)}
+
-
- {componentRegistry.map(entry => ( -
- -
- {entry.name} - {entry.category} -
-
- {renderComponentExample(entry.slug)} -
-

{entry.description}

-
- ))} +
+ +
+ Interface contract +

Built for agents and developers.

+

+ Every item carries typed props, examples, states, usage guidance, generated controls, DOM + render routes, and screenshot routes from one package-owned definition. +

+
+ {['Zod/v4 schemas', 'Generated controls', 'Fixed visual state', 'React or JPEG output'].map( + item => ( + + + {item} + + ) + )} +
+
+ Source is the contract. +

Every public item is registered with schemas, examples, states, and render routes.

+ + + GitHub + +
+
+
+
-
- -

Contracts stay small.

-

- Concrete ships one public React package, one registry, one schema boundary, and one render - contract for DOM and screenshots. -

- -
- -
- @rubriclab/concrete - @rubriclab/concrete/components - @rubriclab/concrete/primitives - @rubriclab/concrete/styles.css - @rubriclab/concrete/registry - @rubriclab/concrete/icons - @rubriclab/concrete/schemas -
-
- -
- /render/foundation/colors - /render/primitive/button - /render/primitive/button.jpg - /render/component/composer - /render/component/composer.jpg -
-
- -

- Use primitives for controls and surfaces. Use registry metadata for docs and screenshots. - Choose pressure before composing, never as a universal primitive prop. -

-
- -
- } label="Exports" value="clean" /> - - - K - -
-
+
+
+ Built by + +

Concrete is Rubric Labs' system for soft, compact, agent-native interfaces.

- -
- -
- - - - - -
- - - Open components + +
+ + + NPM + + + GitHub
-
+
) } -type ChapterMetaProps = { - label: string - meta: string - number: string -} - -function ChapterMeta({ label, meta, number }: ChapterMetaProps) { +function renderHeroFeature(feature: HeroFeature): ReactNode { return ( -
- {number} - {label} - {meta} -
+ ) } -type SubheadProps = { - detail: string - index: string - title: string -} - -function Subhead({ detail, index, title }: SubheadProps) { +function renderSystemLayer(layer: SystemLayer): ReactNode { return ( -
- {index} - {title} - {detail} -
+
+
+ {layer.title} + {layer.description} +
+
{renderLayerPreview(layer.key)}
+
+
+ {layer.items.map(item => ( + {item} + ))} +
+ + Open + +
+
) } -type SwatchGridProps = { - stops: readonly (readonly [string, string, string])[] +function renderLayerPreview(layer: SystemLayer['key']): ReactNode { + switch (layer) { + case 'applications': + return ( +
+ +
+
+
+ Agent ops + Live +
+
+ + +
+
+ + Router + Ready + + + Eval batch + Queued + +
+
+
+
+
+ ) + case 'components': + return ( +
+ +
+ {renderComponentExample('command-menu')} +
+
+
+ ) + case 'foundations': + return ( +
+
+ Ag +
+
+ + + + + +
+
+ + + +
+
+ ) + case 'primitives': + return ( +
+
+ + +
+
+ Badge + + Agent + +
+ + +
+
+
+ ) + } } -function SwatchGrid({ stops }: SwatchGridProps) { +function renderPressureMode(mode: (typeof pressureModes)[number]): ReactNode { return ( -
- {stops.map(([label, color, role], index) => ( - stops.length / 2 ? 'isLight' : undefined} - key={label} - style={{ '--home-swatch': color } as CSSProperties} - > - {label} - {role} - - ))} -
+
+
+ {mode.title} + {mode.mode} +
+ {renderPressureDiagram(mode.title)} +

{mode.body}

+
) } -function renderHomeTypeSample(sample: string, className: string) { - const homeClassName = getHomeTypeClassName(className) +function renderPressureDiagram(title: (typeof pressureModes)[number]['title']): ReactNode { + switch (title) { + case 'Editorial': + return ( +
+ Q2 conversion rose 18% + + + + + Editorial chart + + + + +
+ ) + case 'Product': + return ( +
+ + + + + + +
+ ) + case 'Generative': + return ( +
+ Why did Q2 rise? + + + + Generative output chart + + +
+ ) + case 'Explainer': + return ( +
+ Input + + Process + + Output +
+ ) + } +} - return className === 'scaleBody' ? ( -

{sample}

- ) : ( - {sample} - ) +type SectionIntroProps = { + body: string + title: string } -function getHomeTypeClassName(className: string): string { - switch (className) { - case 'scaleDisplay': - return 'displayRole' - case 'scaleHero': - return 'heroRole' - default: - return className - } +function SectionIntro({ body, title }: SectionIntroProps) { + return ( +
+

{title}

+

{body}

+
+ ) } diff --git a/apps/docs/app/render/[kind]/[slug]/page.tsx b/apps/docs/app/render/[kind]/[slug]/page.tsx index 119daa9..732930f 100644 --- a/apps/docs/app/render/[kind]/[slug]/page.tsx +++ b/apps/docs/app/render/[kind]/[slug]/page.tsx @@ -13,7 +13,8 @@ type RenderPageProps = { export default async function RenderPage({ params, searchParams }: RenderPageProps) { const routeParams = await params - const query = parseRenderQuery(await searchParams) + const resolvedSearchParams = await searchParams + const query = parseRenderQuery(resolvedSearchParams) const item = getCatalogRenderItem(routeParams.kind, routeParams.slug) if (!item) { @@ -24,8 +25,8 @@ export default async function RenderPage({ params, searchParams }: RenderPagePro ) } diff --git a/apps/docs/app/styles/base.css b/apps/docs/app/styles/base.css index c566281..be270c7 100644 --- a/apps/docs/app/styles/base.css +++ b/apps/docs/app/styles/base.css @@ -60,16 +60,28 @@ body { opacity: 1; } -.navIconLink { +.navLogoLink { justify-content: center; - width: 28px; + width: 30px; padding: 0; + border: 1px solid var(--concrete-border-soft); + background: var(--concrete-raised); } -.navIconLink svg { +.navLogoLink svg { + display: block; + flex: none; +} + +.npmLogo { + width: 22px; + height: 8px; +} + +.githubLogo { width: 15px; height: 15px; - fill: currentColor; + fill: currentcolor; } .main { @@ -334,6 +346,66 @@ body { align-items: stretch; } +.detailContractGrid { + display: grid; + grid-template-columns: minmax(0, 0.85fr) minmax(280px, 0.7fr) minmax(320px, 1fr); + gap: 12px; +} + +.detailContractGrid article { + display: grid; + align-content: start; + gap: 10px; + min-width: 0; + padding: 16px; + border: 1px solid var(--concrete-border); + border-radius: var(--concrete-radius-4); + background: var(--concrete-surface); + box-shadow: var(--concrete-shadow-1); +} + +.detailContractGrid svg { + width: 18px; + height: 18px; + color: var(--concrete-sky); +} + +.detailContractGrid strong { + color: var(--concrete-foreground-strong); + font-size: 14px; + font-weight: 800; +} + +.detailContractGrid p { + color: var(--concrete-foreground-muted); + font-size: 12.5px; + line-height: 1.55; +} + +.detailRouteStack { + display: grid; + gap: 7px; +} + +.detailRouteStack code { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.detailSeedCard pre { + max-height: 240px; + margin: 0; + padding: 12px; + overflow: auto; + border: 1px solid var(--concrete-border-soft); + border-radius: var(--concrete-radius-3); + background: var(--concrete-sunken); + color: var(--concrete-foreground-body); + font: 600 11px / 1.55 var(--concrete-font-mono); +} + .playgroundPreview { display: grid; gap: 14px; diff --git a/apps/docs/app/styles/home.css b/apps/docs/app/styles/home.css index 9859295..6304c2b 100644 --- a/apps/docs/app/styles/home.css +++ b/apps/docs/app/styles/home.css @@ -1,910 +1,1309 @@ .docsHome { - width: min(1120px, calc(100vw - 48px)); + position: relative; + width: min(1320px, calc(100vw - 48px)); margin: 0 auto; + overflow-x: clip; + overflow-y: visible; } .docsChapter { - padding: 72px 0; + padding: 48px 0; border-bottom: 1px solid var(--concrete-border); scroll-margin-top: 72px; } -.docsHero { - padding-top: 64px; -} - -.chapterMeta { - display: grid; - grid-template-columns: auto 1fr auto; - gap: 12px; - align-items: baseline; - padding-bottom: 20px; - border-bottom: 1px solid var(--concrete-ink-9); - color: var(--concrete-foreground-muted); - font-size: 12px; - font-weight: 800; +.homeKicker, +.panelKicker { + color: var(--concrete-sky); + font: 800 10px / 1 var(--concrete-font-mono); letter-spacing: 0.08em; text-transform: uppercase; } -.chapterNumber { - color: var(--concrete-sky); +.heroEditorial h1, +.sectionIntro h2, +.agentIntro h2 { + margin: 0; + color: var(--concrete-foreground-strong); font-family: var(--concrete-font-display); - font-size: 28px; - font-style: italic; font-optical-sizing: var(--concrete-font-display-optical-sizing); font-synthesis: none; font-variation-settings: var(--concrete-font-display-settings); font-weight: 400; letter-spacing: 0; - line-height: 1; - text-transform: none; + text-wrap: balance; } -.chapterLabel { - color: var(--concrete-foreground-muted); +.docsHeroV3 { + position: relative; + display: grid; + grid-template-areas: + "copy preview" + "features preview"; + grid-template-columns: minmax(0, 0.92fr) minmax(470px, 1.08fr); + gap: 18px 64px; + align-items: center; + min-height: 660px; + padding: 58px 0 58px; + overflow: visible; + border-bottom: 1px solid var(--concrete-border); } -.docsChapter h1, -.docsChapter h2 { - max-width: 820px; - margin-top: 24px; - color: var(--concrete-foreground-strong); - font-family: var(--concrete-font-display); - font-size: 72px; - font-optical-sizing: var(--concrete-font-display-optical-sizing); - font-synthesis: none; - font-variation-settings: var(--concrete-font-display-settings); - font-weight: 400; - letter-spacing: 0; - line-height: 0.98; - text-wrap: balance; +.homeLatticeField { + position: absolute; + inset: 0; + opacity: 0.68; + pointer-events: none; + mask-image: linear-gradient(90deg, transparent, black 8%, black 92%, transparent); } -.docsChapter h2 { - max-width: 760px; - font-size: 56px; +.heroEditorial, +.heroComponentMount, +.heroFeatureRail { + position: relative; + z-index: 1; +} + +.heroEditorial { + grid-area: copy; + min-width: 0; +} + +.heroEditorial h1 { + max-width: 700px; + margin-top: 22px; + font-size: var(--concrete-type-72); + line-height: 0.94; +} + +.heroShipWord { + font-style: italic; + font-weight: 650; } .docsLead { - max-width: 760px; + max-width: 62ch; margin-top: 22px; color: var(--concrete-foreground-body); - font-size: 17px; - line-height: 1.6; + font-size: var(--concrete-type-17); + line-height: var(--concrete-line-loose); } -.heroInstall { - display: inline-grid; - grid-template-columns: auto minmax(0, 1fr); +.heroCommandRow { + display: flex; + min-width: 0; + margin-top: 24px; +} + +.copyCommand { + display: inline-flex; align-items: center; - max-width: 100%; - margin-top: 18px; + box-sizing: border-box; + min-width: 0; + max-width: min(100%, 390px); + height: 34px; + padding: 0; overflow: hidden; - border: 1px solid var(--concrete-border); + border: 1px solid var(--concrete-ink-9); border-radius: var(--concrete-radius-3); - background: var(--concrete-surface); - box-shadow: var(--concrete-shadow-1); + background: var(--concrete-ink-9); + box-shadow: var(--concrete-shadow-2); + color: var(--concrete-inverse-foreground); + font-family: var(--concrete-font-mono); + cursor: pointer; } -.heroInstall span, -.heroInstall code { +.copyCommand code { + flex: 1 1 auto; min-width: 0; - height: 34px; + padding: 0 13px; + overflow: hidden; + font: 800 var(--concrete-type-12) / 1 var(--concrete-font-mono); + text-overflow: ellipsis; + white-space: nowrap; } -.heroInstall span { +.copyCommand span { display: inline-flex; + flex: none; + gap: 6px; align-items: center; - padding: 0 11px; - border-right: 1px solid var(--concrete-border-soft); - color: var(--concrete-foreground-muted); - font: 800 11px / 1 var(--concrete-font-mono); - letter-spacing: 0.08em; + align-self: stretch; + padding: 0 10px; + border-left: 1px solid var(--concrete-inverse-border); + color: var(--concrete-inverse-muted); + font: 800 10px / 1 var(--concrete-font-mono); text-transform: uppercase; } -.heroInstall code { - display: inline-flex; +.copyCommand svg { + width: 13px; + height: 13px; +} + +.heroComponentMount { + grid-area: preview; + display: grid; + gap: 12px; + align-content: center; + min-width: 0; +} + +.heroComponentMount header { + display: flex; align-items: center; - padding: 0 12px; - overflow: hidden; - color: var(--concrete-foreground-strong); - font: 700 13px / 1 var(--concrete-font-mono); - text-overflow: ellipsis; - white-space: nowrap; + justify-content: space-between; + gap: 12px; + padding: 0 4px; + color: var(--concrete-foreground-soft); + font: 800 10px / 1 var(--concrete-font-mono); + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.heroComponentMount em { + font-style: normal; } -.heroBillboard { +.heroComposerStage { display: grid; - align-content: space-between; - min-height: 330px; - margin-top: 34px; - padding: 32px; - overflow: hidden; - border: 1px solid var(--concrete-border); - border-radius: var(--concrete-radius-4); - background-color: var(--concrete-surface); - background-image: + min-width: 0; + min-height: 318px; + place-items: center; + padding: 0; + overflow: visible; +} + +.heroComposerStage > * { + width: 100%; + max-width: 690px; + min-width: 0; +} + +.heroFeatureRail { + grid-area: features; + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px 14px; + max-width: 560px; + margin-top: 4px; + pointer-events: none; +} + +.heroFeatureRail .homeFeatureCard .concrete-tilt-frame-surface { + height: 100%; + border: 0; + border-radius: 0; + background: transparent; + box-shadow: none; +} + +.heroFeatureRail .homeFeatureCard .concrete-tilt-frame-content { + grid-template-columns: auto minmax(0, 1fr); + place-items: start; + gap: 7px; + min-height: 0; + padding: 0; + text-align: left; +} + +.heroFeatureRail [data-slot="feature-card-icon"] { + width: 22px; + height: 22px; + border-radius: var(--concrete-radius-2); + box-shadow: none; +} + +.heroFeatureRail [data-slot="feature-card-icon"] svg { + width: 12px; + height: 12px; +} + +.heroFeatureRail [data-slot="feature-card-body"] { + gap: 2px; + justify-items: start; +} + +.heroFeatureRail [data-slot="feature-card-body"] strong { + font-size: var(--concrete-type-11); + line-height: 1.1; +} + +.heroFeatureRail [data-slot="feature-card-body"] span { + max-width: none; + font-size: 10.5px; + line-height: 1.25; +} + +.sectionIntro { + display: grid; + gap: 10px; + max-width: 860px; + margin-bottom: 22px; +} + +.sectionIntro h2 { + max-width: 14ch; + font-size: var(--concrete-type-56); + line-height: 0.98; +} + +.sectionIntro p { + max-width: 72ch; + color: var(--concrete-foreground-muted); + font-size: var(--concrete-type-14); + line-height: var(--concrete-line-loose); +} + +.systemShowcase { + position: relative; + padding: 24px 0 28px; + overflow: visible; +} + +.systemShowcase::before { + position: absolute; + right: -10%; + bottom: -72px; + left: -10%; + height: 190px; + background: + linear-gradient(color-mix(in oklab, var(--concrete-sky) 18%, transparent) 1px, transparent 1px), linear-gradient( - 135deg, - color-mix(in oklab, var(--concrete-sky) 10%, transparent), - transparent 42% + 90deg, + color-mix(in oklab, var(--concrete-sky) 18%, transparent) 1px, + transparent 1px ), - linear-gradient(90deg, var(--concrete-lattice) 1px, transparent 1px), - linear-gradient(var(--concrete-lattice) 1px, transparent 1px); + linear-gradient(180deg, transparent, color-mix(in oklab, var(--concrete-sky) 5%, transparent)); background-size: - auto, - 28px 28px, - 28px 28px; - box-shadow: var(--concrete-shadow-2); + 32px 32px, + 32px 32px, + 100% 100%; + content: ""; + opacity: 0.58; + transform: perspective(680px) rotateX(66deg); + transform-origin: bottom center; } -.heroKicker, -.heroStrip { - color: var(--concrete-foreground-muted); - font: 800 12px / 1 var(--concrete-font-mono); - letter-spacing: 0.08em; - text-transform: uppercase; +.systemShowcase::after { + position: absolute; + right: -3%; + bottom: 54px; + left: -3%; + height: 1px; + background: linear-gradient(90deg, transparent, var(--concrete-border), transparent); + content: ""; + opacity: 0.8; + pointer-events: none; } -.heroBillboard p { - max-width: 720px; - margin: 0; +.systemLayerGrid { + position: relative; + z-index: 1; + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 26px; +} + +.systemLayerCard { + position: relative; + display: grid; + grid-template-rows: auto minmax(104px, 1fr) auto; + gap: 10px; + min-width: 0; + height: 270px; + padding: 16px; + overflow: visible; + border: 1px solid var(--concrete-border); + border-radius: var(--concrete-radius-4); + background: color-mix(in oklab, var(--concrete-surface) 93%, transparent); + box-shadow: + 0 8px 22px rgb(17 24 39 / 5%), + 0 1px 0 var(--concrete-border); + backdrop-filter: blur(8px); +} + +.systemLayerCard:not(:last-child)::after { + position: absolute; + top: 50%; + right: -25px; + z-index: 3; + width: 24px; + border-top: 1px dashed color-mix(in oklab, var(--concrete-sky) 34%, var(--concrete-border)); + content: ""; +} + +.systemLayerCard:not(:last-child)::before { + position: absolute; + top: calc(50% - 4px); + right: -26px; + z-index: 4; + width: 7px; + height: 7px; + border-top: 1px solid color-mix(in oklab, var(--concrete-sky) 42%, var(--concrete-border-strong)); + border-right: 1px solid color-mix(in oklab, var(--concrete-sky) 42%, var(--concrete-border-strong)); + content: ""; + transform: rotate(45deg); +} + +.systemLayerCard header { + display: grid; + gap: 4px; + min-width: 0; +} + +.docsHome .systemLayerCard header strong { color: var(--concrete-foreground-strong); - font-family: var(--concrete-font-display); - font-size: 72px; - font-optical-sizing: var(--concrete-font-display-optical-sizing); - font-synthesis: none; - font-variation-settings: var(--concrete-font-display-settings); - font-weight: 400; - letter-spacing: 0; - line-height: 0.94; + font-size: var(--concrete-type-15); + font-weight: 850; } -.heroBillboard em { - font-synthesis: none; - font-style: italic; +.systemLayerCard header span { + color: var(--concrete-foreground-muted); + font-size: var(--concrete-type-12); + line-height: var(--concrete-line-normal); } -.heroStrip { - display: flex; - flex-wrap: wrap; - gap: 8px; - padding-top: 16px; - border-top: 1px solid var(--concrete-border); +.systemLayerPreview { + display: grid; + min-width: 0; + min-height: 0; + align-content: stretch; + overflow: visible; } -.heroStrip span { - display: inline-flex; +.systemLayerCard footer { + display: flex; + gap: 10px; align-items: center; - height: 24px; - padding: 0 8px; - border: 1px solid var(--concrete-border-soft); - border-radius: var(--concrete-radius-pill); - background: color-mix(in oklab, var(--concrete-surface) 68%, transparent); + justify-content: space-between; + align-self: end; + min-width: 0; } -.docsSubhead { - display: grid; - grid-template-columns: 60px 1fr auto; - gap: 14px; - align-items: baseline; - margin: 42px 0 16px; +.systemLayerItems { + display: flex; + flex-wrap: nowrap; + gap: 0 7px; + align-content: start; + min-width: 0; + overflow: hidden; + color: var(--concrete-foreground-muted); + font-size: 9.5px; + font-weight: 700; + line-height: var(--concrete-line-normal); + white-space: nowrap; } -.docsSubhead span { +.systemLayerItems span:not(:last-child)::after { + margin-left: 7px; color: var(--concrete-foreground-soft); - font: 800 12px / 1 var(--concrete-font-mono); - letter-spacing: 0.08em; + content: "·"; } -.docsSubhead strong { - color: var(--concrete-foreground-strong); - font-size: 15px; +.systemLayerCard a { + display: inline-flex; + align-items: center; + flex: none; + justify-self: end; + color: var(--concrete-foreground-soft); + font-size: 10.5px; font-weight: 800; } -.docsSubhead em { +.systemLayerCard a:hover { color: var(--concrete-foreground-muted); - font-size: 13px; - font-style: normal; } -.foundationSplit { +.foundationPreview, +.primitivePreviewList, +.componentPreviewCard, +.applicationPreview { display: grid; - grid-template-columns: minmax(0, 1.1fr) minmax(360px, 0.9fr); - gap: 16px; -} - -.typeSpecimen, -.typeScaleCompact, -.colorFigure, -.densityGrid, -.foundationTrio, -.foundationUtilityGrid, -.iconSystem, -.homePrimitiveCard, -.componentFeatureCard, -.apiGrid > *, -.apiFooter { - border: 1px solid var(--concrete-border); - border-radius: var(--concrete-radius-4); - background: var(--concrete-surface); - box-shadow: var(--concrete-shadow-1); + width: 100%; + height: 100%; + min-width: 0; } -.typeSpecimen { - display: grid; - min-height: 370px; - align-items: center; - padding: 40px; - background-image: - linear-gradient(90deg, var(--concrete-lattice) 1px, transparent 1px), - linear-gradient(var(--concrete-lattice) 1px, transparent 1px); - background-size: 24px 24px; +.foundationPreview { + position: relative; + align-content: center; + gap: 14px; + padding: 0; + overflow: visible; } -.typeSpecimen p { - margin: 0; +.foundationSpecimen { + display: block; +} + +.systemLayerPreview .foundationSpecimen strong { color: var(--concrete-foreground-strong); font-family: var(--concrete-font-display); - font-size: 92px; - font-optical-sizing: var(--concrete-font-display-optical-sizing); - font-synthesis: none; - font-variation-settings: var(--concrete-font-display-settings); + font-size: 48px; font-weight: 400; letter-spacing: 0; - line-height: 0.9; + line-height: 0.85; } -.typeSpecimen em { - font-style: italic; +.miniSwatches { + display: grid; + grid-template-columns: repeat(5, 19px); + gap: 6px; + align-items: center; } -.typeScaleCompact { - display: grid; - align-content: start; - overflow: hidden; +.miniSwatches span { + width: 19px; + height: 19px; + border: 1px solid var(--concrete-border); + border-radius: var(--concrete-radius-2); + box-shadow: var(--concrete-shadow-1); } -.typeScaleCompact > div { - display: grid; - grid-template-columns: 84px minmax(0, 1fr); - gap: 14px; - align-items: baseline; - min-height: 74px; - padding: 16px; - border-bottom: 1px solid var(--concrete-border-soft); +.miniSwatches span:nth-child(1) { + background: var(--concrete-sky); } -.typeScaleCompact > div:last-child { - border-bottom: 0; +.miniSwatches span:nth-child(2) { + background: var(--concrete-sky-2); } -.typeScaleCompact span, -.typeScaleCompact em { - color: var(--concrete-foreground-soft); - font: 800 11px / 1.2 var(--concrete-font-mono); - font-style: normal; - letter-spacing: 0.06em; - text-transform: uppercase; +.miniSwatches span:nth-child(3) { + background: var(--concrete-ink-9); } -.typeScaleCompact strong, -.typeScaleCompact p { - margin: 0; - color: var(--concrete-foreground-strong); - font-size: 32px; - font-weight: 800; - line-height: 1.05; +.miniSwatches span:nth-child(4) { + background: var(--concrete-ink-2); } -.typeScaleCompact em { - grid-column: 2; +.miniSwatches span:nth-child(5) { + background: var(--concrete-surface); } -.typeScaleCompact p { - font-size: 15px; - font-weight: 400; - line-height: 1.45; +.foundationMarks { + display: flex; + gap: 7px; + align-items: center; + padding-top: 2px; } -.typeScaleCompact .displayRole, -.typeScaleCompact .heroRole { - font-family: var(--concrete-font-display); - font-optical-sizing: var(--concrete-font-display-optical-sizing); - font-synthesis: none; - font-variation-settings: var(--concrete-font-display-settings); - font-weight: 400; +.foundationMarks span { + display: block; + height: 15px; + border: 1px solid var(--concrete-border); + border-radius: var(--concrete-radius-3); + background: var(--concrete-raised); + box-shadow: inset 0 1px 0 var(--concrete-surface); } -.typeScaleCompact .displayRole { - font-size: 68px; +.foundationMarks span:nth-child(1) { + width: 22px; + border-radius: var(--concrete-radius-1); } -.typeScaleCompact .heroRole { - font-size: 46px; +.foundationMarks span:nth-child(2) { + width: 35px; + border-radius: var(--concrete-radius-3); } -.colorFigure { - display: grid; - gap: 1px; - overflow: hidden; - background: var(--concrete-border-soft); +.foundationMarks span:nth-child(3) { + width: 50px; + border-radius: var(--concrete-radius-5); } -.swatchGridCompact { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); - gap: 1px; +.primitivePreviewList { + gap: 8px; + align-content: center; + padding: 2px; } -.swatchGridCompact span { +.primitivePreviewRow { display: grid; - align-content: space-between; - min-height: 118px; - padding: 12px; - background: var(--home-swatch); - color: #fff; + grid-template-columns: 82px 1fr; + gap: 10px; + align-items: center; } -.swatchGridCompact .isLight { - color: var(--concrete-foreground-strong); +.primitivePreviewPillLine { + display: flex; + flex-wrap: nowrap; + gap: 9px; + align-items: center; + min-width: 0; + padding-left: 4px; } -.swatchGridCompact b, -.swatchGridCompact i { - display: block; +.primitiveInlineControls { + display: inline-flex; + gap: 8px; + align-items: center; + justify-content: flex-start; + margin-left: auto; min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } -.swatchGridCompact b { - font-size: 12px; - font-weight: 800; +.primitivePreviewList .concrete-field { + width: 100%; } -.swatchGridCompact i { - align-self: end; - font-size: 11px; - font-style: normal; - font-weight: 700; - opacity: 0.72; +.componentPreviewCard, +.applicationPreview { + align-items: center; + justify-items: center; + overflow: visible; +} + +.systemScaleFrame, +.systemScaleFrame .concrete-scale-frame-surface { + width: 100%; + height: 100%; } -.signalGrid { +.systemScaledComponent { display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 1px; + transform-origin: center; } -.signalTile { +.systemScaledComponentMenu { + width: 360px; +} + +.systemScaledApplication { + width: 400px; +} + +.applicationDashboardPreview { display: grid; - grid-template-columns: auto 1fr; - gap: 3px 10px; - align-items: center; - min-height: 78px; - padding: 14px; + gap: 8px; + width: 400px; + padding: 11px; + border: 1px solid var(--concrete-border); + border-radius: var(--concrete-radius-4); background: var(--concrete-surface); + box-shadow: var(--concrete-shadow-1); } -.signalTile i { - grid-row: span 2; - width: 12px; - height: 12px; - border-radius: var(--concrete-radius-pill); - box-shadow: 0 0 0 4px color-mix(in oklab, currentColor 8%, transparent); +.applicationDashboardPreview header, +.applicationDashboardRows span { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; } -.signalTile b { +.docsHome .applicationDashboardPreview header strong { color: var(--concrete-foreground-strong); - font-size: 13px; - text-transform: capitalize; + font-size: var(--concrete-type-13); + font-weight: 850; +} + +.applicationDashboardMetrics { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 6px; } -.signalTile span { +.applicationDashboardRows { + display: grid; + border: 1px solid var(--concrete-border-soft); + border-radius: var(--concrete-radius-3); + overflow: hidden; +} + +.applicationDashboardRows span { + padding: 7px 9px; + border-bottom: 1px solid var(--concrete-border-soft); color: var(--concrete-foreground-muted); - font-size: 12px; + font-size: var(--concrete-type-11); +} + +.applicationDashboardRows span:last-child { + border-bottom: 0; +} + +.applicationDashboardRows b { + color: var(--concrete-foreground-strong); + font-weight: 800; } -.densityGrid { +.applicationDashboardRows em { + color: var(--concrete-terminal); + font-style: normal; + font-weight: 800; +} + +.pressureExplainer { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); overflow: hidden; + border: 1px solid var(--concrete-border); + border-radius: var(--concrete-radius-5); + background: var(--concrete-surface); + box-shadow: + 0 8px 22px rgb(17 24 39 / 4%), + 0 1px 0 var(--concrete-border); } -.densityGrid article { +.pressureMode { display: grid; - gap: 4px; + grid-template-rows: auto 136px auto; + gap: 12px; + min-width: 0; padding: 16px; border-right: 1px solid var(--concrete-border); } -.densityGrid article:last-child { - border-right: 0; +.pressureMode:last-child { + border-right: 0; +} + +.pressureMode header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + padding-bottom: 10px; + border-bottom: 1px solid var(--concrete-border-soft); +} + +.docsHome .pressureMode header strong { + color: var(--concrete-foreground-strong); + font-size: var(--concrete-type-12); + font-weight: 850; + letter-spacing: 0.04em; + text-transform: uppercase; +} + +.pressureMode header em { + padding: 3px 8px; + border: 1px solid var(--concrete-border-soft); + border-radius: var(--concrete-radius-pill); + background: transparent; + color: var(--concrete-foreground-muted); + font-style: normal; + font-size: 10.5px; + font-weight: 750; +} + +.pressureDiagram { + position: relative; + display: grid; + height: 136px; + gap: 7px; + align-content: center; + padding: 14px; + overflow: hidden; + border: 1px solid var(--concrete-border-soft); + border-radius: var(--concrete-radius-4); + background: var(--concrete-raised); +} + +.pressureEditorialDiagram { + align-content: start; + padding: 18px; + background: + linear-gradient(color-mix(in oklab, var(--concrete-ultra) 7%, transparent) 1px, transparent 1px), + linear-gradient( + 90deg, + color-mix(in oklab, var(--concrete-ultra) 7%, transparent) 1px, + transparent 1px + ), + var(--concrete-surface); + background-size: 34px 34px; +} + +.docsHome .pressureEditorialDiagram strong { + max-width: 11ch; + color: var(--concrete-foreground-strong); + font-family: var(--concrete-font-display); + font-size: var(--concrete-type-22); + font-weight: 400; + line-height: 0.98; +} + +.pressureEditorialDiagram span { + position: absolute; + left: 18px; + height: 3px; + border-radius: var(--concrete-radius-pill); + background: color-mix(in oklab, var(--concrete-ink-3) 58%, transparent); +} + +.pressureEditorialDiagram span:nth-of-type(1) { + top: 80px; + width: 72px; +} + +.pressureEditorialDiagram span:nth-of-type(2) { + top: 91px; + width: 54px; +} + +.pressureEditorialDiagram span:nth-of-type(3) { + top: 102px; + width: 64px; } -.densityGrid strong { - color: var(--concrete-foreground-strong); - font-size: 15px; +.pressureMiniChart { + position: absolute; + right: 14px; + bottom: 13px; + width: 92px; + height: 56px; + overflow: visible; } -.densityGrid span { - color: var(--concrete-foreground-muted); - font-size: 12px; - line-height: 1.45; +.pressureMiniChart path { + stroke-linecap: round; + stroke-linejoin: round; } -.densityGrid i { - display: block; - height: 178px; - margin-top: 12px; - border: 1px solid var(--concrete-border-soft); - border-radius: var(--concrete-radius-3); - background-color: var(--concrete-surface); +.pressureMiniChart path:nth-of-type(1) { + fill: color-mix(in oklab, var(--concrete-sky) 9%, transparent); + stroke: none; } -.densityGrid i[data-density="editorial"] { - background-image: - linear-gradient( - 90deg, - color-mix(in oklab, var(--concrete-ultra) 16%, transparent) 1px, - transparent 1px - ), - linear-gradient(color-mix(in oklab, var(--concrete-ultra) 10%, transparent) 1px, transparent 1px); - background-size: 42px 28px; +.pressureMiniChart path:nth-of-type(2) { + fill: none; + stroke: color-mix(in oklab, var(--concrete-sky) 72%, var(--concrete-foreground-muted)); + stroke-width: 2; +} + +.pressureMiniChart path:nth-of-type(3) { + fill: none; + stroke: var(--concrete-border); + stroke-width: 1; } -.densityGrid i[data-density="product"] { - background-image: +.pressureProductDiagram { + grid-template-columns: repeat(4, minmax(0, 1fr)); + grid-template-rows: repeat(3, minmax(0, 1fr)); + gap: 6px; + padding: 10px; + background: + linear-gradient(color-mix(in oklab, var(--concrete-sky) 13%, transparent) 1px, transparent 1px), linear-gradient( 90deg, - color-mix(in oklab, var(--concrete-sky) 16%, transparent) 1px, + color-mix(in oklab, var(--concrete-sky) 13%, transparent) 1px, transparent 1px ), - linear-gradient(color-mix(in oklab, var(--concrete-sky) 12%, transparent) 1px, transparent 1px); - background-size: 14px 14px; + color-mix(in oklab, var(--concrete-sky) 2%, var(--concrete-surface)); + background-size: 11px 11px; } -.densityGrid i[data-density="generative"] { - background-image: linear-gradient( - color-mix(in oklab, var(--concrete-terminal) 15%, transparent) 1px, - transparent 1px - ); - background-size: 100% 28px; +.pressureProductDiagram span { + border: 1px solid color-mix(in oklab, var(--concrete-sky) 22%, var(--concrete-border)); + border-radius: var(--concrete-radius-3); + background: var(--concrete-surface); } -.densityGrid i[data-density="educational"] { - background: - linear-gradient(var(--concrete-surface), var(--concrete-surface)) center 38px / 72% 26px no-repeat, - linear-gradient(var(--concrete-surface), var(--concrete-surface)) center 88px / 58% 26px no-repeat, - linear-gradient(var(--concrete-surface), var(--concrete-surface)) center 138px / 66% 26px - no-repeat, - var(--concrete-sunken); +.pressureProductDiagram span:nth-child(1) { + grid-column: span 2; } -.foundationTrio { - display: grid; - grid-template-columns: minmax(0, 1.2fr) minmax(260px, 0.9fr) minmax(220px, 0.8fr); - gap: 0; - overflow: hidden; +.pressureProductDiagram span:nth-child(2) { + grid-column: span 2; } -.spacingScale { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - border-right: 1px solid var(--concrete-border); +.pressureProductDiagram span:nth-child(3) { + grid-column: span 3; } -.spacingScale span { - display: grid; - align-content: end; - min-height: 118px; - padding: 12px; - border-right: 1px solid var(--concrete-border-soft); - color: var(--concrete-foreground-muted); +.pressureProductDiagram span:nth-child(4) { + background: color-mix(in oklab, var(--concrete-sky) 10%, var(--concrete-surface)); } -.spacingScale span:nth-child(4n) { - border-right: 0; +.pressureProductDiagram span:nth-child(5) { + grid-column: span 2; } -.spacingScale span::before { - content: ""; - display: block; - width: var(--home-space); - height: var(--home-space); - margin-bottom: 12px; - border-radius: var(--concrete-radius-2); - background: var(--concrete-sky-2); - box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--concrete-sky) 14%, transparent); +.pressureProductDiagram span:nth-child(6) { + grid-column: span 2; + background: color-mix(in oklab, var(--concrete-sky) 6%, var(--concrete-surface)); } -.spacingScale b, -.spacingScale i, -.spacingScale em { - display: block; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; +.pressureGenerativeDiagram { + align-content: start; + gap: 7px; + padding: 12px; + background: + linear-gradient( + 180deg, + transparent 0 16px, + color-mix(in oklab, var(--concrete-terminal) 9%, transparent) 16px 17px, + transparent 17px 32px + ), + var(--concrete-surface); + background-size: 100% 32px; } -.spacingScale b { +.docsHome .pressureGenerativeDiagram strong { + justify-self: start; + padding: 6px 9px; + border-radius: var(--concrete-radius-pill); + background: color-mix(in oklab, var(--concrete-ink-2) 64%, var(--concrete-surface)); color: var(--concrete-foreground-strong); - font-size: 12px; - text-transform: uppercase; + font-size: var(--concrete-type-11); + font-weight: 750; } -.spacingScale i { - font: 800 11px / 1.3 var(--concrete-font-mono); - font-style: normal; +.pressureGenerativeDiagram span { + display: block; + height: 26px; + border: 1px solid color-mix(in oklab, var(--concrete-sky) 10%, var(--concrete-border)); + border-radius: var(--concrete-radius-3); + background: var(--concrete-surface); } -.spacingScale em { - color: var(--concrete-foreground-soft); - font-size: 11px; - font-style: normal; - font-weight: 700; +.pressureGenerativeDiagram span:nth-of-type(1) { + width: 84%; } -.radiusGrid { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - border-right: 1px solid var(--concrete-border); +.pressureGenerativeDiagram span:nth-of-type(2) { + width: 72%; } -.radiusGrid article { - display: grid; - gap: 6px; - padding: 12px; - border-right: 1px solid var(--concrete-border-soft); - border-bottom: 1px solid var(--concrete-border-soft); +.pressureTinySparkline { + width: 64%; + height: 22px; } -.radiusGrid article:nth-child(2n) { - border-right: 0; +.pressureTinySparkline path { + fill: none; + stroke: color-mix(in oklab, var(--concrete-sky) 58%, var(--concrete-foreground-muted)); + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 2; } -.radiusGrid i { - display: block; - height: 44px; - border: 1px solid var(--concrete-border); - border-radius: var(--home-radius); - background: var(--concrete-sunken); +.pressureExplainerDiagram { + place-items: center; + grid-template-rows: auto minmax(10px, 1fr) auto minmax(10px, 1fr) auto; + gap: 0; + padding: 16px 0; + background: + radial-gradient( + color-mix(in oklab, var(--concrete-ink-5) 36%, transparent) 1px, + transparent 1.5px + ), + color-mix(in oklab, var(--concrete-mist) 56%, var(--concrete-surface)); + background-size: 16px 16px; } -.radiusGrid b { +.pressureExplainerDiagram span { + position: relative; + width: 72px; + padding: 5px 0; + border: 1px solid var(--concrete-border); + border-radius: var(--concrete-radius-2); + background: var(--concrete-surface); color: var(--concrete-foreground-strong); - font: 800 11px / 1 var(--concrete-font-mono); + text-align: center; + font-size: 10px; + font-weight: 800; } -.radiusGrid span { - color: var(--concrete-foreground-muted); - font-size: 11px; +.pressureExplainerDiagram i { + position: relative; + width: 1px; + height: 100%; + min-height: 10px; + background: color-mix(in oklab, var(--concrete-sky) 28%, var(--concrete-border-strong)); + transform-origin: center; } -.elevationGrid { - display: grid; - align-content: stretch; - gap: 10px; - padding: 14px; +.pressureExplainerDiagram i::after { + position: absolute; + right: -2px; + bottom: 0; + width: 5px; + height: 5px; + border-right: 1px solid var(--concrete-border-strong); + border-bottom: 1px solid var(--concrete-border-strong); + content: ""; + transform: rotate(45deg); } -.elevationGrid span { - display: grid; - place-items: center; - min-height: 48px; - border: 1px solid var(--concrete-border); - border-radius: var(--concrete-radius-3); - background: var(--concrete-surface); +.pressureMode p { color: var(--concrete-foreground-muted); - font-size: 12px; - font-weight: 800; + font-size: var(--concrete-type-12); + line-height: var(--concrete-line-loose); } -.elevationGrid span:nth-child(2) { - box-shadow: var(--concrete-shadow-1); +.agentChapter { + position: relative; + display: grid; + grid-template-columns: minmax(320px, 0.9fr) minmax(0, 1.1fr); + gap: 42px; + margin: 48px 0; + padding: 36px; + overflow: hidden; + border: 1px solid var(--concrete-inverse-border); + border-radius: var(--concrete-radius-5); + background: var(--concrete-depth-background); + color: var(--concrete-inverse-foreground); + box-shadow: 0 1px 0 var(--concrete-inverse-border); } -.elevationGrid span:nth-child(3) { - box-shadow: var(--concrete-shadow-2); +.agentDepthTexture { + position: absolute; + inset: 0; + opacity: 0.48; + pointer-events: none; } -.elevationGrid span:nth-child(4) { - box-shadow: var(--concrete-shadow-3); +.agentIntro, +.agentContractSurface { + position: relative; + z-index: 1; } -.foundationUtilityGrid { +.agentIntro { display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 0; - overflow: hidden; + align-content: start; + gap: 20px; } -.motionFigure, -.focusFigure, -.textureFigure { - display: grid; - gap: 12px; - min-height: 190px; - padding: 16px; - border-right: 1px solid var(--concrete-border); +.agentIntro h2 { + max-width: 10ch; + color: var(--concrete-inverse-foreground); + font-size: var(--concrete-type-40); + line-height: 1.02; } -.textureFigure { - border-right: 0; - grid-template-columns: repeat(3, 1fr); +.agentIntro p { + max-width: 48ch; + color: var(--concrete-inverse-muted); + font-size: var(--concrete-type-13); + line-height: var(--concrete-line-loose); } -.motionFigure span { +.agentContractList { display: grid; - place-items: center; - border: 1px solid var(--concrete-border-soft); - border-radius: var(--concrete-radius-3); - background: var(--concrete-raised); - color: var(--concrete-foreground-muted); - font-size: 12px; - font-weight: 800; - transition: - transform var(--concrete-duration-fast) var(--concrete-ease), - background var(--concrete-duration-fast) var(--concrete-ease); + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 9px; } -.motionFigure span:hover { - transform: translateY(-1px); - background: var(--concrete-surface); +.agentContractList span { + display: inline-flex; + gap: 7px; + align-items: center; + color: var(--concrete-inverse-muted); + font-size: var(--concrete-type-12); + font-weight: 700; } -.focusFigure { - align-content: center; +.agentContractList svg { + width: 14px; + height: 14px; + color: var(--concrete-terminal); } -.focusFigure > * { - justify-self: start; +.agentGithubCallout { + display: grid; + gap: 8px; + margin-top: 8px; + padding: 14px; + border: 1px solid var(--concrete-inverse-border); + border-radius: var(--concrete-radius-4); + background: color-mix(in oklab, var(--concrete-ink-9) 62%, transparent); } -.homeFocusedButton { - outline: 3px solid var(--concrete-focus-ring); - outline-offset: 2px; +.agentChapter .agentGithubCallout strong { + color: var(--concrete-inverse-foreground); + font-size: var(--concrete-type-13); + font-weight: 850; } -.textureFigure > div { - min-height: 100%; - border: 1px solid var(--concrete-border-soft); +.agentChapter .agentGithubCallout p { + font-size: var(--concrete-type-12); + line-height: var(--concrete-line-normal); +} + +.agentGithubCallout a, +.footerInstall a { + display: inline-flex; + gap: 6px; + align-items: center; + justify-self: start; + height: 30px; + padding: 0 10px; + border: 1px solid var(--concrete-inverse-border); border-radius: var(--concrete-radius-3); + background: color-mix(in oklab, var(--concrete-ink-9) 62%, transparent); + color: var(--concrete-inverse-foreground); + font-size: var(--concrete-type-12); + font-weight: 800; +} + +.agentGithubCallout svg { + width: 13px; + height: 13px; } -.iconSystem { +.agentContractSurface { display: grid; - grid-template-columns: 280px 1fr; - gap: 0; - overflow: hidden; + grid-template-columns: 1fr; + align-content: stretch; + min-width: 0; } -.iconRules { +.agentSchemaPanel { display: grid; - border-right: 1px solid var(--concrete-border); + gap: 13px; + align-content: start; + min-width: 0; + padding: 22px; + border: 1px solid var(--concrete-inverse-border); + border-radius: var(--concrete-radius-4); + background: color-mix(in oklab, var(--concrete-ink-9) 78%, transparent); + box-shadow: inset 0 1px 0 var(--concrete-inverse-border); } -.iconRules span { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; - padding: 14px 16px; - border-bottom: 1px solid var(--concrete-border-soft); +.agentSchemaPanel .panelKicker { + color: var(--concrete-inverse-muted); } -.iconRules span:last-child { - border-bottom: 0; +.agentSchemaPanel pre { + min-width: 0; + margin: 0; + overflow: auto; + color: var(--concrete-terminal); + font: 600 var(--concrete-type-12) / 1.65 var(--concrete-font-mono); } -.iconRules b { - color: var(--concrete-foreground-strong); - font-size: 12px; +.renderContractDemo { + grid-template-rows: auto minmax(150px, 1fr) auto auto; } -.iconRules i { - color: var(--concrete-foreground-muted); - font: 800 11px / 1 var(--concrete-font-mono); - font-style: normal; +.renderContractHead { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; } -.iconLibrary { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); +.renderContractHead > span:last-child { + padding: 3px 8px; + border: 1px solid var(--concrete-inverse-border); + border-radius: var(--concrete-radius-pill); + background: color-mix(in oklab, var(--concrete-terminal) 16%, transparent); + color: var(--concrete-terminal); + font: 800 10.5px / 1 var(--concrete-font-mono); + text-transform: uppercase; } -.iconLibrary span { - display: inline-flex; - align-items: center; - gap: 8px; - min-height: 48px; - padding: 0 14px; - border-right: 1px solid var(--concrete-border-soft); - border-bottom: 1px solid var(--concrete-border-soft); - color: var(--concrete-foreground-muted); - font-size: 12px; - font-weight: 800; +.renderContractHead > span:last-child[data-valid="false"] { + background: color-mix(in oklab, var(--concrete-error) 13%, transparent); + color: var(--concrete-error); } -.iconLibrary svg { - width: 16px; - height: 16px; - color: var(--concrete-foreground-strong); +.renderContractDemo textarea { + box-sizing: border-box; + width: 100%; + min-height: 150px; + resize: vertical; + padding: 12px 13px; + border: 1px solid var(--concrete-inverse-border); + border-radius: var(--concrete-radius-3); + background: color-mix(in oklab, var(--concrete-ink-9) 66%, transparent); + color: var(--concrete-terminal); + font: 650 var(--concrete-type-12) / 1.6 var(--concrete-font-mono); + outline: none; + box-shadow: inset 0 1px 0 rgb(255 255 255 / 4%); } -.homePrimitiveGrid, -.componentFeatureGrid { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 16px; - margin-top: 32px; +.renderContractDemo textarea:focus { + border-color: color-mix(in oklab, var(--concrete-sky) 44%, var(--concrete-inverse-border)); + box-shadow: + 0 0 0 3px color-mix(in oklab, var(--concrete-sky) 13%, transparent), + inset 0 1px 0 rgb(255 255 255 / 4%); } -.homePrimitiveCard, -.componentFeatureCard { - position: relative; +.renderContractPreview { display: grid; - grid-template-rows: auto minmax(150px, 1fr); + grid-template-rows: auto 1fr; gap: 12px; + align-items: stretch; min-width: 0; - padding: 16px; - transition: - border-color var(--concrete-duration-fast) var(--concrete-ease), - background var(--concrete-duration-fast) var(--concrete-ease); + min-height: 132px; + padding: 12px; + border: 1px solid var(--concrete-inverse-border); + border-radius: var(--concrete-radius-3); + background: + radial-gradient(color-mix(in oklab, var(--concrete-sky) 12%, transparent) 1px, transparent 1.2px), + color-mix(in oklab, var(--concrete-ink-9) 54%, transparent); + background-size: 14px 14px; } -.homePrimitiveCard:hover, -.componentFeatureCard:hover { - border-color: var(--concrete-border-strong); - background: var(--concrete-raised); +.renderContractPreview[data-error="true"] { + border-color: color-mix(in oklab, var(--concrete-error) 36%, var(--concrete-inverse-border)); } -.homeCardOverlay { - position: absolute; - inset: 0; - z-index: 2; - border-radius: inherit; +.renderContractPreviewHead { + display: grid; + gap: 3px; + min-width: 0; } -.homePrimitiveCard header, -.componentFeatureCard header { - display: flex; - align-items: baseline; - justify-content: space-between; - gap: 12px; +.renderContractCanvas { + display: grid; + min-height: 92px; + place-items: center; + border: 1px solid color-mix(in oklab, var(--concrete-sky) 18%, var(--concrete-inverse-border)); + border-radius: var(--concrete-radius-3); + background: + linear-gradient(color-mix(in oklab, var(--concrete-sky) 6%, transparent) 1px, transparent 1px), + linear-gradient( + 90deg, + color-mix(in oklab, var(--concrete-sky) 6%, transparent) 1px, + transparent 1px + ), + color-mix(in oklab, var(--concrete-surface) 96%, var(--concrete-ink-1)); + background-size: 18px 18px; + box-shadow: + inset 0 1px 0 rgb(255 255 255 / 82%), + 0 10px 22px rgb(0 0 0 / 10%); } -.homePrimitiveCard strong, -.componentFeatureCard strong { - color: var(--concrete-foreground-strong); - font-size: 15px; +.renderContractPreview .concrete-button { + align-self: center; + justify-self: center; +} + +.renderContractPreview span { + overflow: hidden; + color: var(--concrete-inverse-foreground); + font-size: var(--concrete-type-12); font-weight: 800; + text-overflow: ellipsis; + white-space: nowrap; } -.homePrimitiveCard header span, -.componentFeatureCard header span { - color: var(--concrete-foreground-muted); - font-size: 12px; - font-weight: 700; +.renderContractPreview em { + color: var(--concrete-inverse-muted); + font-style: normal; + font-size: 10.5px; } -.homePrimitiveStage, -.componentFeatureStage { - position: relative; - display: grid; - align-self: stretch; - gap: 12px; - height: 100%; - min-width: 0; - place-items: center; - padding: 18px; - border: var(--concrete-border-width-hairline) solid var(--docs-stage-border); - border-radius: var(--concrete-radius-3); - background: var(--docs-stage-background); - box-shadow: var(--docs-stage-shadow-inset); - overflow: visible; +.agentRouteRow { + display: flex; + flex-wrap: wrap; + gap: 8px; } -.homePrimitiveStage > *, -.componentFeatureStage > * { - max-width: 100%; +.agentRouteRow a { + display: inline-flex; + gap: 7px; + align-items: center; + height: 30px; + padding: 0 10px; + border: 1px solid var(--concrete-inverse-border); + border-radius: var(--concrete-radius-3); + background: color-mix(in oklab, var(--concrete-ink-9) 62%, transparent); + color: var(--concrete-inverse-foreground); + font-size: var(--concrete-type-12); + font-weight: 850; } -.componentFeatureCard { - grid-template-rows: auto minmax(252px, 1fr) auto; +.agentRouteRow a svg { + width: 13px; + height: 13px; + color: var(--concrete-sky-3); } -.componentFeatureStage { +.docsFooter { + display: grid; + grid-template-columns: minmax(260px, 0.9fr) minmax(0, 1.1fr) minmax(280px, auto); + gap: 20px; align-items: center; - min-height: 252px; + margin-bottom: 34px; + padding: 14px 16px; + border: 1px solid var(--concrete-border); + border-radius: var(--concrete-radius-4); + background: + linear-gradient( + 180deg, + color-mix(in oklab, var(--concrete-surface) 94%, transparent), + transparent + ), + color-mix(in oklab, var(--concrete-raised) 72%, var(--concrete-surface)); + box-shadow: + 0 1px 0 var(--concrete-border), + 0 10px 24px rgb(17 24 39 / 4%); } -.componentFeatureCard p { - margin: 0; - color: var(--concrete-foreground-muted); - font-size: 12px; - line-height: 1.45; -} - -.componentFeatureStage[data-component="area-chart"], -.componentFeatureStage[data-component="bar-chart"], -.componentFeatureStage[data-component="command-menu"], -.componentFeatureStage[data-component="composer"], -.componentFeatureStage[data-component="chart"], -.componentFeatureStage[data-component="data-table"], -.componentFeatureStage[data-component="date-picker"], -.componentFeatureStage[data-component="date-range-picker"], -.componentFeatureStage[data-component="diagram-canvas"], -.componentFeatureStage[data-component="donut-chart"], -.componentFeatureStage[data-component="file-upload"], -.componentFeatureStage[data-component="flow-diagram"], -.componentFeatureStage[data-component="form-dialog"], -.componentFeatureStage[data-component="form-drawer"], -.componentFeatureStage[data-component="form-shell"], -.componentFeatureStage[data-component="heatmap"], -.componentFeatureStage[data-component="image-upload"], -.componentFeatureStage[data-component="line-chart"], -.componentFeatureStage[data-component="meter"], -.componentFeatureStage[data-component="metric-card"], -.componentFeatureStage[data-component="multi-select"], -.componentFeatureStage[data-component="search-bar"], -.componentFeatureStage[data-component="settings-panel"], -.componentFeatureStage[data-component="stacked-bar-chart"], -.componentFeatureStage[data-component="time-picker"] { - min-height: 320px; -} - -.componentFeatureStage[data-component="date-picker"], -.componentFeatureStage[data-component="date-range-picker"], -.componentFeatureStage[data-component="multi-select"], -.componentFeatureStage[data-component="time-picker"] { - align-items: start; -} - -.apiGrid { +.footerIntro { display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 14px; - margin-top: 32px; + grid-template-columns: auto 1fr; + gap: 2px 10px; + align-items: center; +} + +.footerIntro > span { + color: var(--concrete-foreground-soft); + font: 800 10px / 1 var(--concrete-font-mono); + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.footerWordmark { + width: 76px; + height: 28px; } -.apiGrid p { +.footerIntro p { + grid-column: 1 / -1; + max-width: 34ch; color: var(--concrete-foreground-muted); - font-size: 13px; - line-height: 1.55; + font-size: var(--concrete-type-12); + line-height: var(--concrete-line-normal); } -.apiCodeRows { +.footerRouteGrid { display: flex; flex-wrap: wrap; - gap: 8px; + gap: 6px 16px; + justify-content: center; +} + +.footerRouteGrid a { + display: inline-flex; align-items: center; + justify-content: center; + height: auto; + padding: 0; + border: 0; + background: transparent; + color: var(--concrete-foreground-muted); + font-size: var(--concrete-type-12); + font-weight: 800; +} + +.footerRouteGrid a:hover { + color: var(--concrete-foreground-strong); } -.apiSmoke { +.footerInstall { display: flex; flex-wrap: wrap; gap: 8px; + justify-content: flex-end; align-items: center; } -.apiFooter { - display: grid; - grid-template-columns: minmax(0, 1fr) auto; - gap: 18px; - align-items: center; - margin-top: 16px; - padding: 16px; +.footerInstall .copyCommand { + height: 30px; + box-shadow: none; } -.apiMetrics { - display: grid; - grid-template-columns: repeat(2, minmax(0, 0.5fr)) minmax(120px, 0.7fr) auto; - gap: 14px; - align-items: center; +.footerInstall .copyCommand code { + max-width: 230px; +} + +.footerInstall a { + border-color: var(--concrete-border); + background: var(--concrete-surface); + color: var(--concrete-foreground-strong); } diff --git a/apps/docs/app/styles/primitives.css b/apps/docs/app/styles/primitives.css index af300f0..099b977 100644 --- a/apps/docs/app/styles/primitives.css +++ b/apps/docs/app/styles/primitives.css @@ -3,5 +3,32 @@ } .primitiveConceptCard { + grid-column: span 3; min-width: 0; + padding: 14px; +} + +.primitiveConceptCard .conceptEyebrowRow { + margin-bottom: 10px; +} + +.primitiveConceptCard .conceptEyebrow { + font-size: var(--concrete-type-11); + letter-spacing: 0.08em; +} + +.primitiveConceptCard .conceptStage { + min-height: 132px; + padding: 12px; + overflow: hidden; + border: 1px solid var(--concrete-border-soft); + border-radius: var(--concrete-radius-3); + background: + linear-gradient(var(--concrete-lattice) 1px, transparent 1px), + linear-gradient(90deg, var(--concrete-lattice) 1px, transparent 1px), var(--concrete-canvas); + background-size: 18px 18px; +} + +.primitiveConceptCard .conceptStage > * { + max-width: 100%; } diff --git a/apps/docs/app/styles/responsive.css b/apps/docs/app/styles/responsive.css index a1a225b..4aa08e2 100644 --- a/apps/docs/app/styles/responsive.css +++ b/apps/docs/app/styles/responsive.css @@ -42,6 +42,7 @@ .componentPlaygroundStageDataGrid, .componentCatalogGrid, .componentStateGrid, + .detailContractGrid, .foundationCatalog, .primitiveCatalog, .foundationDataGrid { @@ -179,6 +180,51 @@ width: min(100vw - 32px, 1120px); } + .docsHeroV2, + .agentChapter, + .foundationPanelGrid, + .catalogHeader, + .readyPanel { + grid-template-columns: 1fr; + } + + .docsHeroV2 { + min-height: auto; + gap: 28px; + padding-top: 32px; + } + + .heroFeatureGrid, + .heroMiniGrid, + .systemLayerGrid, + .pressureGridV2, + .primitiveCatalogGrid, + .componentCatalogGridV2, + .applicationGrid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .systemLayerCard:nth-child(2n) { + border-right: 0; + } + + .systemLayerCard { + border-bottom: 1px solid var(--concrete-border); + } + + .systemLayerCard:nth-last-child(-n + 2) { + border-bottom: 0; + } + + .agentChapter { + margin: 54px 0; + } + + .catalogHeaderActions, + .readyPanel .readyActions { + justify-content: flex-start; + } + .docsChapter { padding: 54px 0; } @@ -258,8 +304,69 @@ width: min(100vw - 28px, 1120px); } + .docsHeroV2, + .agentChapter { + padding-right: 0; + padding-left: 0; + border-right: 0; + border-left: 0; + border-radius: 0; + } + + .heroFeatureGrid, + .heroMiniGrid, + .systemLayerGrid, + .pressureGridV2, + .primitiveCatalogGrid, + .componentCatalogGridV2, + .applicationGrid, + .texturePreviewGrid, + .agentMiniPanels, + .signalGridV2 { + grid-template-columns: 1fr; + } + + .sectionIntro { + grid-template-columns: 1fr; + gap: 14px; + } + + .sectionIntro p { + grid-column: 1; + } + + .heroEditorial h1 { + font-size: var(--concrete-type-56); + } + + .heroCommandRow, + .readyPanel .readyActions { + align-items: stretch; + flex-direction: column; + } + + .installSnippet, + .heroButton { + width: 100%; + justify-content: center; + } + + .systemLayerCard, + .systemLayerCard:nth-child(2n) { + border-right: 0; + border-bottom: 1px solid var(--concrete-border); + } + + .systemLayerCard:last-child { + border-bottom: 0; + } + + .spaceRadiusGrid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .docsChapter { - padding: 42px 0; + padding: 34px 0; scroll-margin-top: 96px; } @@ -327,3 +434,235 @@ .siteShell:has(.renderShell) .topbar { display: none; } + +@media (width <= 1240px) { + .systemLayerGrid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .systemLayerCard { + height: 238px; + } + + .systemLayerCard::before, + .systemLayerCard::after { + display: none; + } +} + +@media (width <= 1100px) { + .docsHeroV3, + .agentChapter, + .agentContractSurface, + .docsFooter, + .readyPanel { + grid-template-columns: 1fr; + } + + .docsHeroV3 { + grid-template-areas: + "copy" + "features" + "preview"; + min-height: auto; + gap: 24px; + padding-top: 34px; + padding-bottom: 44px; + } + + .heroComponentMount { + max-width: 760px; + } + + .pressureExplainer, + .footerRouteGrid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .systemLayerCard { + height: 238px; + } + + .systemLayerCard::before, + .systemLayerCard::after { + display: none; + } + + .pressureMode:nth-child(2n) { + border-right: 0; + } + + .pressureMode:nth-child(-n + 2) { + border-bottom: 1px solid var(--concrete-border); + } + + .footerInstall, + .readyPanel .readyActions { + justify-content: flex-start; + } + + .systemLayerCard, + .systemLayerCard:nth-child(2n), + .systemLayerCard:nth-last-child(-n + 2) { + border: 1px solid var(--concrete-border); + } + + .agentActionRow { + justify-content: flex-start; + } +} + +@media (width <= 720px) { + .docsHome { + width: min(100vw - 20px, 1120px); + } + + .nav { + gap: 2px 4px; + } + + .nav a { + padding: 0 8px; + } + + .nav .navLogoLink { + display: none; + } + + .docsHeroV3 { + grid-template-columns: 1fr; + gap: 18px; + padding: 24px 0 32px; + } + + .homeLatticeField { + opacity: 0.56; + } + + .heroEditorial h1, + .docsChapter .sectionIntro h2, + .agentIntro h2, + .readyPanel h2 { + max-width: none; + font-size: var(--concrete-type-32); + } + + .docsLead { + max-width: none; + margin-top: 14px; + font-size: var(--concrete-type-13); + line-height: var(--concrete-line-normal); + } + + .heroFeatureGrid, + .systemLayerGrid, + .pressureExplainer, + .agentContractList { + grid-template-columns: 1fr; + } + + .heroFeatureGrid { + gap: 14px; + } + + .heroFeatureRail { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 8px 10px; + } + + .heroFeatureGrid p { + max-width: none; + } + + .sectionIntro { + grid-template-columns: 1fr; + margin-bottom: 16px; + } + + .heroCommandRow, + .readyPanel .readyActions { + align-items: stretch; + flex-direction: column; + } + + .copyCommand, + .installSnippet, + .heroButton { + width: 100%; + max-width: 100%; + justify-content: center; + } + + .copyCommand span { + width: 34px; + justify-content: center; + padding: 0; + font-size: 0; + } + + .systemShowcase { + padding: 14px 0 22px; + } + + .systemLayerCard, + .systemLayerCard:nth-child(2n) { + height: auto; + min-height: 188px; + border: 1px solid var(--concrete-border); + } + + .systemLayerPreview { + min-height: 76px; + } + + .systemLayerCard footer { + justify-content: flex-end; + } + + .systemLayerItems { + display: none; + } + + .pressureMode, + .pressureMode:nth-child(2n), + .pressureMode:nth-child(-n + 2) { + border-right: 0; + border-bottom: 1px solid var(--concrete-border); + } + + .pressureMode { + grid-template-rows: auto 118px auto; + gap: 10px; + padding: 14px; + } + + .pressureDiagram { + height: 118px; + } + + .pressureMode:last-child { + border-bottom: 0; + } + + .agentChapter { + margin: 32px 0; + padding: 18px; + } + + .docsFooter { + align-items: stretch; + } + + .footerInstall { + justify-content: stretch; + } + + .footerRouteGrid { + gap: 6px 12px; + } + + .footerInstall a { + width: auto; + max-width: none; + } +} diff --git a/apps/docs/src/catalog-render-page.tsx b/apps/docs/src/catalog-render-page.tsx index 33cd123..c937c02 100644 --- a/apps/docs/src/catalog-render-page.tsx +++ b/apps/docs/src/catalog-render-page.tsx @@ -1,24 +1,30 @@ -import { Badge, type ConcretePressure } from '@rubriclab/concrete' +import { Badge, type RenderQuery } from '@rubriclab/concrete' import type { ReactNode } from 'react' import type { CatalogRenderItem } from '@/catalog-render-item' +import { renderDefinitionFromSearchParams, type SearchParamsInput } from '@/rendering' type CatalogRenderPageProps = CatalogRenderItem & { - pressure: ConcretePressure - state: string + query: RenderQuery + searchParams: SearchParamsInput } -export function CatalogRenderPage({ definition, entry, pressure, state }: CatalogRenderPageProps) { +export function CatalogRenderPage({ + definition, + entry, + query, + searchParams +}: CatalogRenderPageProps) { return ( -
+
- {definition.renderExample(state)} - {renderCatalogRenderMeta(entry.name, pressure)} + {renderDefinitionFromSearchParams(definition, searchParams, query.state)} + {renderCatalogRenderMeta(entry.name, query.pressure)}
) } -function renderCatalogRenderMeta(name: string, pressure: ConcretePressure): ReactNode { +function renderCatalogRenderMeta(name: string, pressure: RenderQuery['pressure']): ReactNode { return (
{name} diff --git a/apps/docs/src/component-playground.tsx b/apps/docs/src/component-playground.tsx index 915a132..5db56e3 100644 --- a/apps/docs/src/component-playground.tsx +++ b/apps/docs/src/component-playground.tsx @@ -1,12 +1,9 @@ 'use client' -import { - type ComponentRegistryEntry, - getComponentDefinition, - renderDefinitionInput -} from '@rubriclab/concrete' +import { type ComponentRegistryEntry, getComponentDefinition } from '@rubriclab/concrete' import { useSearchParams } from 'next/navigation' import { CatalogPlayground } from './catalog-playground' +import { renderDefinitionFromSearchParams } from './rendering' type ComponentPlaygroundProps = { entry: ComponentRegistryEntry @@ -19,7 +16,15 @@ export function ComponentPlayground({ entry }: ComponentPlaygroundProps) { return ( setCopied(false), 1400) + } catch { + setCopied(false) + } + } + + return ( + + ) +} diff --git a/apps/docs/src/primitive-playground.tsx b/apps/docs/src/primitive-playground.tsx index 1019757..6bd547d 100644 --- a/apps/docs/src/primitive-playground.tsx +++ b/apps/docs/src/primitive-playground.tsx @@ -1,12 +1,9 @@ 'use client' -import { - getPrimitiveDefinition, - type PrimitiveRegistryEntry, - renderDefinitionInput -} from '@rubriclab/concrete' +import { getPrimitiveDefinition, type PrimitiveRegistryEntry } from '@rubriclab/concrete' import { useSearchParams } from 'next/navigation' import { CatalogPlayground } from './catalog-playground' +import { renderDefinitionFromSearchParams } from './rendering' type PrimitivePlaygroundProps = { entry: PrimitiveRegistryEntry @@ -19,7 +16,15 @@ export function PrimitivePlayground({ entry }: PrimitivePlaygroundProps) { return ( ) diff --git a/apps/docs/src/render-contract-demo.tsx b/apps/docs/src/render-contract-demo.tsx new file mode 100644 index 0000000..bc22da5 --- /dev/null +++ b/apps/docs/src/render-contract-demo.tsx @@ -0,0 +1,134 @@ +'use client' + +import { Button, ConcreteIcon } from '@rubriclab/concrete' +import Link from 'next/link' +import type { ChangeEvent } from 'react' +import { useMemo, useState } from 'react' +import { z } from 'zod/v4' + +const renderableButtonVariants = ['primary', 'secondary', 'sky-soft', 'ultra'] as const + +const buttonContractSchema = z + .object({ + label: z.string().min(1).default('Ship'), + loading: z.boolean().default(false), + variant: z.enum(renderableButtonVariants).default('primary') + }) + .strict() + +type ButtonContract = z.output + +type ButtonContractResult = + | { + contract: ButtonContract + message?: never + success: true + } + | { + contract: ButtonContract + message: string + success: false + } + +const fallbackContract = buttonContractSchema.parse({ + label: 'Invalid JSON', + variant: 'secondary' +}) + +const initialContract = `{ + "label": "Ship", + "variant": "sky-soft", + "loading": false +}` + +export function RenderContractDemo() { + const [source, setSource] = useState(initialContract) + const result = useMemo(() => parseButtonContract(source), [source]) + const routeQuery = useMemo(() => createRouteQuery(result.contract), [result.contract]) + const reactRoute = `/render/primitive/button?${routeQuery}` + const imageRoute = `/render/primitive/button/screenshot?${routeQuery}` + + function updateSource(event: ChangeEvent) { + setSource(event.currentTarget.value) + } + + return ( +
+
+ Editable props JSON + {result.success ? 'Valid' : 'Schema error'} +
+