@leavepulse/ui 0.12.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.
Files changed (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -0
  3. package/dist/component-names.d.ts +1 -0
  4. package/dist/components/LayoutCanvas.vue.d.ts +28 -0
  5. package/dist/components/LayoutNode.vue.d.ts +40 -0
  6. package/dist/components/LpAlert.vue.d.ts +44 -0
  7. package/dist/components/LpAppShell.vue.d.ts +83 -0
  8. package/dist/components/LpAutocomplete.vue.d.ts +50 -0
  9. package/dist/components/LpAvatar.vue.d.ts +20 -0
  10. package/dist/components/LpBadge.vue.d.ts +47 -0
  11. package/dist/components/LpBreadcrumbs.vue.d.ts +14 -0
  12. package/dist/components/LpButton.vue.d.ts +113 -0
  13. package/dist/components/LpCalendar.vue.d.ts +20 -0
  14. package/dist/components/LpCard.vue.d.ts +29 -0
  15. package/dist/components/LpCheckbox.vue.d.ts +28 -0
  16. package/dist/components/LpCodeBlock.vue.d.ts +39 -0
  17. package/dist/components/LpCommandPalette.vue.d.ts +42 -0
  18. package/dist/components/LpConfirmDialog.vue.d.ts +32 -0
  19. package/dist/components/LpContextMenu.vue.d.ts +30 -0
  20. package/dist/components/LpDatePicker.vue.d.ts +25 -0
  21. package/dist/components/LpDisclosure.vue.d.ts +37 -0
  22. package/dist/components/LpDivider.vue.d.ts +17 -0
  23. package/dist/components/LpDrawer.vue.d.ts +88 -0
  24. package/dist/components/LpDropdownMenu.vue.d.ts +23 -0
  25. package/dist/components/LpEmptyState.vue.d.ts +18 -0
  26. package/dist/components/LpFormField.vue.d.ts +21 -0
  27. package/dist/components/LpIcon.vue.d.ts +8 -0
  28. package/dist/components/LpInfraNode.vue.d.ts +21 -0
  29. package/dist/components/LpInput.vue.d.ts +68 -0
  30. package/dist/components/LpLaneNode.vue.d.ts +24 -0
  31. package/dist/components/LpLink.vue.d.ts +27 -0
  32. package/dist/components/LpLogViewer.vue.d.ts +92 -0
  33. package/dist/components/LpModal.vue.d.ts +43 -0
  34. package/dist/components/LpNotificationBell.vue.d.ts +51 -0
  35. package/dist/components/LpNumberField.vue.d.ts +14 -0
  36. package/dist/components/LpOtpInput.vue.d.ts +27 -0
  37. package/dist/components/LpPagination.vue.d.ts +25 -0
  38. package/dist/components/LpPasswordInput.vue.d.ts +28 -0
  39. package/dist/components/LpPhoneInput.vue.d.ts +37 -0
  40. package/dist/components/LpPopover.vue.d.ts +34 -0
  41. package/dist/components/LpProgress.vue.d.ts +12 -0
  42. package/dist/components/LpRadio.vue.d.ts +18 -0
  43. package/dist/components/LpRadioGroup.vue.d.ts +26 -0
  44. package/dist/components/LpScrollArea.vue.d.ts +24 -0
  45. package/dist/components/LpSegmented.vue.d.ts +24 -0
  46. package/dist/components/LpSelect.vue.d.ts +45 -0
  47. package/dist/components/LpServiceNode.vue.d.ts +14 -0
  48. package/dist/components/LpSidebar.vue.d.ts +85 -0
  49. package/dist/components/LpSidebarNav.vue.d.ts +34 -0
  50. package/dist/components/LpSkeleton.vue.d.ts +6 -0
  51. package/dist/components/LpSlider.vue.d.ts +23 -0
  52. package/dist/components/LpStat.vue.d.ts +22 -0
  53. package/dist/components/LpStepper.vue.d.ts +10 -0
  54. package/dist/components/LpSwitch.vue.d.ts +11 -0
  55. package/dist/components/LpTable.vue.d.ts +63 -0
  56. package/dist/components/LpTableOfContents.vue.d.ts +19 -0
  57. package/dist/components/LpTabs.vue.d.ts +45 -0
  58. package/dist/components/LpTextarea.vue.d.ts +17 -0
  59. package/dist/components/LpThemeSwitcher.vue.d.ts +40 -0
  60. package/dist/components/LpToaster.vue.d.ts +3 -0
  61. package/dist/components/LpTooltip.vue.d.ts +19 -0
  62. package/dist/components/LpTopologyCanvas.vue.d.ts +154 -0
  63. package/dist/components/LpUptimeBar.vue.d.ts +30 -0
  64. package/dist/components/codeHighlight.d.ts +8 -0
  65. package/dist/components/countries-data.d.ts +2 -0
  66. package/dist/components/countries.d.ts +20 -0
  67. package/dist/components/dropdown.d.ts +29 -0
  68. package/dist/components/sidebar.d.ts +18 -0
  69. package/dist/composables/useInputFilter.d.ts +14 -0
  70. package/dist/composables/usePillTransition.d.ts +9 -0
  71. package/dist/composables/useToast.d.ts +39 -0
  72. package/dist/countries-data-9rgqJWHo.js +203 -0
  73. package/dist/icons.d.ts +1 -0
  74. package/dist/index.css +1 -0
  75. package/dist/index.d.ts +100 -0
  76. package/dist/index.js +17600 -0
  77. package/dist/layout/registry.d.ts +26 -0
  78. package/dist/layout/tree.d.ts +75 -0
  79. package/dist/layout/useLayout.d.ts +39 -0
  80. package/dist/theme/config.d.ts +16 -0
  81. package/dist/theme/define.d.ts +12 -0
  82. package/dist/theme/presets.d.ts +20 -0
  83. package/dist/theme/tokens.d.ts +72 -0
  84. package/dist/theme/useTheme.d.ts +36 -0
  85. package/package.json +93 -0
  86. package/src/canvas.css +67 -0
  87. package/src/component-names.ts +65 -0
  88. package/src/components/LayoutCanvas.vue +76 -0
  89. package/src/components/LayoutNode.vue +248 -0
  90. package/src/components/LpAlert.vue +59 -0
  91. package/src/components/LpAppShell.vue +210 -0
  92. package/src/components/LpAutocomplete.vue +244 -0
  93. package/src/components/LpAvatar.vue +67 -0
  94. package/src/components/LpBadge.vue +32 -0
  95. package/src/components/LpBreadcrumbs.vue +35 -0
  96. package/src/components/LpButton.vue +111 -0
  97. package/src/components/LpCalendar.vue +134 -0
  98. package/src/components/LpCard.vue +71 -0
  99. package/src/components/LpCheckbox.vue +44 -0
  100. package/src/components/LpCodeBlock.vue +298 -0
  101. package/src/components/LpCommandPalette.vue +323 -0
  102. package/src/components/LpConfirmDialog.vue +49 -0
  103. package/src/components/LpContextMenu.vue +111 -0
  104. package/src/components/LpDatePicker.vue +117 -0
  105. package/src/components/LpDisclosure.vue +92 -0
  106. package/src/components/LpDivider.vue +20 -0
  107. package/src/components/LpDrawer.vue +402 -0
  108. package/src/components/LpDropdownMenu.vue +54 -0
  109. package/src/components/LpEmptyState.vue +21 -0
  110. package/src/components/LpFormField.vue +31 -0
  111. package/src/components/LpIcon.vue +49 -0
  112. package/src/components/LpInfraNode.vue +108 -0
  113. package/src/components/LpInput.vue +147 -0
  114. package/src/components/LpLaneNode.vue +48 -0
  115. package/src/components/LpLink.vue +48 -0
  116. package/src/components/LpLogViewer.vue +569 -0
  117. package/src/components/LpModal.vue +123 -0
  118. package/src/components/LpNotificationBell.vue +238 -0
  119. package/src/components/LpNumberField.vue +56 -0
  120. package/src/components/LpOtpInput.vue +81 -0
  121. package/src/components/LpPagination.vue +165 -0
  122. package/src/components/LpPasswordInput.vue +50 -0
  123. package/src/components/LpPhoneInput.vue +241 -0
  124. package/src/components/LpPopover.vue +42 -0
  125. package/src/components/LpProgress.vue +30 -0
  126. package/src/components/LpRadio.vue +28 -0
  127. package/src/components/LpRadioGroup.vue +43 -0
  128. package/src/components/LpScrollArea.vue +82 -0
  129. package/src/components/LpSegmented.vue +83 -0
  130. package/src/components/LpSelect.vue +0 -0
  131. package/src/components/LpServiceNode.vue +57 -0
  132. package/src/components/LpSidebar.vue +200 -0
  133. package/src/components/LpSidebarNav.vue +118 -0
  134. package/src/components/LpSkeleton.vue +16 -0
  135. package/src/components/LpSlider.vue +53 -0
  136. package/src/components/LpStat.vue +90 -0
  137. package/src/components/LpStepper.vue +46 -0
  138. package/src/components/LpSwitch.vue +19 -0
  139. package/src/components/LpTable.vue +252 -0
  140. package/src/components/LpTableOfContents.vue +183 -0
  141. package/src/components/LpTabs.vue +120 -0
  142. package/src/components/LpTextarea.vue +39 -0
  143. package/src/components/LpThemeSwitcher.vue +168 -0
  144. package/src/components/LpToaster.vue +216 -0
  145. package/src/components/LpTooltip.vue +30 -0
  146. package/src/components/LpTopologyCanvas.vue +370 -0
  147. package/src/components/LpUptimeBar.vue +126 -0
  148. package/src/components/codeHighlight.ts +137 -0
  149. package/src/components/countries-data.ts +207 -0
  150. package/src/components/countries.ts +67 -0
  151. package/src/components/dropdown.ts +64 -0
  152. package/src/components/sidebar.ts +26 -0
  153. package/src/composables/useInputFilter.ts +89 -0
  154. package/src/composables/usePillTransition.ts +19 -0
  155. package/src/composables/useToast.ts +92 -0
  156. package/src/icons.ts +11 -0
  157. package/src/index.css +21 -0
  158. package/src/index.ts +146 -0
  159. package/src/layout/registry.ts +44 -0
  160. package/src/layout/tree.ts +288 -0
  161. package/src/layout/useLayout.ts +134 -0
  162. package/src/nuxt.ts +22 -0
  163. package/src/theme/config.ts +48 -0
  164. package/src/theme/define.ts +50 -0
  165. package/src/theme/presets.ts +279 -0
  166. package/src/theme/tokens.ts +151 -0
  167. package/src/theme/useTheme.ts +288 -0
  168. package/src/tokens/scrollbar.css +138 -0
  169. package/src/tokens/tokens.css +333 -0
  170. package/src/tokens/utilities.css +23 -0
@@ -0,0 +1,50 @@
1
+ import { presets } from "./presets"
2
+ import type { ColorTokens, DensityTokens, FontTokens, ShapeTokens, SurfaceTokens, TokenSet } from "./tokens"
3
+
4
+ /*
5
+ * defineTheme — the public API for building app themes WITHOUT editing the kit.
6
+ *
7
+ * Consuming apps (a docs site, a console) own their themes; the kit only ships a
8
+ * handful of neutral presets. Rather than copy a whole TokenSet to tweak two
9
+ * colours, an app derives from a base and overrides just what differs:
10
+ *
11
+ * import { defineTheme, violet } from "@leavepulse/ui"
12
+ *
13
+ * export const brandDark = defineTheme(violet, {
14
+ * name: "Brand Dark",
15
+ * colors: { brand: "#7c3aed", brandHover: "#6d28d9" },
16
+ * })
17
+ *
18
+ * `base` is a TokenSet or the NAME of a built-in preset. Each axis
19
+ * (colors/shape/density/font/surface) is shallow-merged over the base, so
20
+ * partial overrides are enough. Pass the results straight to
21
+ * <LpThemeSwitcher :themes="[...]"> — no kit change required.
22
+ */
23
+
24
+ export interface ThemeOverrides {
25
+ name?: string
26
+ mode?: "dark" | "light"
27
+ colors?: Partial<ColorTokens>
28
+ shape?: Partial<ShapeTokens>
29
+ density?: Partial<DensityTokens>
30
+ font?: Partial<FontTokens>
31
+ surface?: Partial<SurfaceTokens>
32
+ }
33
+
34
+ export function defineTheme(
35
+ base: TokenSet | keyof typeof presets,
36
+ overrides: ThemeOverrides = {},
37
+ ): TokenSet {
38
+ const src: TokenSet = typeof base === "string" ? presets[base] : base
39
+ return {
40
+ name: overrides.name ?? src.name,
41
+ mode: overrides.mode ?? src.mode,
42
+ colors: { ...src.colors, ...overrides.colors },
43
+ shape: { ...src.shape, ...overrides.shape },
44
+ density: { ...src.density, ...overrides.density },
45
+ font: { ...src.font, ...overrides.font },
46
+ surface: src.surface || overrides.surface
47
+ ? { ...src.surface, ...overrides.surface } as SurfaceTokens
48
+ : undefined,
49
+ }
50
+ }
@@ -0,0 +1,279 @@
1
+ import type { SurfaceTokens, TokenSet } from "./tokens"
2
+
3
+ /*
4
+ * Built-in theme presets — plain TokenSet objects (JSON). These ARE the themes;
5
+ * there are no [data-theme] CSS rules. Apps ship these, let users tweak them,
6
+ * and persist the result as JSON.
7
+ */
8
+
9
+ const sharedShape = { radiusControl: 8, radiusCard: 14, radiusPill: 9999 }
10
+ const sharedDensity = { spacingUnit: 4, controlSm: 32, controlMd: 38, controlLg: 44 }
11
+ const interFont = {
12
+ sans: '"Inter", "Segoe UI", system-ui, sans-serif',
13
+ mono: '"JetBrains Mono", "SF Mono", ui-monospace, monospace',
14
+ }
15
+
16
+ export const dark: TokenSet = {
17
+ name: "Dark",
18
+ mode: "dark",
19
+ colors: {
20
+ surface: "#080b0d",
21
+ surfaceRaised: "#12171d",
22
+ surfaceSoft: "#172027",
23
+ ink: "#eef5f1",
24
+ inkInverse: "#06100b",
25
+ muted: "#9aa8a2",
26
+ mutedStrong: "#c7d2cc",
27
+ brand: "#00bcff",
28
+ brandHover: "#19c6ff",
29
+ brandSoft: "rgba(0, 188, 255, 0.16)",
30
+ action: "#39e58c",
31
+ actionHover: "#4dffa1",
32
+ accent: "#f0b35a",
33
+ danger: "#ff6f6f",
34
+ dangerHover: "#ff8585",
35
+ dangerSoft: "rgba(255, 111, 111, 0.14)",
36
+ line: "rgba(255, 255, 255, 0.1)",
37
+ lineStrong: "rgba(255, 255, 255, 0.18)",
38
+ ring: "rgba(0, 188, 255, 0.45)",
39
+ },
40
+ shape: { ...sharedShape },
41
+ density: { ...sharedDensity },
42
+ font: { ...interFont },
43
+ }
44
+
45
+ export const light: TokenSet = {
46
+ name: "Light",
47
+ mode: "light",
48
+ colors: {
49
+ surface: "#f6f8f7",
50
+ surfaceRaised: "#ffffff",
51
+ surfaceSoft: "#eceff0",
52
+ ink: "#0d1714",
53
+ inkInverse: "#f8fff9",
54
+ muted: "#5d6b65",
55
+ mutedStrong: "#34433d",
56
+ brand: "#0086c7",
57
+ brandHover: "#0095db",
58
+ brandSoft: "rgba(0, 134, 199, 0.12)",
59
+ action: "#1f9d5f",
60
+ actionHover: "#23b06b",
61
+ accent: "#aa6f1d",
62
+ danger: "#c2333b",
63
+ dangerHover: "#d23b44",
64
+ dangerSoft: "rgba(194, 51, 59, 0.12)",
65
+ line: "rgba(13, 23, 20, 0.12)",
66
+ lineStrong: "rgba(13, 23, 20, 0.22)",
67
+ ring: "rgba(0, 134, 199, 0.4)",
68
+ },
69
+ shape: { ...sharedShape },
70
+ density: { ...sharedDensity },
71
+ font: { ...interFont },
72
+ }
73
+
74
+ export const lime: TokenSet = {
75
+ name: "Lime",
76
+ mode: "dark",
77
+ colors: {
78
+ surface: "#050505",
79
+ surfaceRaised: "#0c0d0a",
80
+ surfaceSoft: "#14160f",
81
+ ink: "#f4f7ee",
82
+ inkInverse: "#0a0c05",
83
+ muted: "#8b8f80",
84
+ mutedStrong: "#c3c8b6",
85
+ brand: "#c4f042",
86
+ brandHover: "#d2ff5c",
87
+ brandSoft: "rgba(196, 240, 66, 0.14)",
88
+ action: "#5fd97a",
89
+ actionHover: "#74e88d",
90
+ accent: "#ffb84d",
91
+ danger: "#ff6f6f",
92
+ dangerHover: "#ff8585",
93
+ dangerSoft: "rgba(255, 111, 111, 0.14)",
94
+ line: "rgba(255, 255, 255, 0.08)",
95
+ lineStrong: "rgba(196, 240, 66, 0.3)",
96
+ ring: "rgba(196, 240, 66, 0.4)",
97
+ },
98
+ // a sharper theme — overrides the shape axis too
99
+ shape: { radiusControl: 4, radiusCard: 6, radiusPill: 4 },
100
+ density: { ...sharedDensity },
101
+ // a distinct typeface so the theme has its own voice (not just colour)
102
+ font: {
103
+ sans: '"Space Grotesk", "Inter", system-ui, sans-serif',
104
+ mono: '"IBM Plex Mono", "JetBrains Mono", ui-monospace, monospace',
105
+ },
106
+ }
107
+
108
+ /*
109
+ * Glass skin — frosted panels with backdrop blur, a faint top-down highlight
110
+ * overlay, a layered drop shadow and an inset highlight line. Opt a theme into
111
+ * it by setting its `surface` axis to this (the LeavePulse site uses it).
112
+ */
113
+ const glassSurface: SurfaceTokens = {
114
+ borderWidth: "1px",
115
+ panelBlur: "10px",
116
+ panelSaturate: "120%",
117
+ panelOverlay:
118
+ "linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.01))",
119
+ panelShadow: "0 20px 60px rgba(0, 0, 0, 0.35)",
120
+ panelInset: "inset 0 1px 0 rgba(255, 255, 255, 0.08)",
121
+ }
122
+
123
+ /*
124
+ * LeavePulse site theme — the colours the website shipped before the kit
125
+ * migration (deep navy surfaces, cyan brand, teal accent), with the glass skin.
126
+ * Distinct from `dark` (which is a near-black neutral) so the site keeps its
127
+ * look when it switches its CSS-var dictionary over to the kit.
128
+ */
129
+ export const leavepulse: TokenSet = {
130
+ name: "LeavePulse",
131
+ mode: "dark",
132
+ colors: {
133
+ surface: "#020618",
134
+ surfaceRaised: "#0b1222",
135
+ surfaceSoft: "rgba(11, 18, 34, 0.7)",
136
+ ink: "#f3f6ff",
137
+ inkInverse: "#0b1222",
138
+ muted: "#94a3bf",
139
+ mutedStrong: "#cad5e2",
140
+ brand: "#00bcff",
141
+ brandHover: "#19c3ff",
142
+ brandSoft: "rgba(0, 188, 255, 0.2)",
143
+ action: "#44c2ad",
144
+ actionHover: "#56d3be",
145
+ accent: "#d36a2c",
146
+ danger: "#f87171",
147
+ dangerHover: "#fca5a5",
148
+ dangerSoft: "rgba(248, 113, 113, 0.14)",
149
+ line: "#1c2740",
150
+ lineStrong: "rgba(255, 255, 255, 0.15)",
151
+ ring: "rgba(0, 188, 255, 0.35)",
152
+ },
153
+ shape: { ...sharedShape, radiusControl: 12 },
154
+ density: { ...sharedDensity },
155
+ font: {
156
+ sans: '"Inter", "IBM Plex Sans", "Segoe UI", sans-serif',
157
+ mono: '"JetBrains Mono", "SF Mono", ui-monospace, monospace',
158
+ },
159
+ surface: glassSurface,
160
+ }
161
+
162
+ export const rose: TokenSet = {
163
+ name: "Rose",
164
+ mode: "dark",
165
+ colors: {
166
+ surface: "#120a0d",
167
+ surfaceRaised: "#1c1014",
168
+ surfaceSoft: "#26161b",
169
+ ink: "#fdeef1",
170
+ inkInverse: "#1a0d11",
171
+ muted: "#a98a92",
172
+ mutedStrong: "#d8c0c6",
173
+ brand: "#fb7185",
174
+ brandHover: "#fd8a9b",
175
+ brandSoft: "rgba(251, 113, 133, 0.14)",
176
+ action: "#34d399",
177
+ actionHover: "#4adeaa",
178
+ accent: "#fbbf24",
179
+ danger: "#ef4444",
180
+ dangerHover: "#f56565",
181
+ dangerSoft: "rgba(239, 68, 68, 0.14)",
182
+ line: "rgba(255, 255, 255, 0.1)",
183
+ lineStrong: "rgba(251, 113, 133, 0.3)",
184
+ ring: "rgba(251, 113, 133, 0.4)",
185
+ },
186
+ shape: { ...sharedShape },
187
+ density: { ...sharedDensity },
188
+ font: { ...interFont },
189
+ }
190
+
191
+ export const amber: TokenSet = {
192
+ name: "Amber",
193
+ mode: "dark",
194
+ colors: {
195
+ surface: "#0f0b06",
196
+ surfaceRaised: "#1a130a",
197
+ surfaceSoft: "#241a0e",
198
+ ink: "#fdf3e6",
199
+ inkInverse: "#1a1206",
200
+ muted: "#a3927a",
201
+ mutedStrong: "#d6c6ad",
202
+ brand: "#f59e0b",
203
+ brandHover: "#fbb024",
204
+ brandSoft: "rgba(245, 158, 11, 0.14)",
205
+ action: "#4ade80",
206
+ actionHover: "#5cea90",
207
+ accent: "#38bdf8",
208
+ danger: "#f87171",
209
+ dangerHover: "#fa8a8a",
210
+ dangerSoft: "rgba(248, 113, 113, 0.14)",
211
+ line: "rgba(255, 255, 255, 0.1)",
212
+ lineStrong: "rgba(245, 158, 11, 0.3)",
213
+ ring: "rgba(245, 158, 11, 0.4)",
214
+ },
215
+ shape: { ...sharedShape },
216
+ density: { ...sharedDensity },
217
+ font: { ...interFont },
218
+ }
219
+
220
+ export const violet: TokenSet = {
221
+ name: "Violet",
222
+ mode: "dark",
223
+ colors: {
224
+ surface: "#0c0a14",
225
+ surfaceRaised: "#15111f",
226
+ surfaceSoft: "#1d1729",
227
+ ink: "#f1eefb",
228
+ inkInverse: "#100b1a",
229
+ muted: "#948aa9",
230
+ mutedStrong: "#c6bedb",
231
+ brand: "#a78bfa",
232
+ brandHover: "#b69dfc",
233
+ brandSoft: "rgba(167, 139, 250, 0.14)",
234
+ action: "#34d399",
235
+ actionHover: "#4adeaa",
236
+ accent: "#fbbf24",
237
+ danger: "#f87171",
238
+ dangerHover: "#fa8a8a",
239
+ dangerSoft: "rgba(248, 113, 113, 0.14)",
240
+ line: "rgba(255, 255, 255, 0.1)",
241
+ lineStrong: "rgba(167, 139, 250, 0.3)",
242
+ ring: "rgba(167, 139, 250, 0.4)",
243
+ },
244
+ shape: { ...sharedShape },
245
+ density: { ...sharedDensity },
246
+ font: { ...interFont },
247
+ }
248
+
249
+ export const nord: TokenSet = {
250
+ name: "Nord",
251
+ mode: "dark",
252
+ colors: {
253
+ surface: "#2e3440",
254
+ surfaceRaised: "#3b4252",
255
+ surfaceSoft: "#434c5e",
256
+ ink: "#eceff4",
257
+ inkInverse: "#2e3440",
258
+ muted: "#9aa4b8",
259
+ mutedStrong: "#d8dee9",
260
+ brand: "#88c0d0",
261
+ brandHover: "#9bccd9",
262
+ brandSoft: "rgba(136, 192, 208, 0.16)",
263
+ action: "#a3be8c",
264
+ actionHover: "#b3cb9f",
265
+ accent: "#ebcb8b",
266
+ danger: "#bf616a",
267
+ dangerHover: "#cb727b",
268
+ dangerSoft: "rgba(191, 97, 106, 0.16)",
269
+ line: "rgba(236, 239, 244, 0.1)",
270
+ lineStrong: "rgba(136, 192, 208, 0.35)",
271
+ ring: "rgba(136, 192, 208, 0.45)",
272
+ },
273
+ shape: { ...sharedShape },
274
+ density: { ...sharedDensity },
275
+ font: { ...interFont },
276
+ }
277
+
278
+ export const presets = { dark, light, lime, leavepulse, rose, amber, violet, nord } as const
279
+ export type PresetName = keyof typeof presets
@@ -0,0 +1,151 @@
1
+ /*
2
+ * TokenSet — the serializable shape of a theme. A theme is just this object;
3
+ * persist it as JSON (disk / config / server) and apply it at runtime with
4
+ * useTheme().applyTheme(). camelCase keys map 1:1 to the CSS variables the kit
5
+ * components read (see VAR_MAP).
6
+ */
7
+
8
+ export interface ColorTokens {
9
+ surface: string
10
+ surfaceRaised: string
11
+ surfaceSoft: string
12
+ ink: string
13
+ inkInverse: string
14
+ muted: string
15
+ mutedStrong: string
16
+ brand: string
17
+ brandHover: string
18
+ brandSoft: string
19
+ action: string
20
+ actionHover: string
21
+ accent: string
22
+ danger: string
23
+ dangerHover: string
24
+ dangerSoft: string
25
+ line: string
26
+ lineStrong: string
27
+ ring: string
28
+ }
29
+
30
+ export interface ShapeTokens {
31
+ radiusControl: number
32
+ radiusCard: number
33
+ radiusPill: number
34
+ }
35
+
36
+ export interface DensityTokens {
37
+ /** base spacing unit in px */
38
+ spacingUnit: number
39
+ controlSm: number
40
+ controlMd: number
41
+ controlLg: number
42
+ }
43
+
44
+ export interface FontTokens {
45
+ /** CSS font-family stack for UI text */
46
+ sans: string
47
+ /** CSS font-family stack for numerals / code */
48
+ mono: string
49
+ }
50
+
51
+ /*
52
+ * Surface tokens — the "skin" axis. These describe how a raised panel/card is
53
+ * painted, as plain CSS values so a flat look and a full glass look are the
54
+ * same shape (just different values). Components reference the vars below
55
+ * instead of hard-coding gradients/blur/shadows, so a skin is data, not CSS.
56
+ *
57
+ * flat default: overlay none, blur 0, shadow soft, inset none
58
+ * glass: overlay gradient, blur 36px, layered shadow, inset highlight
59
+ */
60
+ export interface SurfaceTokens {
61
+ /** Border width for panels/cards/controls (CSS length, e.g. "1px"). */
62
+ borderWidth: string
63
+ /** backdrop-filter blur radius (CSS length; "0" disables glass blur). */
64
+ panelBlur: string
65
+ /** backdrop-filter saturate (unitless or %, e.g. "100%" / "180%"). */
66
+ panelSaturate: string
67
+ /** Overlay painted over a panel's base color ("none" or a gradient). */
68
+ panelOverlay: string
69
+ /** Box-shadow for a raised panel (may be multi-layer for glass). */
70
+ panelShadow: string
71
+ /** Inset highlight line for a panel ("none" or an inset box-shadow). */
72
+ panelInset: string
73
+ }
74
+
75
+ export interface TokenSet {
76
+ /** human label, e.g. "Lime" */
77
+ name: string
78
+ /** "dark" | "light" — drives `color-scheme` and the data-theme-mode hint */
79
+ mode: "dark" | "light"
80
+ colors: ColorTokens
81
+ shape: ShapeTokens
82
+ density: DensityTokens
83
+ font: FontTokens
84
+ /** Optional skin axis; older themes without it fall back to a flat default. */
85
+ surface?: SurfaceTokens
86
+ }
87
+
88
+ /** camelCase token key → CSS custom property name. */
89
+ export const COLOR_VARS: Record<keyof ColorTokens, string> = {
90
+ surface: "--color-surface",
91
+ surfaceRaised: "--color-surface-raised",
92
+ surfaceSoft: "--color-surface-soft",
93
+ ink: "--color-ink",
94
+ inkInverse: "--color-ink-inverse",
95
+ muted: "--color-muted",
96
+ mutedStrong: "--color-muted-strong",
97
+ brand: "--color-brand",
98
+ brandHover: "--color-brand-hover",
99
+ brandSoft: "--color-brand-soft",
100
+ action: "--color-action",
101
+ actionHover: "--color-action-hover",
102
+ accent: "--color-accent",
103
+ danger: "--color-danger",
104
+ dangerHover: "--color-danger-hover",
105
+ dangerSoft: "--color-danger-soft",
106
+ line: "--color-line",
107
+ lineStrong: "--color-line-strong",
108
+ ring: "--color-ring",
109
+ }
110
+
111
+ export const SHAPE_VARS: Record<keyof ShapeTokens, string> = {
112
+ radiusControl: "--radius-control",
113
+ radiusCard: "--radius-card",
114
+ radiusPill: "--radius-pill",
115
+ }
116
+
117
+ export const DENSITY_VARS: Record<keyof DensityTokens, string> = {
118
+ spacingUnit: "--spacing-unit",
119
+ controlSm: "--size-control-sm",
120
+ controlMd: "--size-control-md",
121
+ controlLg: "--size-control-lg",
122
+ }
123
+
124
+ export const FONT_VARS: Record<keyof FontTokens, string> = {
125
+ sans: "--font-sans",
126
+ mono: "--font-mono",
127
+ }
128
+
129
+ export const SURFACE_VARS: Record<keyof SurfaceTokens, string> = {
130
+ borderWidth: "--surface-border-width",
131
+ panelBlur: "--surface-panel-blur",
132
+ panelSaturate: "--surface-panel-saturate",
133
+ panelOverlay: "--surface-panel-overlay",
134
+ panelShadow: "--surface-panel-shadow",
135
+ panelInset: "--surface-panel-inset",
136
+ }
137
+
138
+ /*
139
+ * Flat default skin for themes that don't ship a `surface` axis.
140
+ * panelInset is a no-op shadow (not "none") because it's composited in a
141
+ * box-shadow list — `box-shadow: none, <x>` is invalid, so the empty value
142
+ * must be a transparent layer.
143
+ */
144
+ export const DEFAULT_SURFACE: SurfaceTokens = {
145
+ borderWidth: "1px",
146
+ panelBlur: "0px",
147
+ panelSaturate: "100%",
148
+ panelOverlay: "none",
149
+ panelShadow: "0 1px 2px rgba(0, 0, 0, 0.18)",
150
+ panelInset: "0 0 0 0 transparent",
151
+ }