@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.
- package/LICENSE +21 -0
- package/README.md +61 -0
- package/dist/component-names.d.ts +1 -0
- package/dist/components/LayoutCanvas.vue.d.ts +28 -0
- package/dist/components/LayoutNode.vue.d.ts +40 -0
- package/dist/components/LpAlert.vue.d.ts +44 -0
- package/dist/components/LpAppShell.vue.d.ts +83 -0
- package/dist/components/LpAutocomplete.vue.d.ts +50 -0
- package/dist/components/LpAvatar.vue.d.ts +20 -0
- package/dist/components/LpBadge.vue.d.ts +47 -0
- package/dist/components/LpBreadcrumbs.vue.d.ts +14 -0
- package/dist/components/LpButton.vue.d.ts +113 -0
- package/dist/components/LpCalendar.vue.d.ts +20 -0
- package/dist/components/LpCard.vue.d.ts +29 -0
- package/dist/components/LpCheckbox.vue.d.ts +28 -0
- package/dist/components/LpCodeBlock.vue.d.ts +39 -0
- package/dist/components/LpCommandPalette.vue.d.ts +42 -0
- package/dist/components/LpConfirmDialog.vue.d.ts +32 -0
- package/dist/components/LpContextMenu.vue.d.ts +30 -0
- package/dist/components/LpDatePicker.vue.d.ts +25 -0
- package/dist/components/LpDisclosure.vue.d.ts +37 -0
- package/dist/components/LpDivider.vue.d.ts +17 -0
- package/dist/components/LpDrawer.vue.d.ts +88 -0
- package/dist/components/LpDropdownMenu.vue.d.ts +23 -0
- package/dist/components/LpEmptyState.vue.d.ts +18 -0
- package/dist/components/LpFormField.vue.d.ts +21 -0
- package/dist/components/LpIcon.vue.d.ts +8 -0
- package/dist/components/LpInfraNode.vue.d.ts +21 -0
- package/dist/components/LpInput.vue.d.ts +68 -0
- package/dist/components/LpLaneNode.vue.d.ts +24 -0
- package/dist/components/LpLink.vue.d.ts +27 -0
- package/dist/components/LpLogViewer.vue.d.ts +92 -0
- package/dist/components/LpModal.vue.d.ts +43 -0
- package/dist/components/LpNotificationBell.vue.d.ts +51 -0
- package/dist/components/LpNumberField.vue.d.ts +14 -0
- package/dist/components/LpOtpInput.vue.d.ts +27 -0
- package/dist/components/LpPagination.vue.d.ts +25 -0
- package/dist/components/LpPasswordInput.vue.d.ts +28 -0
- package/dist/components/LpPhoneInput.vue.d.ts +37 -0
- package/dist/components/LpPopover.vue.d.ts +34 -0
- package/dist/components/LpProgress.vue.d.ts +12 -0
- package/dist/components/LpRadio.vue.d.ts +18 -0
- package/dist/components/LpRadioGroup.vue.d.ts +26 -0
- package/dist/components/LpScrollArea.vue.d.ts +24 -0
- package/dist/components/LpSegmented.vue.d.ts +24 -0
- package/dist/components/LpSelect.vue.d.ts +45 -0
- package/dist/components/LpServiceNode.vue.d.ts +14 -0
- package/dist/components/LpSidebar.vue.d.ts +85 -0
- package/dist/components/LpSidebarNav.vue.d.ts +34 -0
- package/dist/components/LpSkeleton.vue.d.ts +6 -0
- package/dist/components/LpSlider.vue.d.ts +23 -0
- package/dist/components/LpStat.vue.d.ts +22 -0
- package/dist/components/LpStepper.vue.d.ts +10 -0
- package/dist/components/LpSwitch.vue.d.ts +11 -0
- package/dist/components/LpTable.vue.d.ts +63 -0
- package/dist/components/LpTableOfContents.vue.d.ts +19 -0
- package/dist/components/LpTabs.vue.d.ts +45 -0
- package/dist/components/LpTextarea.vue.d.ts +17 -0
- package/dist/components/LpThemeSwitcher.vue.d.ts +40 -0
- package/dist/components/LpToaster.vue.d.ts +3 -0
- package/dist/components/LpTooltip.vue.d.ts +19 -0
- package/dist/components/LpTopologyCanvas.vue.d.ts +154 -0
- package/dist/components/LpUptimeBar.vue.d.ts +30 -0
- package/dist/components/codeHighlight.d.ts +8 -0
- package/dist/components/countries-data.d.ts +2 -0
- package/dist/components/countries.d.ts +20 -0
- package/dist/components/dropdown.d.ts +29 -0
- package/dist/components/sidebar.d.ts +18 -0
- package/dist/composables/useInputFilter.d.ts +14 -0
- package/dist/composables/usePillTransition.d.ts +9 -0
- package/dist/composables/useToast.d.ts +39 -0
- package/dist/countries-data-9rgqJWHo.js +203 -0
- package/dist/icons.d.ts +1 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.js +17600 -0
- package/dist/layout/registry.d.ts +26 -0
- package/dist/layout/tree.d.ts +75 -0
- package/dist/layout/useLayout.d.ts +39 -0
- package/dist/theme/config.d.ts +16 -0
- package/dist/theme/define.d.ts +12 -0
- package/dist/theme/presets.d.ts +20 -0
- package/dist/theme/tokens.d.ts +72 -0
- package/dist/theme/useTheme.d.ts +36 -0
- package/package.json +93 -0
- package/src/canvas.css +67 -0
- package/src/component-names.ts +65 -0
- package/src/components/LayoutCanvas.vue +76 -0
- package/src/components/LayoutNode.vue +248 -0
- package/src/components/LpAlert.vue +59 -0
- package/src/components/LpAppShell.vue +210 -0
- package/src/components/LpAutocomplete.vue +244 -0
- package/src/components/LpAvatar.vue +67 -0
- package/src/components/LpBadge.vue +32 -0
- package/src/components/LpBreadcrumbs.vue +35 -0
- package/src/components/LpButton.vue +111 -0
- package/src/components/LpCalendar.vue +134 -0
- package/src/components/LpCard.vue +71 -0
- package/src/components/LpCheckbox.vue +44 -0
- package/src/components/LpCodeBlock.vue +298 -0
- package/src/components/LpCommandPalette.vue +323 -0
- package/src/components/LpConfirmDialog.vue +49 -0
- package/src/components/LpContextMenu.vue +111 -0
- package/src/components/LpDatePicker.vue +117 -0
- package/src/components/LpDisclosure.vue +92 -0
- package/src/components/LpDivider.vue +20 -0
- package/src/components/LpDrawer.vue +402 -0
- package/src/components/LpDropdownMenu.vue +54 -0
- package/src/components/LpEmptyState.vue +21 -0
- package/src/components/LpFormField.vue +31 -0
- package/src/components/LpIcon.vue +49 -0
- package/src/components/LpInfraNode.vue +108 -0
- package/src/components/LpInput.vue +147 -0
- package/src/components/LpLaneNode.vue +48 -0
- package/src/components/LpLink.vue +48 -0
- package/src/components/LpLogViewer.vue +569 -0
- package/src/components/LpModal.vue +123 -0
- package/src/components/LpNotificationBell.vue +238 -0
- package/src/components/LpNumberField.vue +56 -0
- package/src/components/LpOtpInput.vue +81 -0
- package/src/components/LpPagination.vue +165 -0
- package/src/components/LpPasswordInput.vue +50 -0
- package/src/components/LpPhoneInput.vue +241 -0
- package/src/components/LpPopover.vue +42 -0
- package/src/components/LpProgress.vue +30 -0
- package/src/components/LpRadio.vue +28 -0
- package/src/components/LpRadioGroup.vue +43 -0
- package/src/components/LpScrollArea.vue +82 -0
- package/src/components/LpSegmented.vue +83 -0
- package/src/components/LpSelect.vue +0 -0
- package/src/components/LpServiceNode.vue +57 -0
- package/src/components/LpSidebar.vue +200 -0
- package/src/components/LpSidebarNav.vue +118 -0
- package/src/components/LpSkeleton.vue +16 -0
- package/src/components/LpSlider.vue +53 -0
- package/src/components/LpStat.vue +90 -0
- package/src/components/LpStepper.vue +46 -0
- package/src/components/LpSwitch.vue +19 -0
- package/src/components/LpTable.vue +252 -0
- package/src/components/LpTableOfContents.vue +183 -0
- package/src/components/LpTabs.vue +120 -0
- package/src/components/LpTextarea.vue +39 -0
- package/src/components/LpThemeSwitcher.vue +168 -0
- package/src/components/LpToaster.vue +216 -0
- package/src/components/LpTooltip.vue +30 -0
- package/src/components/LpTopologyCanvas.vue +370 -0
- package/src/components/LpUptimeBar.vue +126 -0
- package/src/components/codeHighlight.ts +137 -0
- package/src/components/countries-data.ts +207 -0
- package/src/components/countries.ts +67 -0
- package/src/components/dropdown.ts +64 -0
- package/src/components/sidebar.ts +26 -0
- package/src/composables/useInputFilter.ts +89 -0
- package/src/composables/usePillTransition.ts +19 -0
- package/src/composables/useToast.ts +92 -0
- package/src/icons.ts +11 -0
- package/src/index.css +21 -0
- package/src/index.ts +146 -0
- package/src/layout/registry.ts +44 -0
- package/src/layout/tree.ts +288 -0
- package/src/layout/useLayout.ts +134 -0
- package/src/nuxt.ts +22 -0
- package/src/theme/config.ts +48 -0
- package/src/theme/define.ts +50 -0
- package/src/theme/presets.ts +279 -0
- package/src/theme/tokens.ts +151 -0
- package/src/theme/useTheme.ts +288 -0
- package/src/tokens/scrollbar.css +138 -0
- package/src/tokens/tokens.css +333 -0
- 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
|
+
}
|