@motion-proto/live-tokens 0.3.7 → 0.5.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 +1 -1
- package/package.json +11 -9
- package/src/component-editor/BadgeEditor.svelte +24 -22
- package/src/component-editor/CalloutEditor.svelte +3 -3
- package/src/component-editor/CardEditor.svelte +25 -21
- package/src/component-editor/CollapsibleSectionEditor.svelte +27 -25
- package/src/component-editor/CornerBadgeEditor.svelte +37 -35
- package/src/component-editor/DialogEditor.svelte +26 -24
- package/src/component-editor/ImageEditor.svelte +11 -9
- package/src/component-editor/InlineEditActionsEditor.svelte +17 -15
- package/src/component-editor/NotificationEditor.svelte +32 -30
- package/src/component-editor/ProgressBarEditor.svelte +3 -3
- package/src/component-editor/RadioButtonEditor.svelte +31 -29
- package/src/component-editor/SectionDividerEditor.svelte +30 -28
- package/src/component-editor/SegmentedControlEditor.svelte +29 -25
- package/src/component-editor/StandardButtonsEditor.svelte +42 -38
- package/src/component-editor/TabBarEditor.svelte +20 -18
- package/src/component-editor/TableEditor.svelte +4 -4
- package/src/component-editor/TooltipEditor.svelte +11 -9
- package/src/component-editor/registry.ts +2 -2
- package/src/component-editor/scaffolding/AngleDial.svelte +20 -19
- package/src/component-editor/scaffolding/ComponentEditorBase.svelte +44 -20
- package/src/component-editor/scaffolding/ComponentFileManager.svelte +260 -37
- package/src/component-editor/scaffolding/ComponentFileMenu.svelte +41 -29
- package/src/component-editor/scaffolding/ComponentsTab.svelte +7 -3
- package/src/component-editor/scaffolding/CopyFromMenu.svelte +21 -12
- package/src/component-editor/scaffolding/DemoHeader.svelte +13 -4
- package/src/component-editor/scaffolding/DividerEditor.svelte +27 -14
- package/src/component-editor/scaffolding/FieldsetWrapper.svelte +10 -4
- package/src/component-editor/scaffolding/GradientCard.svelte +25 -20
- package/src/component-editor/scaffolding/LinkageChart.svelte +43 -34
- package/src/component-editor/scaffolding/LinkedBlock.svelte +24 -21
- package/src/component-editor/scaffolding/NonStylableConfig.svelte +6 -1
- package/src/component-editor/scaffolding/SaveAsDialog.svelte +39 -35
- package/src/component-editor/scaffolding/ShadowBackdrop.svelte +21 -9
- package/src/component-editor/scaffolding/ShadowBackdropControls.svelte +8 -3
- package/src/component-editor/scaffolding/StateBlock.svelte +30 -13
- package/src/component-editor/scaffolding/TokenLayout.svelte +46 -30
- package/src/component-editor/scaffolding/TypeEditor.svelte +52 -26
- package/src/component-editor/scaffolding/VariantGroup.svelte +81 -48
- package/src/component-editor/scaffolding/componentSectionType.ts +2 -2
- package/src/components/Badge.svelte +45 -26
- package/src/components/Button.svelte +44 -21
- package/src/components/Callout.svelte +17 -12
- package/src/components/Card.svelte +23 -11
- package/src/components/CollapsibleSection.svelte +56 -27
- package/src/components/CornerBadge.svelte +32 -18
- package/src/components/Dialog.svelte +55 -31
- package/src/components/Image.svelte +14 -5
- package/src/components/InlineEditActions.svelte +22 -10
- package/src/components/Notification.svelte +39 -19
- package/src/components/ProgressBar.svelte +27 -17
- package/src/components/RadioButton.svelte +27 -10
- package/src/components/SectionDivider.svelte +34 -26
- package/src/components/SegmentedControl.svelte +23 -9
- package/src/components/TabBar.svelte +23 -10
- package/src/components/Table.svelte +8 -3
- package/src/components/Tooltip.svelte +15 -5
- package/src/lib/ColumnsOverlay.svelte +3 -3
- package/src/lib/LiveEditorOverlay.svelte +73 -36
- package/src/pages/ComponentEditorPage.svelte +17 -13
- package/src/pages/EditorShell.svelte +24 -20
- package/src/styles/form-controls.css +2 -2
- package/src/styles/tokens.css +59 -81
- package/src/ui/BezierCurveEditor.svelte +59 -43
- package/src/ui/ColorEditPanel.svelte +71 -44
- package/src/ui/EditorViewSwitcher.svelte +9 -5
- package/src/ui/FontStackEditor.svelte +16 -15
- package/src/ui/GradientEditor.svelte +42 -33
- package/src/ui/GradientStopPicker.svelte +18 -29
- package/src/ui/PaletteEditor.svelte +238 -212
- package/src/ui/PresetFileManager.svelte +20 -18
- package/src/ui/ProjectFontsSection.svelte +30 -30
- package/src/ui/SurfacesTab.svelte +3 -3
- package/src/ui/TextTab.svelte +2 -2
- package/src/ui/ThemeFileManager.svelte +38 -35
- package/src/ui/Toggle.svelte +11 -9
- package/src/ui/UICopyPopover.svelte +19 -15
- package/src/ui/UIDialog.svelte +48 -30
- package/src/ui/UIFontFamilySelector.svelte +104 -78
- package/src/ui/UIFontSizeSelector.svelte +38 -20
- package/src/ui/UIFontWeightSelector.svelte +33 -13
- package/src/ui/UILineHeightSelector.svelte +33 -13
- package/src/ui/UILinkToggle.svelte +7 -6
- package/src/ui/UIOptionItem.svelte +21 -7
- package/src/ui/UIOptionList.svelte +9 -3
- package/src/ui/UIPaddingSelector.svelte +108 -82
- package/src/ui/UIPaletteSelector.svelte +186 -161
- package/src/ui/UIRadio.svelte +23 -8
- package/src/ui/UIRadioGroup.svelte +9 -8
- package/src/ui/UIRelinkConfirmPopover.svelte +26 -16
- package/src/ui/UITokenSelector.svelte +112 -68
- package/src/ui/UIVariantSelector.svelte +79 -57
- package/src/ui/VariablesTab.svelte +15 -15
- package/src/ui/palette/GradientStopEditor.svelte +45 -26
- package/src/ui/palette/OverridesPanel.svelte +85 -49
- package/src/ui/palette/PaletteBase.svelte +60 -32
- package/src/ui/palette/ScaleCurveEditor.svelte +25 -10
- package/src/ui/sections/ColumnsSection.svelte +13 -13
- package/src/ui/sections/GradientsSection.svelte +12 -9
- package/src/ui/sections/OverlaysSection.svelte +50 -47
- package/src/ui/sections/ShadowsSection.svelte +110 -104
- package/src/ui/sections/TokenScaleTable.svelte +38 -22
- package/src/ui/sections/tokenScales.ts +2 -2
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
interface Props {
|
|
3
|
+
text?: string;
|
|
4
|
+
position?: 'top' | 'bottom';
|
|
5
|
+
open?: boolean;
|
|
6
|
+
children?: import('svelte').Snippet;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
text = '',
|
|
11
|
+
position = 'top',
|
|
12
|
+
open = false,
|
|
13
|
+
children
|
|
14
|
+
}: Props = $props();
|
|
5
15
|
</script>
|
|
6
16
|
|
|
7
17
|
<div class="tooltip-wrapper" class:open>
|
|
8
|
-
|
|
18
|
+
{@render children?.()}
|
|
9
19
|
{#if text}
|
|
10
20
|
<div class="tooltip" class:bottom={position === 'bottom'}>
|
|
11
21
|
{text}
|
|
@@ -20,7 +30,7 @@
|
|
|
20
30
|
--tooltip-text-font-family: var(--font-sans);
|
|
21
31
|
--tooltip-text-font-size: var(--font-size-sm);
|
|
22
32
|
--tooltip-text-font-weight: var(--font-weight-normal);
|
|
23
|
-
--tooltip-text-line-height: var(--line-height-
|
|
33
|
+
--tooltip-text-line-height: var(--line-height-md);
|
|
24
34
|
--tooltip-border: var(--border-neutral);
|
|
25
35
|
--tooltip-border-width: var(--border-width-0);
|
|
26
36
|
--tooltip-radius: var(--radius-md);
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
const isInIframe = typeof window !== 'undefined' && window.parent !== window;
|
|
7
7
|
const enabled = isDev && !isInIframe;
|
|
8
8
|
|
|
9
|
-
let count = 12;
|
|
10
|
-
let gutter = '';
|
|
11
|
-
let margin = '';
|
|
9
|
+
let count = $state(12);
|
|
10
|
+
let gutter = $state('');
|
|
11
|
+
let margin = $state('');
|
|
12
12
|
|
|
13
13
|
function readTokens() {
|
|
14
14
|
const cs = getComputedStyle(document.documentElement);
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
<script
|
|
1
|
+
<script module lang="ts">
|
|
2
2
|
// __PROJECT_ROOT__ is injected by the themeFileApi Vite plugin as a `define`.
|
|
3
3
|
// Consumers don't need to configure it themselves. We declare it locally so
|
|
4
4
|
// this component's type-check passes in consumer projects that haven't added
|
|
5
5
|
// the ambient global to their tsconfig.
|
|
6
6
|
declare const __PROJECT_ROOT__: string | undefined;
|
|
7
|
+
declare const __APP_VERSION__: string | undefined;
|
|
7
8
|
const INJECTED_PROJECT_ROOT: string =
|
|
8
9
|
typeof __PROJECT_ROOT__ !== 'undefined' ? (__PROJECT_ROOT__ ?? '') : '';
|
|
10
|
+
const APP_VERSION: string =
|
|
11
|
+
typeof __APP_VERSION__ !== 'undefined' ? (__APP_VERSION__ ?? '') : '';
|
|
9
12
|
</script>
|
|
10
13
|
|
|
11
14
|
<script lang="ts">
|
|
15
|
+
import { run } from 'svelte/legacy';
|
|
16
|
+
|
|
12
17
|
import { onMount, onDestroy } from 'svelte';
|
|
13
18
|
import { fade } from 'svelte/transition';
|
|
14
19
|
import { cubicInOut } from 'svelte/easing';
|
|
@@ -20,12 +25,23 @@
|
|
|
20
25
|
import { postParentRoute } from './parentRouteStore';
|
|
21
26
|
import type { NavLink } from './navLinkTypes';
|
|
22
27
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
interface Props {
|
|
29
|
+
open?: boolean | undefined;
|
|
30
|
+
editorPath?: string;
|
|
31
|
+
navLinks?: NavLink[];
|
|
32
|
+
pageSources?: Record<string, string>;
|
|
33
|
+
hidePageSourceOn?: string[];
|
|
34
|
+
projectRoot?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let {
|
|
38
|
+
open = $bindable(undefined),
|
|
39
|
+
editorPath = '/editor',
|
|
40
|
+
navLinks = [],
|
|
41
|
+
pageSources = {},
|
|
42
|
+
hidePageSourceOn = [],
|
|
43
|
+
projectRoot = INJECTED_PROJECT_ROOT
|
|
44
|
+
}: Props = $props();
|
|
29
45
|
|
|
30
46
|
// Self-gate: only render in dev, and never inside an iframe (the /editor
|
|
31
47
|
// page embeds this same app in an iframe and would otherwise recursively
|
|
@@ -41,25 +57,33 @@
|
|
|
41
57
|
if (!consumerControlsOpen) {
|
|
42
58
|
open = enabled && quietGet(OPEN_KEY) === '1';
|
|
43
59
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
60
|
+
run(() => {
|
|
61
|
+
if (!consumerControlsOpen && typeof window !== 'undefined') {
|
|
62
|
+
quietSet(OPEN_KEY, open ? '1' : '0');
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
run(() => {
|
|
66
|
+
overlayOpen.set(!!open);
|
|
67
|
+
});
|
|
48
68
|
|
|
49
69
|
// Hide the overlay entirely when the user is already on the editor route
|
|
50
70
|
// (the editor page has its own chrome).
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
71
|
+
let onEditorPath = $derived($route === editorPath);
|
|
72
|
+
let sourceFile = $derived(pageSources[$route]);
|
|
73
|
+
let showSource = $derived(!!sourceFile && !!projectRoot && !hidePageSourceOn.includes($route));
|
|
54
74
|
|
|
55
75
|
// Mount the iframe the first time the editor is shown, then keep it mounted
|
|
56
76
|
// across hide/show cycles so editor state (unsaved slider values, scroll
|
|
57
77
|
// position, expanded sections) survives.
|
|
58
|
-
let hasBeenOpen: boolean = !!open;
|
|
59
|
-
|
|
78
|
+
let hasBeenOpen: boolean = $state(!!open);
|
|
79
|
+
run(() => {
|
|
80
|
+
if (open) hasBeenOpen = true;
|
|
81
|
+
});
|
|
60
82
|
|
|
61
|
-
let editorFrame: HTMLIFrameElement | undefined;
|
|
62
|
-
|
|
83
|
+
let editorFrame: HTMLIFrameElement | undefined = $state();
|
|
84
|
+
run(() => {
|
|
85
|
+
postParentRoute(editorFrame?.contentWindow, $route);
|
|
86
|
+
});
|
|
63
87
|
|
|
64
88
|
type Mode = 'docked' | 'floating';
|
|
65
89
|
|
|
@@ -106,9 +130,9 @@
|
|
|
106
130
|
}
|
|
107
131
|
|
|
108
132
|
const initial = loadState();
|
|
109
|
-
let mode: Mode = initial.mode;
|
|
110
|
-
let dockedWidth: number = Math.max(MIN_WIDTH, initial.dockedWidth);
|
|
111
|
-
let floating = { ...initial.floating };
|
|
133
|
+
let mode: Mode = $state(initial.mode);
|
|
134
|
+
let dockedWidth: number = $state(Math.max(MIN_WIDTH, initial.dockedWidth));
|
|
135
|
+
let floating = $state({ ...initial.floating });
|
|
112
136
|
|
|
113
137
|
// Approximate natural size of the collapsed pill (Editor title + columns toggle).
|
|
114
138
|
// A few pixels of overshoot is fine — the panel has overflow:hidden.
|
|
@@ -122,11 +146,11 @@
|
|
|
122
146
|
|
|
123
147
|
// Suppress CSS transitions during gestures and mode swaps so dragging doesn't
|
|
124
148
|
// re-animate every frame, and floating↔docked swaps snap cleanly.
|
|
125
|
-
let suppressTransition = false;
|
|
149
|
+
let suppressTransition = $state(false);
|
|
126
150
|
|
|
127
151
|
// Gesture state — a transparent scrim covers the iframe while any gesture is active
|
|
128
152
|
// so pointer events land on the panel, not on content inside the iframe.
|
|
129
|
-
let gesturing: 'drag' | 'resize-left' | 'resize-se' | null = null;
|
|
153
|
+
let gesturing: 'drag' | 'resize-left' | 'resize-se' | null = $state(null);
|
|
130
154
|
|
|
131
155
|
function startDrag(e: PointerEvent) {
|
|
132
156
|
if (!open || mode !== 'floating') return;
|
|
@@ -241,15 +265,15 @@
|
|
|
241
265
|
window.removeEventListener('lt-overlay-toggle', handleToggleRequest);
|
|
242
266
|
});
|
|
243
267
|
|
|
244
|
-
|
|
268
|
+
let panelStyle = $derived(!open
|
|
245
269
|
? `position: fixed; top: 12px; right: 12px; width: ${COLLAPSED_WIDTH}px; height: ${COLLAPSED_HEIGHT}px;`
|
|
246
270
|
: mode === 'docked'
|
|
247
271
|
? `position: fixed; top: 0; right: 0; width: ${dockedWidth}px; height: 100vh;`
|
|
248
|
-
: `position: fixed; top: ${floating.y}px; left: ${floating.x}px; width: ${floating.width}px; height: ${floating.height}px
|
|
272
|
+
: `position: fixed; top: ${floating.y}px; left: ${floating.x}px; width: ${floating.width}px; height: ${floating.height}px;`);
|
|
249
273
|
</script>
|
|
250
274
|
|
|
251
275
|
{#if enabled && !onEditorPath}
|
|
252
|
-
<!-- svelte-ignore
|
|
276
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
253
277
|
<div
|
|
254
278
|
class="lt-overlay"
|
|
255
279
|
style={panelStyle}
|
|
@@ -261,13 +285,13 @@
|
|
|
261
285
|
>
|
|
262
286
|
<div
|
|
263
287
|
class="header"
|
|
264
|
-
|
|
265
|
-
|
|
288
|
+
onpointerdown={startDrag}
|
|
289
|
+
ondblclick={handleHeaderDblClick}
|
|
266
290
|
title={open ? 'Double-click to hide' : 'Double-click to show'}
|
|
267
291
|
>
|
|
268
292
|
<button
|
|
269
293
|
class="hdr-btn text title"
|
|
270
|
-
|
|
294
|
+
onclick={toggleOpen}
|
|
271
295
|
title={open ? 'Hide Editor' : 'Show Editor'}
|
|
272
296
|
>
|
|
273
297
|
<i class="fas {open ? 'fa-chevron-right' : 'fa-chevron-left'}"></i>
|
|
@@ -277,7 +301,7 @@
|
|
|
277
301
|
<button
|
|
278
302
|
class="hdr-btn icon"
|
|
279
303
|
class:active={$columnsVisible}
|
|
280
|
-
|
|
304
|
+
onclick={toggleColumns}
|
|
281
305
|
title="{$columnsVisible ? 'Hide' : 'Show'} columns"
|
|
282
306
|
>
|
|
283
307
|
<i class="fas fa-grip-lines-vertical"></i>
|
|
@@ -287,13 +311,17 @@
|
|
|
287
311
|
<button
|
|
288
312
|
class="hdr-btn icon"
|
|
289
313
|
title={mode === 'docked' ? 'Float' : 'Dock to right'}
|
|
290
|
-
|
|
314
|
+
onclick={toggleMode}
|
|
291
315
|
transition:fade={BTN_FADE}
|
|
292
316
|
>
|
|
293
317
|
<i class={mode === 'docked' ? 'fas fa-up-right-from-square' : 'fas fa-thumbtack'}></i>
|
|
294
318
|
</button>
|
|
295
319
|
{/if}
|
|
296
320
|
|
|
321
|
+
{#if APP_VERSION}
|
|
322
|
+
<span class="version" title="live-tokens version">v{APP_VERSION}</span>
|
|
323
|
+
{/if}
|
|
324
|
+
|
|
297
325
|
{#if open}
|
|
298
326
|
<div class="spacer" transition:fade={BTN_FADE}></div>
|
|
299
327
|
{/if}
|
|
@@ -306,7 +334,7 @@
|
|
|
306
334
|
transition:fade={BTN_FADE}
|
|
307
335
|
>
|
|
308
336
|
<i class="fas fa-code"></i>
|
|
309
|
-
Show
|
|
337
|
+
Show page source
|
|
310
338
|
</a>
|
|
311
339
|
{/if}
|
|
312
340
|
|
|
@@ -322,7 +350,7 @@
|
|
|
322
350
|
class:active={$route === link.path}
|
|
323
351
|
aria-selected={$route === link.path}
|
|
324
352
|
disabled={link.disabled}
|
|
325
|
-
|
|
353
|
+
onclick={() => navigate(link.path)}
|
|
326
354
|
>
|
|
327
355
|
{#if link.icon}<i class="fas {link.icon}"></i>{/if}
|
|
328
356
|
<span>{link.label}</span>
|
|
@@ -340,7 +368,7 @@
|
|
|
340
368
|
title="Token editor"
|
|
341
369
|
class="editor-frame"
|
|
342
370
|
bind:this={editorFrame}
|
|
343
|
-
|
|
371
|
+
onload={() => postParentRoute(editorFrame?.contentWindow, $route)}
|
|
344
372
|
></iframe>
|
|
345
373
|
{#if gesturing}
|
|
346
374
|
<div class="gesture-scrim"></div>
|
|
@@ -348,9 +376,9 @@
|
|
|
348
376
|
</div>
|
|
349
377
|
|
|
350
378
|
{#if mode === 'docked'}
|
|
351
|
-
<div class="resize-left"
|
|
379
|
+
<div class="resize-left" onpointerdown={startDockedResize}></div>
|
|
352
380
|
{:else}
|
|
353
|
-
<div class="resize-se"
|
|
381
|
+
<div class="resize-se" onpointerdown={startFloatingResize}></div>
|
|
354
382
|
{/if}
|
|
355
383
|
{/if}
|
|
356
384
|
</div>
|
|
@@ -454,6 +482,15 @@
|
|
|
454
482
|
|
|
455
483
|
.spacer { flex: 1; }
|
|
456
484
|
|
|
485
|
+
.version {
|
|
486
|
+
font-size: 10px;
|
|
487
|
+
font-weight: 500;
|
|
488
|
+
color: rgba(255, 255, 255, 0.4);
|
|
489
|
+
letter-spacing: 0.02em;
|
|
490
|
+
margin-left: 2px;
|
|
491
|
+
user-select: none;
|
|
492
|
+
}
|
|
493
|
+
|
|
457
494
|
.hdr-btn {
|
|
458
495
|
display: inline-flex;
|
|
459
496
|
align-items: center;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { run } from 'svelte/legacy';
|
|
3
|
+
|
|
2
4
|
import { onMount, onDestroy } from 'svelte';
|
|
3
5
|
import ComponentsTab from '../component-editor/scaffolding/ComponentsTab.svelte';
|
|
4
6
|
import PresetFileManager from '../ui/PresetFileManager.svelte';
|
|
@@ -7,19 +9,19 @@
|
|
|
7
9
|
import { listComponents } from '../lib/componentConfigService';
|
|
8
10
|
import { selectedComponent } from '../lib/editorViewStore';
|
|
9
11
|
|
|
10
|
-
let drawerOpen = true;
|
|
12
|
+
let drawerOpen = $state(true);
|
|
11
13
|
|
|
12
14
|
// Demo page is statically imported from `./Demo.svelte` in App.svelte; the
|
|
13
15
|
// glob resolves to an empty object if the file has been deleted, in which
|
|
14
16
|
// case we hide the demo option from the page-switcher.
|
|
15
17
|
const demoExists = Object.keys(import.meta.glob('./Demo.svelte')).length > 0;
|
|
16
18
|
|
|
17
|
-
let pageMenuOpen = false;
|
|
18
|
-
let pageMenuRoot: HTMLElement;
|
|
19
|
+
let pageMenuOpen = $state(false);
|
|
20
|
+
let pageMenuRoot: HTMLElement | undefined = $state();
|
|
19
21
|
|
|
20
22
|
const HINT_DELAY_MS = 80;
|
|
21
|
-
let hintLabel: string | null = null;
|
|
22
|
-
let hintTop = 0;
|
|
23
|
+
let hintLabel: string | null = $state(null);
|
|
24
|
+
let hintTop = $state(0);
|
|
23
25
|
let hintTimer: ReturnType<typeof setTimeout> | null = null;
|
|
24
26
|
|
|
25
27
|
function showHint(label: string, target: HTMLElement) {
|
|
@@ -40,7 +42,9 @@
|
|
|
40
42
|
hintLabel = null;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
run(() => {
|
|
46
|
+
if (drawerOpen) hideHint();
|
|
47
|
+
});
|
|
44
48
|
|
|
45
49
|
function selectComponent(id: string) {
|
|
46
50
|
selectedComponent.set(id);
|
|
@@ -101,7 +105,7 @@
|
|
|
101
105
|
class="rail-toggle"
|
|
102
106
|
aria-label={drawerOpen ? 'Collapse components menu' : 'Expand components menu'}
|
|
103
107
|
aria-expanded={drawerOpen}
|
|
104
|
-
|
|
108
|
+
onclick={() => (drawerOpen = !drawerOpen)}
|
|
105
109
|
>
|
|
106
110
|
<i class="fas {drawerOpen ? 'fa-arrow-left' : 'fa-arrow-right'}"></i>
|
|
107
111
|
</button>
|
|
@@ -112,19 +116,19 @@
|
|
|
112
116
|
aria-haspopup="menu"
|
|
113
117
|
aria-expanded={pageMenuOpen}
|
|
114
118
|
tabindex={drawerOpen ? 0 : -1}
|
|
115
|
-
|
|
119
|
+
onclick={() => drawerOpen && (pageMenuOpen = !pageMenuOpen)}
|
|
116
120
|
>
|
|
117
121
|
<span class="rail-label">Components</span>
|
|
118
122
|
<i class="fas fa-chevron-down rail-chevron" class:open={pageMenuOpen}></i>
|
|
119
123
|
</button>
|
|
120
124
|
{#if pageMenuOpen && drawerOpen}
|
|
121
125
|
<div class="page-menu" role="menu">
|
|
122
|
-
<button class="page-menu-item" role="menuitem"
|
|
126
|
+
<button class="page-menu-item" role="menuitem" onclick={() => selectPage('/')}>
|
|
123
127
|
<i class="fas fa-home"></i>
|
|
124
128
|
<span>Main site</span>
|
|
125
129
|
</button>
|
|
126
130
|
{#if demoExists}
|
|
127
|
-
<button class="page-menu-item" role="menuitem"
|
|
131
|
+
<button class="page-menu-item" role="menuitem" onclick={() => selectPage('/demo')}>
|
|
128
132
|
<i class="fas fa-box-open"></i>
|
|
129
133
|
<span>Demo page</span>
|
|
130
134
|
</button>
|
|
@@ -137,9 +141,9 @@
|
|
|
137
141
|
<button
|
|
138
142
|
class="nav-item"
|
|
139
143
|
class:active={$selectedComponent === item.id}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
144
|
+
onmouseenter={(e) => showHint(item.label, e.currentTarget)}
|
|
145
|
+
onmouseleave={hideHint}
|
|
146
|
+
onclick={() => selectComponent(item.id)}
|
|
143
147
|
>
|
|
144
148
|
<i class={item.icon}></i>
|
|
145
149
|
<span class="rail-label">{item.label}</span>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { run } from 'svelte/legacy';
|
|
3
|
+
|
|
2
4
|
import { onMount, onDestroy } from 'svelte';
|
|
3
5
|
import { get } from 'svelte/store';
|
|
4
6
|
import VariablesTab from '../ui/VariablesTab.svelte';
|
|
@@ -28,18 +30,18 @@
|
|
|
28
30
|
|
|
29
31
|
const componentNavItems = componentRegistryEntries.map(({ id, label, icon }) => ({ id, label, icon }));
|
|
30
32
|
|
|
31
|
-
let selectedTokenSection: string | null = null;
|
|
32
|
-
let saveStatus: 'idle' | 'saving' | 'saved' | 'error' = 'idle';
|
|
33
|
+
let selectedTokenSection: string | null = $state(null);
|
|
34
|
+
let saveStatus: 'idle' | 'saving' | 'saved' | 'error' = $state('idle');
|
|
33
35
|
|
|
34
|
-
let shellEl: HTMLElement | null = null;
|
|
35
|
-
let shellWidth = 1024;
|
|
36
|
+
let shellEl: HTMLElement | null = $state(null);
|
|
37
|
+
let shellWidth = $state(1024);
|
|
36
38
|
const CONDENSE_BELOW = 520;
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
let condensed = $derived($sidebarCondensed === 'auto' ? shellWidth < CONDENSE_BELOW : $sidebarCondensed);
|
|
39
41
|
|
|
40
42
|
const HINT_DELAY_MS = 80;
|
|
41
|
-
let hintLabel: string | null = null;
|
|
42
|
-
let hintTop = 0;
|
|
43
|
+
let hintLabel: string | null = $state(null);
|
|
44
|
+
let hintTop = $state(0);
|
|
43
45
|
let hintTimer: ReturnType<typeof setTimeout> | null = null;
|
|
44
46
|
|
|
45
47
|
function showHint(label: string, target: HTMLElement) {
|
|
@@ -60,7 +62,9 @@
|
|
|
60
62
|
hintLabel = null;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
|
|
65
|
+
run(() => {
|
|
66
|
+
if (!condensed) hideHint();
|
|
67
|
+
});
|
|
64
68
|
|
|
65
69
|
function scrollToSection(sectionId: string) {
|
|
66
70
|
selectedTokenSection = sectionId;
|
|
@@ -80,8 +84,8 @@
|
|
|
80
84
|
});
|
|
81
85
|
}
|
|
82
86
|
|
|
83
|
-
async function handleSave(
|
|
84
|
-
const { fileName, displayName } =
|
|
87
|
+
async function handleSave(detail: { fileName: string; displayName: string }) {
|
|
88
|
+
const { fileName, displayName } = detail;
|
|
85
89
|
saveStatus = 'saving';
|
|
86
90
|
try {
|
|
87
91
|
await persistTheme(get(editorState), fileName, displayName);
|
|
@@ -93,9 +97,9 @@
|
|
|
93
97
|
}
|
|
94
98
|
}
|
|
95
99
|
|
|
96
|
-
async function handleLoad(
|
|
100
|
+
async function handleLoad(detail: { fileName: string }) {
|
|
97
101
|
try {
|
|
98
|
-
await hydrateTheme(
|
|
102
|
+
await hydrateTheme(detail.fileName);
|
|
99
103
|
} catch {
|
|
100
104
|
// silent
|
|
101
105
|
}
|
|
@@ -132,7 +136,7 @@
|
|
|
132
136
|
class="rail-toggle"
|
|
133
137
|
aria-label={condensed ? 'Expand sidebar' : 'Collapse sidebar'}
|
|
134
138
|
aria-expanded={!condensed}
|
|
135
|
-
|
|
139
|
+
onclick={toggleCondensed}
|
|
136
140
|
>
|
|
137
141
|
<i class="fas {condensed ? 'fa-arrow-right' : 'fa-arrow-left'}"></i>
|
|
138
142
|
</button>
|
|
@@ -146,9 +150,9 @@
|
|
|
146
150
|
<button
|
|
147
151
|
class="nav-item"
|
|
148
152
|
class:active={selectedTokenSection === item.id}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
153
|
+
onmouseenter={(e) => showHint(item.label, e.currentTarget)}
|
|
154
|
+
onmouseleave={hideHint}
|
|
155
|
+
onclick={() => scrollToSection(item.id)}
|
|
152
156
|
>
|
|
153
157
|
<i class={item.icon}></i>
|
|
154
158
|
<span class="nav-label">{item.label}</span>
|
|
@@ -157,7 +161,7 @@
|
|
|
157
161
|
</div>
|
|
158
162
|
{#if !condensed}
|
|
159
163
|
<div class="sidebar-footer">
|
|
160
|
-
<ThemeFileManager {saveStatus}
|
|
164
|
+
<ThemeFileManager {saveStatus} onsave={handleSave} onload={handleLoad} />
|
|
161
165
|
</div>
|
|
162
166
|
{/if}
|
|
163
167
|
{:else}
|
|
@@ -166,9 +170,9 @@
|
|
|
166
170
|
<button
|
|
167
171
|
class="nav-item"
|
|
168
172
|
class:active={$selectedComponent === item.id}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
173
|
+
onmouseenter={(e) => showHint(item.label, e.currentTarget)}
|
|
174
|
+
onmouseleave={hideHint}
|
|
175
|
+
onclick={() => selectComponent(item.id)}
|
|
172
176
|
>
|
|
173
177
|
<i class={item.icon}></i>
|
|
174
178
|
<span class="nav-label">{item.label}</span>
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
font-family: var(--font-sans);
|
|
70
70
|
font-size: var(--font-size-md);
|
|
71
71
|
font-weight: var(--font-weight-light);
|
|
72
|
-
line-height: var(--line-height-
|
|
72
|
+
line-height: var(--line-height-md);
|
|
73
73
|
vertical-align: middle;
|
|
74
74
|
cursor: pointer;
|
|
75
75
|
transition: all var(--duration-150);
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
min-height: 2rem;
|
|
125
125
|
font-size: var(--font-size-md);
|
|
126
126
|
font-family: var(--font-sans);
|
|
127
|
-
line-height: var(--line-height-
|
|
127
|
+
line-height: var(--line-height-md);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
/* Disabled options */
|