@misoto22/folio 0.16.0 → 0.17.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/dist/agent/Accordion.md +1 -1
- package/dist/agent/Actions.md +1 -1
- package/dist/agent/Alert.md +1 -1
- package/dist/agent/AppShell.md +1 -1
- package/dist/agent/ArchitectureFigure.md +1 -1
- package/dist/agent/AreaChart.md +1 -1
- package/dist/agent/Article.md +1 -1
- package/dist/agent/AspectRatio.md +1 -1
- package/dist/agent/Avatar.md +1 -1
- package/dist/agent/Badge.md +1 -1
- package/dist/agent/BarChart.md +1 -1
- package/dist/agent/BarList.md +1 -1
- package/dist/agent/BigNumber.md +1 -1
- package/dist/agent/BoxPlot.md +1 -1
- package/dist/agent/Breadcrumb.md +1 -1
- package/dist/agent/BulletChart.md +1 -1
- package/dist/agent/Button.md +1 -1
- package/dist/agent/Calendar.md +1 -1
- package/dist/agent/CalendarHeatmap.md +1 -1
- package/dist/agent/Card.md +1 -1
- package/dist/agent/Checkbox.md +1 -1
- package/dist/agent/Code.md +1 -1
- package/dist/agent/CodeBlock.md +1 -1
- package/dist/agent/Collapsible.md +1 -1
- package/dist/agent/Collection.md +1 -1
- package/dist/agent/ColorPicker.md +1 -1
- package/dist/agent/Combobox.md +1 -1
- package/dist/agent/Command.md +1 -1
- package/dist/agent/ComposedChart.md +1 -1
- package/dist/agent/Contact.md +1 -1
- package/dist/agent/Content.md +1 -1
- package/dist/agent/ContextMenu.md +1 -1
- package/dist/agent/Conversation.md +1 -1
- package/dist/agent/DataflowFigure.md +1 -1
- package/dist/agent/DatePicker.md +1 -1
- package/dist/agent/DescriptionList.md +1 -1
- package/dist/agent/Diagram.md +1 -1
- package/dist/agent/DiagramCanvas.md +1 -1
- package/dist/agent/DiagramExportMenu.md +1 -1
- package/dist/agent/DiagramInspector.md +1 -1
- package/dist/agent/DiagramLegend.md +1 -1
- package/dist/agent/DiagramMinimap.md +1 -1
- package/dist/agent/DiagramToolbar.md +1 -1
- package/dist/agent/Dialog.md +1 -1
- package/dist/agent/DropdownMenu.md +1 -1
- package/dist/agent/EmptyState.md +1 -1
- package/dist/agent/ErrorState.md +1 -1
- package/dist/agent/Evidence.md +1 -1
- package/dist/agent/Facet.md +1 -1
- package/dist/agent/Field.md +1 -1
- package/dist/agent/FigureBand.md +1 -1
- package/dist/agent/FloatingIconButton.md +1 -1
- package/dist/agent/FunnelChart.md +1 -1
- package/dist/agent/Heading.md +1 -1
- package/dist/agent/Heatmap.md +1 -1
- package/dist/agent/Histogram.md +1 -1
- package/dist/agent/Input.md +1 -1
- package/dist/agent/Kbd.md +1 -1
- package/dist/agent/LifecycleFigure.md +1 -1
- package/dist/agent/LineChart.md +1 -1
- package/dist/agent/LinkArrow.md +1 -1
- package/dist/agent/Markdown.md +1 -1
- package/dist/agent/Media.md +1 -1
- package/dist/agent/Metric.md +1 -1
- package/dist/agent/Metrics.md +1 -1
- package/dist/agent/Music.md +1 -1
- package/dist/agent/NativeSelect.md +1 -1
- package/dist/agent/NavItem.md +1 -1
- package/dist/agent/NumberField.md +1 -1
- package/dist/agent/PageHeader.md +1 -1
- package/dist/agent/Pagination.md +1 -1
- package/dist/agent/PieChart.md +1 -1
- package/dist/agent/Popover.md +1 -1
- package/dist/agent/Portfolio.md +1 -1
- package/dist/agent/PortfolioIndex.md +1 -1
- package/dist/agent/Progress.md +1 -1
- package/dist/agent/RadarChart.md +1 -1
- package/dist/agent/RadialChart.md +1 -1
- package/dist/agent/RadioGroup.md +1 -1
- package/dist/agent/Reading.md +1 -1
- package/dist/agent/Recovery.md +1 -1
- package/dist/agent/SankeyChart.md +1 -1
- package/dist/agent/ScatterChart.md +1 -1
- package/dist/agent/ScrollArea.md +1 -1
- package/dist/agent/SearchPalette.md +1 -1
- package/dist/agent/SearchableMenu.md +1 -1
- package/dist/agent/Select.md +1 -1
- package/dist/agent/Separator.md +1 -1
- package/dist/agent/SequenceFigure.md +1 -1
- package/dist/agent/Sheet.md +1 -1
- package/dist/agent/Sidebar.md +1 -1
- package/dist/agent/SiteNavigation.md +1 -1
- package/dist/agent/SiteShell.md +1 -1
- package/dist/agent/Skeleton.md +1 -1
- package/dist/agent/Slider.md +1 -1
- package/dist/agent/Sparkline.md +1 -1
- package/dist/agent/Spinner.md +1 -1
- package/dist/agent/StatusDot.md +1 -1
- package/dist/agent/StatusPill.md +1 -1
- package/dist/agent/Steps.md +1 -1
- package/dist/agent/Switch.md +1 -1
- package/dist/agent/Table.md +1 -1
- package/dist/agent/Tabs.md +1 -1
- package/dist/agent/Tag.md +1 -1
- package/dist/agent/Text.md +1 -1
- package/dist/agent/Textarea.md +1 -1
- package/dist/agent/Timeline.md +1 -1
- package/dist/agent/Timestamp.md +1 -1
- package/dist/agent/Toast.md +1 -1
- package/dist/agent/ToggleGroup.md +1 -1
- package/dist/agent/Toolbar.md +1 -1
- package/dist/agent/Tooltip.md +1 -1
- package/dist/agent/TreemapChart.md +1 -1
- package/dist/agent/WaterfallChart.md +1 -1
- package/dist/agent/Workbench.md +142 -0
- package/dist/agent/WorkflowFigure.md +1 -1
- package/dist/agent/catalog.json +51 -2
- package/dist/agent/index.md +6 -3
- package/dist/components/Badge/Badge.js +1 -1
- package/dist/components/Badge/Badge.js.map +1 -1
- package/dist/components/Button/Button.js +1 -1
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Heading/Heading.js +1 -1
- package/dist/components/Heading/Heading.js.map +1 -1
- package/dist/components/Tag/Tag.js +2 -2
- package/dist/components/Tag/Tag.js.map +1 -1
- package/dist/semantic.css +7 -0
- package/dist/styles.css +1 -1
- package/dist/themes.css +93 -0
- package/dist/tokens.css +16 -2
- package/dist/tokens.d.ts +7 -0
- package/dist/tokens.js +38 -2
- package/dist/tokens.json +38 -2
- package/dist/website/Workbench/Chronology.d.ts +32 -0
- package/dist/website/Workbench/Chronology.js +32 -0
- package/dist/website/Workbench/Chronology.js.map +1 -0
- package/dist/website/Workbench/ContactRow.d.ts +13 -0
- package/dist/website/Workbench/ContactRow.js +11 -0
- package/dist/website/Workbench/ContactRow.js.map +1 -0
- package/dist/website/Workbench/PhotoMosaic.d.ts +13 -0
- package/dist/website/Workbench/PhotoMosaic.js +15 -0
- package/dist/website/Workbench/PhotoMosaic.js.map +1 -0
- package/dist/website/Workbench/Reveal.d.ts +19 -0
- package/dist/website/Workbench/Reveal.js +29 -0
- package/dist/website/Workbench/Reveal.js.map +1 -0
- package/dist/website/Workbench/ToolStrip.d.ts +18 -0
- package/dist/website/Workbench/ToolStrip.js +15 -0
- package/dist/website/Workbench/ToolStrip.js.map +1 -0
- package/dist/website/Workbench/Workbench.d.ts +23 -0
- package/dist/website/Workbench/Workbench.js +22 -0
- package/dist/website/Workbench/Workbench.js.map +1 -0
- package/dist/website/Workbench/WorkbenchCard.d.ts +29 -0
- package/dist/website/Workbench/WorkbenchCard.js +21 -0
- package/dist/website/Workbench/WorkbenchCard.js.map +1 -0
- package/dist/website/Workbench/WorkbenchEntries.d.ts +22 -0
- package/dist/website/Workbench/WorkbenchEntries.js +24 -0
- package/dist/website/Workbench/WorkbenchEntries.js.map +1 -0
- package/dist/website/Workbench/WorkbenchFigure.d.ts +20 -0
- package/dist/website/Workbench/WorkbenchFigure.js +15 -0
- package/dist/website/Workbench/WorkbenchFigure.js.map +1 -0
- package/dist/website/Workbench/WorkbenchHero.d.ts +24 -0
- package/dist/website/Workbench/WorkbenchHero.js +24 -0
- package/dist/website/Workbench/WorkbenchHero.js.map +1 -0
- package/dist/website/Workbench/theme.d.ts +22 -0
- package/dist/website/Workbench/theme.js +12 -0
- package/dist/website/Workbench/theme.js.map +1 -0
- package/dist/website/index.d.ts +11 -0
- package/dist/website/index.js +11 -0
- package/dist/website/index.js.map +1 -1
- package/dist/website-collection.css +6 -6
- package/dist/website-content.css +4 -1
- package/dist/website-conversation.css +1 -1
- package/dist/website-media.css +12 -12
- package/dist/website-portfolio.css +4 -4
- package/dist/website-reading.css +10 -10
- package/dist/website-shell.css +1 -1
- package/dist/website-workbench.css +162 -0
- package/dist/website.css +1 -0
- package/package.json +1 -1
- package/skills/folio-design/rules/tokens.md +4 -2
package/dist/themes.css
CHANGED
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
cobalt 8.05 9.21 7.86 8.41 10.23 8.27
|
|
48
48
|
plum 8.49 9.55 8.12 8.74 10.43 8.41
|
|
49
49
|
moss 5.80 8.30 7.24 8.76 11.32 9.06
|
|
50
|
+
ember 5.46 6.34 5.47 7.81 8.86 7.31
|
|
50
51
|
|
|
51
52
|
`--accent-foreground` resolves to `--paper`, so paper printed ON the accent
|
|
52
53
|
fill is the mark column read the other way up. */
|
|
@@ -94,6 +95,16 @@
|
|
|
94
95
|
--red-soft: rgba(86, 107, 82, 0.1);
|
|
95
96
|
}
|
|
96
97
|
|
|
98
|
+
/* A burnt orange for the Workbench preset: it marks a link or the current
|
|
99
|
+
state and nothing else, so it can carry heat without competing with the
|
|
100
|
+
photographs it sits beside. The lowest-contrast mark after moss; its
|
|
101
|
+
ink is a step darker so a link on a stone panel still clears AA. */
|
|
102
|
+
[data-accent='ember'] {
|
|
103
|
+
--clay: #b8430a;
|
|
104
|
+
--clay-ink: #a83c08;
|
|
105
|
+
--red-soft: rgba(184, 67, 10, 0.1);
|
|
106
|
+
}
|
|
107
|
+
|
|
97
108
|
/* Re-derives the chain, on any element that names an accent.
|
|
98
109
|
|
|
99
110
|
A `var()` is substituted where it is DECLARED, not where it is read:
|
|
@@ -117,6 +128,8 @@
|
|
|
117
128
|
--accent-foreground: var(--on-red);
|
|
118
129
|
--accent-on-dark: var(--red);
|
|
119
130
|
--accent-on-muted: var(--red-ink);
|
|
131
|
+
--action: var(--red);
|
|
132
|
+
--action-foreground: var(--on-red);
|
|
120
133
|
}
|
|
121
134
|
|
|
122
135
|
/* On the dark ground the same hues have to come UP to clear AA, not down. An
|
|
@@ -160,6 +173,30 @@
|
|
|
160
173
|
--clay-ink: #b8cbb3;
|
|
161
174
|
--red-soft: rgba(156, 181, 151, 0.14);
|
|
162
175
|
}
|
|
176
|
+
[data-mode='dark'][data-accent='ember'],
|
|
177
|
+
[data-mode='dark'] [data-accent='ember'] {
|
|
178
|
+
--clay: #f08a4b;
|
|
179
|
+
--clay-ink: #f29a62;
|
|
180
|
+
--red-soft: rgba(240, 138, 75, 0.14);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* ─── Action ───────────────────────────────────────────────────────────────
|
|
184
|
+
What the primary button is filled with. By default it is the accent, which
|
|
185
|
+
is what law 7 asks for. `ink` takes the primary action back to the page's
|
|
186
|
+
own ink while the accent keeps marking links and the current state — the
|
|
187
|
+
Workbench preset's split, where a burnt-orange button would be the loudest
|
|
188
|
+
thing on a page of photographs. Declared after the accent block so it wins
|
|
189
|
+
on the same element, and re-derived on it for the same reason that block
|
|
190
|
+
is: a `var()` resolves where it is written. Ink and paper already swap in
|
|
191
|
+
dark mode, so this axis needs no dark block of its own. */
|
|
192
|
+
[data-action='accent'] {
|
|
193
|
+
--action: var(--accent);
|
|
194
|
+
--action-foreground: var(--accent-foreground);
|
|
195
|
+
}
|
|
196
|
+
[data-action='ink'] {
|
|
197
|
+
--action: var(--ink);
|
|
198
|
+
--action-foreground: var(--paper);
|
|
199
|
+
}
|
|
163
200
|
|
|
164
201
|
/* ─── Surface ──────────────────────────────────────────────────────────────
|
|
165
202
|
The ground and its two steps. Law 8 still holds — dark is a value swap, so
|
|
@@ -234,6 +271,40 @@
|
|
|
234
271
|
--rule-2: rgba(240, 244, 250, 0.26);
|
|
235
272
|
}
|
|
236
273
|
|
|
274
|
+
/* Linen, the Workbench ground. Unlike `warm` and `cool` it also moves the
|
|
275
|
+
three text steps, because the preset's warmth is carried by the ink as much
|
|
276
|
+
as by the paper: a neutral #101010 on a linen ground reads as a cold page
|
|
277
|
+
with a tinted background. The text steps keep the root's ladder — ink,
|
|
278
|
+
a secondary step, and an AA floor — measured on every linen ground:
|
|
279
|
+
light ink 14.33 / 13.60 / 12.42, --ink-2 8.13 / 7.72 / 7.05, --ink-3-aa
|
|
280
|
+
6.15 / 5.84 / 5.33 against paper / paper-2 / stone; dark ink 15.57 /
|
|
281
|
+
14.44 / 13.15, --ink-2 9.67 / 8.96 / 8.16, --ink-3-aa 7.18 / 6.66 / 6.07.
|
|
282
|
+
Rules are the ink itself at the root's two weights, so a hairline stays
|
|
283
|
+
the colour of the type it separates. */
|
|
284
|
+
[data-surface='linen'] {
|
|
285
|
+
--paper: #f7f7f4;
|
|
286
|
+
--paper-2: #f2f1ed;
|
|
287
|
+
--stone: #e8e7e2;
|
|
288
|
+
--rule: rgba(38, 37, 30, 0.1);
|
|
289
|
+
--rule-2: rgba(38, 37, 30, 0.2);
|
|
290
|
+
--ink: #26251e;
|
|
291
|
+
--ink-2: #4d4b44;
|
|
292
|
+
--ink-3: rgba(38, 37, 30, 0.55);
|
|
293
|
+
--ink-3-aa: #5f5d55;
|
|
294
|
+
}
|
|
295
|
+
[data-mode='dark'][data-surface='linen'],
|
|
296
|
+
[data-mode='dark'] [data-surface='linen'] {
|
|
297
|
+
--paper: #14130f;
|
|
298
|
+
--paper-2: #1c1b17;
|
|
299
|
+
--stone: #25231e;
|
|
300
|
+
--rule: rgba(236, 235, 230, 0.14);
|
|
301
|
+
--rule-2: rgba(236, 235, 230, 0.26);
|
|
302
|
+
--ink: #ecebe6;
|
|
303
|
+
--ink-2: #bdbbb3;
|
|
304
|
+
--ink-3: rgba(236, 235, 230, 0.55);
|
|
305
|
+
--ink-3-aa: #a3a199;
|
|
306
|
+
}
|
|
307
|
+
|
|
237
308
|
/* Glass, and the one place this system allows a blur.
|
|
238
309
|
*
|
|
239
310
|
* Law 2 says depth is a hairline and never a blur, and this does not break it:
|
|
@@ -340,6 +411,28 @@
|
|
|
340
411
|
--font-heading: var(--serif);
|
|
341
412
|
}
|
|
342
413
|
|
|
414
|
+
/* ─── Voice ────────────────────────────────────────────────────────────────
|
|
415
|
+
How loud the page speaks, which the type axis does not decide: that axis
|
|
416
|
+
picks a FACE and leaves the ramp alone. `quiet` is the Workbench setting —
|
|
417
|
+
page titles at roughly two-thirds of the ramp, display type at a regular
|
|
418
|
+
weight rather than a light one, and labels set as sentence-case sans in
|
|
419
|
+
place of tracked mono capitals. Body, record and item steps do not move, so
|
|
420
|
+
a quiet page keeps its hierarchy; only its top two steps come down. */
|
|
421
|
+
[data-voice='display'] {
|
|
422
|
+
--display-scale: 1;
|
|
423
|
+
--display-weight: 300;
|
|
424
|
+
--label-font: var(--font-mono);
|
|
425
|
+
--label-case: uppercase;
|
|
426
|
+
--label-tracking-scale: 1;
|
|
427
|
+
}
|
|
428
|
+
[data-voice='quiet'] {
|
|
429
|
+
--display-scale: 0.62;
|
|
430
|
+
--display-weight: 400;
|
|
431
|
+
--label-font: var(--font-sans);
|
|
432
|
+
--label-case: none;
|
|
433
|
+
--label-tracking-scale: 0;
|
|
434
|
+
}
|
|
435
|
+
|
|
343
436
|
/* ─── Motion ───────────────────────────────────────────────────────────────
|
|
344
437
|
`prefers-reduced-motion` is honoured separately and is not a theme: a
|
|
345
438
|
reader's stated need is not one of five looks. This axis is taste. */
|
package/dist/tokens.css
CHANGED
|
@@ -279,14 +279,28 @@
|
|
|
279
279
|
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
+
/* Display voice. How loud a page's display type and labels are, read by the
|
|
283
|
+
website compositions instead of literal values so the voice axis in
|
|
284
|
+
`themes.css` can quiet them. Declared on the root only — never on a fluid
|
|
285
|
+
frame — so an axis set on an ancestor is not reset inside one. */
|
|
286
|
+
:root {
|
|
287
|
+
--display-scale: 1;
|
|
288
|
+
--display-weight: 300;
|
|
289
|
+
--label-font: var(--font-mono);
|
|
290
|
+
--label-case: uppercase;
|
|
291
|
+
--label-tracking-scale: 1;
|
|
292
|
+
}
|
|
293
|
+
|
|
282
294
|
/* The fluid ramp, computed wherever `--fluid` is set.
|
|
283
295
|
`[data-fluid-frame]` must sit INSIDE the element carrying `container-type`:
|
|
284
296
|
a container query unit resolves against an ANCESTOR container, never against
|
|
285
297
|
the element that declares the container itself. */
|
|
286
298
|
:root,
|
|
287
299
|
[data-fluid-frame] {
|
|
288
|
-
|
|
289
|
-
|
|
300
|
+
/* `--display-scale` is the voice axis's lever on the two display steps; at
|
|
301
|
+
1 they are the ramp as drawn. */
|
|
302
|
+
--fs-title: calc(clamp(2.5rem, calc(4.6 * var(--fluid)), 3.375rem) * var(--display-scale, 1)); /* page h1 40 → 54px */
|
|
303
|
+
--fs-lead: calc(clamp(1.875rem, calc(3 * var(--fluid)), 2.625rem) * var(--display-scale, 1)); /* band heading 30 → 42px */
|
|
290
304
|
--fs-heading: clamp(1.5rem, calc(2.1 * var(--fluid)), 1.8125rem); /* record title 24 → 29px */
|
|
291
305
|
--fs-sub: clamp(1.3125rem, calc(1.7 * var(--fluid)), 1.5625rem); /* card sub-head 21 → 25px */
|
|
292
306
|
--fs-item: clamp(1.125rem, calc(1.35 * var(--fluid)), 1.25rem); /* in-card title 18 → 20px */
|
package/dist/tokens.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export type TokenName =
|
|
|
19
19
|
| 'accent-on-dark'
|
|
20
20
|
| 'accent-on-muted'
|
|
21
21
|
| 'accent-wash'
|
|
22
|
+
| 'action'
|
|
23
|
+
| 'action-foreground'
|
|
22
24
|
| 'background'
|
|
23
25
|
| 'background-elevated'
|
|
24
26
|
| 'bar'
|
|
@@ -73,6 +75,8 @@ export type TokenName =
|
|
|
73
75
|
| 'diagram-sigil'
|
|
74
76
|
| 'diagram-surface'
|
|
75
77
|
| 'disabled-opacity'
|
|
78
|
+
| 'display-scale'
|
|
79
|
+
| 'display-weight'
|
|
76
80
|
| 'duration-base'
|
|
77
81
|
| 'duration-fast'
|
|
78
82
|
| 'duration-slow'
|
|
@@ -104,6 +108,9 @@ export type TokenName =
|
|
|
104
108
|
| 'ink-2'
|
|
105
109
|
| 'ink-3'
|
|
106
110
|
| 'ink-3-aa'
|
|
111
|
+
| 'label-case'
|
|
112
|
+
| 'label-font'
|
|
113
|
+
| 'label-tracking-scale'
|
|
107
114
|
| 'lh-cjk'
|
|
108
115
|
| 'lift'
|
|
109
116
|
| 'lift-sm'
|
package/dist/tokens.js
CHANGED
|
@@ -294,16 +294,41 @@ export const TOKENS = {
|
|
|
294
294
|
"category": "space",
|
|
295
295
|
"light": "52px"
|
|
296
296
|
},
|
|
297
|
+
"display-scale": {
|
|
298
|
+
"layer": "tokens",
|
|
299
|
+
"category": "other",
|
|
300
|
+
"light": "1"
|
|
301
|
+
},
|
|
302
|
+
"display-weight": {
|
|
303
|
+
"layer": "tokens",
|
|
304
|
+
"category": "other",
|
|
305
|
+
"light": "300"
|
|
306
|
+
},
|
|
307
|
+
"label-font": {
|
|
308
|
+
"layer": "tokens",
|
|
309
|
+
"category": "other",
|
|
310
|
+
"light": "var(--font-mono)"
|
|
311
|
+
},
|
|
312
|
+
"label-case": {
|
|
313
|
+
"layer": "tokens",
|
|
314
|
+
"category": "other",
|
|
315
|
+
"light": "uppercase"
|
|
316
|
+
},
|
|
317
|
+
"label-tracking-scale": {
|
|
318
|
+
"layer": "tokens",
|
|
319
|
+
"category": "other",
|
|
320
|
+
"light": "1"
|
|
321
|
+
},
|
|
297
322
|
"fs-title": {
|
|
298
323
|
"layer": "tokens",
|
|
299
324
|
"category": "type",
|
|
300
|
-
"light": "clamp(2.5rem, calc(4.6 * var(--fluid)), 3.375rem)",
|
|
325
|
+
"light": "calc(clamp(2.5rem, calc(4.6 * var(--fluid)), 3.375rem) * var(--display-scale, 1))",
|
|
301
326
|
"comment": "page h1 40 → 54px"
|
|
302
327
|
},
|
|
303
328
|
"fs-lead": {
|
|
304
329
|
"layer": "tokens",
|
|
305
330
|
"category": "type",
|
|
306
|
-
"light": "clamp(1.875rem, calc(3 * var(--fluid)), 2.625rem)",
|
|
331
|
+
"light": "calc(clamp(1.875rem, calc(3 * var(--fluid)), 2.625rem) * var(--display-scale, 1))",
|
|
307
332
|
"comment": "band heading 30 → 42px"
|
|
308
333
|
},
|
|
309
334
|
"fs-heading": {
|
|
@@ -748,6 +773,17 @@ export const TOKENS = {
|
|
|
748
773
|
"light": "var(--red-ink)",
|
|
749
774
|
"comment": "Accent text sitting on an accent-muted panel, which --accent cannot do: it clears AA on paper by 4.58:1, and any tint of itself underneath pushes it below 4.5. This names the situation so the choice is not left to whoever writes the next panel."
|
|
750
775
|
},
|
|
776
|
+
"action": {
|
|
777
|
+
"layer": "semantic",
|
|
778
|
+
"category": "other",
|
|
779
|
+
"light": "var(--accent)",
|
|
780
|
+
"comment": "The fill of the one primary action on a screen. It follows the accent unless `data-action` says otherwise: a preset that keeps its accent for links and the current state can hand the primary button back to ink, without a checked box or the current page losing the accent."
|
|
781
|
+
},
|
|
782
|
+
"action-foreground": {
|
|
783
|
+
"layer": "semantic",
|
|
784
|
+
"category": "other",
|
|
785
|
+
"light": "var(--accent-foreground)"
|
|
786
|
+
},
|
|
751
787
|
"success": {
|
|
752
788
|
"layer": "semantic",
|
|
753
789
|
"category": "colour",
|
package/dist/tokens.json
CHANGED
|
@@ -293,16 +293,41 @@
|
|
|
293
293
|
"category": "space",
|
|
294
294
|
"light": "52px"
|
|
295
295
|
},
|
|
296
|
+
"display-scale": {
|
|
297
|
+
"layer": "tokens",
|
|
298
|
+
"category": "other",
|
|
299
|
+
"light": "1"
|
|
300
|
+
},
|
|
301
|
+
"display-weight": {
|
|
302
|
+
"layer": "tokens",
|
|
303
|
+
"category": "other",
|
|
304
|
+
"light": "300"
|
|
305
|
+
},
|
|
306
|
+
"label-font": {
|
|
307
|
+
"layer": "tokens",
|
|
308
|
+
"category": "other",
|
|
309
|
+
"light": "var(--font-mono)"
|
|
310
|
+
},
|
|
311
|
+
"label-case": {
|
|
312
|
+
"layer": "tokens",
|
|
313
|
+
"category": "other",
|
|
314
|
+
"light": "uppercase"
|
|
315
|
+
},
|
|
316
|
+
"label-tracking-scale": {
|
|
317
|
+
"layer": "tokens",
|
|
318
|
+
"category": "other",
|
|
319
|
+
"light": "1"
|
|
320
|
+
},
|
|
296
321
|
"fs-title": {
|
|
297
322
|
"layer": "tokens",
|
|
298
323
|
"category": "type",
|
|
299
|
-
"light": "clamp(2.5rem, calc(4.6 * var(--fluid)), 3.375rem)",
|
|
324
|
+
"light": "calc(clamp(2.5rem, calc(4.6 * var(--fluid)), 3.375rem) * var(--display-scale, 1))",
|
|
300
325
|
"comment": "page h1 40 → 54px"
|
|
301
326
|
},
|
|
302
327
|
"fs-lead": {
|
|
303
328
|
"layer": "tokens",
|
|
304
329
|
"category": "type",
|
|
305
|
-
"light": "clamp(1.875rem, calc(3 * var(--fluid)), 2.625rem)",
|
|
330
|
+
"light": "calc(clamp(1.875rem, calc(3 * var(--fluid)), 2.625rem) * var(--display-scale, 1))",
|
|
306
331
|
"comment": "band heading 30 → 42px"
|
|
307
332
|
},
|
|
308
333
|
"fs-heading": {
|
|
@@ -747,6 +772,17 @@
|
|
|
747
772
|
"light": "var(--red-ink)",
|
|
748
773
|
"comment": "Accent text sitting on an accent-muted panel, which --accent cannot do: it clears AA on paper by 4.58:1, and any tint of itself underneath pushes it below 4.5. This names the situation so the choice is not left to whoever writes the next panel."
|
|
749
774
|
},
|
|
775
|
+
"action": {
|
|
776
|
+
"layer": "semantic",
|
|
777
|
+
"category": "other",
|
|
778
|
+
"light": "var(--accent)",
|
|
779
|
+
"comment": "The fill of the one primary action on a screen. It follows the accent unless `data-action` says otherwise: a preset that keeps its accent for links and the current state can hand the primary button back to ink, without a checked box or the current page losing the accent."
|
|
780
|
+
},
|
|
781
|
+
"action-foreground": {
|
|
782
|
+
"layer": "semantic",
|
|
783
|
+
"category": "other",
|
|
784
|
+
"light": "var(--accent-foreground)"
|
|
785
|
+
},
|
|
750
786
|
"success": {
|
|
751
787
|
"layer": "semantic",
|
|
752
788
|
"category": "colour",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface ChronologyItem {
|
|
5
|
+
id: string;
|
|
6
|
+
title: ReactNode;
|
|
7
|
+
organisation?: ReactNode;
|
|
8
|
+
/** Decimal years, e.g. 2019.5 for July 2019. */
|
|
9
|
+
start: number;
|
|
10
|
+
/** Decimal years; omit for an item that is still going. */
|
|
11
|
+
end?: number;
|
|
12
|
+
kind: 'role' | 'study';
|
|
13
|
+
}
|
|
14
|
+
interface ChronologyProps {
|
|
15
|
+
/** Accessible name of the chart. */
|
|
16
|
+
label: string;
|
|
17
|
+
/** First and last year on the axis, inclusive. */
|
|
18
|
+
from: number;
|
|
19
|
+
to: number;
|
|
20
|
+
items: ChronologyItem[];
|
|
21
|
+
/** Text marking a current item, such as "Now". */
|
|
22
|
+
currentLabel?: ReactNode;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Roles and studies as bars on one year axis, one lane each. Roles are filled,
|
|
26
|
+
* studies outlined, and a current role is ink with an accent end. The bars are
|
|
27
|
+
* a list underneath, so a screen reader hears titles and dates rather than
|
|
28
|
+
* geometry.
|
|
29
|
+
*/
|
|
30
|
+
declare function Chronology({ label, from, to, items, currentLabel }: ChronologyProps): react.JSX.Element;
|
|
31
|
+
|
|
32
|
+
export { Chronology, type ChronologyItem, type ChronologyProps };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
function Chronology({ label, from, to, items, currentLabel }) {
|
|
3
|
+
const span = to + 1 - from;
|
|
4
|
+
const years = Array.from({ length: to - from + 1 }, (_, index) => from + index);
|
|
5
|
+
const position = (value) => `${((value - from) / span * 100).toFixed(3)}%`;
|
|
6
|
+
return /* @__PURE__ */ jsxs("figure", { className: "folio-wb-chronology", "aria-label": label, children: [
|
|
7
|
+
/* @__PURE__ */ jsx("ol", { children: items.map((item) => {
|
|
8
|
+
const current = item.end === void 0;
|
|
9
|
+
const align = current || (item.start - from) / span >= 0.4 ? "end" : "start";
|
|
10
|
+
const style = { "--start": position(item.start), "--end": position(item.end ?? to + 1) };
|
|
11
|
+
return /* @__PURE__ */ jsxs("li", { "data-kind": item.kind, "data-current": current || void 0, "data-align": align, style, children: [
|
|
12
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
13
|
+
/* @__PURE__ */ jsx("span", { children: item.title }),
|
|
14
|
+
item.organisation && /* @__PURE__ */ jsxs("span", { className: "folio-wb-chronology-org", children: [
|
|
15
|
+
" \xB7 ",
|
|
16
|
+
item.organisation
|
|
17
|
+
] }),
|
|
18
|
+
current && currentLabel && /* @__PURE__ */ jsxs("span", { className: "folio-wb-chronology-now", children: [
|
|
19
|
+
" \xB7 ",
|
|
20
|
+
currentLabel
|
|
21
|
+
] })
|
|
22
|
+
] }),
|
|
23
|
+
/* @__PURE__ */ jsx("span", { className: "folio-wb-chronology-bar", "aria-hidden": true })
|
|
24
|
+
] }, item.id);
|
|
25
|
+
}) }),
|
|
26
|
+
/* @__PURE__ */ jsx("div", { className: "folio-wb-chronology-axis", "aria-hidden": true, children: years.map((year) => /* @__PURE__ */ jsx("span", { children: year }, year)) })
|
|
27
|
+
] });
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
Chronology
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=Chronology.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/website/Workbench/Chronology.tsx"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react'\n\nexport interface ChronologyItem {\n id: string\n title: ReactNode\n organisation?: ReactNode\n /** Decimal years, e.g. 2019.5 for July 2019. */\n start: number\n /** Decimal years; omit for an item that is still going. */\n end?: number\n kind: 'role' | 'study'\n}\n\nexport interface ChronologyProps {\n /** Accessible name of the chart. */\n label: string\n /** First and last year on the axis, inclusive. */\n from: number\n to: number\n items: ChronologyItem[]\n /** Text marking a current item, such as \"Now\". */\n currentLabel?: ReactNode\n}\n\n/**\n * Roles and studies as bars on one year axis, one lane each. Roles are filled,\n * studies outlined, and a current role is ink with an accent end. The bars are\n * a list underneath, so a screen reader hears titles and dates rather than\n * geometry.\n */\nexport function Chronology({ label, from, to, items, currentLabel }: ChronologyProps) {\n const span = to + 1 - from\n const years = Array.from({ length: to - from + 1 }, (_, index) => from + index)\n const position = (value: number) => `${(((value - from) / span) * 100).toFixed(3)}%`\n return (\n <figure className=\"folio-wb-chronology\" aria-label={label}>\n <ol>\n {items.map((item) => {\n const current = item.end === undefined\n // A bar that starts in the later part of the axis hangs its label from its end,\n // so a long title never runs off the right of the axis.\n const align = current || (item.start - from) / span >= 0.4 ? 'end' : 'start'\n const style = { '--start': position(item.start), '--end': position(item.end ?? to + 1) } as CSSProperties\n return (\n <li key={item.id} data-kind={item.kind} data-current={current || undefined} data-align={align} style={style}>\n <p>\n <span>{item.title}</span>\n {item.organisation && <span className=\"folio-wb-chronology-org\"> · {item.organisation}</span>}\n {current && currentLabel && <span className=\"folio-wb-chronology-now\"> · {currentLabel}</span>}\n </p>\n <span className=\"folio-wb-chronology-bar\" aria-hidden />\n </li>\n )\n })}\n </ol>\n <div className=\"folio-wb-chronology-axis\" aria-hidden>\n {years.map((year) => (\n <span key={year}>{year}</span>\n ))}\n </div>\n </figure>\n )\n}\n"],"mappings":"AA8CgB,cACsB,YADtB;AAhBT,SAAS,WAAW,EAAE,OAAO,MAAM,IAAI,OAAO,aAAa,GAAoB;AACpF,QAAM,OAAO,KAAK,IAAI;AACtB,QAAM,QAAQ,MAAM,KAAK,EAAE,QAAQ,KAAK,OAAO,EAAE,GAAG,CAAC,GAAG,UAAU,OAAO,KAAK;AAC9E,QAAM,WAAW,CAAC,UAAkB,KAAM,QAAQ,QAAQ,OAAQ,KAAK,QAAQ,CAAC,CAAC;AACjF,SACE,qBAAC,YAAO,WAAU,uBAAsB,cAAY,OAClD;AAAA,wBAAC,QACE,gBAAM,IAAI,CAAC,SAAS;AACnB,YAAM,UAAU,KAAK,QAAQ;AAG7B,YAAM,QAAQ,YAAY,KAAK,QAAQ,QAAQ,QAAQ,MAAM,QAAQ;AACrE,YAAM,QAAQ,EAAE,WAAW,SAAS,KAAK,KAAK,GAAG,SAAS,SAAS,KAAK,OAAO,KAAK,CAAC,EAAE;AACvF,aACE,qBAAC,QAAiB,aAAW,KAAK,MAAM,gBAAc,WAAW,QAAW,cAAY,OAAO,OAC7F;AAAA,6BAAC,OACC;AAAA,8BAAC,UAAM,eAAK,OAAM;AAAA,UACjB,KAAK,gBAAgB,qBAAC,UAAK,WAAU,2BAA0B;AAAA;AAAA,YAAI,KAAK;AAAA,aAAa;AAAA,UACrF,WAAW,gBAAgB,qBAAC,UAAK,WAAU,2BAA0B;AAAA;AAAA,YAAI;AAAA,aAAa;AAAA,WACzF;AAAA,QACA,oBAAC,UAAK,WAAU,2BAA0B,eAAW,MAAC;AAAA,WAN/C,KAAK,EAOd;AAAA,IAEJ,CAAC,GACH;AAAA,IACA,oBAAC,SAAI,WAAU,4BAA2B,eAAW,MAClD,gBAAM,IAAI,CAAC,SACV,oBAAC,UAAiB,kBAAP,IAAY,CACxB,GACH;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface ContactRowProps {
|
|
5
|
+
/** The address, set large — usually a `mailto:` link. */
|
|
6
|
+
address: ReactNode;
|
|
7
|
+
/** One button beside it. */
|
|
8
|
+
action?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/** An address and one action on a single line of the content subgrid. */
|
|
11
|
+
declare function ContactRow({ address, action }: ContactRowProps): react.JSX.Element;
|
|
12
|
+
|
|
13
|
+
export { ContactRow, type ContactRowProps };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
function ContactRow({ address, action }) {
|
|
3
|
+
return /* @__PURE__ */ jsxs("div", { className: "folio-wb-contact", children: [
|
|
4
|
+
/* @__PURE__ */ jsx("div", { className: "folio-wb-contact-address", children: address }),
|
|
5
|
+
action && /* @__PURE__ */ jsx("div", { className: "folio-wb-contact-action", children: action })
|
|
6
|
+
] });
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
ContactRow
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=ContactRow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/website/Workbench/ContactRow.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\n\nexport interface ContactRowProps {\n /** The address, set large — usually a `mailto:` link. */\n address: ReactNode\n /** One button beside it. */\n action?: ReactNode\n}\n\n/** An address and one action on a single line of the content subgrid. */\nexport function ContactRow({ address, action }: ContactRowProps) {\n return (\n <div className=\"folio-wb-contact\">\n <div className=\"folio-wb-contact-address\">{address}</div>\n {action && <div className=\"folio-wb-contact-action\">{action}</div>}\n </div>\n )\n}\n"],"mappings":"AAYI,SACE,KADF;AAFG,SAAS,WAAW,EAAE,SAAS,OAAO,GAAoB;AAC/D,SACE,qBAAC,SAAI,WAAU,oBACb;AAAA,wBAAC,SAAI,WAAU,4BAA4B,mBAAQ;AAAA,IAClD,UAAU,oBAAC,SAAI,WAAU,2BAA2B,kBAAO;AAAA,KAC9D;AAEJ;","names":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface PhotoMosaicProps {
|
|
5
|
+
/** Exactly the photographs to show: the first is the large one, the next four fill a 2×2 beside it. */
|
|
6
|
+
children: ReactNode[];
|
|
7
|
+
/** Caption under the large photograph. */
|
|
8
|
+
caption?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/** One large photograph beside a 2×2 of smaller ones, all on the content subgrid. */
|
|
11
|
+
declare function PhotoMosaic({ children, caption }: PhotoMosaicProps): react.JSX.Element;
|
|
12
|
+
|
|
13
|
+
export { PhotoMosaic, type PhotoMosaicProps };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
function PhotoMosaic({ children, caption }) {
|
|
3
|
+
const [lead, ...rest] = children;
|
|
4
|
+
return /* @__PURE__ */ jsxs("div", { className: "folio-wb-mosaic", children: [
|
|
5
|
+
/* @__PURE__ */ jsxs("figure", { className: "folio-wb-mosaic-lead", children: [
|
|
6
|
+
/* @__PURE__ */ jsx("div", { className: "folio-wb-mosaic-frame", children: lead }),
|
|
7
|
+
caption && /* @__PURE__ */ jsx("figcaption", { children: caption })
|
|
8
|
+
] }),
|
|
9
|
+
rest.slice(0, 4).map((child, index) => /* @__PURE__ */ jsx("div", { className: "folio-wb-mosaic-frame", children: child }, index))
|
|
10
|
+
] });
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
PhotoMosaic
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=PhotoMosaic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/website/Workbench/PhotoMosaic.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\n\nexport interface PhotoMosaicProps {\n /** Exactly the photographs to show: the first is the large one, the next four fill a 2×2 beside it. */\n children: ReactNode[]\n /** Caption under the large photograph. */\n caption?: ReactNode\n}\n\n/** One large photograph beside a 2×2 of smaller ones, all on the content subgrid. */\nexport function PhotoMosaic({ children, caption }: PhotoMosaicProps) {\n const [lead, ...rest] = children\n return (\n <div className=\"folio-wb-mosaic\">\n <figure className=\"folio-wb-mosaic-lead\">\n <div className=\"folio-wb-mosaic-frame\">{lead}</div>\n {caption && <figcaption>{caption}</figcaption>}\n </figure>\n {rest.slice(0, 4).map((child, index) => (\n <div key={index} className=\"folio-wb-mosaic-frame\">\n {child}\n </div>\n ))}\n </div>\n )\n}\n"],"mappings":"AAcM,SACE,KADF;AAJC,SAAS,YAAY,EAAE,UAAU,QAAQ,GAAqB;AACnE,QAAM,CAAC,MAAM,GAAG,IAAI,IAAI;AACxB,SACE,qBAAC,SAAI,WAAU,mBACb;AAAA,yBAAC,YAAO,WAAU,wBAChB;AAAA,0BAAC,SAAI,WAAU,yBAAyB,gBAAK;AAAA,MAC5C,WAAW,oBAAC,gBAAY,mBAAQ;AAAA,OACnC;AAAA,IACC,KAAK,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,OAAO,UAC5B,oBAAC,SAAgB,WAAU,yBACxB,mBADO,KAEV,CACD;AAAA,KACH;AAEJ;","names":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactElement } from 'react';
|
|
3
|
+
|
|
4
|
+
interface RevealProps {
|
|
5
|
+
/** One element; it keeps its own tag and receives the reveal state. */
|
|
6
|
+
children: ReactElement;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Fades and lifts its child the first time it scrolls into view.
|
|
10
|
+
*
|
|
11
|
+
* The server renders the child visible. Only after hydration, and only for an
|
|
12
|
+
* element that starts below the fold, is it hidden and then revealed — so a
|
|
13
|
+
* page without JavaScript, a crawler and anything already on screen never see
|
|
14
|
+
* an empty frame. Reduced motion skips the whole thing, and the duration is the
|
|
15
|
+
* motion axis's own, so `data-motion="still"` makes it instant.
|
|
16
|
+
*/
|
|
17
|
+
declare function Reveal({ children }: RevealProps): react.JSX.Element;
|
|
18
|
+
|
|
19
|
+
export { Reveal, type RevealProps };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
4
|
+
import { useEffect, useRef } from "react";
|
|
5
|
+
function Reveal({ children }) {
|
|
6
|
+
const ref = useRef(null);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const node = ref.current;
|
|
9
|
+
if (!node || typeof IntersectionObserver === "undefined") return;
|
|
10
|
+
if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return;
|
|
11
|
+
if (node.getBoundingClientRect().top < window.innerHeight) return;
|
|
12
|
+
node.dataset.reveal = "hidden";
|
|
13
|
+
const observer = new IntersectionObserver(
|
|
14
|
+
(entries) => {
|
|
15
|
+
if (!entries.some((entry) => entry.isIntersecting)) return;
|
|
16
|
+
node.dataset.reveal = "shown";
|
|
17
|
+
observer.disconnect();
|
|
18
|
+
},
|
|
19
|
+
{ rootMargin: "0px 0px -10% 0px" }
|
|
20
|
+
);
|
|
21
|
+
observer.observe(node);
|
|
22
|
+
return () => observer.disconnect();
|
|
23
|
+
}, []);
|
|
24
|
+
return /* @__PURE__ */ jsx(Slot, { ref, className: "folio-wb-reveal", children });
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
Reveal
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=Reveal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/website/Workbench/Reveal.tsx"],"sourcesContent":["'use client'\n\nimport { Slot } from '@radix-ui/react-slot'\nimport { useEffect, useRef, type ReactElement } from 'react'\n\nexport interface RevealProps {\n /** One element; it keeps its own tag and receives the reveal state. */\n children: ReactElement\n}\n\n/**\n * Fades and lifts its child the first time it scrolls into view.\n *\n * The server renders the child visible. Only after hydration, and only for an\n * element that starts below the fold, is it hidden and then revealed — so a\n * page without JavaScript, a crawler and anything already on screen never see\n * an empty frame. Reduced motion skips the whole thing, and the duration is the\n * motion axis's own, so `data-motion=\"still\"` makes it instant.\n */\nexport function Reveal({ children }: RevealProps) {\n const ref = useRef<HTMLElement>(null)\n useEffect(() => {\n const node = ref.current\n if (!node || typeof IntersectionObserver === 'undefined') return\n if (window.matchMedia?.('(prefers-reduced-motion: reduce)').matches) return\n if (node.getBoundingClientRect().top < window.innerHeight) return\n node.dataset.reveal = 'hidden'\n const observer = new IntersectionObserver(\n (entries) => {\n if (!entries.some((entry) => entry.isIntersecting)) return\n node.dataset.reveal = 'shown'\n observer.disconnect()\n },\n { rootMargin: '0px 0px -10% 0px' },\n )\n observer.observe(node)\n return () => observer.disconnect()\n }, [])\n return <Slot ref={ref} className=\"folio-wb-reveal\">{children}</Slot>\n}\n"],"mappings":";AAsCS;AApCT,SAAS,YAAY;AACrB,SAAS,WAAW,cAAiC;AAgB9C,SAAS,OAAO,EAAE,SAAS,GAAgB;AAChD,QAAM,MAAM,OAAoB,IAAI;AACpC,YAAU,MAAM;AACd,UAAM,OAAO,IAAI;AACjB,QAAI,CAAC,QAAQ,OAAO,yBAAyB,YAAa;AAC1D,QAAI,OAAO,aAAa,kCAAkC,EAAE,QAAS;AACrE,QAAI,KAAK,sBAAsB,EAAE,MAAM,OAAO,YAAa;AAC3D,SAAK,QAAQ,SAAS;AACtB,UAAM,WAAW,IAAI;AAAA,MACnB,CAAC,YAAY;AACX,YAAI,CAAC,QAAQ,KAAK,CAAC,UAAU,MAAM,cAAc,EAAG;AACpD,aAAK,QAAQ,SAAS;AACtB,iBAAS,WAAW;AAAA,MACtB;AAAA,MACA,EAAE,YAAY,mBAAmB;AAAA,IACnC;AACA,aAAS,QAAQ,IAAI;AACrB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,CAAC;AACL,SAAO,oBAAC,QAAK,KAAU,WAAU,mBAAmB,UAAS;AAC/D;","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface ToolStripItem {
|
|
5
|
+
id: string;
|
|
6
|
+
/** The tool's name; it is the tile's accessible label and tooltip. */
|
|
7
|
+
name: string;
|
|
8
|
+
/** A monochrome mark drawn in `currentColor`. */
|
|
9
|
+
icon: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
interface ToolStripProps {
|
|
12
|
+
label: ReactNode;
|
|
13
|
+
items: ToolStripItem[];
|
|
14
|
+
}
|
|
15
|
+
/** A row of equal tiles, one monochrome tool mark each, under a centred caption. */
|
|
16
|
+
declare function ToolStrip({ label, items }: ToolStripProps): react.JSX.Element | null;
|
|
17
|
+
|
|
18
|
+
export { ToolStrip, type ToolStripItem, type ToolStripProps };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
function ToolStrip({ label, items }) {
|
|
3
|
+
if (!items.length) return null;
|
|
4
|
+
return /* @__PURE__ */ jsxs("section", { className: "folio-wb-tools", "aria-label": typeof label === "string" ? label : void 0, children: [
|
|
5
|
+
/* @__PURE__ */ jsx("p", { className: "folio-wb-tools-label", children: label }),
|
|
6
|
+
/* @__PURE__ */ jsx("ul", { children: items.map((item) => /* @__PURE__ */ jsxs("li", { title: item.name, children: [
|
|
7
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: item.icon }),
|
|
8
|
+
/* @__PURE__ */ jsx("span", { className: "folio-wb-visually-hidden", children: item.name })
|
|
9
|
+
] }, item.id)) })
|
|
10
|
+
] });
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
ToolStrip
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=ToolStrip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/website/Workbench/ToolStrip.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\n\nexport interface ToolStripItem {\n id: string\n /** The tool's name; it is the tile's accessible label and tooltip. */\n name: string\n /** A monochrome mark drawn in `currentColor`. */\n icon: ReactNode\n}\n\nexport interface ToolStripProps {\n label: ReactNode\n items: ToolStripItem[]\n}\n\n/** A row of equal tiles, one monochrome tool mark each, under a centred caption. */\nexport function ToolStrip({ label, items }: ToolStripProps) {\n if (!items.length) return null\n return (\n <section className=\"folio-wb-tools\" aria-label={typeof label === 'string' ? label : undefined}>\n <p className=\"folio-wb-tools-label\">{label}</p>\n <ul>\n {items.map((item) => (\n <li key={item.id} title={item.name}>\n <span aria-hidden>{item.icon}</span>\n <span className=\"folio-wb-visually-hidden\">{item.name}</span>\n </li>\n ))}\n </ul>\n </section>\n )\n}\n"],"mappings":"AAoBM,cAGI,YAHJ;AAJC,SAAS,UAAU,EAAE,OAAO,MAAM,GAAmB;AAC1D,MAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,SACE,qBAAC,aAAQ,WAAU,kBAAiB,cAAY,OAAO,UAAU,WAAW,QAAQ,QAClF;AAAA,wBAAC,OAAE,WAAU,wBAAwB,iBAAM;AAAA,IAC3C,oBAAC,QACE,gBAAM,IAAI,CAAC,SACV,qBAAC,QAAiB,OAAO,KAAK,MAC5B;AAAA,0BAAC,UAAK,eAAW,MAAE,eAAK,MAAK;AAAA,MAC7B,oBAAC,UAAK,WAAU,4BAA4B,eAAK,MAAK;AAAA,SAF/C,KAAK,EAGd,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface WorkbenchSectionProps {
|
|
5
|
+
/** The heading's first, ink-coloured clause. */
|
|
6
|
+
title: ReactNode;
|
|
7
|
+
/** The muted continuation that follows the title in the same line. */
|
|
8
|
+
lead?: ReactNode;
|
|
9
|
+
/** One accent link under the heading, such as "All projects →". */
|
|
10
|
+
action?: ReactNode;
|
|
11
|
+
/** Heading level; sections on a page are h2. */
|
|
12
|
+
level?: 2 | 3;
|
|
13
|
+
id?: string;
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The Workbench section: a hairline, a two-tone heading in the first four
|
|
18
|
+
* columns, and the content on an eight-column subgrid beside it. Every section
|
|
19
|
+
* on a Workbench page uses this one rhythm, which is what keeps them aligned.
|
|
20
|
+
*/
|
|
21
|
+
declare function WorkbenchSection({ title, lead, action, level, id, children }: WorkbenchSectionProps): react.JSX.Element;
|
|
22
|
+
|
|
23
|
+
export { WorkbenchSection, type WorkbenchSectionProps };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Reveal } from "./Reveal.js";
|
|
3
|
+
function WorkbenchSection({ title, lead, action, level = 2, id, children }) {
|
|
4
|
+
const Heading = level === 2 ? "h2" : "h3";
|
|
5
|
+
return /* @__PURE__ */ jsx(Reveal, { children: /* @__PURE__ */ jsxs("section", { className: "folio-wb-section", id, children: [
|
|
6
|
+
/* @__PURE__ */ jsxs("div", { className: "folio-wb-section-head", children: [
|
|
7
|
+
/* @__PURE__ */ jsxs(Heading, { className: "folio-wb-heading", children: [
|
|
8
|
+
/* @__PURE__ */ jsx("span", { children: title }),
|
|
9
|
+
lead && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10
|
+
" ",
|
|
11
|
+
/* @__PURE__ */ jsx("span", { className: "folio-wb-heading-lead", children: lead })
|
|
12
|
+
] })
|
|
13
|
+
] }),
|
|
14
|
+
action && /* @__PURE__ */ jsx("div", { className: "folio-wb-section-action", children: action })
|
|
15
|
+
] }),
|
|
16
|
+
/* @__PURE__ */ jsx("div", { className: "folio-wb-section-body", children })
|
|
17
|
+
] }) });
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
WorkbenchSection
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=Workbench.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/website/Workbench/Workbench.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport { Reveal } from './Reveal'\n\nexport interface WorkbenchSectionProps {\n /** The heading's first, ink-coloured clause. */\n title: ReactNode\n /** The muted continuation that follows the title in the same line. */\n lead?: ReactNode\n /** One accent link under the heading, such as \"All projects →\". */\n action?: ReactNode\n /** Heading level; sections on a page are h2. */\n level?: 2 | 3\n id?: string\n children: ReactNode\n}\n\n/**\n * The Workbench section: a hairline, a two-tone heading in the first four\n * columns, and the content on an eight-column subgrid beside it. Every section\n * on a Workbench page uses this one rhythm, which is what keeps them aligned.\n */\nexport function WorkbenchSection({ title, lead, action, level = 2, id, children }: WorkbenchSectionProps) {\n const Heading = level === 2 ? 'h2' : 'h3'\n return (\n <Reveal>\n <section className=\"folio-wb-section\" id={id}>\n <div className=\"folio-wb-section-head\">\n <Heading className=\"folio-wb-heading\">\n <span>{title}</span>\n {lead && <> <span className=\"folio-wb-heading-lead\">{lead}</span></>}\n </Heading>\n {action && <div className=\"folio-wb-section-action\">{action}</div>}\n </div>\n <div className=\"folio-wb-section-body\">{children}</div>\n </section>\n </Reveal>\n )\n}\n"],"mappings":"AA4BY,SACS,UADT,KACS,YADT;AA3BZ,SAAS,cAAc;AAoBhB,SAAS,iBAAiB,EAAE,OAAO,MAAM,QAAQ,QAAQ,GAAG,IAAI,SAAS,GAA0B;AACxG,QAAM,UAAU,UAAU,IAAI,OAAO;AACrC,SACE,oBAAC,UACC,+BAAC,aAAQ,WAAU,oBAAmB,IACpC;AAAA,yBAAC,SAAI,WAAU,yBACb;AAAA,2BAAC,WAAQ,WAAU,oBACjB;AAAA,4BAAC,UAAM,iBAAM;AAAA,QACZ,QAAQ,iCAAE;AAAA;AAAA,UAAC,oBAAC,UAAK,WAAU,yBAAyB,gBAAK;AAAA,WAAO;AAAA,SACnE;AAAA,MACC,UAAU,oBAAC,SAAI,WAAU,2BAA2B,kBAAO;AAAA,OAC9D;AAAA,IACA,oBAAC,SAAI,WAAU,yBAAyB,UAAS;AAAA,KACnD,GACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface WorkbenchCardProps {
|
|
5
|
+
/** A cover image, or a `WorkbenchTile` when there is no picture. */
|
|
6
|
+
cover: ReactNode;
|
|
7
|
+
/** The title, usually a link; the whole card becomes its hit area. */
|
|
8
|
+
title: ReactNode;
|
|
9
|
+
description?: ReactNode;
|
|
10
|
+
meta?: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* An image-led record. The title's link is stretched over the card, so the
|
|
14
|
+
* card is one target without nesting interactive elements.
|
|
15
|
+
*/
|
|
16
|
+
declare function WorkbenchCard({ cover, title, description, meta }: WorkbenchCardProps): react.JSX.Element;
|
|
17
|
+
interface WorkbenchCardGridProps {
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
}
|
|
20
|
+
/** Two cards per row on the content subgrid, one on a phone. */
|
|
21
|
+
declare function WorkbenchCardGrid({ children }: WorkbenchCardGridProps): react.JSX.Element;
|
|
22
|
+
interface WorkbenchTileProps {
|
|
23
|
+
/** Large word set on the tile, such as a product name. */
|
|
24
|
+
label: ReactNode;
|
|
25
|
+
}
|
|
26
|
+
/** A typographic stand-in cover: ink ground, a fine grid, one word. */
|
|
27
|
+
declare function WorkbenchTile({ label }: WorkbenchTileProps): react.JSX.Element;
|
|
28
|
+
|
|
29
|
+
export { WorkbenchCard, WorkbenchCardGrid, type WorkbenchCardGridProps, type WorkbenchCardProps, WorkbenchTile, type WorkbenchTileProps };
|