@motion-proto/live-tokens 0.7.1 → 0.9.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-add-component/SKILL.md +488 -0
- package/README.md +34 -0
- package/dist-plugin/index.cjs +707 -90
- package/dist-plugin/index.d.cts +1 -0
- package/dist-plugin/index.d.ts +1 -0
- package/dist-plugin/index.js +707 -90
- package/package.json +6 -2
- package/src/app/site.css +1 -1
- package/src/editor/component-editor/CollapsibleSectionEditor.svelte +34 -27
- package/src/editor/component-editor/DialogEditor.svelte +4 -4
- package/src/editor/component-editor/NotificationEditor.svelte +3 -1
- package/src/editor/component-editor/SectionDividerEditor.svelte +439 -112
- package/src/editor/component-editor/StandardButtonsEditor.svelte +13 -1
- package/src/editor/component-editor/editors.d.ts +10 -0
- package/src/editor/component-editor/index.ts +16 -1
- package/src/editor/component-editor/registry.ts +103 -26
- package/src/editor/component-editor/scaffolding/AngleDial.svelte +52 -13
- package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +10 -11
- package/src/editor/component-editor/scaffolding/ComponentsTab.svelte +2 -2
- package/src/editor/component-editor/scaffolding/LinkedBlock.svelte +0 -1
- package/src/editor/component-editor/scaffolding/RadialShapePad.svelte +483 -0
- package/src/editor/component-editor/scaffolding/ShadowBackdrop.svelte +15 -2
- package/src/editor/component-editor/scaffolding/StateBlock.svelte +103 -15
- package/src/editor/component-editor/scaffolding/TokenLayout.svelte +9 -6
- package/src/editor/component-editor/scaffolding/TypeEditor.svelte +13 -1
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +239 -25
- package/src/editor/component-editor/scaffolding/buildTypeGroupTokens.ts +1 -0
- package/src/editor/component-editor/scaffolding/componentSources.ts +3 -3
- package/src/editor/component-editor/scaffolding/defaultSections.ts +15 -10
- package/src/editor/component-editor/scaffolding/types.ts +11 -0
- package/src/editor/core/components/componentConfigKeys.ts +22 -3
- package/src/editor/core/components/componentConfigService.ts +2 -2
- package/src/editor/core/components/componentPersist.ts +7 -5
- package/src/editor/core/manifests/manifestService.ts +58 -3
- package/src/editor/core/palettes/familySwap.ts +99 -0
- package/src/editor/core/palettes/paletteDerivation.ts +69 -0
- package/src/editor/core/palettes/tokenRegistry.ts +4 -1
- package/src/editor/core/store/editorStore.ts +206 -12
- package/src/editor/core/store/editorTypes.ts +55 -12
- package/src/editor/core/store/gradientSource.ts +192 -0
- package/src/editor/core/themes/migrations/2026-05-19-collapsiblesection-drop-frame-surface.ts +28 -0
- package/src/editor/core/themes/migrations/2026-05-19-sectiondivider-rich-gradient.ts +35 -0
- package/src/editor/core/themes/migrations/2026-05-20-sectiondivider-slim-variants.ts +82 -0
- package/src/editor/core/themes/migrations/2026-05-21-sectiondivider-spacing-to-padding.ts +24 -0
- package/src/editor/core/themes/migrations/2026-05-22-sectiondivider-intrinsics-to-css.ts +81 -0
- package/src/editor/core/themes/migrations/index.ts +10 -0
- package/src/editor/core/themes/slices/components.ts +27 -4
- package/src/editor/core/themes/slices/gradients.ts +88 -13
- package/src/editor/core/themes/themeInit.ts +2 -2
- package/src/editor/core/themes/themeTypes.ts +56 -1
- package/src/editor/index.ts +10 -1
- package/src/editor/overlay/ColumnsOverlay.svelte +0 -1
- package/src/editor/overlay/LiveEditorOverlay.svelte +1 -4
- package/src/editor/pages/ComponentEditorPage.svelte +53 -3
- package/src/editor/pages/EditorShell.svelte +53 -3
- package/src/editor/styles/ui-editor.css +1 -0
- package/src/editor/styles/ui-form-controls.css +19 -20
- package/src/editor/ui/BezierCurveEditor.svelte +114 -63
- package/src/editor/ui/EditorViewSwitcher.svelte +0 -1
- package/src/editor/ui/FileLoadList.svelte +22 -5
- package/src/editor/ui/FontStackEditor.svelte +214 -76
- package/src/editor/ui/GradientEditor.svelte +435 -215
- package/src/editor/ui/GradientStopPicker.svelte +11 -3
- package/src/editor/ui/ManifestFileManager.svelte +71 -4
- package/src/editor/ui/PaletteEditor.svelte +52 -79
- package/src/editor/ui/ProjectFontsSection.svelte +328 -293
- package/src/editor/ui/ThemeFileManager.svelte +0 -4
- package/src/editor/ui/UIFontFamilySelector.svelte +0 -1
- package/src/editor/ui/UIFontSizeSelector.svelte +3 -0
- package/src/editor/ui/UIInfoPopover.svelte +0 -1
- package/src/editor/ui/UILetterSpacingSelector.svelte +65 -0
- package/src/editor/ui/UIPaletteSelector.svelte +31 -4
- package/src/editor/ui/UIPillButton.svelte +33 -3
- package/src/editor/ui/UISegmentedControl.svelte +114 -0
- package/src/editor/ui/UITokenSelector.svelte +4 -1
- package/src/editor/ui/VariablesTab.svelte +41 -35
- package/src/editor/ui/palette/OverridesPanel.svelte +14 -37
- package/src/editor/ui/palette/PaletteBase.svelte +3 -3
- package/src/editor/ui/sections/ColumnsSection.svelte +1 -2
- package/src/editor/ui/sections/GradientsSection.svelte +1 -1
- package/src/editor/ui/sections/OverlaysSection.svelte +1 -1
- package/src/editor/ui/sections/ShadowsSection.svelte +1 -1
- package/src/system/components/Button.svelte +2 -2
- package/src/system/components/Card.svelte +29 -1
- package/src/system/components/CollapsibleSection.svelte +25 -2
- package/src/system/components/Dialog.svelte +24 -4
- package/src/system/components/FloatingTokenTags.css +43 -24
- package/src/system/components/FloatingTokenTags.svelte +88 -137
- package/src/system/components/Notification.svelte +8 -1
- package/src/system/components/SectionDivider.svelte +532 -381
- package/src/system/styles/CONVENTIONS.md +1 -1
- package/src/system/styles/fonts.css +3 -16
- package/src/system/styles/tokens.css +356 -1199
- package/src/system/styles/tokens.generated.css +544 -0
- package/src/editor/component-editor/scaffolding/DividerEditor.svelte +0 -94
- package/src/editor/component-editor/scaffolding/GradientCard.svelte +0 -296
|
@@ -12,10 +12,13 @@
|
|
|
12
12
|
stopId: string; // unique key (e.g. gradient-var + stop index)
|
|
13
13
|
color: string; // token name like '--color-brand-500'
|
|
14
14
|
opacity?: number; // 0–100
|
|
15
|
+
/** Forwarded to UIPaletteSelector to scope picks to a color family.
|
|
16
|
+
* See UIPaletteSelector's `familyFilter` for accepted values. */
|
|
17
|
+
familyFilter?: string | null;
|
|
15
18
|
onchange?: (payload: { color: string; opacity: number }) => void;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
let { stopId, color, opacity = 100, onchange }: Props = $props();
|
|
21
|
+
let { stopId, color, opacity = 100, familyFilter = null, onchange }: Props = $props();
|
|
19
22
|
|
|
20
23
|
/** Scratch var the embedded picker reads/writes; isolated per stop. */
|
|
21
24
|
let scratchVar = $derived(`--__grad-stop-${stopId}`);
|
|
@@ -26,10 +29,15 @@
|
|
|
26
29
|
return `color-mix(in srgb, ${base} ${Math.round(o)}%, transparent)`;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
/** Parse a scratch var write back into structured stop fields.
|
|
32
|
+
/** Parse a scratch var write back into structured stop fields. UIPaletteSelector's
|
|
33
|
+
* "None" choice writes the literal `transparent`; we round-trip it as a stop
|
|
34
|
+
* whose color is the keyword itself — `formatGradientStopColor` already passes
|
|
35
|
+
* non-`--` colors through verbatim, so the gradient (or solid first-stop) ends
|
|
36
|
+
* up painting `transparent`. */
|
|
30
37
|
function parseScratch(raw: string): { color: string; opacity: number } | null {
|
|
31
38
|
const trimmed = raw.trim();
|
|
32
39
|
if (!trimmed) return null;
|
|
40
|
+
if (trimmed === 'transparent') return { color: 'transparent', opacity: 100 };
|
|
33
41
|
const mixMatch = trimmed.match(/^color-mix\(in srgb,\s*var\((--[a-z0-9-]+)\)\s+(\d+(?:\.\d+)?)%,\s*transparent\)$/i);
|
|
34
42
|
if (mixMatch) {
|
|
35
43
|
return { color: mixMatch[1], opacity: parseFloat(mixMatch[2]) };
|
|
@@ -60,4 +68,4 @@
|
|
|
60
68
|
}
|
|
61
69
|
</script>
|
|
62
70
|
|
|
63
|
-
<UIPaletteSelector variable={scratchVar} onchange={handleChange} />
|
|
71
|
+
<UIPaletteSelector variable={scratchVar} {familyFilter} onchange={handleChange} />
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
applyManifest,
|
|
9
9
|
saveAsManifest,
|
|
10
10
|
saveActiveManifest,
|
|
11
|
+
exportManifest,
|
|
12
|
+
importManifest,
|
|
11
13
|
} from '../core/manifests/manifestService';
|
|
12
14
|
import { dirty, componentDirty } from '../core/store/editorStore';
|
|
13
15
|
import { productionRevision, activeManifest } from '../core/productionPulse';
|
|
@@ -118,14 +120,62 @@
|
|
|
118
120
|
showFileList = false;
|
|
119
121
|
try {
|
|
120
122
|
await applyManifest(file.fileName);
|
|
121
|
-
// applyManifest atomically flips active
|
|
122
|
-
//
|
|
123
|
+
// applyManifest atomically flips active + production pointers and
|
|
124
|
+
// syncs tokens.css; reload to rehydrate the editor from the
|
|
125
|
+
// now-active theme + component configs.
|
|
123
126
|
window.location.reload();
|
|
124
127
|
} catch (err) {
|
|
125
128
|
window.alert(`Failed to apply manifest: ${(err as Error).message}`);
|
|
126
129
|
}
|
|
127
130
|
}
|
|
128
131
|
|
|
132
|
+
async function handleExport(file: ManifestMeta) {
|
|
133
|
+
try {
|
|
134
|
+
await exportManifest(file.fileName);
|
|
135
|
+
} catch (err) {
|
|
136
|
+
window.alert(`Failed to export: ${(err as Error).message}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
let importInput: HTMLInputElement | null = $state(null);
|
|
141
|
+
|
|
142
|
+
function openImport() {
|
|
143
|
+
importInput?.click();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function handleImportFile(event: Event) {
|
|
147
|
+
const input = event.target as HTMLInputElement;
|
|
148
|
+
const file = input.files?.[0];
|
|
149
|
+
input.value = ''; // allow re-picking the same file later
|
|
150
|
+
if (!file) return;
|
|
151
|
+
let bundle: any;
|
|
152
|
+
try {
|
|
153
|
+
bundle = JSON.parse(await file.text());
|
|
154
|
+
} catch {
|
|
155
|
+
window.alert('Selected file is not valid JSON.');
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (bundle?.kind !== 'manifest-bundle') {
|
|
159
|
+
window.alert('Not a manifest bundle (missing kind discriminator).');
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
const result = await importManifest(bundle);
|
|
164
|
+
await refreshFiles();
|
|
165
|
+
const renameCount = Object.keys(result.renames).length;
|
|
166
|
+
if (renameCount > 0) {
|
|
167
|
+
const summary = Object.entries(result.renames)
|
|
168
|
+
.map(([k, v]) => `${k} → ${v}`)
|
|
169
|
+
.join('\n');
|
|
170
|
+
window.alert(
|
|
171
|
+
`Imported as "${result.manifest}". ${renameCount} file(s) renamed to avoid collisions:\n\n${summary}`,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
} catch (err) {
|
|
175
|
+
window.alert(`Failed to import: ${(err as Error).message}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
129
179
|
async function handleDelete(file: ManifestMeta) {
|
|
130
180
|
if (file.isProtected) return;
|
|
131
181
|
if (file.fileName === activeFileName) {
|
|
@@ -218,10 +268,27 @@
|
|
|
218
268
|
<i class="fas fa-folder-open"></i>
|
|
219
269
|
<span>Load…</span>
|
|
220
270
|
</button>
|
|
271
|
+
<button
|
|
272
|
+
class="mfm-btn mfm-btn-row"
|
|
273
|
+
onclick={openImport}
|
|
274
|
+
title="Import a shared manifest bundle"
|
|
275
|
+
>
|
|
276
|
+
<i class="fas fa-file-import"></i>
|
|
277
|
+
<span>Import…</span>
|
|
278
|
+
</button>
|
|
221
279
|
</div>
|
|
222
280
|
</div>
|
|
223
281
|
</div>
|
|
224
282
|
|
|
283
|
+
<!-- Hidden file input for Import; clicked via openImport(). -->
|
|
284
|
+
<input
|
|
285
|
+
bind:this={importInput}
|
|
286
|
+
type="file"
|
|
287
|
+
accept=".json,application/json"
|
|
288
|
+
onchange={handleImportFile}
|
|
289
|
+
style="display: none;"
|
|
290
|
+
/>
|
|
291
|
+
|
|
225
292
|
<FileLoadList
|
|
226
293
|
bind:show={showFileList}
|
|
227
294
|
title="Load Manifest"
|
|
@@ -229,6 +296,8 @@
|
|
|
229
296
|
{activeFileName}
|
|
230
297
|
onload={handleApply}
|
|
231
298
|
ondelete={handleDelete}
|
|
299
|
+
onexport={handleExport}
|
|
300
|
+
exportTitle={(f) => `Export "${f.name}" as a shareable bundle`}
|
|
232
301
|
/>
|
|
233
302
|
|
|
234
303
|
<SaveAsDialog
|
|
@@ -265,7 +334,6 @@
|
|
|
265
334
|
font-size: var(--ui-font-size-xs);
|
|
266
335
|
color: var(--ui-text-secondary);
|
|
267
336
|
text-transform: uppercase;
|
|
268
|
-
letter-spacing: 0.05em;
|
|
269
337
|
}
|
|
270
338
|
|
|
271
339
|
.mfm-card {
|
|
@@ -304,7 +372,6 @@
|
|
|
304
372
|
.mfm-card-label {
|
|
305
373
|
font-size: 10px;
|
|
306
374
|
font-weight: var(--ui-font-weight-semibold);
|
|
307
|
-
letter-spacing: 0.08em;
|
|
308
375
|
text-transform: uppercase;
|
|
309
376
|
color: var(--ui-text-tertiary);
|
|
310
377
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { stopPropagation, createBubbler } from 'svelte/legacy';
|
|
3
3
|
|
|
4
4
|
const bubble = createBubbler();
|
|
5
|
-
import { onMount, onDestroy, tick } from 'svelte';
|
|
5
|
+
import { onMount, onDestroy, tick, untrack } from 'svelte';
|
|
6
6
|
import { hexToOklch } from '../core/palettes/oklch';
|
|
7
7
|
import { type CurveAnchor, lightnessCurveConfig, saturationCurveConfig } from './curveEngine';
|
|
8
8
|
import ColorEditPanel from './ColorEditPanel.svelte';
|
|
9
9
|
import OverridesPanel from './palette/OverridesPanel.svelte';
|
|
10
|
+
import UIPillButton from './UIPillButton.svelte';
|
|
10
11
|
import GradientStopEditor from './palette/GradientStopEditor.svelte';
|
|
11
12
|
import ScaleCurveEditor from './palette/ScaleCurveEditor.svelte';
|
|
12
13
|
import PaletteBase from './palette/PaletteBase.svelte';
|
|
@@ -79,8 +80,18 @@
|
|
|
79
80
|
});
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
let lockedLightnessIdx: number | null = $
|
|
83
|
-
|
|
83
|
+
let lockedLightnessIdx: number | null = $derived.by(() => {
|
|
84
|
+
if (!anchorToBase) return null;
|
|
85
|
+
const x500 = stepIndexToX(4);
|
|
86
|
+
const idx = lightnessCurve.findIndex(a => Math.abs(a.x - x500) < 0.5);
|
|
87
|
+
return idx >= 0 ? idx : null;
|
|
88
|
+
});
|
|
89
|
+
let lockedSaturationIdx: number | null = $derived.by(() => {
|
|
90
|
+
if (!anchorToBase) return null;
|
|
91
|
+
const x500 = stepIndexToX(4);
|
|
92
|
+
const idx = saturationCurve.findIndex(a => Math.abs(a.x - x500) < 0.5);
|
|
93
|
+
return idx >= 0 ? idx : null;
|
|
94
|
+
});
|
|
84
95
|
|
|
85
96
|
// Held at component scope so inline header-swatch handlers and the function
|
|
86
97
|
// handlers share one handle for commit/cancel.
|
|
@@ -95,10 +106,6 @@
|
|
|
95
106
|
return ps ? ps.effective : '#000000';
|
|
96
107
|
}
|
|
97
108
|
|
|
98
|
-
let gradientColorStops = $state('');
|
|
99
|
-
let gradientCssValue = $state('');
|
|
100
|
-
let gradientBarPreview = $state('');
|
|
101
|
-
|
|
102
109
|
function onEmptyModeChange(e: Event) {
|
|
103
110
|
edit('emptyMode', (e.currentTarget as HTMLInputElement).checked ? 'gradient' : 'solid');
|
|
104
111
|
}
|
|
@@ -464,28 +471,21 @@
|
|
|
464
471
|
let gray500Hex = $derived(mode === 'gray'
|
|
465
472
|
? (grayComputed.find(g => g.step.label === '500')?.hex ?? GRAY_FALLBACK)
|
|
466
473
|
: baseColor);
|
|
467
|
-
run(() => {
|
|
468
|
-
if (anchorToBase) {
|
|
469
|
-
const x500 = stepIndexToX(4);
|
|
470
|
-
const lIdx = lightnessCurve.findIndex(a => Math.abs(a.x - x500) < 0.5);
|
|
471
|
-
lockedLightnessIdx = lIdx >= 0 ? lIdx : null;
|
|
472
|
-
const sIdx = saturationCurve.findIndex(a => Math.abs(a.x - x500) < 0.5);
|
|
473
|
-
lockedSaturationIdx = sIdx >= 0 ? sIdx : null;
|
|
474
|
-
} else {
|
|
475
|
-
lockedLightnessIdx = null;
|
|
476
|
-
lockedSaturationIdx = null;
|
|
477
|
-
}
|
|
478
|
-
});
|
|
479
474
|
// Keep the locked lightness anchor y in sync with baseColor. Idempotent.
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
475
|
+
// `lightnessCurve` is read via `untrack` so writing it back via `edit` does
|
|
476
|
+
// not retrigger this effect (Svelte 5 flags the read+write pattern as
|
|
477
|
+
// recursive).
|
|
478
|
+
$effect(() => {
|
|
479
|
+
if (!anchorToBase || lockedLightnessIdx === null || !baseColor) return;
|
|
480
|
+
const targetY = hexToOklch(baseColor).l * 100;
|
|
481
|
+
untrack(() => {
|
|
482
|
+
const idx = lockedLightnessIdx;
|
|
483
|
+
if (idx === null) return;
|
|
484
|
+
const curve = lightnessCurve;
|
|
485
|
+
if (curve[idx] && Math.abs(curve[idx].y - targetY) > 0.01) {
|
|
486
|
+
edit('lightnessCurve', curve.map((a, i) => i === idx ? { ...a, y: targetY } : a));
|
|
487
487
|
}
|
|
488
|
-
}
|
|
488
|
+
});
|
|
489
489
|
});
|
|
490
490
|
let paletteComputed = $derived((() => {
|
|
491
491
|
const _bc = baseColor, _lc = lightnessCurve, _sc = saturationCurve, _co = curveOffset, _ed = editingDraft, _ek = editingKey, _ov = overrides, _ab = anchorToBase;
|
|
@@ -503,21 +503,11 @@
|
|
|
503
503
|
};
|
|
504
504
|
});
|
|
505
505
|
})());
|
|
506
|
-
|
|
507
|
-
run(() => {
|
|
506
|
+
let gradientBarPreview = $derived.by(() => {
|
|
508
507
|
const pc = paletteComputed;
|
|
509
508
|
const sorted = [...gradientStops].sort((a, b) => gradientReverse ? b.position - a.position : a.position - b.position);
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
if (emptySelector && emptyMode === 'gradient') {
|
|
513
|
-
switch (gradientStyle) {
|
|
514
|
-
case 'radial': gradientCssValue = `radial-gradient(circle, ${gradientColorStops})`; break;
|
|
515
|
-
case 'conic': gradientCssValue = `conic-gradient(from ${gradientAngle}deg, ${gradientColorStops})`; break;
|
|
516
|
-
default: gradientCssValue = `linear-gradient(${gradientAngle}deg, ${gradientColorStops})`;
|
|
517
|
-
}
|
|
518
|
-
} else {
|
|
519
|
-
gradientCssValue = '';
|
|
520
|
-
}
|
|
509
|
+
const stops = sorted.map(s => `${stopColor(s, pc)} ${s.position}%`).join(', ');
|
|
510
|
+
return `linear-gradient(to right, ${stops})`;
|
|
521
511
|
});
|
|
522
512
|
let grayScales = $derived(mode === 'gray' ? scales : []);
|
|
523
513
|
let curveVersion = $derived(JSON.stringify(scaleCurves) + JSON.stringify(curveOffset) + gray500Hex);
|
|
@@ -606,12 +596,10 @@
|
|
|
606
596
|
<span>Gradient</span>
|
|
607
597
|
</label>
|
|
608
598
|
{/if}
|
|
609
|
-
<
|
|
610
|
-
<
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
onclick={() => paletteEditorOpen = !paletteEditorOpen}
|
|
614
|
-
>{paletteEditorOpen ? 'Close' : 'Edit'}</button>
|
|
599
|
+
<UIPillButton size="compact" variant="outline" onclick={clearPaletteOverrides}>Clear Overrides</UIPillButton>
|
|
600
|
+
<UIPillButton size="compact" variant="outline" onclick={() => paletteEditorOpen = !paletteEditorOpen}>
|
|
601
|
+
{paletteEditorOpen ? 'Close' : 'Edit'}
|
|
602
|
+
</UIPillButton>
|
|
615
603
|
</div>
|
|
616
604
|
<div class="swatch-grid" style="--swatch-cols: {paletteStepLightness.length + 2}">
|
|
617
605
|
<div class="step-column">
|
|
@@ -718,12 +706,10 @@
|
|
|
718
706
|
<div class="scale-section">
|
|
719
707
|
<div class="scale-header">
|
|
720
708
|
<h4 class="scale-title">{displayLabel ?? label}</h4>
|
|
721
|
-
<
|
|
722
|
-
<
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
onclick={() => grayEditorOpen = !grayEditorOpen}
|
|
726
|
-
>{grayEditorOpen ? 'Close' : 'Edit'}</button>
|
|
709
|
+
<UIPillButton size="compact" variant="outline" onclick={clearPaletteOverrides}>Clear Overrides</UIPillButton>
|
|
710
|
+
<UIPillButton size="compact" variant="outline" onclick={() => grayEditorOpen = !grayEditorOpen}>
|
|
711
|
+
{grayEditorOpen ? 'Close' : 'Edit'}
|
|
712
|
+
</UIPillButton>
|
|
727
713
|
</div>
|
|
728
714
|
<div class="swatch-grid" style="--swatch-cols: {graySteps.length + 2}">
|
|
729
715
|
<div class="step-column">
|
|
@@ -891,21 +877,7 @@
|
|
|
891
877
|
display: flex;
|
|
892
878
|
align-items: center;
|
|
893
879
|
gap: var(--ui-space-8);
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
.edit-toggle {
|
|
897
|
-
font-size: var(--ui-font-size-md);
|
|
898
|
-
color: var(--ui-text-tertiary);
|
|
899
|
-
background: none;
|
|
900
|
-
border: 1px solid var(--ui-border-low);
|
|
901
|
-
border-radius: var(--ui-radius-sm);
|
|
902
|
-
padding: var(--ui-space-2) var(--ui-space-6);
|
|
903
|
-
cursor: pointer;
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
.edit-toggle:hover {
|
|
907
|
-
color: var(--ui-text-primary);
|
|
908
|
-
border-color: var(--ui-border-high);
|
|
880
|
+
padding-bottom: 0.5rem;
|
|
909
881
|
}
|
|
910
882
|
|
|
911
883
|
.derived-toggle {
|
|
@@ -915,17 +887,15 @@
|
|
|
915
887
|
padding: var(--ui-space-6) var(--ui-space-4);
|
|
916
888
|
background: none;
|
|
917
889
|
border: none;
|
|
918
|
-
color: var(--ui-text-
|
|
919
|
-
font-size: var(--ui-font-size-
|
|
920
|
-
font-weight: var(--ui-font-weight-
|
|
890
|
+
color: var(--ui-text-secondary);
|
|
891
|
+
font-size: var(--ui-font-size-lg);
|
|
892
|
+
font-weight: var(--ui-font-weight-light);
|
|
921
893
|
cursor: pointer;
|
|
922
894
|
transition: color var(--ui-transition-fast);
|
|
923
|
-
text-transform: uppercase;
|
|
924
|
-
letter-spacing: 0.04em;
|
|
925
895
|
}
|
|
926
896
|
|
|
927
897
|
.derived-toggle:hover {
|
|
928
|
-
color: var(--ui-text-
|
|
898
|
+
color: var(--ui-text-primary);
|
|
929
899
|
}
|
|
930
900
|
|
|
931
901
|
.derived-toggle i {
|
|
@@ -952,12 +922,11 @@
|
|
|
952
922
|
}
|
|
953
923
|
|
|
954
924
|
.scale-title {
|
|
955
|
-
font-size: var(--ui-font-size-
|
|
956
|
-
font-weight: var(--ui-font-weight-
|
|
957
|
-
color: var(--ui-text-
|
|
925
|
+
font-size: var(--ui-font-size-lg);
|
|
926
|
+
font-weight: var(--ui-font-weight-bold);
|
|
927
|
+
color: var(--ui-text-primary);
|
|
958
928
|
margin: 0;
|
|
959
|
-
|
|
960
|
-
letter-spacing: 0.05em;
|
|
929
|
+
padding-right: 1rem;
|
|
961
930
|
}
|
|
962
931
|
|
|
963
932
|
/* Step columns */
|
|
@@ -1024,7 +993,11 @@
|
|
|
1024
993
|
background: none;
|
|
1025
994
|
border: none;
|
|
1026
995
|
text-align: center;
|
|
996
|
+
display: block;
|
|
997
|
+
width: 100%;
|
|
998
|
+
box-sizing: border-box;
|
|
1027
999
|
min-width: 0;
|
|
1000
|
+
margin-top: var(--ui-space-2);
|
|
1028
1001
|
overflow: hidden;
|
|
1029
1002
|
text-overflow: ellipsis;
|
|
1030
1003
|
}
|