open-ds 0.0.0-stage → 0.1.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 +66 -2
- package/assets/schemes/accessible-first.json +3093 -0
- package/assets/schemes/brand-expressive.json +3124 -0
- package/assets/schemes/content-first.json +3110 -0
- package/assets/schemes/dense-data.json +3489 -0
- package/assets/schemes/grammar.json +3903 -0
- package/assets/schemes/multi-brand.json +4359 -0
- package/assets/skills/open-ds/SKILL.md +50 -0
- package/assets/skills/open-ds-build/SKILL.md +19 -0
- package/assets/skills/open-ds-change/SKILL.md +19 -0
- package/assets/skills/open-ds-choose/SKILL.md +18 -0
- package/assets/skills/open-ds-review/SKILL.md +22 -0
- package/assets/skills/open-ds-write/SKILL.md +13 -0
- package/assets/stories/accordion.stories.tsx +46 -0
- package/assets/stories/alert-dialog.stories.tsx +65 -0
- package/assets/stories/alert.stories.tsx +44 -0
- package/assets/stories/aspect-ratio.stories.tsx +37 -0
- package/assets/stories/avatar.stories.tsx +42 -0
- package/assets/stories/badge.stories.tsx +39 -0
- package/assets/stories/breadcrumb.stories.tsx +54 -0
- package/assets/stories/button.stories.tsx +46 -0
- package/assets/stories/calendar.stories.tsx +30 -0
- package/assets/stories/card.stories.tsx +50 -0
- package/assets/stories/carousel.stories.tsx +64 -0
- package/assets/stories/chart.stories.tsx +61 -0
- package/assets/stories/checkbox.stories.tsx +29 -0
- package/assets/stories/collapsible.stories.tsx +39 -0
- package/assets/stories/combobox.stories.tsx +57 -0
- package/assets/stories/command.stories.tsx +60 -0
- package/assets/stories/context-menu.stories.tsx +55 -0
- package/assets/stories/data-table.stories.tsx +93 -0
- package/assets/stories/date-picker.stories.tsx +27 -0
- package/assets/stories/dialog.stories.tsx +70 -0
- package/assets/stories/drawer.stories.tsx +62 -0
- package/assets/stories/dropdown-menu.stories.tsx +65 -0
- package/assets/stories/empty.stories.tsx +39 -0
- package/assets/stories/field.stories.tsx +42 -0
- package/assets/stories/form.stories.tsx +56 -0
- package/assets/stories/input-group.stories.tsx +41 -0
- package/assets/stories/input-otp.stories.tsx +48 -0
- package/assets/stories/input.stories.tsx +32 -0
- package/assets/stories/kbd.stories.tsx +30 -0
- package/assets/stories/label.stories.tsx +26 -0
- package/assets/stories/native-select.stories.tsx +39 -0
- package/assets/stories/navigation-menu.stories.tsx +41 -0
- package/assets/stories/pagination.stories.tsx +61 -0
- package/assets/stories/popover.stories.tsx +37 -0
- package/assets/stories/progress.stories.tsx +30 -0
- package/assets/stories/radio-group.stories.tsx +45 -0
- package/assets/stories/resizable.stories.tsx +54 -0
- package/assets/stories/scroll-area.stories.tsx +47 -0
- package/assets/stories/select.stories.tsx +57 -0
- package/assets/stories/separator.stories.tsx +28 -0
- package/assets/stories/sheet.stories.tsx +46 -0
- package/assets/stories/sidebar.stories.tsx +62 -0
- package/assets/stories/skeleton.stories.tsx +27 -0
- package/assets/stories/slider.stories.tsx +44 -0
- package/assets/stories/spinner.stories.tsx +25 -0
- package/assets/stories/switch.stories.tsx +29 -0
- package/assets/stories/table.stories.tsx +97 -0
- package/assets/stories/tabs.stories.tsx +55 -0
- package/assets/stories/textarea.stories.tsx +28 -0
- package/assets/stories/toast.stories.tsx +30 -0
- package/assets/stories/toggle-group.stories.tsx +41 -0
- package/assets/stories/toggle.stories.tsx +20 -0
- package/assets/stories/tooltip.stories.tsx +49 -0
- package/assets/tokens/accessible-first/content.json +32 -0
- package/assets/tokens/accessible-first/dark.tokens.json +581 -0
- package/assets/tokens/accessible-first/light.tokens.json +581 -0
- package/assets/tokens/accessible-first/shadcn.css +21 -0
- package/assets/tokens/accessible-first/theme.css +101 -0
- package/assets/tokens/accessible-first/tokens.css +331 -0
- package/assets/tokens/accessible-first/tokens.json +1616 -0
- package/assets/tokens/accessible-first/tokens.scoped.css +333 -0
- package/assets/tokens/brand-expressive/content.json +32 -0
- package/assets/tokens/brand-expressive/dark.tokens.json +585 -0
- package/assets/tokens/brand-expressive/light.tokens.json +585 -0
- package/assets/tokens/brand-expressive/shadcn.css +21 -0
- package/assets/tokens/brand-expressive/theme.css +101 -0
- package/assets/tokens/brand-expressive/tokens.css +331 -0
- package/assets/tokens/brand-expressive/tokens.json +1651 -0
- package/assets/tokens/brand-expressive/tokens.scoped.css +333 -0
- package/assets/tokens/content-first/content.json +32 -0
- package/assets/tokens/content-first/dark.tokens.json +582 -0
- package/assets/tokens/content-first/light.tokens.json +582 -0
- package/assets/tokens/content-first/shadcn.css +21 -0
- package/assets/tokens/content-first/theme.css +101 -0
- package/assets/tokens/content-first/tokens.css +331 -0
- package/assets/tokens/content-first/tokens.json +1631 -0
- package/assets/tokens/content-first/tokens.scoped.css +333 -0
- package/assets/tokens/dense-data/content.json +32 -0
- package/assets/tokens/dense-data/dark.tokens.json +580 -0
- package/assets/tokens/dense-data/light.tokens.json +580 -0
- package/assets/tokens/dense-data/shadcn.css +21 -0
- package/assets/tokens/dense-data/theme.css +101 -0
- package/assets/tokens/dense-data/tokens.css +331 -0
- package/assets/tokens/dense-data/tokens.json +1623 -0
- package/assets/tokens/dense-data/tokens.scoped.css +333 -0
- package/assets/tokens/index.json +143 -0
- package/assets/tokens/multi-brand/aster-dark.tokens.json +625 -0
- package/assets/tokens/multi-brand/aster-light.tokens.json +625 -0
- package/assets/tokens/multi-brand/birch-dark.tokens.json +625 -0
- package/assets/tokens/multi-brand/birch-light.tokens.json +625 -0
- package/assets/tokens/multi-brand/content.json +32 -0
- package/assets/tokens/multi-brand/coral-dark.tokens.json +625 -0
- package/assets/tokens/multi-brand/coral-light.tokens.json +625 -0
- package/assets/tokens/multi-brand/shadcn.css +21 -0
- package/assets/tokens/multi-brand/theme.css +101 -0
- package/assets/tokens/multi-brand/tokens.css +1002 -0
- package/assets/tokens/multi-brand/tokens.json +1754 -0
- package/assets/tokens/multi-brand/tokens.scoped.css +1022 -0
- package/assets/tokens/shadcn-map.json +34 -0
- package/assets/ui/components/accordion.tsx +60 -0
- package/assets/ui/components/alert-dialog.tsx +171 -0
- package/assets/ui/components/alert.tsx +56 -0
- package/assets/ui/components/aspect-ratio.tsx +17 -0
- package/assets/ui/components/avatar.tsx +96 -0
- package/assets/ui/components/badge.tsx +36 -0
- package/assets/ui/components/breadcrumb.tsx +99 -0
- package/assets/ui/components/button.tsx +53 -0
- package/assets/ui/components/calendar.tsx +169 -0
- package/assets/ui/components/card.tsx +72 -0
- package/assets/ui/components/carousel.tsx +224 -0
- package/assets/ui/components/chart.tsx +315 -0
- package/assets/ui/components/checkbox.tsx +29 -0
- package/assets/ui/components/collapsible.tsx +25 -0
- package/assets/ui/components/combobox.tsx +275 -0
- package/assets/ui/components/command.tsx +145 -0
- package/assets/ui/components/context-menu.tsx +218 -0
- package/assets/ui/components/data-table.tsx +307 -0
- package/assets/ui/components/date-picker.tsx +79 -0
- package/assets/ui/components/dialog.tsx +68 -0
- package/assets/ui/components/drawer.tsx +115 -0
- package/assets/ui/components/dropdown-menu.tsx +58 -0
- package/assets/ui/components/empty.tsx +92 -0
- package/assets/ui/components/field.tsx +234 -0
- package/assets/ui/components/form.tsx +146 -0
- package/assets/ui/components/input-group.tsx +154 -0
- package/assets/ui/components/input-otp.tsx +75 -0
- package/assets/ui/components/input.tsx +25 -0
- package/assets/ui/components/kbd.tsx +30 -0
- package/assets/ui/components/label.tsx +22 -0
- package/assets/ui/components/native-select.tsx +59 -0
- package/assets/ui/components/navigation-menu.tsx +149 -0
- package/assets/ui/components/pagination.tsx +108 -0
- package/assets/ui/components/popover.tsx +61 -0
- package/assets/ui/components/progress.tsx +31 -0
- package/assets/ui/components/radio-group.tsx +40 -0
- package/assets/ui/components/resizable.tsx +54 -0
- package/assets/ui/components/scroll-area.tsx +55 -0
- package/assets/ui/components/select.tsx +81 -0
- package/assets/ui/components/separator.tsx +35 -0
- package/assets/ui/components/sheet.tsx +114 -0
- package/assets/ui/components/sidebar.tsx +685 -0
- package/assets/ui/components/skeleton.tsx +15 -0
- package/assets/ui/components/slider.tsx +70 -0
- package/assets/ui/components/spinner.tsx +16 -0
- package/assets/ui/components/switch.tsx +32 -0
- package/assets/ui/components/table.tsx +78 -0
- package/assets/ui/components/tabs.tsx +49 -0
- package/assets/ui/components/textarea.tsx +25 -0
- package/assets/ui/components/toast.tsx +54 -0
- package/assets/ui/components/toggle-group.tsx +88 -0
- package/assets/ui/components/toggle.tsx +48 -0
- package/assets/ui/components/tooltip.tsx +34 -0
- package/assets/ui/lib/use-mobile.ts +20 -0
- package/assets/ui/lib/utils.ts +7 -0
- package/assets/ui/styles.css +27 -0
- package/bin/open-ds.js +6 -0
- package/package.json +56 -4
- package/src/agents.mjs +150 -0
- package/src/cli.mjs +445 -0
- package/src/components.mjs +69 -0
- package/src/context.mjs +143 -0
- package/src/create.mjs +377 -0
- package/src/docs.mjs +570 -0
- package/src/guidance.mjs +63 -0
- package/src/index.mjs +20 -0
- package/src/mcp.mjs +660 -0
- package/src/readmes.mjs +106 -0
- package/src/schemes.mjs +188 -0
- package/src/tokens.mjs +127 -0
- package/templates/project/.github/workflows/ci.yml +15 -0
- package/templates/project/.storybook/component-docs.mdx +26 -0
- package/templates/project/.storybook/main.ts +17 -0
- package/templates/project/.storybook/manager-head.html +3 -0
- package/templates/project/.storybook/manager.ts +37 -0
- package/templates/project/.storybook/preview-head.html +3 -0
- package/templates/project/.storybook/preview.tsx +82 -0
- package/templates/project/docs/docusaurus.config.ts +64 -0
- package/templates/project/docs/sidebars.ts +8 -0
- package/templates/project/docs/src/css/custom.css +275 -0
- package/templates/project/gitignore +6 -0
- package/templates/project/src/styles/index.css +16 -0
- package/templates/project/src/vite-env.d.ts +7 -0
- package/templates/project/stories/docs-blocks.tsx +190 -0
- package/templates/project/stories/samples.tsx +102 -0
- package/templates/project/stories/usage.tsx +31 -0
- package/templates/project/tokens/build.mjs +468 -0
- package/templates/project/tsconfig.json +15 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/* The docs wear the design system. build/docusaurus.css (npm run tokens) holds its tokens and
|
|
2
|
+
points Docusaurus's own variables at them. The rules below dress the parts Docusaurus has no
|
|
3
|
+
variable for in the same tokens and component keys. */
|
|
4
|
+
@import url("https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible:wght@400;700&family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,600;12..96,800&family=DM+Mono:wght@400;500&family=DM+Sans:wght@400;700&family=IBM+Plex+Mono&family=IBM+Plex+Sans:wght@400;500;600&family=Inter:wght@400;600;700&family=Plus+Jakarta+Sans:wght@400;600;700&family=Poppins:wght@400;600;700&family=Source+Serif+4:wght@400;600&display=swap");
|
|
5
|
+
@import "../../../build/docusaurus.css";
|
|
6
|
+
|
|
7
|
+
body {
|
|
8
|
+
font-size: var(--type-body-font-size);
|
|
9
|
+
-webkit-font-smoothing: antialiased;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/* Headings follow the type scale, the first one included. */
|
|
13
|
+
.markdown h1:first-child,
|
|
14
|
+
.markdown h1 {
|
|
15
|
+
--ifm-h1-font-size: var(--type-display-font-size);
|
|
16
|
+
line-height: var(--type-display-line-height);
|
|
17
|
+
font-weight: var(--type-display-font-weight);
|
|
18
|
+
}
|
|
19
|
+
.markdown h2 {
|
|
20
|
+
line-height: var(--type-title-line-height);
|
|
21
|
+
font-weight: var(--type-title-font-weight);
|
|
22
|
+
margin-top: var(--space-gap-section);
|
|
23
|
+
}
|
|
24
|
+
.markdown h3 {
|
|
25
|
+
line-height: var(--type-heading-line-height);
|
|
26
|
+
font-weight: var(--type-heading-font-weight);
|
|
27
|
+
}
|
|
28
|
+
.markdown > h2 {
|
|
29
|
+
--ifm-h2-font-size: var(--type-title-font-size);
|
|
30
|
+
--ifm-h2-vertical-rhythm-top: 1;
|
|
31
|
+
}
|
|
32
|
+
.markdown > h3 {
|
|
33
|
+
--ifm-h3-font-size: var(--type-heading-font-size);
|
|
34
|
+
--ifm-h3-vertical-rhythm-top: 1;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Navigation: label type, control density. */
|
|
38
|
+
.menu__link,
|
|
39
|
+
.table-of-contents__link,
|
|
40
|
+
.breadcrumbs__link,
|
|
41
|
+
.navbar__link {
|
|
42
|
+
font-size: var(--type-label-font-size);
|
|
43
|
+
line-height: var(--type-label-line-height);
|
|
44
|
+
font-weight: var(--type-label-font-weight);
|
|
45
|
+
}
|
|
46
|
+
.menu__link--active:not(.menu__link--sublist) {
|
|
47
|
+
border-radius: var(--radius-control);
|
|
48
|
+
}
|
|
49
|
+
.breadcrumbs__item--active .breadcrumbs__link {
|
|
50
|
+
background: var(--color-surface-selected);
|
|
51
|
+
border-radius: var(--radius-control);
|
|
52
|
+
}
|
|
53
|
+
.navbar {
|
|
54
|
+
border-bottom: var(--border-width-default) solid var(--color-border-default);
|
|
55
|
+
box-shadow: none;
|
|
56
|
+
}
|
|
57
|
+
.footer {
|
|
58
|
+
border-top: var(--border-width-default) solid var(--color-border-default);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Tables read the table component keys. */
|
|
62
|
+
.markdown table {
|
|
63
|
+
display: table;
|
|
64
|
+
width: 100%;
|
|
65
|
+
border-collapse: collapse;
|
|
66
|
+
font-size: var(--table-font-size);
|
|
67
|
+
}
|
|
68
|
+
.markdown table thead tr {
|
|
69
|
+
background: var(--table-header-background);
|
|
70
|
+
}
|
|
71
|
+
.markdown table th,
|
|
72
|
+
.markdown table td {
|
|
73
|
+
border: 0;
|
|
74
|
+
border-bottom: var(--border-width-default) solid var(--table-row-border);
|
|
75
|
+
padding: 0 var(--table-cell-padding-x);
|
|
76
|
+
height: var(--table-row-height);
|
|
77
|
+
text-align: left;
|
|
78
|
+
}
|
|
79
|
+
.markdown table th {
|
|
80
|
+
font-size: var(--type-label-font-size);
|
|
81
|
+
font-weight: var(--type-label-font-weight);
|
|
82
|
+
color: var(--color-text-secondary);
|
|
83
|
+
}
|
|
84
|
+
.markdown table tr:nth-child(2n) {
|
|
85
|
+
background: transparent;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Code uses the data type. */
|
|
89
|
+
code {
|
|
90
|
+
font-family: var(--type-data-font-family);
|
|
91
|
+
border: var(--border-width-default) solid var(--color-border-default);
|
|
92
|
+
padding: 0 var(--space-gap-tight);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Cards, buttons, badges, tabs and callouts read their component keys. */
|
|
96
|
+
.card,
|
|
97
|
+
.pagination-nav__link {
|
|
98
|
+
background: var(--card-background);
|
|
99
|
+
border: var(--border-width-default) solid var(--card-border);
|
|
100
|
+
border-radius: var(--card-radius);
|
|
101
|
+
box-shadow: var(--card-shadow);
|
|
102
|
+
}
|
|
103
|
+
.button {
|
|
104
|
+
height: var(--button-height);
|
|
105
|
+
font-size: var(--button-font-size);
|
|
106
|
+
font-weight: var(--button-font-weight);
|
|
107
|
+
line-height: var(--button-height);
|
|
108
|
+
padding-top: 0;
|
|
109
|
+
padding-bottom: 0;
|
|
110
|
+
}
|
|
111
|
+
.button--primary {
|
|
112
|
+
background: var(--button-primary-background);
|
|
113
|
+
border-color: var(--button-primary-background);
|
|
114
|
+
color: var(--button-primary-label);
|
|
115
|
+
}
|
|
116
|
+
.button--primary:hover {
|
|
117
|
+
background: var(--button-primary-background-hover);
|
|
118
|
+
}
|
|
119
|
+
.button--secondary {
|
|
120
|
+
background: var(--button-secondary-background);
|
|
121
|
+
border-color: var(--button-secondary-border);
|
|
122
|
+
color: var(--button-secondary-label);
|
|
123
|
+
}
|
|
124
|
+
.badge {
|
|
125
|
+
font-size: var(--badge-font-size);
|
|
126
|
+
padding: 0 var(--badge-padding-x);
|
|
127
|
+
background: var(--badge-neutral-background);
|
|
128
|
+
color: var(--badge-neutral-label);
|
|
129
|
+
border: 0;
|
|
130
|
+
}
|
|
131
|
+
.tabs__item {
|
|
132
|
+
color: var(--tabs-label);
|
|
133
|
+
font-size: var(--type-label-font-size);
|
|
134
|
+
}
|
|
135
|
+
.tabs__item--active {
|
|
136
|
+
color: var(--tabs-label-active);
|
|
137
|
+
border-bottom-color: var(--tabs-indicator);
|
|
138
|
+
}
|
|
139
|
+
.alert,
|
|
140
|
+
.theme-admonition {
|
|
141
|
+
border-radius: var(--radius-container);
|
|
142
|
+
border-width: var(--border-width-default);
|
|
143
|
+
box-shadow: none;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* Specimens: small live samples on the foundation pages, drawn from the token variables. */
|
|
147
|
+
.ods-specimen {
|
|
148
|
+
display: flex;
|
|
149
|
+
flex-wrap: wrap;
|
|
150
|
+
gap: var(--space-gap-default, 0.5rem) var(--space-gap-group, 1rem);
|
|
151
|
+
padding: var(--space-inset-container, 1rem);
|
|
152
|
+
margin-bottom: var(--space-gap-section, 1.5rem);
|
|
153
|
+
border: var(--border-width-default, 1px) solid var(--color-border-default);
|
|
154
|
+
border-radius: var(--radius-container, 0.375rem);
|
|
155
|
+
background: var(--color-surface-default);
|
|
156
|
+
}
|
|
157
|
+
.ods-item {
|
|
158
|
+
display: inline-flex;
|
|
159
|
+
align-items: center;
|
|
160
|
+
gap: var(--space-gap-default, 0.5rem);
|
|
161
|
+
min-width: 13rem;
|
|
162
|
+
}
|
|
163
|
+
.ods-type {
|
|
164
|
+
display: flex;
|
|
165
|
+
align-items: baseline;
|
|
166
|
+
gap: var(--space-gap-group, 1rem);
|
|
167
|
+
width: 100%;
|
|
168
|
+
}
|
|
169
|
+
.ods-type .ods-label {
|
|
170
|
+
flex: 0 0 5rem;
|
|
171
|
+
}
|
|
172
|
+
.ods-label {
|
|
173
|
+
font-family: var(--type-data-font-family, monospace);
|
|
174
|
+
font-size: var(--type-caption-font-size, 0.75rem);
|
|
175
|
+
color: var(--color-text-muted);
|
|
176
|
+
}
|
|
177
|
+
.ods-swatch,
|
|
178
|
+
.ods-tile,
|
|
179
|
+
.ods-card {
|
|
180
|
+
display: inline-block;
|
|
181
|
+
width: 1.5rem;
|
|
182
|
+
height: 1.5rem;
|
|
183
|
+
flex: none;
|
|
184
|
+
border-radius: var(--radius-control, 0.25rem);
|
|
185
|
+
border: var(--border-width-default, 1px) solid var(--color-border-default);
|
|
186
|
+
}
|
|
187
|
+
.ods-swatch {
|
|
188
|
+
background: var(--color-text-primary);
|
|
189
|
+
}
|
|
190
|
+
.ods-tile {
|
|
191
|
+
background: var(--color-surface-sunken);
|
|
192
|
+
border-color: var(--color-border-strong);
|
|
193
|
+
}
|
|
194
|
+
.ods-card {
|
|
195
|
+
width: 2.5rem;
|
|
196
|
+
background: var(--color-surface-raised);
|
|
197
|
+
}
|
|
198
|
+
.ods-bar {
|
|
199
|
+
display: inline-block;
|
|
200
|
+
height: 0.5rem;
|
|
201
|
+
min-width: 1px;
|
|
202
|
+
background: var(--color-action-primary);
|
|
203
|
+
border-radius: 1px;
|
|
204
|
+
}
|
|
205
|
+
.ods-line {
|
|
206
|
+
display: inline-block;
|
|
207
|
+
width: 1.5rem;
|
|
208
|
+
background: var(--color-text-primary);
|
|
209
|
+
}
|
|
210
|
+
.ods-font {
|
|
211
|
+
font-size: 1.125rem;
|
|
212
|
+
}
|
|
213
|
+
.ods-motion {
|
|
214
|
+
display: inline-block;
|
|
215
|
+
width: 3rem;
|
|
216
|
+
height: 0.75rem;
|
|
217
|
+
border-radius: 9999px;
|
|
218
|
+
background: var(--color-surface-sunken);
|
|
219
|
+
position: relative;
|
|
220
|
+
}
|
|
221
|
+
.ods-motion > span {
|
|
222
|
+
position: absolute;
|
|
223
|
+
left: 0;
|
|
224
|
+
top: 0;
|
|
225
|
+
width: 0.75rem;
|
|
226
|
+
height: 0.75rem;
|
|
227
|
+
border-radius: 9999px;
|
|
228
|
+
background: var(--color-action-primary);
|
|
229
|
+
transition: left var(--ods-d) var(--motion-easing-standard, ease);
|
|
230
|
+
}
|
|
231
|
+
.ods-specimen:hover .ods-motion > span {
|
|
232
|
+
left: 2.25rem;
|
|
233
|
+
}
|
|
234
|
+
@media (prefers-reduced-motion: reduce) {
|
|
235
|
+
.ods-motion > span {
|
|
236
|
+
transition: none;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
.markdown table .ods-swatch,
|
|
240
|
+
.markdown table .ods-tile,
|
|
241
|
+
.markdown table .ods-card {
|
|
242
|
+
vertical-align: middle;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/* The brand: the Open DS mark in this system's colours, its name in the title type, and a tag
|
|
246
|
+
that says these are its docs. */
|
|
247
|
+
.navbar__brand {
|
|
248
|
+
gap: var(--space-gap-default);
|
|
249
|
+
}
|
|
250
|
+
.navbar__logo {
|
|
251
|
+
height: 1.25rem;
|
|
252
|
+
margin-right: 0;
|
|
253
|
+
}
|
|
254
|
+
.navbar__logo img {
|
|
255
|
+
height: 100%;
|
|
256
|
+
}
|
|
257
|
+
.navbar__title {
|
|
258
|
+
font-family: var(--type-title-font-family);
|
|
259
|
+
font-weight: var(--type-title-font-weight);
|
|
260
|
+
font-size: var(--type-heading-font-size);
|
|
261
|
+
}
|
|
262
|
+
.ods-docs-tag {
|
|
263
|
+
display: inline-flex;
|
|
264
|
+
align-items: center;
|
|
265
|
+
height: 1.375rem;
|
|
266
|
+
padding: 0 var(--badge-padding-x);
|
|
267
|
+
border-radius: var(--badge-radius);
|
|
268
|
+
background: var(--color-surface-selected);
|
|
269
|
+
color: var(--color-text-link);
|
|
270
|
+
font-family: var(--type-label-font-family);
|
|
271
|
+
font-size: var(--type-caption-font-size);
|
|
272
|
+
font-weight: var(--type-label-font-weight);
|
|
273
|
+
letter-spacing: 0.02em;
|
|
274
|
+
text-transform: uppercase;
|
|
275
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* The design system's styles: Tailwind, the tokens built by Style Dictionary (npm run tokens),
|
|
2
|
+
the shadcn and Tailwind theme, and the base styles. Import this once in an app. */
|
|
3
|
+
@import "tailwindcss";
|
|
4
|
+
@import "../../build/tokens.css";
|
|
5
|
+
@import "../../build/theme.css";
|
|
6
|
+
@import "../../build/shadcn.css";
|
|
7
|
+
@import "./base.css";
|
|
8
|
+
|
|
9
|
+
@source "../";
|
|
10
|
+
@source "../../stories";
|
|
11
|
+
|
|
12
|
+
/* Portalled overlays sit on body, so body carries the scheme font too. */
|
|
13
|
+
body {
|
|
14
|
+
font-family: var(--type-body-font-family);
|
|
15
|
+
color: var(--color-text-primary);
|
|
16
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// The blocks of every component's docs page. Each reads the component id and situations from the
|
|
2
|
+
// stories' parameters (openDs), and this design system's scheme.json.
|
|
3
|
+
import { useOf } from "@storybook/addon-docs/blocks";
|
|
4
|
+
import scheme from "../scheme.json";
|
|
5
|
+
import grammar from "../.open-ds/grammar.json";
|
|
6
|
+
import type { Samples } from "./samples";
|
|
7
|
+
|
|
8
|
+
interface SchemeData {
|
|
9
|
+
name: string;
|
|
10
|
+
inventory: {
|
|
11
|
+
in: { id: string; why: string }[];
|
|
12
|
+
out: { id: string; why: string }[];
|
|
13
|
+
};
|
|
14
|
+
samples: Samples;
|
|
15
|
+
usage: { situation: string; use: string; not: string; why: string }[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type Meta = { component: string; situations: string[] };
|
|
19
|
+
type Tree = Record<string, unknown>;
|
|
20
|
+
|
|
21
|
+
// The component keys each built component reads.
|
|
22
|
+
const KEY_GROUP: Record<string, string> = {
|
|
23
|
+
button: "button",
|
|
24
|
+
input: "input",
|
|
25
|
+
select: "input",
|
|
26
|
+
label: "input",
|
|
27
|
+
checkbox: "control",
|
|
28
|
+
switch: "control",
|
|
29
|
+
badge: "badge",
|
|
30
|
+
card: "card",
|
|
31
|
+
table: "table",
|
|
32
|
+
tabs: "tabs",
|
|
33
|
+
dialog: "overlay",
|
|
34
|
+
"dropdown-menu": "overlay",
|
|
35
|
+
toast: "overlay",
|
|
36
|
+
tooltip: "overlay",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** This design system's scheme. */
|
|
40
|
+
function useActiveScheme(): SchemeData {
|
|
41
|
+
return scheme as unknown as SchemeData;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function useOpenDs(): Meta {
|
|
45
|
+
const resolved = useOf("meta");
|
|
46
|
+
const meta = resolved.type === "meta" ? resolved.preparedMeta : undefined;
|
|
47
|
+
return (meta?.parameters?.openDs ?? {
|
|
48
|
+
component: "",
|
|
49
|
+
situations: [],
|
|
50
|
+
}) as Meta;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const get = (tree: unknown, path: string) =>
|
|
54
|
+
path
|
|
55
|
+
.split(".")
|
|
56
|
+
.reduce<unknown>(
|
|
57
|
+
(n, p) => (n && typeof n === "object" ? (n as Tree)[p] : undefined),
|
|
58
|
+
tree,
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
/** The aliases a key points through, light mode, default brand. */
|
|
62
|
+
function chain(s: SchemeData, path: string) {
|
|
63
|
+
const t = (s as unknown as { tokens: Tree }).tokens as {
|
|
64
|
+
primitive: Tree;
|
|
65
|
+
brands: Record<string, { theme: { base?: Tree; light: Tree } }>;
|
|
66
|
+
semantic: Tree;
|
|
67
|
+
component: Tree;
|
|
68
|
+
};
|
|
69
|
+
// Component key → semantic → the first brand's light theme pick → primitive.
|
|
70
|
+
const theme = Object.values(t.brands)[0].theme;
|
|
71
|
+
const trees = [
|
|
72
|
+
t.component,
|
|
73
|
+
t.semantic,
|
|
74
|
+
{ theme: { ...theme.base, ...theme.light } },
|
|
75
|
+
t.primitive,
|
|
76
|
+
];
|
|
77
|
+
const steps: string[] = [];
|
|
78
|
+
let at = path;
|
|
79
|
+
for (let i = 0; i < 8; i++) {
|
|
80
|
+
const node = trees
|
|
81
|
+
.map((x) => get(x, at))
|
|
82
|
+
.find((n) => n && typeof n === "object" && "$value" in (n as Tree)) as
|
|
83
|
+
| { $value: unknown }
|
|
84
|
+
| undefined;
|
|
85
|
+
const m =
|
|
86
|
+
typeof node?.$value === "string" && node.$value.match(/^\{(.+)\}$/);
|
|
87
|
+
if (!m) break;
|
|
88
|
+
steps.push(m[1]);
|
|
89
|
+
at = m[1];
|
|
90
|
+
}
|
|
91
|
+
return steps;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function ComponentInfo() {
|
|
95
|
+
const { component } = useOpenDs();
|
|
96
|
+
const s = useActiveScheme();
|
|
97
|
+
const item = grammar.catalogue.items.find((i) => i.id === component);
|
|
98
|
+
const inv = s.inventory.in.find((i) => i.id === component);
|
|
99
|
+
const out = s.inventory.out.find((i) => i.id === component);
|
|
100
|
+
return (
|
|
101
|
+
<div className="sb-unstyled ods-info">
|
|
102
|
+
<p>{item?.description}</p>
|
|
103
|
+
<p>
|
|
104
|
+
<strong>
|
|
105
|
+
{inv ? "In" : "Not in"} the {s.name} inventory.
|
|
106
|
+
</strong>{" "}
|
|
107
|
+
{inv?.why ?? out?.why ?? "Its answers did not pick it."}{" "}
|
|
108
|
+
{s.inventory.in.length} of {grammar.catalogue.items.length} catalogue
|
|
109
|
+
components are in.
|
|
110
|
+
</p>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function UsageRules() {
|
|
116
|
+
const { situations } = useOpenDs();
|
|
117
|
+
const s = useActiveScheme();
|
|
118
|
+
const titles = Object.fromEntries(
|
|
119
|
+
grammar.situations.map((x) => [x.id, x.title]),
|
|
120
|
+
);
|
|
121
|
+
const rules = s.usage.filter((u) => situations.includes(u.situation));
|
|
122
|
+
if (!rules.length) return null;
|
|
123
|
+
return (
|
|
124
|
+
<table className="ods-table">
|
|
125
|
+
<thead>
|
|
126
|
+
<tr>
|
|
127
|
+
<th>Situation</th>
|
|
128
|
+
<th>Use</th>
|
|
129
|
+
<th>Not</th>
|
|
130
|
+
<th>Why</th>
|
|
131
|
+
</tr>
|
|
132
|
+
</thead>
|
|
133
|
+
<tbody>
|
|
134
|
+
{rules.map((r) => (
|
|
135
|
+
<tr key={r.situation}>
|
|
136
|
+
<td>{titles[r.situation]}</td>
|
|
137
|
+
<td>{r.use}</td>
|
|
138
|
+
<td>{r.not}</td>
|
|
139
|
+
<td>{r.why}</td>
|
|
140
|
+
</tr>
|
|
141
|
+
))}
|
|
142
|
+
</tbody>
|
|
143
|
+
</table>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function ComponentKeys() {
|
|
148
|
+
const { component } = useOpenDs();
|
|
149
|
+
const s = useActiveScheme();
|
|
150
|
+
const keys = grammar.component_keys.filter(
|
|
151
|
+
(k) => k.component === KEY_GROUP[component],
|
|
152
|
+
);
|
|
153
|
+
if (!keys.length)
|
|
154
|
+
return (
|
|
155
|
+
<p>
|
|
156
|
+
From shadcn/ui. It reads shadcn's variables, which theme.css maps
|
|
157
|
+
onto the design system's semantic tokens, and the radius, shadow
|
|
158
|
+
and text scale in shadcn.css.
|
|
159
|
+
</p>
|
|
160
|
+
);
|
|
161
|
+
return (
|
|
162
|
+
<table className="ods-table">
|
|
163
|
+
<thead>
|
|
164
|
+
<tr>
|
|
165
|
+
<th>Key</th>
|
|
166
|
+
<th>What it controls</th>
|
|
167
|
+
<th>Points to</th>
|
|
168
|
+
</tr>
|
|
169
|
+
</thead>
|
|
170
|
+
<tbody>
|
|
171
|
+
{keys.map((k) => (
|
|
172
|
+
<tr key={k.id}>
|
|
173
|
+
<td>
|
|
174
|
+
<code>{k.id}</code>
|
|
175
|
+
</td>
|
|
176
|
+
<td>{k.description}</td>
|
|
177
|
+
<td>
|
|
178
|
+
{chain(s, k.id.replaceAll("/", ".")).map((x, i) => (
|
|
179
|
+
<span key={x}>
|
|
180
|
+
{i ? " → " : ""}
|
|
181
|
+
<code>{x}</code>
|
|
182
|
+
</span>
|
|
183
|
+
))}
|
|
184
|
+
</td>
|
|
185
|
+
</tr>
|
|
186
|
+
))}
|
|
187
|
+
</tbody>
|
|
188
|
+
</table>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// This design system's sample content and inventory (scheme.json). Every story shows its own words,
|
|
2
|
+
// data and status meanings, and says so when the system does not carry the component.
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import scheme from "../scheme.json";
|
|
5
|
+
|
|
6
|
+
type Status = {
|
|
7
|
+
label: string;
|
|
8
|
+
meaning: "neutral" | "info" | "success" | "warning" | "danger";
|
|
9
|
+
why: string;
|
|
10
|
+
};
|
|
11
|
+
export interface Samples {
|
|
12
|
+
screen: string;
|
|
13
|
+
actions: { primary: string; secondary: string };
|
|
14
|
+
statuses: Status[];
|
|
15
|
+
table?: {
|
|
16
|
+
caption: string;
|
|
17
|
+
columns: { label: string; numeric?: boolean }[];
|
|
18
|
+
rows: { cells: string[]; status: string }[];
|
|
19
|
+
};
|
|
20
|
+
metrics: { label: string; value: string }[];
|
|
21
|
+
field: {
|
|
22
|
+
label: string;
|
|
23
|
+
placeholder: string;
|
|
24
|
+
hint: string;
|
|
25
|
+
error: string;
|
|
26
|
+
invalid: string;
|
|
27
|
+
};
|
|
28
|
+
checkbox?: string[];
|
|
29
|
+
select?: { label: string; options: string[]; value: string };
|
|
30
|
+
switches?: string[];
|
|
31
|
+
messages?: {
|
|
32
|
+
success: string;
|
|
33
|
+
error: { title: string; description: string };
|
|
34
|
+
neutral: string;
|
|
35
|
+
};
|
|
36
|
+
confirm?: {
|
|
37
|
+
trigger: string;
|
|
38
|
+
title: string;
|
|
39
|
+
body: string;
|
|
40
|
+
confirm: string;
|
|
41
|
+
cancel: string;
|
|
42
|
+
};
|
|
43
|
+
card?: {
|
|
44
|
+
title: string;
|
|
45
|
+
description: string;
|
|
46
|
+
status: string;
|
|
47
|
+
primary: string;
|
|
48
|
+
secondary: string;
|
|
49
|
+
};
|
|
50
|
+
tabs?: { label: string; content: string }[];
|
|
51
|
+
menu?: { trigger: string; items: string[]; destructive: string };
|
|
52
|
+
icon_action?: string;
|
|
53
|
+
}
|
|
54
|
+
const data = scheme as unknown as {
|
|
55
|
+
name: string;
|
|
56
|
+
inventory: { in: { id: string }[]; out: { id: string; why: string }[] };
|
|
57
|
+
samples: Samples;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/** The tone a status label maps to, from its meaning in the scheme. */
|
|
61
|
+
export const toneOf = (s: Samples, label: string) =>
|
|
62
|
+
s.statuses.find((x) => x.label === label)?.meaning ?? "neutral";
|
|
63
|
+
|
|
64
|
+
// The samples part each component's examples read.
|
|
65
|
+
const PART: Record<string, keyof Samples> = {
|
|
66
|
+
badge: "statuses",
|
|
67
|
+
card: "card",
|
|
68
|
+
checkbox: "checkbox",
|
|
69
|
+
dialog: "confirm",
|
|
70
|
+
"dropdown-menu": "menu",
|
|
71
|
+
select: "select",
|
|
72
|
+
switch: "switches",
|
|
73
|
+
table: "table",
|
|
74
|
+
tabs: "tabs",
|
|
75
|
+
toast: "messages",
|
|
76
|
+
tooltip: "icon_action",
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export function Show({
|
|
80
|
+
component,
|
|
81
|
+
children,
|
|
82
|
+
}: {
|
|
83
|
+
component: string;
|
|
84
|
+
children: (s: Samples) => ReactNode;
|
|
85
|
+
}) {
|
|
86
|
+
if (!data.inventory.in.some((i) => i.id === component)) {
|
|
87
|
+
const out = data.inventory.out.find((i) => i.id === component);
|
|
88
|
+
return (
|
|
89
|
+
<p className="max-w-xl border-l-[length:var(--border-width-focus)] border-[var(--color-border-strong)] pl-[var(--space-gap-group)] text-[var(--color-text-secondary)]">
|
|
90
|
+
{data.name} does not carry this component.{" "}
|
|
91
|
+
{out?.why ?? "It is not in its inventory."}
|
|
92
|
+
</p>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (PART[component] && !data.samples[PART[component]])
|
|
96
|
+
return (
|
|
97
|
+
<p className="text-[var(--color-text-secondary)]">
|
|
98
|
+
{data.name} has no sample content for this component yet.
|
|
99
|
+
</p>
|
|
100
|
+
);
|
|
101
|
+
return <>{children(data.samples)}</>;
|
|
102
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Shows this design system's when-to-use rules for the situations a component serves.
|
|
2
|
+
import scheme from "../scheme.json";
|
|
3
|
+
import situations from "../.open-ds/situations.json";
|
|
4
|
+
|
|
5
|
+
const TITLES: Record<string, string> = Object.fromEntries(
|
|
6
|
+
situations.map((s) => [s.id, s.title]),
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
export function Usage({ situations: ids }: { situations: string[] }) {
|
|
10
|
+
const rules = scheme.usage.filter((u) => ids.includes(u.situation));
|
|
11
|
+
if (!rules.length) return null;
|
|
12
|
+
return (
|
|
13
|
+
<section className="mt-[var(--space-gap-section)] max-w-3xl border-t-[length:var(--border-width-default)] border-[var(--color-border-default)] pt-[var(--space-gap-group)]">
|
|
14
|
+
<h2 className="mb-[var(--space-gap-default)] [font-family:var(--type-heading-font-family)] text-[length:var(--type-heading-font-size)] [font-weight:var(--type-heading-font-weight)]">
|
|
15
|
+
When to use
|
|
16
|
+
</h2>
|
|
17
|
+
<dl className="grid gap-[var(--space-gap-group)]">
|
|
18
|
+
{rules.map((r) => (
|
|
19
|
+
<div key={r.situation}>
|
|
20
|
+
<dt className="[font-weight:var(--type-label-font-weight)]">
|
|
21
|
+
{TITLES[r.situation]}
|
|
22
|
+
</dt>
|
|
23
|
+
<dd className="text-[var(--color-text-secondary)]">
|
|
24
|
+
Use {r.use}. Avoid: {r.not}. {r.why}
|
|
25
|
+
</dd>
|
|
26
|
+
</div>
|
|
27
|
+
))}
|
|
28
|
+
</dl>
|
|
29
|
+
</section>
|
|
30
|
+
);
|
|
31
|
+
}
|