@motion-proto/live-tokens 0.44.0 → 0.46.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/CHANGELOG.md +103 -0
- package/dist-plugin/index.cjs +1 -1
- package/dist-plugin/index.js +1 -1
- package/package.json +1 -1
- package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +0 -1
- package/src/editor/component-editor/scaffolding/ComponentFileMenu.svelte +1 -1
- package/src/editor/core/palettes/colorHarmony.ts +35 -6
- package/src/editor/core/palettes/paletteDerivation.ts +2 -3
- package/src/editor/core/store/editorTypes.ts +2 -2
- package/src/editor/docs/CodeBlock.svelte +0 -2
- package/src/editor/docs/Docs.svelte +0 -3
- package/src/editor/pages/ComponentEditorPage.svelte +3 -5
- package/src/editor/pages/EditorShell.svelte +3 -5
- package/src/editor/ui/ColorEditPanel.svelte +19 -22
- package/src/editor/ui/EditorViewSwitcher.svelte +2 -3
- package/src/editor/ui/FileLoadList.svelte +7 -9
- package/src/editor/ui/ManifestFileManager.svelte +1 -3
- package/src/editor/ui/ProjectFontsSection.svelte +0 -4
- package/src/editor/ui/SurfacesTab.svelte +3 -3
- package/src/editor/ui/TextStylesSection.svelte +6 -8
- package/src/editor/ui/ThemeFileManager.svelte +1 -3
- package/src/editor/ui/UIEasingSelector.svelte +0 -2
- package/src/editor/ui/UIFontFamilySelector.svelte +9 -3
- package/src/editor/ui/UIMenuButton.svelte +230 -0
- package/src/editor/ui/UIPaletteSelector.svelte +0 -1
- package/src/editor/ui/VariablesTab.svelte +3 -4
- package/src/editor/ui/colors/AxisNumeral.svelte +70 -0
- package/src/editor/ui/colors/ColorReadouts.svelte +0 -2
- package/src/editor/ui/colors/ColorStory.svelte +24 -77
- package/src/editor/ui/colors/ColorWheel.svelte +48 -29
- package/src/editor/ui/colors/ColorsTab.svelte +361 -212
- package/src/editor/ui/colors/HarmonyAxesList.svelte +264 -141
- package/src/editor/ui/colors/LightnessBar.svelte +0 -2
- package/src/editor/ui/colors/harmonyDrag.ts +10 -0
- package/src/editor/ui/colors/harmonyModeIcons.ts +5 -0
- package/src/editor/ui/colors/paletteBaseColor.ts +25 -39
- package/src/live-tokens/data/tokens.generated.css +28 -28
- package/src/system/components/ImageLightbox.svelte +0 -2
- package/src/system/components/SectionDivider.svelte +4 -4
- package/src/editor/core/palettes/recommendText.ts +0 -216
- package/src/editor/core/palettes/solveTextContrast.ts +0 -254
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,108 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.46.0 — Harmony axes are numbered, and you assign them with a picker
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **The four harmony axes are numbered, not named.** `AXIS_ROLES`
|
|
8
|
+
(`Anchor`/`Secondary`/`Tertiary`/`Quaternary`) is deleted; every call site
|
|
9
|
+
routes through the new `axisLabel(index)`, and only axis 1 keeps a word.
|
|
10
|
+
Rows read `1 Anchor`, `2`, `3`, `4`. History entries read `colors: axis 3
|
|
11
|
+
hue`, `colors: anchor rotate`, `colors: assign Brand`, `colors: unassign
|
|
12
|
+
Brand`. Aria and titles drop the doubled "axis": `Rotate axis 3 hue`,
|
|
13
|
+
`Brand, on axis 2 of 4. ... Delete to unassign.` `bindFamilyToAxis` and
|
|
14
|
+
`unbindFamily` keep their names, so the model verb is unchanged.
|
|
15
|
+
|
|
16
|
+
- **One source of truth for axis status.** `axisStatuses(mode, axes)` replaces
|
|
17
|
+
the three per-surface derivations off `modeActiveAxes`, so the swatch row,
|
|
18
|
+
the wheel and the axes list can no longer disagree about a family bound to an
|
|
19
|
+
axis the current mode gives no position. That family now reads as
|
|
20
|
+
bound-and-off-wheel everywhere: the list keeps its chip at full strength and
|
|
21
|
+
states `Off the wheel · <Mode> uses N`, the free dot carries its axis numeral and
|
|
22
|
+
says why it left the ring, and the swatch row's mark tracks the same status.
|
|
23
|
+
Unused rows replace the bare "Empty" with their reason. New helpers
|
|
24
|
+
`activeAxisCount` and `axisLabel` keep those strings out of per-call-site
|
|
25
|
+
composition.
|
|
26
|
+
|
|
27
|
+
- **Assigning a family to an axis is a picker.** Each row opens an `Assign to
|
|
28
|
+
...` menu listing the eligible families, with meta reading `moves from
|
|
29
|
+
anchor` / `moves from axis 2`. Dragging a chip onto an axis still works and
|
|
30
|
+
is now the accelerator, not the only path. The axes description leads with
|
|
31
|
+
the click path and mentions drag second.
|
|
32
|
+
|
|
33
|
+
- **The Colors view is laid out around the wheel.** Color Harmony and Harmony
|
|
34
|
+
axes sit side by side, the family swatches tuck under the harmony presets,
|
|
35
|
+
the axes list moves under the mode row, and the selected color's edit panel
|
|
36
|
+
moves under the wheel with the lightness bar inside it and Absolute Chroma in
|
|
37
|
+
its header. The three slider rows are grid-aligned on one column set.
|
|
38
|
+
|
|
39
|
+
- **`Special` moves ahead of `Canvas` in `PALETTE_SPECS`.** It reorders the
|
|
40
|
+
family list in the editor and the block order in
|
|
41
|
+
`src/live-tokens/data/tokens.generated.css`. No token name is added, renamed
|
|
42
|
+
or removed, so no migration applies.
|
|
43
|
+
|
|
44
|
+
- **SectionDivider's eyebrow letter-spacing default is
|
|
45
|
+
`--letter-spacing-normal`.** All three sizes previously defaulted to
|
|
46
|
+
`--letter-spacing-wide`. Consumers on a saved component config keep their own
|
|
47
|
+
value; consumers on `default` pick this up.
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
- **`UIMenuButton`**, the shared editor menu-button behind the axis picker.
|
|
52
|
+
`aria-haspopup="menu"`, arrow navigation that wraps, Home/End, and dismissal
|
|
53
|
+
on Escape, Tab or outside mousedown, each pinned by a test. Internal to the
|
|
54
|
+
editor; it is not exported from `@motion-proto/live-tokens/ui`.
|
|
55
|
+
|
|
56
|
+
- **`AxisNumeral`**, the one numeral treatment shared by the swatch row, the
|
|
57
|
+
wheel and the axes list.
|
|
58
|
+
|
|
59
|
+
### Removed
|
|
60
|
+
|
|
61
|
+
- **The tint-neutrals button.** Absolute Chroma sits beside the harmony presets
|
|
62
|
+
and covers the case.
|
|
63
|
+
|
|
64
|
+
- **Chrome the surfaces did not need.** The Theme eyebrow and the panel's
|
|
65
|
+
preview square in the Colors view, the Proportional preview eyebrow, and the
|
|
66
|
+
inline axes description, which is now an info icon. Selected rows lose the
|
|
67
|
+
third emphasis signal on `.role`: the settled treatment is inverted numeral
|
|
68
|
+
plus one row border.
|
|
69
|
+
|
|
70
|
+
## 0.45.0 — The Color Story shows the tokens you actually have
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
|
|
74
|
+
- **The Color Story's text steps read the live tokens.** The primary, secondary
|
|
75
|
+
and tertiary row rendered the values the *Even neutral steps* pill would have
|
|
76
|
+
written, not the current ones, so the same step could report two different
|
|
77
|
+
ratios in the same frame (the Canvas header said 17.9:1 while the row said
|
|
78
|
+
14.7:1). Each step now resolves `--text-primary` / `--text-secondary` /
|
|
79
|
+
`--text-tertiary` through the same path the functional chips and tone pills
|
|
80
|
+
already used, renders in its own token, and reports its real contrast against
|
|
81
|
+
the canvas.
|
|
82
|
+
|
|
83
|
+
### Removed
|
|
84
|
+
|
|
85
|
+
- **The Color Story's action pills.** *Raise all text to AA*, *Even neutral
|
|
86
|
+
steps*, and the *Anchor at pure white/black* toggle, added in 0.44.0, are
|
|
87
|
+
gone. The story is a proportional preview, and authoring text steps from it
|
|
88
|
+
put a second palette editor next to the real one. Text steps are edited in
|
|
89
|
+
the Tokens view.
|
|
90
|
+
|
|
91
|
+
- **The text-contrast solvers.** `solveTextContrast.ts` and `recommendText.ts`
|
|
92
|
+
(plus `applySolvedTextCurves` and `applySuggestedNeutralText`) backed only
|
|
93
|
+
those pills and are deleted. Both were internal to `src/editor/core/palettes/`
|
|
94
|
+
and never reachable through the package exports, so no consumer import
|
|
95
|
+
changes. `BW_GUARD_MIN_L` / `BW_GUARD_MAX_L` are unaffected: they live in
|
|
96
|
+
`paletteDerivation.ts` and still guard derived inverted text.
|
|
97
|
+
|
|
98
|
+
### Changed
|
|
99
|
+
|
|
100
|
+
- **The story's prose lines and its unlabeled header ratio are gone.** The three
|
|
101
|
+
sentences under Canvas ("The dominant surface. Body text sits here." and its
|
|
102
|
+
two siblings) said nothing the labelled steps don't, and the ratio beside the
|
|
103
|
+
Canvas heading was primary's, measured but never named. The stacked steps
|
|
104
|
+
carry all three ratios now.
|
|
105
|
+
|
|
3
106
|
## 0.44.0 — Every text step derives to body contrast
|
|
4
107
|
|
|
5
108
|
### Added
|
package/dist-plugin/index.cjs
CHANGED
|
@@ -198,10 +198,10 @@ function sampleCurve(anchors, xPos) {
|
|
|
198
198
|
var PALETTE_SPECS = [
|
|
199
199
|
{ label: "Brand", cssNamespace: "brand", initialColor: { l: 0.5573, c: 0.1841, h: 25.49 } },
|
|
200
200
|
{ label: "Accent", cssNamespace: "accent", initialColor: { l: 0.7674, c: 0.164, h: 70.44 } },
|
|
201
|
+
{ label: "Special", cssNamespace: "special", initialColor: { l: 0.6056, c: 0.2189, h: 292.72 } },
|
|
201
202
|
{ label: "Canvas", cssNamespace: "canvas", emptySelector: true, initialColor: { l: 0.2284, c: 0.0384, h: 282.93 } },
|
|
202
203
|
{ label: "Neutral", cssNamespace: "neutral", neutral: true, initialColor: { l: 0.5679, c: 0.0134, h: 240.07 } },
|
|
203
204
|
{ label: "Alternate", cssNamespace: "alternate", neutral: true, displayLabel: "Alternate (neutral)", initialColor: { l: 0.5873, c: 87e-4, h: 48.57 } },
|
|
204
|
-
{ label: "Special", cssNamespace: "special", initialColor: { l: 0.6056, c: 0.2189, h: 292.72 } },
|
|
205
205
|
{ label: "Info", cssNamespace: "info", initialColor: { l: 0.5871, c: 0.1855, h: 259.56 } },
|
|
206
206
|
{ label: "Success", cssNamespace: "success", initialColor: { l: 0.7198, c: 0.1918, h: 149.52 } },
|
|
207
207
|
{ label: "Warning", cssNamespace: "warning", initialColor: { l: 0.6704, c: 0.1716, h: 48.75 } },
|
package/dist-plugin/index.js
CHANGED
|
@@ -157,10 +157,10 @@ function sampleCurve(anchors, xPos) {
|
|
|
157
157
|
var PALETTE_SPECS = [
|
|
158
158
|
{ label: "Brand", cssNamespace: "brand", initialColor: { l: 0.5573, c: 0.1841, h: 25.49 } },
|
|
159
159
|
{ label: "Accent", cssNamespace: "accent", initialColor: { l: 0.7674, c: 0.164, h: 70.44 } },
|
|
160
|
+
{ label: "Special", cssNamespace: "special", initialColor: { l: 0.6056, c: 0.2189, h: 292.72 } },
|
|
160
161
|
{ label: "Canvas", cssNamespace: "canvas", emptySelector: true, initialColor: { l: 0.2284, c: 0.0384, h: 282.93 } },
|
|
161
162
|
{ label: "Neutral", cssNamespace: "neutral", neutral: true, initialColor: { l: 0.5679, c: 0.0134, h: 240.07 } },
|
|
162
163
|
{ label: "Alternate", cssNamespace: "alternate", neutral: true, displayLabel: "Alternate (neutral)", initialColor: { l: 0.5873, c: 87e-4, h: 48.57 } },
|
|
163
|
-
{ label: "Special", cssNamespace: "special", initialColor: { l: 0.6056, c: 0.2189, h: 292.72 } },
|
|
164
164
|
{ label: "Info", cssNamespace: "info", initialColor: { l: 0.5871, c: 0.1855, h: 259.56 } },
|
|
165
165
|
{ label: "Success", cssNamespace: "success", initialColor: { l: 0.7198, c: 0.1918, h: 149.52 } },
|
|
166
166
|
{ label: "Warning", cssNamespace: "warning", initialColor: { l: 0.6704, c: 0.1716, h: 48.75 } },
|
package/package.json
CHANGED
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
title="Load {component} Config"
|
|
109
109
|
{files}
|
|
110
110
|
{activeFileName}
|
|
111
|
-
systemBadge={{ label: '
|
|
111
|
+
systemBadge={{ label: 'System', title: 'Protected system config' }}
|
|
112
112
|
emptyMessage="No saved files"
|
|
113
113
|
onload={handleLoad}
|
|
114
114
|
ondelete={handleDelete}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Harmony rotates HUE ONLY (Global invariant 6). Each palette keeps its own
|
|
2
2
|
// OKLCH chroma and lightness; only a family's hue moves onto a geometric
|
|
3
3
|
// relationship with the anchor. The anchor is axis 0's stored hue: harmony lives
|
|
4
|
-
// on four fixed axes
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// on four fixed axes, numbered, each owning a hue whether or not a color family
|
|
5
|
+
// is bound to it. No chroma clamp or cap lives here; a saturated background is a
|
|
6
|
+
// legitimate choice, not something to correct.
|
|
7
7
|
|
|
8
8
|
import type { Oklch } from './oklch';
|
|
9
9
|
import type { PaletteConfig } from '../themes/themeTypes';
|
|
@@ -24,7 +24,6 @@ export type HarmonyMode =
|
|
|
24
24
|
export const HARMONY_ELIGIBLE: readonly string[] = ['Brand', 'Accent', 'Canvas', 'Special', 'Neutral', 'Alternate'];
|
|
25
25
|
|
|
26
26
|
export const AXIS_COUNT = 4;
|
|
27
|
-
export const AXIS_ROLES = ['Anchor', 'Secondary', 'Tertiary', 'Quaternary'] as const;
|
|
28
27
|
|
|
29
28
|
export interface HarmonyAxis {
|
|
30
29
|
/** Hue in [0, 360). Always present, bound or not. */
|
|
@@ -85,7 +84,7 @@ const specInitialHue = (label: string): number =>
|
|
|
85
84
|
|
|
86
85
|
/**
|
|
87
86
|
* Seed the four axes for a fresh editor: the default trio bound (hues read from
|
|
88
|
-
* `PALETTE_SPECS`, never hardcoded) and
|
|
87
|
+
* `PALETTE_SPECS`, never hardcoded) and axis 4 unbound at anchor + 270 (the
|
|
89
88
|
* square slot-3 offset). Fresh array each call — it seeds mutable state.
|
|
90
89
|
*/
|
|
91
90
|
export function defaultHarmonyAxes(): HarmonyAxis[] {
|
|
@@ -110,6 +109,36 @@ export function modeActiveAxes(mode: HarmonyMode): boolean[] {
|
|
|
110
109
|
return slots.map((h, i) => slots.slice(0, i).every((prev) => prev !== h));
|
|
111
110
|
}
|
|
112
111
|
|
|
112
|
+
export type AxisStatus = 'on-wheel' | 'off-wheel' | 'unused';
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Per-axis presentation status. The single source every Colors surface reads,
|
|
116
|
+
* so the wheel, the swatch row and the axes list cannot disagree about the
|
|
117
|
+
* same axis.
|
|
118
|
+
*
|
|
119
|
+
* on-wheel — the mode deals this slot a distinct hue: rail, handle, numeral.
|
|
120
|
+
* off-wheel — a family is bound, but the mode deals the slot no position.
|
|
121
|
+
* The binding is real and returns when the mode changes; the
|
|
122
|
+
* family edits as the free dot meanwhile.
|
|
123
|
+
* unused — no family bound and no position dealt.
|
|
124
|
+
*/
|
|
125
|
+
export function axisStatuses(mode: HarmonyMode, axes: HarmonyAxis[]): AxisStatus[] {
|
|
126
|
+
return modeActiveAxes(mode).map((active, i) => {
|
|
127
|
+
if (active) return 'on-wheel';
|
|
128
|
+
return axes[i].family !== null ? 'off-wheel' : 'unused';
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** How many axes `mode` deals a distinct position to. Reason strings quote it. */
|
|
133
|
+
export function activeAxisCount(mode: HarmonyMode): number {
|
|
134
|
+
return modeActiveAxes(mode).filter(Boolean).length;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Axis 1 is the slot the other three are measured from, so it keeps a name. */
|
|
138
|
+
export function axisLabel(index: number): string {
|
|
139
|
+
return index === 0 ? 'anchor' : `axis ${index + 1}`;
|
|
140
|
+
}
|
|
141
|
+
|
|
113
142
|
/**
|
|
114
143
|
* Re-deal every axis's hue from `mode`'s geometry, anchored on axis 0's hue.
|
|
115
144
|
* Bindings are preserved; `'custom'` imposes no constraint and returns a copy.
|
|
@@ -173,7 +202,7 @@ export function sanitizeHarmonyAxes(
|
|
|
173
202
|
axis.hue = norm(palettes[axis.family].baseColor.h);
|
|
174
203
|
}
|
|
175
204
|
}
|
|
176
|
-
// With no stored axes (a theme predating them), the default
|
|
205
|
+
// With no stored axes (a theme predating them), the default axis 4 hue is
|
|
177
206
|
// an offset from the anchor, so it follows the anchor's palette-seeded hue
|
|
178
207
|
// rather than the spec hue the defaults were built from.
|
|
179
208
|
const last = axes[AXIS_COUNT - 1];
|
|
@@ -40,10 +40,10 @@ export interface PaletteSpec {
|
|
|
40
40
|
export const PALETTE_SPECS: readonly PaletteSpec[] = [
|
|
41
41
|
{ label: 'Brand', cssNamespace: 'brand', initialColor: { l: 0.5573, c: 0.1841, h: 25.49 } },
|
|
42
42
|
{ label: 'Accent', cssNamespace: 'accent', initialColor: { l: 0.7674, c: 0.164, h: 70.44 } },
|
|
43
|
+
{ label: 'Special', cssNamespace: 'special', initialColor: { l: 0.6056, c: 0.2189, h: 292.72 } },
|
|
43
44
|
{ label: 'Canvas', cssNamespace: 'canvas', emptySelector: true, initialColor: { l: 0.2284, c: 0.0384, h: 282.93 } },
|
|
44
45
|
{ label: 'Neutral', cssNamespace: 'neutral', neutral: true, initialColor: { l: 0.5679, c: 0.0134, h: 240.07 } },
|
|
45
46
|
{ label: 'Alternate', cssNamespace: 'alternate', neutral: true, displayLabel: 'Alternate (neutral)', initialColor: { l: 0.5873, c: 0.0087, h: 48.57 } },
|
|
46
|
-
{ label: 'Special', cssNamespace: 'special', initialColor: { l: 0.6056, c: 0.2189, h: 292.72 } },
|
|
47
47
|
{ label: 'Info', cssNamespace: 'info', initialColor: { l: 0.5871, c: 0.1855, h: 259.56 } },
|
|
48
48
|
{ label: 'Success', cssNamespace: 'success', initialColor: { l: 0.7198, c: 0.1918, h: 149.52 } },
|
|
49
49
|
{ label: 'Warning', cssNamespace: 'warning', initialColor: { l: 0.6704, c: 0.1716, h: 48.75 } },
|
|
@@ -104,8 +104,7 @@ export const SCALES: readonly Scale[] = [
|
|
|
104
104
|
];
|
|
105
105
|
|
|
106
106
|
/** Guard band for derived near-black/near-white text: values stay between
|
|
107
|
-
* ≈ #111 and ≈ #e8e8e8
|
|
108
|
-
* beats the guard (see `recommendText.ts`). */
|
|
107
|
+
* ≈ #111 and ≈ #e8e8e8, the range most designers prefer over pure extremes. */
|
|
109
108
|
export const BW_GUARD_MIN_L = 0.17;
|
|
110
109
|
export const BW_GUARD_MAX_L = 0.93;
|
|
111
110
|
|
|
@@ -137,8 +137,8 @@ export interface EditorState {
|
|
|
137
137
|
columns: ColumnsState;
|
|
138
138
|
components: Record<string, ComponentSlice>;
|
|
139
139
|
gradients: { tokens: GradientToken[] };
|
|
140
|
-
/** Four fixed axes (index
|
|
141
|
-
*
|
|
140
|
+
/** Four fixed numbered axes (index 0 is the anchor); each owns a hue;
|
|
141
|
+
* family is the live-bound color or null. */
|
|
142
142
|
harmonyAxes: HarmonyAxis[];
|
|
143
143
|
cssVars: Record<string, string>;
|
|
144
144
|
}
|
|
@@ -67,8 +67,6 @@
|
|
|
67
67
|
font-family: var(--font-mono, ui-monospace, monospace);
|
|
68
68
|
font-size: var(--font-size-xs, 0.75rem);
|
|
69
69
|
color: var(--text-tertiary, #7e8285);
|
|
70
|
-
text-transform: uppercase;
|
|
71
|
-
letter-spacing: var(--letter-spacing-wider, 0.06em);
|
|
72
70
|
background: color-mix(in srgb, var(--surface-neutral-lowest, #040c13) 60%, transparent);
|
|
73
71
|
border-left: var(--border-width-1, 1px) solid var(--border-neutral-faint, #1c2327);
|
|
74
72
|
border-bottom: var(--border-width-1, 1px) solid var(--border-neutral-faint, #1c2327);
|
|
@@ -449,7 +449,6 @@
|
|
|
449
449
|
font-size: var(--font-size-lg, 1.125rem);
|
|
450
450
|
line-height: 1.75rem;
|
|
451
451
|
font-weight: var(--font-weight-bold, 700);
|
|
452
|
-
letter-spacing: 0.025em;
|
|
453
452
|
color: var(--text-primary);
|
|
454
453
|
text-decoration: none;
|
|
455
454
|
cursor: pointer;
|
|
@@ -638,8 +637,6 @@
|
|
|
638
637
|
.footer-dir {
|
|
639
638
|
font-size: var(--font-size-xs, 0.75rem);
|
|
640
639
|
color: var(--text-tertiary);
|
|
641
|
-
text-transform: uppercase;
|
|
642
|
-
letter-spacing: var(--letter-spacing-wider, 0.08em);
|
|
643
640
|
}
|
|
644
641
|
.chapter-link { text-decoration: none; }
|
|
645
642
|
|
|
@@ -343,9 +343,9 @@
|
|
|
343
343
|
background: black;
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
-
/* Divider between
|
|
347
|
-
dimmer border token (sub-element separator), with an
|
|
348
|
-
|
|
346
|
+
/* Divider between the System and Custom groups. The horizontal line uses the
|
|
347
|
+
dimmer border token (sub-element separator), with an eyebrow label that
|
|
348
|
+
fades out when the rail is collapsed so the line still reads. */
|
|
349
349
|
.nav-divider {
|
|
350
350
|
display: grid;
|
|
351
351
|
grid-template-columns: 48px 1fr;
|
|
@@ -360,8 +360,6 @@
|
|
|
360
360
|
font-size: var(--ui-font-size-xs);
|
|
361
361
|
font-weight: var(--ui-font-weight-semibold);
|
|
362
362
|
color: var(--ui-text-tertiary);
|
|
363
|
-
text-transform: uppercase;
|
|
364
|
-
letter-spacing: 0.04em;
|
|
365
363
|
opacity: 0;
|
|
366
364
|
transition: opacity 180ms ease;
|
|
367
365
|
}
|
|
@@ -299,9 +299,9 @@
|
|
|
299
299
|
flex-shrink: 0;
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
-
/* Divider between
|
|
303
|
-
dimmer border token (sub-element separator), with an
|
|
304
|
-
|
|
302
|
+
/* Divider between the System and Custom groups. The horizontal line uses the
|
|
303
|
+
dimmer border token (sub-element separator), with an eyebrow label that
|
|
304
|
+
fades out when the rail is condensed so the line still reads. */
|
|
305
305
|
.nav-divider {
|
|
306
306
|
display: grid;
|
|
307
307
|
grid-template-columns: 48px 1fr;
|
|
@@ -316,8 +316,6 @@
|
|
|
316
316
|
font-size: var(--ui-font-size-xs);
|
|
317
317
|
font-weight: var(--ui-font-weight-semibold);
|
|
318
318
|
color: var(--ui-text-tertiary);
|
|
319
|
-
text-transform: uppercase;
|
|
320
|
-
letter-spacing: 0.04em;
|
|
321
319
|
opacity: 1;
|
|
322
320
|
transition: opacity 180ms ease;
|
|
323
321
|
}
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
/** Hide the confirm/cancel actions for live-apply consumers (Colors view
|
|
13
13
|
* readout) where edits commit through the store as they happen. */
|
|
14
14
|
hideActions?: boolean;
|
|
15
|
+
/** Hide the preview square where the surrounding view already shows the
|
|
16
|
+
* color (Colors view: wheel, swatches and derived scale all do). */
|
|
17
|
+
hidePreview?: boolean;
|
|
15
18
|
onConfirm?: () => void;
|
|
16
19
|
onCancel?: () => void;
|
|
17
20
|
onRemoveOverride?: () => void;
|
|
@@ -36,6 +39,7 @@
|
|
|
36
39
|
title = null,
|
|
37
40
|
showRemoveOverride = false,
|
|
38
41
|
hideActions = false,
|
|
42
|
+
hidePreview = false,
|
|
39
43
|
onConfirm = () => {},
|
|
40
44
|
onCancel = () => {},
|
|
41
45
|
onRemoveOverride = () => {},
|
|
@@ -131,7 +135,9 @@
|
|
|
131
135
|
|
|
132
136
|
<div class="hsl-panel">
|
|
133
137
|
<div class="hsl-panel-header">
|
|
134
|
-
|
|
138
|
+
{#if !hidePreview}
|
|
139
|
+
<div class="hsl-preview" style="background: {previewHex}"></div>
|
|
140
|
+
{/if}
|
|
135
141
|
{#if hasEyeDropper}
|
|
136
142
|
<button
|
|
137
143
|
class="eyedropper-btn"
|
|
@@ -190,7 +196,7 @@
|
|
|
190
196
|
type="number"
|
|
191
197
|
min="0"
|
|
192
198
|
max="360"
|
|
193
|
-
value={hue}
|
|
199
|
+
value={Math.round(hue)}
|
|
194
200
|
onchange={(e) => onHueChromaChange(Math.min(360, Math.max(0, +e.currentTarget.value)), chroma, lPct)}
|
|
195
201
|
/><span class="hsl-slider-unit">°</span>
|
|
196
202
|
</div>
|
|
@@ -205,14 +211,14 @@
|
|
|
205
211
|
oninput={(e) => onHueChromaChange(hue, +e.currentTarget.value, lPct)} />
|
|
206
212
|
</div>
|
|
207
213
|
<input
|
|
208
|
-
class="hsl-slider-input
|
|
214
|
+
class="hsl-slider-input"
|
|
209
215
|
type="number"
|
|
210
216
|
min="0"
|
|
211
217
|
max={chromaMax}
|
|
212
218
|
step="0.001"
|
|
213
219
|
value={chroma.toFixed(3)}
|
|
214
220
|
onchange={(e) => onHueChromaChange(hue, Math.min(chromaMax, Math.max(0, +e.currentTarget.value)), lPct)}
|
|
215
|
-
|
|
221
|
+
/><span class="hsl-slider-unit"></span>
|
|
216
222
|
</div>
|
|
217
223
|
<div class="hsl-slider-row">
|
|
218
224
|
<span class="hsl-slider-label">L</span>
|
|
@@ -330,25 +336,24 @@
|
|
|
330
336
|
flex-wrap: wrap;
|
|
331
337
|
}
|
|
332
338
|
|
|
339
|
+
/* Shared column tracks keep every bar and every input the same width
|
|
340
|
+
regardless of row content; the row wrappers dissolve into the grid. */
|
|
333
341
|
.hsl-sliders {
|
|
334
|
-
display:
|
|
335
|
-
|
|
336
|
-
gap: var(--ui-space-6);
|
|
342
|
+
display: grid;
|
|
343
|
+
grid-template-columns: 2.5rem minmax(6rem, 1fr) 3.5rem 0.75rem;
|
|
344
|
+
gap: var(--ui-space-6) var(--ui-space-8);
|
|
345
|
+
align-items: center;
|
|
337
346
|
}
|
|
338
347
|
|
|
339
348
|
.hsl-slider-row {
|
|
340
|
-
display:
|
|
341
|
-
align-items: center;
|
|
342
|
-
gap: var(--ui-space-8);
|
|
349
|
+
display: contents;
|
|
343
350
|
}
|
|
344
351
|
|
|
345
352
|
.hsl-slider-label {
|
|
346
353
|
font-size: var(--ui-font-size-md);
|
|
347
354
|
font-weight: var(--ui-font-weight-semibold);
|
|
348
355
|
color: var(--ui-text-tertiary);
|
|
349
|
-
width: 2.5rem;
|
|
350
356
|
text-align: right;
|
|
351
|
-
flex-shrink: 0;
|
|
352
357
|
}
|
|
353
358
|
|
|
354
359
|
.slider-track {
|
|
@@ -356,8 +361,6 @@
|
|
|
356
361
|
height: 1.25rem;
|
|
357
362
|
border-radius: var(--ui-radius-md);
|
|
358
363
|
border: 1px solid var(--ui-border-low);
|
|
359
|
-
flex: 1;
|
|
360
|
-
min-width: 6rem;
|
|
361
364
|
}
|
|
362
365
|
|
|
363
366
|
.chroma-hint {
|
|
@@ -422,9 +425,9 @@
|
|
|
422
425
|
font-size: var(--ui-font-size-md);
|
|
423
426
|
color: var(--ui-text-primary);
|
|
424
427
|
font-family: var(--ui-font-mono);
|
|
425
|
-
width:
|
|
428
|
+
width: 100%;
|
|
429
|
+
box-sizing: border-box;
|
|
426
430
|
text-align: right;
|
|
427
|
-
flex-shrink: 0;
|
|
428
431
|
background: var(--ui-surface-lowest);
|
|
429
432
|
border: 1px solid var(--ui-border-low);
|
|
430
433
|
border-radius: var(--ui-radius-sm);
|
|
@@ -433,10 +436,6 @@
|
|
|
433
436
|
appearance: textfield;
|
|
434
437
|
}
|
|
435
438
|
|
|
436
|
-
.hsl-slider-input.chroma-input {
|
|
437
|
-
width: 3.5rem;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
439
|
.hsl-slider-input::-webkit-inner-spin-button,
|
|
441
440
|
.hsl-slider-input::-webkit-outer-spin-button {
|
|
442
441
|
-webkit-appearance: none;
|
|
@@ -452,7 +451,5 @@
|
|
|
452
451
|
font-size: var(--ui-font-size-md);
|
|
453
452
|
color: var(--ui-text-muted);
|
|
454
453
|
font-family: var(--ui-font-mono);
|
|
455
|
-
width: 0.75rem;
|
|
456
|
-
flex-shrink: 0;
|
|
457
454
|
}
|
|
458
455
|
</style>
|
|
@@ -116,10 +116,9 @@
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
.seg-label {
|
|
119
|
-
font-size:
|
|
119
|
+
font-size: var(--ui-font-size-xs);
|
|
120
120
|
font-weight: var(--ui-font-weight-semibold);
|
|
121
|
-
text-
|
|
122
|
-
color: #fff;
|
|
121
|
+
color: var(--ui-text-primary);
|
|
123
122
|
padding-left: var(--ui-space-2);
|
|
124
123
|
margin-bottom: 2px;
|
|
125
124
|
}
|
|
@@ -152,7 +152,7 @@
|
|
|
152
152
|
<span class="updated-at" title={file.updatedAt}>{formatUpdatedAt(file.updatedAt)}</span>
|
|
153
153
|
{/if}
|
|
154
154
|
{#if file.fileName === activeFileName}
|
|
155
|
-
<span class="active-badge">
|
|
155
|
+
<span class="active-badge">Active</span>
|
|
156
156
|
{/if}
|
|
157
157
|
{#if onexport}
|
|
158
158
|
<button
|
|
@@ -207,10 +207,9 @@
|
|
|
207
207
|
padding: 4px 0;
|
|
208
208
|
background: none;
|
|
209
209
|
border: none;
|
|
210
|
-
color:
|
|
211
|
-
font-size:
|
|
212
|
-
font-weight:
|
|
213
|
-
text-transform: uppercase;
|
|
210
|
+
color: var(--ui-text-tertiary);
|
|
211
|
+
font-size: var(--ui-font-size-xs);
|
|
212
|
+
font-weight: var(--ui-font-weight-semibold);
|
|
214
213
|
cursor: pointer;
|
|
215
214
|
text-align: left;
|
|
216
215
|
}
|
|
@@ -312,13 +311,12 @@
|
|
|
312
311
|
|
|
313
312
|
.system-badge {
|
|
314
313
|
flex-shrink: 0;
|
|
315
|
-
font-size:
|
|
314
|
+
font-size: var(--ui-font-size-xs);
|
|
316
315
|
padding: 1px 6px;
|
|
317
316
|
border-radius: 3px;
|
|
318
317
|
background: transparent;
|
|
319
318
|
border: 1px solid #3a3a3a;
|
|
320
|
-
color:
|
|
321
|
-
text-transform: uppercase;
|
|
319
|
+
color: var(--ui-text-tertiary);
|
|
322
320
|
}
|
|
323
321
|
|
|
324
322
|
.updated-at {
|
|
@@ -331,7 +329,7 @@
|
|
|
331
329
|
|
|
332
330
|
.active-badge {
|
|
333
331
|
flex-shrink: 0;
|
|
334
|
-
font-size:
|
|
332
|
+
font-size: var(--ui-font-size-xs);
|
|
335
333
|
padding: 1px 6px;
|
|
336
334
|
border-radius: 3px;
|
|
337
335
|
background: #333;
|
|
@@ -343,7 +343,6 @@
|
|
|
343
343
|
.mfm-header-label {
|
|
344
344
|
font-size: var(--ui-font-size-xs);
|
|
345
345
|
color: var(--ui-text-secondary);
|
|
346
|
-
text-transform: uppercase;
|
|
347
346
|
}
|
|
348
347
|
|
|
349
348
|
.mfm-card {
|
|
@@ -380,9 +379,8 @@
|
|
|
380
379
|
}
|
|
381
380
|
|
|
382
381
|
.mfm-card-label {
|
|
383
|
-
font-size:
|
|
382
|
+
font-size: var(--ui-font-size-xs);
|
|
384
383
|
font-weight: var(--ui-font-weight-semibold);
|
|
385
|
-
text-transform: uppercase;
|
|
386
384
|
color: var(--ui-text-tertiary);
|
|
387
385
|
}
|
|
388
386
|
|
|
@@ -539,8 +539,6 @@
|
|
|
539
539
|
font-size: var(--ui-font-size-xs);
|
|
540
540
|
font-weight: var(--ui-font-weight-semibold);
|
|
541
541
|
color: var(--ui-text-tertiary);
|
|
542
|
-
text-transform: uppercase;
|
|
543
|
-
letter-spacing: 0.04em;
|
|
544
542
|
}
|
|
545
543
|
.pf-browse-row {
|
|
546
544
|
display: flex;
|
|
@@ -569,8 +567,6 @@
|
|
|
569
567
|
gap: var(--ui-space-8);
|
|
570
568
|
color: var(--ui-text-tertiary);
|
|
571
569
|
font-size: var(--ui-font-size-xs);
|
|
572
|
-
text-transform: uppercase;
|
|
573
|
-
letter-spacing: 0.04em;
|
|
574
570
|
}
|
|
575
571
|
.pf-add-divider::before,
|
|
576
572
|
.pf-add-divider::after {
|
|
@@ -290,9 +290,9 @@
|
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
.group-title {
|
|
293
|
-
font-size: var(--ui-font-size-
|
|
294
|
-
font-weight: var(--ui-font-weight-
|
|
295
|
-
color: var(--ui-text-
|
|
293
|
+
font-size: var(--ui-font-size-xl);
|
|
294
|
+
font-weight: var(--ui-font-weight-bold);
|
|
295
|
+
color: var(--ui-text-primary);
|
|
296
296
|
margin: 0;
|
|
297
297
|
}
|
|
298
298
|
|
|
@@ -23,28 +23,28 @@
|
|
|
23
23
|
|
|
24
24
|
<div class="ts-controls">
|
|
25
25
|
<div class="ts-field">
|
|
26
|
-
<span class="ts-label">
|
|
26
|
+
<span class="ts-label">Family</span>
|
|
27
27
|
<UIFontFamilySelector variable={`${style.prefix}-font-family`} />
|
|
28
28
|
</div>
|
|
29
29
|
<div class="ts-field">
|
|
30
|
-
<span class="ts-label">
|
|
30
|
+
<span class="ts-label">Size</span>
|
|
31
31
|
<UIFontSizeSelector variable={`${style.prefix}-font-size`} />
|
|
32
32
|
</div>
|
|
33
33
|
<div class="ts-field">
|
|
34
|
-
<span class="ts-label">
|
|
34
|
+
<span class="ts-label">Weight</span>
|
|
35
35
|
<UIFontWeightSelector variable={`${style.prefix}-font-weight`} />
|
|
36
36
|
</div>
|
|
37
37
|
<div class="ts-field">
|
|
38
|
-
<span class="ts-label">
|
|
38
|
+
<span class="ts-label">Letter spacing</span>
|
|
39
39
|
<UILetterSpacingSelector variable={`${style.prefix}-letter-spacing`} />
|
|
40
40
|
</div>
|
|
41
41
|
<div class="ts-field">
|
|
42
|
-
<span class="ts-label">
|
|
42
|
+
<span class="ts-label">Line height</span>
|
|
43
43
|
<UILineHeightSelector variable={`${style.prefix}-line-height`} />
|
|
44
44
|
</div>
|
|
45
45
|
{#if style.hasTextTransform}
|
|
46
46
|
<div class="ts-field">
|
|
47
|
-
<span class="ts-label">
|
|
47
|
+
<span class="ts-label">Transform</span>
|
|
48
48
|
<UITextTransformSelector variable={`${style.prefix}-text-transform`} />
|
|
49
49
|
</div>
|
|
50
50
|
{/if}
|
|
@@ -165,8 +165,6 @@
|
|
|
165
165
|
.ts-label {
|
|
166
166
|
font-size: var(--ui-font-size-xs);
|
|
167
167
|
font-weight: var(--ui-font-weight-medium);
|
|
168
|
-
letter-spacing: 0.04em;
|
|
169
|
-
text-transform: uppercase;
|
|
170
168
|
color: var(--ui-text-muted);
|
|
171
169
|
white-space: nowrap;
|
|
172
170
|
}
|
|
@@ -417,7 +417,7 @@
|
|
|
417
417
|
activeFileName={$activeFileName}
|
|
418
418
|
sortable
|
|
419
419
|
showUpdatedAt
|
|
420
|
-
systemBadge={{ label: '
|
|
420
|
+
systemBadge={{ label: 'System', title: 'Protected system theme' }}
|
|
421
421
|
emptyMessage="No saved files"
|
|
422
422
|
canDelete={(file) => file.fileName !== 'default' && file.fileName !== $themeProductionInfo?.fileName}
|
|
423
423
|
onload={handleLoad}
|
|
@@ -460,7 +460,6 @@
|
|
|
460
460
|
.tfm-header-label {
|
|
461
461
|
font-size: var(--ui-font-size-xs);
|
|
462
462
|
color: var(--ui-text-secondary);
|
|
463
|
-
text-transform: uppercase;
|
|
464
463
|
}
|
|
465
464
|
|
|
466
465
|
/* Two-card pipeline (Editor → Production) — theme card + production card
|
|
@@ -508,7 +507,6 @@
|
|
|
508
507
|
.tfm-card-label {
|
|
509
508
|
font-size: var(--ui-font-size-xs);
|
|
510
509
|
font-weight: var(--ui-font-weight-semibold);
|
|
511
|
-
text-transform: uppercase;
|
|
512
510
|
color: var(--ui-text-secondary);
|
|
513
511
|
line-height: 1.1;
|
|
514
512
|
}
|