@rokkit/ui 1.3.3 → 1.3.5

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 (176) hide show
  1. package/dist/components/index.js +63 -0
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.js +8 -0
  4. package/dist/markdown-plugin.js +1 -0
  5. package/dist/types/alert-list.js +7 -0
  6. package/dist/types/avatar.js +4 -0
  7. package/dist/types/badge.js +4 -0
  8. package/dist/types/breadcrumbs.js +4 -0
  9. package/dist/types/button.js +7 -0
  10. package/dist/types/card.js +4 -0
  11. package/dist/types/carousel.js +4 -0
  12. package/dist/types/chat.js +1 -0
  13. package/dist/types/code.js +12 -0
  14. package/dist/types/connector.js +8 -0
  15. package/dist/types/divider.js +4 -0
  16. package/dist/types/floating-action.js +12 -0
  17. package/dist/types/floating-navigation.js +1 -0
  18. package/dist/types/frame.js +8 -0
  19. package/dist/types/index.js +93 -0
  20. package/dist/types/item-content.js +8 -0
  21. package/dist/types/item-switch.js +10 -0
  22. package/dist/types/item-toggle.js +12 -0
  23. package/dist/types/list.js +36 -0
  24. package/dist/types/lock-mode.js +1 -0
  25. package/dist/types/menu.js +25 -0
  26. package/dist/types/message.js +4 -0
  27. package/dist/types/nav-content.js +4 -0
  28. package/dist/types/palette.js +54 -0
  29. package/dist/types/pill.js +4 -0
  30. package/dist/types/progress-bar.js +4 -0
  31. package/dist/types/range.js +7 -0
  32. package/dist/types/rating.js +4 -0
  33. package/dist/types/responsive-grid.js +4 -0
  34. package/dist/types/reveal.js +4 -0
  35. package/dist/types/search-filter.js +7 -0
  36. package/dist/types/select.js +21 -0
  37. package/dist/types/shine.js +7 -0
  38. package/dist/types/stack.js +4 -0
  39. package/dist/types/status-list.js +7 -0
  40. package/dist/types/stepper.js +4 -0
  41. package/dist/types/switch.js +7 -0
  42. package/dist/types/table.js +23 -0
  43. package/dist/types/tabs.js +7 -0
  44. package/dist/types/tilt.js +4 -0
  45. package/dist/types/timeline.js +14 -0
  46. package/dist/types/toggle.js +7 -0
  47. package/dist/types/toolbar.js +20 -0
  48. package/dist/types/tooltip.js +1 -0
  49. package/dist/types/tree-table.js +10 -0
  50. package/dist/types/tree.js +94 -0
  51. package/dist/types/upload-file-status.js +8 -0
  52. package/dist/types/upload-progress.js +8 -0
  53. package/dist/types/upload-target.js +7 -0
  54. package/dist/utils/palette.js +641 -0
  55. package/dist/utils/relative-time.js +17 -0
  56. package/dist/utils/shiki.js +118 -0
  57. package/package.json +13 -14
  58. package/src/components/index.ts +0 -63
  59. package/src/index.ts +0 -73
  60. package/src/markdown-plugin.ts +0 -12
  61. package/src/types/alert-list.ts +0 -28
  62. package/src/types/avatar.ts +0 -41
  63. package/src/types/badge.ts +0 -37
  64. package/src/types/breadcrumbs.ts +0 -43
  65. package/src/types/button.ts +0 -92
  66. package/src/types/card.ts +0 -38
  67. package/src/types/carousel.ts +0 -49
  68. package/src/types/chat.ts +0 -81
  69. package/src/types/code.ts +0 -147
  70. package/src/types/connector.ts +0 -22
  71. package/src/types/divider.ts +0 -20
  72. package/src/types/floating-action.ts +0 -123
  73. package/src/types/floating-navigation.ts +0 -80
  74. package/src/types/frame.ts +0 -29
  75. package/src/types/index.ts +0 -137
  76. package/src/types/item-content.ts +0 -26
  77. package/src/types/item-switch.ts +0 -34
  78. package/src/types/item-toggle.ts +0 -52
  79. package/src/types/list.ts +0 -200
  80. package/src/types/lock-mode.ts +0 -16
  81. package/src/types/menu.ts +0 -95
  82. package/src/types/message.ts +0 -54
  83. package/src/types/nav-content.ts +0 -31
  84. package/src/types/palette.ts +0 -160
  85. package/src/types/pill.ts +0 -43
  86. package/src/types/progress-bar.ts +0 -19
  87. package/src/types/range.ts +0 -51
  88. package/src/types/rating.ts +0 -43
  89. package/src/types/responsive-grid.ts +0 -25
  90. package/src/types/reveal.ts +0 -49
  91. package/src/types/search-filter.ts +0 -67
  92. package/src/types/select.ts +0 -176
  93. package/src/types/shine.ts +0 -37
  94. package/src/types/stack.ts +0 -40
  95. package/src/types/status-list.ts +0 -42
  96. package/src/types/stepper.ts +0 -74
  97. package/src/types/switch.ts +0 -68
  98. package/src/types/table.ts +0 -219
  99. package/src/types/tabs.ts +0 -103
  100. package/src/types/tilt.ts +0 -28
  101. package/src/types/timeline.ts +0 -53
  102. package/src/types/toggle.ts +0 -81
  103. package/src/types/toolbar.ts +0 -167
  104. package/src/types/tooltip.ts +0 -21
  105. package/src/types/tree-table.ts +0 -103
  106. package/src/types/tree.ts +0 -302
  107. package/src/types/upload-file-status.ts +0 -45
  108. package/src/types/upload-progress.ts +0 -111
  109. package/src/types/upload-target.ts +0 -71
  110. package/src/utils/palette.ts +0 -750
  111. package/src/utils/relative-time.ts +0 -12
  112. package/src/utils/shiki.ts +0 -137
  113. /package/{src → dist}/MarkdownRenderer.svelte +0 -0
  114. /package/{src → dist}/components/AlertList.svelte +0 -0
  115. /package/{src → dist}/components/Avatar.svelte +0 -0
  116. /package/{src → dist}/components/Badge.svelte +0 -0
  117. /package/{src → dist}/components/BreadCrumbs.svelte +0 -0
  118. /package/{src → dist}/components/Button.svelte +0 -0
  119. /package/{src → dist}/components/ButtonGroup.svelte +0 -0
  120. /package/{src → dist}/components/Card.svelte +0 -0
  121. /package/{src → dist}/components/Carousel.svelte +0 -0
  122. /package/{src → dist}/components/ChatComposer.svelte +0 -0
  123. /package/{src → dist}/components/ChatHistory.svelte +0 -0
  124. /package/{src → dist}/components/ChatMessage.svelte +0 -0
  125. /package/{src → dist}/components/ChatShell.svelte +0 -0
  126. /package/{src → dist}/components/ChatTimeline.svelte +0 -0
  127. /package/{src → dist}/components/Code.svelte +0 -0
  128. /package/{src → dist}/components/CodeBlock.svelte +0 -0
  129. /package/{src → dist}/components/CodeGroup.svelte +0 -0
  130. /package/{src → dist}/components/CommandPalette.svelte +0 -0
  131. /package/{src → dist}/components/Connector.svelte +0 -0
  132. /package/{src → dist}/components/Divider.svelte +0 -0
  133. /package/{src → dist}/components/Dropdown.svelte +0 -0
  134. /package/{src → dist}/components/FloatingAction.svelte +0 -0
  135. /package/{src → dist}/components/FloatingNavigation.svelte +0 -0
  136. /package/{src → dist}/components/Frame.svelte +0 -0
  137. /package/{src → dist}/components/Grid.svelte +0 -0
  138. /package/{src → dist}/components/ItemContent.svelte +0 -0
  139. /package/{src → dist}/components/ItemSwitch.svelte +0 -0
  140. /package/{src → dist}/components/ItemToggle.svelte +0 -0
  141. /package/{src → dist}/components/LazyTree.svelte +0 -0
  142. /package/{src → dist}/components/List.svelte +0 -0
  143. /package/{src → dist}/components/LockMode.svelte +0 -0
  144. /package/{src → dist}/components/Menu.svelte +0 -0
  145. /package/{src → dist}/components/Message.svelte +0 -0
  146. /package/{src → dist}/components/MultiSelect.svelte +0 -0
  147. /package/{src → dist}/components/NavContent.svelte +0 -0
  148. /package/{src → dist}/components/PaletteManager.svelte +0 -0
  149. /package/{src → dist}/components/Pill.svelte +0 -0
  150. /package/{src → dist}/components/ProgressBar.svelte +0 -0
  151. /package/{src → dist}/components/Range.svelte +0 -0
  152. /package/{src → dist}/components/Rating.svelte +0 -0
  153. /package/{src → dist}/components/ResponsiveGrid.svelte +0 -0
  154. /package/{src → dist}/components/Reveal.svelte +0 -0
  155. /package/{src → dist}/components/SearchFilter.svelte +0 -0
  156. /package/{src → dist}/components/Select.svelte +0 -0
  157. /package/{src → dist}/components/Shine.svelte +0 -0
  158. /package/{src → dist}/components/Stack.svelte +0 -0
  159. /package/{src → dist}/components/StatusList.svelte +0 -0
  160. /package/{src → dist}/components/Stepper.svelte +0 -0
  161. /package/{src → dist}/components/Swatch.svelte +0 -0
  162. /package/{src → dist}/components/Switch.svelte +0 -0
  163. /package/{src → dist}/components/Table.svelte +0 -0
  164. /package/{src → dist}/components/Tabs.svelte +0 -0
  165. /package/{src → dist}/components/Tilt.svelte +0 -0
  166. /package/{src → dist}/components/Timeline.svelte +0 -0
  167. /package/{src → dist}/components/Toggle.svelte +0 -0
  168. /package/{src → dist}/components/Toolbar.svelte +0 -0
  169. /package/{src → dist}/components/ToolbarGroup.svelte +0 -0
  170. /package/{src → dist}/components/Tooltip.svelte +0 -0
  171. /package/{src → dist}/components/Tree.svelte +0 -0
  172. /package/{src → dist}/components/TreeTable.svelte +0 -0
  173. /package/{src → dist}/components/UploadFileStatus.svelte +0 -0
  174. /package/{src → dist}/components/UploadProgress.svelte +0 -0
  175. /package/{src → dist}/components/UploadTarget.svelte +0 -0
  176. /package/{src → dist}/utils/upload.js +0 -0
