@scattered-light/loomiere 0.3.0 → 0.4.1
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/README.md +6 -1
- package/bin/loomiere.mjs +24 -0
- package/build/build-tokens.mjs +93 -49
- package/exporters/README.md +1 -1
- package/exporters/ag-grid-settings.mjs +7 -7
- package/exporters/ag-grid.mjs +6 -6
- package/exporters/chakra.mjs +43 -43
- package/exporters/component-styles.mjs +4 -4
- package/exporters/design-system.mjs +17 -12
- package/exporters/figma.mjs +774 -68
- package/exporters/mui.mjs +40 -40
- package/exporters/shadcn.mjs +5 -13
- package/exporters/tailwind.mjs +14 -5
- package/figma/README.md +136 -0
- package/figma/build-plugin.mjs +25 -0
- package/figma/engine.js +730 -0
- package/figma/library/README.md +92 -0
- package/figma/library/check/known-differences.md +20 -0
- package/figma/library/check/mojave.json +246 -0
- package/figma/library/kit/base.js +89 -0
- package/figma/library/kit/components.js +95 -0
- package/figma/library/kit/docs.js +37 -0
- package/figma/library/kit/fingerprint.js +143 -0
- package/figma/library/pages/02-palettes.js +40 -0
- package/figma/library/pages/03-color.js +126 -0
- package/figma/library/pages/04-type.js +56 -0
- package/figma/library/pages/05-scale.js +58 -0
- package/figma/library/pages/06-size.js +111 -0
- package/figma/library/pages/07-elevation-focus-motion.js +108 -0
- package/figma/library/pages/08-themes.js +36 -0
- package/figma/library/pages/09-fields/01-input.js +55 -0
- package/figma/library/pages/09-fields/02-checks.js +82 -0
- package/figma/library/pages/09-fields/03-field.js +32 -0
- package/figma/library/pages/09-fields/04-more-fields.js +144 -0
- package/figma/library/pages/09-fields/05-labels.js +14 -0
- package/figma/library/pages/09-fields/06-doc.js +75 -0
- package/figma/library/pages/10-buttons/01-buttons.js +97 -0
- package/figma/library/pages/10-buttons/02-doc.js +55 -0
- package/figma/library/pages/11-popups/01-popups.js +166 -0
- package/figma/library/pages/11-popups/02-more-popups.js +90 -0
- package/figma/library/pages/11-popups/03-labels.js +14 -0
- package/figma/library/pages/11-popups/04-doc.js +89 -0
- package/figma/library/pages/12-overlays/01-overlays.js +135 -0
- package/figma/library/pages/12-overlays/02-labels.js +10 -0
- package/figma/library/pages/12-overlays/03-doc.js +80 -0
- package/figma/library/pages/13-disclosure/01-disclosure.js +205 -0
- package/figma/library/pages/13-disclosure/02-collapsible.js +39 -0
- package/figma/library/pages/13-disclosure/03-labels.js +16 -0
- package/figma/library/pages/13-disclosure/04-doc.js +91 -0
- package/figma/library/pages/14-display/01-display.js +165 -0
- package/figma/library/pages/14-display/02-more-display.js +55 -0
- package/figma/library/pages/14-display/03-labels.js +14 -0
- package/figma/library/pages/14-display/04-doc.js +96 -0
- package/figma/library/pages/15-cover.js +87 -0
- package/figma/library/run-order.json +21 -0
- package/figma/library/tools/compare.mjs +11 -0
- package/figma/library/tools/diff-snippet.js +15 -0
- package/figma/library/tools/kit-script.mjs +21 -0
- package/figma/library/tools/run.mjs +27 -0
- package/figma/library/tools/runs.mjs +34 -0
- package/figma/plugin/code.js +746 -0
- package/figma/plugin/manifest.json +14 -0
- package/figma/plugin/ui.html +237 -0
- package/figma/plugin-main.js +14 -0
- package/generator/brand.mjs +16 -14
- package/generator/brand.schema.json +60 -0
- package/generator/generate.mjs +2 -2
- package/generator/pairs.mjs +6 -1
- package/generator/roles.mjs +55 -15
- package/generator/vision.mjs +7 -2
- package/lib/config.mjs +2 -0
- package/lib/contrast.mjs +8 -3
- package/lib/figma.mjs +338 -0
- package/lib/studio.mjs +4 -0
- package/lib/tool-server.mjs +7 -4
- package/package.json +5 -1
- package/tokens/README.md +10 -5
- package/tokens/component/avatar.json +41 -6
- package/tokens/semantic/color.json +1 -1
- package/tokens/semantic/elevation.json +8 -43
- package/tokens/semantic/typography.json +61 -94
- package/tools/brand-builder/builder.js +33 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"font": {
|
|
3
3
|
"$description": "Text styles for the condense, base, magnify and minimize tiers. Each style has its parts (family, size, weight, line height, letter spacing) and a -font shorthand that combines them.",
|
|
4
|
-
"base": {
|
|
4
|
+
"body-base": {
|
|
5
5
|
"$type": "typography",
|
|
6
6
|
"$value": {
|
|
7
7
|
"fontFamily": "{font-family.body}",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
"$description": "Body copy in the base tier, the default UI and body text."
|
|
14
14
|
},
|
|
15
|
-
"base
|
|
15
|
+
"selected-base": {
|
|
16
16
|
"$type": "typography",
|
|
17
17
|
"$value": {
|
|
18
18
|
"fontFamily": "{font-family.body}",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"$description": "The selected or current item in the base tier (the default UI and body text): selected tabs and toggles, the current nav item or page. Base body text at semibold, so selection reads without changing size."
|
|
25
25
|
},
|
|
26
|
-
"base
|
|
26
|
+
"label-base": {
|
|
27
27
|
"$type": "typography",
|
|
28
28
|
"$value": {
|
|
29
29
|
"fontFamily": "{font-family.body}",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
},
|
|
35
35
|
"$description": "Form labels in the base tier, the default UI and body text."
|
|
36
36
|
},
|
|
37
|
-
"base
|
|
37
|
+
"link-base": {
|
|
38
38
|
"$type": "typography",
|
|
39
|
-
"$value": "{font.base}",
|
|
39
|
+
"$value": "{font.body-base}",
|
|
40
40
|
"$description": "Links in the base tier. The same type as base body text: a link stands out by color and underline, not by its type."
|
|
41
41
|
},
|
|
42
|
-
"base
|
|
42
|
+
"subtitle-base": {
|
|
43
43
|
"$type": "typography",
|
|
44
44
|
"$value": {
|
|
45
45
|
"fontFamily": "{font-family.body}",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"$description": "Subtitles in the base tier, the default UI and body text."
|
|
52
52
|
},
|
|
53
|
-
"base
|
|
53
|
+
"trigger-base": {
|
|
54
54
|
"$type": "typography",
|
|
55
55
|
"$value": {
|
|
56
56
|
"fontFamily": "{font-family.body}",
|
|
@@ -61,7 +61,18 @@
|
|
|
61
61
|
},
|
|
62
62
|
"$description": "Buttons and triggers in the base tier, the default UI and body text."
|
|
63
63
|
},
|
|
64
|
-
"
|
|
64
|
+
"title-base": {
|
|
65
|
+
"$type": "typography",
|
|
66
|
+
"$value": {
|
|
67
|
+
"fontFamily": "{font-family.display}",
|
|
68
|
+
"fontSize": "{font-size.md}",
|
|
69
|
+
"fontWeight": "{font-weight.semibold}",
|
|
70
|
+
"letterSpacing": "{letter-spacing.normal}",
|
|
71
|
+
"lineHeight": "{line-height.md}"
|
|
72
|
+
},
|
|
73
|
+
"$description": "Titles in the base tier: a toast, an accordion row, a list item heading. Titles use the display family; the tier sets the size."
|
|
74
|
+
},
|
|
75
|
+
"code-condense": {
|
|
65
76
|
"$type": "typography",
|
|
66
77
|
"$value": {
|
|
67
78
|
"fontFamily": "{font-family.mono}",
|
|
@@ -72,7 +83,7 @@
|
|
|
72
83
|
},
|
|
73
84
|
"$description": "Code uses the mono family so characters line up."
|
|
74
85
|
},
|
|
75
|
-
"condense": {
|
|
86
|
+
"body-condense": {
|
|
76
87
|
"$type": "typography",
|
|
77
88
|
"$value": {
|
|
78
89
|
"fontFamily": "{font-family.body}",
|
|
@@ -83,7 +94,7 @@
|
|
|
83
94
|
},
|
|
84
95
|
"$description": "Body copy in the condense tier, dense UI text (tables, secondary labels)."
|
|
85
96
|
},
|
|
86
|
-
"condense
|
|
97
|
+
"trigger-condense": {
|
|
87
98
|
"$type": "typography",
|
|
88
99
|
"$value": {
|
|
89
100
|
"fontFamily": "{font-family.body}",
|
|
@@ -94,7 +105,7 @@
|
|
|
94
105
|
},
|
|
95
106
|
"$description": "Buttons and triggers in the condense tier (dense UI): condense body text at medium, like base-trigger one tier down."
|
|
96
107
|
},
|
|
97
|
-
"condense
|
|
108
|
+
"selected-condense": {
|
|
98
109
|
"$type": "typography",
|
|
99
110
|
"$value": {
|
|
100
111
|
"fontFamily": "{font-family.body}",
|
|
@@ -105,12 +116,12 @@
|
|
|
105
116
|
},
|
|
106
117
|
"$description": "The selected or current item in the condense tier (dense UI text): selected tabs and toggles, the current nav item or page. Condense body text at semibold, so selection reads without changing size."
|
|
107
118
|
},
|
|
108
|
-
"condense
|
|
119
|
+
"link-condense": {
|
|
109
120
|
"$type": "typography",
|
|
110
|
-
"$value": "{font.condense}",
|
|
121
|
+
"$value": "{font.body-condense}",
|
|
111
122
|
"$description": "Links in the condense tier. The same type as condense body text: a link stands out by color and underline, not by its type."
|
|
112
123
|
},
|
|
113
|
-
"condense
|
|
124
|
+
"subtitle-condense": {
|
|
114
125
|
"$type": "typography",
|
|
115
126
|
"$value": {
|
|
116
127
|
"fontFamily": "{font-family.body}",
|
|
@@ -121,7 +132,7 @@
|
|
|
121
132
|
},
|
|
122
133
|
"$description": "Subtitles in the condense tier, dense UI text (tables, secondary labels)."
|
|
123
134
|
},
|
|
124
|
-
"condense
|
|
135
|
+
"eyebrow-condense": {
|
|
125
136
|
"$type": "typography",
|
|
126
137
|
"$value": {
|
|
127
138
|
"fontFamily": "{font-family.body}",
|
|
@@ -135,7 +146,18 @@
|
|
|
135
146
|
"sl.text-transform": "uppercase"
|
|
136
147
|
}
|
|
137
148
|
},
|
|
138
|
-
"
|
|
149
|
+
"title-condense": {
|
|
150
|
+
"$type": "typography",
|
|
151
|
+
"$value": {
|
|
152
|
+
"fontFamily": "{font-family.display}",
|
|
153
|
+
"fontSize": "{font-size.sm}",
|
|
154
|
+
"fontWeight": "{font-weight.semibold}",
|
|
155
|
+
"letterSpacing": "{letter-spacing.normal}",
|
|
156
|
+
"lineHeight": "{line-height.sm}"
|
|
157
|
+
},
|
|
158
|
+
"$description": "Titles in the condense tier: group headers in tables, menus and dense panels. Titles use the display family; the tier sets the size."
|
|
159
|
+
},
|
|
160
|
+
"body-magnify": {
|
|
139
161
|
"$type": "typography",
|
|
140
162
|
"$value": {
|
|
141
163
|
"fontFamily": "{font-family.body}",
|
|
@@ -146,7 +168,7 @@
|
|
|
146
168
|
},
|
|
147
169
|
"$description": "Body copy in the magnify tier, emphasized body text (lead paragraphs)."
|
|
148
170
|
},
|
|
149
|
-
"magnify
|
|
171
|
+
"trigger-magnify": {
|
|
150
172
|
"$type": "typography",
|
|
151
173
|
"$value": {
|
|
152
174
|
"fontFamily": "{font-family.body}",
|
|
@@ -157,7 +179,18 @@
|
|
|
157
179
|
},
|
|
158
180
|
"$description": "Buttons and triggers in the magnify tier (emphasized, larger UI): magnify body text at medium, like base-trigger one tier up."
|
|
159
181
|
},
|
|
160
|
-
"
|
|
182
|
+
"title-magnify": {
|
|
183
|
+
"$type": "typography",
|
|
184
|
+
"$value": {
|
|
185
|
+
"fontFamily": "{font-family.display}",
|
|
186
|
+
"fontSize": "{font-size.lg}",
|
|
187
|
+
"fontWeight": "{font-weight.semibold}",
|
|
188
|
+
"letterSpacing": "{letter-spacing.normal}",
|
|
189
|
+
"lineHeight": "{line-height.md}"
|
|
190
|
+
},
|
|
191
|
+
"$description": "Titles in the magnify tier: popovers, cards and fieldsets. Titles use the display family; the tier sets the size."
|
|
192
|
+
},
|
|
193
|
+
"body-minimize": {
|
|
161
194
|
"$type": "typography",
|
|
162
195
|
"$value": {
|
|
163
196
|
"fontFamily": "{font-family.body}",
|
|
@@ -168,7 +201,7 @@
|
|
|
168
201
|
},
|
|
169
202
|
"$description": "Body copy in the minimize tier, the smallest functional text (captions, fine print)."
|
|
170
203
|
},
|
|
171
|
-
"minimize
|
|
204
|
+
"trigger-minimize": {
|
|
172
205
|
"$type": "typography",
|
|
173
206
|
"$value": {
|
|
174
207
|
"fontFamily": "{font-family.body}",
|
|
@@ -179,7 +212,7 @@
|
|
|
179
212
|
},
|
|
180
213
|
"$description": "Buttons and triggers in the minimize tier (the smallest UI): minimize body text at medium, like base-trigger one tier down."
|
|
181
214
|
},
|
|
182
|
-
"minimize
|
|
215
|
+
"selected-minimize": {
|
|
183
216
|
"$type": "typography",
|
|
184
217
|
"$value": {
|
|
185
218
|
"fontFamily": "{font-family.body}",
|
|
@@ -190,12 +223,12 @@
|
|
|
190
223
|
},
|
|
191
224
|
"$description": "The selected or current item in the minimize tier (the smallest functional text): selected tabs and toggles, the current nav item or page. Minimize body text at semibold, so selection reads without changing size."
|
|
192
225
|
},
|
|
193
|
-
"minimize
|
|
226
|
+
"link-minimize": {
|
|
194
227
|
"$type": "typography",
|
|
195
|
-
"$value": "{font.minimize}",
|
|
228
|
+
"$value": "{font.body-minimize}",
|
|
196
229
|
"$description": "Links in the minimize tier. The same type as minimize body text: a link stands out by color and underline, not by its type."
|
|
197
230
|
},
|
|
198
|
-
"minimize
|
|
231
|
+
"subtitle-minimize": {
|
|
199
232
|
"$type": "typography",
|
|
200
233
|
"$value": {
|
|
201
234
|
"fontFamily": "{font-family.body}",
|
|
@@ -206,7 +239,7 @@
|
|
|
206
239
|
},
|
|
207
240
|
"$description": "Subtitles in the minimize tier, the smallest functional text (captions, fine print)."
|
|
208
241
|
},
|
|
209
|
-
"minimize
|
|
242
|
+
"eyebrow-minimize": {
|
|
210
243
|
"$type": "typography",
|
|
211
244
|
"$value": {
|
|
212
245
|
"fontFamily": "{font-family.body}",
|
|
@@ -220,7 +253,7 @@
|
|
|
220
253
|
"sl.text-transform": "uppercase"
|
|
221
254
|
}
|
|
222
255
|
},
|
|
223
|
-
"
|
|
256
|
+
"title-amplify": {
|
|
224
257
|
"$type": "typography",
|
|
225
258
|
"$value": {
|
|
226
259
|
"fontFamily": "{font-family.display}",
|
|
@@ -229,20 +262,9 @@
|
|
|
229
262
|
"letterSpacing": "{letter-spacing.normal}",
|
|
230
263
|
"lineHeight": "{line-height.2xl}"
|
|
231
264
|
},
|
|
232
|
-
"$description": "
|
|
265
|
+
"$description": "Titles in the amplify tier: dialogs, drawers and page sections. Titles use the display family; the tier sets the size."
|
|
233
266
|
},
|
|
234
|
-
"maximize
|
|
235
|
-
"$type": "typography",
|
|
236
|
-
"$value": {
|
|
237
|
-
"fontFamily": "{font-family.display}",
|
|
238
|
-
"fontSize": "{font-size.3xl}",
|
|
239
|
-
"fontWeight": "{font-weight.semibold}",
|
|
240
|
-
"letterSpacing": "{letter-spacing.normal}",
|
|
241
|
-
"lineHeight": "{line-height.3xl}"
|
|
242
|
-
},
|
|
243
|
-
"$description": "Display text at 3xl, for headings and hero copy."
|
|
244
|
-
},
|
|
245
|
-
"maximize-4xl": {
|
|
267
|
+
"title-maximize": {
|
|
246
268
|
"$type": "typography",
|
|
247
269
|
"$value": {
|
|
248
270
|
"fontFamily": "{font-family.display}",
|
|
@@ -251,62 +273,7 @@
|
|
|
251
273
|
"letterSpacing": "{letter-spacing.normal}",
|
|
252
274
|
"lineHeight": "{line-height.4xl}"
|
|
253
275
|
},
|
|
254
|
-
"$description": "
|
|
255
|
-
},
|
|
256
|
-
"maximize-lg": {
|
|
257
|
-
"$type": "typography",
|
|
258
|
-
"$value": {
|
|
259
|
-
"fontFamily": "{font-family.display}",
|
|
260
|
-
"fontSize": "{font-size.lg}",
|
|
261
|
-
"fontWeight": "{font-weight.semibold}",
|
|
262
|
-
"letterSpacing": "{letter-spacing.normal}",
|
|
263
|
-
"lineHeight": "{line-height.md}"
|
|
264
|
-
},
|
|
265
|
-
"$description": "Display text at lg, for headings and hero copy."
|
|
266
|
-
},
|
|
267
|
-
"maximize-md": {
|
|
268
|
-
"$type": "typography",
|
|
269
|
-
"$value": {
|
|
270
|
-
"fontFamily": "{font-family.display}",
|
|
271
|
-
"fontSize": "{font-size.md}",
|
|
272
|
-
"fontWeight": "{font-weight.semibold}",
|
|
273
|
-
"letterSpacing": "{letter-spacing.normal}",
|
|
274
|
-
"lineHeight": "{line-height.md}"
|
|
275
|
-
},
|
|
276
|
-
"$description": "Display text at md, for headings and hero copy."
|
|
277
|
-
},
|
|
278
|
-
"maximize-sm": {
|
|
279
|
-
"$type": "typography",
|
|
280
|
-
"$value": {
|
|
281
|
-
"fontFamily": "{font-family.display}",
|
|
282
|
-
"fontSize": "{font-size.sm}",
|
|
283
|
-
"fontWeight": "{font-weight.semibold}",
|
|
284
|
-
"letterSpacing": "{letter-spacing.normal}",
|
|
285
|
-
"lineHeight": "{line-height.sm}"
|
|
286
|
-
},
|
|
287
|
-
"$description": "Display text at sm, for headings and hero copy."
|
|
288
|
-
},
|
|
289
|
-
"maximize-xl": {
|
|
290
|
-
"$type": "typography",
|
|
291
|
-
"$value": {
|
|
292
|
-
"fontFamily": "{font-family.display}",
|
|
293
|
-
"fontSize": "{font-size.xl}",
|
|
294
|
-
"fontWeight": "{font-weight.semibold}",
|
|
295
|
-
"letterSpacing": "{letter-spacing.normal}",
|
|
296
|
-
"lineHeight": "{line-height.md}"
|
|
297
|
-
},
|
|
298
|
-
"$description": "Display text at xl, for headings and hero copy."
|
|
299
|
-
},
|
|
300
|
-
"maximize-xs": {
|
|
301
|
-
"$type": "typography",
|
|
302
|
-
"$value": {
|
|
303
|
-
"fontFamily": "{font-family.display}",
|
|
304
|
-
"fontSize": "{font-size.xs}",
|
|
305
|
-
"fontWeight": "{font-weight.semibold}",
|
|
306
|
-
"letterSpacing": "{letter-spacing.normal}",
|
|
307
|
-
"lineHeight": "{line-height.xs}"
|
|
308
|
-
},
|
|
309
|
-
"$description": "Display text at xs, for headings and hero copy."
|
|
276
|
+
"$description": "Titles in the maximize tier: the page head. Titles use the display family; the tier sets the size."
|
|
310
277
|
}
|
|
311
278
|
}
|
|
312
279
|
}
|
|
@@ -11,7 +11,7 @@ import { buildPrimitives } from '../../generator/brand.mjs';
|
|
|
11
11
|
import { checkDataColors, DATA_CONTRAST, nudgeDataColor, VISIONS } from '../../generator/data-colors.mjs';
|
|
12
12
|
import { VISION_THEMES, visionColors } from '../../generator/vision.mjs';
|
|
13
13
|
import { formatBrand } from '../../generator/format-brand.mjs';
|
|
14
|
-
import { CONCEPTS, conceptModes, defaultPick, LEVELS, pickRef, SLOTS, stepRef, STYLES, withDefaults } from '../../generator/roles.mjs';
|
|
14
|
+
import { CONCEPTS, conceptModes, defaultPick, LEVELS, pickRef, SLOTS, STATUSES, stepRef, STYLES, withDefaults } from '../../generator/roles.mjs';
|
|
15
15
|
|
|
16
16
|
const BRAND_ROLES = ['neutral', 'primary', 'secondary', 'tertiary', 'quaternary'];
|
|
17
17
|
const ALERT_ROLES = ['success', 'warning', 'error', 'info'];
|
|
@@ -238,7 +238,7 @@ function editorsHtml() {
|
|
|
238
238
|
''));
|
|
239
239
|
|
|
240
240
|
out.push(`<section class="band" id="vision"><div class="band-head"><h2>Color vision</h2>
|
|
241
|
-
<p class="muted">Each theme redesigns this brand's colors for one kind of color blindness, moving each color only as far as it needs to so colors that look different to most people don't blur together. Contrast steps stay the same. Open a theme to tune any color.
|
|
241
|
+
<p class="muted">Each theme redesigns this brand's colors for one kind of color blindness, moving each color only as far as it needs to so colors that look different to most people don't blur together. Contrast steps stay the same. Open a theme to tune any color. Each is a theme of its own: a page turns one on with <code>data-theme="deuteranopia"</code> on its root element.</p></div>
|
|
242
242
|
<div class="row"><label class="toggle"><input type="checkbox" id="vision-seen"${state.visionSeen ? ' checked' : ''}> Show each theme as people with that vision see it</label></div>
|
|
243
243
|
<div class="preview" id="pv-vision"></div>
|
|
244
244
|
${visionDetailHtml()}</section>`);
|
|
@@ -248,6 +248,7 @@ function editorsHtml() {
|
|
|
248
248
|
const chromeOpts = pals.filter(([, p]) => p.contrast === 'neutral').map(([n]) => [n, n]);
|
|
249
249
|
const accentOpts = pals.filter(([, p]) => p.contrast !== 'neutral').map(([n]) => [n, n]);
|
|
250
250
|
const colorOpts = [['accent', `accent (${r.accent})`], ['chrome', `chrome (${r.chrome})`], ...pals.map(([n]) => [n, n])];
|
|
251
|
+
const pairOpts = [['', 'Automatic'], ...Object.keys(b.color.pairs ?? {}).map((n) => [n, n])];
|
|
251
252
|
const styleOpts = Object.keys(STYLES).map((v) => [v, v]);
|
|
252
253
|
out.push(band('pairs', 'Pairs', 'Named background and text combinations. Pick them in the pair lab (<code>loomiere lab</code>); here you can see whether palette changes still keep them at AA.', null,
|
|
253
254
|
'<div class="preview" id="pv-pairs"></div>'));
|
|
@@ -313,6 +314,9 @@ function editorsHtml() {
|
|
|
313
314
|
<div class="panel"><h3>Emphasis ladder</h3>
|
|
314
315
|
${LEVELS.map((level) => `<div class="row"><b class="level">${level}</b>${selectIn(`roles.emphasis.${level}.style`, r.emphasis[level].style, styleOpts, 'Style')}${selectIn(`roles.emphasis.${level}.color`, r.emphasis[level].color, colorOpts, 'Color')}</div>`).join('')}
|
|
315
316
|
<small class="muted">In code: <code><Button emphasis="subtle"></code>, or <code>data-emphasis="subtle"</code> on any element. Add <code>palette="error"</code> (<code>data-color</code>) to repaint a level.</small></div>
|
|
317
|
+
<div class="panel"><h3>Statuses</h3>
|
|
318
|
+
${STATUSES.filter((st) => st === 'default' || b.color.palettes[st]).map((st) => `<div class="row"><b class="level">${st}</b>${LEVELS.map((level) => selectIn(`roles.status.${st}.${level}`, r.status?.[st]?.[level] ?? '', pairOpts, level)).join('')}</div>`).join('')}
|
|
319
|
+
<small class="muted">Automatic is the level's style in the status's palette (for default, the ladder above). Pick a brand pair to have it stand in for that level. In code: <code>data-status="warning"</code> on any element.</small></div>
|
|
316
320
|
<div class="panel"><h3>What uses what</h3><p class="muted">Each part of the sample screen reads one role. Change a setting and the parts that use it light up.</p>
|
|
317
321
|
<div class="palette-strip" id="pv-strip"></div>
|
|
318
322
|
<div class="row"><button class="btn small" type="button" data-act="step" data-step="brand">Adjust brand colors</button></div></div>`,
|
|
@@ -533,12 +537,14 @@ function visionDetailHtml() {
|
|
|
533
537
|
};
|
|
534
538
|
const head = '<thead><tr><th></th><th>Brand · as seen</th><th>Theme · as seen</th><th>Color</th><th></th></tr></thead>';
|
|
535
539
|
const paletteRows = Object.entries(g.keys).map(([r, hex]) => row(c.palettes[r].label ? `${c.palettes[r].label} (${r})` : r, 'keys', r, g.brandKeys[r], hex));
|
|
536
|
-
const
|
|
540
|
+
const brandData = Object.fromEntries(c.data);
|
|
541
|
+
const dataRows = g.data.map(([n, hex], i) =>
|
|
542
|
+
row(n, 'data', n, brandData[n], hex).replace('<th scope="row">', `<th scope="row">${i ? `<button class="icon-btn" type="button" data-act="vision-data-up" data-theme="${theme}" data-i="${i}" aria-label="Move ${esc(n)} up in ${name}">↑</button>` : ''}`));
|
|
537
543
|
return `<div class="panel vision-detail"><div class="row"><h3>${name} colors</h3>
|
|
538
544
|
<button class="btn small" type="button" data-act="vision-open" data-theme="${theme}">Close</button></div>
|
|
539
545
|
<small class="muted">Each pair of swatches is the color, then how it looks with ${name.toLowerCase()}. Change a color to pin it; the others move to make room. A palette's color is its most colorful key, and the whole ramp follows it.</small>
|
|
540
546
|
<div class="table-wrap"><table class="vtable">${head}<tbody><tr><td colspan="5" class="vgroup">Palettes</td></tr>${paletteRows.join('')}
|
|
541
|
-
<tr><td colspan="5" class="vgroup">Data colors</td></tr>${dataRows.join('')}</tbody></table></div></div>`;
|
|
547
|
+
<tr><td colspan="5" class="vgroup">Data colors, in this theme's series order (↑ moves one up; saved as <code>dataOrder</code>)</td></tr>${dataRows.join('')}</tbody></table></div></div>`;
|
|
542
548
|
}
|
|
543
549
|
|
|
544
550
|
function pairsHtml() {
|
|
@@ -960,6 +966,16 @@ document.addEventListener('change', (e) => {
|
|
|
960
966
|
set(real, el.checked ? state.brand.color.ink : undefined);
|
|
961
967
|
return renderEditors();
|
|
962
968
|
}
|
|
969
|
+
if (bind.startsWith('roles.status.')) {
|
|
970
|
+
// Automatic is the absence of a pick, so it leaves the file.
|
|
971
|
+
set(bind, el.value || undefined);
|
|
972
|
+
const [, , st] = bind.split('.');
|
|
973
|
+
const picks = state.brand.roles?.status;
|
|
974
|
+
if (picks?.[st] && !Object.values(picks[st]).some(Boolean)) delete picks[st];
|
|
975
|
+
if (picks && !Object.keys(picks).length) delete state.brand.roles.status;
|
|
976
|
+
renderEditors();
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
963
979
|
if (bind.startsWith('roles.')) {
|
|
964
980
|
set(bind, readInput(el));
|
|
965
981
|
renderEditors();
|
|
@@ -1033,6 +1049,19 @@ document.addEventListener('click', (e) => {
|
|
|
1033
1049
|
if (!Object.keys(v).length) delete state.brand.color.vision;
|
|
1034
1050
|
break;
|
|
1035
1051
|
}
|
|
1052
|
+
case 'vision-data-up': {
|
|
1053
|
+
const { theme } = b.dataset;
|
|
1054
|
+
const c = state.brand.color;
|
|
1055
|
+
const order = visionColors(c)[theme].data.map(([n]) => n);
|
|
1056
|
+
[order[i - 1], order[i]] = [order[i], order[i - 1]];
|
|
1057
|
+
c.vision ??= {};
|
|
1058
|
+
c.vision[theme] ??= {};
|
|
1059
|
+
if (order.join() === c.data.map(([n]) => n).join()) delete c.vision[theme].dataOrder;
|
|
1060
|
+
else c.vision[theme].dataOrder = order;
|
|
1061
|
+
if (!Object.keys(c.vision[theme]).length) delete c.vision[theme];
|
|
1062
|
+
if (!Object.keys(c.vision).length) delete c.vision;
|
|
1063
|
+
break;
|
|
1064
|
+
}
|
|
1036
1065
|
case 'measure-fonts': return measureFonts().then(renderEditors);
|
|
1037
1066
|
case 'pins-off': state.usePins = false; $('pins').checked = false; return renderPreviews();
|
|
1038
1067
|
case 'revert': state.brand = JSON.parse(state.savedText); delete state.brand.$schema; delete state.brand.name; break;
|