@motion-proto/live-tokens 0.6.2 → 0.8.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/README.md +14 -13
- package/dist-plugin/index.cjs +854 -226
- package/dist-plugin/index.d.cts +2 -1
- package/dist-plugin/index.d.ts +2 -1
- package/dist-plugin/index.js +852 -225
- package/package.json +26 -40
- package/src/{styles → app}/site.css +1 -1
- package/src/{component-editor → editor/component-editor}/BadgeEditor.svelte +8 -82
- package/src/{component-editor → editor/component-editor}/CalloutEditor.svelte +4 -4
- package/src/{component-editor → editor/component-editor}/CardEditor.svelte +28 -76
- package/src/{component-editor → editor/component-editor}/CollapsibleSectionEditor.svelte +37 -30
- package/src/{component-editor → editor/component-editor}/CornerBadgeEditor.svelte +31 -93
- package/src/{component-editor → editor/component-editor}/DialogEditor.svelte +60 -57
- package/src/editor/component-editor/ImageEditor.svelte +30 -0
- package/src/{component-editor → editor/component-editor}/InlineEditActionsEditor.svelte +6 -4
- package/src/editor/component-editor/MenuSelectEditor.svelte +160 -0
- package/src/{component-editor → editor/component-editor}/NotificationEditor.svelte +67 -38
- package/src/{component-editor → editor/component-editor}/ProgressBarEditor.svelte +5 -4
- package/src/{component-editor → editor/component-editor}/RadioButtonEditor.svelte +3 -3
- package/src/editor/component-editor/SectionDividerEditor.svelte +565 -0
- package/src/{component-editor → editor/component-editor}/SegmentedControlEditor.svelte +2 -2
- package/src/{component-editor → editor/component-editor}/StandardButtonsEditor.svelte +29 -21
- package/src/{component-editor → editor/component-editor}/TabBarEditor.svelte +9 -14
- package/src/{component-editor → editor/component-editor}/TableEditor.svelte +9 -18
- package/src/{component-editor → editor/component-editor}/TooltipEditor.svelte +11 -47
- package/src/editor/component-editor/editors.d.ts +10 -0
- package/src/{component-editor → editor/component-editor}/registry.ts +28 -18
- package/src/{component-editor → editor/component-editor}/scaffolding/AngleDial.svelte +54 -15
- package/src/{component-editor → editor/component-editor}/scaffolding/ComponentEditorBase.svelte +3 -51
- package/src/{component-editor → editor/component-editor}/scaffolding/ComponentFileManager.svelte +151 -424
- package/src/{component-editor → editor/component-editor}/scaffolding/ComponentFileMenu.svelte +18 -170
- package/src/{component-editor → editor/component-editor}/scaffolding/ComponentsTab.svelte +2 -2
- package/src/{component-editor → editor/component-editor}/scaffolding/CopyFromMenu.svelte +44 -4
- package/src/{component-editor → editor/component-editor}/scaffolding/FieldsetWrapper.svelte +1 -1
- package/src/{component-editor → editor/component-editor}/scaffolding/LinkageChart.svelte +6 -6
- package/src/{component-editor → editor/component-editor}/scaffolding/LinkedBlock.svelte +6 -12
- package/src/editor/component-editor/scaffolding/NonStylableConfig.svelte +38 -0
- package/src/editor/component-editor/scaffolding/RadialShapePad.svelte +483 -0
- package/src/{component-editor → editor/component-editor}/scaffolding/SaveAsDialog.svelte +66 -12
- package/src/editor/component-editor/scaffolding/ShadowBackdrop.svelte +85 -0
- package/src/editor/component-editor/scaffolding/ShadowBackdropControls.svelte +132 -0
- package/src/editor/component-editor/scaffolding/StateBlock.svelte +345 -0
- package/src/{component-editor → editor/component-editor}/scaffolding/TokenLayout.svelte +17 -12
- package/src/{component-editor → editor/component-editor}/scaffolding/TypeEditor.svelte +13 -1
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +858 -0
- package/src/{component-editor → editor/component-editor}/scaffolding/buildTypeGroupTokens.ts +1 -0
- package/src/{component-editor → editor/component-editor}/scaffolding/editorContext.ts +19 -9
- package/src/{component-editor → editor/component-editor}/scaffolding/linkedBlock.ts +2 -2
- package/src/{component-editor → editor/component-editor}/scaffolding/types.ts +25 -0
- package/src/{lib → editor/core/components}/componentConfigKeys.ts +8 -0
- package/src/{lib → editor/core/components}/componentConfigService.ts +3 -3
- package/src/{lib → editor/core/components}/componentPersist.ts +11 -9
- package/src/editor/core/flashStatus.ts +30 -0
- package/src/{lib → editor/core/fonts}/fontLoader.ts +2 -2
- package/src/{lib → editor/core/fonts}/fontMigration.ts +4 -4
- package/src/{lib → editor/core/fonts}/fontParse.ts +1 -1
- package/src/editor/core/manifests/manifestService.ts +171 -0
- package/src/editor/core/palettes/familySwap.ts +99 -0
- package/src/{lib → editor/core/palettes}/paletteDerivation.ts +71 -2
- package/src/{lib → editor/core/palettes}/tokenRegistry.ts +9 -6
- package/src/editor/core/productionPulse.ts +37 -0
- package/src/{lib → editor/core/routing}/router.ts +1 -1
- package/src/{lib/files/versionedFileResource.ts → editor/core/storage/files/versionedFileResourceClient.ts} +8 -1
- package/src/{lib → editor/core/store}/editorCore.ts +24 -8
- package/src/{lib → editor/core/store}/editorPersistence.ts +3 -3
- package/src/{lib → editor/core/store}/editorRenderer.ts +2 -2
- package/src/{lib → editor/core/store}/editorStore.ts +222 -28
- package/src/{lib → editor/core/store}/editorTypes.ts +56 -13
- 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/{lib → editor/core/themes}/migrations/index.ts +10 -0
- package/src/{lib → editor/core/themes}/slices/columns.ts +2 -2
- package/src/{lib → editor/core/themes}/slices/components.ts +20 -6
- package/src/{lib → editor/core/themes}/slices/fonts.ts +1 -1
- package/src/{lib → editor/core/themes}/slices/gradients.ts +89 -14
- package/src/{lib → editor/core/themes}/slices/overlays.ts +1 -1
- package/src/{lib → editor/core/themes}/slices/palettes.ts +1 -1
- package/src/{lib → editor/core/themes}/slices/shadows.ts +3 -3
- package/src/{lib → editor/core/themes}/themeInit.ts +8 -8
- package/src/{lib → editor/core/themes}/themeService.ts +6 -6
- package/src/{lib → editor/core/themes}/themeTypes.ts +67 -8
- package/src/editor/index.ts +69 -0
- package/src/{lib → editor/overlay}/ColumnsOverlay.svelte +0 -1
- package/src/{lib → editor/overlay}/LiveEditorOverlay.svelte +80 -129
- package/src/{lib → editor/overlay}/columnsOverlay.ts +2 -2
- package/src/{pages → editor/pages}/ComponentEditorPage.svelte +12 -12
- package/src/{pages → editor/pages}/Editor.svelte +4 -4
- package/src/{pages → editor/pages}/EditorShell.svelte +18 -36
- package/src/{styles → editor/styles}/ui-editor.css +43 -22
- package/src/{styles → editor/styles}/ui-form-controls.css +23 -24
- package/src/{ui → editor/ui}/BezierCurveEditor.svelte +119 -68
- package/src/{ui → editor/ui}/ColorEditPanel.svelte +13 -13
- package/src/{ui → editor/ui}/EditorViewSwitcher.svelte +7 -6
- package/src/editor/ui/FileLoadList.svelte +367 -0
- package/src/editor/ui/FilePill.svelte +80 -0
- package/src/editor/ui/FontStackEditor.svelte +499 -0
- package/src/editor/ui/GradientEditor.svelte +690 -0
- package/src/{ui → editor/ui}/GradientStopPicker.svelte +12 -4
- package/src/editor/ui/ManifestFileManager.svelte +438 -0
- package/src/{ui → editor/ui}/PaletteEditor.svelte +180 -673
- package/src/editor/ui/ProjectFontsSection.svelte +638 -0
- package/src/{ui → editor/ui}/SurfacesTab.svelte +3 -3
- package/src/{ui → editor/ui}/TextTab.svelte +3 -3
- package/src/editor/ui/ThemeFileManager.svelte +783 -0
- package/src/{ui → editor/ui}/UICopyPopover.svelte +4 -4
- package/src/{ui → editor/ui}/UIFontFamilySelector.svelte +6 -7
- package/src/{ui → editor/ui}/UIFontSizeSelector.svelte +4 -1
- package/src/editor/ui/UIInfoPopover.svelte +243 -0
- package/src/editor/ui/UILetterSpacingSelector.svelte +65 -0
- package/src/{ui → editor/ui}/UILineHeightSelector.svelte +5 -5
- package/src/{ui → editor/ui}/UILinkToggle.svelte +2 -2
- package/src/{ui → editor/ui}/UIPaddingSelector.svelte +6 -6
- package/src/{ui → editor/ui}/UIPaletteSelector.svelte +57 -30
- package/src/editor/ui/UIPillButton.svelte +168 -0
- package/src/{ui → editor/ui}/UIRadio.svelte +2 -2
- package/src/{ui → editor/ui}/UIRelinkConfirmPopover.svelte +4 -4
- package/src/editor/ui/UISegmentedControl.svelte +114 -0
- package/src/editor/ui/UISquareButton.svelte +172 -0
- package/src/{ui → editor/ui}/UITokenSelector.svelte +14 -11
- package/src/{ui → editor/ui}/UIVariantSelector.svelte +1 -1
- package/src/{ui → editor/ui}/VariablesTab.svelte +46 -17
- package/src/{ui → editor/ui}/palette/GradientStopEditor.svelte +13 -13
- package/src/{ui → editor/ui}/palette/OverridesPanel.svelte +24 -47
- package/src/{ui → editor/ui}/palette/PaletteBase.svelte +11 -8
- package/src/{ui → editor/ui}/palette/paletteEditorState.ts +1 -1
- package/src/editor/ui/palette/paletteMath.ts +275 -0
- package/src/{ui → editor/ui}/sections/ColumnsSection.svelte +137 -18
- package/src/{ui → editor/ui}/sections/GradientsSection.svelte +8 -8
- package/src/{ui → editor/ui}/sections/OverlaysSection.svelte +18 -18
- package/src/{ui → editor/ui}/sections/ShadowsSection.svelte +23 -23
- package/src/{ui → editor/ui}/sections/TokenScaleTable.svelte +3 -3
- package/src/{components → system/components}/Badge.svelte +0 -36
- package/src/{components → system/components}/Button.svelte +2 -2
- package/src/{components → system/components}/Card.svelte +34 -60
- package/src/{components → system/components}/CollapsibleSection.svelte +25 -2
- package/src/{components → system/components}/CornerBadge.svelte +8 -24
- package/src/{components → system/components}/Dialog.svelte +1 -1
- package/src/system/components/FloatingTokenTags.css +275 -0
- package/src/system/components/FloatingTokenTags.svelte +543 -0
- package/src/{components → system/components}/InlineEditActions.svelte +6 -4
- package/src/system/components/MenuSelect.svelte +229 -0
- package/src/{components → system/components}/Notification.svelte +8 -1
- package/src/{components → system/components}/ProgressBar.svelte +29 -11
- package/src/system/components/SectionDivider.svelte +560 -0
- package/src/{components → system/components}/SegmentedControl.svelte +49 -43
- package/src/{components → system/components}/TabBar.svelte +81 -65
- package/src/{components → system/components}/Table.svelte +17 -3
- package/src/{components → system/components}/Tooltip.svelte +6 -4
- package/src/system/styles/CONVENTIONS.md +178 -0
- package/src/system/styles/fonts.css +20 -0
- package/src/system/styles/tokens.css +601 -0
- package/src/system/styles/tokens.generated.css +544 -0
- package/src/component-editor/ImageEditor.svelte +0 -74
- package/src/component-editor/SectionDividerEditor.svelte +0 -265
- package/src/component-editor/scaffolding/DividerEditor.svelte +0 -94
- package/src/component-editor/scaffolding/GradientCard.svelte +0 -296
- package/src/component-editor/scaffolding/NonStylableConfig.svelte +0 -62
- package/src/component-editor/scaffolding/ShadowBackdrop.svelte +0 -37
- package/src/component-editor/scaffolding/ShadowBackdropControls.svelte +0 -61
- package/src/component-editor/scaffolding/StateBlock.svelte +0 -132
- package/src/component-editor/scaffolding/VariantGroup.svelte +0 -310
- package/src/components/SectionDivider.svelte +0 -483
- package/src/data/google-fonts.json +0 -75
- package/src/lib/index.ts +0 -68
- package/src/lib/presetService.ts +0 -214
- package/src/lib/productionPulse.ts +0 -32
- package/src/styles/fonts.css +0 -30
- package/src/styles/tokens.css +0 -1324
- package/src/ui/FontStackEditor.svelte +0 -361
- package/src/ui/GradientEditor.svelte +0 -470
- package/src/ui/PresetFileManager.svelte +0 -1116
- package/src/ui/ProjectFontsSection.svelte +0 -645
- package/src/ui/ThemeFileManager.svelte +0 -1020
- package/src/ui/UnsavedComponentsDialog.svelte +0 -315
- /package/src/{component-editor → editor/component-editor}/index.ts +0 -0
- /package/src/{component-editor → editor/component-editor}/scaffolding/DemoHeader.svelte +0 -0
- /package/src/{component-editor → editor/component-editor}/scaffolding/componentSectionType.ts +0 -0
- /package/src/{component-editor → editor/component-editor}/scaffolding/componentSources.ts +0 -0
- /package/src/{component-editor → editor/component-editor}/scaffolding/defaultSections.ts +0 -0
- /package/src/{component-editor → editor/component-editor}/scaffolding/siblings.ts +0 -0
- /package/src/{lib → editor/core}/cssVarSync.ts +0 -0
- /package/src/{lib → editor/core/palettes}/oklch.ts +0 -0
- /package/src/{lib → editor/core/routing}/navLinkTypes.ts +0 -0
- /package/src/{lib → editor/core/routing}/parentRouteStore.ts +0 -0
- /package/src/{lib → editor/core/storage}/storage.ts +0 -0
- /package/src/{lib → editor/core/store}/editorConfig.ts +0 -0
- /package/src/{lib → editor/core/store}/editorConfigStore.ts +0 -0
- /package/src/{lib → editor/core/store}/editorKeybindings.ts +0 -0
- /package/src/{lib → editor/core/store}/editorViewStore.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-04-24-component-prefix-and-suffix-renames.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-04-24-legacy-keys-and-bg-to-canvas.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-04-27-segmentedcontrol-disabled-flatten.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-05-08-collapsiblesection-frame-and-cleanup.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-05-08-collapsiblesection-variant-namespace.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-05-10-sectiondivider-gradient-stops.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-05-13-primary-to-brand.ts +0 -0
- /package/src/{lib → editor/core/themes}/parsers/globalRootBlock.ts +0 -0
- /package/src/{lib → editor/core/themes}/slices/domainVars.ts +0 -0
- /package/src/{lib → editor/overlay}/overlayState.ts +0 -0
- /package/src/{pages → editor/pages}/ComponentEditorPage.svelte.d.ts +0 -0
- /package/src/{pages → editor/pages}/Editor.svelte.d.ts +0 -0
- /package/src/{ui → editor/ui}/Toggle.svelte +0 -0
- /package/src/{ui → editor/ui}/UIDialog.svelte +0 -0
- /package/src/{ui → editor/ui}/UIFontWeightSelector.svelte +0 -0
- /package/src/{ui → editor/ui}/UIOptionItem.svelte +0 -0
- /package/src/{ui → editor/ui}/UIOptionList.svelte +0 -0
- /package/src/{ui → editor/ui}/UIRadioGroup.svelte +0 -0
- /package/src/{lib → editor/ui}/copyPopover.ts +0 -0
- /package/src/{ui → editor/ui}/curveEngine.ts +0 -0
- /package/src/{ui → editor/ui}/index.ts +0 -0
- /package/src/{ui → editor/ui}/keepInViewport.ts +0 -0
- /package/src/{ui → editor/ui}/palette/ScaleCurveEditor.svelte +0 -0
- /package/src/{lib → editor/ui}/scrollSection.ts +0 -0
- /package/src/{ui → editor/ui}/sections/tokenScales.ts +0 -0
- /package/src/{ui → editor/ui}/variantScales.ts +0 -0
- /package/src/{assets → system/assets}/newspaper.webp +0 -0
- /package/src/{assets → system/assets}/offering.webp +0 -0
- /package/src/{components → system/components}/Callout.svelte +0 -0
- /package/src/{components → system/components}/Image.svelte +0 -0
- /package/src/{components → system/components}/RadioButton.svelte +0 -0
- /package/src/{components → system/components}/types.ts +0 -0
- /package/src/{styles → system/styles}/_padding.scss +0 -0
- /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-italic-latin-ext.woff2 +0 -0
- /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-italic-latin.woff2 +0 -0
- /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-roman-latin-ext.woff2 +0 -0
- /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-roman-latin.woff2 +0 -0
- /package/src/{styles → system/styles}/fonts/Manrope/Manrope-latin-ext.woff2 +0 -0
- /package/src/{styles → system/styles}/fonts/Manrope/Manrope-latin.woff2 +0 -0
package/dist-plugin/index.cjs
CHANGED
|
@@ -27,18 +27,18 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
));
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
|
|
30
|
-
//
|
|
30
|
+
// vite-plugin/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
themeFileApi: () => themeFileApi
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
|
-
//
|
|
37
|
+
// vite-plugin/themeFileApi.ts
|
|
38
38
|
var import_fs2 = __toESM(require("fs"), 1);
|
|
39
39
|
var import_path2 = __toESM(require("path"), 1);
|
|
40
40
|
|
|
41
|
-
// src/
|
|
41
|
+
// src/editor/core/themes/parsers/globalRootBlock.ts
|
|
42
42
|
function extractGlobalRootBody(source) {
|
|
43
43
|
const re = /:global\(:root\)\s*\{([^}]*)\}/g;
|
|
44
44
|
const bodies = [];
|
|
@@ -49,12 +49,416 @@ function extractGlobalRootBody(source) {
|
|
|
49
49
|
return bodies.join("\n");
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
// src/
|
|
52
|
+
// src/editor/core/storage/files/versionedFileResourceClient.ts
|
|
53
53
|
function sanitizeFileName(name) {
|
|
54
54
|
return name.toLowerCase().trim().replace(/\s+/g, "-").replace(/[^a-z0-9\-_]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "") || "unnamed";
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
// src/
|
|
57
|
+
// src/editor/core/palettes/oklch.ts
|
|
58
|
+
function srgbToLinear(c) {
|
|
59
|
+
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
60
|
+
}
|
|
61
|
+
function linearToSrgb(c) {
|
|
62
|
+
return c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
|
|
63
|
+
}
|
|
64
|
+
function hexToLinearRgb(hex) {
|
|
65
|
+
const r = parseInt(hex.slice(1, 3), 16) / 255;
|
|
66
|
+
const g = parseInt(hex.slice(3, 5), 16) / 255;
|
|
67
|
+
const b = parseInt(hex.slice(5, 7), 16) / 255;
|
|
68
|
+
return [srgbToLinear(r), srgbToLinear(g), srgbToLinear(b)];
|
|
69
|
+
}
|
|
70
|
+
function linearRgbToHex(r, g, b) {
|
|
71
|
+
const toHex = (c) => {
|
|
72
|
+
const v = Math.round(Math.max(0, Math.min(1, linearToSrgb(c))) * 255);
|
|
73
|
+
return v.toString(16).padStart(2, "0");
|
|
74
|
+
};
|
|
75
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
76
|
+
}
|
|
77
|
+
function linearRgbToOklab(r, g, b) {
|
|
78
|
+
const l_ = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
|
|
79
|
+
const m_ = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
|
|
80
|
+
const s_ = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
|
|
81
|
+
const l = Math.cbrt(l_);
|
|
82
|
+
const m = Math.cbrt(m_);
|
|
83
|
+
const s = Math.cbrt(s_);
|
|
84
|
+
return [
|
|
85
|
+
0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
|
|
86
|
+
1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
|
|
87
|
+
0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s
|
|
88
|
+
];
|
|
89
|
+
}
|
|
90
|
+
function oklabToLinearRgb(L, a, b) {
|
|
91
|
+
const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
|
|
92
|
+
const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
|
|
93
|
+
const s_ = L - 0.0894841775 * a - 1.291485548 * b;
|
|
94
|
+
const l = l_ * l_ * l_;
|
|
95
|
+
const m = m_ * m_ * m_;
|
|
96
|
+
const s = s_ * s_ * s_;
|
|
97
|
+
return [
|
|
98
|
+
4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
|
|
99
|
+
-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
|
|
100
|
+
-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s
|
|
101
|
+
];
|
|
102
|
+
}
|
|
103
|
+
function oklabToOklch(L, a, b) {
|
|
104
|
+
const c = Math.sqrt(a * a + b * b);
|
|
105
|
+
let h = Math.atan2(b, a) * 180 / Math.PI;
|
|
106
|
+
if (h < 0) h += 360;
|
|
107
|
+
return { l: L, c, h };
|
|
108
|
+
}
|
|
109
|
+
function oklchToOklab(l, c, h) {
|
|
110
|
+
const hRad = h * Math.PI / 180;
|
|
111
|
+
return [l, c * Math.cos(hRad), c * Math.sin(hRad)];
|
|
112
|
+
}
|
|
113
|
+
function hexToOklch(hex) {
|
|
114
|
+
const [r, g, b] = hexToLinearRgb(hex);
|
|
115
|
+
const [L, a, bVal] = linearRgbToOklab(r, g, b);
|
|
116
|
+
return oklabToOklch(L, a, bVal);
|
|
117
|
+
}
|
|
118
|
+
function oklchToHex(l, c, h) {
|
|
119
|
+
const [L, a, b] = oklchToOklab(l, c, h);
|
|
120
|
+
const [r, g, bVal] = oklabToLinearRgb(L, a, b);
|
|
121
|
+
return linearRgbToHex(r, g, bVal);
|
|
122
|
+
}
|
|
123
|
+
function isInGamut(r, g, b) {
|
|
124
|
+
const eps = 1e-4;
|
|
125
|
+
return r >= -eps && r <= 1 + eps && g >= -eps && g <= 1 + eps && b >= -eps && b <= 1 + eps;
|
|
126
|
+
}
|
|
127
|
+
function gamutClamp(l, c, h) {
|
|
128
|
+
if (l <= 0) return { l: 0, c: 0, h };
|
|
129
|
+
if (l >= 1) return { l: 1, c: 0, h };
|
|
130
|
+
const [L, a, b] = oklchToOklab(l, c, h);
|
|
131
|
+
const [r, g, bVal] = oklabToLinearRgb(L, a, b);
|
|
132
|
+
if (isInGamut(r, g, bVal)) return { l, c, h };
|
|
133
|
+
let lo = 0;
|
|
134
|
+
let hi = c;
|
|
135
|
+
for (let i = 0; i < 20; i++) {
|
|
136
|
+
const mid = (lo + hi) / 2;
|
|
137
|
+
const [La, aa, ba] = oklchToOklab(l, mid, h);
|
|
138
|
+
const [rr, gg, bb] = oklabToLinearRgb(La, aa, ba);
|
|
139
|
+
if (isInGamut(rr, gg, bb)) {
|
|
140
|
+
lo = mid;
|
|
141
|
+
} else {
|
|
142
|
+
hi = mid;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return { l, c: lo, h };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// src/editor/ui/curveEngine.ts
|
|
149
|
+
function makeAnchor(x, y, tangentLen = 15) {
|
|
150
|
+
return { x, y, inDx: -tangentLen, inDy: 0, outDx: tangentLen, outDy: 0 };
|
|
151
|
+
}
|
|
152
|
+
function evalBezier(p0x, p0y, c0x, c0y, c1x, c1y, p1x, p1y, t) {
|
|
153
|
+
const u = 1 - t, u2 = u * u, u3 = u2 * u;
|
|
154
|
+
const t2 = t * t, t3 = t2 * t;
|
|
155
|
+
return {
|
|
156
|
+
x: u3 * p0x + 3 * u2 * t * c0x + 3 * u * t2 * c1x + t3 * p1x,
|
|
157
|
+
y: u3 * p0y + 3 * u2 * t * c0y + 3 * u * t2 * c1y + t3 * p1y
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function sampleCurve(anchors, xPos) {
|
|
161
|
+
if (anchors.length === 0) return 0;
|
|
162
|
+
if (anchors.length === 1) return anchors[0].y;
|
|
163
|
+
if (xPos <= anchors[0].x) return anchors[0].y;
|
|
164
|
+
if (xPos >= anchors[anchors.length - 1].x) return anchors[anchors.length - 1].y;
|
|
165
|
+
let seg = 0;
|
|
166
|
+
while (seg < anchors.length - 2 && anchors[seg + 1].x < xPos) seg++;
|
|
167
|
+
const a0 = anchors[seg], a1 = anchors[seg + 1];
|
|
168
|
+
const p0x = a0.x, p0y = a0.y;
|
|
169
|
+
const c0x = a0.x + a0.outDx, c0y = a0.y + a0.outDy;
|
|
170
|
+
const c1x = a1.x + a1.inDx, c1y = a1.y + a1.inDy;
|
|
171
|
+
const p1x = a1.x, p1y = a1.y;
|
|
172
|
+
let lo = 0, hi = 1;
|
|
173
|
+
for (let i = 0; i < 20; i++) {
|
|
174
|
+
const mid = (lo + hi) / 2;
|
|
175
|
+
const pt = evalBezier(p0x, p0y, c0x, c0y, c1x, c1y, p1x, p1y, mid);
|
|
176
|
+
if (pt.x < xPos) lo = mid;
|
|
177
|
+
else hi = mid;
|
|
178
|
+
}
|
|
179
|
+
return evalBezier(p0x, p0y, c0x, c0y, c1x, c1y, p1x, p1y, (lo + hi) / 2).y;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// src/editor/core/palettes/paletteDerivation.ts
|
|
183
|
+
var PALETTE_SPECS = [
|
|
184
|
+
{ label: "Neutral", cssNamespace: "neutral", mode: "gray", initialColor: "#808080" },
|
|
185
|
+
{ label: "Alternate", cssNamespace: "alternate", mode: "gray", initialColor: "#808080" },
|
|
186
|
+
{ label: "Background", cssNamespace: "canvas", mode: "chromatic", emptySelector: true, initialColor: "#1a1a2e" },
|
|
187
|
+
{ label: "Brand", cssNamespace: "brand", mode: "chromatic", initialColor: "#c93636" },
|
|
188
|
+
{ label: "Accent", cssNamespace: "accent", mode: "chromatic", initialColor: "#f49e0b" },
|
|
189
|
+
{ label: "Special", cssNamespace: "special", mode: "chromatic", initialColor: "#8b5cf6" },
|
|
190
|
+
{ label: "Info", cssNamespace: "info", mode: "chromatic", initialColor: "#3077e8" },
|
|
191
|
+
{ label: "Success", cssNamespace: "success", mode: "chromatic", initialColor: "#21c45d" },
|
|
192
|
+
{ label: "Warning", cssNamespace: "warning", mode: "chromatic", initialColor: "#e66e1a" },
|
|
193
|
+
{ label: "Danger", cssNamespace: "danger", mode: "chromatic", initialColor: "#e8304f" }
|
|
194
|
+
];
|
|
195
|
+
var PALETTE_STEPS = [
|
|
196
|
+
{ label: "100" },
|
|
197
|
+
{ label: "200" },
|
|
198
|
+
{ label: "300" },
|
|
199
|
+
{ label: "400" },
|
|
200
|
+
{ label: "500" },
|
|
201
|
+
{ label: "600" },
|
|
202
|
+
{ label: "700" },
|
|
203
|
+
{ label: "800" },
|
|
204
|
+
{ label: "850" },
|
|
205
|
+
{ label: "900" },
|
|
206
|
+
{ label: "950" }
|
|
207
|
+
];
|
|
208
|
+
var GRAY_STEPS = [
|
|
209
|
+
{ label: "100" },
|
|
210
|
+
{ label: "200" },
|
|
211
|
+
{ label: "300" },
|
|
212
|
+
{ label: "400" },
|
|
213
|
+
{ label: "500" },
|
|
214
|
+
{ label: "600" },
|
|
215
|
+
{ label: "700" },
|
|
216
|
+
{ label: "800" },
|
|
217
|
+
{ label: "850" },
|
|
218
|
+
{ label: "900" },
|
|
219
|
+
{ label: "950" }
|
|
220
|
+
];
|
|
221
|
+
var SCALES = [
|
|
222
|
+
{
|
|
223
|
+
title: "Surfaces",
|
|
224
|
+
isText: false,
|
|
225
|
+
steps: [
|
|
226
|
+
{ name: "lowest", position: -1 },
|
|
227
|
+
{ name: "lower", position: -2 / 3 },
|
|
228
|
+
{ name: "low", position: -1 / 3 },
|
|
229
|
+
{ name: "default", position: 0 },
|
|
230
|
+
{ name: "high", position: 1 / 3 },
|
|
231
|
+
{ name: "higher", position: 2 / 3 },
|
|
232
|
+
{ name: "highest", position: 1 }
|
|
233
|
+
]
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
title: "Borders",
|
|
237
|
+
isText: false,
|
|
238
|
+
steps: [
|
|
239
|
+
{ name: "faint", position: -1 },
|
|
240
|
+
{ name: "subtle", position: -0.5 },
|
|
241
|
+
{ name: "default", position: 0 },
|
|
242
|
+
{ name: "medium", position: 0.5 },
|
|
243
|
+
{ name: "strong", position: 1 }
|
|
244
|
+
]
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
title: "Text",
|
|
248
|
+
isText: true,
|
|
249
|
+
steps: [
|
|
250
|
+
{ name: "primary", position: 0 },
|
|
251
|
+
{ name: "secondary", position: 0 },
|
|
252
|
+
{ name: "tertiary", position: 0 },
|
|
253
|
+
{ name: "muted", position: 0 },
|
|
254
|
+
{ name: "disabled", position: 0 }
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
];
|
|
258
|
+
var DEFAULT_PALETTE_LIGHTNESS = () => [makeAnchor(0, 95, 5), makeAnchor(100, 8, 5)];
|
|
259
|
+
var DEFAULT_PALETTE_SATURATION = () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)];
|
|
260
|
+
var DEFAULT_GRAY_LIGHTNESS = () => [makeAnchor(0, 92, 5), makeAnchor(100, 3, 5)];
|
|
261
|
+
var DEFAULT_GRAY_SATURATION = () => [makeAnchor(0, 20, 30), makeAnchor(100, 20, 30)];
|
|
262
|
+
var DEFAULT_TINT_CHROMA = 0.04;
|
|
263
|
+
var defaultScaleCurves = {
|
|
264
|
+
Surfaces: {
|
|
265
|
+
lightness: () => [makeAnchor(0, 15, 5), makeAnchor(100, 47, 5)],
|
|
266
|
+
saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)]
|
|
267
|
+
},
|
|
268
|
+
Borders: {
|
|
269
|
+
lightness: () => [makeAnchor(0, 25, 5), makeAnchor(100, 80, 5)],
|
|
270
|
+
saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)]
|
|
271
|
+
},
|
|
272
|
+
Text: {
|
|
273
|
+
lightness: () => [makeAnchor(0, 120, 30), makeAnchor(100, 55, 30)],
|
|
274
|
+
saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 15, 30)]
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
function paletteStepKey(label) {
|
|
278
|
+
return `Palette-${label}`;
|
|
279
|
+
}
|
|
280
|
+
function grayStepKey(label) {
|
|
281
|
+
return `gray-${label}`;
|
|
282
|
+
}
|
|
283
|
+
function stepKey(scaleTitle, stepName) {
|
|
284
|
+
return `${scaleTitle}-${stepName}`;
|
|
285
|
+
}
|
|
286
|
+
function stepIndexToX(index, total) {
|
|
287
|
+
return total > 1 ? index / (total - 1) * 100 : 50;
|
|
288
|
+
}
|
|
289
|
+
function computePaletteColor(index, base, lightnessCurve, saturationCurve, curveOffset) {
|
|
290
|
+
const { c: baseC, h } = hexToOklch(base);
|
|
291
|
+
const xPos = stepIndexToX(index, PALETTE_STEPS.length);
|
|
292
|
+
const targetL = Math.max(0, Math.min(100, sampleCurve(lightnessCurve, xPos) + (curveOffset.lightness ?? 0))) / 100;
|
|
293
|
+
const satMul = Math.max(0, Math.min(2, (sampleCurve(saturationCurve, xPos) + (curveOffset.saturation ?? 0)) / 100));
|
|
294
|
+
const targetC = baseC * satMul;
|
|
295
|
+
const clamped = gamutClamp(targetL, targetC, h);
|
|
296
|
+
return oklchToHex(clamped.l, clamped.c, clamped.h);
|
|
297
|
+
}
|
|
298
|
+
function computeGrayColor(index, hue, chroma, grayLightnessCurve, graySaturationCurve, curveOffset) {
|
|
299
|
+
const xPos = stepIndexToX(index, GRAY_STEPS.length);
|
|
300
|
+
const lOff = curveOffset["gray-lightness"] ?? 0;
|
|
301
|
+
const sOff = curveOffset["gray-saturation"] ?? 0;
|
|
302
|
+
const targetL = Math.max(0, Math.min(100, sampleCurve(grayLightnessCurve, xPos) + lOff)) / 100;
|
|
303
|
+
const satMul = Math.max(0, Math.min(2, (sampleCurve(graySaturationCurve, xPos) + sOff) / 100));
|
|
304
|
+
const targetC = chroma * satMul;
|
|
305
|
+
const clamped = gamutClamp(targetL, targetC, hue);
|
|
306
|
+
return oklchToHex(clamped.l, clamped.c, clamped.h);
|
|
307
|
+
}
|
|
308
|
+
function computeDerivedColor(step, base, scaleTitle, scaleCurves, curveOffset) {
|
|
309
|
+
const scale = SCALES.find((s) => s.title === scaleTitle);
|
|
310
|
+
const idx = scale.steps.indexOf(step);
|
|
311
|
+
const xPos = stepIndexToX(idx, scale.steps.length);
|
|
312
|
+
const defs = defaultScaleCurves[scaleTitle];
|
|
313
|
+
const lCurve = scaleCurves[scaleTitle]?.lightness ?? defs.lightness();
|
|
314
|
+
const sCurve = scaleCurves[scaleTitle]?.saturation ?? defs.saturation();
|
|
315
|
+
const lOff = curveOffset[`${scaleTitle}-lightness`] ?? 0;
|
|
316
|
+
const sOff = curveOffset[`${scaleTitle}-saturation`] ?? 0;
|
|
317
|
+
const { l: baseL, c: baseC, h: baseH } = hexToOklch(base);
|
|
318
|
+
let targetL;
|
|
319
|
+
if (scale.isText) {
|
|
320
|
+
const lMul = Math.max(0, Math.min(2, (sampleCurve(lCurve, xPos) + lOff) / 100));
|
|
321
|
+
targetL = Math.max(0, Math.min(1, baseL * lMul));
|
|
322
|
+
} else {
|
|
323
|
+
targetL = Math.max(0, Math.min(100, sampleCurve(lCurve, xPos) + lOff)) / 100;
|
|
324
|
+
}
|
|
325
|
+
const satMul = Math.max(0, Math.min(2, (sampleCurve(sCurve, xPos) + sOff) / 100));
|
|
326
|
+
const targetC = baseC * satMul;
|
|
327
|
+
const clamped = gamutClamp(targetL, targetC, baseH);
|
|
328
|
+
return oklchToHex(clamped.l, clamped.c, clamped.h);
|
|
329
|
+
}
|
|
330
|
+
function scaleToCssVar(scaleTitle, stepName, cssNamespace) {
|
|
331
|
+
if (cssNamespace === null) return null;
|
|
332
|
+
if (scaleTitle === "Surfaces") {
|
|
333
|
+
const suffix = stepName === "default" ? "" : `-${stepName}`;
|
|
334
|
+
return cssNamespace === "neutral" ? `--surface-neutral${suffix}` : `--surface-${cssNamespace}${suffix}`;
|
|
335
|
+
}
|
|
336
|
+
if (scaleTitle === "Borders") {
|
|
337
|
+
const suffix = stepName === "default" ? "" : `-${stepName}`;
|
|
338
|
+
return cssNamespace === "neutral" ? `--border-neutral${suffix}` : `--border-${cssNamespace}${suffix}`;
|
|
339
|
+
}
|
|
340
|
+
if (scaleTitle === "Text") {
|
|
341
|
+
if (cssNamespace === "neutral") return `--text-${stepName}`;
|
|
342
|
+
return stepName === "primary" ? `--text-${cssNamespace}` : `--text-${cssNamespace}-${stepName}`;
|
|
343
|
+
}
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
function derivePaletteVars(spec, config) {
|
|
347
|
+
const out = {};
|
|
348
|
+
if (!config) return out;
|
|
349
|
+
const baseColor = config.baseColor ?? spec.initialColor;
|
|
350
|
+
const overrides = config.overrides ?? {};
|
|
351
|
+
const curveOffset = config.curveOffset ?? {};
|
|
352
|
+
const scaleCurves = config.scaleCurves ?? {};
|
|
353
|
+
let baseForScales;
|
|
354
|
+
if (spec.mode === "gray") {
|
|
355
|
+
const grayLightnessCurve = config.grayLightnessCurve ?? DEFAULT_GRAY_LIGHTNESS();
|
|
356
|
+
const graySaturationCurve = config.graySaturationCurve ?? DEFAULT_GRAY_SATURATION();
|
|
357
|
+
const tintHue = config.tintHue ?? 240;
|
|
358
|
+
const tintChroma = config.tintChroma ?? DEFAULT_TINT_CHROMA;
|
|
359
|
+
let gray500 = "#808080";
|
|
360
|
+
GRAY_STEPS.forEach((step, index) => {
|
|
361
|
+
const k = grayStepKey(step.label);
|
|
362
|
+
const hex = computeGrayColor(index, tintHue, tintChroma, grayLightnessCurve, graySaturationCurve, curveOffset);
|
|
363
|
+
const effective = k in overrides ? overrides[k] : hex;
|
|
364
|
+
out[`--color-${spec.cssNamespace}-${step.label}`] = effective;
|
|
365
|
+
if (step.label === "500") gray500 = hex;
|
|
366
|
+
});
|
|
367
|
+
baseForScales = gray500;
|
|
368
|
+
} else {
|
|
369
|
+
const lightnessCurve = config.lightnessCurve ?? DEFAULT_PALETTE_LIGHTNESS();
|
|
370
|
+
const saturationCurve = config.saturationCurve ?? DEFAULT_PALETTE_SATURATION();
|
|
371
|
+
PALETTE_STEPS.forEach((ps, index) => {
|
|
372
|
+
const k = paletteStepKey(ps.label);
|
|
373
|
+
const hex = computePaletteColor(index, baseColor, lightnessCurve, saturationCurve, curveOffset);
|
|
374
|
+
const effective = k in overrides ? overrides[k] : hex;
|
|
375
|
+
out[`--color-${spec.cssNamespace}-${ps.label}`] = effective;
|
|
376
|
+
});
|
|
377
|
+
baseForScales = baseColor;
|
|
378
|
+
}
|
|
379
|
+
for (const scale of SCALES) {
|
|
380
|
+
for (const step of scale.steps) {
|
|
381
|
+
const k = stepKey(scale.title, step.name);
|
|
382
|
+
const hex = k in overrides ? overrides[k] : computeDerivedColor(step, baseForScales, scale.title, scaleCurves, curveOffset);
|
|
383
|
+
const varName = scaleToCssVar(scale.title, step.name, spec.cssNamespace);
|
|
384
|
+
if (varName) out[varName] = hex;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (spec.emptySelector) {
|
|
388
|
+
const emptyMode = config.emptyMode ?? "solid";
|
|
389
|
+
const emptyStep = config.emptyStep ?? "850";
|
|
390
|
+
const gradientStyle = config.gradientStyle ?? "linear";
|
|
391
|
+
const gradientAngle = config.gradientAngle ?? 180;
|
|
392
|
+
const gradientReverse = config.gradientReverse ?? false;
|
|
393
|
+
const gradientSize = config.gradientSize ?? "page";
|
|
394
|
+
const gradientStops = config.gradientStops ?? [
|
|
395
|
+
{ position: 0, paletteLabel: "800" },
|
|
396
|
+
{ position: 100, paletteLabel: "950" }
|
|
397
|
+
];
|
|
398
|
+
if (emptyMode === "solid") {
|
|
399
|
+
const stepHex = out[`--color-${spec.cssNamespace}-${emptyStep}`];
|
|
400
|
+
if (stepHex) out["--page-bg"] = stepHex;
|
|
401
|
+
out["--page-bg-attachment"] = "scroll";
|
|
402
|
+
} else {
|
|
403
|
+
const sortedStops = [...gradientStops].sort(
|
|
404
|
+
(a, b) => gradientReverse ? b.position - a.position : a.position - b.position
|
|
405
|
+
);
|
|
406
|
+
const stopsCss = sortedStops.map((s) => `${out[`--color-${spec.cssNamespace}-${s.paletteLabel}`] ?? "#000000"} ${s.position}%`).join(", ");
|
|
407
|
+
let gradient;
|
|
408
|
+
switch (gradientStyle) {
|
|
409
|
+
case "radial":
|
|
410
|
+
gradient = `radial-gradient(circle, ${stopsCss})`;
|
|
411
|
+
break;
|
|
412
|
+
case "conic":
|
|
413
|
+
gradient = `conic-gradient(from ${gradientAngle}deg, ${stopsCss})`;
|
|
414
|
+
break;
|
|
415
|
+
default:
|
|
416
|
+
gradient = `linear-gradient(${gradientAngle}deg, ${stopsCss})`;
|
|
417
|
+
}
|
|
418
|
+
out["--page-bg"] = gradient;
|
|
419
|
+
out["--page-bg-attachment"] = gradientSize === "window" ? "fixed" : "scroll";
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return out;
|
|
423
|
+
}
|
|
424
|
+
function palettesToVars(palettes) {
|
|
425
|
+
const out = {};
|
|
426
|
+
for (const spec of PALETTE_SPECS) {
|
|
427
|
+
Object.assign(out, derivePaletteVars(spec, palettes[spec.label]));
|
|
428
|
+
}
|
|
429
|
+
return out;
|
|
430
|
+
}
|
|
431
|
+
var HEX_RE = /^#[0-9a-f]{6}$/i;
|
|
432
|
+
function reconcilePalettesFromCssVars(palettes, cssVars) {
|
|
433
|
+
const next = structuredClone(palettes);
|
|
434
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
435
|
+
const snapped = /* @__PURE__ */ new Set();
|
|
436
|
+
for (const spec of PALETTE_SPECS) {
|
|
437
|
+
const current = next[spec.label];
|
|
438
|
+
if (current === void 0) continue;
|
|
439
|
+
if (current._imported === true) {
|
|
440
|
+
const anchorHex = cssVars[`--color-${spec.cssNamespace}-500`];
|
|
441
|
+
if (anchorHex && HEX_RE.test(anchorHex.trim())) {
|
|
442
|
+
const hex = anchorHex.trim();
|
|
443
|
+
if (spec.mode === "gray") {
|
|
444
|
+
const { c, h } = hexToOklch(hex);
|
|
445
|
+
next[spec.label] = { ...current, tintHue: h, tintChroma: c, _imported: false };
|
|
446
|
+
} else {
|
|
447
|
+
next[spec.label] = { ...current, baseColor: hex, _imported: false };
|
|
448
|
+
}
|
|
449
|
+
snapped.add(spec.label);
|
|
450
|
+
} else {
|
|
451
|
+
next[spec.label] = { ...current, _imported: false };
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
for (const k of Object.keys(derivePaletteVars(spec, next[spec.label]))) {
|
|
455
|
+
consumed.add(k);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return { palettes: next, consumed, snapped };
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// vite-plugin/files/versionedFileResourceServer.ts
|
|
58
462
|
var import_fs = __toESM(require("fs"), 1);
|
|
59
463
|
var import_path = __toESM(require("path"), 1);
|
|
60
464
|
function versionedFileResourceServer(opts) {
|
|
@@ -114,7 +518,7 @@ function versionedFileResourceServer(opts) {
|
|
|
114
518
|
};
|
|
115
519
|
}
|
|
116
520
|
|
|
117
|
-
//
|
|
521
|
+
// vite-plugin/files/routeTable.ts
|
|
118
522
|
async function dispatch(req, res, routes) {
|
|
119
523
|
const url = req.url || "";
|
|
120
524
|
const method = req.method || "GET";
|
|
@@ -142,16 +546,46 @@ async function dispatch(req, res, routes) {
|
|
|
142
546
|
return false;
|
|
143
547
|
}
|
|
144
548
|
|
|
145
|
-
//
|
|
146
|
-
|
|
549
|
+
// vite-plugin/files/nameAllocator.ts
|
|
550
|
+
function nextAvailableName(exists, baseName, maxAttempts = 1e3) {
|
|
551
|
+
if (!exists(baseName)) return baseName;
|
|
552
|
+
for (let i = 2; i < maxAttempts; i++) {
|
|
553
|
+
const candidate = `${baseName}-${i}`;
|
|
554
|
+
if (!exists(candidate)) return candidate;
|
|
555
|
+
}
|
|
556
|
+
throw new Error(`Could not allocate a non-colliding name for "${baseName}"`);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// vite-plugin/themeFileApi.ts
|
|
560
|
+
var import_node_url = require("url");
|
|
561
|
+
var import_meta = {};
|
|
562
|
+
var PKG_VERSION = (() => {
|
|
563
|
+
try {
|
|
564
|
+
let dir = import_path2.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
565
|
+
for (let i = 0; i < 4; i++) {
|
|
566
|
+
const p = import_path2.default.join(dir, "package.json");
|
|
567
|
+
if (import_fs2.default.existsSync(p)) {
|
|
568
|
+
const json = JSON.parse(import_fs2.default.readFileSync(p, "utf-8"));
|
|
569
|
+
if (json?.name === "@motion-proto/live-tokens") return json.version ?? "";
|
|
570
|
+
}
|
|
571
|
+
const up = import_path2.default.dirname(dir);
|
|
572
|
+
if (up === dir) break;
|
|
573
|
+
dir = up;
|
|
574
|
+
}
|
|
575
|
+
} catch {
|
|
576
|
+
}
|
|
577
|
+
return "";
|
|
578
|
+
})();
|
|
147
579
|
function themeFileApi(opts) {
|
|
148
580
|
const THEMES_DIR = import_path2.default.resolve(opts.themesDir);
|
|
149
581
|
const CSS_PATH = import_path2.default.resolve(opts.tokensCssPath);
|
|
582
|
+
const GENERATED_CSS_PATH = opts.tokensGeneratedCssPath ? import_path2.default.resolve(opts.tokensGeneratedCssPath) : import_path2.default.join(import_path2.default.dirname(CSS_PATH), "tokens.generated.css");
|
|
150
583
|
const FONTS_CSS_PATH = opts.fontsCssPath ? import_path2.default.resolve(opts.fontsCssPath) : import_path2.default.join(import_path2.default.dirname(CSS_PATH), "fonts.css");
|
|
151
584
|
const API_BASE = opts.apiBase ?? "/api";
|
|
152
585
|
const COMPONENT_CONFIGS_DIR = opts.componentConfigsDir ? import_path2.default.resolve(opts.componentConfigsDir) : import_path2.default.resolve("component-configs");
|
|
153
|
-
const COMPONENTS_SRC_DIR = opts.componentsSrcDir ? import_path2.default.resolve(opts.componentsSrcDir) : import_path2.default.resolve("src/components");
|
|
154
|
-
const
|
|
586
|
+
const COMPONENTS_SRC_DIR = opts.componentsSrcDir ? import_path2.default.resolve(opts.componentsSrcDir) : import_path2.default.resolve("src/system/components");
|
|
587
|
+
const MANIFESTS_DIR = opts.manifestsDir ? import_path2.default.resolve(opts.manifestsDir) : import_path2.default.resolve("manifests");
|
|
588
|
+
const LEGACY_PRESETS_DIR = import_path2.default.resolve("presets");
|
|
155
589
|
const themesResource = versionedFileResourceServer({
|
|
156
590
|
dir: THEMES_DIR
|
|
157
591
|
});
|
|
@@ -164,7 +598,7 @@ function themeFileApi(opts) {
|
|
|
164
598
|
}
|
|
165
599
|
return r;
|
|
166
600
|
}
|
|
167
|
-
const
|
|
601
|
+
const manifestsResource = versionedFileResourceServer({ dir: MANIFESTS_DIR });
|
|
168
602
|
function ensureThemesDir() {
|
|
169
603
|
themesResource.ensureDir();
|
|
170
604
|
if (!import_fs2.default.existsSync(import_path2.default.join(THEMES_DIR, "default.json"))) {
|
|
@@ -192,6 +626,17 @@ function themeFileApi(opts) {
|
|
|
192
626
|
res.setHeader("Content-Type", "application/json");
|
|
193
627
|
res.end(JSON.stringify(data));
|
|
194
628
|
}
|
|
629
|
+
function normalizeTheme(theme) {
|
|
630
|
+
if (!theme || typeof theme !== "object") return theme;
|
|
631
|
+
const palettes = theme.editorConfigs ?? {};
|
|
632
|
+
const cssVars = theme.cssVariables ?? {};
|
|
633
|
+
const { palettes: nextPalettes, consumed } = reconcilePalettesFromCssVars(palettes, cssVars);
|
|
634
|
+
const nextCssVars = {};
|
|
635
|
+
for (const [k, v] of Object.entries(cssVars)) {
|
|
636
|
+
if (!consumed.has(k)) nextCssVars[k] = v;
|
|
637
|
+
}
|
|
638
|
+
return { ...theme, editorConfigs: nextPalettes, cssVariables: nextCssVars };
|
|
639
|
+
}
|
|
195
640
|
const SYSTEM_CASCADES_SSR = {
|
|
196
641
|
"system-ui-sans": 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
197
642
|
"system-ui-serif": 'Georgia, "Times New Roman", serif',
|
|
@@ -223,42 +668,78 @@ function themeFileApi(opts) {
|
|
|
223
668
|
}
|
|
224
669
|
return out;
|
|
225
670
|
}
|
|
226
|
-
function
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
671
|
+
function regenerateTokensCss() {
|
|
672
|
+
const lines = [];
|
|
673
|
+
lines.push("/* Generated by themeFileApi from the production theme and component configs. Do not edit. */");
|
|
674
|
+
lines.push("/* tokens.css holds developer-authored defaults; this file holds editor overrides. */");
|
|
675
|
+
lines.push("");
|
|
676
|
+
const productionThemeName = themesResource.getProductionName();
|
|
677
|
+
const themePath = import_path2.default.join(THEMES_DIR, `${productionThemeName}.json`);
|
|
678
|
+
let themeVarCount = 0;
|
|
679
|
+
if (import_fs2.default.existsSync(themePath)) {
|
|
680
|
+
const themeData = JSON.parse(import_fs2.default.readFileSync(themePath, "utf-8"));
|
|
681
|
+
const cssVars = { ...themeData.cssVariables || {} };
|
|
682
|
+
Object.assign(cssVars, palettesToVars(themeData.editorConfigs ?? {}));
|
|
683
|
+
const resolvedFontVars = resolveFontStacks(themeData);
|
|
684
|
+
for (const [name, value] of Object.entries(resolvedFontVars)) {
|
|
685
|
+
cssVars[name] = value;
|
|
686
|
+
}
|
|
687
|
+
themeVarCount = Object.keys(cssVars).length;
|
|
688
|
+
if (themeVarCount > 0) {
|
|
689
|
+
lines.push(`/* Production theme: ${productionThemeName} */`);
|
|
690
|
+
lines.push(":root:root {");
|
|
691
|
+
for (const [name, value] of Object.entries(cssVars)) {
|
|
692
|
+
lines.push(` ${name}: ${value};`);
|
|
244
693
|
}
|
|
245
|
-
|
|
694
|
+
lines.push("}");
|
|
695
|
+
lines.push("");
|
|
246
696
|
}
|
|
247
|
-
);
|
|
248
|
-
let finalContent = updatedContent;
|
|
249
|
-
if (remaining.size > 0) {
|
|
250
|
-
const newVars = [...remaining].map((name) => ` ${name}: ${cssVars[name]};`).join("\n");
|
|
251
|
-
finalContent = finalContent.replace(
|
|
252
|
-
/\n\}(\s*)$/,
|
|
253
|
-
`
|
|
254
|
-
|
|
255
|
-
/* Token additions */
|
|
256
|
-
${newVars}
|
|
257
|
-
}$1`
|
|
258
|
-
);
|
|
259
697
|
}
|
|
260
|
-
|
|
261
|
-
|
|
698
|
+
let componentOverrideCount = 0;
|
|
699
|
+
if (import_fs2.default.existsSync(COMPONENT_CONFIGS_DIR)) {
|
|
700
|
+
const blocks = [];
|
|
701
|
+
for (const comp of listComponentNames()) {
|
|
702
|
+
const prod = componentResource(comp).getProductionName();
|
|
703
|
+
if (prod === "default") continue;
|
|
704
|
+
const prodCfg = readComponentConfig(comp, prod);
|
|
705
|
+
const defaultCfg = readComponentConfig(comp, "default");
|
|
706
|
+
if (!prodCfg || !defaultCfg) continue;
|
|
707
|
+
const overrides = [];
|
|
708
|
+
const defaultAliases = defaultCfg.aliases ?? {};
|
|
709
|
+
for (const [varName, semanticValue] of Object.entries(prodCfg.aliases ?? {})) {
|
|
710
|
+
if (!aliasValuesEqual(defaultAliases[varName], semanticValue)) {
|
|
711
|
+
overrides.push([varName, semanticValue]);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
if (overrides.length === 0) continue;
|
|
715
|
+
const block = [` /* ${comp} (${prod}) */`];
|
|
716
|
+
for (const [varName, semanticValue] of overrides) {
|
|
717
|
+
block.push(` ${varName}: ${aliasValueToCss(semanticValue)};`);
|
|
718
|
+
}
|
|
719
|
+
blocks.push(block);
|
|
720
|
+
componentOverrideCount += overrides.length;
|
|
721
|
+
}
|
|
722
|
+
if (blocks.length > 0) {
|
|
723
|
+
lines.push("/* Component aliases (production configs differing from defaults) */");
|
|
724
|
+
lines.push(":root:root {");
|
|
725
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
726
|
+
if (i > 0) lines.push("");
|
|
727
|
+
lines.push(...blocks[i]);
|
|
728
|
+
}
|
|
729
|
+
lines.push("}");
|
|
730
|
+
lines.push("");
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
if (!import_fs2.default.existsSync(import_path2.default.dirname(GENERATED_CSS_PATH))) {
|
|
734
|
+
import_fs2.default.mkdirSync(import_path2.default.dirname(GENERATED_CSS_PATH), { recursive: true });
|
|
735
|
+
}
|
|
736
|
+
import_fs2.default.writeFileSync(GENERATED_CSS_PATH, lines.join("\n"));
|
|
737
|
+
console.log(
|
|
738
|
+
`[regenerateTokensCss] Wrote ${import_path2.default.basename(GENERATED_CSS_PATH)} (${themeVarCount} theme vars, ${componentOverrideCount} component overrides)`
|
|
739
|
+
);
|
|
740
|
+
}
|
|
741
|
+
function syncTokensToCss(_fileName) {
|
|
742
|
+
regenerateTokensCss();
|
|
262
743
|
}
|
|
263
744
|
function syncFontsToCss(fileName) {
|
|
264
745
|
const themePath = import_path2.default.join(THEMES_DIR, `${fileName}.json`);
|
|
@@ -270,15 +751,20 @@ ${newVars}
|
|
|
270
751
|
lines.push("/* Generated from the production theme by syncFontsToCss. Do not edit. */");
|
|
271
752
|
lines.push("/* Both fonts.css and fonts/ are in dist/, so relative paths work at runtime. */");
|
|
272
753
|
lines.push("");
|
|
273
|
-
|
|
754
|
+
const urlSources = sources.filter((s) => s.kind !== "font-face" && s.url);
|
|
755
|
+
const faceSources = sources.filter((s) => s.kind === "font-face" && s.cssText);
|
|
756
|
+
for (const source of urlSources) {
|
|
274
757
|
const familyNames = source.families.map((f) => f.name).join(", ");
|
|
275
758
|
const label = source.label ? `${source.label} \u2014 ${familyNames}` : familyNames;
|
|
276
759
|
lines.push(`/* ${label} */`);
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
760
|
+
lines.push(`@import url('${source.url}');`);
|
|
761
|
+
lines.push("");
|
|
762
|
+
}
|
|
763
|
+
for (const source of faceSources) {
|
|
764
|
+
const familyNames = source.families.map((f) => f.name).join(", ");
|
|
765
|
+
const label = source.label ? `${source.label} \u2014 ${familyNames}` : familyNames;
|
|
766
|
+
lines.push(`/* ${label} */`);
|
|
767
|
+
lines.push(source.cssText);
|
|
282
768
|
lines.push("");
|
|
283
769
|
}
|
|
284
770
|
const content = lines.join("\n");
|
|
@@ -360,25 +846,90 @@ ${newVars}
|
|
|
360
846
|
r.ensureMeta();
|
|
361
847
|
}
|
|
362
848
|
}
|
|
363
|
-
function
|
|
364
|
-
|
|
365
|
-
|
|
849
|
+
function ensureManifestsDir() {
|
|
850
|
+
if (!import_fs2.default.existsSync(MANIFESTS_DIR) && import_fs2.default.existsSync(LEGACY_PRESETS_DIR)) {
|
|
851
|
+
import_fs2.default.renameSync(LEGACY_PRESETS_DIR, MANIFESTS_DIR);
|
|
852
|
+
const legacyProd = import_path2.default.join(MANIFESTS_DIR, "_production.json");
|
|
853
|
+
if (import_fs2.default.existsSync(legacyProd)) import_fs2.default.unlinkSync(legacyProd);
|
|
854
|
+
}
|
|
855
|
+
manifestsResource.ensureDir();
|
|
856
|
+
const defaultPath = import_path2.default.join(MANIFESTS_DIR, "default.json");
|
|
366
857
|
if (!import_fs2.default.existsSync(defaultPath)) {
|
|
367
858
|
const componentConfigs = {};
|
|
368
859
|
for (const comp of listComponentNames()) {
|
|
369
860
|
componentConfigs[comp] = componentResource(comp).getActiveName();
|
|
370
861
|
}
|
|
371
862
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
372
|
-
const
|
|
373
|
-
name: "Default
|
|
863
|
+
const defaultManifest = {
|
|
864
|
+
name: "Default",
|
|
374
865
|
createdAt: now,
|
|
375
866
|
updatedAt: now,
|
|
376
867
|
theme: themesResource.getActiveName(),
|
|
377
868
|
componentConfigs
|
|
378
869
|
};
|
|
379
|
-
import_fs2.default.writeFileSync(defaultPath, JSON.stringify(
|
|
870
|
+
import_fs2.default.writeFileSync(defaultPath, JSON.stringify(defaultManifest, null, 2));
|
|
380
871
|
}
|
|
381
|
-
|
|
872
|
+
if (!import_fs2.default.existsSync(manifestsResource.activePath)) {
|
|
873
|
+
import_fs2.default.writeFileSync(
|
|
874
|
+
manifestsResource.activePath,
|
|
875
|
+
JSON.stringify({ activeFile: "default" })
|
|
876
|
+
);
|
|
877
|
+
} else {
|
|
878
|
+
const activeName = manifestsResource.getActiveName();
|
|
879
|
+
if (!import_fs2.default.existsSync(manifestsResource.filePath(activeName))) {
|
|
880
|
+
manifestsResource.setActiveName("default");
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
const stragglerProd = import_path2.default.join(MANIFESTS_DIR, "_production.json");
|
|
884
|
+
if (import_fs2.default.existsSync(stragglerProd)) import_fs2.default.unlinkSync(stragglerProd);
|
|
885
|
+
}
|
|
886
|
+
function patchActiveManifest(field, comp, fileName) {
|
|
887
|
+
const activeFile = manifestsResource.getActiveName();
|
|
888
|
+
if (activeFile === "default") return false;
|
|
889
|
+
const manifestPath = manifestsResource.filePath(activeFile);
|
|
890
|
+
if (!import_fs2.default.existsSync(manifestPath)) return false;
|
|
891
|
+
let manifest;
|
|
892
|
+
try {
|
|
893
|
+
manifest = JSON.parse(import_fs2.default.readFileSync(manifestPath, "utf-8"));
|
|
894
|
+
} catch {
|
|
895
|
+
return false;
|
|
896
|
+
}
|
|
897
|
+
if (field === "theme") {
|
|
898
|
+
manifest.theme = fileName;
|
|
899
|
+
} else if (field === "component" && comp) {
|
|
900
|
+
manifest.componentConfigs = manifest.componentConfigs ?? {};
|
|
901
|
+
manifest.componentConfigs[comp] = fileName;
|
|
902
|
+
}
|
|
903
|
+
manifest.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
904
|
+
import_fs2.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
905
|
+
return true;
|
|
906
|
+
}
|
|
907
|
+
function formatAliasGradient(v) {
|
|
908
|
+
const stopColor = (s) => {
|
|
909
|
+
const base = s.color.startsWith("--") ? `var(${s.color})` : s.color;
|
|
910
|
+
const opacity = s.opacity ?? 100;
|
|
911
|
+
return opacity >= 100 ? base : `color-mix(in srgb, ${base} ${opacity}%, transparent)`;
|
|
912
|
+
};
|
|
913
|
+
if (v.type === "none") return "transparent";
|
|
914
|
+
if (v.type === "solid") {
|
|
915
|
+
const first = v.stops[0];
|
|
916
|
+
if (!first) return "transparent";
|
|
917
|
+
return stopColor(first);
|
|
918
|
+
}
|
|
919
|
+
const stops = v.stops.map((s) => `${stopColor(s)} ${s.position}%`).join(", ");
|
|
920
|
+
if (v.type === "linear") return `linear-gradient(${v.angle}deg, ${stops})`;
|
|
921
|
+
const radial = v.radius && v.radius > 0 ? `circle ${v.radius}px at center` : "circle";
|
|
922
|
+
return `radial-gradient(${radial}, ${stops})`;
|
|
923
|
+
}
|
|
924
|
+
function aliasValueToCss(v) {
|
|
925
|
+
if (typeof v === "string") return v.startsWith("--") ? `var(${v})` : v;
|
|
926
|
+
return formatAliasGradient(v.value);
|
|
927
|
+
}
|
|
928
|
+
function aliasValuesEqual(a, b) {
|
|
929
|
+
if (a === void 0 || b === void 0) return a === b;
|
|
930
|
+
if (typeof a === "string" && typeof b === "string") return a === b;
|
|
931
|
+
if (typeof a !== typeof b) return false;
|
|
932
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
382
933
|
}
|
|
383
934
|
function readComponentConfig(comp, name) {
|
|
384
935
|
const filePath = componentResource(comp).filePath(name);
|
|
@@ -389,70 +940,25 @@ ${newVars}
|
|
|
389
940
|
return null;
|
|
390
941
|
}
|
|
391
942
|
}
|
|
392
|
-
const COMPONENT_OVERRIDES_START = "/* component-aliases:start */";
|
|
393
|
-
const COMPONENT_OVERRIDES_END = "/* component-aliases:end */";
|
|
394
943
|
function syncComponentsToCss() {
|
|
395
|
-
|
|
396
|
-
if (!import_fs2.default.existsSync(COMPONENT_CONFIGS_DIR)) return;
|
|
397
|
-
const lines = [];
|
|
398
|
-
const components = listComponentNames();
|
|
399
|
-
for (const comp of components) {
|
|
400
|
-
const prod = componentResource(comp).getProductionName();
|
|
401
|
-
if (prod === "default") continue;
|
|
402
|
-
const prodCfg = readComponentConfig(comp, prod);
|
|
403
|
-
const defaultCfg = readComponentConfig(comp, "default");
|
|
404
|
-
if (!prodCfg || !defaultCfg) continue;
|
|
405
|
-
const overrides = [];
|
|
406
|
-
for (const [varName, semanticName] of Object.entries(prodCfg.aliases ?? {})) {
|
|
407
|
-
if ((defaultCfg.aliases ?? {})[varName] !== semanticName) {
|
|
408
|
-
overrides.push([varName, semanticName]);
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
if (overrides.length === 0) continue;
|
|
412
|
-
lines.push(` /* ${comp} (${prod}) */`);
|
|
413
|
-
for (const [varName, semanticName] of overrides) {
|
|
414
|
-
lines.push(` ${varName}: var(${semanticName});`);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
const block = lines.length > 0 ? `
|
|
418
|
-
|
|
419
|
-
${COMPONENT_OVERRIDES_START}
|
|
420
|
-
:root:root {
|
|
421
|
-
${lines.join("\n")}
|
|
422
|
-
}
|
|
423
|
-
${COMPONENT_OVERRIDES_END}
|
|
424
|
-
` : "";
|
|
425
|
-
let cssContent = import_fs2.default.readFileSync(CSS_PATH, "utf-8");
|
|
426
|
-
const startIdx = cssContent.indexOf(COMPONENT_OVERRIDES_START);
|
|
427
|
-
const endIdx = cssContent.indexOf(COMPONENT_OVERRIDES_END);
|
|
428
|
-
if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
|
|
429
|
-
let stripStart = startIdx;
|
|
430
|
-
while (stripStart > 0 && cssContent[stripStart - 1] === "\n") stripStart--;
|
|
431
|
-
const after = cssContent.slice(endIdx + COMPONENT_OVERRIDES_END.length);
|
|
432
|
-
cssContent = cssContent.slice(0, stripStart) + (block || "\n") + after.replace(/^\n+/, "");
|
|
433
|
-
} else if (block) {
|
|
434
|
-
cssContent = cssContent.replace(/\n*$/, "") + block;
|
|
435
|
-
}
|
|
436
|
-
import_fs2.default.writeFileSync(CSS_PATH, cssContent);
|
|
437
|
-
console.log(
|
|
438
|
-
`[syncComponentsToCss] Wrote ${lines.filter((l) => !l.trim().startsWith("/*")).length} alias override(s) to tokens.css`
|
|
439
|
-
);
|
|
944
|
+
regenerateTokensCss();
|
|
440
945
|
}
|
|
441
946
|
const escapedBase = API_BASE.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
442
947
|
const THEMES_ROUTE = `${API_BASE}/themes`;
|
|
443
948
|
const THEMES_ACTIVE_ROUTE = `${API_BASE}/themes/active`;
|
|
444
949
|
const THEMES_PRODUCTION_ROUTE = `${API_BASE}/themes/production`;
|
|
445
950
|
const COMPONENT_CONFIGS_ROUTE = `${API_BASE}/component-configs`;
|
|
446
|
-
const
|
|
447
|
-
const
|
|
448
|
-
const PRESETS_PRODUCTION_ROUTE = `${API_BASE}/presets/production`;
|
|
951
|
+
const MANIFESTS_ROUTE = `${API_BASE}/manifests`;
|
|
952
|
+
const MANIFESTS_ACTIVE_ROUTE = `${API_BASE}/manifests/active`;
|
|
449
953
|
const THEME_BY_NAME_REGEX = new RegExp(`^${escapedBase}/themes/([a-z0-9\\-_]+)$`);
|
|
450
954
|
const COMP_LIST_REGEX = new RegExp(`^${escapedBase}/component-configs/([a-z0-9\\-_]+)$`);
|
|
451
955
|
const COMP_ACTIVE_REGEX = new RegExp(`^${escapedBase}/component-configs/([a-z0-9\\-_]+)/active$`);
|
|
452
956
|
const COMP_PRODUCTION_REGEX = new RegExp(`^${escapedBase}/component-configs/([a-z0-9\\-_]+)/production$`);
|
|
453
957
|
const COMP_BY_NAME_REGEX = new RegExp(`^${escapedBase}/component-configs/([a-z0-9\\-_]+)/([a-z0-9\\-_]+)$`);
|
|
454
|
-
const
|
|
455
|
-
const
|
|
958
|
+
const MANIFEST_APPLY_REGEX = new RegExp(`^${escapedBase}/manifests/([a-z0-9\\-_]+)/apply$`);
|
|
959
|
+
const MANIFEST_EXPORT_REGEX = new RegExp(`^${escapedBase}/manifests/([a-z0-9\\-_]+)/export$`);
|
|
960
|
+
const MANIFEST_IMPORT_ROUTE = `${API_BASE}/manifests/import`;
|
|
961
|
+
const MANIFEST_BY_NAME_REGEX = new RegExp(`^${escapedBase}/manifests/([a-z0-9\\-_]+)$`);
|
|
456
962
|
async function handleListThemes(_ctx) {
|
|
457
963
|
const activeFile = themesResource.getActiveName();
|
|
458
964
|
const files = import_fs2.default.readdirSync(THEMES_DIR).filter((f) => f.endsWith(".json") && !f.startsWith("_")).map((f) => {
|
|
@@ -475,7 +981,7 @@ ${COMPONENT_OVERRIDES_END}
|
|
|
475
981
|
jsonResponse(res, 404, { error: "Active theme not found" });
|
|
476
982
|
return;
|
|
477
983
|
}
|
|
478
|
-
const data = JSON.parse(import_fs2.default.readFileSync(filePath, "utf-8"));
|
|
984
|
+
const data = normalizeTheme(JSON.parse(import_fs2.default.readFileSync(filePath, "utf-8")));
|
|
479
985
|
data._fileName = activeFile;
|
|
480
986
|
jsonResponse(res, 200, data);
|
|
481
987
|
}
|
|
@@ -496,7 +1002,7 @@ ${COMPONENT_OVERRIDES_END}
|
|
|
496
1002
|
jsonResponse(res, 200, { fileName: prodFile, name: prodFile, cssVariables: {} });
|
|
497
1003
|
return;
|
|
498
1004
|
}
|
|
499
|
-
const data = JSON.parse(import_fs2.default.readFileSync(filePath, "utf-8"));
|
|
1005
|
+
const data = normalizeTheme(JSON.parse(import_fs2.default.readFileSync(filePath, "utf-8")));
|
|
500
1006
|
jsonResponse(res, 200, {
|
|
501
1007
|
fileName: prodFile,
|
|
502
1008
|
name: data.name || prodFile,
|
|
@@ -511,10 +1017,18 @@ ${COMPONENT_OVERRIDES_END}
|
|
|
511
1017
|
jsonResponse(res, 404, { error: "Theme not found" });
|
|
512
1018
|
return;
|
|
513
1019
|
}
|
|
1020
|
+
if (manifestsResource.getActiveName() === "default") {
|
|
1021
|
+
jsonResponse(res, 409, {
|
|
1022
|
+
error: "Active manifest is protected. Save As first.",
|
|
1023
|
+
code: "ACTIVE_IS_PROTECTED"
|
|
1024
|
+
});
|
|
1025
|
+
return;
|
|
1026
|
+
}
|
|
514
1027
|
themesResource.setProductionName(fileName);
|
|
515
1028
|
syncTokensToCss(fileName);
|
|
516
1029
|
syncFontsToCss(fileName);
|
|
517
1030
|
syncComponentsToCss();
|
|
1031
|
+
patchActiveManifest("theme", null, fileName);
|
|
518
1032
|
const data = JSON.parse(import_fs2.default.readFileSync(themesResource.filePath(fileName), "utf-8"));
|
|
519
1033
|
jsonResponse(res, 200, {
|
|
520
1034
|
ok: true,
|
|
@@ -531,7 +1045,7 @@ ${COMPONENT_OVERRIDES_END}
|
|
|
531
1045
|
jsonResponse(res, 404, { error: "Not found" });
|
|
532
1046
|
return;
|
|
533
1047
|
}
|
|
534
|
-
const data = JSON.parse(import_fs2.default.readFileSync(filePath, "utf-8"));
|
|
1048
|
+
const data = normalizeTheme(JSON.parse(import_fs2.default.readFileSync(filePath, "utf-8")));
|
|
535
1049
|
data._fileName = fileName;
|
|
536
1050
|
jsonResponse(res, 200, data);
|
|
537
1051
|
return;
|
|
@@ -561,6 +1075,13 @@ ${COMPONENT_OVERRIDES_END}
|
|
|
561
1075
|
jsonResponse(res, 403, { error: "Cannot delete the default theme" });
|
|
562
1076
|
return;
|
|
563
1077
|
}
|
|
1078
|
+
if (themesResource.getProductionName() === fileName) {
|
|
1079
|
+
jsonResponse(res, 403, {
|
|
1080
|
+
error: "Cannot delete the production theme. Adopt a different theme first.",
|
|
1081
|
+
code: "PRODUCTION_THEME"
|
|
1082
|
+
});
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
564
1085
|
if (import_fs2.default.existsSync(filePath)) {
|
|
565
1086
|
import_fs2.default.unlinkSync(filePath);
|
|
566
1087
|
if (themesResource.getActiveName() === fileName) {
|
|
@@ -628,9 +1149,17 @@ ${COMPONENT_OVERRIDES_END}
|
|
|
628
1149
|
jsonResponse(res, 404, { error: "Config not found" });
|
|
629
1150
|
return;
|
|
630
1151
|
}
|
|
1152
|
+
if (manifestsResource.getActiveName() === "default") {
|
|
1153
|
+
jsonResponse(res, 409, {
|
|
1154
|
+
error: "Active manifest is protected. Save As first.",
|
|
1155
|
+
code: "ACTIVE_IS_PROTECTED"
|
|
1156
|
+
});
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
631
1159
|
r.ensureDir();
|
|
632
1160
|
r.setProductionName(fileName);
|
|
633
1161
|
syncComponentsToCss();
|
|
1162
|
+
patchActiveManifest("component", comp, fileName);
|
|
634
1163
|
const cfg = readComponentConfig(comp, fileName);
|
|
635
1164
|
jsonResponse(res, 200, {
|
|
636
1165
|
ok: true,
|
|
@@ -720,112 +1249,46 @@ ${COMPONENT_OVERRIDES_END}
|
|
|
720
1249
|
});
|
|
721
1250
|
jsonResponse(res, 200, { component: comp, files, activeFile, productionFile });
|
|
722
1251
|
}
|
|
723
|
-
async function
|
|
724
|
-
const activeFile =
|
|
725
|
-
const files = import_fs2.default.readdirSync(
|
|
726
|
-
const filePath = import_path2.default.join(
|
|
1252
|
+
async function handleListManifests({ res }) {
|
|
1253
|
+
const activeFile = manifestsResource.getActiveName();
|
|
1254
|
+
const files = import_fs2.default.readdirSync(MANIFESTS_DIR).filter((f) => f.endsWith(".json") && !f.startsWith("_")).map((f) => {
|
|
1255
|
+
const filePath = import_path2.default.join(MANIFESTS_DIR, f);
|
|
727
1256
|
const data = JSON.parse(import_fs2.default.readFileSync(filePath, "utf-8"));
|
|
728
1257
|
const fileName = f.replace(".json", "");
|
|
729
1258
|
return {
|
|
730
1259
|
name: data.name || fileName,
|
|
731
1260
|
fileName,
|
|
732
1261
|
updatedAt: data.updatedAt || "",
|
|
733
|
-
isActive: fileName === activeFile
|
|
1262
|
+
isActive: fileName === activeFile,
|
|
1263
|
+
isProtected: fileName === "default"
|
|
734
1264
|
};
|
|
735
1265
|
});
|
|
736
1266
|
jsonResponse(res, 200, { files, activeFile });
|
|
737
1267
|
}
|
|
738
|
-
async function
|
|
739
|
-
const activeFile =
|
|
740
|
-
const filePath =
|
|
1268
|
+
async function handleGetActiveManifest({ res }) {
|
|
1269
|
+
const activeFile = manifestsResource.getActiveName();
|
|
1270
|
+
const filePath = manifestsResource.filePath(activeFile);
|
|
741
1271
|
if (!import_fs2.default.existsSync(filePath)) {
|
|
742
|
-
jsonResponse(res, 404, { error: "Active
|
|
1272
|
+
jsonResponse(res, 404, { error: "Active manifest not found" });
|
|
743
1273
|
return;
|
|
744
1274
|
}
|
|
745
1275
|
const data = JSON.parse(import_fs2.default.readFileSync(filePath, "utf-8"));
|
|
746
1276
|
data._fileName = activeFile;
|
|
747
1277
|
jsonResponse(res, 200, data);
|
|
748
1278
|
}
|
|
749
|
-
async function
|
|
1279
|
+
async function handleSetActiveManifest({ req, res }) {
|
|
750
1280
|
const body = JSON.parse(await readBody(req));
|
|
751
1281
|
const fileName = sanitizeFileName(body.name || "default");
|
|
752
|
-
if (!import_fs2.default.existsSync(
|
|
753
|
-
jsonResponse(res, 404, { error: "
|
|
1282
|
+
if (!import_fs2.default.existsSync(manifestsResource.filePath(fileName))) {
|
|
1283
|
+
jsonResponse(res, 404, { error: "Manifest not found" });
|
|
754
1284
|
return;
|
|
755
1285
|
}
|
|
756
|
-
|
|
1286
|
+
manifestsResource.setActiveName(fileName);
|
|
757
1287
|
jsonResponse(res, 200, { ok: true, activeFile: fileName });
|
|
758
1288
|
}
|
|
759
|
-
async function
|
|
760
|
-
const prodFile = presetsResource.getProductionName();
|
|
761
|
-
const filePath = presetsResource.filePath(prodFile);
|
|
762
|
-
if (!import_fs2.default.existsSync(filePath)) {
|
|
763
|
-
jsonResponse(res, 200, {
|
|
764
|
-
fileName: prodFile,
|
|
765
|
-
name: prodFile,
|
|
766
|
-
theme: "default",
|
|
767
|
-
componentConfigs: {},
|
|
768
|
-
updatedAt: ""
|
|
769
|
-
});
|
|
770
|
-
return;
|
|
771
|
-
}
|
|
772
|
-
const data = JSON.parse(import_fs2.default.readFileSync(filePath, "utf-8"));
|
|
773
|
-
jsonResponse(res, 200, {
|
|
774
|
-
fileName: prodFile,
|
|
775
|
-
name: data.name || prodFile,
|
|
776
|
-
theme: data.theme || "default",
|
|
777
|
-
componentConfigs: data.componentConfigs || {},
|
|
778
|
-
updatedAt: data.updatedAt || ""
|
|
779
|
-
});
|
|
780
|
-
}
|
|
781
|
-
async function handleSetProductionPreset({ req, res }) {
|
|
782
|
-
const body = JSON.parse(await readBody(req));
|
|
783
|
-
const fileName = sanitizeFileName(body.name || "default");
|
|
784
|
-
const presetPath = presetsResource.filePath(fileName);
|
|
785
|
-
if (!import_fs2.default.existsSync(presetPath)) {
|
|
786
|
-
jsonResponse(res, 404, { error: "Preset not found" });
|
|
787
|
-
return;
|
|
788
|
-
}
|
|
789
|
-
const preset = JSON.parse(import_fs2.default.readFileSync(presetPath, "utf-8"));
|
|
790
|
-
const themeName = sanitizeFileName(preset.theme || "default");
|
|
791
|
-
if (!import_fs2.default.existsSync(themesResource.filePath(themeName))) {
|
|
792
|
-
jsonResponse(res, 422, { error: `Preset references missing theme: ${themeName}` });
|
|
793
|
-
return;
|
|
794
|
-
}
|
|
795
|
-
const knownComponents = new Set(listComponentNames());
|
|
796
|
-
const componentConfigs = preset.componentConfigs ?? {};
|
|
797
|
-
const apply = [];
|
|
798
|
-
for (const [comp, configFile] of Object.entries(componentConfigs)) {
|
|
799
|
-
if (!knownComponents.has(comp)) continue;
|
|
800
|
-
const sanitized = sanitizeFileName(String(configFile) || "default");
|
|
801
|
-
if (!import_fs2.default.existsSync(componentResource(comp).filePath(sanitized))) {
|
|
802
|
-
jsonResponse(res, 422, {
|
|
803
|
-
error: `Preset references missing config: ${comp}/${sanitized}`
|
|
804
|
-
});
|
|
805
|
-
return;
|
|
806
|
-
}
|
|
807
|
-
apply.push([comp, sanitized]);
|
|
808
|
-
}
|
|
809
|
-
themesResource.setProductionName(themeName);
|
|
810
|
-
for (const [comp, configFile] of apply) {
|
|
811
|
-
componentResource(comp).setProductionName(configFile);
|
|
812
|
-
}
|
|
813
|
-
presetsResource.setProductionName(fileName);
|
|
814
|
-
syncTokensToCss(themeName);
|
|
815
|
-
syncFontsToCss(themeName);
|
|
816
|
-
syncComponentsToCss();
|
|
817
|
-
jsonResponse(res, 200, {
|
|
818
|
-
ok: true,
|
|
819
|
-
fileName,
|
|
820
|
-
name: preset.name || fileName,
|
|
821
|
-
theme: themeName,
|
|
822
|
-
componentConfigs: Object.fromEntries(apply),
|
|
823
|
-
updatedAt: preset.updatedAt || ""
|
|
824
|
-
});
|
|
825
|
-
}
|
|
826
|
-
async function handlePresetByName({ params, req, res }) {
|
|
1289
|
+
async function handleManifestByName({ params, req, res }) {
|
|
827
1290
|
const [fileName] = params;
|
|
828
|
-
const filePath =
|
|
1291
|
+
const filePath = manifestsResource.filePath(fileName);
|
|
829
1292
|
if (req.method === "GET") {
|
|
830
1293
|
if (!import_fs2.default.existsSync(filePath)) {
|
|
831
1294
|
jsonResponse(res, 404, { error: "Not found" });
|
|
@@ -838,7 +1301,7 @@ ${COMPONENT_OVERRIDES_END}
|
|
|
838
1301
|
}
|
|
839
1302
|
if (req.method === "PUT") {
|
|
840
1303
|
if (fileName === "default") {
|
|
841
|
-
jsonResponse(res, 403, { error: "Cannot overwrite the default
|
|
1304
|
+
jsonResponse(res, 403, { error: "Cannot overwrite the default manifest" });
|
|
842
1305
|
return;
|
|
843
1306
|
}
|
|
844
1307
|
const body = JSON.parse(await readBody(req));
|
|
@@ -857,35 +1320,35 @@ ${COMPONENT_OVERRIDES_END}
|
|
|
857
1320
|
}
|
|
858
1321
|
if (req.method === "DELETE") {
|
|
859
1322
|
if (fileName === "default") {
|
|
860
|
-
jsonResponse(res, 403, { error: "Cannot delete the default
|
|
1323
|
+
jsonResponse(res, 403, { error: "Cannot delete the default manifest" });
|
|
861
1324
|
return;
|
|
862
1325
|
}
|
|
863
1326
|
if (import_fs2.default.existsSync(filePath)) {
|
|
864
1327
|
import_fs2.default.unlinkSync(filePath);
|
|
865
|
-
if (
|
|
866
|
-
|
|
1328
|
+
if (manifestsResource.getActiveName() === fileName) {
|
|
1329
|
+
manifestsResource.setActiveName("default");
|
|
867
1330
|
}
|
|
868
1331
|
}
|
|
869
1332
|
jsonResponse(res, 200, { ok: true });
|
|
870
1333
|
return;
|
|
871
1334
|
}
|
|
872
1335
|
}
|
|
873
|
-
async function
|
|
1336
|
+
async function handleApplyManifest({ params, res }) {
|
|
874
1337
|
const [fileName] = params;
|
|
875
|
-
const
|
|
876
|
-
if (!import_fs2.default.existsSync(
|
|
877
|
-
jsonResponse(res, 404, { error: "
|
|
1338
|
+
const manifestPath = manifestsResource.filePath(fileName);
|
|
1339
|
+
if (!import_fs2.default.existsSync(manifestPath)) {
|
|
1340
|
+
jsonResponse(res, 404, { error: "Manifest not found" });
|
|
878
1341
|
return;
|
|
879
1342
|
}
|
|
880
|
-
const
|
|
881
|
-
const themeName = sanitizeFileName(
|
|
1343
|
+
const manifest = JSON.parse(import_fs2.default.readFileSync(manifestPath, "utf-8"));
|
|
1344
|
+
const themeName = sanitizeFileName(manifest.theme || "default");
|
|
882
1345
|
const themePath = themesResource.filePath(themeName);
|
|
883
1346
|
if (!import_fs2.default.existsSync(themePath)) {
|
|
884
|
-
jsonResponse(res, 422, { error: `
|
|
1347
|
+
jsonResponse(res, 422, { error: `Manifest references missing theme: ${themeName}` });
|
|
885
1348
|
return;
|
|
886
1349
|
}
|
|
887
1350
|
const knownComponents = new Set(listComponentNames());
|
|
888
|
-
const componentConfigs =
|
|
1351
|
+
const componentConfigs = manifest.componentConfigs ?? {};
|
|
889
1352
|
const resolvedConfigs = {};
|
|
890
1353
|
const apply = [];
|
|
891
1354
|
for (const [comp, configFile] of Object.entries(componentConfigs)) {
|
|
@@ -895,18 +1358,22 @@ ${COMPONENT_OVERRIDES_END}
|
|
|
895
1358
|
const cfgPath = r.filePath(sanitized);
|
|
896
1359
|
if (!import_fs2.default.existsSync(cfgPath)) {
|
|
897
1360
|
jsonResponse(res, 422, {
|
|
898
|
-
error: `
|
|
1361
|
+
error: `Manifest references missing config: ${comp}/${sanitized}`
|
|
899
1362
|
});
|
|
900
1363
|
return;
|
|
901
1364
|
}
|
|
902
1365
|
apply.push([comp, sanitized]);
|
|
903
1366
|
}
|
|
904
1367
|
themesResource.setActiveName(themeName);
|
|
905
|
-
|
|
1368
|
+
themesResource.setProductionName(themeName);
|
|
1369
|
+
syncTokensToCss(themeName);
|
|
1370
|
+
syncFontsToCss(themeName);
|
|
1371
|
+
const themeData = normalizeTheme(JSON.parse(import_fs2.default.readFileSync(themePath, "utf-8")));
|
|
906
1372
|
themeData._fileName = themeName;
|
|
907
1373
|
for (const [comp, configFile] of apply) {
|
|
908
1374
|
const r = componentResource(comp);
|
|
909
1375
|
r.setActiveName(configFile);
|
|
1376
|
+
r.setProductionName(configFile);
|
|
910
1377
|
const cfg = readComponentConfig(comp, configFile);
|
|
911
1378
|
if (cfg) resolvedConfigs[comp] = { ...cfg, _fileName: configFile };
|
|
912
1379
|
}
|
|
@@ -916,14 +1383,166 @@ ${COMPONENT_OVERRIDES_END}
|
|
|
916
1383
|
const cfg = readComponentConfig(comp, activeName);
|
|
917
1384
|
if (cfg) resolvedConfigs[comp] = { ...cfg, _fileName: activeName };
|
|
918
1385
|
}
|
|
919
|
-
|
|
1386
|
+
syncComponentsToCss();
|
|
1387
|
+
manifestsResource.setActiveName(fileName);
|
|
920
1388
|
jsonResponse(res, 200, {
|
|
921
1389
|
ok: true,
|
|
922
|
-
|
|
1390
|
+
manifest: { ...manifest, _fileName: fileName },
|
|
923
1391
|
theme: themeData,
|
|
924
1392
|
componentConfigs: resolvedConfigs
|
|
925
1393
|
});
|
|
926
1394
|
}
|
|
1395
|
+
async function handleExportManifest({ params, res }) {
|
|
1396
|
+
const [fileName] = params;
|
|
1397
|
+
const manifestPath = manifestsResource.filePath(fileName);
|
|
1398
|
+
if (!import_fs2.default.existsSync(manifestPath)) {
|
|
1399
|
+
jsonResponse(res, 404, { error: "Manifest not found" });
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
const manifest = JSON.parse(import_fs2.default.readFileSync(manifestPath, "utf-8"));
|
|
1403
|
+
const themeName = sanitizeFileName(manifest.theme || "default");
|
|
1404
|
+
const themePath = themesResource.filePath(themeName);
|
|
1405
|
+
if (!import_fs2.default.existsSync(themePath)) {
|
|
1406
|
+
jsonResponse(res, 422, { error: `Manifest references missing theme: ${themeName}` });
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
const theme = JSON.parse(import_fs2.default.readFileSync(themePath, "utf-8"));
|
|
1410
|
+
const knownComponents = new Set(listComponentNames());
|
|
1411
|
+
const componentConfigs = {};
|
|
1412
|
+
for (const [comp, configFile] of Object.entries(manifest.componentConfigs ?? {})) {
|
|
1413
|
+
if (!knownComponents.has(comp)) continue;
|
|
1414
|
+
const sanitized = sanitizeFileName(String(configFile) || "default");
|
|
1415
|
+
if (sanitized === "default") continue;
|
|
1416
|
+
const cfgPath = componentResource(comp).filePath(sanitized);
|
|
1417
|
+
if (!import_fs2.default.existsSync(cfgPath)) {
|
|
1418
|
+
jsonResponse(res, 422, {
|
|
1419
|
+
error: `Manifest references missing config: ${comp}/${sanitized}`
|
|
1420
|
+
});
|
|
1421
|
+
return;
|
|
1422
|
+
}
|
|
1423
|
+
const cfg = JSON.parse(import_fs2.default.readFileSync(cfgPath, "utf-8"));
|
|
1424
|
+
componentConfigs[`${comp}/${sanitized}`] = cfg;
|
|
1425
|
+
}
|
|
1426
|
+
const bundle = {
|
|
1427
|
+
kind: "manifest-bundle",
|
|
1428
|
+
schemaVersion: 1,
|
|
1429
|
+
liveTokensVersion: PKG_VERSION,
|
|
1430
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1431
|
+
manifest,
|
|
1432
|
+
theme,
|
|
1433
|
+
componentConfigs
|
|
1434
|
+
};
|
|
1435
|
+
res.statusCode = 200;
|
|
1436
|
+
res.setHeader("Content-Type", "application/json");
|
|
1437
|
+
res.setHeader(
|
|
1438
|
+
"Content-Disposition",
|
|
1439
|
+
`attachment; filename="${fileName}.bundle.json"`
|
|
1440
|
+
);
|
|
1441
|
+
res.end(JSON.stringify(bundle, null, 2));
|
|
1442
|
+
}
|
|
1443
|
+
function nextAvailableName2(resourceFilePath, baseName) {
|
|
1444
|
+
return nextAvailableName(
|
|
1445
|
+
(n) => import_fs2.default.existsSync(resourceFilePath(n)),
|
|
1446
|
+
sanitizeFileName(baseName)
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1449
|
+
async function handleImportManifest({ req, res }) {
|
|
1450
|
+
let bundle;
|
|
1451
|
+
try {
|
|
1452
|
+
bundle = JSON.parse(await readBody(req));
|
|
1453
|
+
} catch {
|
|
1454
|
+
jsonResponse(res, 400, { error: "Body is not valid JSON" });
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1457
|
+
if (!bundle || bundle.kind !== "manifest-bundle") {
|
|
1458
|
+
jsonResponse(res, 400, {
|
|
1459
|
+
error: "Not a manifest bundle (kind discriminator missing or wrong)"
|
|
1460
|
+
});
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1463
|
+
if (bundle.schemaVersion !== 1) {
|
|
1464
|
+
jsonResponse(res, 400, {
|
|
1465
|
+
error: `Unsupported bundle schemaVersion: ${bundle.schemaVersion}`
|
|
1466
|
+
});
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
if (!bundle.manifest || !bundle.theme || !bundle.componentConfigs) {
|
|
1470
|
+
jsonResponse(res, 400, { error: "Bundle missing manifest / theme / componentConfigs" });
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
const renames = {};
|
|
1474
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1475
|
+
const originalThemeName = sanitizeFileName(bundle.manifest.theme || "default");
|
|
1476
|
+
const finalThemeName = nextAvailableName2(
|
|
1477
|
+
(n) => themesResource.filePath(n),
|
|
1478
|
+
originalThemeName
|
|
1479
|
+
);
|
|
1480
|
+
if (finalThemeName !== originalThemeName) {
|
|
1481
|
+
renames[`theme:${originalThemeName}`] = finalThemeName;
|
|
1482
|
+
}
|
|
1483
|
+
const themeBody = { ...bundle.theme };
|
|
1484
|
+
themeBody.updatedAt = now;
|
|
1485
|
+
if (!themeBody.createdAt) themeBody.createdAt = now;
|
|
1486
|
+
themesResource.ensureDir();
|
|
1487
|
+
import_fs2.default.writeFileSync(themesResource.filePath(finalThemeName), JSON.stringify(themeBody, null, 2));
|
|
1488
|
+
const knownComponents = new Set(listComponentNames());
|
|
1489
|
+
const componentRenames = {};
|
|
1490
|
+
for (const [key, cfgValue] of Object.entries(bundle.componentConfigs)) {
|
|
1491
|
+
const [comp, originalName] = key.split("/");
|
|
1492
|
+
if (!comp || !originalName) continue;
|
|
1493
|
+
if (!knownComponents.has(comp)) continue;
|
|
1494
|
+
const r = componentResource(comp);
|
|
1495
|
+
const finalName = nextAvailableName2(
|
|
1496
|
+
(n) => r.filePath(n),
|
|
1497
|
+
originalName
|
|
1498
|
+
);
|
|
1499
|
+
if (finalName !== originalName) {
|
|
1500
|
+
renames[`componentConfig:${comp}/${originalName}`] = finalName;
|
|
1501
|
+
}
|
|
1502
|
+
componentRenames[`${comp}/${originalName}`] = finalName;
|
|
1503
|
+
const cfgBody = { ...cfgValue };
|
|
1504
|
+
cfgBody.component = comp;
|
|
1505
|
+
cfgBody.name = finalName;
|
|
1506
|
+
cfgBody.updatedAt = now;
|
|
1507
|
+
if (!cfgBody.createdAt) cfgBody.createdAt = now;
|
|
1508
|
+
r.ensureDir();
|
|
1509
|
+
import_fs2.default.writeFileSync(r.filePath(finalName), JSON.stringify(cfgBody, null, 2));
|
|
1510
|
+
}
|
|
1511
|
+
const rewrittenManifest = {
|
|
1512
|
+
...bundle.manifest,
|
|
1513
|
+
theme: finalThemeName,
|
|
1514
|
+
componentConfigs: {}
|
|
1515
|
+
};
|
|
1516
|
+
for (const [comp, configName] of Object.entries(bundle.manifest.componentConfigs ?? {})) {
|
|
1517
|
+
const original = String(configName);
|
|
1518
|
+
if (original === "default") {
|
|
1519
|
+
rewrittenManifest.componentConfigs[comp] = "default";
|
|
1520
|
+
continue;
|
|
1521
|
+
}
|
|
1522
|
+
const finalName = componentRenames[`${comp}/${original}`] ?? original;
|
|
1523
|
+
rewrittenManifest.componentConfigs[comp] = finalName;
|
|
1524
|
+
}
|
|
1525
|
+
rewrittenManifest.updatedAt = now;
|
|
1526
|
+
if (!rewrittenManifest.createdAt) rewrittenManifest.createdAt = now;
|
|
1527
|
+
const originalManifestName = sanitizeFileName(bundle.manifest.name || "imported");
|
|
1528
|
+
const finalManifestName = nextAvailableName2(
|
|
1529
|
+
(n) => manifestsResource.filePath(n),
|
|
1530
|
+
originalManifestName
|
|
1531
|
+
);
|
|
1532
|
+
if (finalManifestName !== originalManifestName) {
|
|
1533
|
+
renames[`manifest:${originalManifestName}`] = finalManifestName;
|
|
1534
|
+
}
|
|
1535
|
+
manifestsResource.ensureDir();
|
|
1536
|
+
import_fs2.default.writeFileSync(
|
|
1537
|
+
manifestsResource.filePath(finalManifestName),
|
|
1538
|
+
JSON.stringify(rewrittenManifest, null, 2)
|
|
1539
|
+
);
|
|
1540
|
+
jsonResponse(res, 200, {
|
|
1541
|
+
ok: true,
|
|
1542
|
+
manifest: finalManifestName,
|
|
1543
|
+
renames
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
927
1546
|
function methodNotAllowed({ res }) {
|
|
928
1547
|
jsonResponse(res, 405, { error: "Method not allowed" });
|
|
929
1548
|
}
|
|
@@ -957,21 +1576,29 @@ ${COMPONENT_OVERRIDES_END}
|
|
|
957
1576
|
{ method: "GET", pattern: THEME_BY_NAME_REGEX, handler: handleThemeByName },
|
|
958
1577
|
{ method: "PUT", pattern: THEME_BY_NAME_REGEX, handler: handleThemeByName },
|
|
959
1578
|
{ method: "DELETE", pattern: THEME_BY_NAME_REGEX, handler: handleThemeByName },
|
|
960
|
-
//
|
|
961
|
-
{ method: "GET", pattern:
|
|
962
|
-
{ method: "GET", pattern:
|
|
963
|
-
{ method: "PUT", pattern:
|
|
964
|
-
|
|
965
|
-
{ method: "
|
|
966
|
-
|
|
967
|
-
{ method: "
|
|
968
|
-
{ method: "
|
|
969
|
-
|
|
970
|
-
{ method: "
|
|
971
|
-
|
|
972
|
-
{ method: "GET", pattern:
|
|
973
|
-
{ method: "
|
|
974
|
-
|
|
1579
|
+
// Manifests — list / active are exact strings, must run before regexes
|
|
1580
|
+
{ method: "GET", pattern: MANIFESTS_ROUTE, handler: handleListManifests },
|
|
1581
|
+
{ method: "GET", pattern: MANIFESTS_ACTIVE_ROUTE, handler: handleGetActiveManifest },
|
|
1582
|
+
{ method: "PUT", pattern: MANIFESTS_ACTIVE_ROUTE, handler: handleSetActiveManifest },
|
|
1583
|
+
// Manifests — exact import route runs before :name regexes
|
|
1584
|
+
{ method: "POST", pattern: MANIFEST_IMPORT_ROUTE, handler: handleImportManifest },
|
|
1585
|
+
{ method: "PUT", pattern: MANIFEST_IMPORT_ROUTE, handler: methodNotAllowed },
|
|
1586
|
+
{ method: "GET", pattern: MANIFEST_IMPORT_ROUTE, handler: methodNotAllowed },
|
|
1587
|
+
{ method: "DELETE", pattern: MANIFEST_IMPORT_ROUTE, handler: methodNotAllowed },
|
|
1588
|
+
// Manifests — :name/apply (more specific than :name)
|
|
1589
|
+
{ method: "PUT", pattern: MANIFEST_APPLY_REGEX, handler: handleApplyManifest },
|
|
1590
|
+
{ method: "POST", pattern: MANIFEST_APPLY_REGEX, handler: methodNotAllowed },
|
|
1591
|
+
{ method: "GET", pattern: MANIFEST_APPLY_REGEX, handler: methodNotAllowed },
|
|
1592
|
+
{ method: "DELETE", pattern: MANIFEST_APPLY_REGEX, handler: methodNotAllowed },
|
|
1593
|
+
// Manifests — :name/export (more specific than :name)
|
|
1594
|
+
{ method: "GET", pattern: MANIFEST_EXPORT_REGEX, handler: handleExportManifest },
|
|
1595
|
+
{ method: "PUT", pattern: MANIFEST_EXPORT_REGEX, handler: methodNotAllowed },
|
|
1596
|
+
{ method: "POST", pattern: MANIFEST_EXPORT_REGEX, handler: methodNotAllowed },
|
|
1597
|
+
{ method: "DELETE", pattern: MANIFEST_EXPORT_REGEX, handler: methodNotAllowed },
|
|
1598
|
+
// Manifests — :name CRUD (broadest manifest route, runs last)
|
|
1599
|
+
{ method: "GET", pattern: MANIFEST_BY_NAME_REGEX, handler: handleManifestByName },
|
|
1600
|
+
{ method: "PUT", pattern: MANIFEST_BY_NAME_REGEX, handler: handleManifestByName },
|
|
1601
|
+
{ method: "DELETE", pattern: MANIFEST_BY_NAME_REGEX, handler: handleManifestByName }
|
|
975
1602
|
];
|
|
976
1603
|
return {
|
|
977
1604
|
name: "theme-file-api",
|
|
@@ -986,7 +1613,8 @@ ${COMPONENT_OVERRIDES_END}
|
|
|
986
1613
|
configureServer(server) {
|
|
987
1614
|
ensureThemesDir();
|
|
988
1615
|
ensureComponentConfigsDir();
|
|
989
|
-
|
|
1616
|
+
ensureManifestsDir();
|
|
1617
|
+
regenerateTokensCss();
|
|
990
1618
|
server.middlewares.use(async (req, res, next) => {
|
|
991
1619
|
const handled = await dispatch(req, res, routes);
|
|
992
1620
|
if (!handled) next();
|