@motion-proto/live-tokens 0.1.0 → 0.3.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.
Files changed (225) hide show
  1. package/README.md +160 -21
  2. package/dist-plugin/index.cjs +823 -336
  3. package/dist-plugin/index.d.cts +9 -7
  4. package/dist-plugin/index.d.ts +9 -7
  5. package/dist-plugin/index.js +822 -335
  6. package/package.json +51 -23
  7. package/src/assets/newspaper.webp +0 -0
  8. package/src/assets/offering.webp +0 -0
  9. package/src/component-editor/BadgeEditor.svelte +170 -0
  10. package/src/component-editor/CalloutEditor.svelte +103 -0
  11. package/src/component-editor/CardEditor.svelte +184 -0
  12. package/src/component-editor/CollapsibleSectionEditor.svelte +167 -0
  13. package/src/component-editor/CornerBadgeEditor.svelte +207 -0
  14. package/src/component-editor/DialogEditor.svelte +172 -0
  15. package/src/component-editor/ImageEditor.svelte +72 -0
  16. package/src/component-editor/InlineEditActionsEditor.svelte +83 -0
  17. package/src/component-editor/NotificationEditor.svelte +160 -0
  18. package/src/component-editor/ProgressBarEditor.svelte +124 -0
  19. package/src/component-editor/RadioButtonEditor.svelte +140 -0
  20. package/src/component-editor/SectionDividerEditor.svelte +263 -0
  21. package/src/component-editor/SegmentedControlEditor.svelte +154 -0
  22. package/src/component-editor/StandardButtonsEditor.svelte +178 -0
  23. package/src/component-editor/TabBarEditor.svelte +137 -0
  24. package/src/component-editor/TableEditor.svelte +128 -0
  25. package/src/component-editor/TooltipEditor.svelte +122 -0
  26. package/src/component-editor/editorTokens.test.ts +93 -0
  27. package/src/component-editor/groupKeySlots.test.ts +67 -0
  28. package/src/component-editor/groupKeySnapshot.test.ts +52 -0
  29. package/src/component-editor/index.ts +5 -0
  30. package/src/component-editor/registry.ts +246 -0
  31. package/src/component-editor/scaffolding/AngleDial.svelte +185 -0
  32. package/src/component-editor/scaffolding/ComponentEditorBase.svelte +96 -0
  33. package/src/component-editor/scaffolding/ComponentFileManager.svelte +682 -0
  34. package/src/component-editor/scaffolding/ComponentFileMenu.svelte +312 -0
  35. package/src/component-editor/scaffolding/ComponentsTab.svelte +69 -0
  36. package/src/component-editor/scaffolding/CopyFromMenu.svelte +246 -0
  37. package/src/component-editor/scaffolding/DemoHeader.svelte +21 -0
  38. package/src/component-editor/scaffolding/DividerEditor.svelte +81 -0
  39. package/src/component-editor/scaffolding/FieldsetWrapper.svelte +46 -0
  40. package/src/component-editor/scaffolding/GradientCard.svelte +291 -0
  41. package/src/component-editor/scaffolding/LinkageChart.svelte +297 -0
  42. package/src/component-editor/scaffolding/LinkedBlock.svelte +418 -0
  43. package/src/component-editor/scaffolding/NonStylableConfig.svelte +57 -0
  44. package/src/component-editor/scaffolding/SaveAsDialog.svelte +177 -0
  45. package/src/component-editor/scaffolding/ShadowBackdrop.svelte +25 -0
  46. package/src/component-editor/scaffolding/ShadowBackdropControls.svelte +56 -0
  47. package/src/component-editor/scaffolding/StateBlock.svelte +115 -0
  48. package/src/component-editor/scaffolding/TokenLayout.svelte +511 -0
  49. package/src/component-editor/scaffolding/TypeEditor.svelte +82 -0
  50. package/src/component-editor/scaffolding/VariantGroup.svelte +277 -0
  51. package/src/component-editor/scaffolding/buildTypeGroupTokens.ts +97 -0
  52. package/src/component-editor/scaffolding/componentSectionType.ts +8 -0
  53. package/src/component-editor/scaffolding/componentSources.ts +9 -0
  54. package/src/component-editor/scaffolding/defaultSections.ts +16 -0
  55. package/src/component-editor/scaffolding/editorContext.ts +44 -0
  56. package/src/component-editor/scaffolding/linkedBlock.ts +226 -0
  57. package/src/component-editor/scaffolding/siblings.ts +33 -0
  58. package/src/component-editor/scaffolding/types.ts +39 -0
  59. package/src/components/Badge.svelte +231 -42
  60. package/src/components/Button.svelte +324 -124
  61. package/src/components/Callout.svelte +145 -0
  62. package/src/components/Card.svelte +123 -25
  63. package/src/components/CollapsibleSection.svelte +213 -35
  64. package/src/components/CornerBadge.svelte +224 -0
  65. package/src/components/Dialog.svelte +137 -114
  66. package/src/components/Image.svelte +43 -0
  67. package/src/components/InlineEditActions.svelte +74 -14
  68. package/src/components/Notification.svelte +184 -163
  69. package/src/components/ProgressBar.svelte +216 -22
  70. package/src/components/RadioButton.svelte +110 -40
  71. package/src/components/SectionDivider.svelte +428 -74
  72. package/src/components/SegmentedControl.svelte +203 -0
  73. package/src/components/TabBar.svelte +146 -21
  74. package/src/components/Table.svelte +102 -0
  75. package/src/components/Tooltip.svelte +45 -19
  76. package/src/components/types.ts +51 -0
  77. package/src/data/google-fonts.json +75 -0
  78. package/src/lib/ColumnsOverlay.svelte +20 -7
  79. package/src/lib/LiveEditorOverlay.svelte +265 -82
  80. package/src/lib/columnsOverlay.ts +21 -17
  81. package/src/lib/componentConfig.test.ts +204 -0
  82. package/src/lib/componentConfigKeys.ts +19 -0
  83. package/src/lib/componentConfigService.ts +88 -0
  84. package/src/lib/copyPopover.ts +30 -0
  85. package/src/lib/cssVarSync.ts +59 -7
  86. package/src/lib/editorConfigStore.ts +0 -10
  87. package/src/lib/editorCore.ts +402 -0
  88. package/src/lib/editorKeybindings.ts +52 -0
  89. package/src/lib/editorPersistence.ts +106 -0
  90. package/src/lib/editorRenderer.ts +74 -0
  91. package/src/lib/editorStore.test.ts +328 -0
  92. package/src/lib/editorStore.ts +412 -0
  93. package/src/lib/editorTypes.ts +100 -0
  94. package/src/lib/editorViewStore.ts +55 -0
  95. package/src/lib/files/versionedFileResource.ts +140 -0
  96. package/src/lib/fontLoader.ts +130 -0
  97. package/src/lib/fontMigration.ts +140 -0
  98. package/src/lib/fontParse.ts +168 -0
  99. package/src/lib/index.ts +48 -31
  100. package/src/lib/lazyConfig.test.ts +54 -0
  101. package/src/lib/migrations/2026-04-24-component-prefix-and-suffix-renames.ts +64 -0
  102. package/src/lib/migrations/2026-04-24-legacy-keys-and-bg-to-canvas.ts +71 -0
  103. package/src/lib/migrations/2026-04-27-segmentedcontrol-disabled-flatten.ts +43 -0
  104. package/src/lib/migrations/2026-05-08-collapsiblesection-frame-and-cleanup.ts +68 -0
  105. package/src/lib/migrations/2026-05-08-collapsiblesection-variant-namespace.ts +35 -0
  106. package/src/lib/migrations/2026-05-10-sectiondivider-gradient-stops.ts +50 -0
  107. package/src/lib/migrations/2026-05-13-primary-to-brand.ts +90 -0
  108. package/src/lib/migrations/index.ts +93 -0
  109. package/src/lib/migrations/migrations.test.ts +341 -0
  110. package/src/lib/navLinkTypes.ts +1 -0
  111. package/src/lib/overlayState.ts +3 -0
  112. package/src/lib/paletteDerivation.ts +300 -0
  113. package/src/lib/parentRouteStore.ts +42 -0
  114. package/src/lib/parsers/globalRootBlock.ts +32 -0
  115. package/src/lib/presetService.ts +94 -0
  116. package/src/lib/router.ts +49 -0
  117. package/src/lib/scrollSection.ts +45 -0
  118. package/src/lib/slices/columns.ts +59 -0
  119. package/src/lib/slices/components.ts +362 -0
  120. package/src/lib/slices/domainVars.ts +15 -0
  121. package/src/lib/slices/fonts.ts +30 -0
  122. package/src/lib/slices/gradients.ts +153 -0
  123. package/src/lib/slices/overlays.ts +132 -0
  124. package/src/lib/slices/palettes.ts +26 -0
  125. package/src/lib/slices/shadows.ts +123 -0
  126. package/src/lib/storage.ts +88 -0
  127. package/src/lib/themeInit.ts +74 -0
  128. package/src/lib/themeService.ts +101 -0
  129. package/src/lib/themeTypes.ts +146 -0
  130. package/src/lib/tokenRegistry.ts +148 -0
  131. package/src/pages/ComponentEditorPage.svelte +384 -0
  132. package/src/pages/ComponentEditorPage.svelte.d.ts +2 -0
  133. package/src/pages/Editor.svelte +98 -0
  134. package/src/pages/Editor.svelte.d.ts +2 -0
  135. package/src/pages/EditorShell.svelte +348 -0
  136. package/src/styles/_padding.scss +34 -0
  137. package/src/styles/fonts/Fraunces/Fraunces-italic-latin-ext.woff2 +0 -0
  138. package/src/styles/fonts/Fraunces/Fraunces-italic-latin.woff2 +0 -0
  139. package/src/styles/fonts/Fraunces/Fraunces-roman-latin-ext.woff2 +0 -0
  140. package/src/styles/fonts/Fraunces/Fraunces-roman-latin.woff2 +0 -0
  141. package/src/styles/fonts/Manrope/Manrope-latin-ext.woff2 +0 -0
  142. package/src/styles/fonts/Manrope/Manrope-latin.woff2 +0 -0
  143. package/src/styles/fonts.css +22 -10
  144. package/src/styles/form-controls.css +14 -16
  145. package/src/styles/tokens.css +1322 -0
  146. package/src/styles/ui-editor.css +126 -0
  147. package/src/{showcase → ui}/BezierCurveEditor.svelte +14 -14
  148. package/src/{showcase → ui}/ColorEditPanel.svelte +42 -36
  149. package/src/ui/EditorViewSwitcher.svelte +180 -0
  150. package/src/ui/FontStackEditor.svelte +360 -0
  151. package/src/ui/GradientEditor.svelte +461 -0
  152. package/src/ui/GradientStopPicker.svelte +74 -0
  153. package/src/ui/PaletteEditor.svelte +1590 -0
  154. package/src/ui/PaletteEditor.test.ts +108 -0
  155. package/src/ui/PresetFileManager.svelte +567 -0
  156. package/src/ui/ProjectFontsSection.svelte +645 -0
  157. package/src/{showcase → ui}/SurfacesTab.svelte +39 -41
  158. package/src/{showcase → ui}/TextTab.svelte +27 -29
  159. package/src/{showcase/TokenFileManager.svelte → ui/ThemeFileManager.svelte} +196 -112
  160. package/src/ui/Toggle.svelte +108 -0
  161. package/src/ui/UICopyPopover.svelte +78 -0
  162. package/src/{showcase/EditorDialog.svelte → ui/UIDialog.svelte} +66 -25
  163. package/src/ui/UIFontFamilySelector.svelte +309 -0
  164. package/src/ui/UIFontSizeSelector.svelte +165 -0
  165. package/src/ui/UIFontWeightSelector.svelte +52 -0
  166. package/src/ui/UILineHeightSelector.svelte +47 -0
  167. package/src/ui/UILinkToggle.svelte +60 -0
  168. package/src/ui/UIOptionItem.svelte +74 -0
  169. package/src/ui/UIOptionList.svelte +27 -0
  170. package/src/ui/UIPaddingSelector.svelte +661 -0
  171. package/src/ui/UIPaletteSelector.svelte +1084 -0
  172. package/src/ui/UIRadio.svelte +72 -0
  173. package/src/ui/UIRadioGroup.svelte +59 -0
  174. package/src/ui/UIRelinkConfirmPopover.svelte +235 -0
  175. package/src/ui/UITokenSelector.svelte +509 -0
  176. package/src/ui/UIVariantSelector.svelte +145 -0
  177. package/src/ui/VariablesTab.svelte +252 -0
  178. package/src/ui/index.ts +31 -0
  179. package/src/ui/keepInViewport.ts +84 -0
  180. package/src/ui/palette/GradientStopEditor.svelte +482 -0
  181. package/src/ui/palette/OverridesPanel.svelte +526 -0
  182. package/src/ui/palette/PaletteBase.svelte +165 -0
  183. package/src/ui/palette/ScaleCurveEditor.svelte +38 -0
  184. package/src/ui/palette/paletteEditorState.ts +89 -0
  185. package/src/ui/sections/ColumnsSection.svelte +273 -0
  186. package/src/ui/sections/GradientsSection.svelte +147 -0
  187. package/src/ui/sections/OverlaysSection.svelte +670 -0
  188. package/src/ui/sections/ShadowsSection.svelte +1250 -0
  189. package/src/ui/sections/TokenScaleTable.svelte +332 -0
  190. package/src/ui/sections/tokenScales.ts +81 -0
  191. package/src/ui/variantScales.ts +108 -0
  192. package/src/components/DetailNav.svelte +0 -78
  193. package/src/components/Toggle.svelte +0 -86
  194. package/src/lib/pageSource.ts +0 -6
  195. package/src/lib/tokenInit.ts +0 -29
  196. package/src/lib/tokenService.ts +0 -144
  197. package/src/lib/tokenTypes.ts +0 -45
  198. package/src/pages/Admin.svelte +0 -100
  199. package/src/pages/ShowcasePage.svelte +0 -146
  200. package/src/showcase/BackupBrowser.svelte +0 -617
  201. package/src/showcase/ComponentsTab.svelte +0 -107
  202. package/src/showcase/PaletteEditor.svelte +0 -2579
  203. package/src/showcase/PaletteSelector.svelte +0 -627
  204. package/src/showcase/TokenMap.svelte +0 -54
  205. package/src/showcase/VariablesTab.svelte +0 -2657
  206. package/src/showcase/VisualsTab.svelte +0 -233
  207. package/src/showcase/demos/BadgeDemo.svelte +0 -58
  208. package/src/showcase/demos/CardDemo.svelte +0 -52
  209. package/src/showcase/demos/ChoiceButtonsDemo.svelte +0 -194
  210. package/src/showcase/demos/CollapsibleSectionDemo.svelte +0 -56
  211. package/src/showcase/demos/DialogDemo.svelte +0 -42
  212. package/src/showcase/demos/InlineEditActionsDemo.svelte +0 -27
  213. package/src/showcase/demos/NotificationDemo.svelte +0 -149
  214. package/src/showcase/demos/ProgressBarDemo.svelte +0 -56
  215. package/src/showcase/demos/RadioButtonDemo.svelte +0 -58
  216. package/src/showcase/demos/SectionDividerDemo.svelte +0 -79
  217. package/src/showcase/demos/StandardButtonsDemo.svelte +0 -457
  218. package/src/showcase/demos/TabBarDemo.svelte +0 -60
  219. package/src/showcase/demos/TooltipDemo.svelte +0 -54
  220. package/src/showcase/editor.css +0 -93
  221. package/src/showcase/index.ts +0 -17
  222. package/src/styles/fonts/Domine/Domine-VariableFont_wght.ttf +0 -0
  223. package/src/styles/fonts/Domine/OFL.txt +0 -97
  224. package/src/styles/fonts/Domine/README.txt +0 -66
  225. /package/src/{showcase → ui}/curveEngine.ts +0 -0