@@ -0,0 +1,641 @@
1
+ /**
2
+ * Palette Utilities
3
+ *
4
+ * Functions for color manipulation, shade generation, and runtime palette application.
5
+ */
6
+ // =============================================================================
7
+ // Color Conversion Utilities
8
+ // =============================================================================
9
+ /**
10
+ * Convert hex color to RGB
11
+ */
12
+ export function hexToRgb(hex) {
13
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
14
+ if (!result) {
15
+ throw new Error(`Invalid hex color: ${hex}`);
16
+ }
17
+ return {
18
+ r: parseInt(result[1], 16),
19
+ g: parseInt(result[2], 16),
20
+ b: parseInt(result[3], 16)
21
+ };
22
+ }
23
+ /**
24
+ * Convert RGB to hex color
25
+ */
26
+ export function rgbToHex(rgb) {
27
+ const toHex = (n) => {
28
+ const hex = Math.round(Math.max(0, Math.min(255, n))).toString(16);
29
+ return hex.length === 1 ? `0${hex}` : hex;
30
+ };
31
+ return `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`;
32
+ }
33
+ function computeHue(norm, max, d) {
34
+ const { r, g, b } = norm;
35
+ if (max === r)
36
+ return ((g - b) / d + (g < b ? 6 : 0)) / 6;
37
+ if (max === g)
38
+ return ((b - r) / d + 2) / 6;
39
+ return ((r - g) / d + 4) / 6;
40
+ }
41
+ export function rgbToHsl(rgb) {
42
+ const norm = { r: rgb.r / 255, g: rgb.g / 255, b: rgb.b / 255 };
43
+ const max = Math.max(norm.r, norm.g, norm.b);
44
+ const min = Math.min(norm.r, norm.g, norm.b);
45
+ const l = (max + min) / 2;
46
+ if (max === min)
47
+ return { h: 0, s: 0, l: l * 100 };
48
+ const d = max - min;
49
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
50
+ const h = computeHue(norm, max, d);
51
+ return { h: h * 360, s: s * 100, l: l * 100 };
52
+ }
53
+ function normalizeT(t) {
54
+ if (t < 0)
55
+ return t + 1;
56
+ if (t > 1)
57
+ return t - 1;
58
+ return t;
59
+ }
60
+ function hue2rgb(p, q, t) {
61
+ const tt = normalizeT(t);
62
+ if (tt < 1 / 6)
63
+ return p + (q - p) * 6 * tt;
64
+ if (tt < 1 / 2)
65
+ return q;
66
+ if (tt < 2 / 3)
67
+ return p + (q - p) * (2 / 3 - tt) * 6;
68
+ return p;
69
+ }
70
+ /**
71
+ * Convert HSL to RGB
72
+ */
73
+ export function hslToRgb(hsl) {
74
+ const h = hsl.h / 360;
75
+ const s = hsl.s / 100;
76
+ const l = hsl.l / 100;
77
+ if (s === 0) {
78
+ const val = Math.round(l * 255);
79
+ return { r: val, g: val, b: val };
80
+ }
81
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
82
+ const p = 2 * l - q;
83
+ return {
84
+ r: Math.round(hue2rgb(p, q, h + 1 / 3) * 255),
85
+ g: Math.round(hue2rgb(p, q, h) * 255),
86
+ b: Math.round(hue2rgb(p, q, h - 1 / 3) * 255)
87
+ };
88
+ }
89
+ /**
90
+ * Convert hex to HSL
91
+ */
92
+ export function hexToHsl(hex) {
93
+ return rgbToHsl(hexToRgb(hex));
94
+ }
95
+ /**
96
+ * Convert HSL to hex
97
+ */
98
+ export function hslToHex(hsl) {
99
+ return rgbToHex(hslToRgb(hsl));
100
+ }
101
+ // =============================================================================
102
+ // OKLCH Conversion Utilities
103
+ // =============================================================================
104
+ function srgbToLinear(c) {
105
+ const s = c / 255;
106
+ return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
107
+ }
108
+ function linearToSrgb(c) {
109
+ const s = c <= 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
110
+ return Math.round(Math.max(0, Math.min(255, s * 255)));
111
+ }
112
+ // CSS Color Level 4 matrices (via XYZ D65) for round-trip precision.
113
+ const SRGB_TO_XYZ = [
114
+ [0.4123907993, 0.3575843394, 0.1804807884],
115
+ [0.2126390059, 0.7151686788, 0.0721923154],
116
+ [0.0193308187, 0.1191947798, 0.9505321522]
117
+ ];
118
+ const XYZ_TO_LMS = [
119
+ [0.8189330101, 0.3618667424, -0.1288597137],
120
+ [0.0329845436, 0.9293118715, 0.0361456387],
121
+ [0.0482003018, 0.2643662691, 0.633851707]
122
+ ];
123
+ const LMS3_TO_OKLAB = [
124
+ [0.2104542553, 0.793617785, -0.0040720468],
125
+ [1.9779984951, -2.428592205, 0.4505937099],
126
+ [0.0259040371, 0.7827717662, -0.808675766]
127
+ ];
128
+ const OKLAB_TO_LMS3 = [
129
+ [1.0, 0.3963377774, 0.2158037573],
130
+ [1.0, -0.1055613458, -0.0638541728],
131
+ [1.0, -0.0894841775, -1.291485548]
132
+ ];
133
+ const LMS_TO_XYZ = [
134
+ [1.2270138511, -0.5577999807, 0.281256149],
135
+ [-0.0405801784, 1.1122568696, -0.0716766787],
136
+ [-0.0763812845, -0.4214819784, 1.5861632204]
137
+ ];
138
+ const XYZ_TO_SRGB = [
139
+ [3.2409699419, -1.5373831776, -0.4986107603],
140
+ [-0.9692436363, 1.8759675015, 0.0415550574],
141
+ [0.0556300797, -0.2039769589, 1.0569715142]
142
+ ];
143
+ function matMul(m, v) {
144
+ return m.map((row) => row[0] * v[0] + row[1] * v[1] + row[2] * v[2]);
145
+ }
146
+ /**
147
+ * Convert RGB to OKLCH (via XYZ D65 for precision)
148
+ */
149
+ export function rgbToOklch(rgb) {
150
+ const lin = [srgbToLinear(rgb.r), srgbToLinear(rgb.g), srgbToLinear(rgb.b)];
151
+ const xyz = matMul(SRGB_TO_XYZ, lin);
152
+ const lms = matMul(XYZ_TO_LMS, xyz);
153
+ const lms3 = [Math.cbrt(lms[0]), Math.cbrt(lms[1]), Math.cbrt(lms[2])];
154
+ const [L, a, b] = matMul(LMS3_TO_OKLAB, lms3);
155
+ const C = Math.sqrt(a * a + b * b);
156
+ let H = (Math.atan2(b, a) * 180) / Math.PI;
157
+ if (H < 0)
158
+ H += 360;
159
+ return { L, C, H };
160
+ }
161
+ /**
162
+ * Convert OKLCH to RGB (via XYZ D65 for precision)
163
+ */
164
+ export function oklchToRgb(oklch) {
165
+ const hRad = (oklch.H * Math.PI) / 180;
166
+ const lab = [oklch.L, oklch.C * Math.cos(hRad), oklch.C * Math.sin(hRad)];
167
+ const lms3 = matMul(OKLAB_TO_LMS3, lab);
168
+ const lms = [lms3[0] ** 3, lms3[1] ** 3, lms3[2] ** 3];
169
+ const xyz = matMul(LMS_TO_XYZ, lms);
170
+ const lin = matMul(XYZ_TO_SRGB, xyz);
171
+ return {
172
+ r: linearToSrgb(lin[0]),
173
+ g: linearToSrgb(lin[1]),
174
+ b: linearToSrgb(lin[2])
175
+ };
176
+ }
177
+ /**
178
+ * Convert hex to OKLCH
179
+ */
180
+ export function hexToOklch(hex) {
181
+ return rgbToOklch(hexToRgb(hex));
182
+ }
183
+ /**
184
+ * Convert OKLCH to hex
185
+ */
186
+ export function oklchToHex(oklch) {
187
+ return rgbToHex(oklchToRgb(oklch));
188
+ }
189
+ // =============================================================================
190
+ // Shade Generation
191
+ // =============================================================================
192
+ /**
193
+ * Generate Tailwind-like shades from a base hex color
194
+ * The input color is used as the 500 shade
195
+ */
196
+ export function generateShades(hex) {
197
+ const hsl = hexToHsl(hex);
198
+ // Shade configuration: [saturation multiplier, target lightness]
199
+ // Lighter shades have higher lightness, lower saturation
200
+ // Darker shades have lower lightness, slightly higher saturation
201
+ const shadeConfig = {
202
+ '50': [0.9, 97],
203
+ '100': [0.92, 94],
204
+ '200': [0.94, 86],
205
+ '300': [0.96, 75],
206
+ '400': [0.98, 60],
207
+ '500': [1.0, hsl.l], // Keep original lightness
208
+ '600': [1.02, Math.max(hsl.l * 0.82, 25)],
209
+ '700': [1.04, Math.max(hsl.l * 0.65, 20)],
210
+ '800': [1.06, Math.max(hsl.l * 0.5, 15)],
211
+ '900': [1.08, Math.max(hsl.l * 0.35, 12)],
212
+ '950': [1.12, Math.max(hsl.l * 0.22, 8)]
213
+ };
214
+ const shades = {};
215
+ for (const [shade, [satMult, lightness]] of Object.entries(shadeConfig)) {
216
+ const newHsl = {
217
+ h: hsl.h,
218
+ s: Math.min(100, hsl.s * satMult),
219
+ l: lightness
220
+ };
221
+ shades[shade] = hslToHex(newHsl);
222
+ }
223
+ return shades;
224
+ }
225
+ /**
226
+ * Check if a string is a valid hex color
227
+ */
228
+ export function isHexColor(value) {
229
+ return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value);
230
+ }
231
+ // =============================================================================
232
+ // Tailwind Colors (Built-in Presets)
233
+ // =============================================================================
234
+ export const tailwindColors = {
235
+ slate: {
236
+ '50': '#f8fafc',
237
+ '100': '#f1f5f9',
238
+ '200': '#e2e8f0',
239
+ '300': '#cbd5e1',
240
+ '400': '#94a3b8',
241
+ '500': '#64748b',
242
+ '600': '#475569',
243
+ '700': '#334155',
244
+ '800': '#1e293b',
245
+ '900': '#0f172a',
246
+ '950': '#020617'
247
+ },
248
+ gray: {
249
+ '50': '#f9fafb',
250
+ '100': '#f3f4f6',
251
+ '200': '#e5e7eb',
252
+ '300': '#d1d5db',
253
+ '400': '#9ca3af',
254
+ '500': '#6b7280',
255
+ '600': '#4b5563',
256
+ '700': '#374151',
257
+ '800': '#1f2937',
258
+ '900': '#111827',
259
+ '950': '#030712'
260
+ },
261
+ zinc: {
262
+ '50': '#fafafa',
263
+ '100': '#f4f4f5',
264
+ '200': '#e4e4e7',
265
+ '300': '#d4d4d8',
266
+ '400': '#a1a1aa',
267
+ '500': '#71717a',
268
+ '600': '#52525b',
269
+ '700': '#3f3f46',
270
+ '800': '#27272a',
271
+ '900': '#18181b',
272
+ '950': '#09090b'
273
+ },
274
+ neutral: {
275
+ '50': '#fafafa',
276
+ '100': '#f5f5f5',
277
+ '200': '#e5e5e5',
278
+ '300': '#d4d4d4',
279
+ '400': '#a3a3a3',
280
+ '500': '#737373',
281
+ '600': '#525252',
282
+ '700': '#404040',
283
+ '800': '#262626',
284
+ '900': '#171717',
285
+ '950': '#0a0a0a'
286
+ },
287
+ stone: {
288
+ '50': '#fafaf9',
289
+ '100': '#f5f5f4',
290
+ '200': '#e7e5e4',
291
+ '300': '#d6d3d1',
292
+ '400': '#a8a29e',
293
+ '500': '#78716c',
294
+ '600': '#57534e',
295
+ '700': '#44403c',
296
+ '800': '#292524',
297
+ '900': '#1c1917',
298
+ '950': '#0c0a09'
299
+ },
300
+ red: {
301
+ '50': '#fef2f2',
302
+ '100': '#fee2e2',
303
+ '200': '#fecaca',
304
+ '300': '#fca5a5',
305
+ '400': '#f87171',
306
+ '500': '#ef4444',
307
+ '600': '#dc2626',
308
+ '700': '#b91c1c',
309
+ '800': '#991b1b',
310
+ '900': '#7f1d1d',
311
+ '950': '#450a0a'
312
+ },
313
+ orange: {
314
+ '50': '#fff7ed',
315
+ '100': '#ffedd5',
316
+ '200': '#fed7aa',
317
+ '300': '#fdba74',
318
+ '400': '#fb923c',
319
+ '500': '#f97316',
320
+ '600': '#ea580c',
321
+ '700': '#c2410c',
322
+ '800': '#9a3412',
323
+ '900': '#7c2d12',
324
+ '950': '#431407'
325
+ },
326
+ amber: {
327
+ '50': '#fffbeb',
328
+ '100': '#fef3c7',
329
+ '200': '#fde68a',
330
+ '300': '#fcd34d',
331
+ '400': '#fbbf24',
332
+ '500': '#f59e0b',
333
+ '600': '#d97706',
334
+ '700': '#b45309',
335
+ '800': '#92400e',
336
+ '900': '#78350f',
337
+ '950': '#451a03'
338
+ },
339
+ yellow: {
340
+ '50': '#fefce8',
341
+ '100': '#fef9c3',
342
+ '200': '#fef08a',
343
+ '300': '#fde047',
344
+ '400': '#facc15',
345
+ '500': '#eab308',
346
+ '600': '#ca8a04',
347
+ '700': '#a16207',
348
+ '800': '#854d0e',
349
+ '900': '#713f12',
350
+ '950': '#422006'
351
+ },
352
+ lime: {
353
+ '50': '#f7fee7',
354
+ '100': '#ecfccb',
355
+ '200': '#d9f99d',
356
+ '300': '#bef264',
357
+ '400': '#a3e635',
358
+ '500': '#84cc16',
359
+ '600': '#65a30d',
360
+ '700': '#4d7c0f',
361
+ '800': '#3f6212',
362
+ '900': '#365314',
363
+ '950': '#1a2e05'
364
+ },
365
+ green: {
366
+ '50': '#f0fdf4',
367
+ '100': '#dcfce7',
368
+ '200': '#bbf7d0',
369
+ '300': '#86efac',
370
+ '400': '#4ade80',
371
+ '500': '#22c55e',
372
+ '600': '#16a34a',
373
+ '700': '#15803d',
374
+ '800': '#166534',
375
+ '900': '#14532d',
376
+ '950': '#052e16'
377
+ },
378
+ emerald: {
379
+ '50': '#ecfdf5',
380
+ '100': '#d1fae5',
381
+ '200': '#a7f3d0',
382
+ '300': '#6ee7b7',
383
+ '400': '#34d399',
384
+ '500': '#10b981',
385
+ '600': '#059669',
386
+ '700': '#047857',
387
+ '800': '#065f46',
388
+ '900': '#064e3b',
389
+ '950': '#022c22'
390
+ },
391
+ teal: {
392
+ '50': '#f0fdfa',
393
+ '100': '#ccfbf1',
394
+ '200': '#99f6e4',
395
+ '300': '#5eead4',
396
+ '400': '#2dd4bf',
397
+ '500': '#14b8a6',
398
+ '600': '#0d9488',
399
+ '700': '#0f766e',
400
+ '800': '#115e59',
401
+ '900': '#134e4a',
402
+ '950': '#042f2e'
403
+ },
404
+ cyan: {
405
+ '50': '#ecfeff',
406
+ '100': '#cffafe',
407
+ '200': '#a5f3fc',
408
+ '300': '#67e8f9',
409
+ '400': '#22d3ee',
410
+ '500': '#06b6d4',
411
+ '600': '#0891b2',
412
+ '700': '#0e7490',
413
+ '800': '#155e75',
414
+ '900': '#164e63',
415
+ '950': '#083344'
416
+ },
417
+ sky: {
418
+ '50': '#f0f9ff',
419
+ '100': '#e0f2fe',
420
+ '200': '#bae6fd',
421
+ '300': '#7dd3fc',
422
+ '400': '#38bdf8',
423
+ '500': '#0ea5e9',
424
+ '600': '#0284c7',
425
+ '700': '#0369a1',
426
+ '800': '#075985',
427
+ '900': '#0c4a6e',
428
+ '950': '#082f49'
429
+ },
430
+ blue: {
431
+ '50': '#eff6ff',
432
+ '100': '#dbeafe',
433
+ '200': '#bfdbfe',
434
+ '300': '#93c5fd',
435
+ '400': '#60a5fa',
436
+ '500': '#3b82f6',
437
+ '600': '#2563eb',
438
+ '700': '#1d4ed8',
439
+ '800': '#1e40af',
440
+ '900': '#1e3a8a',
441
+ '950': '#172554'
442
+ },
443
+ indigo: {
444
+ '50': '#eef2ff',
445
+ '100': '#e0e7ff',
446
+ '200': '#c7d2fe',
447
+ '300': '#a5b4fc',
448
+ '400': '#818cf8',
449
+ '500': '#6366f1',
450
+ '600': '#4f46e5',
451
+ '700': '#4338ca',
452
+ '800': '#3730a3',
453
+ '900': '#312e81',
454
+ '950': '#1e1b4b'
455
+ },
456
+ violet: {
457
+ '50': '#f5f3ff',
458
+ '100': '#ede9fe',
459
+ '200': '#ddd6fe',
460
+ '300': '#c4b5fd',
461
+ '400': '#a78bfa',
462
+ '500': '#8b5cf6',
463
+ '600': '#7c3aed',
464
+ '700': '#6d28d9',
465
+ '800': '#5b21b6',
466
+ '900': '#4c1d95',
467
+ '950': '#2e1065'
468
+ },
469
+ purple: {
470
+ '50': '#faf5ff',
471
+ '100': '#f3e8ff',
472
+ '200': '#e9d5ff',
473
+ '300': '#d8b4fe',
474
+ '400': '#c084fc',
475
+ '500': '#a855f7',
476
+ '600': '#9333ea',
477
+ '700': '#7e22ce',
478
+ '800': '#6b21a8',
479
+ '900': '#581c87',
480
+ '950': '#3b0764'
481
+ },
482
+ fuchsia: {
483
+ '50': '#fdf4ff',
484
+ '100': '#fae8ff',
485
+ '200': '#f5d0fe',
486
+ '300': '#f0abfc',
487
+ '400': '#e879f9',
488
+ '500': '#d946ef',
489
+ '600': '#c026d3',
490
+ '700': '#a21caf',
491
+ '800': '#86198f',
492
+ '900': '#701a75',
493
+ '950': '#4a044e'
494
+ },
495
+ pink: {
496
+ '50': '#fdf2f8',
497
+ '100': '#fce7f3',
498
+ '200': '#fbcfe8',
499
+ '300': '#f9a8d4',
500
+ '400': '#f472b6',
501
+ '500': '#ec4899',
502
+ '600': '#db2777',
503
+ '700': '#be185d',
504
+ '800': '#9d174d',
505
+ '900': '#831843',
506
+ '950': '#500724'
507
+ },
508
+ rose: {
509
+ '50': '#fff1f2',
510
+ '100': '#ffe4e6',
511
+ '200': '#fecdd3',
512
+ '300': '#fda4af',
513
+ '400': '#fb7185',
514
+ '500': '#f43f5e',
515
+ '600': '#e11d48',
516
+ '700': '#be123c',
517
+ '800': '#9f1239',
518
+ '900': '#881337',
519
+ '950': '#4c0519'
520
+ }
521
+ };
522
+ /**
523
+ * Get shades for a color (either Tailwind preset or custom hex)
524
+ */
525
+ export function getShades(color) {
526
+ if (isHexColor(color)) {
527
+ return generateShades(color);
528
+ }
529
+ const preset = tailwindColors[color.toLowerCase()];
530
+ if (preset) {
531
+ return preset;
532
+ }
533
+ throw new Error(`Unknown color: ${color}. Must be a hex color or Tailwind color name.`);
534
+ }
535
+ // =============================================================================
536
+ // Runtime Palette Application
537
+ // =============================================================================
538
+ /**
539
+ * Format a hex color as CSS variable components for the given color space.
540
+ */
541
+ function formatComponents(hex, colorSpace) {
542
+ switch (colorSpace) {
543
+ case 'hsl': {
544
+ const hsl = hexToHsl(hex);
545
+ return `${Math.round(hsl.h)} ${Math.round(hsl.s)}% ${Math.round(hsl.l)}%`;
546
+ }
547
+ case 'oklch': {
548
+ const oklch = hexToOklch(hex);
549
+ const L = Math.round(oklch.L * 10000) / 10000;
550
+ const C = Math.round(oklch.C * 10000) / 10000;
551
+ const H = Math.round(oklch.H * 100) / 100;
552
+ return `${L} ${C} ${H}`;
553
+ }
554
+ case 'rgb':
555
+ default: {
556
+ const rgb = hexToRgb(hex);
557
+ return `${rgb.r},${rgb.g},${rgb.b}`;
558
+ }
559
+ }
560
+ }
561
+ /**
562
+ * Apply a color palette to the document root
563
+ * Sets CSS variables for each color role and shade
564
+ */
565
+ export function applyPalette(mapping, element = document.documentElement, colorSpace = 'rgb') {
566
+ for (const [role, color] of Object.entries(mapping)) {
567
+ if (!color)
568
+ continue;
569
+ const shades = getShades(color);
570
+ for (const [shade, hex] of Object.entries(shades)) {
571
+ element.style.setProperty(`--color-${role}-${shade}`, formatComponents(hex, colorSpace));
572
+ }
573
+ // Also set the default (500) as the base color variable
574
+ element.style.setProperty(`--color-${role}`, formatComponents(shades['500'], colorSpace));
575
+ }
576
+ }
577
+ const DEFAULT_PALETTE_ROLES = [
578
+ 'primary',
579
+ 'secondary',
580
+ 'accent',
581
+ 'surface',
582
+ 'success',
583
+ 'warning',
584
+ 'danger',
585
+ 'info'
586
+ ];
587
+ const ALL_SHADE_KEYS = [
588
+ '50',
589
+ '100',
590
+ '200',
591
+ '300',
592
+ '400',
593
+ '500',
594
+ '600',
595
+ '700',
596
+ '800',
597
+ '900',
598
+ '950'
599
+ ];
600
+ /**
601
+ * Remove custom palette CSS variables (reset to theme defaults)
602
+ */
603
+ export function resetPalette(roles = DEFAULT_PALETTE_ROLES, element = document.documentElement) {
604
+ for (const role of roles) {
605
+ element.style.removeProperty(`--color-${role}`);
606
+ for (const shade of ALL_SHADE_KEYS) {
607
+ element.style.removeProperty(`--color-${role}-${shade}`);
608
+ }
609
+ }
610
+ }
611
+ /**
612
+ * Save palette to localStorage. SSR-safe.
613
+ */
614
+ export function savePalette(key, mapping) {
615
+ if (typeof localStorage === 'undefined')
616
+ return;
617
+ localStorage.setItem(key, JSON.stringify(mapping));
618
+ }
619
+ /**
620
+ * Load palette from localStorage. SSR-safe.
621
+ */
622
+ export function loadPalette(key) {
623
+ if (typeof localStorage === 'undefined')
624
+ return null;
625
+ const stored = localStorage.getItem(key);
626
+ if (stored) {
627
+ try {
628
+ return JSON.parse(stored);
629
+ }
630
+ catch {
631
+ return null;
632
+ }
633
+ }
634
+ return null;
635
+ }
636
+ /**
637
+ * Get list of available Tailwind color names
638
+ */
639
+ export function getTailwindColorNames() {
640
+ return Object.keys(tailwindColors);
641
+ }
@@ -0,0 +1,17 @@
1
+ /** Format an ISO timestamp as a short relative label ("5m ago"), or a clock time when relative=false. */
2
+ export function formatRelativeTime(timestamp, relative = true) {
3
+ const ms = new Date(timestamp).getTime();
4
+ if (Number.isNaN(ms))
5
+ return '';
6
+ if (!relative)
7
+ return new Date(ms).toLocaleTimeString();
8
+ const minutes = Math.round((Date.now() - ms) / 60000);
9
+ if (minutes < 1)
10
+ return 'just now';
11
+ if (minutes < 60)
12
+ return `${minutes}m ago`;
13
+ const hours = Math.round(minutes / 60);
14
+ if (hours < 24)
15
+ return `${hours}h ago`;
16
+ return `${Math.round(hours / 24)}d ago`;
17
+ }