@awarebydefault/display-case 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +309 -0
- package/display-case.prompt.md +64 -0
- package/docs/ai-agents.md +126 -0
- package/docs/cli.md +99 -0
- package/docs/configuration.md +410 -0
- package/docs/documentation-panel.md +50 -0
- package/docs/examples/README.md +14 -0
- package/docs/examples/multi-variant.case.tsx +30 -0
- package/docs/examples/plain.case.tsx +22 -0
- package/docs/examples/tweak-control.placard.md +80 -0
- package/docs/examples/tweaks.case.tsx +39 -0
- package/docs/hierarchy.md +59 -0
- package/docs/quick-start.md +78 -0
- package/docs/style-engines.md +180 -0
- package/docs/testing.md +245 -0
- package/docs/theming.md +97 -0
- package/docs/tweaks.md +75 -0
- package/docs/writing-cases.md +144 -0
- package/docs/writing-placard-docs.md +194 -0
- package/package.json +113 -0
- package/skills/display-case-author-case/README.md +20 -0
- package/skills/display-case-author-case/SKILL.md +40 -0
- package/skills/display-case-author-placard-doc/README.md +24 -0
- package/skills/display-case-author-placard-doc/SKILL.md +65 -0
- package/skills/display-case-review/README.md +19 -0
- package/skills/display-case-review/SKILL.md +30 -0
- package/skills/display-case-snapshot/README.md +20 -0
- package/skills/display-case-snapshot/SKILL.md +29 -0
- package/src/checks/a11y-scanner.test.ts +240 -0
- package/src/checks/a11y-scanner.ts +410 -0
- package/src/checks/check-text.test.ts +53 -0
- package/src/checks/check-text.ts +78 -0
- package/src/checks/check.test.ts +194 -0
- package/src/checks/check.ts +473 -0
- package/src/checks/providers/pixelmatch-diff.test.ts +79 -0
- package/src/checks/providers/pixelmatch-diff.ts +30 -0
- package/src/checks/providers/playwright-driver.ts +104 -0
- package/src/checks/ssr-check.test.ts +73 -0
- package/src/checks/ssr-check.ts +96 -0
- package/src/checks/structure-check.cross-package.test.ts +165 -0
- package/src/checks/structure-check.test.ts +651 -0
- package/src/checks/structure-check.ts +988 -0
- package/src/checks/tokens-check.test.ts +159 -0
- package/src/checks/tokens-check.ts +162 -0
- package/src/cli.ts +218 -0
- package/src/commands/agents.test.ts +24 -0
- package/src/commands/agents.ts +28 -0
- package/src/commands/init-run.test.ts +123 -0
- package/src/commands/init.test.ts +63 -0
- package/src/commands/init.ts +412 -0
- package/src/commands/publish.test.ts +210 -0
- package/src/commands/publish.ts +292 -0
- package/src/core/affected.test.ts +99 -0
- package/src/core/affected.ts +144 -0
- package/src/core/catalog.test.ts +152 -0
- package/src/core/catalog.ts +92 -0
- package/src/core/discovery.test.ts +184 -0
- package/src/core/discovery.ts +250 -0
- package/src/core/manifest.ts +41 -0
- package/src/core/mdx-lite/__fixtures__/box-stub.tsx +7 -0
- package/src/core/mdx-lite/index.ts +393 -0
- package/src/core/mdx-lite/mdx-lite.test.ts +345 -0
- package/src/core/mdx-plugin.test.ts +60 -0
- package/src/core/mdx-plugin.ts +30 -0
- package/src/flow-step.test-d.ts +39 -0
- package/src/index.test.ts +100 -0
- package/src/index.ts +564 -0
- package/src/render/collect-styles.emotion.test.tsx +114 -0
- package/src/render/collect-styles.test.tsx +72 -0
- package/src/render/collect-styles.ts +33 -0
- package/src/render/documents.test.ts +184 -0
- package/src/render/documents.ts +88 -0
- package/src/render/render-node.test.tsx +160 -0
- package/src/render/render-node.tsx +133 -0
- package/src/render/ssr-primer.test.tsx +25 -0
- package/src/render/ssr-primer.tsx +54 -0
- package/src/render/ssr-render.test.tsx +142 -0
- package/src/render/ssr-render.tsx +63 -0
- package/src/render/ssr-shell.test.tsx +57 -0
- package/src/render/ssr-shell.tsx +54 -0
- package/src/server/prod-server.ts +237 -0
- package/src/server/server.test.ts +117 -0
- package/src/server/server.ts +1039 -0
- package/src/style-engine.test-d.ts +37 -0
- package/src/testing/test-helpers.ts +27 -0
- package/src/types/pixelmatch.d.ts +12 -0
- package/src/ui/browser-entry.tsx +51 -0
- package/src/ui/chrome.css +485 -0
- package/src/ui/design-system/README.md +88 -0
- package/src/ui/design-system/components/controls/Button.case.tsx +52 -0
- package/src/ui/design-system/components/controls/Button.css +89 -0
- package/src/ui/design-system/components/controls/Button.placard.md +14 -0
- package/src/ui/design-system/components/controls/Button.test.tsx +45 -0
- package/src/ui/design-system/components/controls/Button.tsx +41 -0
- package/src/ui/design-system/components/controls/IconButton.case.tsx +52 -0
- package/src/ui/design-system/components/controls/IconButton.css +67 -0
- package/src/ui/design-system/components/controls/IconButton.placard.md +13 -0
- package/src/ui/design-system/components/controls/IconButton.test.tsx +39 -0
- package/src/ui/design-system/components/controls/IconButton.tsx +47 -0
- package/src/ui/design-system/components/controls/Input.case.tsx +50 -0
- package/src/ui/design-system/components/controls/Input.css +52 -0
- package/src/ui/design-system/components/controls/Input.placard.md +12 -0
- package/src/ui/design-system/components/controls/Input.test.tsx +43 -0
- package/src/ui/design-system/components/controls/Input.tsx +45 -0
- package/src/ui/design-system/components/controls/Select.case.tsx +48 -0
- package/src/ui/design-system/components/controls/Select.css +44 -0
- package/src/ui/design-system/components/controls/Select.placard.md +15 -0
- package/src/ui/design-system/components/controls/Select.test.tsx +57 -0
- package/src/ui/design-system/components/controls/Select.tsx +58 -0
- package/src/ui/design-system/components/controls/SelectMenu.case.tsx +100 -0
- package/src/ui/design-system/components/controls/SelectMenu.css +72 -0
- package/src/ui/design-system/components/controls/SelectMenu.placard.md +18 -0
- package/src/ui/design-system/components/controls/SelectMenu.test.tsx +66 -0
- package/src/ui/design-system/components/controls/SelectMenu.tsx +377 -0
- package/src/ui/design-system/components/index.ts +66 -0
- package/src/ui/design-system/components/primer-specimen/ColorRamp.case.tsx +44 -0
- package/src/ui/design-system/components/primer-specimen/ColorRamp.placard.md +15 -0
- package/src/ui/design-system/components/primer-specimen/ColorRamp.tsx +51 -0
- package/src/ui/design-system/components/primer-specimen/DefinitionList.case.tsx +38 -0
- package/src/ui/design-system/components/primer-specimen/DefinitionList.placard.md +15 -0
- package/src/ui/design-system/components/primer-specimen/DefinitionList.tsx +41 -0
- package/src/ui/design-system/components/primer-specimen/FontFamilies.case.tsx +24 -0
- package/src/ui/design-system/components/primer-specimen/FontFamilies.placard.md +12 -0
- package/src/ui/design-system/components/primer-specimen/FontFamilies.tsx +41 -0
- package/src/ui/design-system/components/primer-specimen/GlyphGrid.case.tsx +27 -0
- package/src/ui/design-system/components/primer-specimen/GlyphGrid.placard.md +13 -0
- package/src/ui/design-system/components/primer-specimen/GlyphGrid.tsx +34 -0
- package/src/ui/design-system/components/primer-specimen/LayoutMock.case.tsx +36 -0
- package/src/ui/design-system/components/primer-specimen/LayoutMock.placard.md +7 -0
- package/src/ui/design-system/components/primer-specimen/LayoutMock.tsx +36 -0
- package/src/ui/design-system/components/primer-specimen/SpacingScale.case.tsx +20 -0
- package/src/ui/design-system/components/primer-specimen/SpacingScale.placard.md +12 -0
- package/src/ui/design-system/components/primer-specimen/SpacingScale.tsx +33 -0
- package/src/ui/design-system/components/primer-specimen/SpecimenBoxRow.case.tsx +56 -0
- package/src/ui/design-system/components/primer-specimen/SpecimenBoxRow.placard.md +17 -0
- package/src/ui/design-system/components/primer-specimen/SpecimenBoxRow.tsx +45 -0
- package/src/ui/design-system/components/primer-specimen/StatusList.case.tsx +17 -0
- package/src/ui/design-system/components/primer-specimen/StatusList.placard.md +16 -0
- package/src/ui/design-system/components/primer-specimen/StatusList.tsx +39 -0
- package/src/ui/design-system/components/primer-specimen/SwatchGrid.case.tsx +26 -0
- package/src/ui/design-system/components/primer-specimen/SwatchGrid.placard.md +15 -0
- package/src/ui/design-system/components/primer-specimen/SwatchGrid.tsx +42 -0
- package/src/ui/design-system/components/primer-specimen/TypeScale.case.tsx +23 -0
- package/src/ui/design-system/components/primer-specimen/TypeScale.placard.md +14 -0
- package/src/ui/design-system/components/primer-specimen/TypeScale.tsx +34 -0
- package/src/ui/design-system/components/primer-specimen/WeightSpecimen.case.tsx +28 -0
- package/src/ui/design-system/components/primer-specimen/WeightSpecimen.placard.md +15 -0
- package/src/ui/design-system/components/primer-specimen/WeightSpecimen.tsx +46 -0
- package/src/ui/design-system/components/primer-specimen/index.ts +31 -0
- package/src/ui/design-system/components/primer-specimen/styles.css +476 -0
- package/src/ui/design-system/components/shell/A11yPage.case.tsx +237 -0
- package/src/ui/design-system/components/shell/A11yPage.placard.md +15 -0
- package/src/ui/design-system/components/shell/CaseTemplate.case.tsx +32 -0
- package/src/ui/design-system/components/shell/CaseTemplate.placard.md +5 -0
- package/src/ui/design-system/components/shell/CasesPage.case.tsx +141 -0
- package/src/ui/design-system/components/shell/CasesPage.placard.md +12 -0
- package/src/ui/design-system/components/shell/PrimerPage.case.tsx +22 -0
- package/src/ui/design-system/components/shell/PrimerPage.placard.md +3 -0
- package/src/ui/design-system/components/shell/PrimerTemplate.case.tsx +22 -0
- package/src/ui/design-system/components/shell/PrimerTemplate.placard.md +5 -0
- package/src/ui/design-system/components/shell/ShellView.case.tsx +57 -0
- package/src/ui/design-system/components/shell/ShellView.placard.md +5 -0
- package/src/ui/design-system/components/shell/ShellView.tsx +678 -0
- package/src/ui/design-system/components/shell/shell-fixtures.tsx +727 -0
- package/src/ui/design-system/components/showcase/A11yBadge.case.tsx +46 -0
- package/src/ui/design-system/components/showcase/A11yBadge.css +27 -0
- package/src/ui/design-system/components/showcase/A11yBadge.placard.md +11 -0
- package/src/ui/design-system/components/showcase/A11yBadge.test.tsx +31 -0
- package/src/ui/design-system/components/showcase/A11yBadge.tsx +41 -0
- package/src/ui/design-system/components/showcase/A11yPanel.case.tsx +121 -0
- package/src/ui/design-system/components/showcase/A11yPanel.css +198 -0
- package/src/ui/design-system/components/showcase/A11yPanel.placard.md +19 -0
- package/src/ui/design-system/components/showcase/A11yPanel.test.tsx +81 -0
- package/src/ui/design-system/components/showcase/A11yPanel.tsx +144 -0
- package/src/ui/design-system/components/showcase/Chip.case.tsx +48 -0
- package/src/ui/design-system/components/showcase/Chip.css +51 -0
- package/src/ui/design-system/components/showcase/Chip.placard.md +13 -0
- package/src/ui/design-system/components/showcase/Chip.test.tsx +46 -0
- package/src/ui/design-system/components/showcase/Chip.tsx +54 -0
- package/src/ui/design-system/components/showcase/Eyebrow.case.tsx +30 -0
- package/src/ui/design-system/components/showcase/Eyebrow.css +16 -0
- package/src/ui/design-system/components/showcase/Eyebrow.placard.md +10 -0
- package/src/ui/design-system/components/showcase/Eyebrow.test.tsx +38 -0
- package/src/ui/design-system/components/showcase/Eyebrow.tsx +29 -0
- package/src/ui/design-system/components/showcase/FlowNav.case.tsx +35 -0
- package/src/ui/design-system/components/showcase/FlowNav.css +29 -0
- package/src/ui/design-system/components/showcase/FlowNav.placard.md +13 -0
- package/src/ui/design-system/components/showcase/FlowNav.test.tsx +48 -0
- package/src/ui/design-system/components/showcase/FlowNav.tsx +58 -0
- package/src/ui/design-system/components/showcase/ImpactTag.case.tsx +19 -0
- package/src/ui/design-system/components/showcase/ImpactTag.css +36 -0
- package/src/ui/design-system/components/showcase/ImpactTag.placard.md +14 -0
- package/src/ui/design-system/components/showcase/ImpactTag.test.tsx +40 -0
- package/src/ui/design-system/components/showcase/ImpactTag.tsx +35 -0
- package/src/ui/design-system/components/showcase/NavItem.case.tsx +86 -0
- package/src/ui/design-system/components/showcase/NavItem.css +111 -0
- package/src/ui/design-system/components/showcase/NavItem.placard.md +13 -0
- package/src/ui/design-system/components/showcase/NavItem.test.tsx +65 -0
- package/src/ui/design-system/components/showcase/NavItem.tsx +95 -0
- package/src/ui/design-system/components/showcase/RenderAddress.case.tsx +21 -0
- package/src/ui/design-system/components/showcase/RenderAddress.css +35 -0
- package/src/ui/design-system/components/showcase/RenderAddress.placard.md +7 -0
- package/src/ui/design-system/components/showcase/RenderAddress.test.tsx +26 -0
- package/src/ui/design-system/components/showcase/RenderAddress.tsx +43 -0
- package/src/ui/design-system/components/showcase/SegmentedToggle.case.tsx +84 -0
- package/src/ui/design-system/components/showcase/SegmentedToggle.css +61 -0
- package/src/ui/design-system/components/showcase/SegmentedToggle.placard.md +21 -0
- package/src/ui/design-system/components/showcase/SegmentedToggle.test.tsx +81 -0
- package/src/ui/design-system/components/showcase/SegmentedToggle.tsx +75 -0
- package/src/ui/design-system/components/showcase/Sidebar.case.tsx +67 -0
- package/src/ui/design-system/components/showcase/Sidebar.css +6 -0
- package/src/ui/design-system/components/showcase/Sidebar.placard.md +14 -0
- package/src/ui/design-system/components/showcase/Sidebar.test.tsx +32 -0
- package/src/ui/design-system/components/showcase/Sidebar.tsx +30 -0
- package/src/ui/design-system/components/showcase/Stage.case.tsx +51 -0
- package/src/ui/design-system/components/showcase/Stage.css +91 -0
- package/src/ui/design-system/components/showcase/Stage.placard.md +15 -0
- package/src/ui/design-system/components/showcase/Stage.test.tsx +84 -0
- package/src/ui/design-system/components/showcase/Stage.tsx +97 -0
- package/src/ui/design-system/components/showcase/TweaksPanel.case.tsx +81 -0
- package/src/ui/design-system/components/showcase/TweaksPanel.css +169 -0
- package/src/ui/design-system/components/showcase/TweaksPanel.placard.md +20 -0
- package/src/ui/design-system/components/showcase/TweaksPanel.tsx +230 -0
- package/src/ui/design-system/components/showcase/Wordmark.case.tsx +42 -0
- package/src/ui/design-system/components/showcase/Wordmark.css +31 -0
- package/src/ui/design-system/components/showcase/Wordmark.placard.md +10 -0
- package/src/ui/design-system/components/showcase/Wordmark.test.tsx +22 -0
- package/src/ui/design-system/components/showcase/Wordmark.tsx +22 -0
- package/src/ui/design-system/primer-specimens/brand.tsx +26 -0
- package/src/ui/design-system/primer-specimens/colors.tsx +83 -0
- package/src/ui/design-system/primer-specimens/components.tsx +308 -0
- package/src/ui/design-system/primer-specimens/foundations.tsx +71 -0
- package/src/ui/design-system/primer-specimens/index.ts +25 -0
- package/src/ui/design-system/primer-specimens/showcase.tsx +68 -0
- package/src/ui/design-system/primer-specimens/spacing.tsx +101 -0
- package/src/ui/design-system/primer-specimens/type.tsx +75 -0
- package/src/ui/design-system/primer.mdx +236 -0
- package/src/ui/design-system/styles.css +14 -0
- package/src/ui/design-system/tokens/colors.css +172 -0
- package/src/ui/design-system/tokens/fonts.css +18 -0
- package/src/ui/design-system/tokens/spacing.css +48 -0
- package/src/ui/design-system/tokens/typography.css +49 -0
- package/src/ui/markdown.test.tsx +54 -0
- package/src/ui/markdown.tsx +19 -0
- package/src/ui/primer-mount.tsx +76 -0
- package/src/ui/primer.css +175 -0
- package/src/ui/primer.tsx +277 -0
- package/src/ui/render-mount.tsx +284 -0
- package/src/ui/shell-core.test.ts +340 -0
- package/src/ui/shell-core.ts +295 -0
- package/src/ui/shell.tsx +60 -0
- package/src/ui/test-ids.ts +53 -0
- package/src/ui/use-shell.ts +1230 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive showcase specimens for Display Case's own Primer. These wrap
|
|
3
|
+
* stateful behaviour the MDX can't express inline: the FlowNav stepper (tracks
|
|
4
|
+
* the active step) and the TweaksPanel demo.
|
|
5
|
+
*
|
|
6
|
+
* The render-address bar is the reusable {@link RenderAddress} showcase
|
|
7
|
+
* component (under `components/showcase/`); this module just supplies Display
|
|
8
|
+
* Case's default URL.
|
|
9
|
+
*/
|
|
10
|
+
import { useState } from 'react'
|
|
11
|
+
import {
|
|
12
|
+
FlowNav,
|
|
13
|
+
Input,
|
|
14
|
+
Select,
|
|
15
|
+
RenderAddress as SpecimenRenderAddress,
|
|
16
|
+
TweaksPanel,
|
|
17
|
+
} from '../components'
|
|
18
|
+
|
|
19
|
+
const FLOW_STEPS = [
|
|
20
|
+
{ id: 'Request link', label: 'Request link' },
|
|
21
|
+
{ id: 'Check email', label: 'Check email' },
|
|
22
|
+
{ id: 'Signed in', label: 'Signed in' },
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
export function FlowNavDemo() {
|
|
26
|
+
const [active, setActive] = useState('Check email')
|
|
27
|
+
return (
|
|
28
|
+
<div className="dcpl-block">
|
|
29
|
+
<FlowNav steps={FLOW_STEPS} activeId={active} onSelect={setActive} />
|
|
30
|
+
</div>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function TweaksPanelDemo() {
|
|
35
|
+
const items = [
|
|
36
|
+
{
|
|
37
|
+
label: 'label',
|
|
38
|
+
control: (
|
|
39
|
+
<Input size="sm" defaultValue="Snapshot" style={{ width: '8rem' }} />
|
|
40
|
+
),
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: 'variant',
|
|
44
|
+
control: <Select size="sm" options={['ghost', 'accent']} />,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
label: 'disabled',
|
|
48
|
+
control: <input type="checkbox" aria-label="disabled" />,
|
|
49
|
+
},
|
|
50
|
+
]
|
|
51
|
+
return (
|
|
52
|
+
<div style={{ width: '100%', maxWidth: '24rem', margin: '0 auto' }}>
|
|
53
|
+
<TweaksPanel
|
|
54
|
+
url="?t.variant=accent"
|
|
55
|
+
items={items}
|
|
56
|
+
onToggleMode={() => {}}
|
|
57
|
+
/>
|
|
58
|
+
</div>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function RenderAddress({
|
|
63
|
+
url = '/render/button/playground?theme=light&t.variant=accent',
|
|
64
|
+
}: {
|
|
65
|
+
url?: string
|
|
66
|
+
}) {
|
|
67
|
+
return <SpecimenRenderAddress url={url} />
|
|
68
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spacing specimens for Display Case's own Primer — the tight rem-based spacing
|
|
3
|
+
* scale, the modest corner radii, and the flat, border-led elevation model
|
|
4
|
+
* (shadow is reserved for genuinely floating layers).
|
|
5
|
+
*
|
|
6
|
+
* Thin wrappers over the reusable {@link SpacingScale}/{@link SpecimenBoxRow}
|
|
7
|
+
* primitives (under `components/primer-specimen/`); the Display-Case-specific
|
|
8
|
+
* data lives here.
|
|
9
|
+
*/
|
|
10
|
+
import {
|
|
11
|
+
type BoxSpec,
|
|
12
|
+
type SpaceStep,
|
|
13
|
+
SpecimenBoxRow,
|
|
14
|
+
SpacingScale as SpecimenSpacingScale,
|
|
15
|
+
} from '../components/primer-specimen'
|
|
16
|
+
|
|
17
|
+
const SPACE: SpaceStep[] = [
|
|
18
|
+
{ token: 'space-1', value: '2px', width: 2 },
|
|
19
|
+
{ token: 'space-2', value: '4px', width: 4 },
|
|
20
|
+
{ token: 'space-3', value: '6px', width: 6 },
|
|
21
|
+
{ token: 'space-4', value: '8px', width: 8 },
|
|
22
|
+
{ token: 'space-6', value: '12px', width: 12 },
|
|
23
|
+
{ token: 'space-8', value: '16px', width: 16 },
|
|
24
|
+
{ token: 'space-10', value: '20px', width: 20 },
|
|
25
|
+
{ token: 'space-16', value: '32px', width: 32 },
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
const RADII: BoxSpec[] = [
|
|
29
|
+
{ label: 'none', note: '0', boxStyle: { borderRadius: '0' } },
|
|
30
|
+
{
|
|
31
|
+
label: 'sm',
|
|
32
|
+
note: '5px · controls',
|
|
33
|
+
boxStyle: { borderRadius: 'var(--dc-radius-sm)' },
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
label: 'md',
|
|
37
|
+
note: '8px · panels',
|
|
38
|
+
boxStyle: { borderRadius: 'var(--dc-radius-md)' },
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
label: 'lg',
|
|
42
|
+
note: '12px · overlays',
|
|
43
|
+
boxStyle: { borderRadius: 'var(--dc-radius-lg)' },
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
label: 'full',
|
|
47
|
+
note: 'pills · dots',
|
|
48
|
+
boxStyle: { borderRadius: 'var(--dc-radius-full)', width: '48px' },
|
|
49
|
+
},
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
// The elevation boxes share a wider surface-on-shadow shape; only the border /
|
|
53
|
+
// shadow differs per item.
|
|
54
|
+
const elevBox = (extra: BoxSpec['boxStyle']): BoxSpec['boxStyle'] => ({
|
|
55
|
+
width: '134px',
|
|
56
|
+
height: '56px',
|
|
57
|
+
background: 'var(--dc-surface)',
|
|
58
|
+
borderRadius: 'var(--dc-radius-md)',
|
|
59
|
+
...extra,
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const ELEVATION: BoxSpec[] = [
|
|
63
|
+
{
|
|
64
|
+
note: 'border-line',
|
|
65
|
+
content: '1px border',
|
|
66
|
+
boxStyle: elevBox({ border: 'var(--dc-border-line)' }),
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
note: 'border-strong',
|
|
70
|
+
content: 'strong',
|
|
71
|
+
boxStyle: elevBox({ border: '1px solid var(--dc-border-strong)' }),
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
note: 'rare — hairline lift',
|
|
75
|
+
content: 'shadow-sm',
|
|
76
|
+
boxStyle: elevBox({
|
|
77
|
+
border: 'var(--dc-border-line)',
|
|
78
|
+
boxShadow: 'var(--dc-shadow-sm)',
|
|
79
|
+
}),
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
note: 'menus / popovers only',
|
|
83
|
+
content: 'overlay',
|
|
84
|
+
boxStyle: elevBox({
|
|
85
|
+
border: 'var(--dc-border-line)',
|
|
86
|
+
boxShadow: 'var(--dc-shadow-overlay)',
|
|
87
|
+
}),
|
|
88
|
+
},
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
export function SpacingScale() {
|
|
92
|
+
return <SpecimenSpacingScale steps={SPACE} />
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function RadiusRow() {
|
|
96
|
+
return <SpecimenBoxRow items={RADII} />
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function ElevationRow() {
|
|
100
|
+
return <SpecimenBoxRow items={ELEVATION} />
|
|
101
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type specimens for Display Case's own Primer — the two-family pairing (Hanken
|
|
3
|
+
* Grotesk for chrome, JetBrains Mono for developer texture), the dense px-based
|
|
4
|
+
* size scale, and the three weights plus the signature uppercase eyebrow label.
|
|
5
|
+
*
|
|
6
|
+
* Thin wrappers over the reusable {@link FontFamilies}/{@link TypeScale}/
|
|
7
|
+
* {@link WeightSpecimen} primitives (under `components/primer-specimen/`); the
|
|
8
|
+
* Display-Case-specific data lives here.
|
|
9
|
+
*/
|
|
10
|
+
import { Eyebrow } from '../components'
|
|
11
|
+
import {
|
|
12
|
+
type FontFamily,
|
|
13
|
+
FontFamilies as SpecimenFontFamilies,
|
|
14
|
+
TypeScale as SpecimenTypeScale,
|
|
15
|
+
type TypeStep,
|
|
16
|
+
type WeightSpec,
|
|
17
|
+
WeightSpecimen,
|
|
18
|
+
} from '../components/primer-specimen'
|
|
19
|
+
|
|
20
|
+
const FAMILIES: FontFamily[] = [
|
|
21
|
+
{
|
|
22
|
+
tag: 'Sans · UI',
|
|
23
|
+
sample: 'Display Case shows the work, not itself',
|
|
24
|
+
note: 'Hanken Grotesk, ui-sans-serif, system-ui, "Segoe UI", Roboto…',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
tag: 'Mono · Code',
|
|
28
|
+
sample: '/render/<component>/<case>?theme=dark',
|
|
29
|
+
note: 'JetBrains Mono, ui-monospace, "SF Mono", Menlo…',
|
|
30
|
+
mono: true,
|
|
31
|
+
},
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
const SCALE: TypeStep[] = [
|
|
35
|
+
{ tag: 'xl · 28', size: '28px', sample: 'Doc heading' },
|
|
36
|
+
{ tag: 'lg · 20', size: '20px', sample: 'Section title' },
|
|
37
|
+
{ tag: 'md · 16', size: '16px', sample: 'Icon glyph / emphasis' },
|
|
38
|
+
{
|
|
39
|
+
tag: 'base · 14',
|
|
40
|
+
size: '14px',
|
|
41
|
+
sample: 'Chrome baseline — nav, buttons, body',
|
|
42
|
+
},
|
|
43
|
+
{ tag: 'sm · 12', size: '12px', sample: 'Secondary — zoom %, captions' },
|
|
44
|
+
{ tag: 'xs · 11', size: '11px', sample: 'Eyebrow labels, dimension hints' },
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
const WEIGHTS: WeightSpec[] = [
|
|
48
|
+
{ weight: 400, name: 'Normal', role: 'body' },
|
|
49
|
+
{ weight: 500, name: 'Medium', role: 'active' },
|
|
50
|
+
{ weight: 600, name: 'Semibold', role: 'titles' },
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
export function FontFamilies() {
|
|
54
|
+
return <SpecimenFontFamilies families={FAMILIES} />
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function TypeScale() {
|
|
58
|
+
return <SpecimenTypeScale steps={SCALE} />
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function Weights() {
|
|
62
|
+
return (
|
|
63
|
+
<WeightSpecimen
|
|
64
|
+
weights={WEIGHTS}
|
|
65
|
+
footer={
|
|
66
|
+
<>
|
|
67
|
+
<div className="dcpl-divider" />
|
|
68
|
+
<Eyebrow>
|
|
69
|
+
Components · group label · 11px / 500 / 0.08em uppercase
|
|
70
|
+
</Eyebrow>
|
|
71
|
+
</>
|
|
72
|
+
}
|
|
73
|
+
/>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { Button, Eyebrow, Stage, Wordmark } from './components'
|
|
2
|
+
import { MarigoldRamp, PaperRamp, SemanticSwatches, StatusHues, DefList, StatesRow, LayoutMock, FontFamilies, TypeScale, Weights, SpacingScale, RadiusRow, ElevationRow, Glyphs, RenderAddress, ControlsOverview, ShowcaseOverview, PrimerOverview } from './primer-specimens'
|
|
3
|
+
|
|
4
|
+
<Eyebrow tone="accent">Primer</Eyebrow>
|
|
5
|
+
|
|
6
|
+
# Design System
|
|
7
|
+
|
|
8
|
+
Display Case is **chrome that defers to the content**. Its whole job is to frame
|
|
9
|
+
someone else's component — the exhibit — so the showcase itself stays quiet,
|
|
10
|
+
warm, and legible. It's Bun-native, AI-forward, and a lightweight alternative to
|
|
11
|
+
Storybook. This page is the **Primer**: long-form wall text with embedded live
|
|
12
|
+
specimens, authored in MDX and dogfooding the design system's own components.
|
|
13
|
+
|
|
14
|
+
<Display
|
|
15
|
+
title="Wordmark"
|
|
16
|
+
subtitle="Type-only lockup — brackets frame the name like a case">
|
|
17
|
+
<Wordmark style={{ fontSize: '0.875rem' }}>Display Case</Wordmark>
|
|
18
|
+
<Wordmark style={{ fontSize: '1.5rem' }}>Display Case</Wordmark>
|
|
19
|
+
<Wordmark style={{ fontSize: '2.25rem' }}>Display Case</Wordmark>
|
|
20
|
+
</Display>
|
|
21
|
+
|
|
22
|
+
Three ideas shape every decision here. **Defer to the content** — the chrome is
|
|
23
|
+
small, warm, and recessive; the component on the stage owns the visual weight.
|
|
24
|
+
**Have a little charm** — paper neutrals, a single marigold accent, a bracketed
|
|
25
|
+
wordmark, soft corner ticks; crafted, not clinical. **Be legible to machines** —
|
|
26
|
+
deterministic render URLs, a manifest-first mindset, grouped addressable controls.
|
|
27
|
+
|
|
28
|
+
## Content fundamentals
|
|
29
|
+
|
|
30
|
+
How Display Case writes. The vibe is a calm museum primer, not a marketing
|
|
31
|
+
page — quietly opinionated, never shouting, never decorating the copy.
|
|
32
|
+
|
|
33
|
+
<Display
|
|
34
|
+
title="Voice & mechanics"
|
|
35
|
+
subtitle="The rules every label, button, and line of copy follows"
|
|
36
|
+
flush>
|
|
37
|
+
<DefList />
|
|
38
|
+
</Display>
|
|
39
|
+
|
|
40
|
+
## Visual foundations
|
|
41
|
+
|
|
42
|
+
The "Vitrine" identity — warm, editorial, flat, and quiet. Detailed specimens
|
|
43
|
+
for colour, type, and spacing follow in their own sections; these are the
|
|
44
|
+
principles that bind them.
|
|
45
|
+
|
|
46
|
+
**Elevation** is flat by default — the only thing that lifts is a genuinely
|
|
47
|
+
floating layer (a menu or popover). Everything else is border-led; there are no
|
|
48
|
+
card shadows. **Backgrounds** carry no gradients, photos, or patterns; the one
|
|
49
|
+
permitted texture is the faint dotted backdrop behind an exhibit, and the corner
|
|
50
|
+
ticks are the only decorative flourish. **Motion** is quiet and quick — around
|
|
51
|
+
120ms on a gentle ease, no bounces or loops. **Interaction states**: hover is a
|
|
52
|
+
warm fill wash, pressed deepens it with a half-pixel nudge, **selected is
|
|
53
|
+
marigold**, focus draws a 2px marigold ring, and disabled drops to ~45% opacity.
|
|
54
|
+
|
|
55
|
+
<Display
|
|
56
|
+
title="States"
|
|
57
|
+
subtitle="Hover · selected (marigold) · focus · disabled">
|
|
58
|
+
<StatesRow />
|
|
59
|
+
</Display>
|
|
60
|
+
|
|
61
|
+
<Display
|
|
62
|
+
title="Layout"
|
|
63
|
+
subtitle="A fixed three-region grid — header, sidebar, main">
|
|
64
|
+
<LayoutMock />
|
|
65
|
+
</Display>
|
|
66
|
+
|
|
67
|
+
## Colours
|
|
68
|
+
|
|
69
|
+
Warm paper neutrals, not cold grey. The canvas is ivory, the sidebar a touch
|
|
70
|
+
warmer, text a warm near-black ink — never `#000`. One colour does all the
|
|
71
|
+
emphatic work: **marigold** marks the active case, focus rings, and links.
|
|
72
|
+
Restraint is the point — a second accent would compete with the exhibit.
|
|
73
|
+
|
|
74
|
+
Warmth never costs legibility — every text and accent pairing clears **WCAG AA**
|
|
75
|
+
in both themes. The accent takes the most tuning: small marigold text on
|
|
76
|
+
near-white paper is hard-capped by the 4.5∶1 rule, so the brand token sits at
|
|
77
|
+
**`#a8570a`** — the brightest marigold that still clears AA *both* as a label on
|
|
78
|
+
the sidebar fill and under the white text of an accent button. (The ramp's
|
|
79
|
+
brighter `#c2690a` reads at only ~3.5 as text, so it stays a fill/decoration
|
|
80
|
+
hue.) The quiet "subtle" text tier and the status hues are likewise nudged per
|
|
81
|
+
theme to stay readable on ivory and on charcoal.
|
|
82
|
+
|
|
83
|
+
<Display
|
|
84
|
+
title="Accent — marigold"
|
|
85
|
+
subtitle="The brand token is #a8570a (AA-tuned); the ramp's #c2690a anchors the family">
|
|
86
|
+
<MarigoldRamp />
|
|
87
|
+
</Display>
|
|
88
|
+
|
|
89
|
+
<Display
|
|
90
|
+
title="Paper ramp"
|
|
91
|
+
subtitle="Warm taupe-undertoned neutrals — surfaces, text, borders">
|
|
92
|
+
<PaperRamp />
|
|
93
|
+
</Display>
|
|
94
|
+
|
|
95
|
+
<Display
|
|
96
|
+
title="Semantic roles — light"
|
|
97
|
+
subtitle="The role tokens components consume"
|
|
98
|
+
theme="light">
|
|
99
|
+
<SemanticSwatches />
|
|
100
|
+
</Display>
|
|
101
|
+
|
|
102
|
+
<Display
|
|
103
|
+
title="Semantic roles — dark"
|
|
104
|
+
subtitle="The same roles under data-theme=dark — warm charcoal, never pure black"
|
|
105
|
+
theme="dark">
|
|
106
|
+
<SemanticSwatches />
|
|
107
|
+
</Display>
|
|
108
|
+
|
|
109
|
+
<Display
|
|
110
|
+
title="Status hues"
|
|
111
|
+
subtitle="Reserved for check output — pass, warn, fail. Lift on charcoal to hold AA.">
|
|
112
|
+
<StatusHues />
|
|
113
|
+
</Display>
|
|
114
|
+
|
|
115
|
+
## Type
|
|
116
|
+
|
|
117
|
+
Two families. **Hanken Grotesk** carries all chrome text; **JetBrains Mono**
|
|
118
|
+
carries developer texture — labels, values, code, and the wordmark. A dense 14px
|
|
119
|
+
base keeps the chrome compact so the exhibit gets the room.
|
|
120
|
+
|
|
121
|
+
<Display
|
|
122
|
+
title="Font families"
|
|
123
|
+
subtitle="System sans for chrome, mono for code & values">
|
|
124
|
+
<FontFamilies />
|
|
125
|
+
</Display>
|
|
126
|
+
|
|
127
|
+
<Display
|
|
128
|
+
title="Type scale"
|
|
129
|
+
subtitle="px-based; the chrome lives small so content gets room">
|
|
130
|
+
<TypeScale />
|
|
131
|
+
</Display>
|
|
132
|
+
|
|
133
|
+
<Display
|
|
134
|
+
title="Weights & labels"
|
|
135
|
+
subtitle="Three weights; the uppercase eyebrow pattern">
|
|
136
|
+
<Weights />
|
|
137
|
+
</Display>
|
|
138
|
+
|
|
139
|
+
## Spacing
|
|
140
|
+
|
|
141
|
+
Tight, rem-based spacing keeps the chrome compact. Corners are modest — 5px on
|
|
142
|
+
controls, 8px on panels, 12px on overlays. **Borders carry the structure**: 1px
|
|
143
|
+
warm hairlines define every region, and elevation is reserved for floating layers.
|
|
144
|
+
|
|
145
|
+
<Display
|
|
146
|
+
title="Spacing scale"
|
|
147
|
+
subtitle="Tight, rem-based — dense chrome yields room to content">
|
|
148
|
+
<SpacingScale />
|
|
149
|
+
</Display>
|
|
150
|
+
|
|
151
|
+
<Display
|
|
152
|
+
title="Radius"
|
|
153
|
+
subtitle="Modest, precise — softened, never pill-round or brutalist-square">
|
|
154
|
+
<RadiusRow />
|
|
155
|
+
</Display>
|
|
156
|
+
|
|
157
|
+
<Display
|
|
158
|
+
title="Borders & elevation"
|
|
159
|
+
subtitle="Flat by default — borders carry structure, not shadow">
|
|
160
|
+
<ElevationRow />
|
|
161
|
+
</Display>
|
|
162
|
+
|
|
163
|
+
## Brand
|
|
164
|
+
|
|
165
|
+
The wordmark is type only — `[ Display Case ]` with mono brackets in marigold.
|
|
166
|
+
There is no logo image, and that's intentional. The icon vocabulary is just as
|
|
167
|
+
restrained: Unicode glyphs only — no icon font, no SVG, no emoji.
|
|
168
|
+
|
|
169
|
+
<Display
|
|
170
|
+
title="Iconography"
|
|
171
|
+
subtitle="Unicode glyphs only — rendered in the UI font">
|
|
172
|
+
<Glyphs />
|
|
173
|
+
</Display>
|
|
174
|
+
|
|
175
|
+
## Components
|
|
176
|
+
|
|
177
|
+
Three families compose the whole interface, mirroring the `components/` folders.
|
|
178
|
+
**Controls** are the input atoms, **showcase parts** are the shell's molecules
|
|
179
|
+
and organisms, and the **Primer primitives** are the prop-driven specimens this
|
|
180
|
+
wall text is assembled from. Each family below is one grouped exhibit — a mono
|
|
181
|
+
tag on the left, the live component on the right. **Display Case dogfoods every
|
|
182
|
+
one of them.**
|
|
183
|
+
|
|
184
|
+
<Display
|
|
185
|
+
title="Controls"
|
|
186
|
+
subtitle="Button · IconButton · Input · Select">
|
|
187
|
+
<ControlsOverview />
|
|
188
|
+
</Display>
|
|
189
|
+
|
|
190
|
+
<Display
|
|
191
|
+
title="Showcase parts"
|
|
192
|
+
subtitle="Eyebrow · Chip · NavItem · Stage · FlowNav · TweaksPanel · RenderAddress">
|
|
193
|
+
<ShowcaseOverview />
|
|
194
|
+
</Display>
|
|
195
|
+
|
|
196
|
+
<Display
|
|
197
|
+
title="Primer primitives"
|
|
198
|
+
subtitle="SwatchGrid · SpacingScale · GlyphGrid · SpecimenBoxRow">
|
|
199
|
+
<PrimerOverview />
|
|
200
|
+
</Display>
|
|
201
|
+
|
|
202
|
+
## Deterministic render URLs
|
|
203
|
+
|
|
204
|
+
Every case renders at a stable URL. **Same URL, same render** — so an agent can
|
|
205
|
+
enumerate the manifest, snapshot exactly one variant, and verify it without a
|
|
206
|
+
human in the loop. Tweak state encodes into the query string, so a specific
|
|
207
|
+
configuration is a link you can paste.
|
|
208
|
+
|
|
209
|
+
<Display
|
|
210
|
+
title="Render address"
|
|
211
|
+
subtitle="GET /render/<component>/<case>?theme=…&t.<tweak>=…">
|
|
212
|
+
<RenderAddress />
|
|
213
|
+
</Display>
|
|
214
|
+
|
|
215
|
+
## Get started
|
|
216
|
+
|
|
217
|
+
1. **Link the tokens once.** Pull in `styles.css` — every value is a `--dc-*`
|
|
218
|
+
custom property.
|
|
219
|
+
2. **Render under a scope.** Wrap anything in `data-theme="light"` or `"dark"`.
|
|
220
|
+
3. **Wrap specimens.** Put each live demo in `<Display title subtitle theme>`;
|
|
221
|
+
its title becomes the sidebar table-of-contents entry.
|
|
222
|
+
|
|
223
|
+
```mdx
|
|
224
|
+
import { Button, Stage } from './components'
|
|
225
|
+
|
|
226
|
+
<Display title="Button" subtitle="The one true action" theme="dark">
|
|
227
|
+
<Stage caption="Playground">
|
|
228
|
+
<Button variant="accent">Snapshot</Button>
|
|
229
|
+
</Stage>
|
|
230
|
+
</Display>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Switch to **Cases** in the sidebar to browse every component and its variants on
|
|
234
|
+
the stage. The source of truth for this system is the **Display Case Design
|
|
235
|
+
System** project on [claude.ai/design](https://claude.ai/design), kept in sync
|
|
236
|
+
via `/design-sync`.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
Display Case Design System — "The Vitrine".
|
|
3
|
+
Global stylesheet entry point. Consumers link THIS one file;
|
|
4
|
+
it is a manifest of @imports only. Every token and the webfont
|
|
5
|
+
declarations live in the files below.
|
|
6
|
+
|
|
7
|
+
Display Case dogfoods this system: its own browse chrome
|
|
8
|
+
(ui/chrome.css) is styled entirely from these `--dc-*` tokens.
|
|
9
|
+
============================================================ */
|
|
10
|
+
|
|
11
|
+
@import "./tokens/fonts.css";
|
|
12
|
+
@import "./tokens/colors.css";
|
|
13
|
+
@import "./tokens/typography.css";
|
|
14
|
+
@import "./tokens/spacing.css";
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
Display Case — Color tokens
|
|
3
|
+
"The Vitrine": warm paper neutrals, a warm-ink primary, and a
|
|
4
|
+
single marigold accent. Deliberately NOT cold gray — the chrome
|
|
5
|
+
is calm and warm so the showcased component is the exhibit.
|
|
6
|
+
No external UI library is referenced.
|
|
7
|
+
============================================================ */
|
|
8
|
+
|
|
9
|
+
:root {
|
|
10
|
+
/* --- Paper ramp (warm, taupe-undertoned neutrals) ----------- */
|
|
11
|
+
--dc-paper-50: #fbfaf6;
|
|
12
|
+
--dc-paper-100: #f4f1e9;
|
|
13
|
+
--dc-paper-200: #e6e0d4;
|
|
14
|
+
--dc-paper-300: #d6cebe;
|
|
15
|
+
--dc-paper-400: #b3a896;
|
|
16
|
+
--dc-paper-500: #8a8073;
|
|
17
|
+
--dc-paper-600: #6b6259;
|
|
18
|
+
--dc-paper-700: #4a423a;
|
|
19
|
+
--dc-paper-800: #2e2822;
|
|
20
|
+
--dc-paper-900: #211d18;
|
|
21
|
+
--dc-paper-950: #15110d;
|
|
22
|
+
|
|
23
|
+
/* --- Marigold ramp (the one accent) ------------------------- */
|
|
24
|
+
--dc-marigold-200: #fbe3bb;
|
|
25
|
+
--dc-marigold-300: #f6c878;
|
|
26
|
+
--dc-marigold-400: #f0a23b;
|
|
27
|
+
--dc-marigold-500: #e0820b; /* mid */
|
|
28
|
+
--dc-marigold-600: #c2690a; /* the marigold family's nominal accent step */
|
|
29
|
+
--dc-marigold-700: #9a4f0a; /* deeper — the accent's hover/pressed */
|
|
30
|
+
|
|
31
|
+
/* --- Status hues (used sparingly, for check output) --------- */
|
|
32
|
+
--dc-green-600: #3f7d4e;
|
|
33
|
+
--dc-amber-500: #d98a1f;
|
|
34
|
+
--dc-red-600: #c4493a;
|
|
35
|
+
--dc-red-700: #9e3528;
|
|
36
|
+
|
|
37
|
+
/* ============================================================
|
|
38
|
+
Semantic aliases — LIGHT (default)
|
|
39
|
+
These are the names components consume.
|
|
40
|
+
============================================================ */
|
|
41
|
+
--dc-bg: var(--dc-paper-50); /* app canvas */
|
|
42
|
+
--dc-bg-subtle: var(--dc-paper-100); /* sidebar / raised fill */
|
|
43
|
+
--dc-surface: #ffffff; /* inputs / stage inside */
|
|
44
|
+
--dc-fg: var(--dc-paper-900); /* primary text (warm ink)*/
|
|
45
|
+
--dc-fg-muted: var(--dc-paper-600); /* labels / secondary */
|
|
46
|
+
--dc-fg-subtle: #736a5d; /* quiet text — the lightest warm taupe that still
|
|
47
|
+
clears AA (4.5) on paper-50/100 + white. paper-500
|
|
48
|
+
(#8a8073) read at only ~3.4–3.9. */
|
|
49
|
+
--dc-border: var(--dc-paper-200); /* warm hairlines */
|
|
50
|
+
--dc-border-strong: var(--dc-paper-300);
|
|
51
|
+
|
|
52
|
+
/* Primary = warm ink (rare, for the one true action). */
|
|
53
|
+
--dc-ink: var(--dc-paper-900);
|
|
54
|
+
--dc-ink-hover: var(--dc-paper-800);
|
|
55
|
+
--dc-ink-fg: var(--dc-paper-50);
|
|
56
|
+
|
|
57
|
+
/* Accent = marigold (active case, focus, links, highlights). Tuned to #a8570a:
|
|
58
|
+
the brightest marigold that still clears AA *both* as small text on paper
|
|
59
|
+
(4.6 on the sidebar fill) and under white fill text on the accent button
|
|
60
|
+
(5.2) — the two ways the accent is used. The ramp's nominal #c2690a reads at
|
|
61
|
+
only ~3.5 as text; this keeps as much of that brightness as AA allows. -700
|
|
62
|
+
carries the hover. */
|
|
63
|
+
--dc-brand: #a8570a;
|
|
64
|
+
--dc-brand-hover: var(--dc-marigold-700);
|
|
65
|
+
--dc-brand-fg: #ffffff;
|
|
66
|
+
--dc-brand-subtle: #fbf0dd; /* faint marigold wash */
|
|
67
|
+
|
|
68
|
+
--dc-hover: var(--dc-paper-100); /* control hover fill */
|
|
69
|
+
--dc-active: var(--dc-paper-200); /* control pressed fill */
|
|
70
|
+
--dc-focus-ring: var(--dc-marigold-400);
|
|
71
|
+
|
|
72
|
+
--dc-success: var(--dc-green-600);
|
|
73
|
+
--dc-warning: var(--dc-amber-500);
|
|
74
|
+
--dc-danger: var(--dc-red-600);
|
|
75
|
+
|
|
76
|
+
/* Consumer-app canvas names the render harness + app-surface specimens paint
|
|
77
|
+
(server.ts/primer `var(--color-bg, …)`). The Vitrine IS its own consumer,
|
|
78
|
+
so it fulfils that contract by aliasing them to its themed surface — without
|
|
79
|
+
this, the /render frame body stays transparent and every dark-theme specimen
|
|
80
|
+
renders on a white canvas (failing contrast). Re-declared per theme below so
|
|
81
|
+
they re-resolve against the active scope's --dc-bg/--dc-fg. */
|
|
82
|
+
--color-bg: var(--dc-bg);
|
|
83
|
+
--color-fg: var(--dc-fg);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* ============================================================
|
|
87
|
+
Semantic aliases — LIGHT (explicit scope)
|
|
88
|
+
The light values above live only on :root, so a scope nested
|
|
89
|
+
inside a dark ancestor (e.g. a <Display theme="light"> specimen
|
|
90
|
+
on a dark primer) needs them re-declared to override the
|
|
91
|
+
inherited dark values. The ramps stay global on :root.
|
|
92
|
+
============================================================ */
|
|
93
|
+
[data-theme="light"] {
|
|
94
|
+
--dc-bg: var(--dc-paper-50);
|
|
95
|
+
--dc-bg-subtle: var(--dc-paper-100);
|
|
96
|
+
--dc-surface: #ffffff;
|
|
97
|
+
--dc-fg: var(--dc-paper-900);
|
|
98
|
+
--dc-fg-muted: var(--dc-paper-600);
|
|
99
|
+
--dc-fg-subtle: #736a5d;
|
|
100
|
+
--dc-border: var(--dc-paper-200);
|
|
101
|
+
--dc-border-strong: var(--dc-paper-300);
|
|
102
|
+
/* Re-resolve the composite so its inner var(--dc-border) binds to *this*
|
|
103
|
+
scope's border colour — see the note in the dark block below. */
|
|
104
|
+
--dc-border-line: var(--dc-border-width) solid var(--dc-border);
|
|
105
|
+
|
|
106
|
+
--dc-ink: var(--dc-paper-900);
|
|
107
|
+
--dc-ink-hover: var(--dc-paper-800);
|
|
108
|
+
--dc-ink-fg: var(--dc-paper-50);
|
|
109
|
+
|
|
110
|
+
--dc-brand: #a8570a;
|
|
111
|
+
--dc-brand-hover: var(--dc-marigold-700);
|
|
112
|
+
--dc-brand-fg: #ffffff;
|
|
113
|
+
--dc-brand-subtle: #fbf0dd;
|
|
114
|
+
|
|
115
|
+
--dc-hover: var(--dc-paper-100);
|
|
116
|
+
--dc-active: var(--dc-paper-200);
|
|
117
|
+
--dc-focus-ring: var(--dc-marigold-400);
|
|
118
|
+
|
|
119
|
+
--dc-success: var(--dc-green-600);
|
|
120
|
+
--dc-warning: var(--dc-amber-500);
|
|
121
|
+
--dc-danger: var(--dc-red-600);
|
|
122
|
+
|
|
123
|
+
--color-bg: var(--dc-bg);
|
|
124
|
+
--color-fg: var(--dc-fg);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* ============================================================
|
|
128
|
+
Semantic aliases — DARK
|
|
129
|
+
Activated by [data-theme="dark"] on <html> or any scope.
|
|
130
|
+
Warm charcoal, never pure black.
|
|
131
|
+
============================================================ */
|
|
132
|
+
:root[data-theme="dark"],
|
|
133
|
+
[data-theme="dark"] {
|
|
134
|
+
--dc-bg: #1a1714;
|
|
135
|
+
--dc-bg-subtle: #211d19;
|
|
136
|
+
--dc-surface: #262019;
|
|
137
|
+
--dc-fg: #f2ede3;
|
|
138
|
+
--dc-fg-muted: #a89e91;
|
|
139
|
+
--dc-fg-subtle: #9a8f80; /* quiet text on charcoal — lifted from #7c7164
|
|
140
|
+
(~3.4–3.7) to clear AA on bg/subtle/surface. */
|
|
141
|
+
--dc-border: #332c24;
|
|
142
|
+
--dc-border-strong: #453c30;
|
|
143
|
+
/* Composite border tokens substitute their inner var() at the scope where
|
|
144
|
+
they are *declared*, not where they are used. Declared only on :root, the
|
|
145
|
+
light --dc-border would stay baked into --dc-border-line even inside a
|
|
146
|
+
forced-dark scope, so themed swatches/tiles kept light hairlines. Re-declare
|
|
147
|
+
it here so the composite re-resolves against this scope's --dc-border. */
|
|
148
|
+
--dc-border-line: var(--dc-border-width) solid var(--dc-border);
|
|
149
|
+
|
|
150
|
+
--dc-ink: #f2ede3;
|
|
151
|
+
--dc-ink-hover: #ffffff;
|
|
152
|
+
--dc-ink-fg: #1a1714;
|
|
153
|
+
|
|
154
|
+
--dc-brand: var(--dc-marigold-400);
|
|
155
|
+
--dc-brand-hover: var(--dc-marigold-300);
|
|
156
|
+
--dc-brand-fg: #1a1714;
|
|
157
|
+
--dc-brand-subtle: #2a2118;
|
|
158
|
+
|
|
159
|
+
--dc-hover: #211d19;
|
|
160
|
+
--dc-active: #2e2820;
|
|
161
|
+
--dc-focus-ring: var(--dc-marigold-500);
|
|
162
|
+
|
|
163
|
+
/* Status as TEXT on charcoal: the light red/green read at only ~3.3 here, so
|
|
164
|
+
lift them for dark. (warning/amber already clears AA on charcoal.) Tags and
|
|
165
|
+
badges that carry white text use the fixed ramp reds directly, not these. */
|
|
166
|
+
--dc-success: #579d68;
|
|
167
|
+
--dc-warning: var(--dc-amber-500);
|
|
168
|
+
--dc-danger: #d97366;
|
|
169
|
+
|
|
170
|
+
--color-bg: var(--dc-bg);
|
|
171
|
+
--color-fg: var(--dc-fg);
|
|
172
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
Display Case — Font face declarations
|
|
3
|
+
Two webfonts give the chrome its developer-native personality:
|
|
4
|
+
· Hanken Grotesk — warm, legible UI grotesk for all chrome text
|
|
5
|
+
· JetBrains Mono — characterful mono for labels, values, code,
|
|
6
|
+
and the bracketed wordmark
|
|
7
|
+
Loaded from the Google Fonts CDN. Swap these @import lines for
|
|
8
|
+
self-hosted woff2 if you need a fully offline bundle.
|
|
9
|
+
|
|
10
|
+
Note: when Display Case serves its own browse chrome it injects
|
|
11
|
+
the equivalent <link rel="stylesheet"> into the document head
|
|
12
|
+
(see server.ts FONT_LINKS) rather than this @import, so the font
|
|
13
|
+
declaration leads the document and never fights a consumer's own
|
|
14
|
+
stylesheet @imports. This file remains the canonical source for
|
|
15
|
+
anyone linking styles.css directly.
|
|
16
|
+
============================================================ */
|
|
17
|
+
|
|
18
|
+
@import url("https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap");
|