@motion-proto/live-tokens 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -13
- package/dist-plugin/index.cjs +147 -136
- package/dist-plugin/index.d.cts +1 -1
- package/dist-plugin/index.d.ts +1 -1
- package/dist-plugin/index.js +145 -135
- package/package.json +25 -40
- 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 +3 -3
- 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 +64 -37
- package/src/{component-editor → editor/component-editor}/ProgressBarEditor.svelte +5 -4
- package/src/{component-editor → editor/component-editor}/RadioButtonEditor.svelte +3 -3
- package/src/{component-editor → editor/component-editor}/SectionDividerEditor.svelte +57 -84
- package/src/{component-editor → editor/component-editor}/SegmentedControlEditor.svelte +2 -2
- package/src/{component-editor → editor/component-editor}/StandardButtonsEditor.svelte +16 -20
- 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/{component-editor → editor/component-editor}/registry.ts +28 -18
- package/src/{component-editor → editor/component-editor}/scaffolding/AngleDial.svelte +2 -2
- package/src/{component-editor → editor/component-editor}/scaffolding/ComponentEditorBase.svelte +3 -51
- package/src/{component-editor → editor/component-editor}/scaffolding/ComponentFileManager.svelte +144 -416
- 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/DividerEditor.svelte +1 -1
- package/src/{component-editor → editor/component-editor}/scaffolding/FieldsetWrapper.svelte +1 -1
- package/src/{component-editor → editor/component-editor}/scaffolding/GradientCard.svelte +6 -6
- package/src/{component-editor → editor/component-editor}/scaffolding/LinkageChart.svelte +6 -6
- package/src/{component-editor → editor/component-editor}/scaffolding/LinkedBlock.svelte +6 -11
- package/src/editor/component-editor/scaffolding/NonStylableConfig.svelte +38 -0
- package/src/{component-editor → editor/component-editor}/scaffolding/SaveAsDialog.svelte +66 -12
- package/src/editor/component-editor/scaffolding/ShadowBackdrop.svelte +72 -0
- package/src/editor/component-editor/scaffolding/ShadowBackdropControls.svelte +132 -0
- package/src/editor/component-editor/scaffolding/StateBlock.svelte +257 -0
- package/src/{component-editor → editor/component-editor}/scaffolding/TokenLayout.svelte +9 -7
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +644 -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 +14 -0
- package/src/{lib → editor/core/components}/componentConfigService.ts +2 -2
- package/src/{lib → editor/core/components}/componentPersist.ts +5 -5
- 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 +116 -0
- package/src/{lib → editor/core/palettes}/paletteDerivation.ts +2 -2
- package/src/{lib → editor/core/palettes}/tokenRegistry.ts +5 -5
- 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 +17 -17
- package/src/{lib → editor/core/store}/editorTypes.ts +1 -1
- package/src/{lib → editor/core/themes}/slices/columns.ts +2 -2
- package/src/{lib → editor/core/themes}/slices/components.ts +2 -2
- package/src/{lib → editor/core/themes}/slices/fonts.ts +1 -1
- package/src/{lib → editor/core/themes}/slices/gradients.ts +2 -2
- 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 +6 -6
- package/src/{lib → editor/core/themes}/themeService.ts +6 -6
- package/src/{lib → editor/core/themes}/themeTypes.ts +11 -7
- package/src/editor/index.ts +69 -0
- package/src/{lib → editor/overlay}/LiveEditorOverlay.svelte +79 -125
- 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 +41 -21
- package/src/{styles → editor/styles}/ui-form-controls.css +8 -8
- package/src/{ui → editor/ui}/BezierCurveEditor.svelte +8 -8
- package/src/{ui → editor/ui}/ColorEditPanel.svelte +13 -13
- package/src/{ui → editor/ui}/EditorViewSwitcher.svelte +8 -6
- package/src/editor/ui/FileLoadList.svelte +350 -0
- package/src/editor/ui/FilePill.svelte +80 -0
- package/src/{ui → editor/ui}/FontStackEditor.svelte +7 -7
- package/src/{ui → editor/ui}/GradientEditor.svelte +11 -11
- package/src/{ui → editor/ui}/GradientStopPicker.svelte +1 -1
- package/src/editor/ui/ManifestFileManager.svelte +371 -0
- package/src/{ui → editor/ui}/PaletteEditor.svelte +132 -598
- package/src/{ui → editor/ui}/ProjectFontsSection.svelte +102 -144
- package/src/{ui → editor/ui}/SurfacesTab.svelte +3 -3
- package/src/{ui → editor/ui}/TextTab.svelte +3 -3
- package/src/{ui → editor/ui}/ThemeFileManager.svelte +286 -519
- package/src/{ui → editor/ui}/UICopyPopover.svelte +4 -4
- package/src/{ui → editor/ui}/UIFontFamilySelector.svelte +6 -6
- package/src/{ui → editor/ui}/UIFontSizeSelector.svelte +1 -1
- package/src/editor/ui/UIInfoPopover.svelte +244 -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 +26 -26
- package/src/editor/ui/UIPillButton.svelte +138 -0
- package/src/{ui → editor/ui}/UIRadio.svelte +2 -2
- package/src/{ui → editor/ui}/UIRelinkConfirmPopover.svelte +4 -4
- package/src/editor/ui/UISquareButton.svelte +172 -0
- package/src/{ui → editor/ui}/UITokenSelector.svelte +10 -10
- package/src/{ui → editor/ui}/UIVariantSelector.svelte +1 -1
- package/src/{ui → editor/ui}/VariablesTab.svelte +31 -8
- package/src/{ui → editor/ui}/palette/GradientStopEditor.svelte +13 -13
- package/src/{ui → editor/ui}/palette/OverridesPanel.svelte +13 -13
- package/src/{ui → editor/ui}/palette/PaletteBase.svelte +8 -5
- 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 -17
- package/src/{ui → editor/ui}/sections/GradientsSection.svelte +7 -7
- package/src/{ui → editor/ui}/sections/OverlaysSection.svelte +17 -17
- package/src/{ui → editor/ui}/sections/ShadowsSection.svelte +22 -22
- package/src/{ui → editor/ui}/sections/TokenScaleTable.svelte +3 -3
- package/src/{components → system/components}/Badge.svelte +0 -36
- package/src/{components → system/components}/Card.svelte +8 -62
- package/src/{components → system/components}/CornerBadge.svelte +8 -24
- package/src/{components → system/components}/Dialog.svelte +1 -1
- package/src/system/components/FloatingTokenTags.css +256 -0
- package/src/system/components/FloatingTokenTags.svelte +592 -0
- package/src/{components → system/components}/InlineEditActions.svelte +6 -4
- package/src/system/components/MenuSelect.svelte +229 -0
- package/src/{components → system/components}/ProgressBar.svelte +29 -11
- 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/{styles → system/styles}/fonts.css +6 -3
- package/src/{styles → system/styles}/tokens.css +149 -29
- package/src/component-editor/ImageEditor.svelte +0 -74
- 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/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/ui/PresetFileManager.svelte +0 -1116
- package/src/ui/UnsavedComponentsDialog.svelte +0 -315
- /package/src/{styles → app}/site.css +0 -0
- /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/TypeEditor.svelte +0 -0
- /package/src/{component-editor → editor/component-editor}/scaffolding/buildTypeGroupTokens.ts +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/components}/componentConfigKeys.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}/migrations/index.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}/ColumnsOverlay.svelte +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}/Button.svelte +0 -0
- /package/src/{components → system/components}/Callout.svelte +0 -0
- /package/src/{components → system/components}/CollapsibleSection.svelte +0 -0
- /package/src/{components → system/components}/Image.svelte +0 -0
- /package/src/{components → system/components}/Notification.svelte +0 -0
- /package/src/{components → system/components}/RadioButton.svelte +0 -0
- /package/src/{components → system/components}/SectionDivider.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
|
@@ -3,22 +3,31 @@
|
|
|
3
3
|
|
|
4
4
|
const bubble = createBubbler();
|
|
5
5
|
import { onMount, onDestroy, tick } from 'svelte';
|
|
6
|
-
import { hexToOklch
|
|
7
|
-
import { type CurveAnchor,
|
|
6
|
+
import { hexToOklch } from '../core/palettes/oklch';
|
|
7
|
+
import { type CurveAnchor, lightnessCurveConfig, saturationCurveConfig } from './curveEngine';
|
|
8
8
|
import ColorEditPanel from './ColorEditPanel.svelte';
|
|
9
9
|
import OverridesPanel from './palette/OverridesPanel.svelte';
|
|
10
10
|
import GradientStopEditor from './palette/GradientStopEditor.svelte';
|
|
11
11
|
import ScaleCurveEditor from './palette/ScaleCurveEditor.svelte';
|
|
12
12
|
import PaletteBase from './palette/PaletteBase.svelte';
|
|
13
13
|
import { type EditingState, idleState, BASE_KEY, isEditingBase as isBaseEdit } from './palette/paletteEditorState';
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
import {
|
|
15
|
+
type Step, type Scale, type GrayStep, type CurveOffset, type ScaleCurves,
|
|
16
|
+
GRAY_FALLBACK, DEFAULT_TINT_CHROMA,
|
|
17
|
+
DEFAULT_PALETTE_LIGHTNESS, DEFAULT_PALETTE_SATURATION, DEFAULT_GRAY_LIGHTNESS, DEFAULT_GRAY_SATURATION,
|
|
18
|
+
defaultScaleCurves, defaultScaleCurvesObject,
|
|
19
|
+
paletteStepLightness, graySteps, scales,
|
|
20
|
+
paletteStepKey, grayStepKey, stepKey, scaleCurveKey as getScaleCurveKey,
|
|
21
|
+
stepIndexToX,
|
|
22
|
+
injectLockedAnchor, removeLockedAnchor,
|
|
23
|
+
computeGrayColor as computeGrayColorPure,
|
|
24
|
+
computePaletteColor as computePaletteColorPure,
|
|
25
|
+
computeDerivedColor as computeDerivedColorPure,
|
|
26
|
+
snapScaleToPalette as snapScaleToPalettePure,
|
|
27
|
+
} from './palette/paletteMath';
|
|
28
|
+
import type { PaletteConfig, GradientStop } from '../core/themes/themeTypes';
|
|
29
|
+
import { editorState, mutate, setPaletteConfig, beginSliderGesture, beginScope, commitScope, cancelScope, type Scope } from '../core/store/editorStore';
|
|
30
|
+
import { showCopyPopover } from './copyPopover';
|
|
22
31
|
|
|
23
32
|
interface Props {
|
|
24
33
|
label: string;
|
|
@@ -56,14 +65,6 @@
|
|
|
56
65
|
};
|
|
57
66
|
}
|
|
58
67
|
|
|
59
|
-
function defaultScaleCurvesObject() {
|
|
60
|
-
return {
|
|
61
|
-
Surfaces: { lightness: defaultScaleCurves.Surfaces.lightness(), saturation: defaultScaleCurves.Surfaces.saturation() },
|
|
62
|
-
Borders: { lightness: defaultScaleCurves.Borders.lightness(), saturation: defaultScaleCurves.Borders.saturation() },
|
|
63
|
-
Text: { lightness: defaultScaleCurves.Text.lightness(), saturation: defaultScaleCurves.Text.saturation() },
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
68
|
function edit<K extends keyof PaletteConfig>(field: K, value: PaletteConfig[K]): void {
|
|
68
69
|
mutate(`${label}: ${String(field)}`, (s) => {
|
|
69
70
|
if (!s.palettes[label]) s.palettes[label] = defaultPaletteConfig();
|
|
@@ -78,16 +79,17 @@
|
|
|
78
79
|
});
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
// --- Transient UI state (not persisted; not in PaletteConfig) ---
|
|
82
82
|
let lockedLightnessIdx: number | null = $state(null);
|
|
83
83
|
let lockedSaturationIdx: number | null = $state(null);
|
|
84
84
|
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
// scope so the inline header-swatch handlers and the function handlers
|
|
88
|
-
// share the same handle for commitScope/cancelScope.
|
|
85
|
+
// Held at component scope so inline header-swatch handlers and the function
|
|
86
|
+
// handlers share one handle for commit/cancel.
|
|
89
87
|
let paletteEditScope: Scope | null = null;
|
|
90
88
|
|
|
89
|
+
function openSession() {
|
|
90
|
+
paletteEditScope = beginScope({ label: 'palette session', collapseToOne: true, clipUndoFloor: true });
|
|
91
|
+
}
|
|
92
|
+
|
|
91
93
|
function stopColor(stop: GradientStop, pc: typeof paletteComputed): string {
|
|
92
94
|
const ps = pc?.find(p => p.label === stop.paletteLabel);
|
|
93
95
|
return ps ? ps.effective : '#000000';
|
|
@@ -101,133 +103,34 @@
|
|
|
101
103
|
edit('emptyMode', (e.currentTarget as HTMLInputElement).checked ? 'gradient' : 'solid');
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
// --- Gray mode ---
|
|
105
|
-
|
|
106
|
-
interface GrayStep {
|
|
107
|
-
label: string;
|
|
108
|
-
hue: number;
|
|
109
|
-
saturation: number;
|
|
110
|
-
lightness: number;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const graySteps: GrayStep[] = [
|
|
114
|
-
{ label: '100', hue: 240, saturation: 5, lightness: 92 },
|
|
115
|
-
{ label: '200', hue: 220, saturation: 13, lightness: 84 },
|
|
116
|
-
{ label: '300', hue: 216, saturation: 12, lightness: 72 },
|
|
117
|
-
{ label: '400', hue: 240, saturation: 5, lightness: 61 },
|
|
118
|
-
{ label: '500', hue: 240, saturation: 5, lightness: 50 },
|
|
119
|
-
{ label: '600', hue: 240, saturation: 5, lightness: 42 },
|
|
120
|
-
{ label: '700', hue: 240, saturation: 5, lightness: 34 },
|
|
121
|
-
{ label: '800', hue: 240, saturation: 10, lightness: 25 },
|
|
122
|
-
{ label: '850', hue: 229, saturation: 20, lightness: 18 },
|
|
123
|
-
{ label: '900', hue: 240, saturation: 30, lightness: 10 },
|
|
124
|
-
{ label: '950', hue: 229, saturation: 34, lightness: 3 },
|
|
125
|
-
];
|
|
126
|
-
|
|
127
106
|
let grayEditorOpen = $state(false);
|
|
128
107
|
let showDerived = $state(false);
|
|
129
|
-
|
|
130
|
-
// --- Palette curve editors (lightness + saturation) ---
|
|
131
108
|
let paletteEditorOpen = $state(false);
|
|
132
109
|
|
|
133
|
-
// Default curve anchors (used for initial state and reset)
|
|
134
|
-
const DEFAULT_PALETTE_LIGHTNESS = () => [makeAnchor(0, 95, 5), makeAnchor(100, 8, 5)];
|
|
135
|
-
const DEFAULT_PALETTE_SATURATION = () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)];
|
|
136
|
-
const DEFAULT_GRAY_LIGHTNESS = () => [makeAnchor(0, 92, 5), makeAnchor(100, 3, 5)];
|
|
137
|
-
const DEFAULT_GRAY_SATURATION = () => [makeAnchor(0, 20, 30), makeAnchor(100, 20, 30)];
|
|
138
|
-
|
|
139
110
|
function setLightnessCurve(a: CurveAnchor[]) { edit('lightnessCurve', a); }
|
|
140
111
|
function setSaturationCurve(a: CurveAnchor[]) { edit('saturationCurve', a); }
|
|
141
112
|
function setGrayLightnessCurve(a: CurveAnchor[]) { edit('grayLightnessCurve', a); }
|
|
142
113
|
function setGraySaturationCurve(a: CurveAnchor[]) { edit('graySaturationCurve', a); }
|
|
143
114
|
|
|
144
|
-
// --- Curve offset + clipboard (shared across all curve editors) ---
|
|
145
|
-
|
|
146
115
|
function handleOffset(key: string, value: number) {
|
|
147
116
|
edit('curveOffset', { ...curveOffset, [key]: value });
|
|
148
117
|
}
|
|
149
118
|
|
|
150
|
-
// Gray step index to curve x-position
|
|
151
|
-
function grayStepToX(index: number): number {
|
|
152
|
-
return graySteps.length > 1 ? (index / (graySteps.length - 1)) * 100 : 50;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Base chroma for gray tinting (editable via the color panel's chroma slider)
|
|
156
|
-
const DEFAULT_TINT_CHROMA = 0.04;
|
|
157
|
-
|
|
158
|
-
// --- Editing-state machine (M4 fold) ---
|
|
159
|
-
//
|
|
160
|
-
// Single discriminated union replaces five independent `let` decls
|
|
161
|
-
// (`editingKey`, `editingSnapshot`, `editingDraft`, `snapshotTintHue`,
|
|
162
|
-
// `snapshotTintChroma`). The compatibility `$:` derivations below preserve
|
|
163
|
-
// existing read sites while writes go through `editing = { kind: ... }`.
|
|
164
119
|
let editing: EditingState = $state(idleState);
|
|
165
120
|
|
|
121
|
+
let injectedLightness = false;
|
|
122
|
+
let injectedSaturation = false;
|
|
166
123
|
|
|
167
124
|
function computeGrayColor(index: number, hue: number, chroma: number = tintChroma): string {
|
|
168
|
-
|
|
169
|
-
const lOff = curveOffset['gray-lightness'] ?? 0;
|
|
170
|
-
const sOff = curveOffset['gray-saturation'] ?? 0;
|
|
171
|
-
|
|
172
|
-
const targetL = Math.max(0, Math.min(100, sampleCurve(grayLightnessCurve, xPos) + lOff)) / 100;
|
|
173
|
-
const satMul = Math.max(0, Math.min(2, (sampleCurve(graySaturationCurve, xPos) + sOff) / 100));
|
|
174
|
-
const targetC = chroma * satMul;
|
|
175
|
-
|
|
176
|
-
const clamped = gamutClamp(targetL, targetC, hue);
|
|
177
|
-
return oklchToHex(clamped.l, clamped.c, clamped.h);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function grayStepKey(label: string): string {
|
|
181
|
-
return `gray-${label}`;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
// --- Chromatic palette steps ---
|
|
189
|
-
|
|
190
|
-
const paletteStepLightness = [
|
|
191
|
-
{ label: '100', lightness: 95 },
|
|
192
|
-
{ label: '200', lightness: 88 },
|
|
193
|
-
{ label: '300', lightness: 78 },
|
|
194
|
-
{ label: '400', lightness: 68 },
|
|
195
|
-
{ label: '500', lightness: 57 },
|
|
196
|
-
{ label: '600', lightness: 49 },
|
|
197
|
-
{ label: '700', lightness: 41 },
|
|
198
|
-
{ label: '800', lightness: 32 },
|
|
199
|
-
{ label: '850', lightness: 25 },
|
|
200
|
-
{ label: '900', lightness: 17 },
|
|
201
|
-
{ label: '950', lightness: 8 },
|
|
202
|
-
];
|
|
203
|
-
|
|
204
|
-
function paletteStepKey(label: string): string {
|
|
205
|
-
return `Palette-${label}`;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function stepIndexToX(index: number): number {
|
|
209
|
-
return (index / (paletteStepLightness.length - 1)) * 100;
|
|
125
|
+
return computeGrayColorPure(index, hue, chroma, grayLightnessCurve, graySaturationCurve, curveOffset);
|
|
210
126
|
}
|
|
211
127
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
let injectedLightness = false;
|
|
215
|
-
let injectedSaturation = false;
|
|
216
|
-
|
|
217
|
-
function injectLockedAnchor(curve: CurveAnchor[], x: number, y: number): { curve: CurveAnchor[], idx: number, injected: boolean } {
|
|
218
|
-
const existing = curve.findIndex(a => Math.abs(a.x - x) < 0.5);
|
|
219
|
-
if (existing >= 0) {
|
|
220
|
-
if (curve[existing].x === x && Math.abs(curve[existing].y - y) < 0.01) return { curve, idx: existing, injected: false };
|
|
221
|
-
return { curve: curve.map((a, i) => i === existing ? { ...a, x, y } : a), idx: existing, injected: false };
|
|
222
|
-
}
|
|
223
|
-
let insertAt = curve.findIndex(a => a.x > x);
|
|
224
|
-
if (insertAt < 0) insertAt = curve.length;
|
|
225
|
-
return { curve: [...curve.slice(0, insertAt), makeAnchor(x, y, 15), ...curve.slice(insertAt)], idx: insertAt, injected: true };
|
|
128
|
+
function computePaletteColor(index: number, base: string): string {
|
|
129
|
+
return computePaletteColorPure(index, base, lightnessCurve, saturationCurve, curveOffset);
|
|
226
130
|
}
|
|
227
131
|
|
|
228
|
-
function
|
|
229
|
-
|
|
230
|
-
return curve.filter((_, i) => i !== idx);
|
|
132
|
+
function computeDerivedColor(step: Step, base: string, scaleTitle: string): string {
|
|
133
|
+
return computeDerivedColorPure(step, base, scaleTitle, scaleCurves, curveOffset);
|
|
231
134
|
}
|
|
232
135
|
|
|
233
136
|
/**
|
|
@@ -268,26 +171,12 @@
|
|
|
268
171
|
|
|
269
172
|
|
|
270
173
|
|
|
271
|
-
function computePaletteColor(index: number, base: string): string {
|
|
272
|
-
const { c: baseC, h } = hexToOklch(base);
|
|
273
|
-
const xPos = stepIndexToX(index);
|
|
274
|
-
|
|
275
|
-
const targetL = Math.max(0, Math.min(100, sampleCurve(lightnessCurve, xPos) + (curveOffset['lightness'] ?? 0))) / 100;
|
|
276
|
-
const satMul = Math.max(0, Math.min(2, (sampleCurve(saturationCurve, xPos) + (curveOffset['saturation'] ?? 0)) / 100));
|
|
277
|
-
const targetC = baseC * satMul;
|
|
278
|
-
|
|
279
|
-
const clamped = gamutClamp(targetL, targetC, h);
|
|
280
|
-
return oklchToHex(clamped.l, clamped.c, clamped.h);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
174
|
function startBaseEdit() {
|
|
286
175
|
if (editing.kind === 'editingBase') { confirmEdit(); return; }
|
|
287
176
|
editing = mode === 'gray'
|
|
288
177
|
? { kind: 'editingBase', snapshotHex: gray500Hex, snapshotTintHue: tintHue, snapshotTintChroma: tintChroma }
|
|
289
178
|
: { kind: 'editingBase', snapshotHex: baseColor, snapshotTintHue: null, snapshotTintChroma: null };
|
|
290
|
-
|
|
179
|
+
openSession();
|
|
291
180
|
}
|
|
292
181
|
|
|
293
182
|
function handlePaletteClick(ps: { label: string; lightness: number; index: number }) {
|
|
@@ -298,80 +187,9 @@
|
|
|
298
187
|
}
|
|
299
188
|
const current = (k in overrides) ? overrides[k] : computePaletteColor(ps.index, baseColor);
|
|
300
189
|
editing = { kind: 'editingStep', stepKey: k, snapshot: current, draft: current };
|
|
301
|
-
|
|
190
|
+
openSession();
|
|
302
191
|
}
|
|
303
192
|
|
|
304
|
-
// --- Scale types ---
|
|
305
|
-
|
|
306
|
-
interface Step {
|
|
307
|
-
name: string;
|
|
308
|
-
position: number;
|
|
309
|
-
lightness?: number;
|
|
310
|
-
saturation?: number;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
interface Scale {
|
|
314
|
-
title: string;
|
|
315
|
-
isText: boolean;
|
|
316
|
-
steps: Step[];
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const scales: Scale[] = [
|
|
320
|
-
{
|
|
321
|
-
title: 'Surfaces',
|
|
322
|
-
isText: false,
|
|
323
|
-
steps: [
|
|
324
|
-
{ name: 'lowest', position: -1 },
|
|
325
|
-
{ name: 'lower', position: -2/3 },
|
|
326
|
-
{ name: 'low', position: -1/3 },
|
|
327
|
-
{ name: 'default', position: 0 },
|
|
328
|
-
{ name: 'high', position: 1/3 },
|
|
329
|
-
{ name: 'higher', position: 2/3 },
|
|
330
|
-
{ name: 'highest', position: 1 },
|
|
331
|
-
]
|
|
332
|
-
},
|
|
333
|
-
{
|
|
334
|
-
title: 'Borders',
|
|
335
|
-
isText: false,
|
|
336
|
-
steps: [
|
|
337
|
-
{ name: 'faint', position: -1 },
|
|
338
|
-
{ name: 'subtle', position: -0.5 },
|
|
339
|
-
{ name: 'default', position: 0 },
|
|
340
|
-
{ name: 'medium', position: 0.5 },
|
|
341
|
-
{ name: 'strong', position: 1 },
|
|
342
|
-
]
|
|
343
|
-
},
|
|
344
|
-
{
|
|
345
|
-
title: 'Text',
|
|
346
|
-
isText: true,
|
|
347
|
-
steps: [
|
|
348
|
-
{ name: 'primary', position: 0 },
|
|
349
|
-
{ name: 'secondary', position: 0 },
|
|
350
|
-
{ name: 'tertiary', position: 0 },
|
|
351
|
-
{ name: 'muted', position: 0 },
|
|
352
|
-
{ name: 'disabled', position: 0 },
|
|
353
|
-
]
|
|
354
|
-
}
|
|
355
|
-
];
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
// --- Per-scale curve state (Surfaces & Borders) ---
|
|
359
|
-
|
|
360
|
-
const defaultScaleCurves: Record<string, { lightness: () => CurveAnchor[]; saturation: () => CurveAnchor[] }> = {
|
|
361
|
-
Surfaces: {
|
|
362
|
-
lightness: () => [makeAnchor(0, 15, 5), makeAnchor(100, 47, 5)],
|
|
363
|
-
saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)],
|
|
364
|
-
},
|
|
365
|
-
Borders: {
|
|
366
|
-
lightness: () => [makeAnchor(0, 25, 5), makeAnchor(100, 80, 5)],
|
|
367
|
-
saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)],
|
|
368
|
-
},
|
|
369
|
-
Text: {
|
|
370
|
-
lightness: () => [makeAnchor(0, 120, 30), makeAnchor(100, 55, 30)],
|
|
371
|
-
saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 15, 30)],
|
|
372
|
-
},
|
|
373
|
-
};
|
|
374
|
-
|
|
375
193
|
let scaleEditorOpen: Record<string, boolean> = $state({ Surfaces: false, Borders: false, Text: false });
|
|
376
194
|
|
|
377
195
|
function toggleScaleEditor(title: string) {
|
|
@@ -384,77 +202,9 @@
|
|
|
384
202
|
edit('scaleCurves', { ...scaleCurves, [title]: { ...cur, [channel]: a } });
|
|
385
203
|
}
|
|
386
204
|
|
|
387
|
-
function getScaleCurveKey(scaleTitle: string, channel: 'lightness' | 'saturation'): string {
|
|
388
|
-
return `${scaleTitle}-${channel}`;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
interface ScaleConfig {
|
|
392
|
-
lightnessLow: number;
|
|
393
|
-
lightnessHigh: number;
|
|
394
|
-
saturation: number;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
function configForScale(title: string): ScaleConfig {
|
|
398
|
-
return { lightnessLow: 0, lightnessHigh: 100, saturation: 100 };
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
function stepKey(scaleTitle: string, stepName: string): string {
|
|
403
|
-
return `${scaleTitle}-${stepName}`;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
function derivedHex(step: Step, base: string, scaleTitle: string, _version?: string): string {
|
|
408
|
-
return computeDerivedColor(step, base, configForScale(scaleTitle), scaleTitle);
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
// --- Compute derived color via OKLCH ---
|
|
418
|
-
|
|
419
|
-
function scaleStepToX(step: Step, scale: Scale): number {
|
|
420
|
-
const idx = scale.steps.indexOf(step);
|
|
421
|
-
return scale.steps.length > 1 ? (idx / (scale.steps.length - 1)) * 100 : 50;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
function computeDerivedColor(step: Step, base: string, config: ScaleConfig, scaleTitle: string): string {
|
|
425
|
-
const { l: baseL, c: baseC, h: baseH } = hexToOklch(base);
|
|
426
|
-
const scale = scales.find(s => s.title === scaleTitle)!;
|
|
427
|
-
const xPos = scaleStepToX(step, scale);
|
|
428
|
-
|
|
429
|
-
const lCurve = scaleCurves[scaleTitle]?.lightness ?? [];
|
|
430
|
-
const sCurve = scaleCurves[scaleTitle]?.saturation ?? [];
|
|
431
|
-
const lKey = getScaleCurveKey(scaleTitle, 'lightness');
|
|
432
|
-
const sKey = getScaleCurveKey(scaleTitle, 'saturation');
|
|
433
|
-
const lOff = curveOffset[lKey] ?? 0;
|
|
434
|
-
const sOff = curveOffset[sKey] ?? 0;
|
|
435
|
-
|
|
436
|
-
let targetL: number;
|
|
437
|
-
if (scale.isText) {
|
|
438
|
-
// Text: lightness curve is a multiplier (100 = 1x base lightness)
|
|
439
|
-
const lMul = Math.max(0, Math.min(2, (sampleCurve(lCurve, xPos) + lOff) / 100));
|
|
440
|
-
targetL = Math.max(0, Math.min(1, baseL * lMul));
|
|
441
|
-
} else {
|
|
442
|
-
targetL = Math.max(0, Math.min(100, sampleCurve(lCurve, xPos) + lOff)) / 100;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
const satMul = Math.max(0, Math.min(2, (sampleCurve(sCurve, xPos) + sOff) / 100));
|
|
446
|
-
const targetC = baseC * satMul;
|
|
447
|
-
|
|
448
|
-
const clamped = gamutClamp(targetL, targetC, baseH);
|
|
449
|
-
return oklchToHex(clamped.l, clamped.c, clamped.h);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
// --- Interaction handlers ---
|
|
453
|
-
|
|
454
205
|
function handleColorChange(hex: string) {
|
|
455
206
|
if (isEditingBase) {
|
|
456
|
-
// Gray mode's base is derived from tintHue/tintChroma
|
|
457
|
-
// writes those). The raw hex path only applies to chromatic palettes.
|
|
207
|
+
// Gray mode's base is derived from tintHue/tintChroma; raw hex only applies to chromatic.
|
|
458
208
|
if (mode === 'chromatic') edit('baseColor', hex);
|
|
459
209
|
return;
|
|
460
210
|
}
|
|
@@ -477,9 +227,9 @@
|
|
|
477
227
|
confirmEdit();
|
|
478
228
|
return;
|
|
479
229
|
}
|
|
480
|
-
const current = (k in overrides) ? overrides[k] : computeDerivedColor(step, gray500Hex,
|
|
230
|
+
const current = (k in overrides) ? overrides[k] : computeDerivedColor(step, gray500Hex, scaleTitle);
|
|
481
231
|
editing = { kind: 'editingStep', stepKey: k, snapshot: current, draft: current };
|
|
482
|
-
|
|
232
|
+
openSession();
|
|
483
233
|
}
|
|
484
234
|
|
|
485
235
|
function handleGrayClick(gStep: GrayStep, index: number) {
|
|
@@ -490,13 +240,13 @@
|
|
|
490
240
|
}
|
|
491
241
|
const current = (k in overrides) ? overrides[k] : computeGrayColor(index, tintHue, tintChroma);
|
|
492
242
|
editing = { kind: 'editingStep', stepKey: k, snapshot: current, draft: current };
|
|
493
|
-
|
|
243
|
+
openSession();
|
|
494
244
|
}
|
|
495
245
|
|
|
496
246
|
async function confirmEdit() {
|
|
497
247
|
if (editingKey) {
|
|
498
|
-
// Accumulate
|
|
499
|
-
//
|
|
248
|
+
// Accumulate override changes into one patch so the session commit sees
|
|
249
|
+
// a single final state (no intermediate reactive round-trips).
|
|
500
250
|
let nextOverrides = { ...overrides };
|
|
501
251
|
if (editingDraft !== null) {
|
|
502
252
|
const computed = computedValueForKey(editingKey);
|
|
@@ -525,8 +275,7 @@
|
|
|
525
275
|
|
|
526
276
|
function cancelEdit() {
|
|
527
277
|
editing = idleState;
|
|
528
|
-
// Restoring the session snapshot
|
|
529
|
-
// which pulls baseColor/tintHue/tintChroma/overrides/… back to pre-open.
|
|
278
|
+
// Restoring the session snapshot pulls baseColor/tintHue/overrides/… back to pre-open.
|
|
530
279
|
if (paletteEditScope) { cancelScope(paletteEditScope); paletteEditScope = null; }
|
|
531
280
|
}
|
|
532
281
|
|
|
@@ -547,7 +296,7 @@
|
|
|
547
296
|
for (const scale of scales) {
|
|
548
297
|
for (const step of scale.steps) {
|
|
549
298
|
if (stepKey(scale.title, step.name) === key) {
|
|
550
|
-
return computeDerivedColor(step, gray500Hex,
|
|
299
|
+
return computeDerivedColor(step, gray500Hex, scale.title);
|
|
551
300
|
}
|
|
552
301
|
}
|
|
553
302
|
}
|
|
@@ -556,33 +305,7 @@
|
|
|
556
305
|
|
|
557
306
|
function effectiveColor(k: string, step: Step, scaleTitle: string, _version?: string): string {
|
|
558
307
|
if (editingKey === k && editingDraft !== null) return editingDraft;
|
|
559
|
-
return (k in overrides) ? overrides[k] : computeDerivedColor(step, gray500Hex,
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// --- Brightness/Saturation gradient helpers for scale editor ---
|
|
563
|
-
|
|
564
|
-
function lightnessGrad(base: string): string {
|
|
565
|
-
const { c, h } = hexToOklch(base);
|
|
566
|
-
const points: string[] = [];
|
|
567
|
-
for (let i = 0; i <= 8; i++) {
|
|
568
|
-
const l = i / 8;
|
|
569
|
-
const clamped = gamutClamp(l, c, h);
|
|
570
|
-
points.push(`${oklchToHex(clamped.l, clamped.c, clamped.h)} ${Math.round((i / 8) * 100)}%`);
|
|
571
|
-
}
|
|
572
|
-
return `linear-gradient(to right, ${points.join(', ')})`;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
function saturationGrad(base: string): string {
|
|
576
|
-
const { l, c, h } = hexToOklch(base);
|
|
577
|
-
const midL = Math.max(0.3, Math.min(0.7, l));
|
|
578
|
-
const points: string[] = [];
|
|
579
|
-
for (let i = 0; i <= 8; i++) {
|
|
580
|
-
const scale = (i / 8) * 2;
|
|
581
|
-
const targetC = c * scale;
|
|
582
|
-
const clamped = gamutClamp(midL, targetC, h);
|
|
583
|
-
points.push(`${oklchToHex(clamped.l, clamped.c, clamped.h)} ${Math.round((i / 8) * 100)}%`);
|
|
584
|
-
}
|
|
585
|
-
return `linear-gradient(to right, ${points.join(', ')})`;
|
|
308
|
+
return (k in overrides) ? overrides[k] : computeDerivedColor(step, gray500Hex, scaleTitle);
|
|
586
309
|
}
|
|
587
310
|
|
|
588
311
|
let copiedKey: string | null = $state(null);
|
|
@@ -601,42 +324,8 @@
|
|
|
601
324
|
setTimeout(() => { copiedLabelKey = null; }, 1500);
|
|
602
325
|
}
|
|
603
326
|
|
|
604
|
-
// --- Snap-all: constrain an entire scale to unique palette steps ---
|
|
605
|
-
|
|
606
327
|
function snapScaleToPalette(scale: Scale): Record<string, string> {
|
|
607
|
-
|
|
608
|
-
const n = scale.steps.length;
|
|
609
|
-
|
|
610
|
-
const stepL = scale.steps.map(step => {
|
|
611
|
-
const derived = computeDerivedColor(step, baseColor, cfg, scale.title);
|
|
612
|
-
return hexToOklch(derived).l;
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
const palL = paletteComputed.map(ps => hexToOklch(ps.hex).l);
|
|
616
|
-
|
|
617
|
-
const palDarkFirst = [...paletteComputed].reverse();
|
|
618
|
-
const palLDarkFirst = [...palL].reverse();
|
|
619
|
-
|
|
620
|
-
let bestStart = 0;
|
|
621
|
-
let bestCost = Infinity;
|
|
622
|
-
for (let start = 0; start <= palDarkFirst.length - n; start++) {
|
|
623
|
-
let cost = 0;
|
|
624
|
-
for (let i = 0; i < n; i++) {
|
|
625
|
-
const d = stepL[i] - palLDarkFirst[start + i];
|
|
626
|
-
cost += d * d;
|
|
627
|
-
}
|
|
628
|
-
if (cost < bestCost) {
|
|
629
|
-
bestCost = cost;
|
|
630
|
-
bestStart = start;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
const assigned: Record<string, string> = {};
|
|
635
|
-
for (let i = 0; i < n; i++) {
|
|
636
|
-
const k = stepKey(scale.title, scale.steps[i].name);
|
|
637
|
-
assigned[k] = palDarkFirst[bestStart + i].hex;
|
|
638
|
-
}
|
|
639
|
-
return assigned;
|
|
328
|
+
return snapScaleToPalettePure(scale, baseColor, scaleCurves, curveOffset, paletteComputed);
|
|
640
329
|
}
|
|
641
330
|
|
|
642
331
|
function toggleSnapAll(scale: Scale) {
|
|
@@ -668,10 +357,6 @@
|
|
|
668
357
|
edit('overrides', next);
|
|
669
358
|
}
|
|
670
359
|
|
|
671
|
-
function scaleHasOverrides(scale: Scale): boolean {
|
|
672
|
-
return scale.steps.some(s => stepKey(scale.title, s.name) in overrides);
|
|
673
|
-
}
|
|
674
|
-
|
|
675
360
|
function clearScaleOverrides(scale: Scale) {
|
|
676
361
|
snapPickerKey = null;
|
|
677
362
|
const nextOverrides = { ...overrides };
|
|
@@ -726,63 +411,38 @@
|
|
|
726
411
|
if (changed) edit('overrides', next);
|
|
727
412
|
}
|
|
728
413
|
|
|
729
|
-
|
|
730
|
-
// CSS-var emission lives in `paletteDerivation` → `editorRenderer`; the store
|
|
731
|
-
// is the single source of truth for palette config and the renderer
|
|
732
|
-
// subscription writes the derived `--color-*` / `--surface-*` / `--border-*`
|
|
733
|
-
// / `--text-*` / `--page-bg` variables to :root.
|
|
734
|
-
|
|
735
|
-
// --- Load external config ---
|
|
736
|
-
//
|
|
737
|
-
// External file loads come through editorStore.loadFromFile, which
|
|
738
|
-
// overwrites $editorState.palettes — no component-side mirroring needed.
|
|
739
|
-
// This export is kept only for callers that want to push a config in
|
|
740
|
-
// directly.
|
|
741
414
|
export function loadConfig(config: PaletteConfig) {
|
|
742
415
|
setPaletteConfig(label, config);
|
|
743
416
|
}
|
|
744
417
|
|
|
745
|
-
|
|
746
|
-
//
|
|
747
|
-
//
|
|
748
|
-
//
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
let
|
|
756
|
-
let
|
|
757
|
-
let
|
|
758
|
-
let
|
|
759
|
-
let
|
|
760
|
-
let
|
|
761
|
-
let
|
|
762
|
-
let
|
|
763
|
-
let
|
|
764
|
-
let
|
|
765
|
-
let
|
|
766
|
-
let
|
|
767
|
-
let anchorToBase = $derived(paletteConfig?.anchorToBase ?? true);
|
|
768
|
-
let emptyMode = $derived(paletteConfig?.emptyMode ?? 'solid');
|
|
769
|
-
let emptyStep = $derived(paletteConfig?.emptyStep ?? '850');
|
|
770
|
-
let gradientStyle = $derived(paletteConfig?.gradientStyle ?? 'linear');
|
|
771
|
-
let gradientAngle = $derived(paletteConfig?.gradientAngle ?? 180);
|
|
772
|
-
let gradientReverse = $derived(paletteConfig?.gradientReverse ?? false);
|
|
773
|
-
let gradientStops = $derived(paletteConfig?.gradientStops ?? [
|
|
418
|
+
// Each field reads `$editorState.palettes[label]` directly. A chained
|
|
419
|
+
// `$derived` of the whole config would return the same object reference on
|
|
420
|
+
// every mutate-in-place store update (Svelte 5 uses `===` equality) and
|
|
421
|
+
// short-circuit the downstream chain — swatches would freeze.
|
|
422
|
+
let baseColor = $derived($editorState.palettes[label]?.baseColor ?? initialColor);
|
|
423
|
+
let tintHue = $derived($editorState.palettes[label]?.tintHue ?? 240);
|
|
424
|
+
let tintChroma = $derived($editorState.palettes[label]?.tintChroma ?? DEFAULT_TINT_CHROMA);
|
|
425
|
+
let lightnessCurve = $derived($editorState.palettes[label]?.lightnessCurve ?? DEFAULT_PALETTE_LIGHTNESS());
|
|
426
|
+
let saturationCurve = $derived($editorState.palettes[label]?.saturationCurve ?? DEFAULT_PALETTE_SATURATION());
|
|
427
|
+
let grayLightnessCurve = $derived($editorState.palettes[label]?.grayLightnessCurve ?? DEFAULT_GRAY_LIGHTNESS());
|
|
428
|
+
let graySaturationCurve = $derived($editorState.palettes[label]?.graySaturationCurve ?? DEFAULT_GRAY_SATURATION());
|
|
429
|
+
let scaleCurves = $derived($editorState.palettes[label]?.scaleCurves ?? defaultScaleCurvesObject());
|
|
430
|
+
let curveOffset = $derived($editorState.palettes[label]?.curveOffset ?? { lightness: 0, saturation: 0 });
|
|
431
|
+
let overrides = $derived($editorState.palettes[label]?.overrides ?? {});
|
|
432
|
+
let snappedScales = $derived(new Set($editorState.palettes[label]?.snappedScales ?? []));
|
|
433
|
+
let anchorToBase = $derived($editorState.palettes[label]?.anchorToBase ?? true);
|
|
434
|
+
let emptyMode = $derived($editorState.palettes[label]?.emptyMode ?? 'solid');
|
|
435
|
+
let emptyStep = $derived($editorState.palettes[label]?.emptyStep ?? '850');
|
|
436
|
+
let gradientStyle = $derived($editorState.palettes[label]?.gradientStyle ?? 'linear');
|
|
437
|
+
let gradientAngle = $derived($editorState.palettes[label]?.gradientAngle ?? 180);
|
|
438
|
+
let gradientReverse = $derived($editorState.palettes[label]?.gradientReverse ?? false);
|
|
439
|
+
let gradientStops = $derived($editorState.palettes[label]?.gradientStops ?? [
|
|
774
440
|
{ position: 0, paletteLabel: '800' },
|
|
775
441
|
{ position: 100, paletteLabel: '950' },
|
|
776
442
|
]);
|
|
777
|
-
let gradientSize = $derived(
|
|
778
|
-
// Read-side compat: existing `editingKey === ...` etc. comparisons keep
|
|
779
|
-
// working. New code should narrow on `editing.kind` directly.
|
|
443
|
+
let gradientSize = $derived($editorState.palettes[label]?.gradientSize ?? 'page');
|
|
780
444
|
let editingKey = $derived(editing.kind === 'idle' ? null : editing.kind === 'editingBase' ? BASE_KEY : editing.stepKey);
|
|
781
445
|
let editingDraft = $derived(editing.kind === 'editingStep' ? editing.draft : null);
|
|
782
|
-
let editingSnapshot = $derived(editing.kind === 'idle' ? null : editing.kind === 'editingBase' ? editing.snapshotHex : editing.snapshot);
|
|
783
|
-
let snapshotTintHue = $derived(editing.kind === 'editingBase' ? editing.snapshotTintHue : null);
|
|
784
|
-
let snapshotTintChroma = $derived(editing.kind === 'editingBase' ? editing.snapshotTintChroma : null);
|
|
785
|
-
// Reactive map of computed gray colors
|
|
786
446
|
let grayComputed = $derived((() => {
|
|
787
447
|
const _gl = grayLightnessCurve, _gs = graySaturationCurve, _co = curveOffset, _tc = tintChroma, _th = tintHue;
|
|
788
448
|
return graySteps.map((step, index) => ({
|
|
@@ -799,12 +459,11 @@
|
|
|
799
459
|
effective: (_ek === g.key && _ed !== null) ? _ed : (g.key in _ov) ? _ov[g.key] : g.hex,
|
|
800
460
|
}));
|
|
801
461
|
})());
|
|
802
|
-
//
|
|
803
|
-
//
|
|
462
|
+
// Always use the computed (curve-derived) value so derived scales update in
|
|
463
|
+
// realtime when tint changes.
|
|
804
464
|
let gray500Hex = $derived(mode === 'gray'
|
|
805
465
|
? (grayComputed.find(g => g.step.label === '500')?.hex ?? GRAY_FALLBACK)
|
|
806
466
|
: baseColor);
|
|
807
|
-
// Derive locked anchor indices from curve shape — no writes to state.
|
|
808
467
|
run(() => {
|
|
809
468
|
if (anchorToBase) {
|
|
810
469
|
const x500 = stepIndexToX(4);
|
|
@@ -817,14 +476,9 @@
|
|
|
817
476
|
lockedSaturationIdx = null;
|
|
818
477
|
}
|
|
819
478
|
});
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
* target. During a baseColor drag (inside a slider transaction) this
|
|
824
|
-
* additional curve edit merges into the same history entry. On undo/redo
|
|
825
|
-
* the curve already has the correct y (they're saved together), so this
|
|
826
|
-
* is a no-op.
|
|
827
|
-
*/
|
|
479
|
+
// Keep the locked lightness anchor y in sync with baseColor. Idempotent.
|
|
480
|
+
// During a baseColor drag the curve edit merges into the same history entry;
|
|
481
|
+
// on undo/redo the curve already has the correct y, so this is a no-op.
|
|
828
482
|
run(() => {
|
|
829
483
|
if (anchorToBase && lockedLightnessIdx !== null && baseColor) {
|
|
830
484
|
const targetY = hexToOklch(baseColor).l * 100;
|
|
@@ -865,27 +519,13 @@
|
|
|
865
519
|
gradientCssValue = '';
|
|
866
520
|
}
|
|
867
521
|
});
|
|
868
|
-
|
|
869
|
-
let grayScales = $derived(mode === 'gray' ? scales.filter(scale => {
|
|
870
|
-
if (scale.title === 'Surfaces') return true;
|
|
871
|
-
if (scale.title === 'Borders') return true;
|
|
872
|
-
if (scale.title === 'Text') return true;
|
|
873
|
-
return false;
|
|
874
|
-
}) : []);
|
|
522
|
+
let grayScales = $derived(mode === 'gray' ? scales : []);
|
|
875
523
|
let curveVersion = $derived(JSON.stringify(scaleCurves) + JSON.stringify(curveOffset) + gray500Hex);
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
*
|
|
881
|
-
* Note: `effectiveColor` itself always uses `gray500Hex` for non-override
|
|
882
|
-
* derivation (pre-existing); the chromatic vs gray distinction here is
|
|
883
|
-
* only for the `derivedHex` (the "Ag" preview / border-color base).
|
|
884
|
-
*/
|
|
885
|
-
let derivedHexForBase = $derived((step: Step, scaleTitle: string) => derivedHex(step, baseColor, scaleTitle, curveVersion));
|
|
886
|
-
let derivedHexForGray = $derived((step: Step, scaleTitle: string) => derivedHex(step, gray500Hex, scaleTitle, curveVersion));
|
|
524
|
+
// Chromatic vs gray distinction is only for the `derivedHex` ("Ag" preview /
|
|
525
|
+
// border-color base); `effectiveColor` always uses `gray500Hex` for non-override derivation.
|
|
526
|
+
let derivedHexForBase = $derived((step: Step, scaleTitle: string) => computeDerivedColor(step, baseColor, scaleTitle));
|
|
527
|
+
let derivedHexForGray = $derived((step: Step, scaleTitle: string) => computeDerivedColor(step, gray500Hex, scaleTitle));
|
|
887
528
|
let effectiveHexAny = $derived((k: string, step: Step, scaleTitle: string) => effectiveColor(k, step, scaleTitle, curveVersion));
|
|
888
|
-
// --- Reactive editing state ---
|
|
889
529
|
|
|
890
530
|
let isEditingBase = $derived(isBaseEdit(editing));
|
|
891
531
|
let editingColor = $derived(isEditingBase
|
|
@@ -915,8 +555,7 @@
|
|
|
915
555
|
? `${editingStepInfo.scale} \u203A ${editingStepInfo.step}`
|
|
916
556
|
: null);
|
|
917
557
|
$effect(() => {
|
|
918
|
-
//
|
|
919
|
-
// tracks them explicitly (resnapScales() reads them indirectly).
|
|
558
|
+
// Touch each input so the effect tracks them (resnapScales reads indirectly).
|
|
920
559
|
void baseColor;
|
|
921
560
|
void scaleCurves;
|
|
922
561
|
void lightnessCurve;
|
|
@@ -1073,86 +712,6 @@
|
|
|
1073
712
|
|
|
1074
713
|
</div>
|
|
1075
714
|
|
|
1076
|
-
<button class="derived-toggle" type="button" onclick={() => showDerived = !showDerived}>
|
|
1077
|
-
<i class="fas" class:fa-chevron-right={!showDerived} class:fa-chevron-down={showDerived}></i>
|
|
1078
|
-
<span>Text, Surfaces & Borders</span>
|
|
1079
|
-
</button>
|
|
1080
|
-
|
|
1081
|
-
{#if showDerived}
|
|
1082
|
-
<div class="scales-row">
|
|
1083
|
-
{#each scales.filter(s => s.isText) as scale}
|
|
1084
|
-
<OverridesPanel
|
|
1085
|
-
{scale}
|
|
1086
|
-
editorOpen={scaleEditorOpen[scale.title] ?? false}
|
|
1087
|
-
snapped={snappedScales.has(scale.title)}
|
|
1088
|
-
supportsSnap={true}
|
|
1089
|
-
{cssNamespace}
|
|
1090
|
-
{scaleCurves}
|
|
1091
|
-
{curveOffset}
|
|
1092
|
-
{defaultScaleCurves}
|
|
1093
|
-
{overrides}
|
|
1094
|
-
{editingKey}
|
|
1095
|
-
{snapPickerKey}
|
|
1096
|
-
{copiedKey}
|
|
1097
|
-
{copiedLabelKey}
|
|
1098
|
-
{paletteComputed}
|
|
1099
|
-
derivedHexFor={derivedHexForBase}
|
|
1100
|
-
effectiveHexFor={effectiveHexAny}
|
|
1101
|
-
stepKeyFor={stepKey}
|
|
1102
|
-
scaleCurveKeyFor={getScaleCurveKey}
|
|
1103
|
-
onToggleSnap={toggleSnapAll}
|
|
1104
|
-
onClearScaleOverrides={clearScaleOverrides}
|
|
1105
|
-
onToggleEditor={toggleScaleEditor}
|
|
1106
|
-
onResetOverride={resetOverride}
|
|
1107
|
-
onOverrideClick={handleOverrideClick}
|
|
1108
|
-
onSnappedClick={handleSnappedClick}
|
|
1109
|
-
onSelectSnapValue={selectSnapValue}
|
|
1110
|
-
onCopyHex={copyHex}
|
|
1111
|
-
onCopyVarName={copyVarName}
|
|
1112
|
-
onSetScaleCurve={setScaleCurve}
|
|
1113
|
-
onOffsetChange={handleOffset}
|
|
1114
|
-
/>
|
|
1115
|
-
{/each}
|
|
1116
|
-
</div>
|
|
1117
|
-
|
|
1118
|
-
<!-- Surfaces & Borders — per-scale editors -->
|
|
1119
|
-
<div class="scales-row">
|
|
1120
|
-
{#each scales.filter(s => !s.isText) as scale}
|
|
1121
|
-
<OverridesPanel
|
|
1122
|
-
{scale}
|
|
1123
|
-
editorOpen={scaleEditorOpen[scale.title] ?? false}
|
|
1124
|
-
snapped={snappedScales.has(scale.title)}
|
|
1125
|
-
supportsSnap={true}
|
|
1126
|
-
{cssNamespace}
|
|
1127
|
-
{scaleCurves}
|
|
1128
|
-
{curveOffset}
|
|
1129
|
-
{defaultScaleCurves}
|
|
1130
|
-
{overrides}
|
|
1131
|
-
{editingKey}
|
|
1132
|
-
{snapPickerKey}
|
|
1133
|
-
{copiedKey}
|
|
1134
|
-
{copiedLabelKey}
|
|
1135
|
-
{paletteComputed}
|
|
1136
|
-
derivedHexFor={derivedHexForBase}
|
|
1137
|
-
effectiveHexFor={effectiveHexAny}
|
|
1138
|
-
stepKeyFor={stepKey}
|
|
1139
|
-
scaleCurveKeyFor={getScaleCurveKey}
|
|
1140
|
-
onToggleSnap={toggleSnapAll}
|
|
1141
|
-
onClearScaleOverrides={clearScaleOverrides}
|
|
1142
|
-
onToggleEditor={toggleScaleEditor}
|
|
1143
|
-
onResetOverride={resetOverride}
|
|
1144
|
-
onOverrideClick={handleOverrideClick}
|
|
1145
|
-
onSnappedClick={handleSnappedClick}
|
|
1146
|
-
onSelectSnapValue={selectSnapValue}
|
|
1147
|
-
onCopyHex={copyHex}
|
|
1148
|
-
onCopyVarName={copyVarName}
|
|
1149
|
-
onSetScaleCurve={setScaleCurve}
|
|
1150
|
-
onOffsetChange={handleOffset}
|
|
1151
|
-
/>
|
|
1152
|
-
{/each}
|
|
1153
|
-
</div>
|
|
1154
|
-
{/if}
|
|
1155
|
-
|
|
1156
715
|
{:else}
|
|
1157
716
|
<!-- Gray mode: palette + text row -->
|
|
1158
717
|
<div class="scales-row">
|
|
@@ -1234,6 +793,41 @@
|
|
|
1234
793
|
</div>
|
|
1235
794
|
</div>
|
|
1236
795
|
</div>
|
|
796
|
+
{/if}
|
|
797
|
+
|
|
798
|
+
{#snippet overridesPanel(scale: Scale, canSnap: boolean, derivedHexFor: (step: Step, scaleTitle: string) => string)}
|
|
799
|
+
<OverridesPanel
|
|
800
|
+
{scale}
|
|
801
|
+
editorOpen={scaleEditorOpen[scale.title] ?? false}
|
|
802
|
+
snapped={canSnap && snappedScales.has(scale.title)}
|
|
803
|
+
supportsSnap={canSnap}
|
|
804
|
+
{cssNamespace}
|
|
805
|
+
{scaleCurves}
|
|
806
|
+
{curveOffset}
|
|
807
|
+
{defaultScaleCurves}
|
|
808
|
+
{overrides}
|
|
809
|
+
{editingKey}
|
|
810
|
+
{snapPickerKey}
|
|
811
|
+
{copiedKey}
|
|
812
|
+
{copiedLabelKey}
|
|
813
|
+
{paletteComputed}
|
|
814
|
+
{derivedHexFor}
|
|
815
|
+
effectiveHexFor={effectiveHexAny}
|
|
816
|
+
stepKeyFor={stepKey}
|
|
817
|
+
scaleCurveKeyFor={getScaleCurveKey}
|
|
818
|
+
onToggleSnap={toggleSnapAll}
|
|
819
|
+
onClearScaleOverrides={clearScaleOverrides}
|
|
820
|
+
onToggleEditor={toggleScaleEditor}
|
|
821
|
+
onResetOverride={resetOverride}
|
|
822
|
+
onOverrideClick={handleOverrideClick}
|
|
823
|
+
onSnappedClick={handleSnappedClick}
|
|
824
|
+
onSelectSnapValue={selectSnapValue}
|
|
825
|
+
onCopyHex={copyHex}
|
|
826
|
+
onCopyVarName={copyVarName}
|
|
827
|
+
onSetScaleCurve={setScaleCurve}
|
|
828
|
+
onOffsetChange={handleOffset}
|
|
829
|
+
/>
|
|
830
|
+
{/snippet}
|
|
1237
831
|
|
|
1238
832
|
<button class="derived-toggle" type="button" onclick={() => showDerived = !showDerived}>
|
|
1239
833
|
<i class="fas" class:fa-chevron-right={!showDerived} class:fa-chevron-down={showDerived}></i>
|
|
@@ -1241,78 +835,18 @@
|
|
|
1241
835
|
</button>
|
|
1242
836
|
|
|
1243
837
|
{#if showDerived}
|
|
1244
|
-
|
|
1245
|
-
{
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
{
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
{editingKey}
|
|
1257
|
-
{snapPickerKey}
|
|
1258
|
-
{copiedKey}
|
|
1259
|
-
{copiedLabelKey}
|
|
1260
|
-
{paletteComputed}
|
|
1261
|
-
derivedHexFor={derivedHexForGray}
|
|
1262
|
-
effectiveHexFor={effectiveHexAny}
|
|
1263
|
-
stepKeyFor={stepKey}
|
|
1264
|
-
scaleCurveKeyFor={getScaleCurveKey}
|
|
1265
|
-
onToggleSnap={toggleSnapAll}
|
|
1266
|
-
onClearScaleOverrides={clearScaleOverrides}
|
|
1267
|
-
onToggleEditor={toggleScaleEditor}
|
|
1268
|
-
onResetOverride={resetOverride}
|
|
1269
|
-
onOverrideClick={handleOverrideClick}
|
|
1270
|
-
onSnappedClick={handleSnappedClick}
|
|
1271
|
-
onSelectSnapValue={selectSnapValue}
|
|
1272
|
-
onCopyHex={copyHex}
|
|
1273
|
-
onCopyVarName={copyVarName}
|
|
1274
|
-
onSetScaleCurve={setScaleCurve}
|
|
1275
|
-
onOffsetChange={handleOffset}
|
|
1276
|
-
/>
|
|
1277
|
-
{/each}
|
|
1278
|
-
</div>
|
|
1279
|
-
<!-- Surfaces & Borders for gray mode -->
|
|
1280
|
-
<div class="scales-row">
|
|
1281
|
-
{#each grayScales.filter(s => !s.isText) as scale}
|
|
1282
|
-
<OverridesPanel
|
|
1283
|
-
{scale}
|
|
1284
|
-
editorOpen={scaleEditorOpen[scale.title] ?? false}
|
|
1285
|
-
snapped={false}
|
|
1286
|
-
supportsSnap={false}
|
|
1287
|
-
{cssNamespace}
|
|
1288
|
-
{scaleCurves}
|
|
1289
|
-
{curveOffset}
|
|
1290
|
-
{defaultScaleCurves}
|
|
1291
|
-
{overrides}
|
|
1292
|
-
{editingKey}
|
|
1293
|
-
{snapPickerKey}
|
|
1294
|
-
{copiedKey}
|
|
1295
|
-
{copiedLabelKey}
|
|
1296
|
-
{paletteComputed}
|
|
1297
|
-
derivedHexFor={derivedHexForGray}
|
|
1298
|
-
effectiveHexFor={effectiveHexAny}
|
|
1299
|
-
stepKeyFor={stepKey}
|
|
1300
|
-
scaleCurveKeyFor={getScaleCurveKey}
|
|
1301
|
-
onToggleSnap={toggleSnapAll}
|
|
1302
|
-
onClearScaleOverrides={clearScaleOverrides}
|
|
1303
|
-
onToggleEditor={toggleScaleEditor}
|
|
1304
|
-
onResetOverride={resetOverride}
|
|
1305
|
-
onOverrideClick={handleOverrideClick}
|
|
1306
|
-
onSnappedClick={handleSnappedClick}
|
|
1307
|
-
onSelectSnapValue={selectSnapValue}
|
|
1308
|
-
onCopyHex={copyHex}
|
|
1309
|
-
onCopyVarName={copyVarName}
|
|
1310
|
-
onSetScaleCurve={setScaleCurve}
|
|
1311
|
-
onOffsetChange={handleOffset}
|
|
1312
|
-
/>
|
|
1313
|
-
{/each}
|
|
1314
|
-
</div>
|
|
1315
|
-
{/if}
|
|
838
|
+
{@const activeScales = mode === 'gray' ? grayScales : scales}
|
|
839
|
+
{@const derivedHexFor = mode === 'gray' ? derivedHexForGray : derivedHexForBase}
|
|
840
|
+
<div class="scales-row">
|
|
841
|
+
{#each activeScales.filter(s => s.isText) as scale}
|
|
842
|
+
{@render overridesPanel(scale, true, derivedHexFor)}
|
|
843
|
+
{/each}
|
|
844
|
+
</div>
|
|
845
|
+
<div class="scales-row">
|
|
846
|
+
{#each activeScales.filter(s => !s.isText) as scale}
|
|
847
|
+
{@render overridesPanel(scale, mode !== 'gray', derivedHexFor)}
|
|
848
|
+
{/each}
|
|
849
|
+
</div>
|
|
1316
850
|
{/if}
|
|
1317
851
|
|
|
1318
852
|
<!-- Color Edit Panel (non-base edits) -->
|
|
@@ -1342,7 +876,7 @@
|
|
|
1342
876
|
padding: var(--ui-space-16) var(--ui-space-16) var(--ui-space-24);
|
|
1343
877
|
background: none;
|
|
1344
878
|
border: none;
|
|
1345
|
-
border-bottom: 1px solid var(--ui-border-
|
|
879
|
+
border-bottom: 1px solid var(--ui-border-low);
|
|
1346
880
|
font-family: var(--ui-font-sans);
|
|
1347
881
|
min-width: 0;
|
|
1348
882
|
}
|
|
@@ -1363,7 +897,7 @@
|
|
|
1363
897
|
font-size: var(--ui-font-size-md);
|
|
1364
898
|
color: var(--ui-text-tertiary);
|
|
1365
899
|
background: none;
|
|
1366
|
-
border: 1px solid var(--ui-border-
|
|
900
|
+
border: 1px solid var(--ui-border-low);
|
|
1367
901
|
border-radius: var(--ui-radius-sm);
|
|
1368
902
|
padding: var(--ui-space-2) var(--ui-space-6);
|
|
1369
903
|
cursor: pointer;
|
|
@@ -1371,7 +905,7 @@
|
|
|
1371
905
|
|
|
1372
906
|
.edit-toggle:hover {
|
|
1373
907
|
color: var(--ui-text-primary);
|
|
1374
|
-
border-color: var(--ui-border-
|
|
908
|
+
border-color: var(--ui-border-high);
|
|
1375
909
|
}
|
|
1376
910
|
|
|
1377
911
|
.derived-toggle {
|
|
@@ -1474,7 +1008,7 @@
|
|
|
1474
1008
|
width: 100%;
|
|
1475
1009
|
height: 2rem;
|
|
1476
1010
|
border-radius: var(--ui-radius-sm);
|
|
1477
|
-
border: 1px solid var(--ui-border-
|
|
1011
|
+
border: 1px solid var(--ui-border-low);
|
|
1478
1012
|
}
|
|
1479
1013
|
|
|
1480
1014
|
/* Step hex values */
|
|
@@ -1530,12 +1064,12 @@
|
|
|
1530
1064
|
}
|
|
1531
1065
|
|
|
1532
1066
|
.swatch.gray-swatch:hover {
|
|
1533
|
-
border-color: var(--ui-border-
|
|
1067
|
+
border-color: var(--ui-border-high);
|
|
1534
1068
|
}
|
|
1535
1069
|
|
|
1536
1070
|
.swatch.gray-swatch.active {
|
|
1537
|
-
border-color: var(--ui-border-
|
|
1538
|
-
outline: 2px solid var(--ui-border-
|
|
1071
|
+
border-color: var(--ui-border-higher);
|
|
1072
|
+
outline: 2px solid var(--ui-border-high);
|
|
1539
1073
|
outline-offset: 1px;
|
|
1540
1074
|
}
|
|
1541
1075
|
|