@motion-proto/live-tokens 0.47.0 → 0.48.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-shape-space/SKILL.md +68 -0
- package/.claude/skills/live-tokens-create-component/SKILL.md +2 -2
- package/.claude/skills/live-tokens-generate-theme/SKILL.md +152 -0
- package/CHANGELOG.md +292 -0
- package/README.md +37 -26
- package/bin/adjust.mjs +254 -0
- package/bin/cli.mjs +94 -7
- package/bin/generate-theme.mjs +251 -0
- package/bin/migrate.mjs +95 -6
- package/dist-plugin/adjust/index.cjs +259 -0
- package/dist-plugin/adjust/index.d.cts +45 -0
- package/dist-plugin/adjust/index.d.ts +45 -0
- package/dist-plugin/adjust/index.js +176 -0
- package/dist-plugin/{chunk-H4TRUINI.js → chunk-44RSTAII.js} +0 -48
- package/dist-plugin/chunk-6OZFXIQI.js +316 -0
- package/dist-plugin/chunk-76TFDTJO.js +556 -0
- package/dist-plugin/chunk-D3ZVKOR4.js +52 -0
- package/dist-plugin/dataPaths-DBN0RPuT.d.cts +54 -0
- package/dist-plugin/dataPaths-DBN0RPuT.d.ts +54 -0
- package/dist-plugin/generateColorsAndType/index.cjs +1781 -0
- package/dist-plugin/generateColorsAndType/index.d.cts +81 -0
- package/dist-plugin/generateColorsAndType/index.d.ts +81 -0
- package/dist-plugin/generateColorsAndType/index.js +1210 -0
- package/dist-plugin/index.cjs +901 -533
- package/dist-plugin/index.d.cts +3 -2
- package/dist-plugin/index.d.ts +3 -2
- package/dist-plugin/index.js +658 -1082
- package/dist-plugin/migrateData/index.cjs +728 -0
- package/dist-plugin/migrateData/index.d.cts +60 -0
- package/dist-plugin/migrateData/index.d.ts +60 -0
- package/dist-plugin/migrateData/index.js +348 -0
- package/dist-plugin/themeTypes-DMHZOnUn.d.cts +211 -0
- package/dist-plugin/themeTypes-DMHZOnUn.d.ts +211 -0
- package/dist-plugin/tokensCssMigrations/index.cjs +2 -1
- package/dist-plugin/tokensCssMigrations/index.d.cts +3 -15
- package/dist-plugin/tokensCssMigrations/index.d.ts +3 -15
- package/dist-plugin/tokensCssMigrations/index.js +4 -2
- package/package.json +18 -4
- package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +183 -158
- package/src/editor/component-editor/scaffolding/ComponentFileMenu.svelte +0 -4
- package/src/editor/component-editor/scaffolding/SaveAsDialog.svelte +4 -4
- package/src/editor/component-editor/scaffolding/TokenLayout.svelte +2 -59
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +1 -1
- package/src/editor/core/components/adjustAliases.ts +180 -0
- package/src/editor/core/components/aliasKinds.ts +73 -0
- package/src/editor/core/components/componentConfigService.ts +26 -38
- package/src/editor/core/flashStatus.ts +1 -1
- package/src/editor/core/fonts/fontMigration.ts +13 -13
- package/src/editor/core/fonts/fontPairing.ts +35 -0
- package/src/editor/core/palettes/paletteDerivation.ts +128 -16
- package/src/editor/core/preview/lookPreview.ts +141 -0
- package/src/editor/core/productionPulse.ts +34 -21
- package/src/editor/core/storage/files/versionedFileResourceClient.ts +18 -45
- package/src/editor/core/store/editorConfigStore.ts +2 -2
- package/src/editor/core/store/editorPersistence.ts +0 -1
- package/src/editor/core/store/editorStore.ts +114 -51
- package/src/editor/core/store/editorTypes.ts +0 -1
- package/src/editor/core/store/gradientSource.ts +2 -2
- package/src/editor/core/themes/colorsAndTypeService.ts +95 -0
- package/src/editor/core/themes/generateColorsAndType.ts +433 -0
- package/src/editor/core/themes/loadRows.ts +64 -0
- package/src/editor/core/themes/lookSummary.ts +75 -0
- package/src/editor/core/themes/migrations/2026-04-24-legacy-keys-and-bg-to-canvas.ts +3 -3
- package/src/editor/core/themes/migrations/2026-05-13-primary-to-brand.ts +2 -2
- package/src/editor/core/themes/migrations/2026-05-26-drop-overlay-extra-stops.ts +3 -3
- package/src/editor/core/themes/migrations/2026-08-13-drop-legacy-shape-space-keys.ts +38 -0
- package/src/editor/core/themes/migrations/2026-08-15-line-height-scale-rename.ts +57 -0
- package/src/editor/core/themes/migrations/index.ts +19 -11
- package/src/editor/core/themes/slices/components.ts +4 -4
- package/src/editor/core/themes/slices/fonts.ts +1 -1
- package/src/editor/core/themes/slices/gradients.ts +22 -0
- package/src/editor/core/themes/slices/palettes.ts +2 -2
- package/src/editor/core/themes/themeInit.ts +21 -29
- package/src/editor/core/themes/themeService.ts +218 -78
- package/src/editor/core/themes/themeTypes.ts +94 -51
- package/src/editor/docs/Docs.svelte +1 -0
- package/src/editor/docs/chapters.ts +1 -0
- package/src/editor/docs/content/01-overview.md +1 -1
- package/src/editor/docs/content/editing-tokens.md +6 -6
- package/src/editor/docs/content/getting-started.md +9 -7
- package/src/editor/docs/content/themes-workflow.md +74 -34
- package/src/editor/docs/content/where-themes-live.md +61 -0
- package/src/editor/docs/content.generated.ts +5 -4
- package/src/editor/index.ts +27 -27
- package/src/editor/pages/ComponentEditorPage.svelte +2 -2
- package/src/editor/pages/EditorShell.svelte +4 -30
- package/src/editor/ui/BezierCurveEditor.svelte +2 -2
- package/src/editor/ui/ColorEditPanel.svelte +1 -1
- package/src/editor/ui/FileLoadList.svelte +67 -7
- package/src/editor/ui/GradientEditor.svelte +3 -3
- package/src/editor/ui/PaletteEditor.svelte +26 -12
- package/src/editor/ui/ThemePanel.svelte +1067 -0
- package/src/editor/ui/UIDialog.svelte +11 -9
- package/src/editor/ui/UIPillButton.svelte +7 -2
- package/src/editor/ui/colors/ColorWheel.svelte +34 -1
- package/src/editor/ui/curveEngine.ts +48 -0
- package/src/editor/ui/index.ts +4 -2
- package/src/editor/ui/palette/PaletteBase.svelte +75 -51
- package/src/editor/ui/palette/PaletteJumpButton.svelte +3 -8
- package/src/live-tokens/data/colors-and-type/autumn.json +2490 -0
- package/src/live-tokens/data/{themes → colors-and-type}/default.json +816 -293
- package/src/live-tokens/data/colors-and-type/halloween.json +2529 -0
- package/src/live-tokens/data/colors-and-type/midnight-study.json +2536 -0
- package/src/live-tokens/data/colors-and-type/ocean.json +2489 -0
- package/src/live-tokens/data/colors-and-type/royal-velvet.json +2520 -0
- package/src/live-tokens/data/colors-and-type/spring-meadow.json +2476 -0
- package/src/live-tokens/data/colors-and-type/sunset.json +2528 -0
- package/src/live-tokens/data/themes/autumn.json +3918 -0
- package/src/live-tokens/data/themes/halloween.json +3992 -0
- package/src/live-tokens/data/themes/midnight-study.json +3932 -0
- package/src/live-tokens/data/themes/ocean.json +3917 -0
- package/src/live-tokens/data/themes/royal-velvet.json +3983 -0
- package/src/live-tokens/data/themes/spring-meadow.json +3904 -0
- package/src/live-tokens/data/themes/sunset.json +3931 -0
- package/src/live-tokens/data/tokens.generated.css +106 -117
- package/src/system/styles/CONVENTIONS.md +1 -1
- package/src/system/styles/fonts.css +1 -1
- package/template/README.md +7 -5
- package/template/_gitignore +0 -6
- package/src/editor/core/components/componentPersist.ts +0 -62
- package/src/editor/core/manifests/manifestService.ts +0 -172
- package/src/editor/ui/ManifestFileManager.svelte +0 -446
- package/src/editor/ui/ThemeFileManager.svelte +0 -785
- package/src/live-tokens/data/manifests/default.json +0 -35
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Migration } from './index';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The data half of the tokens.css migration `2026-07-20-line-height-rename`,
|
|
5
|
+
* which reshaped the line-height scale from size vocabulary to leading
|
|
6
|
+
* vocabulary. That pass renames the definitions in `tokens.css`; a saved file
|
|
7
|
+
* still references the old names, and a reference to a token that no longer
|
|
8
|
+
* exists renders as nothing. Both layers reference the scale, so both migrate:
|
|
9
|
+
* colors-and-type through its `cssVariables`, a component config through its
|
|
10
|
+
* alias values.
|
|
11
|
+
*
|
|
12
|
+
* `xl` (2) has no slot in the leading scale, so it lands on `relaxed` (1.75),
|
|
13
|
+
* the nearest surviving step. That is a visible change to a line that used it,
|
|
14
|
+
* and the only alternative is a dangling reference.
|
|
15
|
+
*
|
|
16
|
+
* Values alone, never keys: a key is a definition (or, in a component config,
|
|
17
|
+
* the component's own token), and remapping `--line-height-xl` onto
|
|
18
|
+
* `--line-height-relaxed` would redefine a surviving step at 2 for everything
|
|
19
|
+
* that references it.
|
|
20
|
+
*/
|
|
21
|
+
const RENAMED: Record<string, string> = {
|
|
22
|
+
'--line-height-xs': '--line-height-none',
|
|
23
|
+
'--line-height-sm': '--line-height-tighter',
|
|
24
|
+
'--line-height-md': '--line-height-normal',
|
|
25
|
+
'--line-height-lg': '--line-height-relaxed',
|
|
26
|
+
'--line-height-xl': '--line-height-relaxed',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Bare (`--line-height-md`) and wrapped (`var(--line-height-md)`) references
|
|
30
|
+
// both occur; the lookahead keeps `--line-height-md` from matching inside a
|
|
31
|
+
// longer name.
|
|
32
|
+
const REFERENCE = /--line-height-(?:xs|sm|md|lg|xl)(?![\w-])/g;
|
|
33
|
+
|
|
34
|
+
function renameValues(rawVars: Record<string, string>): Record<string, string> {
|
|
35
|
+
const out: Record<string, string> = {};
|
|
36
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
37
|
+
out[key] =
|
|
38
|
+
typeof value === 'string' ? value.replace(REFERENCE, (name) => RENAMED[name]) : value;
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const colorsAndTypeMigration_2026_08_15_lineHeightScaleRename: Migration = {
|
|
44
|
+
id: '2026-08-15-line-height-scale-rename-colors-and-type',
|
|
45
|
+
fromVersion: 4,
|
|
46
|
+
toVersion: 5,
|
|
47
|
+
appliesTo: 'colors-and-type',
|
|
48
|
+
apply: renameValues,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const componentMigration_2026_08_15_lineHeightScaleRename: Migration = {
|
|
52
|
+
id: '2026-08-15-line-height-scale-rename-component',
|
|
53
|
+
fromVersion: 20,
|
|
54
|
+
toVersion: 21,
|
|
55
|
+
appliesTo: 'component-config',
|
|
56
|
+
apply: renameValues,
|
|
57
|
+
};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* is past a given version, that migration's bookkeeping is dead code and
|
|
9
9
|
* the file can be deleted.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
11
|
+
* ColorsAndType and component-config have INDEPENDENT version sequences. Every
|
|
12
12
|
* theme migration steps the theme version; every component-config migration
|
|
13
13
|
* steps the component-config version. There is no shared 'both' kind.
|
|
14
14
|
*/
|
|
@@ -25,19 +25,19 @@ export interface Migration {
|
|
|
25
25
|
/** Post-condition version — files past this no longer need this migration. */
|
|
26
26
|
toVersion: number;
|
|
27
27
|
/** Which storage flavor this applies to. */
|
|
28
|
-
appliesTo: '
|
|
28
|
+
appliesTo: 'colors-and-type' | 'component-config';
|
|
29
29
|
/** Pure transform on the raw vars map. May add, remove, or rename keys. */
|
|
30
30
|
apply(rawVars: Record<string, string>, meta: MigrationMeta): Record<string, string>;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
import {
|
|
33
|
+
import { colorsAndTypeMigration_2026_04_24_legacyKeysAndBgToCanvas } from './2026-04-24-legacy-keys-and-bg-to-canvas';
|
|
34
34
|
import { componentMigration_2026_04_24_prefixAndSuffixRenames } from './2026-04-24-component-prefix-and-suffix-renames';
|
|
35
35
|
import { componentMigration_2026_04_27_segmentedcontrolDisabledFlatten } from './2026-04-27-segmentedcontrol-disabled-flatten';
|
|
36
36
|
import { componentMigration_2026_05_08_collapsiblesectionVariantNamespace } from './2026-05-08-collapsiblesection-variant-namespace';
|
|
37
37
|
import { componentMigration_2026_05_08_collapsiblesectionFrameAndCleanup } from './2026-05-08-collapsiblesection-frame-and-cleanup';
|
|
38
38
|
import { componentMigration_2026_05_10_sectiondividerGradientStops } from './2026-05-10-sectiondivider-gradient-stops';
|
|
39
39
|
import {
|
|
40
|
-
|
|
40
|
+
colorsAndTypeMigration_2026_05_13_primaryToBrand,
|
|
41
41
|
componentMigration_2026_05_13_primaryToBrand,
|
|
42
42
|
} from './2026-05-13-primary-to-brand';
|
|
43
43
|
import { componentMigration_2026_05_19_collapsiblesectionDropFrameSurface } from './2026-05-19-collapsiblesection-drop-frame-surface';
|
|
@@ -51,20 +51,25 @@ import { componentMigration_2026_05_24_progressbarCollapseVariants } from './202
|
|
|
51
51
|
import { componentMigration_2026_05_24_collapsiblesectionDropActiveState } from './2026-05-24-collapsiblesection-drop-active-state';
|
|
52
52
|
import { componentMigration_2026_05_25_cornerbadgeFlattenVariants } from './2026-05-25-cornerbadge-flatten-variants';
|
|
53
53
|
import {
|
|
54
|
-
|
|
54
|
+
colorsAndTypeMigration_2026_05_26_dropOverlayExtraStops,
|
|
55
55
|
componentMigration_2026_05_26_dropOverlayExtraStops,
|
|
56
56
|
} from './2026-05-26-drop-overlay-extra-stops';
|
|
57
57
|
import { componentMigration_2026_05_29_tabbarIndicatorThicknessToPerStateWidth } from './2026-05-29-tabbar-indicator-thickness-to-per-state-width';
|
|
58
58
|
import { componentMigration_2026_05_29_segmentedcontrolSmallDividerRename } from './2026-05-29-segmentedcontrol-small-divider-rename';
|
|
59
59
|
import { componentMigration_2026_05_29_toggleDeriveTrackFromThumb } from './2026-05-29-toggle-derive-track-from-thumb';
|
|
60
|
+
import { colorsAndTypeMigration_2026_08_13_dropLegacyShapeSpaceKeys } from './2026-08-13-drop-legacy-shape-space-keys';
|
|
61
|
+
import {
|
|
62
|
+
colorsAndTypeMigration_2026_08_15_lineHeightScaleRename,
|
|
63
|
+
componentMigration_2026_08_15_lineHeightScaleRename,
|
|
64
|
+
} from './2026-08-15-line-height-scale-rename';
|
|
60
65
|
|
|
61
66
|
/**
|
|
62
67
|
* Registered migrations. Order in this array does not matter — the runner
|
|
63
68
|
* filters by `appliesTo` and sorts by `toVersion` before applying.
|
|
64
69
|
*/
|
|
65
70
|
export const MIGRATIONS: Migration[] = [
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
colorsAndTypeMigration_2026_04_24_legacyKeysAndBgToCanvas,
|
|
72
|
+
colorsAndTypeMigration_2026_05_13_primaryToBrand,
|
|
68
73
|
componentMigration_2026_04_24_prefixAndSuffixRenames,
|
|
69
74
|
componentMigration_2026_04_27_segmentedcontrolDisabledFlatten,
|
|
70
75
|
componentMigration_2026_05_08_collapsiblesectionVariantNamespace,
|
|
@@ -81,14 +86,17 @@ export const MIGRATIONS: Migration[] = [
|
|
|
81
86
|
componentMigration_2026_05_24_progressbarCollapseVariants,
|
|
82
87
|
componentMigration_2026_05_24_collapsiblesectionDropActiveState,
|
|
83
88
|
componentMigration_2026_05_25_cornerbadgeFlattenVariants,
|
|
84
|
-
|
|
89
|
+
colorsAndTypeMigration_2026_05_26_dropOverlayExtraStops,
|
|
85
90
|
componentMigration_2026_05_26_dropOverlayExtraStops,
|
|
86
91
|
componentMigration_2026_05_29_tabbarIndicatorThicknessToPerStateWidth,
|
|
87
92
|
componentMigration_2026_05_29_segmentedcontrolSmallDividerRename,
|
|
88
93
|
componentMigration_2026_05_29_toggleDeriveTrackFromThumb,
|
|
94
|
+
colorsAndTypeMigration_2026_08_13_dropLegacyShapeSpaceKeys,
|
|
95
|
+
colorsAndTypeMigration_2026_08_15_lineHeightScaleRename,
|
|
96
|
+
componentMigration_2026_08_15_lineHeightScaleRename,
|
|
89
97
|
];
|
|
90
98
|
|
|
91
|
-
function countFor(kind: '
|
|
99
|
+
function countFor(kind: 'colors-and-type' | 'component-config'): number {
|
|
92
100
|
return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
|
|
93
101
|
}
|
|
94
102
|
|
|
@@ -97,7 +105,7 @@ function countFor(kind: 'theme' | 'component-config'): number {
|
|
|
97
105
|
* adding a new dated migration file (and importing it above) auto-bumps the
|
|
98
106
|
* relevant constant.
|
|
99
107
|
*/
|
|
100
|
-
export const
|
|
108
|
+
export const CURRENT_COLORS_AND_TYPE_SCHEMA_VERSION = countFor('colors-and-type');
|
|
101
109
|
export const CURRENT_COMPONENT_SCHEMA_VERSION = countFor('component-config');
|
|
102
110
|
|
|
103
111
|
/**
|
|
@@ -109,7 +117,7 @@ export const CURRENT_COMPONENT_SCHEMA_VERSION = countFor('component-config');
|
|
|
109
117
|
* fromVersion=N can be deleted without affecting any load path.
|
|
110
118
|
*/
|
|
111
119
|
export function runMigrations(
|
|
112
|
-
kind: '
|
|
120
|
+
kind: 'colors-and-type' | 'component-config',
|
|
113
121
|
fileVersion: number,
|
|
114
122
|
rawVars: Record<string, string>,
|
|
115
123
|
meta: MigrationMeta = {},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Components slice — per-component `{
|
|
2
|
+
* Components slice — per-component `{ aliases, config, unlinked? }`.
|
|
3
3
|
*
|
|
4
4
|
* `aliases` are the typed component-token → semantic-token map (each entry is
|
|
5
5
|
* a `CssVarRef` discriminated union: `{ kind: 'token', name }` or
|
|
@@ -106,7 +106,7 @@ export function setComponentAlias(component: string, varName: string, ref: CssVa
|
|
|
106
106
|
if (existing) {
|
|
107
107
|
existing.aliases[varName] = ref;
|
|
108
108
|
} else {
|
|
109
|
-
s.components[component] = {
|
|
109
|
+
s.components[component] = { aliases: { [varName]: ref }, config: {} };
|
|
110
110
|
}
|
|
111
111
|
});
|
|
112
112
|
}
|
|
@@ -125,7 +125,7 @@ export function setComponentConfig(component: string, key: string, value: unknow
|
|
|
125
125
|
if (existing) {
|
|
126
126
|
existing.config[key] = value;
|
|
127
127
|
} else {
|
|
128
|
-
s.components[component] = {
|
|
128
|
+
s.components[component] = { aliases: {}, config: { [key]: value } };
|
|
129
129
|
}
|
|
130
130
|
});
|
|
131
131
|
}
|
|
@@ -272,7 +272,7 @@ export function setComponentAliasLinked(component: string, varName: string, ref:
|
|
|
272
272
|
return;
|
|
273
273
|
}
|
|
274
274
|
mutate(`link ${component}/${groupKey}`, (s) => {
|
|
275
|
-
const slice = s.components[component] ?? (s.components[component] = {
|
|
275
|
+
const slice = s.components[component] ?? (s.components[component] = { aliases: {}, config: {} });
|
|
276
276
|
const unlinked = (slice.unlinked ?? []).filter((p) => p !== varName);
|
|
277
277
|
slice.aliases[varName] = ref;
|
|
278
278
|
for (const v of siblings) {
|
|
@@ -20,7 +20,7 @@ export function setFontStacks(stacks: FontStack[]): void {
|
|
|
20
20
|
* Populate fonts from the server's active theme at boot. Does not push
|
|
21
21
|
* a history entry — the boot load is a starting point, not an edit.
|
|
22
22
|
*/
|
|
23
|
-
export function
|
|
23
|
+
export function seedFontsFromColorsAndType(sources: FontSource[], stacks: FontStack[]): void {
|
|
24
24
|
store.update((s) => {
|
|
25
25
|
s.fonts.sources = structuredClone(sources);
|
|
26
26
|
s.fonts.stacks = structuredClone(stacks);
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* edits flow through.
|
|
6
6
|
*/
|
|
7
7
|
import type { EditorState, GradientToken, GradientTokenStop, GradientType, GradientAliasValue } from '../../store/editorTypes';
|
|
8
|
+
import type { GradientDiskToken } from '../themeTypes';
|
|
8
9
|
import { mutate } from '../../store/editorCore';
|
|
9
10
|
|
|
10
11
|
export function makeDefaultGradients(): GradientToken[] {
|
|
@@ -48,6 +49,27 @@ export function makeDefaultGradients(): GradientToken[] {
|
|
|
48
49
|
];
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Loader: restore the gradient library from a file's structured `gradients`
|
|
54
|
+
* field and scrub the rendered `--gradient-N` strings from the vars bag — they
|
|
55
|
+
* are a projection kept for production CSS, never a basis. Files without the
|
|
56
|
+
* field (saved before gradients round-tripped) keep the seeded defaults, which
|
|
57
|
+
* match what those files rendered. A file whose slots don't match the fixed
|
|
58
|
+
* four is stale-shaped and also keeps defaults, mirroring the persistence
|
|
59
|
+
* layer's `migrateGradients` guard.
|
|
60
|
+
*/
|
|
61
|
+
export function loadGradientsFromFile(
|
|
62
|
+
next: EditorState,
|
|
63
|
+
gradients: GradientDiskToken[] | undefined,
|
|
64
|
+
rawVars: Record<string, string>,
|
|
65
|
+
): void {
|
|
66
|
+
const expected = makeDefaultGradients().map((g) => g.variable).sort();
|
|
67
|
+
for (const name of expected) delete rawVars[name];
|
|
68
|
+
const have = (gradients ?? []).map((g) => g.variable).sort();
|
|
69
|
+
const matches = have.length === expected.length && expected.every((v, i) => v === have[i]);
|
|
70
|
+
if (matches) next.gradients.tokens = structuredClone(gradients) as GradientToken[];
|
|
71
|
+
}
|
|
72
|
+
|
|
51
73
|
function formatGradientStop(s: GradientTokenStop): string {
|
|
52
74
|
return `${formatGradientStopColor(s)} ${s.position}%`;
|
|
53
75
|
}
|
|
@@ -15,9 +15,9 @@ export function setPaletteConfig(label: string, config: PaletteConfig): void {
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Server-boot path: populate all palettes at once without a history entry.
|
|
18
|
-
* Mirrors `
|
|
18
|
+
* Mirrors `seedFontsFromColorsAndType`.
|
|
19
19
|
*/
|
|
20
|
-
export function
|
|
20
|
+
export function seedPalettesFromColorsAndType(palettes: Record<string, PaletteConfig>): void {
|
|
21
21
|
store.update((s) => {
|
|
22
22
|
s.palettes = structuredClone(palettes);
|
|
23
23
|
return s;
|
|
@@ -1,31 +1,25 @@
|
|
|
1
|
-
import type { AliasDiskValue,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import type { AliasDiskValue, ColorsAndType } from './themeTypes';
|
|
2
|
+
import { openThemeSlug } from '../store/editorConfigStore';
|
|
3
|
+
import { migrateColorsAndTypeFonts } from '../fonts/fontMigration';
|
|
4
4
|
import { applyFontSources, applyFontStacks } from '../fonts/fontLoader';
|
|
5
5
|
import { loadFromFile, seedComponentsFromApi } from '../store/editorStore';
|
|
6
|
-
import { getActiveComponentConfig } from '../components/componentConfigService';
|
|
6
|
+
import { getActiveComponentConfig, type ComponentSummary } from '../components/componentConfigService';
|
|
7
7
|
import { safeFetch } from '../storage/storage';
|
|
8
8
|
import { API_BASE } from '../storage/apiBase';
|
|
9
9
|
|
|
10
|
-
interface ComponentSummaryDto {
|
|
11
|
-
name: string;
|
|
12
|
-
activeFile: string;
|
|
13
|
-
productionFile: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
10
|
interface ListComponentsDto {
|
|
17
|
-
components:
|
|
11
|
+
components: ComponentSummary[];
|
|
18
12
|
}
|
|
19
13
|
|
|
20
14
|
/**
|
|
21
|
-
* Fetch the
|
|
22
|
-
* to :root before the app mounts. Seeds the editor store so
|
|
23
|
-
* initialize from the
|
|
15
|
+
* Fetch the live colors and type from the server and apply their CSS
|
|
16
|
+
* variables to :root before the app mounts. Seeds the editor store so
|
|
17
|
+
* PaletteEditors initialize from the server state instead of stale localStorage.
|
|
24
18
|
*
|
|
25
|
-
* Routes the
|
|
19
|
+
* Routes the payload through `loadFromFile` so palette-derived vars in
|
|
26
20
|
* `deriveCssVars` correctly overwrite any stale hexes baked into
|
|
27
|
-
* `
|
|
28
|
-
* `
|
|
21
|
+
* `cssVariables` by `handleSave`'s scrape. Writing
|
|
22
|
+
* `cssVariables` directly to inline :root (the previous approach)
|
|
29
23
|
* bypassed the store and left the subscriber's `lastApplied` diff cache
|
|
30
24
|
* out of sync, so palette-derived values stayed stale until a
|
|
31
25
|
* `PaletteEditor` mounted and re-emitted them.
|
|
@@ -35,32 +29,30 @@ interface ListComponentsDto {
|
|
|
35
29
|
* `safeFetch` (instead of empty try/catch) to make the silence intentional.
|
|
36
30
|
*/
|
|
37
31
|
export async function initializeTheme(): Promise<void> {
|
|
38
|
-
const
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
loadFromFile(
|
|
42
|
-
if (
|
|
43
|
-
applyFontSources(
|
|
32
|
+
const colorsAndType = await safeFetch<ColorsAndType>(`${API_BASE}/colors-and-type/active`);
|
|
33
|
+
if (colorsAndType) {
|
|
34
|
+
migrateColorsAndTypeFonts(colorsAndType);
|
|
35
|
+
loadFromFile(colorsAndType);
|
|
36
|
+
if (colorsAndType.fontSources && colorsAndType.fontSources.length > 0) {
|
|
37
|
+
applyFontSources(colorsAndType.fontSources);
|
|
44
38
|
}
|
|
45
|
-
if (
|
|
46
|
-
applyFontStacks(
|
|
39
|
+
if (colorsAndType.fontStacks && colorsAndType.fontStacks.length > 0) {
|
|
40
|
+
applyFontStacks(colorsAndType.fontStacks, colorsAndType.fontSources ?? []);
|
|
47
41
|
}
|
|
48
|
-
|
|
49
|
-
activeFileName.set(fileName);
|
|
42
|
+
openThemeSlug.set(colorsAndType._fileName || 'default');
|
|
50
43
|
}
|
|
51
44
|
|
|
52
45
|
const list = await safeFetch<ListComponentsDto>(`${API_BASE}/component-configs`);
|
|
53
46
|
if (list && Array.isArray(list.components)) {
|
|
54
47
|
const configs: Record<
|
|
55
48
|
string,
|
|
56
|
-
{
|
|
49
|
+
{ aliases: Record<string, AliasDiskValue>; config?: Record<string, unknown>; schemaVersion?: number }
|
|
57
50
|
> = {};
|
|
58
51
|
await Promise.all(
|
|
59
52
|
list.components.map(async (c) => {
|
|
60
53
|
const cfg = await getActiveComponentConfig(c.name);
|
|
61
54
|
if (cfg) {
|
|
62
55
|
configs[c.name] = {
|
|
63
|
-
activeFile: c.activeFile,
|
|
64
56
|
aliases: cfg.aliases,
|
|
65
57
|
config: cfg.config,
|
|
66
58
|
schemaVersion: cfg.schemaVersion,
|