@@ -0,0 +1,384 @@
1
+ <script lang="ts">
2
+ import { onMount, onDestroy } from 'svelte';
3
+ import ComponentsTab from '../component-editor/scaffolding/ComponentsTab.svelte';
4
+ import PresetFileManager from '../ui/PresetFileManager.svelte';
5
+ import { navigate } from '../lib/router';
6
+ import { componentRegistryEntries, validateRegistryAgainstServerScan } from '../component-editor/registry';
7
+ import { listComponents } from '../lib/componentConfigService';
8
+ import { selectedComponent } from '../lib/editorViewStore';
9
+
10
+ let drawerOpen = true;
11
+
12
+ // Demo page is statically imported from `./Demo.svelte` in App.svelte; the
13
+ // glob resolves to an empty object if the file has been deleted, in which
14
+ // case we hide the demo option from the page-switcher.
15
+ const demoExists = Object.keys(import.meta.glob('./Demo.svelte')).length > 0;
16
+
17
+ let pageMenuOpen = false;
18
+ let pageMenuRoot: HTMLElement;
19
+
20
+ const HINT_DELAY_MS = 80;
21
+ let hintLabel: string | null = null;
22
+ let hintTop = 0;
23
+ let hintTimer: ReturnType<typeof setTimeout> | null = null;
24
+
25
+ function showHint(label: string, target: HTMLElement) {
26
+ if (drawerOpen) return;
27
+ if (hintTimer) clearTimeout(hintTimer);
28
+ const top = target.getBoundingClientRect().top + target.offsetHeight / 2;
29
+ hintTimer = setTimeout(() => {
30
+ hintLabel = label;
31
+ hintTop = top;
32
+ }, HINT_DELAY_MS);
33
+ }
34
+
35
+ function hideHint() {
36
+ if (hintTimer) {
37
+ clearTimeout(hintTimer);
38
+ hintTimer = null;
39
+ }
40
+ hintLabel = null;
41
+ }
42
+
43
+ $: if (drawerOpen) hideHint();
44
+
45
+ function selectComponent(id: string) {
46
+ selectedComponent.set(id);
47
+ hideHint();
48
+ }
49
+
50
+ function selectPage(path: string) {
51
+ pageMenuOpen = false;
52
+ navigate(path);
53
+ }
54
+
55
+ function handleDocClick(e: MouseEvent) {
56
+ if (!pageMenuOpen) return;
57
+ if (pageMenuRoot && !pageMenuRoot.contains(e.target as Node)) {
58
+ pageMenuOpen = false;
59
+ }
60
+ }
61
+
62
+ function handleKeydown(e: KeyboardEvent) {
63
+ if (e.key === 'Escape') {
64
+ if (pageMenuOpen) pageMenuOpen = false;
65
+ else if (drawerOpen) drawerOpen = false;
66
+ }
67
+ }
68
+
69
+ onMount(async () => {
70
+ document.addEventListener('click', handleDocClick, true);
71
+ window.addEventListener('keydown', handleKeydown);
72
+ try {
73
+ const summaries = await listComponents();
74
+ validateRegistryAgainstServerScan(summaries.map((s) => s.name));
75
+ } catch {
76
+ // Server unreachable — registry's eager schema registration still works
77
+ // for the editor; validation just gets skipped this boot.
78
+ }
79
+ });
80
+
81
+ onDestroy(() => {
82
+ document.removeEventListener('click', handleDocClick, true);
83
+ window.removeEventListener('keydown', handleKeydown);
84
+ });
85
+
86
+ const componentNavItems = componentRegistryEntries.map(({ id, label, icon }) => ({ id, label, icon }));
87
+ </script>
88
+
89
+ <!--
90
+ Site-level component editor page. Wrapped in .editor-page so the
91
+ ComponentsTab scaffolding (labels, section wrappers) can resolve its
92
+ --ui-* custom properties from styles/ui-editor.css. The actual components inside
93
+ still read the user's design tokens, so live edits in the overlay
94
+ editor flow straight through to this page.
95
+ -->
96
+ <div class="editor-page components-shell" class:rail-expanded={drawerOpen}>
97
+ <nav class="sidebar rail" class:expanded={drawerOpen}>
98
+ <div class="rail-header" bind:this={pageMenuRoot}>
99
+ <button
100
+ type="button"
101
+ class="rail-toggle"
102
+ aria-label={drawerOpen ? 'Collapse components menu' : 'Expand components menu'}
103
+ aria-expanded={drawerOpen}
104
+ on:click={() => (drawerOpen = !drawerOpen)}
105
+ >
106
+ <i class="fas {drawerOpen ? 'fa-arrow-left' : 'fa-arrow-right'}"></i>
107
+ </button>
108
+ <button
109
+ type="button"
110
+ class="page-menu-trigger"
111
+ class:open={pageMenuOpen}
112
+ aria-haspopup="menu"
113
+ aria-expanded={pageMenuOpen}
114
+ tabindex={drawerOpen ? 0 : -1}
115
+ on:click={() => drawerOpen && (pageMenuOpen = !pageMenuOpen)}
116
+ >
117
+ <span class="rail-label">Components</span>
118
+ <i class="fas fa-chevron-down rail-chevron" class:open={pageMenuOpen}></i>
119
+ </button>
120
+ {#if pageMenuOpen && drawerOpen}
121
+ <div class="page-menu" role="menu">
122
+ <button class="page-menu-item" role="menuitem" on:click={() => selectPage('/')}>
123
+ <i class="fas fa-home"></i>
124
+ <span>Main site</span>
125
+ </button>
126
+ {#if demoExists}
127
+ <button class="page-menu-item" role="menuitem" on:click={() => selectPage('/demo')}>
128
+ <i class="fas fa-box-open"></i>
129
+ <span>Demo page</span>
130
+ </button>
131
+ {/if}
132
+ </div>
133
+ {/if}
134
+ </div>
135
+ <div class="nav-items">
136
+ {#each componentNavItems as item}
137
+ <button
138
+ class="nav-item"
139
+ class:active={$selectedComponent === item.id}
140
+ on:mouseenter={(e) => showHint(item.label, e.currentTarget)}
141
+ on:mouseleave={hideHint}
142
+ on:click={() => selectComponent(item.id)}
143
+ >
144
+ <i class={item.icon}></i>
145
+ <span class="rail-label">{item.label}</span>
146
+ </button>
147
+ {/each}
148
+ </div>
149
+ {#if drawerOpen}
150
+ <div class="sidebar-footer">
151
+ <PresetFileManager />
152
+ </div>
153
+ {/if}
154
+ </nav>
155
+
156
+ <main class="content">
157
+ <ComponentsTab selectedComponent={$selectedComponent} />
158
+ </main>
159
+
160
+ {#if hintLabel !== null && !drawerOpen}
161
+ <div class="rail-hint" style="top: {hintTop}px">{hintLabel}</div>
162
+ {/if}
163
+ </div>
164
+
165
+ <style>
166
+ @import '../styles/ui-editor.css';
167
+ .components-shell {
168
+ --rail-w: 48px;
169
+ display: grid;
170
+ grid-template-columns: var(--rail-w) minmax(0, 1fr);
171
+ height: 100vh;
172
+ width: 100%;
173
+ background: black;
174
+ overflow: hidden;
175
+ transition: grid-template-columns 220ms ease;
176
+ }
177
+
178
+ .components-shell.rail-expanded {
179
+ --rail-w: 240px;
180
+ }
181
+
182
+ .sidebar.rail {
183
+ position: relative;
184
+ height: 100vh;
185
+ overflow-y: auto;
186
+ overflow-x: hidden;
187
+ background: black;
188
+ border-right: 1px solid var(--ui-border-faint);
189
+ display: flex;
190
+ flex-direction: column;
191
+ min-width: 0;
192
+ }
193
+
194
+ .rail-header {
195
+ position: relative;
196
+ display: grid;
197
+ grid-template-columns: 48px 1fr;
198
+ align-items: center;
199
+ padding: var(--ui-space-12) 0 var(--ui-space-12) 0;
200
+ border-bottom: 1px solid var(--ui-border-faint);
201
+ }
202
+
203
+ .rail-toggle {
204
+ display: flex;
205
+ align-items: center;
206
+ justify-content: center;
207
+ width: 48px;
208
+ height: 36px;
209
+ padding: 0;
210
+ background: none;
211
+ border: none;
212
+ color: var(--ui-text-primary);
213
+ cursor: pointer;
214
+ transition: background var(--ui-transition-fast);
215
+ }
216
+
217
+ .rail-toggle:hover {
218
+ background: var(--ui-hover);
219
+ }
220
+
221
+ .page-menu-trigger {
222
+ display: flex;
223
+ align-items: center;
224
+ justify-content: space-between;
225
+ gap: var(--ui-space-8);
226
+ height: 36px;
227
+ padding: 0 var(--ui-space-10) 0 0;
228
+ background: none;
229
+ border: none;
230
+ color: var(--ui-text-primary);
231
+ font-family: inherit;
232
+ font-size: var(--ui-font-size-lg);
233
+ font-weight: var(--ui-font-weight-bold);
234
+ text-align: left;
235
+ cursor: pointer;
236
+ transition: opacity 180ms ease;
237
+ opacity: 0;
238
+ pointer-events: none;
239
+ }
240
+
241
+ .components-shell.rail-expanded .page-menu-trigger {
242
+ opacity: 1;
243
+ pointer-events: auto;
244
+ }
245
+
246
+ .rail-chevron {
247
+ font-size: 0.7em;
248
+ color: var(--ui-text-tertiary);
249
+ transition: transform var(--ui-transition-fast);
250
+ }
251
+
252
+ .rail-chevron.open {
253
+ transform: rotate(180deg);
254
+ }
255
+
256
+ .rail-label {
257
+ white-space: nowrap;
258
+ overflow: hidden;
259
+ opacity: 0;
260
+ transition: opacity 180ms ease;
261
+ }
262
+
263
+ .components-shell.rail-expanded .rail-label {
264
+ opacity: 1;
265
+ }
266
+
267
+ .page-menu {
268
+ position: absolute;
269
+ top: calc(100% - var(--ui-space-2));
270
+ left: 48px;
271
+ right: var(--ui-space-8);
272
+ background: var(--ui-surface-low);
273
+ border: 1px solid var(--ui-border-default);
274
+ border-radius: var(--ui-radius-md);
275
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
276
+ padding: var(--ui-space-4);
277
+ display: flex;
278
+ flex-direction: column;
279
+ gap: 2px;
280
+ z-index: 10;
281
+ }
282
+
283
+ .page-menu-item {
284
+ display: flex;
285
+ align-items: center;
286
+ gap: var(--ui-space-8);
287
+ padding: var(--ui-space-6) var(--ui-space-10);
288
+ background: none;
289
+ border: none;
290
+ border-radius: var(--ui-radius-sm);
291
+ color: var(--ui-text-secondary);
292
+ font-family: inherit;
293
+ font-size: var(--ui-font-size-md);
294
+ text-align: left;
295
+ cursor: pointer;
296
+ transition: background var(--ui-transition-fast), color var(--ui-transition-fast);
297
+ }
298
+
299
+ .page-menu-item i {
300
+ width: 1rem;
301
+ text-align: center;
302
+ opacity: 0.7;
303
+ }
304
+
305
+ .page-menu-item:hover {
306
+ background: var(--ui-hover);
307
+ color: var(--ui-text-primary);
308
+ }
309
+
310
+ .nav-items {
311
+ display: flex;
312
+ flex-direction: column;
313
+ gap: var(--ui-space-2);
314
+ padding: 0 0 var(--ui-space-16);
315
+ background: black;
316
+ }
317
+
318
+ .sidebar-footer {
319
+ flex-shrink: 0;
320
+ margin-top: auto;
321
+ padding: var(--ui-space-12) var(--ui-space-8) var(--ui-space-16);
322
+ border-top: 1px solid var(--ui-border-faint);
323
+ }
324
+
325
+ .nav-item {
326
+ display: grid;
327
+ grid-template-columns: 48px 1fr;
328
+ align-items: center;
329
+ width: 100%;
330
+ height: 36px;
331
+ padding: 0;
332
+ background: none;
333
+ border: none;
334
+ border-radius: 0;
335
+ color: var(--ui-text-tertiary);
336
+ font-size: var(--ui-font-size-md);
337
+ cursor: pointer;
338
+ text-align: left;
339
+ overflow: hidden;
340
+ transition: color 60ms ease, background 60ms ease;
341
+ }
342
+
343
+ .nav-item:hover {
344
+ color: var(--ui-text-secondary);
345
+ background: var(--ui-hover);
346
+ }
347
+
348
+ .nav-item.active {
349
+ color: var(--ui-text-primary);
350
+ background: var(--ui-surface-high);
351
+ }
352
+
353
+ .nav-item i {
354
+ justify-self: center;
355
+ width: 1.25rem;
356
+ text-align: center;
357
+ font-size: var(--ui-font-size-md);
358
+ opacity: 0.85;
359
+ }
360
+
361
+ .content {
362
+ padding: 0 var(--ui-space-32);
363
+ background: black;
364
+ min-width: 0;
365
+ height: 100vh;
366
+ overflow-y: auto;
367
+ }
368
+
369
+ .rail-hint {
370
+ position: fixed;
371
+ left: calc(var(--rail-w) + var(--ui-space-6));
372
+ transform: translateY(-50%);
373
+ z-index: 50;
374
+ padding: var(--ui-space-4) var(--ui-space-8);
375
+ background: var(--ui-surface-low);
376
+ border: 1px solid var(--ui-border-default);
377
+ border-radius: var(--ui-radius-sm);
378
+ color: var(--ui-text-primary);
379
+ font-size: var(--ui-font-size-sm);
380
+ white-space: nowrap;
381
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
382
+ pointer-events: none;
383
+ }
384
+ </style>
@@ -0,0 +1,2 @@
1
+ import { SvelteComponent } from 'svelte';
2
+ export default class ComponentEditorPage extends SvelteComponent<Record<string, never>> {}
@@ -0,0 +1,98 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import EditorShell from './EditorShell.svelte';
4
+ import UICopyPopover from '../ui/UICopyPopover.svelte';
5
+ import { installEditorKeybindings } from '../lib/editorKeybindings';
6
+ import { initializeEditorStore } from '../lib/editorStore';
7
+ import { storageKey } from '../lib/editorConfig';
8
+
9
+ const inOverlay = typeof window !== 'undefined' && window.parent !== window;
10
+
11
+ // Where "Back to site" sends the user. Prefer the previous non-editor entry
12
+ // from session history; fall back to /demo and finally /.
13
+ const backHref = pickBackHref();
14
+
15
+ function pickBackHref(): string {
16
+ try {
17
+ const prev = sessionStorage.getItem(storageKey('prev-route'));
18
+ if (prev && prev !== '/editor') return prev;
19
+ } catch {
20
+ // ignore
21
+ }
22
+ return '/demo';
23
+ }
24
+
25
+ onMount(() => {
26
+ initializeEditorStore();
27
+ return installEditorKeybindings();
28
+ });
29
+ </script>
30
+
31
+ <div class="editor-page">
32
+ {#if !inOverlay}
33
+ <div class="editor-bar">
34
+ <div class="bar-left">
35
+ <a href={backHref} class="back-link">
36
+ <i class="fas fa-arrow-left"></i>
37
+ <span>Back to site</span>
38
+ </a>
39
+ <span class="editor-label">Editor</span>
40
+ </div>
41
+ </div>
42
+ {/if}
43
+
44
+ <EditorShell />
45
+ <UICopyPopover />
46
+ </div>
47
+
48
+ <style>
49
+ @import '../styles/ui-editor.css';
50
+
51
+ .editor-page {
52
+ min-height: 100vh;
53
+ background: black;
54
+ }
55
+
56
+ .editor-bar {
57
+ display: flex;
58
+ align-items: center;
59
+ gap: var(--ui-space-16);
60
+ padding: var(--ui-space-10) var(--ui-space-16);
61
+ background: black;
62
+ border-bottom: 1px solid var(--ui-border-faint);
63
+ min-height: 52px;
64
+ }
65
+
66
+ .bar-left {
67
+ display: flex;
68
+ align-items: center;
69
+ gap: var(--ui-space-16);
70
+ min-width: 0;
71
+ }
72
+
73
+ .back-link {
74
+ display: flex;
75
+ align-items: center;
76
+ gap: var(--ui-space-6);
77
+ color: var(--ui-text-tertiary);
78
+ text-decoration: none;
79
+ font-size: var(--ui-font-size-md);
80
+ transition: color var(--ui-transition-fast);
81
+ }
82
+
83
+ .back-link:hover {
84
+ color: var(--ui-text-primary);
85
+ }
86
+
87
+ .editor-label {
88
+ font-size: var(--ui-font-size-md);
89
+ font-weight: var(--ui-font-weight-semibold);
90
+ color: var(--ui-text-secondary);
91
+ }
92
+
93
+ @media (max-width: 1100px) {
94
+ .editor-label {
95
+ display: none;
96
+ }
97
+ }
98
+ </style>
@@ -0,0 +1,2 @@
1
+ import { SvelteComponent } from 'svelte';
2
+ export default class Editor extends SvelteComponent<Record<string, never>> {}