@motion-proto/live-tokens 0.62.0 → 0.64.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/.claude/skills/live-tokens-adjust-geometry/SKILL.md +4 -4
- package/.claude/skills/live-tokens-build-page/SKILL.md +21 -3
- package/.claude/skills/live-tokens-create-component/SKILL.md +16 -48
- package/.claude/skills/live-tokens-create-component/references/fixed-overlays.md +10 -1
- package/.claude/skills/live-tokens-create-component/references/intrinsics.md +7 -5
- package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +1 -1
- package/.claude/skills/live-tokens-create-component/references/token-naming.md +50 -0
- package/.claude/skills/live-tokens-generate-theme/SKILL.md +16 -9
- package/.claude/skills/live-tokens-pair-fonts/SKILL.md +8 -6
- package/.claude/skills/live-tokens-pick-component/SKILL.md +19 -5
- package/CHANGELOG.md +100 -0
- package/bin/migrate.mjs +6 -2
- package/dist-plugin/adjust/index.cjs +1 -1
- package/dist-plugin/adjust/index.d.cts +1 -1
- package/dist-plugin/adjust/index.d.ts +1 -1
- package/dist-plugin/adjust/index.js +1 -1
- package/dist-plugin/{chunk-232GZGQU.js → chunk-NDJJORKJ.js} +342 -5
- package/dist-plugin/{chunk-Y5CNFSSV.js → chunk-RVE3MNKM.js} +1 -1
- package/dist-plugin/{chunk-OPYOK2CA.js → chunk-ZHPX7ZYQ.js} +39 -1
- package/dist-plugin/{dataPaths-CRfD1LdA.d.ts → dataPaths-DZUzVv8H.d.cts} +3 -3
- package/dist-plugin/{dataPaths-CRfD1LdA.d.cts → dataPaths-DZUzVv8H.d.ts} +3 -3
- package/dist-plugin/fontPairing/index.cjs +32 -8
- package/dist-plugin/fontPairing/index.d.cts +1 -1
- package/dist-plugin/fontPairing/index.d.ts +1 -1
- package/dist-plugin/fontPairing/index.js +32 -8
- package/dist-plugin/generateColorsAndType/index.cjs +1 -1
- package/dist-plugin/generateColorsAndType/index.d.cts +1 -1
- package/dist-plugin/generateColorsAndType/index.d.ts +1 -1
- package/dist-plugin/generateColorsAndType/index.js +1 -1
- package/dist-plugin/index.cjs +417 -34
- package/dist-plugin/index.d.cts +1 -1
- package/dist-plugin/index.d.ts +1 -1
- package/dist-plugin/index.js +31 -23
- package/dist-plugin/migrateData/index.cjs +350 -9
- package/dist-plugin/migrateData/index.d.cts +1 -1
- package/dist-plugin/migrateData/index.d.ts +1 -1
- package/dist-plugin/migrateData/index.js +9 -5
- package/dist-plugin/tokensCssMigrations/index.cjs +39 -1
- package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
- package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
- package/dist-plugin/tokensCssMigrations/index.js +2 -2
- package/package.json +9 -2
- package/src/app/site.css +16 -0
- package/src/editor/core/fonts/googleFontsUrl.ts +44 -8
- package/src/editor/core/preview/lookPreview.ts +46 -5
- package/src/editor/core/productionPulse.ts +6 -2
- package/src/editor/core/sketch/index.ts +60 -0
- package/src/editor/core/sketch/maskField.ts +5 -5
- package/src/editor/core/sketch/sketchLayer.ts +19 -8
- package/src/editor/core/sketch/sketchStore.ts +238 -85
- package/src/editor/core/sketch/{sketchPresetService.ts → sketchStyleService.ts} +14 -14
- package/src/editor/core/sketch/{sketchPresets.ts → sketchStyles.ts} +17 -17
- package/src/editor/core/themes/themeDocumentSync.ts +2 -0
- package/src/editor/core/themes/themeInit.ts +19 -1
- package/src/editor/core/themes/themeService.ts +7 -2
- package/src/editor/core/themes/themeTypes.ts +5 -0
- package/src/editor/docs/content/editing-tokens.md +1 -1
- package/src/editor/docs/content/sketch-mode.md +27 -16
- package/src/editor/docs/content/themes-workflow.md +30 -21
- package/src/editor/docs/content/where-themes-live.md +9 -5
- package/src/editor/docs/content.generated.ts +4 -4
- package/src/editor/overlay/LiveTokensRouter.svelte +1 -1
- package/src/editor/ui/EditorViewSwitcher.svelte +3 -3
- package/src/editor/ui/FontStackEditor.svelte +49 -11
- package/src/editor/ui/ProjectFontsSection.svelte +6 -0
- package/src/editor/ui/ThemePanel.svelte +47 -1
- package/src/editor/ui/sections/textStyles.ts +15 -1
- package/src/editor/ui/sketch/SketchPreview.svelte +3 -3
- package/src/editor/ui/sketch/SketchTab.svelte +87 -53
- package/src/system/components/FloatingTokenTags.css +10 -8
- package/src/system/styles/tokens.css +17 -2
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
markComponentSaved,
|
|
59
59
|
} from '../core/store/editorStore';
|
|
60
60
|
import { openThemeSlug } from '../core/store/editorConfigStore';
|
|
61
|
+
import { sketchOffLook, themeSketchStyle } from '../core/sketch/sketchStore';
|
|
61
62
|
import { editorView } from '../core/store/editorViewStore';
|
|
62
63
|
import {
|
|
63
64
|
componentActiveRevision,
|
|
@@ -83,6 +84,9 @@
|
|
|
83
84
|
let { showComponentsLink = true }: Props = $props();
|
|
84
85
|
|
|
85
86
|
let canOpenComponents = $derived(showComponentsLink && $editorView !== 'components');
|
|
87
|
+
// showComponentsLink=false marks the ThemePanel that renders outside the
|
|
88
|
+
// view switcher (ComponentEditorPage), where neither pill can navigate.
|
|
89
|
+
let canOpenSketchStyle = $derived(showComponentsLink && $editorView !== 'sketch');
|
|
86
90
|
|
|
87
91
|
let files: ThemeMeta[] = $state([]);
|
|
88
92
|
let colorsFiles: ColorsAndTypeMeta[] = $state([]);
|
|
@@ -104,7 +108,7 @@
|
|
|
104
108
|
let dirtyComponentCount = $derived(
|
|
105
109
|
Object.values($componentDirty).filter(Boolean).length,
|
|
106
110
|
);
|
|
107
|
-
let unsavedEdits = $derived($colorsAndTypeDirty || dirtyComponentCount > 0);
|
|
111
|
+
let unsavedEdits = $derived($colorsAndTypeDirty || dirtyComponentCount > 0 || $sketchOffLook);
|
|
108
112
|
|
|
109
113
|
async function refreshFiles() {
|
|
110
114
|
try {
|
|
@@ -120,6 +124,10 @@
|
|
|
120
124
|
if (active) {
|
|
121
125
|
openThemeSlug.set(active._fileName ?? 'default');
|
|
122
126
|
currentDisplayName = active.name ?? $openThemeSlug;
|
|
127
|
+
// Deleting the open theme repoints active without going through Load
|
|
128
|
+
// or Save, both of which already set this; this is the path that
|
|
129
|
+
// makes sketchStore's "set by every path that opens a theme" true.
|
|
130
|
+
themeSketchStyle.set(active.sketchStyle);
|
|
123
131
|
}
|
|
124
132
|
} catch {
|
|
125
133
|
// silent
|
|
@@ -177,6 +185,10 @@
|
|
|
177
185
|
editorView.set('components');
|
|
178
186
|
}
|
|
179
187
|
|
|
188
|
+
function openSketchStyle() {
|
|
189
|
+
editorView.set('sketch');
|
|
190
|
+
}
|
|
191
|
+
|
|
180
192
|
onMount(async () => {
|
|
181
193
|
await refreshFiles();
|
|
182
194
|
await refreshActive();
|
|
@@ -851,6 +863,40 @@
|
|
|
851
863
|
</UIPillButton>
|
|
852
864
|
{/if}
|
|
853
865
|
</div>
|
|
866
|
+
|
|
867
|
+
<div class="part-head part-static">
|
|
868
|
+
<span class="part-label">Sketchstyle</span>
|
|
869
|
+
<span class="part-summary">
|
|
870
|
+
<span class="part-summary-sep">·</span>
|
|
871
|
+
{#if $sketchOffLook}
|
|
872
|
+
<span>off the theme</span>
|
|
873
|
+
{:else if $themeSketchStyle}
|
|
874
|
+
<span class="part-summary-text">{$themeSketchStyle.label}</span>
|
|
875
|
+
{:else}
|
|
876
|
+
<span>none</span>
|
|
877
|
+
{/if}
|
|
878
|
+
</span>
|
|
879
|
+
{#if canOpenSketchStyle}
|
|
880
|
+
<UIPillButton
|
|
881
|
+
size="compact"
|
|
882
|
+
icon="fa-pen-nib"
|
|
883
|
+
title="Open the Sketchstyle view"
|
|
884
|
+
onclick={openSketchStyle}
|
|
885
|
+
>
|
|
886
|
+
Open
|
|
887
|
+
</UIPillButton>
|
|
888
|
+
{/if}
|
|
889
|
+
<UIInfoPopover title="Sketchstyle" ariaLabel="About the sketchstyle">
|
|
890
|
+
<p>
|
|
891
|
+
<strong>Sketchstyle</strong> is part of the theme, the same way colors and type are.
|
|
892
|
+
It travels with the theme when you save, load or share it.
|
|
893
|
+
</p>
|
|
894
|
+
<p>
|
|
895
|
+
It does not reach a production build. Adopt publishes the crisp look; the drawing
|
|
896
|
+
stays a preview.
|
|
897
|
+
</p>
|
|
898
|
+
</UIInfoPopover>
|
|
899
|
+
</div>
|
|
854
900
|
</div>
|
|
855
901
|
</div>
|
|
856
902
|
|
|
@@ -64,6 +64,20 @@ export const TEXT_STYLES: TextStyle[] = [
|
|
|
64
64
|
defaultElement: 'small',
|
|
65
65
|
preview: 'Captions and secondary text.',
|
|
66
66
|
},
|
|
67
|
+
{
|
|
68
|
+
name: 'editorial-xl',
|
|
69
|
+
label: 'Editorial XL',
|
|
70
|
+
prefix: '--editorial-xl',
|
|
71
|
+
defaultElement: 'editorial-xl',
|
|
72
|
+
preview: 'Pull quotes and opening statements.',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'editorial-lg',
|
|
76
|
+
label: 'Editorial LG',
|
|
77
|
+
prefix: '--editorial-lg',
|
|
78
|
+
defaultElement: 'editorial-lg',
|
|
79
|
+
preview: 'Standfirsts and section ledes.',
|
|
80
|
+
},
|
|
67
81
|
{
|
|
68
82
|
name: 'editorial-md',
|
|
69
83
|
label: 'Editorial MD',
|
|
@@ -76,7 +90,7 @@ export const TEXT_STYLES: TextStyle[] = [
|
|
|
76
90
|
label: 'Editorial SM',
|
|
77
91
|
prefix: '--editorial-sm',
|
|
78
92
|
defaultElement: 'editorial-sm',
|
|
79
|
-
preview: '
|
|
93
|
+
preview: 'Captions, credits, and asides.',
|
|
80
94
|
},
|
|
81
95
|
{
|
|
82
96
|
name: 'code',
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
import Callout from '../../../system/components/Callout.svelte';
|
|
7
7
|
import Toggle from '../../../system/components/Toggle.svelte';
|
|
8
8
|
import { setSketchScope } from '../../core/sketch/sketchLayer';
|
|
9
|
-
import type {
|
|
9
|
+
import type { SketchStyle } from '../../core/sketch/sketchStyles';
|
|
10
10
|
|
|
11
11
|
interface Props {
|
|
12
|
-
settings:
|
|
12
|
+
settings: SketchStyle;
|
|
13
13
|
enabled: boolean;
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
<p>Fill and outline displace on different noise seeds, so they disagree at the edges.</p>
|
|
43
43
|
</Card>
|
|
44
44
|
<Card title="Second card">
|
|
45
|
-
<p>Same size and same
|
|
45
|
+
<p>Same size and same sketchstyle. A different seed keeps the silhouette from repeating.</p>
|
|
46
46
|
</Card>
|
|
47
47
|
</div>
|
|
48
48
|
</section>
|
|
@@ -10,20 +10,23 @@
|
|
|
10
10
|
import UIPillButton from '../UIPillButton.svelte';
|
|
11
11
|
import UIReveal, { REVEAL_MS } from '../UIReveal.svelte';
|
|
12
12
|
import { scrollSectionIntoView } from '../scrollSection';
|
|
13
|
-
import {
|
|
13
|
+
import { SKETCH_STYLES } from '../../core/sketch/sketchStyles';
|
|
14
|
+
import { openThemeSlug } from '../../core/store/editorConfigStore';
|
|
14
15
|
import {
|
|
15
16
|
sketchEnabled,
|
|
16
|
-
|
|
17
|
+
setSketchEnabled,
|
|
18
|
+
sketchOffLook,
|
|
19
|
+
sketchStyleName,
|
|
17
20
|
sketchDirty,
|
|
18
21
|
sketchSettings,
|
|
19
|
-
|
|
22
|
+
selectSketchStyle,
|
|
20
23
|
updateSketchSettings,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
savedSketchStyles,
|
|
25
|
+
refreshSavedSketchStyles,
|
|
26
|
+
selectSavedSketchStyle,
|
|
27
|
+
saveCurrentSketchStyle,
|
|
28
|
+
deleteSavedSketchStyle,
|
|
29
|
+
USER_STYLE_PREFIX,
|
|
27
30
|
} from '../../core/sketch/sketchStore';
|
|
28
31
|
|
|
29
32
|
interface Props {
|
|
@@ -37,6 +40,11 @@
|
|
|
37
40
|
|
|
38
41
|
let s = $derived($sketchSettings);
|
|
39
42
|
|
|
43
|
+
// Save is disabled for the protected Default theme (ThemePanel.svelte);
|
|
44
|
+
// Save As is the gesture actually on offer there, so the off-look copy has
|
|
45
|
+
// to name it instead.
|
|
46
|
+
let activeIsProtected = $derived($openThemeSlug === 'default');
|
|
47
|
+
|
|
40
48
|
type SectionKey = 'border' | 'fill' | 'shape' | 'icons' | 'noise';
|
|
41
49
|
|
|
42
50
|
const SECTION_KEYS: SectionKey[] = ['border', 'fill', 'shape', 'icons', 'noise'];
|
|
@@ -81,8 +89,8 @@
|
|
|
81
89
|
const ROUGHNESS = ['smooth', 'grainy', 'rough'] as const;
|
|
82
90
|
|
|
83
91
|
/** A layer's own wavelength: the multiple, and the length it resolves to
|
|
84
|
-
against the shared wave. The ratio is what a
|
|
85
|
-
are what you can picture. */
|
|
92
|
+
against the shared wave. The ratio is what a sketchstyle carries; the
|
|
93
|
+
pixels are what you can picture. */
|
|
86
94
|
const against = (multiple: number) => `${Math.round(s.wobble * multiple)}px`;
|
|
87
95
|
|
|
88
96
|
/** The wave's shape, named rather than numbered: 1 is the field as the filter
|
|
@@ -110,52 +118,52 @@
|
|
|
110
118
|
+ (s.waveform > 1 ? ` · ${waveformLabel(s.waveform)}` : ''),
|
|
111
119
|
});
|
|
112
120
|
|
|
113
|
-
/** Shipped and saved
|
|
114
|
-
picking a saved one clears the shipped selection natively. */
|
|
115
|
-
const
|
|
121
|
+
/** Shipped and saved sketchstyles are one choice, so they share one radio
|
|
122
|
+
group: picking a saved one clears the shipped selection natively. */
|
|
123
|
+
const STYLE_RADIO_GROUP = 'sketchstyle';
|
|
116
124
|
|
|
117
125
|
/** What the readout under the grid says. The selection survives a dial move,
|
|
118
126
|
so the base keeps its name here and the blurb reports the drift instead. */
|
|
119
127
|
let active = $derived(
|
|
120
128
|
$sketchDirty
|
|
121
129
|
? { name: s.label, blurb: `Modified from ${s.label}. Save it to keep it.` }
|
|
122
|
-
: { name: s.label, blurb: s.blurb || 'Your saved
|
|
130
|
+
: { name: s.label, blurb: s.blurb || 'Your saved sketchstyle.' },
|
|
123
131
|
);
|
|
124
132
|
|
|
125
133
|
let naming = $state(false);
|
|
126
134
|
let draftName = $state('');
|
|
127
|
-
let
|
|
135
|
+
let styleError = $state('');
|
|
128
136
|
|
|
129
137
|
onMount(() => {
|
|
130
|
-
// No dev plugin (a built preview, say) means no saved
|
|
131
|
-
// missing door, not a fault worth reporting in the tab.
|
|
132
|
-
|
|
138
|
+
// No dev plugin (a built preview, say) means no saved sketchstyles. That
|
|
139
|
+
// is a missing door, not a fault worth reporting in the tab.
|
|
140
|
+
refreshSavedSketchStyles().catch(() => {});
|
|
133
141
|
});
|
|
134
142
|
|
|
135
143
|
function startNaming() {
|
|
136
|
-
draftName = s.label && $
|
|
137
|
-
|
|
144
|
+
draftName = s.label && $sketchStyleName.startsWith(USER_STYLE_PREFIX) ? s.label : '';
|
|
145
|
+
styleError = '';
|
|
138
146
|
naming = true;
|
|
139
147
|
}
|
|
140
148
|
|
|
141
149
|
async function commitSave(e: SubmitEvent) {
|
|
142
150
|
e.preventDefault();
|
|
143
151
|
try {
|
|
144
|
-
await
|
|
152
|
+
await saveCurrentSketchStyle(draftName);
|
|
145
153
|
naming = false;
|
|
146
154
|
draftName = '';
|
|
147
|
-
|
|
155
|
+
styleError = '';
|
|
148
156
|
} catch (err) {
|
|
149
|
-
|
|
157
|
+
styleError = err instanceof Error ? err.message : 'Save failed';
|
|
150
158
|
}
|
|
151
159
|
}
|
|
152
160
|
|
|
153
|
-
async function
|
|
161
|
+
async function runStyleAction(action: Promise<unknown>) {
|
|
154
162
|
try {
|
|
155
163
|
await action;
|
|
156
|
-
|
|
164
|
+
styleError = '';
|
|
157
165
|
} catch (err) {
|
|
158
|
-
|
|
166
|
+
styleError = err instanceof Error ? err.message : 'That did not work';
|
|
159
167
|
}
|
|
160
168
|
}
|
|
161
169
|
|
|
@@ -229,19 +237,20 @@
|
|
|
229
237
|
<div class="sketch-tab">
|
|
230
238
|
<header class="head">
|
|
231
239
|
<div class="head-row">
|
|
232
|
-
<h2 class="section-title">
|
|
240
|
+
<h2 class="section-title">Sketchstyle</h2>
|
|
233
241
|
<div class="switch">
|
|
234
242
|
<Toggle
|
|
235
243
|
label="Sketch mode"
|
|
236
244
|
labelFirst
|
|
237
245
|
checked={$sketchEnabled}
|
|
238
|
-
onchange={
|
|
246
|
+
onchange={setSketchEnabled}
|
|
239
247
|
/>
|
|
240
248
|
<UIInfoPopover title="Sketch mode">
|
|
241
249
|
<p>
|
|
242
|
-
An effect layer over the active theme. It
|
|
243
|
-
|
|
244
|
-
|
|
250
|
+
An effect layer over the active theme. It repaints each component's fill and
|
|
251
|
+
outline from the tokens that component already owns, then pushes them around a
|
|
252
|
+
shared noise field. Save in the Theme panel folds the dials into the open theme,
|
|
253
|
+
or Save As when the open theme is Motion Proto, the read-only built-in one.
|
|
245
254
|
</p>
|
|
246
255
|
<p>
|
|
247
256
|
While it is on, the effect applies to the page behind this editor as well as to the
|
|
@@ -255,28 +264,46 @@
|
|
|
255
264
|
<div class="readout" aria-live="polite">
|
|
256
265
|
<span class="readout-name">{active.name}</span>
|
|
257
266
|
<p class="readout-blurb">{active.blurb}</p>
|
|
267
|
+
{#if $sketchOffLook}
|
|
268
|
+
{#if $sketchEnabled}
|
|
269
|
+
<p class="readout-off-look">
|
|
270
|
+
{#if activeIsProtected}
|
|
271
|
+
Motion Proto is read-only, and these dials are ahead of it. Use Save As in the
|
|
272
|
+
Theme panel to keep them in a new theme.
|
|
273
|
+
{:else}
|
|
274
|
+
These dials are ahead of the saved theme. Save it in the Theme panel to fold them
|
|
275
|
+
in.
|
|
276
|
+
{/if}
|
|
277
|
+
</p>
|
|
278
|
+
{:else}
|
|
279
|
+
<p class="readout-off-look">
|
|
280
|
+
The theme carries a sketchstyle this page is not painting. Saving now would drop
|
|
281
|
+
it.
|
|
282
|
+
</p>
|
|
283
|
+
{/if}
|
|
284
|
+
{/if}
|
|
258
285
|
</div>
|
|
259
286
|
|
|
260
287
|
<div class="presets">
|
|
261
|
-
{#each Object.entries(
|
|
288
|
+
{#each Object.entries(SKETCH_STYLES) as [name, style] (name)}
|
|
262
289
|
<label class="preset">
|
|
263
290
|
<input
|
|
264
291
|
type="radio"
|
|
265
|
-
name={
|
|
292
|
+
name={STYLE_RADIO_GROUP}
|
|
266
293
|
value={name}
|
|
267
|
-
checked={$
|
|
268
|
-
onchange={() =>
|
|
294
|
+
checked={$sketchStyleName === name}
|
|
295
|
+
onchange={() => selectSketchStyle(name)}
|
|
269
296
|
/>
|
|
270
|
-
<span class="preset-name">{
|
|
297
|
+
<span class="preset-name">{style.label}</span>
|
|
271
298
|
</label>
|
|
272
299
|
{/each}
|
|
273
300
|
</div>
|
|
274
301
|
|
|
275
302
|
<div class="saved">
|
|
276
303
|
<div class="saved-head">
|
|
277
|
-
<span class="band-label">Saved</span>
|
|
304
|
+
<span class="band-label">Saved sketchstyles</span>
|
|
278
305
|
<UIPillButton size="compact" icon="fa-floppy-disk" onclick={startNaming}>
|
|
279
|
-
Save
|
|
306
|
+
Save as sketchstyle…
|
|
280
307
|
</UIPillButton>
|
|
281
308
|
</div>
|
|
282
309
|
|
|
@@ -286,8 +313,8 @@
|
|
|
286
313
|
<input
|
|
287
314
|
class="save-name"
|
|
288
315
|
bind:value={draftName}
|
|
289
|
-
placeholder="
|
|
290
|
-
aria-label="
|
|
316
|
+
placeholder="Sketchstyle name"
|
|
317
|
+
aria-label="Sketchstyle name"
|
|
291
318
|
autofocus
|
|
292
319
|
/>
|
|
293
320
|
<UIPillButton size="compact" variant="primary" type="submit">Save</UIPillButton>
|
|
@@ -295,17 +322,17 @@
|
|
|
295
322
|
</form>
|
|
296
323
|
{/if}
|
|
297
324
|
|
|
298
|
-
{#if $
|
|
325
|
+
{#if $savedSketchStyles.length > 0}
|
|
299
326
|
<div class="presets">
|
|
300
|
-
{#each $
|
|
327
|
+
{#each $savedSketchStyles as saved (saved.fileName)}
|
|
301
328
|
<div class="saved-item">
|
|
302
329
|
<label class="preset">
|
|
303
330
|
<input
|
|
304
331
|
type="radio"
|
|
305
|
-
name={
|
|
306
|
-
value={
|
|
307
|
-
checked={$
|
|
308
|
-
onchange={() =>
|
|
332
|
+
name={STYLE_RADIO_GROUP}
|
|
333
|
+
value={USER_STYLE_PREFIX + saved.fileName}
|
|
334
|
+
checked={$sketchStyleName === USER_STYLE_PREFIX + saved.fileName}
|
|
335
|
+
onchange={() => runStyleAction(selectSavedSketchStyle(saved.fileName))}
|
|
309
336
|
/>
|
|
310
337
|
<span class="preset-name">{saved.name}</span>
|
|
311
338
|
</label>
|
|
@@ -314,15 +341,15 @@
|
|
|
314
341
|
class="saved-delete"
|
|
315
342
|
title="Delete {saved.name}"
|
|
316
343
|
aria-label="Delete {saved.name}"
|
|
317
|
-
onclick={() =>
|
|
344
|
+
onclick={() => runStyleAction(deleteSavedSketchStyle(saved.fileName))}
|
|
318
345
|
><i class="fas fa-xmark"></i></button>
|
|
319
346
|
</div>
|
|
320
347
|
{/each}
|
|
321
348
|
</div>
|
|
322
349
|
{/if}
|
|
323
350
|
|
|
324
|
-
{#if
|
|
325
|
-
<p class="saved-error">{
|
|
351
|
+
{#if styleError}
|
|
352
|
+
<p class="saved-error">{styleError}</p>
|
|
326
353
|
{/if}
|
|
327
354
|
</div>
|
|
328
355
|
</div>
|
|
@@ -793,9 +820,9 @@
|
|
|
793
820
|
}
|
|
794
821
|
|
|
795
822
|
|
|
796
|
-
/* Grid, saved band and readout are one control: which
|
|
797
|
-
that
|
|
798
|
-
caption under the tab. */
|
|
823
|
+
/* Grid, saved band and readout are one control: which sketchstyle is on, and
|
|
824
|
+
what that sketchstyle is. Splitting them left the description reading as a
|
|
825
|
+
stray caption under the tab. */
|
|
799
826
|
.picker {
|
|
800
827
|
display: flex;
|
|
801
828
|
flex-direction: column;
|
|
@@ -988,6 +1015,13 @@
|
|
|
988
1015
|
color: var(--ui-text-secondary);
|
|
989
1016
|
}
|
|
990
1017
|
|
|
1018
|
+
.readout-off-look {
|
|
1019
|
+
margin: var(--ui-space-2) 0 0;
|
|
1020
|
+
font-size: var(--ui-font-size-sm);
|
|
1021
|
+
font-weight: var(--ui-font-weight-medium);
|
|
1022
|
+
color: var(--ui-text-primary);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
991
1025
|
.dormant {
|
|
992
1026
|
margin: 0;
|
|
993
1027
|
font-size: var(--ui-font-size-sm);
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
* animations are hardcoded so token edits don't repaint our chrome. The
|
|
4
4
|
* exceptions are intentional and ARE the demo: the central box's
|
|
5
5
|
* surface/radius/border (set inline), the dropdown (rendered through
|
|
6
|
-
* <MenuSelect>),
|
|
6
|
+
* <MenuSelect>), elevation, which reads from the --shadow-* scale, and the
|
|
7
|
+
* zap colour, which tracks --text-accent so the beam stays on-theme.
|
|
7
8
|
* File is global; keep selectors `ftt-` prefixed.
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
.ftt-stage {
|
|
11
12
|
--ftt-contrast-color: var(--color-white);
|
|
13
|
+
--ftt-zap-color: var(--text-accent);
|
|
12
14
|
--ftt-string-opacity: 0.5;
|
|
13
15
|
position: relative;
|
|
14
16
|
width: 100%;
|
|
@@ -85,7 +87,7 @@
|
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
.ftt-string.ftt-live {
|
|
88
|
-
stroke:
|
|
90
|
+
stroke: var(--ftt-zap-color);
|
|
89
91
|
opacity: 1;
|
|
90
92
|
}
|
|
91
93
|
|
|
@@ -103,18 +105,18 @@
|
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
/* --- Energy ball ---------------------------------------------------------- */
|
|
106
|
-
/*
|
|
107
|
-
trail, not a colour-shifting projectile. */
|
|
108
|
+
/* Shares --ftt-zap-color with `.ftt-string.ftt-live` so the beam reads as a
|
|
109
|
+
continuous trail, not a colour-shifting projectile. */
|
|
108
110
|
.ftt-energy-ball {
|
|
109
111
|
position: absolute;
|
|
110
112
|
width: 0.875rem;
|
|
111
113
|
height: 0.875rem;
|
|
112
114
|
translate: -50% -50%;
|
|
113
115
|
border-radius: 9999px;
|
|
114
|
-
background:
|
|
116
|
+
background: var(--ftt-zap-color);
|
|
115
117
|
box-shadow:
|
|
116
|
-
0 0 8px 2px
|
|
117
|
-
0 0 18px 4px
|
|
118
|
+
0 0 8px 2px var(--ftt-zap-color),
|
|
119
|
+
0 0 18px 4px var(--ftt-zap-color);
|
|
118
120
|
pointer-events: none;
|
|
119
121
|
opacity: 0;
|
|
120
122
|
z-index: 6;
|
|
@@ -233,7 +235,7 @@
|
|
|
233
235
|
z-index: 30;
|
|
234
236
|
}
|
|
235
237
|
.ftt-tag-trigger:focus-visible {
|
|
236
|
-
outline: 2px solid
|
|
238
|
+
outline: 2px solid var(--ftt-zap-color);
|
|
237
239
|
outline-offset: 3px;
|
|
238
240
|
border-radius: 9999px;
|
|
239
241
|
}
|
|
@@ -681,8 +681,23 @@
|
|
|
681
681
|
--code-line-height: var(--line-height-normal);
|
|
682
682
|
--code-letter-spacing: var(--letter-spacing-normal);
|
|
683
683
|
|
|
684
|
-
/* Editorial — the long-reading role.
|
|
685
|
-
|
|
684
|
+
/* Editorial — the long-reading role. `md` is the reading step and takes the
|
|
685
|
+
most open leading; every step away from it tightens by one, so a lede or a
|
|
686
|
+
pull quote is not set at reading leading. Sizes stay inside the xs–xl band
|
|
687
|
+
the responsive scale leaves constant, so an article does not resize itself
|
|
688
|
+
between breakpoints. */
|
|
689
|
+
--editorial-xl-font-family: var(--font-editorial);
|
|
690
|
+
--editorial-xl-font-size: var(--font-size-xl);
|
|
691
|
+
--editorial-xl-font-weight: var(--font-weight-normal);
|
|
692
|
+
--editorial-xl-line-height: var(--line-height-tighter);
|
|
693
|
+
--editorial-xl-letter-spacing: var(--letter-spacing-normal);
|
|
694
|
+
|
|
695
|
+
--editorial-lg-font-family: var(--font-editorial);
|
|
696
|
+
--editorial-lg-font-size: var(--font-size-lg);
|
|
697
|
+
--editorial-lg-font-weight: var(--font-weight-normal);
|
|
698
|
+
--editorial-lg-line-height: var(--line-height-tight);
|
|
699
|
+
--editorial-lg-letter-spacing: var(--letter-spacing-normal);
|
|
700
|
+
|
|
686
701
|
--editorial-md-font-family: var(--font-editorial);
|
|
687
702
|
--editorial-md-font-size: var(--font-size-md);
|
|
688
703
|
--editorial-md-font-weight: var(--font-weight-normal);
|