@tollerud/ui 1.1.4 → 3.0.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 (361) hide show
  1. package/AGENTS.md +34 -11
  2. package/CHANGELOG.md +376 -0
  3. package/COMPONENTS.md +951 -0
  4. package/GETTING_STARTED.md +159 -0
  5. package/README.md +51 -43
  6. package/SKILL.md +55 -19
  7. package/components.json +18 -0
  8. package/dist/accordion.d.ts +20 -0
  9. package/dist/accordion.js +5 -0
  10. package/dist/accordion.js.map +1 -0
  11. package/dist/action-diff.d.ts +26 -0
  12. package/dist/action-diff.js +5 -0
  13. package/dist/action-diff.js.map +1 -0
  14. package/dist/action-row.d.ts +36 -0
  15. package/dist/action-row.js +6 -0
  16. package/dist/action-row.js.map +1 -0
  17. package/dist/alert-inbox.d.ts +23 -0
  18. package/dist/alert-inbox.js +6 -0
  19. package/dist/alert-inbox.js.map +1 -0
  20. package/dist/alert.d.ts +33 -0
  21. package/dist/alert.js +5 -0
  22. package/dist/alert.js.map +1 -0
  23. package/dist/approval-card.d.ts +27 -0
  24. package/dist/approval-card.js +5 -0
  25. package/dist/approval-card.js.map +1 -0
  26. package/dist/area-chart.d.ts +10 -0
  27. package/dist/area-chart.js +5 -0
  28. package/dist/area-chart.js.map +1 -0
  29. package/dist/avatar.d.ts +27 -0
  30. package/dist/avatar.js +5 -0
  31. package/dist/avatar.js.map +1 -0
  32. package/dist/backup-status-panel.d.ts +25 -0
  33. package/dist/backup-status-panel.js +6 -0
  34. package/dist/backup-status-panel.js.map +1 -0
  35. package/dist/badge.d.ts +17 -0
  36. package/dist/badge.js +5 -0
  37. package/dist/badge.js.map +1 -0
  38. package/dist/bar-chart.d.ts +15 -0
  39. package/dist/bar-chart.js +5 -0
  40. package/dist/bar-chart.js.map +1 -0
  41. package/dist/bento-dashboard.d.ts +30 -0
  42. package/dist/bento-dashboard.js +5 -0
  43. package/dist/bento-dashboard.js.map +1 -0
  44. package/dist/breadcrumb.d.ts +16 -0
  45. package/dist/breadcrumb.js +5 -0
  46. package/dist/breadcrumb.js.map +1 -0
  47. package/dist/button.d.ts +29 -0
  48. package/dist/button.js +5 -0
  49. package/dist/button.js.map +1 -0
  50. package/dist/card.d.ts +10 -0
  51. package/dist/card.js +5 -0
  52. package/dist/card.js.map +1 -0
  53. package/dist/checkbox.d.ts +9 -0
  54. package/dist/checkbox.js +5 -0
  55. package/dist/checkbox.js.map +1 -0
  56. package/dist/chunk-2QWKOCWF.js +79 -0
  57. package/dist/chunk-2QWKOCWF.js.map +1 -0
  58. package/dist/chunk-3TGMGBKM.js +393 -0
  59. package/dist/chunk-3TGMGBKM.js.map +1 -0
  60. package/dist/chunk-3XTZPDNV.js +94 -0
  61. package/dist/chunk-3XTZPDNV.js.map +1 -0
  62. package/dist/chunk-435JHF7G.js +65 -0
  63. package/dist/chunk-435JHF7G.js.map +1 -0
  64. package/dist/chunk-4PA2ACNF.js +52 -0
  65. package/dist/chunk-4PA2ACNF.js.map +1 -0
  66. package/dist/chunk-5GWHUJ5D.js +29 -0
  67. package/dist/chunk-5GWHUJ5D.js.map +1 -0
  68. package/dist/chunk-6FUKJD3W.js +123 -0
  69. package/dist/chunk-6FUKJD3W.js.map +1 -0
  70. package/dist/chunk-6IS2AYYG.js +106 -0
  71. package/dist/chunk-6IS2AYYG.js.map +1 -0
  72. package/dist/chunk-6PZKU6ZL.js +78 -0
  73. package/dist/chunk-6PZKU6ZL.js.map +1 -0
  74. package/dist/chunk-6SKTH45H.js +75 -0
  75. package/dist/chunk-6SKTH45H.js.map +1 -0
  76. package/dist/chunk-6UXW5YUC.js +77 -0
  77. package/dist/chunk-6UXW5YUC.js.map +1 -0
  78. package/dist/chunk-7EP2T3OW.js +52 -0
  79. package/dist/chunk-7EP2T3OW.js.map +1 -0
  80. package/dist/chunk-7J5QXUQN.js +38 -0
  81. package/dist/chunk-7J5QXUQN.js.map +1 -0
  82. package/dist/chunk-7TOT5ME3.js +53 -0
  83. package/dist/chunk-7TOT5ME3.js.map +1 -0
  84. package/dist/chunk-A6L5C3IJ.js +47 -0
  85. package/dist/chunk-A6L5C3IJ.js.map +1 -0
  86. package/dist/chunk-ANW6J6PV.js +42 -0
  87. package/dist/chunk-ANW6J6PV.js.map +1 -0
  88. package/dist/chunk-APFFKNPS.js +80 -0
  89. package/dist/chunk-APFFKNPS.js.map +1 -0
  90. package/dist/chunk-AZADSX4Z.js +85 -0
  91. package/dist/chunk-AZADSX4Z.js.map +1 -0
  92. package/dist/chunk-BPCH5LJ3.js +36 -0
  93. package/dist/chunk-BPCH5LJ3.js.map +1 -0
  94. package/dist/chunk-CBQ63EBL.js +85 -0
  95. package/dist/chunk-CBQ63EBL.js.map +1 -0
  96. package/dist/chunk-CDI7353B.js +40 -0
  97. package/dist/chunk-CDI7353B.js.map +1 -0
  98. package/dist/chunk-CKNWXYMA.js +53 -0
  99. package/dist/chunk-CKNWXYMA.js.map +1 -0
  100. package/dist/chunk-DFM7UUKB.js +79 -0
  101. package/dist/chunk-DFM7UUKB.js.map +1 -0
  102. package/dist/chunk-DGCRHVWW.js +84 -0
  103. package/dist/chunk-DGCRHVWW.js.map +1 -0
  104. package/dist/chunk-DNJI65VQ.js +22 -0
  105. package/dist/chunk-DNJI65VQ.js.map +1 -0
  106. package/dist/chunk-DOUDJU4P.js +63 -0
  107. package/dist/chunk-DOUDJU4P.js.map +1 -0
  108. package/dist/chunk-DRCMGIQ6.js +64 -0
  109. package/dist/chunk-DRCMGIQ6.js.map +1 -0
  110. package/dist/chunk-DZOBXK2S.js +28 -0
  111. package/dist/chunk-DZOBXK2S.js.map +1 -0
  112. package/dist/chunk-EN4OJCEF.js +54 -0
  113. package/dist/chunk-EN4OJCEF.js.map +1 -0
  114. package/dist/chunk-EVHZFYWX.js +33 -0
  115. package/dist/chunk-EVHZFYWX.js.map +1 -0
  116. package/dist/chunk-FGXOV2QH.js +23 -0
  117. package/dist/chunk-FGXOV2QH.js.map +1 -0
  118. package/dist/chunk-G2VKWNZA.js +53 -0
  119. package/dist/chunk-G2VKWNZA.js.map +1 -0
  120. package/dist/chunk-GTM2DE4C.js +156 -0
  121. package/dist/chunk-GTM2DE4C.js.map +1 -0
  122. package/dist/chunk-H3ZVGTJM.js +165 -0
  123. package/dist/chunk-H3ZVGTJM.js.map +1 -0
  124. package/dist/chunk-HWAWUEHC.js +28 -0
  125. package/dist/chunk-HWAWUEHC.js.map +1 -0
  126. package/dist/chunk-HWJVRTWO.js +36 -0
  127. package/dist/chunk-HWJVRTWO.js.map +1 -0
  128. package/dist/chunk-HYQGOC2E.js +79 -0
  129. package/dist/chunk-HYQGOC2E.js.map +1 -0
  130. package/dist/chunk-ILADNTUB.js +77 -0
  131. package/dist/chunk-ILADNTUB.js.map +1 -0
  132. package/dist/chunk-ISHZ6ZPJ.js +31 -0
  133. package/dist/chunk-ISHZ6ZPJ.js.map +1 -0
  134. package/dist/chunk-JRFSUVSO.js +66 -0
  135. package/dist/chunk-JRFSUVSO.js.map +1 -0
  136. package/dist/chunk-KI6OTVID.js +91 -0
  137. package/dist/chunk-KI6OTVID.js.map +1 -0
  138. package/dist/chunk-LUM2YJBH.js +73 -0
  139. package/dist/chunk-LUM2YJBH.js.map +1 -0
  140. package/dist/chunk-NHPISZWS.js +71 -0
  141. package/dist/chunk-NHPISZWS.js.map +1 -0
  142. package/dist/chunk-NOLWJJHT.js +52 -0
  143. package/dist/chunk-NOLWJJHT.js.map +1 -0
  144. package/dist/chunk-NPVINX3Q.js +20 -0
  145. package/dist/chunk-NPVINX3Q.js.map +1 -0
  146. package/dist/chunk-NSMU66ZX.js +47 -0
  147. package/dist/chunk-NSMU66ZX.js.map +1 -0
  148. package/dist/chunk-O57QMLNI.js +68 -0
  149. package/dist/chunk-O57QMLNI.js.map +1 -0
  150. package/dist/chunk-O5SWPHUQ.js +79 -0
  151. package/dist/chunk-O5SWPHUQ.js.map +1 -0
  152. package/dist/chunk-OGVSZ7NV.js +53 -0
  153. package/dist/chunk-OGVSZ7NV.js.map +1 -0
  154. package/dist/chunk-OONIUDST.js +48 -0
  155. package/dist/chunk-OONIUDST.js.map +1 -0
  156. package/dist/chunk-PLF3BBQI.js +139 -0
  157. package/dist/chunk-PLF3BBQI.js.map +1 -0
  158. package/dist/chunk-Q74VRQEX.js +26 -0
  159. package/dist/chunk-Q74VRQEX.js.map +1 -0
  160. package/dist/chunk-QEHTPQHL.js +35 -0
  161. package/dist/chunk-QEHTPQHL.js.map +1 -0
  162. package/dist/chunk-RJTDQOT2.js +73 -0
  163. package/dist/chunk-RJTDQOT2.js.map +1 -0
  164. package/dist/chunk-RQ3RXKAZ.js +203 -0
  165. package/dist/chunk-RQ3RXKAZ.js.map +1 -0
  166. package/dist/chunk-RWJELAS6.js +46 -0
  167. package/dist/chunk-RWJELAS6.js.map +1 -0
  168. package/dist/chunk-RZK2S2OO.js +126 -0
  169. package/dist/chunk-RZK2S2OO.js.map +1 -0
  170. package/dist/chunk-SAP7JSSO.js +106 -0
  171. package/dist/chunk-SAP7JSSO.js.map +1 -0
  172. package/dist/chunk-T3TQPOVM.js +79 -0
  173. package/dist/chunk-T3TQPOVM.js.map +1 -0
  174. package/dist/chunk-T56TTOI6.js +53 -0
  175. package/dist/chunk-T56TTOI6.js.map +1 -0
  176. package/dist/chunk-T7EFDE2L.js +36 -0
  177. package/dist/chunk-T7EFDE2L.js.map +1 -0
  178. package/dist/chunk-V3P5QLLX.js +154 -0
  179. package/dist/chunk-V3P5QLLX.js.map +1 -0
  180. package/dist/chunk-VTRUUT5K.js +31 -0
  181. package/dist/chunk-VTRUUT5K.js.map +1 -0
  182. package/dist/chunk-WDANALHD.js +95 -0
  183. package/dist/chunk-WDANALHD.js.map +1 -0
  184. package/dist/chunk-WSQNPRGN.js +12 -0
  185. package/dist/chunk-WSQNPRGN.js.map +1 -0
  186. package/dist/chunk-XR5QBVEV.js +56 -0
  187. package/dist/chunk-XR5QBVEV.js.map +1 -0
  188. package/dist/chunk-YYWODLER.js +111 -0
  189. package/dist/chunk-YYWODLER.js.map +1 -0
  190. package/dist/chunk-ZOXO3G3I.js +50 -0
  191. package/dist/chunk-ZOXO3G3I.js.map +1 -0
  192. package/dist/code-block.d.ts +14 -0
  193. package/dist/code-block.js +5 -0
  194. package/dist/code-block.js.map +1 -0
  195. package/dist/combobox.d.ts +26 -0
  196. package/dist/combobox.js +5 -0
  197. package/dist/combobox.js.map +1 -0
  198. package/dist/command-menu.d.ts +52 -0
  199. package/dist/command-menu.js +7 -0
  200. package/dist/command-menu.js.map +1 -0
  201. package/dist/container.d.ts +9 -0
  202. package/dist/container.js +5 -0
  203. package/dist/container.js.map +1 -0
  204. package/dist/cta-band.d.ts +12 -0
  205. package/dist/cta-band.js +5 -0
  206. package/dist/cta-band.js.map +1 -0
  207. package/dist/data-table.d.ts +58 -0
  208. package/dist/data-table.js +12 -0
  209. package/dist/data-table.js.map +1 -0
  210. package/dist/date-picker.d.ts +20 -0
  211. package/dist/date-picker.js +5 -0
  212. package/dist/date-picker.js.map +1 -0
  213. package/dist/dialog.d.ts +21 -0
  214. package/dist/dialog.js +5 -0
  215. package/dist/dialog.js.map +1 -0
  216. package/dist/divider.d.ts +12 -0
  217. package/dist/divider.js +5 -0
  218. package/dist/divider.js.map +1 -0
  219. package/dist/docker-stack-card.d.ts +21 -0
  220. package/dist/docker-stack-card.js +6 -0
  221. package/dist/docker-stack-card.js.map +1 -0
  222. package/dist/donut.d.ts +15 -0
  223. package/dist/donut.js +5 -0
  224. package/dist/donut.js.map +1 -0
  225. package/dist/dropdown-menu.d.ts +15 -0
  226. package/dist/dropdown-menu.js +5 -0
  227. package/dist/dropdown-menu.js.map +1 -0
  228. package/dist/empty.d.ts +12 -0
  229. package/dist/empty.js +5 -0
  230. package/dist/empty.js.map +1 -0
  231. package/dist/feature-card.d.ts +11 -0
  232. package/dist/feature-card.js +6 -0
  233. package/dist/feature-card.js.map +1 -0
  234. package/dist/file-upload.d.ts +20 -0
  235. package/dist/file-upload.js +5 -0
  236. package/dist/file-upload.js.map +1 -0
  237. package/dist/footer.d.ts +35 -0
  238. package/dist/footer.js +5 -0
  239. package/dist/footer.js.map +1 -0
  240. package/dist/form-row.d.ts +15 -0
  241. package/dist/form-row.js +5 -0
  242. package/dist/form-row.js.map +1 -0
  243. package/dist/glow-card.d.ts +14 -0
  244. package/dist/glow-card.js +5 -0
  245. package/dist/glow-card.js.map +1 -0
  246. package/dist/hero-block.d.ts +16 -0
  247. package/dist/hero-block.js +7 -0
  248. package/dist/hero-block.js.map +1 -0
  249. package/dist/host-card.d.ts +27 -0
  250. package/dist/host-card.js +6 -0
  251. package/dist/host-card.js.map +1 -0
  252. package/dist/incident-card.d.ts +23 -0
  253. package/dist/incident-card.js +5 -0
  254. package/dist/incident-card.js.map +1 -0
  255. package/dist/index.d.ts +76 -960
  256. package/dist/index.js +68 -3812
  257. package/dist/index.js.map +1 -1
  258. package/dist/input.d.ts +10 -0
  259. package/dist/input.js +5 -0
  260. package/dist/input.js.map +1 -0
  261. package/dist/kbd.d.ts +24 -0
  262. package/dist/kbd.js +5 -0
  263. package/dist/kbd.js.map +1 -0
  264. package/dist/log-viewer.d.ts +35 -0
  265. package/dist/log-viewer.js +5 -0
  266. package/dist/log-viewer.js.map +1 -0
  267. package/dist/meter.d.ts +23 -0
  268. package/dist/meter.js +5 -0
  269. package/dist/meter.js.map +1 -0
  270. package/dist/noir-glow-background.d.ts +50 -0
  271. package/dist/noir-glow-background.js +4 -0
  272. package/dist/noir-glow-background.js.map +1 -0
  273. package/dist/pagination.d.ts +16 -0
  274. package/dist/pagination.js +5 -0
  275. package/dist/pagination.js.map +1 -0
  276. package/dist/panel.d.ts +12 -0
  277. package/dist/panel.js +5 -0
  278. package/dist/panel.js.map +1 -0
  279. package/dist/password-input.d.ts +10 -0
  280. package/dist/password-input.js +5 -0
  281. package/dist/password-input.js.map +1 -0
  282. package/dist/pill.d.ts +14 -0
  283. package/dist/pill.js +5 -0
  284. package/dist/pill.js.map +1 -0
  285. package/dist/pricing-card.d.ts +20 -0
  286. package/dist/pricing-card.js +6 -0
  287. package/dist/pricing-card.js.map +1 -0
  288. package/dist/progress.d.ts +6 -0
  289. package/dist/progress.js +5 -0
  290. package/dist/progress.js.map +1 -0
  291. package/dist/radio-group.d.ts +18 -0
  292. package/dist/radio-group.js +5 -0
  293. package/dist/radio-group.js.map +1 -0
  294. package/dist/rollback-plan.d.ts +23 -0
  295. package/dist/rollback-plan.js +5 -0
  296. package/dist/rollback-plan.js.map +1 -0
  297. package/dist/segmented.d.ts +17 -0
  298. package/dist/segmented.js +5 -0
  299. package/dist/segmented.js.map +1 -0
  300. package/dist/select.d.ts +18 -0
  301. package/dist/select.js +5 -0
  302. package/dist/select.js.map +1 -0
  303. package/dist/service-health-card.d.ts +21 -0
  304. package/dist/service-health-card.js +6 -0
  305. package/dist/service-health-card.js.map +1 -0
  306. package/dist/sheet.d.ts +25 -0
  307. package/dist/sheet.js +5 -0
  308. package/dist/sheet.js.map +1 -0
  309. package/dist/skeleton.d.ts +5 -0
  310. package/dist/skeleton.js +5 -0
  311. package/dist/skeleton.js.map +1 -0
  312. package/dist/slider.d.ts +12 -0
  313. package/dist/slider.js +5 -0
  314. package/dist/slider.js.map +1 -0
  315. package/dist/sparkline.d.ts +16 -0
  316. package/dist/sparkline.js +5 -0
  317. package/dist/sparkline.js.map +1 -0
  318. package/dist/stat-card.d.ts +15 -0
  319. package/dist/stat-card.js +5 -0
  320. package/dist/stat-card.js.map +1 -0
  321. package/dist/status-dot.d.ts +13 -0
  322. package/dist/status-dot.js +5 -0
  323. package/dist/status-dot.js.map +1 -0
  324. package/dist/stepper.d.ts +16 -0
  325. package/dist/stepper.js +5 -0
  326. package/dist/stepper.js.map +1 -0
  327. package/dist/switch.d.ts +9 -0
  328. package/dist/switch.js +5 -0
  329. package/dist/switch.js.map +1 -0
  330. package/dist/tabs.d.ts +9 -0
  331. package/dist/tabs.js +5 -0
  332. package/dist/tabs.js.map +1 -0
  333. package/dist/tag-input.d.ts +20 -0
  334. package/dist/tag-input.js +5 -0
  335. package/dist/tag-input.js.map +1 -0
  336. package/dist/textarea.d.ts +10 -0
  337. package/dist/textarea.js +5 -0
  338. package/dist/textarea.js.map +1 -0
  339. package/dist/timeline.d.ts +30 -0
  340. package/dist/timeline.js +5 -0
  341. package/dist/timeline.js.map +1 -0
  342. package/dist/toaster.d.ts +10 -0
  343. package/dist/toaster.js +4 -0
  344. package/dist/toaster.js.map +1 -0
  345. package/dist/tooltip.d.ts +12 -0
  346. package/dist/tooltip.js +5 -0
  347. package/dist/tooltip.js.map +1 -0
  348. package/dist/utils.d.ts +5 -0
  349. package/dist/utils.js +4 -0
  350. package/dist/utils.js.map +1 -0
  351. package/globals-layers.css +935 -0
  352. package/globals-v3.css +17 -0
  353. package/globals-v4.css +2 -0
  354. package/globals.css +12 -939
  355. package/package.json +82 -17
  356. package/registry.json +920 -0
  357. package/tailwind.css +9 -0
  358. package/tollerud-preset.js +55 -50
  359. package/dist/index.cjs +0 -3938
  360. package/dist/index.cjs.map +0 -1
  361. package/dist/index.d.cts +0 -960
package/dist/index.js CHANGED
@@ -1,3815 +1,71 @@
1
1
  'use client';
2
- import { clsx } from 'clsx';
3
- import { twMerge } from 'tailwind-merge';
4
- import * as React2 from 'react';
5
- import { forwardRef, useState, useCallback, lazy, useRef, useEffect, useMemo, useId, Fragment as Fragment$1, createContext, useContext, Suspense } from 'react';
6
- import { Slot } from '@radix-ui/react-slot';
7
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
- import { motion } from 'framer-motion';
9
- import * as DialogPrimitive from '@radix-ui/react-dialog';
10
- import { X, ChevronRight, ChevronLeft, MoreHorizontal, Check, ChevronDown, EyeOff, Eye, Calendar, Upload, File } from 'lucide-react';
11
- import * as TooltipPrimitive from '@radix-ui/react-tooltip';
12
- import * as TabsPrimitive from '@radix-ui/react-tabs';
13
- import * as ProgressPrimitive from '@radix-ui/react-progress';
14
- import { Toaster as Toaster$1 } from 'sonner';
15
- import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
16
-
17
- // lib/utils.ts
18
- function cn(...inputs) {
19
- return twMerge(clsx(inputs));
20
- }
21
- var variants = {
22
- primary: "bg-tollerud-yellow text-tollerud-black border-tollerud-yellow hover:bg-tollerud-yellow hover:shadow-tollerud-glow",
23
- secondary: "bg-transparent text-tollerud-text-primary border-tollerud-border hover:border-tollerud-text-secondary hover:bg-tollerud-surface-hover",
24
- ghost: "bg-transparent text-tollerud-text-secondary border-transparent hover:text-tollerud-text-primary hover:bg-tollerud-surface-hover",
25
- destructive: "bg-tollerud-error text-white border-tollerud-error hover:shadow-[0_0_12px_rgba(239,68,68,0.3)]",
26
- terminal: 'font-mono text-tollerud-yellow border-[rgba(255,255,0,0.25)] bg-transparent before:content-["\u276F_"] before:opacity-70 hover:border-tollerud-yellow hover:shadow-tollerud-glow hover:bg-[rgba(255,255,0,0.05)]'
27
- };
28
- var sizes = {
29
- sm: "px-3 py-1 text-sm",
30
- md: "px-4 py-2 text-base",
31
- lg: "px-6 py-3 text-lg"
32
- };
33
- function buttonVariants({ variant = "secondary", size = "md", className } = {}) {
34
- return cn(
35
- "inline-flex items-center justify-center gap-2 font-semibold rounded transition-all duration-[150ms] focus-visible:outline-2 focus-visible:outline-tollerud-yellow focus-visible:outline-offset-2",
36
- "border cursor-pointer",
37
- "disabled:opacity-50 disabled:pointer-events-none",
38
- variants[variant],
39
- sizes[size],
40
- className
41
- );
42
- }
43
- var Button = forwardRef(
44
- ({ className, variant = "secondary", size = "md", asChild = false, ...props }, ref) => {
45
- const Comp = asChild ? Slot : "button";
46
- return /* @__PURE__ */ jsx(
47
- Comp,
48
- {
49
- ref,
50
- className: buttonVariants({ variant, size, className }),
51
- ...props
52
- }
53
- );
54
- }
55
- );
56
- Button.displayName = "Button";
57
- var toneStyles = {
58
- default: { wrapper: "border-tollerud-border bg-tollerud-surface-raised", icon: "text-tollerud-text-muted" },
59
- accent: { wrapper: "border-tollerud-yellow/30 bg-tollerud-yellow/5", icon: "text-tollerud-yellow" },
60
- info: { wrapper: "border-blue-500/30 bg-blue-500/5", icon: "text-blue-400" },
61
- success: { wrapper: "border-green-500/30 bg-green-500/5", icon: "text-green-400" },
62
- error: { wrapper: "border-red-500/30 bg-red-500/5", icon: "text-red-400" }
63
- };
64
- var Alert = forwardRef(
65
- ({ className, tone = "default", title, icon, children, ...props }, ref) => {
66
- const styles = toneStyles[tone];
67
- return /* @__PURE__ */ jsxs(
68
- "div",
69
- {
70
- ref,
71
- role: "alert",
72
- className: cn(
73
- "flex gap-3 rounded-md border p-4",
74
- styles.wrapper,
75
- className
76
- ),
77
- ...props,
78
- children: [
79
- icon && /* @__PURE__ */ jsx("span", { className: cn("mt-0.5 flex-shrink-0 w-[18px] h-[18px]", styles.icon), children: icon }),
80
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
81
- title && /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-tollerud-text-primary leading-snug", children: title }),
82
- children && /* @__PURE__ */ jsx("p", { className: cn("text-sm text-tollerud-text-secondary leading-relaxed", title && "mt-1"), children })
83
- ] })
84
- ]
85
- }
86
- );
87
- }
88
- );
89
- Alert.displayName = "Alert";
90
- var Card = forwardRef(
91
- ({ className, accent, density, ...props }, ref) => {
92
- return /* @__PURE__ */ jsx(
93
- "div",
94
- {
95
- ref,
96
- "data-density": density ?? void 0,
97
- className: cn(
98
- "rounded-lg border bg-tollerud-surface-raised p-6 transition-[border-color] duration-[150ms]",
99
- accent ? "border-tollerud-yellow/25" : "border-tollerud-border",
100
- "hover:border-tollerud-noir-500",
101
- className
102
- ),
103
- ...props
104
- }
105
- );
106
- }
107
- );
108
- Card.displayName = "Card";
109
- var badgeVariants = {
110
- default: "bg-tollerud-noir-700 text-tollerud-text-secondary",
111
- accent: "bg-tollerud-yellow/15 text-tollerud-yellow",
112
- success: "bg-tollerud-success/15 text-tollerud-success",
113
- error: "bg-tollerud-error/15 text-tollerud-error",
114
- info: "bg-tollerud-info/15 text-tollerud-info",
115
- warning: "bg-tollerud-yellow/15 text-tollerud-warning"
116
- };
117
- var Badge = forwardRef(
118
- ({ className, variant = "default", ...props }, ref) => {
119
- return /* @__PURE__ */ jsx(
120
- "span",
121
- {
122
- ref,
123
- className: cn(
124
- "inline-flex items-center px-2 py-0.5 text-xs font-medium rounded",
125
- "tracking-wide",
126
- badgeVariants[variant],
127
- className
128
- ),
129
- ...props
130
- }
131
- );
132
- }
133
- );
134
- Badge.displayName = "Badge";
135
- var statusColors = {
136
- online: "bg-tollerud-success",
137
- offline: "bg-tollerud-error",
138
- warning: "bg-tollerud-yellow",
139
- idle: "bg-tollerud-noir-400"
140
- };
141
- var pulseColors = {
142
- online: "rgba(34,197,94,0.5)",
143
- warning: "rgba(232,213,0,0.45)",
144
- offline: "rgba(239,68,68,0.5)"
145
- };
146
- var animationKeyframes = `
147
- @keyframes tollerud-dot-pulse {
148
- 0%, 100% { box-shadow: 0 0 0 0 var(--pulse-color, rgba(34,197,94,0.5)); }
149
- 50% { box-shadow: 0 0 0 5px var(--pulse-color, rgba(34,197,94,0)); }
150
- }
151
- `;
152
- var StatusDot = forwardRef(
153
- ({ className, status = "idle", label, noPulse, ...props }, ref) => {
154
- const shouldPulse = !noPulse && (status === "online" || status === "warning" || status === "offline");
155
- const pulseColor = pulseColors[status];
156
- return /* @__PURE__ */ jsxs(
157
- "span",
158
- {
159
- ref,
160
- className: cn("inline-flex items-center gap-1.5 text-xs font-medium", className),
161
- ...props,
162
- children: [
163
- /* @__PURE__ */ jsx("style", { children: animationKeyframes }),
164
- /* @__PURE__ */ jsx(
165
- motion.span,
166
- {
167
- layout: true,
168
- animate: {
169
- scaleX: [1, 1.6, 1],
170
- scaleY: [1, 0.6, 1]
171
- },
172
- transition: {
173
- duration: 0.4,
174
- ease: "easeOut",
175
- times: [0, 0.3, 1]
176
- },
177
- className: cn(
178
- "inline-block w-2 h-2 rounded-full",
179
- statusColors[status],
180
- shouldPulse && "animate-tollerud-dot-pulse"
181
- ),
182
- style: {
183
- ...shouldPulse && pulseColor ? { "--pulse-color": pulseColor } : {},
184
- animation: shouldPulse ? "tollerud-dot-pulse 2s ease-in-out infinite" : void 0
185
- }
186
- },
187
- status
188
- ),
189
- label && /* @__PURE__ */ jsx("span", { children: label })
190
- ]
191
- }
192
- );
193
- }
194
- );
195
- StatusDot.displayName = "StatusDot";
196
- var Input = forwardRef(
197
- ({ className, label, error, id, ...props }, ref) => {
198
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
199
- label && /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-xs font-medium text-tollerud-text-muted", children: label }),
200
- /* @__PURE__ */ jsx(
201
- "input",
202
- {
203
- ref,
204
- id,
205
- className: cn(
206
- "font-sans text-base px-3 py-2 rounded",
207
- "bg-tollerud-surface-raised border",
208
- "text-tollerud-text-primary",
209
- "placeholder:text-tollerud-text-muted",
210
- "transition-[border-color] duration-[150ms]",
211
- "focus:outline-none focus:border-tollerud-yellow focus:shadow-[0_0_0_1px_#E8D500]",
212
- error ? "border-tollerud-error" : "border-tollerud-border",
213
- className
214
- ),
215
- ...props
216
- }
217
- ),
218
- error && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-error mt-0.5", children: error })
219
- ] });
220
- }
221
- );
222
- Input.displayName = "Input";
223
- var CodeBlock = forwardRef(
224
- ({ className, children, code, promptPrefix, showCopy = true, ...props }, ref) => {
225
- const [copied, setCopied] = useState(false);
226
- const content = code ? /* @__PURE__ */ jsx("code", { className: "text-tollerud-noir-200", children: code }) : children;
227
- const handleCopy = useCallback(async () => {
228
- const text = code ?? (typeof children === "string" ? children : "");
229
- if (!text) return;
230
- try {
231
- await navigator.clipboard.writeText(text);
232
- } catch {
233
- const textarea = document.createElement("textarea");
234
- textarea.value = text;
235
- textarea.style.position = "fixed";
236
- textarea.style.opacity = "0";
237
- document.body.appendChild(textarea);
238
- textarea.select();
239
- document.execCommand("copy");
240
- document.body.removeChild(textarea);
241
- }
242
- setCopied(true);
243
- setTimeout(() => setCopied(false), 1500);
244
- }, [code, children]);
245
- return /* @__PURE__ */ jsxs("div", { className: "relative group", children: [
246
- /* @__PURE__ */ jsx(
247
- "pre",
248
- {
249
- ref,
250
- className: cn(
251
- "font-mono text-sm leading-relaxed overflow-x-auto rounded border p-4",
252
- "bg-tollerud-noir-900 border-tollerud-border text-tollerud-noir-200",
253
- className
254
- ),
255
- ...props,
256
- children: content
257
- }
258
- ),
259
- showCopy && /* @__PURE__ */ jsx(
260
- "button",
261
- {
262
- onClick: handleCopy,
263
- className: cn(
264
- "absolute top-2 right-2 px-2 py-1 rounded text-xs font-medium",
265
- "opacity-0 group-hover:opacity-100 transition-all",
266
- "bg-tollerud-noir-800 border border-tollerud-border/30 text-tollerud-text-muted",
267
- "hover:bg-tollerud-surface-raised hover:text-tollerud-text-primary",
268
- copied && "opacity-100 bg-tollerud-success/15 text-tollerud-success border-tollerud-success/40"
269
- ),
270
- "aria-label": copied ? "Copied" : "Copy code",
271
- children: copied ? "\u2713 Copied" : "Copy"
272
- }
273
- )
274
- ] });
275
- }
276
- );
277
- CodeBlock.displayName = "CodeBlock";
278
- var StatCard = forwardRef(
279
- ({ className, label, value, change, accent, ...props }, ref) => {
280
- return /* @__PURE__ */ jsxs(
281
- "div",
282
- {
283
- ref,
284
- className: cn(
285
- "group relative rounded-lg border p-4",
286
- "bg-tollerud-surface-raised",
287
- "transition-all duration-200 ease-out",
288
- "hover:translate-y-[-1px]",
289
- accent ? "border-tollerud-yellow/20 hover:border-tollerud-yellow/40 hover:shadow-[0_0_20px_rgba(232,213,0,0.08)]" : "border-tollerud-border hover:border-tollerud-noir-500 hover:shadow-[0_4px_12px_rgba(0,0,0,0.3)]",
290
- className
291
- ),
292
- ...props,
293
- children: [
294
- accent && /* @__PURE__ */ jsx("span", { className: "absolute top-0 left-4 right-4 h-px bg-gradient-to-r from-transparent via-tollerud-yellow/60 to-transparent" }),
295
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
296
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase tracking-wider text-tollerud-text-muted", children: label }),
297
- change && /* @__PURE__ */ jsxs(
298
- "span",
299
- {
300
- className: cn(
301
- "inline-flex items-center gap-0.5 text-[11px] font-semibold whitespace-nowrap",
302
- change.direction === "up" ? "text-tollerud-success" : "text-tollerud-error"
303
- ),
304
- children: [
305
- /* @__PURE__ */ jsx(
306
- "svg",
307
- {
308
- className: cn(
309
- "w-3 h-3",
310
- change.direction === "down" && "rotate-180"
311
- ),
312
- viewBox: "0 0 24 24",
313
- fill: "none",
314
- stroke: "currentColor",
315
- strokeWidth: 2.5,
316
- strokeLinecap: "round",
317
- strokeLinejoin: "round",
318
- children: /* @__PURE__ */ jsx("path", { d: "M12 5v14M5 12l7 7 7-7" })
319
- }
320
- ),
321
- change.value
322
- ]
323
- }
324
- )
325
- ] }),
326
- /* @__PURE__ */ jsx(
327
- "p",
328
- {
329
- className: cn(
330
- "text-2xl font-bold tracking-tight mt-1",
331
- accent ? "text-tollerud-yellow" : "text-tollerud-text-primary"
332
- ),
333
- children: value
334
- }
335
- )
336
- ]
337
- }
338
- );
339
- }
340
- );
341
- StatCard.displayName = "StatCard";
342
- var Container = forwardRef(
343
- ({ className, as: Tag = "div", ...props }, ref) => {
344
- return /* @__PURE__ */ jsx(
345
- Tag,
346
- {
347
- ref,
348
- className: cn("mx-auto w-full max-w-[1100px] px-6", className),
349
- ...props
350
- }
351
- );
352
- }
353
- );
354
- Container.displayName = "Container";
355
- var GrainGradient = lazy(
356
- () => import('@paper-design/shaders-react').then((module) => ({
357
- default: module.GrainGradient
358
- }))
359
- );
360
- var intensityMap = {
361
- subtle: 0.24,
362
- medium: 0.45,
363
- loud: 0.68
364
- };
365
- var speedMap = {
366
- still: 0,
367
- slow: 0.45,
368
- medium: 1,
369
- fast: 1.8
370
- };
371
- var grainMap = {
372
- none: 0,
373
- soft: 0.12,
374
- high: 0.28
375
- };
376
- function cx(...classes) {
377
- return classes.filter(Boolean).join(" ");
378
- }
379
- function CssFallback({ preserveCenter = true, noiseOverlay = true }) {
380
- return /* @__PURE__ */ jsxs(Fragment, { children: [
381
- /* @__PURE__ */ jsx("div", { className: "tollerud-noir-glow-bg", "aria-hidden": "true" }),
382
- preserveCenter && /* @__PURE__ */ jsx("div", { className: "tollerud-noir-glow-vignette", "aria-hidden": "true" }),
383
- noiseOverlay && /* @__PURE__ */ jsx("div", { className: "tollerud-noir-noise", "aria-hidden": "true" })
384
- ] });
385
- }
386
- function NoirGlowBackground({
387
- className,
388
- style,
389
- shape = "corners",
390
- intensity = "medium",
391
- speed = "medium",
392
- grain = "none",
393
- softness = 0.76,
394
- colorBack = "hsl(0, 0%, 0%)",
395
- colors = ["hsl(54, 85%, 66%)", "hsl(56, 100%, 80%)", "hsl(56, 100%, 50%)"],
396
- preserveCenter = false,
397
- noiseOverlay = false,
398
- forceCssFallback = false,
399
- inert = true
400
- }) {
401
- const wrapperClassName = cx(
402
- "tollerud-noir-glow-root absolute inset-0 z-0 overflow-hidden",
403
- inert && "pointer-events-none",
404
- className
405
- );
406
- if (forceCssFallback) {
407
- return /* @__PURE__ */ jsx("div", { className: wrapperClassName, style, "aria-hidden": "true", children: /* @__PURE__ */ jsx(CssFallback, { preserveCenter, noiseOverlay }) });
408
- }
409
- return /* @__PURE__ */ jsxs("div", { className: wrapperClassName, style, "aria-hidden": "true", children: [
410
- /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(CssFallback, { preserveCenter, noiseOverlay }), children: /* @__PURE__ */ jsx(
411
- GrainGradient,
412
- {
413
- style: { height: "100%", width: "100%" },
414
- colorBack,
415
- softness,
416
- intensity: intensityMap[intensity],
417
- noise: grainMap[grain],
418
- shape,
419
- offsetX: 0,
420
- offsetY: 0,
421
- scale: 1,
422
- rotation: 0,
423
- speed: speedMap[speed],
424
- colors
425
- }
426
- ) }),
427
- preserveCenter && /* @__PURE__ */ jsx("div", { className: "tollerud-noir-glow-vignette", "aria-hidden": "true" }),
428
- noiseOverlay && /* @__PURE__ */ jsx("div", { className: "tollerud-noir-noise", "aria-hidden": "true" })
429
- ] });
430
- }
431
- var Kbd = forwardRef(
432
- ({ className, keys, size = "md", ...props }, ref) => {
433
- const keyArray = typeof keys === "string" ? [keys] : keys;
434
- return /* @__PURE__ */ jsx(
435
- "span",
436
- {
437
- ref,
438
- className: cn(
439
- "tollerud-kbd",
440
- size === "sm" && "tollerud-kbd--sm",
441
- className
442
- ),
443
- ...props,
444
- children: keyArray.map((key, i) => /* @__PURE__ */ jsx("span", { className: "tollerud-kbd__key", children: key }, i))
445
- }
446
- );
447
- }
448
- );
449
- Kbd.displayName = "Kbd";
450
- var ActionRow = forwardRef(
451
- ({
452
- action,
453
- highlighted = false,
454
- showShortcut = true,
455
- className,
456
- disabled,
457
- onClick,
458
- ...props
459
- }, ref) => {
460
- return /* @__PURE__ */ jsxs(
461
- "button",
462
- {
463
- ref,
464
- type: "button",
465
- disabled: disabled ?? action.disabled,
466
- onClick: (e) => {
467
- onClick?.(e);
468
- action.onSelect?.();
469
- },
470
- className: cn(
471
- "tollerud-action-row",
472
- highlighted && "tollerud-action-row--highlighted",
473
- (disabled ?? action.disabled) && "tollerud-action-row--disabled",
474
- className
475
- ),
476
- role: "option",
477
- "aria-selected": highlighted,
478
- "aria-disabled": disabled ?? action.disabled,
479
- ...props,
480
- children: [
481
- action.icon && /* @__PURE__ */ jsx("span", { className: "tollerud-action-row__icon", children: action.icon }),
482
- /* @__PURE__ */ jsxs("span", { className: "tollerud-action-row__content", children: [
483
- /* @__PURE__ */ jsx("span", { className: "tollerud-action-row__label", children: action.label }),
484
- action.description && /* @__PURE__ */ jsx("span", { className: "tollerud-action-row__description", children: action.description })
485
- ] }),
486
- showShortcut && action.shortcut && /* @__PURE__ */ jsx("span", { className: "tollerud-action-row__shortcut", children: /* @__PURE__ */ jsx(Kbd, { keys: action.shortcut, size: "sm" }) })
487
- ]
488
- }
489
- );
490
- }
491
- );
492
- ActionRow.displayName = "ActionRow";
493
- var CommandMenu = forwardRef(
494
- ({
495
- open,
496
- onOpenChange,
497
- groups,
498
- placeholder = "Type a command\u2026",
499
- emptyMessage = "No matching commands",
500
- className,
501
- filter: customFilter,
502
- onAction
503
- }, ref) => {
504
- const [query, setQuery] = useState("");
505
- const [selectedIndex, setSelectedIndex] = useState(0);
506
- const inputRef = useRef(null);
507
- const listRef = useRef(null);
508
- const flatItems = groups.flatMap((g) => g.items);
509
- const handleKeyDown = useCallback(
510
- (e) => {
511
- if (e.key === "Escape") {
512
- e.preventDefault();
513
- onOpenChange(false);
514
- return;
515
- }
516
- if (e.key === "ArrowDown") {
517
- e.preventDefault();
518
- setSelectedIndex(
519
- (prev) => prev < flatItems.length - 1 ? prev + 1 : 0
520
- );
521
- return;
522
- }
523
- if (e.key === "ArrowUp") {
524
- e.preventDefault();
525
- setSelectedIndex(
526
- (prev) => prev > 0 ? prev - 1 : flatItems.length - 1
527
- );
528
- return;
529
- }
530
- if (e.key === "Enter") {
531
- e.preventDefault();
532
- const item = flatItems[selectedIndex];
533
- if (item && !item.disabled) {
534
- item.onSelect?.();
535
- onAction?.(item);
536
- onOpenChange(false);
537
- }
538
- return;
539
- }
540
- },
541
- [flatItems, selectedIndex, onOpenChange, onAction]
542
- );
543
- useEffect(() => {
544
- function handleGlobalKey(e) {
545
- if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
546
- e.preventDefault();
547
- onOpenChange(!open);
548
- }
549
- }
550
- document.addEventListener("keydown", handleGlobalKey);
551
- return () => document.removeEventListener("keydown", handleGlobalKey);
552
- }, [open, onOpenChange]);
553
- useEffect(() => {
554
- if (open) {
555
- setQuery("");
556
- setSelectedIndex(0);
557
- const timer = setTimeout(() => inputRef.current?.focus(), 50);
558
- return () => clearTimeout(timer);
559
- }
560
- }, [open]);
561
- useEffect(() => {
562
- if (open) {
563
- document.body.style.overflow = "hidden";
564
- } else {
565
- document.body.style.overflow = "";
566
- }
567
- return () => {
568
- document.body.style.overflow = "";
569
- };
570
- }, [open]);
571
- const filteredGroups = customFilter ? customFilter(query, groups) : query.trim() ? groups.map((g) => ({
572
- ...g,
573
- items: g.items.filter(
574
- (item) => item.label.toLowerCase().includes(query.toLowerCase()) || item.description?.toLowerCase().includes(query.toLowerCase()) || item.group?.toLowerCase().includes(query.toLowerCase())
575
- )
576
- })).filter((g) => g.items.length > 0) : groups;
577
- const currentFlat = filteredGroups.flatMap((g) => g.items);
578
- useEffect(() => {
579
- if (selectedIndex >= currentFlat.length) {
580
- setSelectedIndex(0);
581
- }
582
- }, [currentFlat.length, selectedIndex]);
583
- if (!open) return null;
584
- return /* @__PURE__ */ jsxs(Fragment, { children: [
585
- /* @__PURE__ */ jsx(
586
- "div",
587
- {
588
- className: "tollerud-cmd-overlay",
589
- onClick: () => onOpenChange(false),
590
- "aria-hidden": "true"
591
- }
592
- ),
593
- /* @__PURE__ */ jsxs(
594
- "div",
595
- {
596
- className: cn("tollerud-cmd", className),
597
- role: "listbox",
598
- "aria-label": "Command palette",
599
- onKeyDown: handleKeyDown,
600
- children: [
601
- /* @__PURE__ */ jsxs("div", { className: "tollerud-cmd__header", children: [
602
- /* @__PURE__ */ jsx("span", { className: "tollerud-cmd__search-icon", children: /* @__PURE__ */ jsxs(
603
- "svg",
604
- {
605
- width: "18",
606
- height: "18",
607
- viewBox: "0 0 24 24",
608
- fill: "none",
609
- stroke: "currentColor",
610
- strokeWidth: "2",
611
- strokeLinecap: "round",
612
- strokeLinejoin: "round",
613
- children: [
614
- /* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "8" }),
615
- /* @__PURE__ */ jsx("path", { d: "m21 21-4.35-4.35" })
616
- ]
617
- }
618
- ) }),
619
- /* @__PURE__ */ jsx(
620
- "input",
621
- {
622
- ref: inputRef,
623
- type: "text",
624
- className: "tollerud-cmd__input",
625
- placeholder,
626
- value: query,
627
- onChange: (e) => {
628
- setQuery(e.target.value);
629
- setSelectedIndex(0);
630
- },
631
- autoComplete: "off",
632
- spellCheck: false
633
- }
634
- )
635
- ] }),
636
- /* @__PURE__ */ jsxs("div", { ref: listRef, className: "tollerud-cmd__list", children: [
637
- filteredGroups.length === 0 && /* @__PURE__ */ jsx("div", { className: "tollerud-cmd__empty", children: emptyMessage }),
638
- filteredGroups.map((group, gi) => {
639
- const flatOffset = filteredGroups.slice(0, gi).reduce((acc, g) => acc + g.items.length, 0);
640
- return /* @__PURE__ */ jsxs("div", { className: "tollerud-cmd__group", children: [
641
- /* @__PURE__ */ jsx("div", { className: "tollerud-cmd__group-label", children: group.label }),
642
- group.items.map((item, ii) => {
643
- const flatIndex = flatOffset + ii;
644
- return /* @__PURE__ */ jsx(
645
- ActionRow,
646
- {
647
- action: item,
648
- highlighted: selectedIndex === flatIndex,
649
- onClick: () => {
650
- item.onSelect?.();
651
- onAction?.(item);
652
- onOpenChange(false);
653
- },
654
- onMouseEnter: () => setSelectedIndex(flatIndex)
655
- },
656
- item.id
657
- );
658
- })
659
- ] }, group.label);
660
- })
661
- ] }),
662
- /* @__PURE__ */ jsxs("div", { className: "tollerud-cmd__footer", children: [
663
- /* @__PURE__ */ jsxs("span", { className: "tollerud-cmd__hint", children: [
664
- /* @__PURE__ */ jsx("span", { className: "tollerud-kbd tollerud-kbd--sm", children: /* @__PURE__ */ jsx("span", { className: "tollerud-kbd__key", children: "\u2191" }) }),
665
- /* @__PURE__ */ jsx("span", { className: "tollerud-kbd tollerud-kbd--sm", children: /* @__PURE__ */ jsx("span", { className: "tollerud-kbd__key", children: "\u2193" }) }),
666
- /* @__PURE__ */ jsx("span", { className: "tollerud-cmd__hint-text", children: "navigate" })
667
- ] }),
668
- /* @__PURE__ */ jsxs("span", { className: "tollerud-cmd__hint", children: [
669
- /* @__PURE__ */ jsx("span", { className: "tollerud-kbd tollerud-kbd--sm", children: /* @__PURE__ */ jsx("span", { className: "tollerud-kbd__key", children: "\u21B5" }) }),
670
- /* @__PURE__ */ jsx("span", { className: "tollerud-cmd__hint-text", children: "select" })
671
- ] }),
672
- /* @__PURE__ */ jsxs("span", { className: "tollerud-cmd__hint", children: [
673
- /* @__PURE__ */ jsx("span", { className: "tollerud-kbd tollerud-kbd--sm", children: /* @__PURE__ */ jsx("span", { className: "tollerud-kbd__key", children: "Esc" }) }),
674
- /* @__PURE__ */ jsx("span", { className: "tollerud-cmd__hint-text", children: "close" })
675
- ] })
676
- ] })
677
- ]
678
- }
679
- )
680
- ] });
681
- }
682
- );
683
- CommandMenu.displayName = "CommandMenu";
684
- var ServiceHealthCard = forwardRef(
685
- ({ className, service, status = "online", uptime, responseTime, version, loading, ...props }, ref) => {
686
- return /* @__PURE__ */ jsxs(
687
- "div",
688
- {
689
- ref,
690
- className: cn(
691
- "rounded-lg border bg-tollerud-surface-raised p-4",
692
- "transition-[border-color] duration-[150ms]",
693
- status === "offline" && "border-tollerud-error/40",
694
- status === "warning" && "border-tollerud-yellow/30",
695
- status === "online" && "border-tollerud-border hover:border-tollerud-noir-500",
696
- status === "idle" && "border-tollerud-border opacity-60",
697
- loading && "animate-pulse",
698
- className
699
- ),
700
- ...props,
701
- children: [
702
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
703
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-tollerud-foreground truncate", children: service }),
704
- /* @__PURE__ */ jsx(StatusDot, { status })
705
- ] }),
706
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-x-4 gap-y-1 text-xs text-tollerud-text-muted", children: [
707
- uptime && /* @__PURE__ */ jsxs("span", { children: [
708
- "Uptime: ",
709
- /* @__PURE__ */ jsx("span", { className: "text-tollerud-text-secondary", children: uptime })
710
- ] }),
711
- responseTime && /* @__PURE__ */ jsxs("span", { children: [
712
- "Response: ",
713
- /* @__PURE__ */ jsx("span", { className: "text-tollerud-text-secondary", children: responseTime })
714
- ] }),
715
- version && /* @__PURE__ */ jsxs("span", { children: [
716
- "Version: ",
717
- /* @__PURE__ */ jsx("span", { className: "text-tollerud-text-secondary", children: version })
718
- ] })
719
- ] })
720
- ]
721
- }
722
- );
723
- }
724
- );
725
- ServiceHealthCard.displayName = "ServiceHealthCard";
726
- var HostCard = forwardRef(
727
- ({ className, hostname, ip, status = "online", cpu, memory, disk, uptime, containers, loading, ...props }, ref) => {
728
- return /* @__PURE__ */ jsxs(
729
- "div",
730
- {
731
- ref,
732
- className: cn(
733
- "rounded-lg border bg-tollerud-surface-raised p-4",
734
- "transition-[border-color] duration-[150ms]",
735
- status === "offline" && "border-tollerud-error/40",
736
- status === "warning" && "border-tollerud-yellow/30",
737
- status === "online" && "border-tollerud-border hover:border-tollerud-noir-500",
738
- loading && "animate-pulse",
739
- className
740
- ),
741
- ...props,
742
- children: [
743
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
744
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
745
- /* @__PURE__ */ jsx(StatusDot, { status }),
746
- /* @__PURE__ */ jsx("span", { className: "font-semibold text-sm text-tollerud-foreground truncate", children: hostname })
747
- ] }),
748
- containers !== void 0 && /* @__PURE__ */ jsxs("span", { className: "text-[11px] text-tollerud-text-muted whitespace-nowrap ml-2", children: [
749
- containers,
750
- " container",
751
- containers !== 1 ? "s" : ""
752
- ] })
753
- ] }),
754
- ip && /* @__PURE__ */ jsx("div", { className: "text-xs text-tollerud-text-muted mb-2 font-mono", children: ip }),
755
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-x-4 gap-y-1 text-xs text-tollerud-text-muted", children: [
756
- cpu && /* @__PURE__ */ jsxs("span", { children: [
757
- "CPU: ",
758
- /* @__PURE__ */ jsx("span", { className: "text-tollerud-text-secondary", children: cpu })
759
- ] }),
760
- memory && /* @__PURE__ */ jsxs("span", { children: [
761
- "RAM: ",
762
- /* @__PURE__ */ jsx("span", { className: "text-tollerud-text-secondary", children: memory })
763
- ] }),
764
- disk && /* @__PURE__ */ jsxs("span", { children: [
765
- "Disk: ",
766
- /* @__PURE__ */ jsx("span", { className: "text-tollerud-text-secondary", children: disk })
767
- ] }),
768
- uptime && /* @__PURE__ */ jsxs("span", { children: [
769
- "Up: ",
770
- /* @__PURE__ */ jsx("span", { className: "text-tollerud-text-secondary", children: uptime })
771
- ] })
772
- ] })
773
- ]
774
- }
775
- );
776
- }
777
- );
778
- HostCard.displayName = "HostCard";
779
- var DockerStackCard = forwardRef(
780
- ({ className, name, services, composePath, loading, ...props }, ref) => {
781
- const onlineCount = services.filter((s) => s.status === "online").length;
782
- const degraded = services.some((s) => s.status === "offline" || s.status === "warning");
783
- const status = services.every((s) => s.status === "online") ? "online" : degraded ? "warning" : "offline";
784
- return /* @__PURE__ */ jsxs(
785
- "div",
786
- {
787
- ref,
788
- className: cn(
789
- "rounded-lg border bg-tollerud-surface-raised p-4",
790
- "transition-[border-color] duration-[150ms]",
791
- status === "offline" && "border-tollerud-error/40",
792
- status === "warning" && "border-tollerud-yellow/30",
793
- status === "online" && "border-tollerud-border hover:border-tollerud-noir-500",
794
- loading && "animate-pulse",
795
- className
796
- ),
797
- ...props,
798
- children: [
799
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
800
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
801
- /* @__PURE__ */ jsx(StatusDot, { status }),
802
- /* @__PURE__ */ jsx("span", { className: "font-semibold text-sm text-tollerud-foreground truncate", children: name })
803
- ] }),
804
- /* @__PURE__ */ jsxs("span", { className: "text-xs text-tollerud-text-muted whitespace-nowrap ml-2", children: [
805
- onlineCount,
806
- "/",
807
- services.length,
808
- " healthy"
809
- ] })
810
- ] }),
811
- composePath && /* @__PURE__ */ jsx("div", { className: "text-[11px] text-tollerud-text-muted font-mono mb-2 truncate", children: composePath }),
812
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children: services.map((svc) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
813
- /* @__PURE__ */ jsx("span", { className: "text-tollerud-text-secondary truncate", children: svc.name }),
814
- /* @__PURE__ */ jsx(StatusDot, { status: svc.status })
815
- ] }, svc.name)) })
816
- ]
817
- }
818
- );
819
- }
820
- );
821
- DockerStackCard.displayName = "DockerStackCard";
822
- var severityStyles = {
823
- critical: { border: "border-tollerud-error/50", dot: "bg-tollerud-error shadow-[0_0_8px_rgba(239,68,68,0.6)]", label: "text-tollerud-error" },
824
- high: { border: "border-tollerud-yellow/50", dot: "bg-tollerud-yellow shadow-[0_0_8px_rgba(232,213,0,0.5)]", label: "text-tollerud-yellow" },
825
- medium: { border: "border-tollerud-amber/40", dot: "bg-tollerud-amber", label: "text-tollerud-amber" },
826
- low: { border: "border-tollerud-noir-500", dot: "bg-tollerud-noir-400", label: "text-tollerud-text-muted" },
827
- info: { border: "border-tollerud-info/30", dot: "bg-tollerud-info", label: "text-tollerud-info" }
828
- };
829
- var IncidentCard = forwardRef(
830
- ({ className, title, severity, timestamp, description, service, acknowledged, loading, ...props }, ref) => {
831
- const style = severityStyles[severity];
832
- return /* @__PURE__ */ jsx(
833
- "div",
834
- {
835
- ref,
836
- className: cn(
837
- "rounded-lg border bg-tollerud-surface-raised p-4",
838
- "transition-[border-color] duration-[150ms]",
839
- style.border,
840
- acknowledged && "opacity-50",
841
- loading && "animate-pulse",
842
- className
843
- ),
844
- ...props,
845
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
846
- /* @__PURE__ */ jsx("span", { className: cn("w-2 h-2 rounded-full mt-1.5 flex-shrink-0", style.dot) }),
847
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
848
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
849
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-tollerud-foreground truncate", children: title }),
850
- /* @__PURE__ */ jsx("span", { className: cn("text-[11px] font-medium uppercase whitespace-nowrap", style.label), children: severity })
851
- ] }),
852
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-0.5 text-xs text-tollerud-text-muted", children: [
853
- /* @__PURE__ */ jsx("span", { children: timestamp }),
854
- service && /* @__PURE__ */ jsxs(Fragment, { children: [
855
- /* @__PURE__ */ jsx("span", { className: "text-tollerud-noir-500", children: "\xB7" }),
856
- /* @__PURE__ */ jsx("span", { children: service })
857
- ] })
858
- ] }),
859
- description && /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-xs text-tollerud-text-secondary leading-relaxed", children: description })
860
- ] })
861
- ] })
862
- }
863
- );
864
- }
865
- );
866
- IncidentCard.displayName = "IncidentCard";
867
- var stateStyles = {
868
- pending: "border-tollerud-yellow/30 hover:border-tollerud-yellow/50",
869
- approved: "border-tollerud-success/40 opacity-70",
870
- rejected: "border-tollerud-error/40 opacity-70"
871
- };
872
- var stateLabels = {
873
- pending: { text: "Awaiting approval", cls: "text-tollerud-yellow" },
874
- approved: { text: "Approved", cls: "text-tollerud-success" },
875
- rejected: { text: "Rejected", cls: "text-tollerud-error" }
876
- };
877
- var ApprovalCard = forwardRef(
878
- ({ className, action, description, source, state = "pending", timestamp, onApprove, onReject, disabled, loading, ...props }, ref) => {
879
- const label = stateLabels[state];
880
- return /* @__PURE__ */ jsxs(
881
- "div",
882
- {
883
- ref,
884
- className: cn(
885
- "rounded-lg border bg-tollerud-surface-raised p-4",
886
- "transition-all duration-[150ms]",
887
- stateStyles[state],
888
- loading && "animate-pulse",
889
- className
890
- ),
891
- ...props,
892
- children: [
893
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1.5", children: [
894
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-tollerud-foreground truncate", children: action }),
895
- /* @__PURE__ */ jsx("span", { className: cn("text-[11px] font-medium whitespace-nowrap ml-2", label.cls), children: label.text })
896
- ] }),
897
- description && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-text-secondary mb-1.5 leading-relaxed", children: description }),
898
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-x-4 gap-y-0.5 text-[11px] text-tollerud-text-muted mb-3", children: [
899
- source && /* @__PURE__ */ jsx("span", { className: "font-mono", children: source }),
900
- timestamp && /* @__PURE__ */ jsx("span", { children: timestamp })
901
- ] }),
902
- state === "pending" && /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
903
- /* @__PURE__ */ jsx(
904
- "button",
905
- {
906
- type: "button",
907
- disabled,
908
- onClick: onApprove,
909
- className: cn(
910
- "flex-1 rounded-md px-3 py-1.5 text-xs font-semibold transition-all",
911
- "bg-tollerud-success text-tollerud-text-inverse",
912
- "hover:brightness-110 disabled:opacity-40 disabled:cursor-not-allowed"
913
- ),
914
- children: "Approve"
915
- }
916
- ),
917
- /* @__PURE__ */ jsx(
918
- "button",
919
- {
920
- type: "button",
921
- disabled,
922
- onClick: onReject,
923
- className: cn(
924
- "flex-1 rounded-md px-3 py-1.5 text-xs font-semibold transition-all",
925
- "bg-tollerud-error text-white",
926
- "hover:brightness-110 disabled:opacity-40 disabled:cursor-not-allowed"
927
- ),
928
- children: "Reject"
929
- }
930
- )
931
- ] })
932
- ]
933
- }
934
- );
935
- }
936
- );
937
- ApprovalCard.displayName = "ApprovalCard";
938
- var BackupStatusPanel = forwardRef(
939
- ({ className, jobs, totalSize, lastFullBackup, loading, ...props }, ref) => {
940
- const failed = jobs.filter((j) => j.status === "offline").length;
941
- return /* @__PURE__ */ jsxs(
942
- "div",
943
- {
944
- ref,
945
- className: cn(
946
- "rounded-lg border border-tollerud-border bg-tollerud-surface-raised",
947
- loading && "animate-pulse",
948
- className
949
- ),
950
- ...props,
951
- children: [
952
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-tollerud-border", children: [
953
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-tollerud-foreground", children: "Backups" }),
954
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-[11px] text-tollerud-text-muted", children: [
955
- totalSize && /* @__PURE__ */ jsx("span", { children: totalSize }),
956
- lastFullBackup && /* @__PURE__ */ jsxs("span", { children: [
957
- "Last full: ",
958
- lastFullBackup
959
- ] })
960
- ] })
961
- ] }),
962
- /* @__PURE__ */ jsxs("div", { className: "p-1", children: [
963
- jobs.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-3 py-6 text-xs text-center text-tollerud-text-muted", children: "No backup jobs configured" }),
964
- jobs.map((job) => /* @__PURE__ */ jsxs(
965
- "div",
966
- {
967
- className: "flex items-center justify-between px-3 py-2 rounded-md hover:bg-tollerud-noir-800/50 transition-colors",
968
- children: [
969
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [
970
- /* @__PURE__ */ jsx(StatusDot, { status: job.status }),
971
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-tollerud-foreground truncate", children: job.name })
972
- ] }),
973
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-[11px] text-tollerud-text-muted flex-shrink-0 ml-2", children: [
974
- job.size && /* @__PURE__ */ jsx("span", { children: job.size }),
975
- job.target && /* @__PURE__ */ jsx("span", { className: "hidden sm:inline font-mono", children: job.target })
976
- ] })
977
- ]
978
- },
979
- job.name
980
- ))
981
- ] }),
982
- failed > 0 && /* @__PURE__ */ jsx("div", { className: "px-4 py-2 border-t border-tollerud-border", children: /* @__PURE__ */ jsxs("span", { className: "text-[11px] text-tollerud-error", children: [
983
- failed,
984
- " job",
985
- failed !== 1 ? "s" : "",
986
- " failed \u2014 check logs"
987
- ] }) })
988
- ]
989
- }
990
- );
991
- }
992
- );
993
- BackupStatusPanel.displayName = "BackupStatusPanel";
994
- var Timeline = forwardRef(
995
- ({ className, items, active, loading, ...props }, ref) => {
996
- return /* @__PURE__ */ jsx(
997
- "div",
998
- {
999
- ref,
1000
- className: cn("tollerud-timeline", loading && "animate-pulse", className),
1001
- role: "list",
1002
- "aria-label": "Activity timeline",
1003
- ...props,
1004
- children: items.map((item, i) => {
1005
- const isLast = i === items.length - 1;
1006
- return /* @__PURE__ */ jsxs("div", { className: "tollerud-timeline__item", role: "listitem", children: [
1007
- /* @__PURE__ */ jsx("div", { className: "tollerud-timeline__marker", children: /* @__PURE__ */ jsxs("div", { className: "tollerud-timeline__dot-group", children: [
1008
- item.icon ? /* @__PURE__ */ jsx("span", { className: "tollerud-timeline__icon", children: item.icon }) : /* @__PURE__ */ jsx(
1009
- "span",
1010
- {
1011
- className: cn(
1012
- "tollerud-timeline__dot",
1013
- active && "tollerud-timeline__dot--active",
1014
- item.status === "online" && "bg-tollerud-success shadow-[0_0_6px_rgba(34,197,94,0.5)]",
1015
- item.status === "offline" && "bg-tollerud-error",
1016
- item.status === "warning" && "bg-tollerud-yellow shadow-[0_0_6px_rgba(232,213,0,0.5)]",
1017
- !item.status && "bg-tollerud-noir-500"
1018
- )
1019
- }
1020
- ),
1021
- !isLast && /* @__PURE__ */ jsx("div", { className: "tollerud-timeline__line" })
1022
- ] }) }),
1023
- /* @__PURE__ */ jsxs("div", { className: "tollerud-timeline__content", children: [
1024
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
1025
- /* @__PURE__ */ jsx("span", { className: "tollerud-timeline__title", children: item.title }),
1026
- /* @__PURE__ */ jsx("span", { className: "tollerud-timeline__time", children: item.time })
1027
- ] }),
1028
- item.description && /* @__PURE__ */ jsx("p", { className: "tollerud-timeline__description", children: item.description }),
1029
- item.meta && item.meta.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5 mt-1", children: item.meta.map((m) => /* @__PURE__ */ jsx("span", { className: "tollerud-timeline__meta", children: m }, m)) })
1030
- ] })
1031
- ] }, item.id);
1032
- })
1033
- }
1034
- );
1035
- }
1036
- );
1037
- Timeline.displayName = "Timeline";
1038
- var AlertInbox = forwardRef(
1039
- ({ className, alerts, filterSeverity = "", onAcknowledge, loading, emptyMessage = "All clear \u2014 no incidents", ...props }, ref) => {
1040
- const filtered = filterSeverity ? alerts.filter((a) => a.severity === filterSeverity) : alerts;
1041
- const counts = {
1042
- total: alerts.length,
1043
- unacknowledged: alerts.filter((a) => !a.acknowledged).length,
1044
- critical: alerts.filter((a) => a.severity === "critical" && !a.acknowledged).length
1045
- };
1046
- return /* @__PURE__ */ jsxs(
1047
- "div",
1048
- {
1049
- ref,
1050
- className: cn(
1051
- "rounded-lg border border-tollerud-border bg-tollerud-surface-raised overflow-hidden",
1052
- loading && "animate-pulse",
1053
- className
1054
- ),
1055
- ...props,
1056
- children: [
1057
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-tollerud-border", children: [
1058
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1059
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-tollerud-foreground", children: "Alerts" }),
1060
- counts.unacknowledged > 0 && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-[11px] text-tollerud-error font-medium", children: [
1061
- /* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-tollerud-error animate-pulse" }),
1062
- counts.unacknowledged,
1063
- " unread"
1064
- ] }),
1065
- counts.critical > 0 && /* @__PURE__ */ jsxs("span", { className: "text-[11px] text-tollerud-error font-bold", children: [
1066
- counts.critical,
1067
- " critical"
1068
- ] })
1069
- ] }),
1070
- /* @__PURE__ */ jsxs("span", { className: "text-xs text-tollerud-text-muted", children: [
1071
- filtered.length,
1072
- " of ",
1073
- alerts.length
1074
- ] })
1075
- ] }),
1076
- /* @__PURE__ */ jsxs("div", { className: "divide-y divide-tollerud-border/50 max-h-[480px] overflow-y-auto", children: [
1077
- filtered.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-4 py-8 text-xs text-center text-tollerud-text-muted", children: emptyMessage }),
1078
- filtered.map((alert) => /* @__PURE__ */ jsxs("div", { className: "relative group", children: [
1079
- /* @__PURE__ */ jsx(
1080
- IncidentCard,
1081
- {
1082
- title: alert.title,
1083
- severity: alert.severity,
1084
- timestamp: alert.timestamp,
1085
- description: alert.description,
1086
- service: alert.service,
1087
- acknowledged: alert.acknowledged,
1088
- className: "border-0 rounded-none bg-transparent hover:bg-tollerud-noir-800/30"
1089
- }
1090
- ),
1091
- alert.acknowledged && /* @__PURE__ */ jsx("span", { className: "absolute bottom-2 right-3 text-[10px] font-medium text-tollerud-text-muted/50", children: "Acknowledged" }),
1092
- !alert.acknowledged && onAcknowledge && /* @__PURE__ */ jsx(
1093
- "button",
1094
- {
1095
- type: "button",
1096
- onClick: () => onAcknowledge(alert.id),
1097
- className: cn(
1098
- "absolute bottom-2 right-3 text-[10px] font-medium px-2 py-0.5 rounded",
1099
- "text-tollerud-yellow/70 hover:text-tollerud-yellow hover:bg-tollerud-yellow/10",
1100
- "opacity-0 group-hover:opacity-100 transition-opacity duration-150"
1101
- ),
1102
- children: "Acknowledge"
1103
- }
1104
- )
1105
- ] }, alert.id))
1106
- ] })
1107
- ]
1108
- }
1109
- );
1110
- }
1111
- );
1112
- AlertInbox.displayName = "AlertInbox";
1113
- var stepIcon = {
1114
- pending: "\u25CB",
1115
- running: "\u25C9",
1116
- success: "\u25CF",
1117
- failed: "\u2715",
1118
- skipped: "\u2014"
1119
- };
1120
- var stepStyles = {
1121
- pending: "text-tollerud-noir-400",
1122
- running: "text-tollerud-yellow animate-pulse",
1123
- success: "text-tollerud-success",
1124
- failed: "text-tollerud-error",
1125
- skipped: "text-tollerud-noir-500"
1126
- };
1127
- var RollbackPlan = forwardRef(
1128
- ({ className, name, steps, executing, loading, ...props }, ref) => {
1129
- const statusSummary = {
1130
- pending: steps.filter((s) => s.status === "pending").length,
1131
- running: steps.filter((s) => s.status === "running").length,
1132
- success: steps.filter((s) => s.status === "success").length,
1133
- failed: steps.filter((s) => s.status === "failed").length,
1134
- skipped: steps.filter((s) => s.status === "skipped").length
1135
- };
1136
- return /* @__PURE__ */ jsxs(
1137
- "div",
1138
- {
1139
- ref,
1140
- className: cn(
1141
- "rounded-lg border border-tollerud-border bg-tollerud-surface-raised",
1142
- loading && "animate-pulse",
1143
- className
1144
- ),
1145
- ...props,
1146
- children: [
1147
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-tollerud-border", children: [
1148
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1149
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-tollerud-foreground", children: name }),
1150
- executing && /* @__PURE__ */ jsx("span", { className: "text-[11px] text-tollerud-yellow font-medium animate-pulse", children: "Executing\u2026" })
1151
- ] }),
1152
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-[11px] text-tollerud-text-muted", children: [
1153
- statusSummary.success > 0 && /* @__PURE__ */ jsxs("span", { className: "text-tollerud-success", children: [
1154
- statusSummary.success,
1155
- " done"
1156
- ] }),
1157
- statusSummary.failed > 0 && /* @__PURE__ */ jsxs("span", { className: "text-tollerud-error", children: [
1158
- statusSummary.failed,
1159
- " failed"
1160
- ] }),
1161
- statusSummary.running > 0 && /* @__PURE__ */ jsxs("span", { className: "text-tollerud-yellow", children: [
1162
- statusSummary.running,
1163
- " running"
1164
- ] })
1165
- ] })
1166
- ] }),
1167
- /* @__PURE__ */ jsx("div", { className: "p-1", children: steps.map((step) => /* @__PURE__ */ jsxs(
1168
- "div",
1169
- {
1170
- className: cn(
1171
- "flex items-start gap-3 px-3 py-2 rounded-md",
1172
- "transition-colors duration-[150ms]",
1173
- step.status === "failed" && "bg-tollerud-error/5",
1174
- step.status === "running" && "bg-tollerud-yellow/5"
1175
- ),
1176
- children: [
1177
- /* @__PURE__ */ jsx("span", { className: cn("font-mono text-sm mt-0.5 flex-shrink-0", stepStyles[step.status]), children: stepIcon[step.status] }),
1178
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
1179
- /* @__PURE__ */ jsx("span", { className: cn(
1180
- "text-xs font-medium",
1181
- step.status === "success" ? "text-tollerud-success" : step.status === "failed" ? "text-tollerud-error" : step.status === "skipped" ? "text-tollerud-noir-500" : "text-tollerud-foreground"
1182
- ), children: step.label }),
1183
- step.description && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-tollerud-text-muted mt-0.5", children: step.description })
1184
- ] }),
1185
- /* @__PURE__ */ jsx("span", { className: cn(
1186
- "text-[10px] uppercase font-semibold flex-shrink-0",
1187
- stepStyles[step.status]
1188
- ), children: step.status })
1189
- ]
1190
- },
1191
- step.id
1192
- )) })
1193
- ]
1194
- }
1195
- );
1196
- }
1197
- );
1198
- RollbackPlan.displayName = "RollbackPlan";
1199
- var diffStyles = {
1200
- add: "bg-tollerud-success/[0.06] text-tollerud-success hover:bg-tollerud-success/[0.10]",
1201
- remove: "bg-tollerud-error/[0.06] text-tollerud-error hover:bg-tollerud-error/[0.10]",
1202
- context: "text-tollerud-noir-300"
1203
- };
1204
- var diffPrefix = {
1205
- add: "+",
1206
- remove: "-",
1207
- context: " "
1208
- };
1209
- var ActionDiff = forwardRef(
1210
- ({ className, lines, label, view = "unified", loading, ...props }, ref) => {
1211
- const [showContext, setShowContext] = useState(true);
1212
- const stats = useMemo(() => {
1213
- const adds = lines.filter((l) => l.type === "add").length;
1214
- const rems = lines.filter((l) => l.type === "remove").length;
1215
- return { adds, rems };
1216
- }, [lines]);
1217
- const displayLines = showContext ? lines : lines.filter((l) => l.type !== "context");
1218
- const hasContext = lines.some((l) => l.type === "context");
1219
- return /* @__PURE__ */ jsxs(
1220
- "div",
1221
- {
1222
- ref,
1223
- className: cn(
1224
- "rounded-lg border border-tollerud-border bg-[var(--color-tollerud-surface-raised)] overflow-hidden",
1225
- loading && "animate-pulse",
1226
- className
1227
- ),
1228
- ...props,
1229
- children: [
1230
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2.5 border-b border-tollerud-border bg-tollerud-noir-900", children: [
1231
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 min-w-0", children: label && /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-tollerud-foreground font-mono truncate", children: label }) }),
1232
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-[11px]", children: [
1233
- /* @__PURE__ */ jsxs("span", { className: "text-tollerud-success", children: [
1234
- "+",
1235
- stats.adds
1236
- ] }),
1237
- /* @__PURE__ */ jsxs("span", { className: "text-tollerud-error", children: [
1238
- "-",
1239
- stats.rems
1240
- ] }),
1241
- hasContext && /* @__PURE__ */ jsx(
1242
- "button",
1243
- {
1244
- type: "button",
1245
- onClick: () => setShowContext(!showContext),
1246
- className: "text-tollerud-text-muted hover:text-tollerud-foreground transition-colors",
1247
- children: showContext ? "Hide context" : "Show context"
1248
- }
1249
- )
1250
- ] })
1251
- ] }),
1252
- /* @__PURE__ */ jsx("div", { className: "overflow-x-auto font-mono text-xs leading-relaxed", children: /* @__PURE__ */ jsx("table", { className: "w-full border-collapse", children: /* @__PURE__ */ jsx("tbody", { children: displayLines.map((line, i) => /* @__PURE__ */ jsxs(
1253
- "tr",
1254
- {
1255
- className: cn(
1256
- "transition-colors duration-[100ms]",
1257
- diffStyles[line.type]
1258
- ),
1259
- children: [
1260
- /* @__PURE__ */ jsx("td", { className: cn(
1261
- "w-10 text-right px-2 py-px select-none",
1262
- "text-tollerud-noir-500 border-r border-tollerud-border/30",
1263
- "text-[10px] align-top"
1264
- ), children: line.oldLine ?? "" }),
1265
- /* @__PURE__ */ jsx("td", { className: cn(
1266
- "w-10 text-right px-2 py-px select-none",
1267
- "text-tollerud-noir-500 border-r border-tollerud-border/30",
1268
- "text-[10px] align-top"
1269
- ), children: line.newLine ?? "" }),
1270
- /* @__PURE__ */ jsxs("td", { className: "px-2 py-px whitespace-pre-wrap", children: [
1271
- /* @__PURE__ */ jsx("span", { className: "select-none opacity-50 mr-2", children: diffPrefix[line.type] }),
1272
- line.text
1273
- ] })
1274
- ]
1275
- },
1276
- i
1277
- )) }) }) })
1278
- ]
1279
- }
1280
- );
1281
- }
1282
- );
1283
- ActionDiff.displayName = "ActionDiff";
1284
- var levelStyles = {
1285
- debug: "text-tollerud-noir-400",
1286
- trace: "text-tollerud-noir-300",
1287
- info: "text-tollerud-foreground",
1288
- warn: "text-tollerud-amber",
1289
- error: "text-tollerud-error"
1290
- };
1291
- var levelLabels = {
1292
- debug: "DBG",
1293
- trace: "TRC",
1294
- info: "INF",
1295
- warn: "WRN",
1296
- error: "ERR"
1297
- };
1298
- var LogViewer = forwardRef(
1299
- ({ className, lines, maxLines = 5e3, showLineNumbers = true, showTimestamps = true, follow = true, searchable, height = "400px", loading, ...props }, ref) => {
1300
- const [search, setSearch] = useState("");
1301
- const [isFollowing, setIsFollowing] = useState(follow);
1302
- const scrollRef = useRef(null);
1303
- const displayedLines = useMemo(() => {
1304
- return lines.length > maxLines ? lines.slice(-maxLines) : lines;
1305
- }, [lines, maxLines]);
1306
- const filteredLines = useMemo(() => {
1307
- if (!search.trim()) return displayedLines;
1308
- return displayedLines.filter(
1309
- (l) => l.text.toLowerCase().includes(search.toLowerCase()) || l.source?.toLowerCase().includes(search.toLowerCase())
1310
- );
1311
- }, [displayedLines, search]);
1312
- useEffect(() => {
1313
- if (isFollowing && scrollRef.current) {
1314
- scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
1315
- }
1316
- }, [filteredLines.length, isFollowing]);
1317
- const handleScroll = (e) => {
1318
- const el = e.currentTarget;
1319
- const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 40;
1320
- setIsFollowing(atBottom);
1321
- };
1322
- const filteredFrom = displayedLines.indexOf(filteredLines[0]);
1323
- return /* @__PURE__ */ jsxs(
1324
- "div",
1325
- {
1326
- ref,
1327
- className: cn(
1328
- "rounded-lg border border-tollerud-border bg-[var(--color-tollerud-surface-raised)] overflow-hidden tollerud-log-viewer",
1329
- loading && "animate-pulse",
1330
- className
1331
- ),
1332
- ...props,
1333
- children: [
1334
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-2 border-b border-tollerud-border bg-tollerud-noir-900", children: [
1335
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-tollerud-text-muted", children: [
1336
- isFollowing ? /* @__PURE__ */ jsx("span", { className: "text-tollerud-yellow font-medium", children: "\u25CF Live" }) : /* @__PURE__ */ jsx("span", { className: "text-tollerud-noir-400", children: "\u25CF Paused" }),
1337
- /* @__PURE__ */ jsxs("span", { children: [
1338
- filteredLines.length,
1339
- " lines"
1340
- ] }),
1341
- lines.length > maxLines && /* @__PURE__ */ jsxs("span", { className: "text-tollerud-amber", children: [
1342
- "(showing last ",
1343
- maxLines,
1344
- ")"
1345
- ] })
1346
- ] }),
1347
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: searchable && /* @__PURE__ */ jsx(
1348
- "input",
1349
- {
1350
- type: "text",
1351
- value: search,
1352
- onChange: (e) => setSearch(e.target.value),
1353
- placeholder: "Search logs\u2026",
1354
- className: cn(
1355
- "w-40 text-[11px] px-2 py-1 rounded bg-tollerud-noir-800",
1356
- "border border-tollerud-noir-600 text-tollerud-foreground",
1357
- "placeholder:text-tollerud-noir-400 outline-none",
1358
- "focus:border-tollerud-yellow/50 transition-colors"
1359
- )
1360
- }
1361
- ) })
1362
- ] }),
1363
- /* @__PURE__ */ jsxs(
1364
- "div",
1365
- {
1366
- ref: scrollRef,
1367
- onScroll: handleScroll,
1368
- className: "overflow-y-auto font-mono text-xs leading-relaxed p-3",
1369
- style: { height },
1370
- children: [
1371
- filteredLines.length === 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full text-tollerud-noir-400 text-xs", children: search ? "No matching log lines" : "No log output" }),
1372
- filteredLines.map((line, i) => {
1373
- const absLineNum = filteredFrom >= 0 ? filteredFrom + i + 1 : i + 1;
1374
- const level = line.level ?? "info";
1375
- return /* @__PURE__ */ jsxs(
1376
- "div",
1377
- {
1378
- className: cn(
1379
- "flex gap-3 hover:bg-[var(--color-tollerud-surface-hover)] px-1 py-px rounded-sm",
1380
- levelStyles[level]
1381
- ),
1382
- children: [
1383
- showLineNumbers && /* @__PURE__ */ jsx("span", { className: "text-tollerud-noir-500 text-right select-none w-8 flex-shrink-0", children: absLineNum }),
1384
- showTimestamps && line.timestamp && /* @__PURE__ */ jsx("span", { className: "text-tollerud-noir-400 flex-shrink-0 select-none", children: line.timestamp }),
1385
- /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 w-7 text-center font-bold text-[10px] uppercase opacity-60", children: levelLabels[level] }),
1386
- /* @__PURE__ */ jsx("span", { className: "whitespace-pre-wrap break-all", children: line.text })
1387
- ]
1388
- },
1389
- `${absLineNum}-${i}`
1390
- );
1391
- })
1392
- ]
1393
- }
1394
- )
1395
- ]
1396
- }
1397
- );
1398
- }
1399
- );
1400
- LogViewer.displayName = "LogViewer";
1401
- var Textarea = forwardRef(
1402
- ({ className, label, error, id, ...props }, ref) => {
1403
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
1404
- label && /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-xs font-medium text-tollerud-text-muted", children: label }),
1405
- /* @__PURE__ */ jsx(
1406
- "textarea",
1407
- {
1408
- ref,
1409
- id,
1410
- className: cn(
1411
- "font-sans text-base px-3 py-2 rounded min-h-[80px] resize-y",
1412
- "bg-tollerud-surface-raised border",
1413
- "text-tollerud-text-primary",
1414
- "placeholder:text-tollerud-text-muted",
1415
- "transition-[border-color] duration-[150ms]",
1416
- "focus:outline-none focus:border-tollerud-yellow focus:shadow-[0_0_0_1px_#E8D500]",
1417
- error ? "border-tollerud-error" : "border-tollerud-border",
1418
- className
1419
- ),
1420
- ...props
1421
- }
1422
- ),
1423
- error && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-error mt-0.5", children: error })
1424
- ] });
1425
- }
1426
- );
1427
- Textarea.displayName = "Textarea";
1428
- var Select = forwardRef(
1429
- ({ className, label, error, placeholder, options = [], value, onChange, ...props }, ref) => {
1430
- const [open, setOpen] = useState(false);
1431
- const [highlightedIdx, setHighlightedIdx] = useState(0);
1432
- const containerRef = useRef(null);
1433
- const listRef = useRef(null);
1434
- const selectedOption = options.find((o) => o.value === value);
1435
- useEffect(() => {
1436
- if (!open) return;
1437
- const handleClick = (e) => {
1438
- if (containerRef.current && !containerRef.current.contains(e.target)) {
1439
- setOpen(false);
1440
- }
1441
- };
1442
- document.addEventListener("mousedown", handleClick);
1443
- return () => document.removeEventListener("mousedown", handleClick);
1444
- }, [open]);
1445
- useEffect(() => {
1446
- if (open) {
1447
- const idx = value ? options.findIndex((o) => o.value === value) : -1;
1448
- setHighlightedIdx(idx >= 0 ? idx : 0);
1449
- }
1450
- }, [open, options, value]);
1451
- useEffect(() => {
1452
- if (open && listRef.current) {
1453
- const item = listRef.current.children[highlightedIdx];
1454
- item?.scrollIntoView({ block: "nearest" });
1455
- }
1456
- }, [open, highlightedIdx]);
1457
- const selectOption = useCallback(
1458
- (opt) => {
1459
- onChange?.(opt.value);
1460
- setOpen(false);
1461
- },
1462
- [onChange]
1463
- );
1464
- const handleKeyDown = (e) => {
1465
- if (!open) {
1466
- if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
1467
- e.preventDefault();
1468
- setOpen(true);
1469
- }
1470
- return;
1471
- }
1472
- switch (e.key) {
1473
- case "Escape":
1474
- e.preventDefault();
1475
- setOpen(false);
1476
- break;
1477
- case "ArrowDown":
1478
- e.preventDefault();
1479
- setHighlightedIdx((prev) => Math.min(prev + 1, options.length - 1));
1480
- break;
1481
- case "ArrowUp":
1482
- e.preventDefault();
1483
- setHighlightedIdx((prev) => Math.max(prev - 1, 0));
1484
- break;
1485
- case "Enter":
1486
- e.preventDefault();
1487
- if (options[highlightedIdx]) {
1488
- selectOption(options[highlightedIdx]);
1489
- }
1490
- break;
1491
- }
1492
- };
1493
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", ref, children: [
1494
- label && /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-tollerud-text-muted", children: label }),
1495
- /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "relative", children: [
1496
- /* @__PURE__ */ jsxs(
1497
- "button",
1498
- {
1499
- type: "button",
1500
- onClick: () => setOpen(!open),
1501
- onKeyDown: handleKeyDown,
1502
- "aria-haspopup": "listbox",
1503
- "aria-expanded": open,
1504
- className: cn(
1505
- "font-sans text-sm w-full flex items-center justify-between px-3 py-2.5 rounded-lg",
1506
- "bg-tollerud-surface-raised",
1507
- "text-tollerud-text-primary text-left",
1508
- "transition-all duration-150 ease-out cursor-pointer",
1509
- error ? "border-tollerud-error/70 focus:border-tollerud-error focus:shadow-[0_0_0_1px_#EF4444]" : "border-tollerud-border focus:border-tollerud-yellow focus:shadow-[0_0_0_1px_#E8D500]",
1510
- "border hover:border-tollerud-noir-400",
1511
- "focus:outline-none",
1512
- className
1513
- ),
1514
- children: [
1515
- /* @__PURE__ */ jsx("span", { className: cn(!selectedOption && "text-tollerud-text-muted"), children: selectedOption ? selectedOption.label : placeholder || "Select\u2026" }),
1516
- /* @__PURE__ */ jsx(
1517
- "svg",
1518
- {
1519
- className: cn(
1520
- "h-4 w-4 text-tollerud-text-muted transition-transform duration-150 flex-shrink-0",
1521
- open && "rotate-180"
1522
- ),
1523
- fill: "none",
1524
- viewBox: "0 0 24 24",
1525
- stroke: "currentColor",
1526
- strokeWidth: 2,
1527
- "aria-hidden": "true",
1528
- children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 9l6 6 6-6" })
1529
- }
1530
- )
1531
- ]
1532
- }
1533
- ),
1534
- open && /* @__PURE__ */ jsxs(
1535
- "div",
1536
- {
1537
- ref: listRef,
1538
- role: "listbox",
1539
- className: cn(
1540
- "absolute z-10 left-0 right-0 mt-1 py-1",
1541
- "rounded-lg border border-tollerud-border bg-tollerud-surface-overlay",
1542
- "shadow-[0_8px_24px_rgba(0,0,0,0.4)]",
1543
- "max-h-60 overflow-y-auto"
1544
- ),
1545
- children: [
1546
- options.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-xs text-tollerud-text-muted text-center", children: "No options" }),
1547
- options.map((opt, idx) => /* @__PURE__ */ jsx(
1548
- "button",
1549
- {
1550
- type: "button",
1551
- role: "option",
1552
- "aria-selected": opt.value === value,
1553
- onClick: () => selectOption(opt),
1554
- onMouseEnter: () => setHighlightedIdx(idx),
1555
- className: cn(
1556
- "w-full text-sm text-left px-3 py-2 transition-colors duration-75",
1557
- "cursor-pointer",
1558
- opt.value === value ? "text-tollerud-yellow" : "text-tollerud-text-primary",
1559
- idx === highlightedIdx && !(opt.value === value) ? "bg-tollerud-noir-700" : "hover:bg-tollerud-noir-700/60",
1560
- opt.value === value && highlightedIdx === idx && "bg-tollerud-noir-700"
1561
- ),
1562
- children: opt.label
1563
- },
1564
- opt.value
1565
- ))
1566
- ]
1567
- }
1568
- )
1569
- ] }),
1570
- error && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-error mt-0.5", children: error })
1571
- ] });
1572
- }
1573
- );
1574
- Select.displayName = "Select";
1575
- var Checkbox = forwardRef(
1576
- ({ className, label, id: idProp, checked, ...props }, ref) => {
1577
- const autoId = useId();
1578
- const id = idProp ?? autoId;
1579
- return /* @__PURE__ */ jsxs(
1580
- "label",
1581
- {
1582
- htmlFor: id,
1583
- className: cn(
1584
- "inline-flex items-center gap-2 cursor-pointer select-none group",
1585
- "text-sm text-tollerud-text-primary",
1586
- props.disabled && "opacity-50 pointer-events-none",
1587
- className
1588
- ),
1589
- children: [
1590
- /* @__PURE__ */ jsxs("span", { className: "relative flex items-center justify-center", children: [
1591
- /* @__PURE__ */ jsx(
1592
- "input",
1593
- {
1594
- ref,
1595
- id,
1596
- type: "checkbox",
1597
- checked,
1598
- className: "peer sr-only",
1599
- ...props
1600
- }
1601
- ),
1602
- /* @__PURE__ */ jsx(
1603
- "span",
1604
- {
1605
- className: cn(
1606
- "h-4 w-4 rounded border transition-all duration-[150ms]",
1607
- "flex items-center justify-center",
1608
- "bg-tollerud-surface-raised border-tollerud-border",
1609
- "peer-focus-visible:outline-2 peer-focus-visible:outline-tollerud-yellow",
1610
- "peer-checked:bg-tollerud-yellow peer-checked:border-tollerud-yellow",
1611
- "group-hover:border-tollerud-text-secondary"
1612
- ),
1613
- children: /* @__PURE__ */ jsx(
1614
- "svg",
1615
- {
1616
- className: cn(
1617
- "h-3 w-3 text-tollerud-noir-black transition-opacity duration-[150ms]",
1618
- checked ? "opacity-100" : "opacity-0"
1619
- ),
1620
- viewBox: "0 0 12 12",
1621
- fill: "none",
1622
- "aria-hidden": "true",
1623
- children: /* @__PURE__ */ jsx(
1624
- "path",
1625
- {
1626
- d: "M2.5 6l2.5 2.5 4.5-5",
1627
- stroke: "currentColor",
1628
- strokeWidth: 2,
1629
- strokeLinecap: "round",
1630
- strokeLinejoin: "round"
1631
- }
1632
- )
1633
- }
1634
- )
1635
- }
1636
- )
1637
- ] }),
1638
- label && /* @__PURE__ */ jsx("span", { children: label })
1639
- ]
1640
- }
1641
- );
1642
- }
1643
- );
1644
- Checkbox.displayName = "Checkbox";
1645
- var Switch = forwardRef(
1646
- ({ className, label, id: idProp, checked, ...props }, ref) => {
1647
- const autoId = useId();
1648
- const id = idProp ?? autoId;
1649
- return /* @__PURE__ */ jsxs(
1650
- "label",
1651
- {
1652
- htmlFor: id,
1653
- className: cn(
1654
- "inline-flex items-center gap-2.5 cursor-pointer select-none group",
1655
- "text-sm text-tollerud-text-primary",
1656
- props.disabled && "opacity-40 pointer-events-none cursor-not-allowed",
1657
- className
1658
- ),
1659
- children: [
1660
- /* @__PURE__ */ jsxs(
1661
- "span",
1662
- {
1663
- className: cn(
1664
- "relative inline-flex items-center h-5 w-9 flex-shrink-0 rounded-full",
1665
- "transition-colors duration-200 ease-out",
1666
- checked ? "bg-tollerud-yellow" : "bg-tollerud-noir-600",
1667
- "group-hover:bg-tollerud-noir-500",
1668
- checked && "group-hover:bg-tollerud-yellow-warm",
1669
- "peer-focus-visible:outline-2 peer-focus-visible:outline-tollerud-yellow peer-focus-visible:outline-offset-2"
1670
- ),
1671
- children: [
1672
- /* @__PURE__ */ jsx(
1673
- "input",
1674
- {
1675
- ref,
1676
- id,
1677
- type: "checkbox",
1678
- role: "switch",
1679
- checked,
1680
- className: "peer absolute inset-0 opacity-0 w-full h-full cursor-pointer z-10",
1681
- ...props
1682
- }
1683
- ),
1684
- /* @__PURE__ */ jsx(
1685
- "span",
1686
- {
1687
- className: cn(
1688
- "block h-3.5 w-3.5 rounded-full shadow-sm",
1689
- "transition-all duration-200 ease-out",
1690
- checked ? "translate-x-[18px] bg-tollerud-black" : "translate-x-[3px] bg-tollerud-white"
1691
- )
1692
- }
1693
- )
1694
- ]
1695
- }
1696
- ),
1697
- label && /* @__PURE__ */ jsx("span", { children: label })
1698
- ]
1699
- }
1700
- );
1701
- }
1702
- );
1703
- Switch.displayName = "Switch";
1704
- var RadioGroup = forwardRef(
1705
- ({ label, error, children, className }, ref) => {
1706
- useId();
1707
- return /* @__PURE__ */ jsxs("fieldset", { ref, className: cn("flex flex-col gap-1", className), children: [
1708
- label && /* @__PURE__ */ jsx("legend", { className: "text-xs font-medium text-tollerud-text-muted mb-1", children: label }),
1709
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children }),
1710
- error && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-error mt-0.5", children: error })
1711
- ] });
1712
- }
1713
- );
1714
- RadioGroup.displayName = "RadioGroup";
1715
- var Radio = forwardRef(
1716
- ({ className, label, id: idProp, ...props }, ref) => {
1717
- const autoId = useId();
1718
- const id = idProp ?? autoId;
1719
- return /* @__PURE__ */ jsxs(
1720
- "label",
1721
- {
1722
- htmlFor: id,
1723
- className: cn(
1724
- "inline-flex items-center gap-2 cursor-pointer select-none group",
1725
- "text-sm text-tollerud-text-primary",
1726
- props.disabled && "opacity-50 pointer-events-none",
1727
- className
1728
- ),
1729
- children: [
1730
- /* @__PURE__ */ jsxs("span", { className: "relative flex items-center justify-center", children: [
1731
- /* @__PURE__ */ jsx(
1732
- "input",
1733
- {
1734
- ref,
1735
- id,
1736
- type: "radio",
1737
- className: "peer sr-only",
1738
- ...props
1739
- }
1740
- ),
1741
- /* @__PURE__ */ jsx(
1742
- "span",
1743
- {
1744
- className: cn(
1745
- "h-4 w-4 rounded-full border transition-all duration-[150ms]",
1746
- "bg-tollerud-surface-raised border-tollerud-border",
1747
- "peer-focus-visible:outline-2 peer-focus-visible:outline-tollerud-yellow",
1748
- "peer-checked:border-tollerud-yellow",
1749
- "group-hover:border-tollerud-text-secondary",
1750
- "flex items-center justify-center"
1751
- ),
1752
- children: /* @__PURE__ */ jsx(
1753
- "span",
1754
- {
1755
- className: cn(
1756
- "h-2 w-2 rounded-full bg-tollerud-yellow transition-opacity duration-[150ms]",
1757
- props.checked ? "opacity-100" : "opacity-0"
1758
- )
1759
- }
1760
- )
1761
- }
1762
- )
1763
- ] }),
1764
- label && /* @__PURE__ */ jsx("span", { children: label })
1765
- ]
1766
- }
1767
- );
1768
- }
1769
- );
1770
- Radio.displayName = "Radio";
1771
- var defaultLabels = {
1772
- tollerudProject: "A Tollerud Project",
1773
- allRightsReserved: "All rights reserved."
1774
- };
1775
- var MONOGRAM_PATH = "M82.4839273,140.272626 L95.1738252,140.272626 L95.1738252,143 L34.8114657,143 L34.8114657,140.272626 L47.5013636,140.272626 L47.5013636,28.2924381 C40.1277806,26.4177752 32.9252955,25.2241422 26.4088393,25.2241422 C12.1757856,25.2241422 4.11617359,34.5982703 4.11617359,39.8821508 C4.11617359,40.9049161 4.63028596,41.5867596 5.65932936,41.5867596 C7.20248513,41.5867596 7.37440169,40.3931266 8.06043062,38.8593855 C10.4615319,33.575505 15.6059302,31.5307881 20.4073141,31.5307881 C29.152955,31.5307881 35.1552988,38.5184637 35.1552988,47.2107482 C35.1552988,56.2447681 28.8107592,62.8907084 18.0070315,62.8907084 C7.5454996,62.891522 0,53.6882617 0,43.8023442 C0,30.8497582 11.3178401,21.986606 26.5799372,21.986606 C51.1026062,21.986606 84.1989996,39.2011209 104.948509,39.2011209 C118.495534,39.2011209 126.384048,31.7016558 126.384048,19.4300996 C126.384048,10.3968933 118.667451,4.60203698 115.580321,4.60203698 C114.552096,4.60203698 113.69415,5.1130128 113.69415,6.13577809 C113.69415,7.49946515 114.552096,7.6695192 115.409223,8.01044097 C115.752237,8.18049502 122.268693,10.5669474 122.268693,19.2592319 C122.268693,28.2924381 115.238125,34.0872945 107.177694,34.0872945 C97.7460244,34.0872945 91.0584702,26.4177752 91.0584702,17.8955448 C91.0584702,6.64675391 99.9760277,0 109.749893,0 C122.268693,0 129.642276,9.88510384 129.642276,19.6001536 C129.642276,34.2581622 119.181563,42.4386572 104.947691,42.4386572 C98.0890388,42.4386572 90.5443579,40.9049161 82.4839273,38.6901451 L82.4839273,140.272626 Z";
1776
- function Footer({
1777
- labels,
1778
- layout = "responsive",
1779
- className,
1780
- style,
1781
- unstyled = false,
1782
- accent = false,
1783
- classNameInner,
1784
- classNameLogo,
1785
- classNameText,
1786
- classNameLink
1787
- }) {
1788
- const t = { ...defaultLabels, ...labels };
1789
- const attribution = t.attribution?.trim();
1790
- const footerSurface = unstyled ? "" : accent ? "border-t border-tollerud-yellow/20 bg-tollerud-yellow/5" : "border-t border-tollerud-border bg-tollerud-noir-900/80";
1791
- const innerLayoutClasses = layout === "row" ? "max-w-7xl mx-auto px-8 flex flex-row items-center justify-between gap-4" : "max-w-7xl mx-auto px-8 flex flex-col md:flex-row items-center justify-center md:justify-between gap-4 md:gap-0";
1792
- const logoColor = unstyled ? "" : accent ? "text-tollerud-yellow" : "text-tollerud-text-muted";
1793
- const textWrapperClasses = layout === "row" ? "flex-1 text-right ml-4" : "flex-1 text-center md:text-right md:ml-4";
1794
- const textLayoutClasses = layout === "row" ? "text-sm text-tollerud-text-secondary inline-flex flex-row items-center justify-end text-right gap-0" : "text-sm text-tollerud-text-secondary flex flex-col md:flex-row md:inline gap-0";
1795
- return /* @__PURE__ */ jsx("footer", { className: cn("w-full pt-4 pb-4", footerSurface, className), style, children: /* @__PURE__ */ jsxs("div", { className: cn(innerLayoutClasses, classNameInner), children: [
1796
- /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 md:flex-shrink-0", children: /* @__PURE__ */ jsxs(
1797
- "svg",
1798
- {
1799
- width: "24",
1800
- height: "24",
1801
- viewBox: "0 0 130 143",
1802
- version: "1.1",
1803
- xmlns: "http://www.w3.org/2000/svg",
1804
- xmlnsXlink: "http://www.w3.org/1999/xlink",
1805
- className: cn("h-5 w-5", logoColor, classNameLogo),
1806
- role: "img",
1807
- children: [
1808
- /* @__PURE__ */ jsx("title", { children: "Tollerud Logo" }),
1809
- /* @__PURE__ */ jsx("g", { id: "Page-1", stroke: "none", strokeWidth: "1", fill: "none", fillRule: "evenodd", children: /* @__PURE__ */ jsx("g", { id: "Tollerud-Monogram", transform: "translate(-86.000000, -109.000000)", fill: "currentColor", children: /* @__PURE__ */ jsx("g", { id: "Group-2", transform: "translate(32.000000, 55.000000)", children: /* @__PURE__ */ jsx("g", { id: "Group", transform: "translate(54.000000, 54.000000)", children: /* @__PURE__ */ jsx("path", { d: MONOGRAM_PATH, id: "Monogram" }) }) }) }) })
1810
- ]
1811
- }
1812
- ) }),
1813
- /* @__PURE__ */ jsx("div", { className: textWrapperClasses, children: /* @__PURE__ */ jsxs("p", { className: cn(textLayoutClasses, classNameText), children: [
1814
- /* @__PURE__ */ jsxs("span", { children: [
1815
- /* @__PURE__ */ jsx(
1816
- "a",
1817
- {
1818
- href: "https://tollerud.no",
1819
- target: "_blank",
1820
- rel: "noopener noreferrer",
1821
- className: cn(
1822
- "underline decoration-tollerud-yellow decoration-[3px] underline-offset-[4px] hover:opacity-80 transition-opacity",
1823
- classNameLink
1824
- ),
1825
- style: {
1826
- textDecorationThickness: "3px",
1827
- textUnderlineOffset: "4px"
1828
- },
1829
- children: t.tollerudProject
1830
- }
1831
- ),
1832
- attribution ? /* @__PURE__ */ jsxs(Fragment, { children: [
1833
- " ",
1834
- /* @__PURE__ */ jsx("span", { children: attribution })
1835
- ] }) : null,
1836
- " "
1837
- ] }),
1838
- /* @__PURE__ */ jsx("span", { className: layout === "row" ? "ml-1" : "md:ml-1", children: t.allRightsReserved })
1839
- ] }) })
1840
- ] }) });
1841
- }
1842
- var Dialog = DialogPrimitive.Root;
1843
- var DialogTrigger = DialogPrimitive.Trigger;
1844
- var DialogPortal = DialogPrimitive.Portal;
1845
- var DialogClose = DialogPrimitive.Close;
1846
- var DialogOverlay = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1847
- DialogPrimitive.Overlay,
1848
- {
1849
- ref,
1850
- className: cn(
1851
- "fixed inset-0 z-50 bg-black/60 backdrop-blur-sm",
1852
- className
1853
- ),
1854
- ...props
1855
- }
1856
- ));
1857
- DialogOverlay.displayName = "DialogOverlay";
1858
- var DialogContent = React2.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
1859
- /* @__PURE__ */ jsx(DialogOverlay, {}),
1860
- /* @__PURE__ */ jsxs(
1861
- DialogPrimitive.Content,
1862
- {
1863
- ref,
1864
- className: cn(
1865
- "fixed top-1/2 left-1/2 z-50 w-full max-w-lg -translate-x-1/2 -translate-y-1/2",
1866
- "rounded-lg border border-tollerud-border/30 bg-tollerud-noir-900 p-6 shadow-xl",
1867
- "data-[state=open]:animate-none data-[state=closed]:animate-none",
1868
- className
1869
- ),
1870
- ...props,
1871
- children: [
1872
- children,
1873
- /* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute top-4 right-4 rounded-sm p-1 text-tollerud-text-muted hover:text-tollerud-foreground transition-colors cursor-pointer", children: [
1874
- /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
1875
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
1876
- ] })
1877
- ]
1878
- }
1879
- )
1880
- ] }));
1881
- DialogContent.displayName = "DialogContent";
1882
- var DialogHeader = ({
1883
- className,
1884
- ...props
1885
- }) => /* @__PURE__ */ jsx(
1886
- "div",
1887
- {
1888
- className: cn("flex flex-col gap-1.5 mb-4", className),
1889
- ...props
1890
- }
1891
- );
1892
- DialogHeader.displayName = "DialogHeader";
1893
- var DialogFooter = ({
1894
- className,
1895
- ...props
1896
- }) => /* @__PURE__ */ jsx(
1897
- "div",
1898
- {
1899
- className: cn("flex flex-col-reverse sm:flex-row sm:justify-end gap-2 mt-6", className),
1900
- ...props
1901
- }
1902
- );
1903
- DialogFooter.displayName = "DialogFooter";
1904
- var DialogTitle = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1905
- DialogPrimitive.Title,
1906
- {
1907
- ref,
1908
- className: cn("text-base font-semibold text-tollerud-foreground", className),
1909
- ...props
1910
- }
1911
- ));
1912
- DialogTitle.displayName = "DialogTitle";
1913
- var DialogDescription = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1914
- DialogPrimitive.Description,
1915
- {
1916
- ref,
1917
- className: cn("text-sm text-tollerud-text-secondary", className),
1918
- ...props
1919
- }
1920
- ));
1921
- DialogDescription.displayName = "DialogDescription";
1922
- var TooltipProvider = TooltipPrimitive.Provider;
1923
- var TooltipContext = React2.createContext(null);
1924
- function Tooltip({
1925
- children,
1926
- defaultOpen,
1927
- open: controlledOpen,
1928
- onOpenChange: controlledOnOpenChange,
1929
- ...props
1930
- }) {
1931
- const [internalOpen, setInternalOpen] = React2.useState(defaultOpen ?? false);
1932
- const isControlled = controlledOpen !== void 0;
1933
- const open = isControlled ? controlledOpen : internalOpen;
1934
- const setOpen = isControlled ? controlledOnOpenChange ?? setInternalOpen : setInternalOpen;
1935
- return /* @__PURE__ */ jsx(TooltipContext.Provider, { value: { open, setOpen }, children: /* @__PURE__ */ jsx(TooltipPrimitive.Root, { open, onOpenChange: (v) => setOpen(v), ...props, children }) });
1936
- }
1937
- Tooltip.displayName = "Tooltip";
1938
- var TooltipTrigger = React2.forwardRef(({ onClick, onTouchStart, children, ...props }, ref) => {
1939
- const ctx = React2.useContext(TooltipContext);
1940
- const touchFired = React2.useRef(false);
1941
- return /* @__PURE__ */ jsx(
1942
- TooltipPrimitive.Trigger,
1943
- {
1944
- ref,
1945
- onClick: (e) => {
1946
- if (touchFired.current) {
1947
- touchFired.current = false;
1948
- return;
1949
- }
1950
- if (ctx) {
1951
- ctx.setOpen(!ctx.open);
1952
- }
1953
- onClick?.(e);
1954
- },
1955
- onTouchStart: (e) => {
1956
- touchFired.current = true;
1957
- if (ctx && !ctx.open) {
1958
- ctx.setOpen(true);
1959
- }
1960
- onTouchStart?.(e);
1961
- },
1962
- ...props,
1963
- children
1964
- }
1965
- );
1966
- });
1967
- TooltipTrigger.displayName = "TooltipTrigger";
1968
- var TooltipContent = React2.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
1969
- TooltipPrimitive.Content,
1970
- {
1971
- ref,
1972
- sideOffset,
1973
- className: cn(
1974
- "z-50 overflow-hidden rounded-md border border-tollerud-border/30",
1975
- "bg-tollerud-noir-800 px-3 py-1.5 text-xs text-tollerud-foreground",
1976
- "shadow-md",
1977
- "animate-in fade-in-0 zoom-in-95",
1978
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
1979
- "data-[side=bottom]:slide-in-from-top-1",
1980
- "data-[side=left]:slide-in-from-right-1",
1981
- "data-[side=right]:slide-in-from-left-1",
1982
- "data-[side=top]:slide-in-from-bottom-1",
1983
- className
1984
- ),
1985
- ...props
1986
- }
1987
- ));
1988
- TooltipContent.displayName = "TooltipContent";
1989
- var Tabs = TabsPrimitive.Root;
1990
- var TabsList = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1991
- TabsPrimitive.List,
1992
- {
1993
- ref,
1994
- className: cn(
1995
- "inline-flex h-9 items-center justify-center rounded-lg",
1996
- "bg-tollerud-noir-800 p-1 text-tollerud-text-muted",
1997
- className
1998
- ),
1999
- ...props
2000
- }
2001
- ));
2002
- TabsList.displayName = "TabsList";
2003
- var TabsTrigger = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2004
- TabsPrimitive.Trigger,
2005
- {
2006
- ref,
2007
- className: cn(
2008
- "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1",
2009
- "text-xs font-medium transition-all",
2010
- "text-tollerud-text-muted hover:text-tollerud-foreground",
2011
- "data-[state=active]:bg-tollerud-surface-raised data-[state=active]:text-tollerud-foreground data-[state=active]:shadow-sm",
2012
- "disabled:pointer-events-none disabled:opacity-50",
2013
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-tollerud-yellow/50",
2014
- className
2015
- ),
2016
- ...props
2017
- }
2018
- ));
2019
- TabsTrigger.displayName = "TabsTrigger";
2020
- var TabsContent = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2021
- TabsPrimitive.Content,
2022
- {
2023
- ref,
2024
- className: cn(
2025
- "mt-2 ring-offset-tollerud-black focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-tollerud-yellow/50 focus-visible:ring-offset-2",
2026
- className
2027
- ),
2028
- ...props
2029
- }
2030
- ));
2031
- TabsContent.displayName = "TabsContent";
2032
- function Skeleton({
2033
- className,
2034
- ...props
2035
- }) {
2036
- return /* @__PURE__ */ jsx(
2037
- "div",
2038
- {
2039
- className: cn(
2040
- "animate-pulse rounded-md bg-tollerud-noir-800",
2041
- className
2042
- ),
2043
- ...props
2044
- }
2045
- );
2046
- }
2047
- var Progress = React2.forwardRef(({ className, value, ...props }, ref) => /* @__PURE__ */ jsx(
2048
- ProgressPrimitive.Root,
2049
- {
2050
- ref,
2051
- className: cn(
2052
- "relative h-2 w-full overflow-hidden rounded-full bg-tollerud-noir-800",
2053
- className
2054
- ),
2055
- ...props,
2056
- children: /* @__PURE__ */ jsx(
2057
- ProgressPrimitive.Indicator,
2058
- {
2059
- className: "h-full w-full flex-1 rounded-full bg-tollerud-yellow transition-all duration-300 ease-in-out",
2060
- style: { transform: `translateX(-${100 - (value || 0)}%)` }
2061
- }
2062
- )
2063
- }
2064
- ));
2065
- Progress.displayName = "Progress";
2066
- var Toaster = ({ theme = "dark", ...props }) => {
2067
- const [mobile, setMobile] = useState(false);
2068
- useEffect(() => {
2069
- const check = () => setMobile(window.innerWidth < 640);
2070
- check();
2071
- window.addEventListener("resize", check);
2072
- return () => window.removeEventListener("resize", check);
2073
- }, []);
2074
- return /* @__PURE__ */ jsx(
2075
- Toaster$1,
2076
- {
2077
- position: mobile ? "top-center" : "top-right",
2078
- theme,
2079
- className: "toaster group",
2080
- toastOptions: {
2081
- classNames: {
2082
- toast: "group toast group-[.toaster]:bg-tollerud-noir-900 group-[.toaster]:text-tollerud-foreground group-[.toaster]:border group-[.toaster]:border-tollerud-border/30 group-[.toaster]:shadow-lg",
2083
- description: "group-[.toast]:text-tollerud-text-muted text-xs",
2084
- actionButton: "group-[.toast]:bg-tollerud-yellow group-[.toast]:text-tollerud-black group-[.toast]:text-xs group-[.toast]:font-medium group-[.toast]:px-3 group-[.toast]:py-1 group-[.toast]:rounded",
2085
- cancelButton: "group-[.toast]:bg-tollerud-noir-800 group-[.toast]:text-tollerud-text-muted group-[.toast]:text-xs group-[.toast]:px-3 group-[.toast]:py-1 group-[.toast]:rounded",
2086
- success: "group-[.toast]:border-l-tollerud-success group-[.toast]:border-l-2",
2087
- error: "group-[.toast]:border-l-tollerud-error group-[.toast]:border-l-2",
2088
- warning: "group-[.toast]:border-l-tollerud-yellow group-[.toast]:border-l-2",
2089
- info: "group-[.toast]:border-l-tollerud-info group-[.toast]:border-l-2"
2090
- }
2091
- },
2092
- ...props
2093
- }
2094
- );
2095
- };
2096
- var Empty = forwardRef(
2097
- ({ className, ...props }, ref) => {
2098
- return /* @__PURE__ */ jsx(
2099
- "div",
2100
- {
2101
- ref,
2102
- className: cn(
2103
- "flex w-full flex-1 flex-col items-center justify-center text-center py-12",
2104
- className
2105
- ),
2106
- ...props
2107
- }
2108
- );
2109
- }
2110
- );
2111
- Empty.displayName = "Empty";
2112
- var EmptyHeader = forwardRef(
2113
- ({ className, ...props }, ref) => {
2114
- return /* @__PURE__ */ jsx(
2115
- "div",
2116
- {
2117
- ref,
2118
- className: cn(
2119
- "flex max-w-sm flex-col items-center gap-2",
2120
- className
2121
- ),
2122
- ...props
2123
- }
2124
- );
2125
- }
2126
- );
2127
- EmptyHeader.displayName = "EmptyHeader";
2128
- var EmptyIcon = forwardRef(
2129
- ({ className, ...props }, ref) => {
2130
- return /* @__PURE__ */ jsx(
2131
- "div",
2132
- {
2133
- ref,
2134
- className: cn(
2135
- "flex items-center justify-center w-12 h-12 rounded-full bg-tollerud-noir-800 text-tollerud-text-muted mb-2",
2136
- className
2137
- ),
2138
- ...props
2139
- }
2140
- );
2141
- }
2142
- );
2143
- EmptyIcon.displayName = "EmptyIcon";
2144
- var EmptyTitle = forwardRef(
2145
- ({ className, ...props }, ref) => {
2146
- return /* @__PURE__ */ jsx(
2147
- "h3",
2148
- {
2149
- ref,
2150
- className: cn(
2151
- "text-base font-semibold text-tollerud-foreground",
2152
- className
2153
- ),
2154
- ...props
2155
- }
2156
- );
2157
- }
2158
- );
2159
- EmptyTitle.displayName = "EmptyTitle";
2160
- var EmptyDescription = forwardRef(
2161
- ({ className, ...props }, ref) => {
2162
- return /* @__PURE__ */ jsx(
2163
- "p",
2164
- {
2165
- ref,
2166
- className: cn(
2167
- "text-sm text-tollerud-text-secondary max-w-sm",
2168
- className
2169
- ),
2170
- ...props
2171
- }
2172
- );
2173
- }
2174
- );
2175
- EmptyDescription.displayName = "EmptyDescription";
2176
- var EmptyContent = forwardRef(
2177
- ({ className, ...props }, ref) => {
2178
- return /* @__PURE__ */ jsx(
2179
- "div",
2180
- {
2181
- ref,
2182
- className: cn(
2183
- "flex w-full max-w-sm flex-col items-center gap-4 mt-4",
2184
- className
2185
- ),
2186
- ...props
2187
- }
2188
- );
2189
- }
2190
- );
2191
- EmptyContent.displayName = "EmptyContent";
2192
- var DropdownMenu = DropdownMenuPrimitive.Root;
2193
- var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
2194
- var DropdownMenuContent = forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(
2195
- DropdownMenuPrimitive.Content,
2196
- {
2197
- ref,
2198
- sideOffset,
2199
- className: cn(
2200
- "z-50 min-w-[9rem] overflow-hidden rounded-lg border p-1 shadow-md",
2201
- "bg-tollerud-noir-850 border-tollerud-border/30 text-tollerud-text-primary",
2202
- "data-[state=open]:animate-in data-[state=closed]:animate-out",
2203
- "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
2204
- "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
2205
- "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
2206
- "data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
2207
- className
2208
- ),
2209
- ...props
2210
- }
2211
- ) }));
2212
- DropdownMenuContent.displayName = "DropdownMenuContent";
2213
- var DropdownMenuItem = forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(
2214
- DropdownMenuPrimitive.Item,
2215
- {
2216
- ref,
2217
- className: cn(
2218
- "relative flex cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm outline-none",
2219
- "text-tollerud-text-secondary data-[highlighted]:text-tollerud-text-primary",
2220
- "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
2221
- "data-[highlighted]:bg-tollerud-surface-raised",
2222
- inset && "pl-8",
2223
- className
2224
- ),
2225
- ...props
2226
- }
2227
- ));
2228
- DropdownMenuItem.displayName = "DropdownMenuItem";
2229
- var DropdownMenuSeparator = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2230
- DropdownMenuPrimitive.Separator,
2231
- {
2232
- ref,
2233
- className: cn("-mx-1 my-1 h-px bg-tollerud-border/30", className),
2234
- ...props
2235
- }
2236
- ));
2237
- DropdownMenuSeparator.displayName = "DropdownMenuSeparator";
2238
- var DropdownMenuLabel = forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(
2239
- DropdownMenuPrimitive.Label,
2240
- {
2241
- ref,
2242
- className: cn("px-2 py-1.5 text-xs font-semibold text-tollerud-text-muted", inset && "pl-8", className),
2243
- ...props
2244
- }
2245
- ));
2246
- DropdownMenuLabel.displayName = "DropdownMenuLabel";
2247
- var Sheet = ({ open, onOpenChange, children }) => /* @__PURE__ */ jsx(DialogPrimitive.Root, { open, onOpenChange, children });
2248
- var SheetTrigger = DialogPrimitive.Trigger;
2249
- var SheetClose = DialogPrimitive.Close;
2250
- var SheetOverlay = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2251
- DialogPrimitive.Overlay,
2252
- {
2253
- ref,
2254
- className: cn(
2255
- "fixed inset-0 z-50 bg-black/60 backdrop-blur-sm",
2256
- "data-[state=open]:animate-in data-[state=closed]:animate-out",
2257
- "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
2258
- className
2259
- ),
2260
- ...props
2261
- }
2262
- ));
2263
- SheetOverlay.displayName = "SheetOverlay";
2264
- var SheetContent = forwardRef(({ className, children, side = "right", ...props }, ref) => /* @__PURE__ */ jsx(SheetOverlay, { children: /* @__PURE__ */ jsxs(
2265
- DialogPrimitive.Content,
2266
- {
2267
- ref,
2268
- className: cn(
2269
- "fixed z-50 gap-4 bg-tollerud-noir-900 border-tollerud-border/30 p-6 shadow-lg",
2270
- "data-[state=open]:animate-in data-[state=closed]:animate-out",
2271
- side === "right" && [
2272
- "inset-y-0 right-0 h-full w-full max-w-md border-l",
2273
- "data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right"
2274
- ],
2275
- side === "left" && [
2276
- "inset-y-0 left-0 h-full w-full max-w-md border-r",
2277
- "data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left"
2278
- ],
2279
- className
2280
- ),
2281
- ...props,
2282
- children: [
2283
- children,
2284
- /* @__PURE__ */ jsxs(SheetClose, { className: "absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100 transition-opacity text-tollerud-text-muted hover:text-tollerud-text-primary", children: [
2285
- /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2286
- /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
2287
- /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
2288
- ] }),
2289
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
2290
- ] })
2291
- ]
2292
- }
2293
- ) }));
2294
- SheetContent.displayName = "SheetContent";
2295
- var SheetHeader = ({ className, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-1.5 text-left", className), ...props });
2296
- var SheetTitle = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2297
- DialogPrimitive.Title,
2298
- {
2299
- ref,
2300
- className: cn("text-base font-semibold text-tollerud-text-primary", className),
2301
- ...props
2302
- }
2303
- ));
2304
- SheetTitle.displayName = "SheetTitle";
2305
- var SheetDescription = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2306
- DialogPrimitive.Description,
2307
- {
2308
- ref,
2309
- className: cn("text-sm text-tollerud-text-secondary", className),
2310
- ...props
2311
- }
2312
- ));
2313
- SheetDescription.displayName = "SheetDescription";
2314
- function DataTableInner({
2315
- columns,
2316
- data,
2317
- rowKey,
2318
- onRowClick,
2319
- className,
2320
- emptyMessage = "No data",
2321
- forwardedRef
2322
- }) {
2323
- const [sortKey, setSortKey] = useState(null);
2324
- const [sortDir, setSortDir] = useState("asc");
2325
- const [filters, setFilters] = useState({});
2326
- const filtered = useMemo(() => {
2327
- const activeFilters = Object.entries(filters).filter(([, v]) => v.trim() !== "");
2328
- if (activeFilters.length === 0) return data;
2329
- return data.filter(
2330
- (row) => activeFilters.every(([key, filterValue]) => {
2331
- const cellValue = String(row[key] ?? "").toLowerCase();
2332
- return cellValue.includes(filterValue.toLowerCase());
2333
- })
2334
- );
2335
- }, [data, filters]);
2336
- const sorted = useMemo(() => {
2337
- if (!sortKey) return filtered;
2338
- const col = columns.find((c) => c.key === sortKey);
2339
- if (!col?.sortable) return filtered;
2340
- return [...filtered].sort((a, b) => {
2341
- const aVal = a[sortKey];
2342
- const bVal = b[sortKey];
2343
- if (typeof aVal === "number" && typeof bVal === "number") {
2344
- return sortDir === "asc" ? aVal - bVal : bVal - aVal;
2345
- }
2346
- const aStr = String(aVal ?? "");
2347
- const bStr = String(bVal ?? "");
2348
- const cmp = aStr.localeCompare(bStr, "nb", { numeric: true });
2349
- return sortDir === "asc" ? cmp : -cmp;
2350
- });
2351
- }, [filtered, sortKey, sortDir, columns]);
2352
- const getRowKey = (row, i) => {
2353
- if (typeof rowKey === "function") return rowKey(row);
2354
- if (rowKey) return row[rowKey];
2355
- return row.id ?? row.key ?? i;
2356
- };
2357
- const toggleSort = (key) => {
2358
- if (sortKey === key) {
2359
- setSortDir((d) => d === "asc" ? "desc" : "asc");
2360
- } else {
2361
- setSortKey(key);
2362
- setSortDir("asc");
2363
- }
2364
- };
2365
- const updateFilter = (key, value) => {
2366
- setFilters((prev) => {
2367
- const next = { ...prev };
2368
- if (value.trim() === "") {
2369
- delete next[key];
2370
- } else {
2371
- next[key] = value;
2372
- }
2373
- return next;
2374
- });
2375
- };
2376
- const hasActiveFilters = Object.values(filters).some((v) => v.trim() !== "");
2377
- const filterableColumns = columns.filter((c) => c.filterable);
2378
- return /* @__PURE__ */ jsx("div", { ref: forwardedRef, className: cn("overflow-x-auto rounded-lg border border-tollerud-border/30", className), children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
2379
- /* @__PURE__ */ jsxs("thead", { children: [
2380
- /* @__PURE__ */ jsx("tr", { className: "border-b border-tollerud-border/30 bg-tollerud-noir-900", children: columns.map((col) => /* @__PURE__ */ jsx(
2381
- "th",
2382
- {
2383
- className: cn(
2384
- "px-3 py-2.5 text-xs font-semibold text-tollerud-text-muted uppercase tracking-wider",
2385
- col.sortable && "cursor-pointer select-none hover:text-tollerud-text-primary transition-colors",
2386
- col.align === "right" && "text-right",
2387
- col.align === "center" && "text-center"
2388
- ),
2389
- style: col.width ? { width: col.width } : void 0,
2390
- onClick: () => col.sortable && toggleSort(col.key),
2391
- children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
2392
- col.label,
2393
- col.sortable && sortKey === col.key && /* @__PURE__ */ jsx("span", { className: "text-tollerud-accent", children: sortDir === "asc" ? "\u2191" : "\u2193" }),
2394
- col.sortable && sortKey !== col.key && /* @__PURE__ */ jsx("span", { className: "text-tollerud-text-muted/30", children: "\u2195" }),
2395
- col.filterable && /* @__PURE__ */ jsx(
2396
- "svg",
2397
- {
2398
- width: "12",
2399
- height: "12",
2400
- viewBox: "0 0 24 24",
2401
- fill: "none",
2402
- stroke: "currentColor",
2403
- strokeWidth: "2",
2404
- strokeLinecap: "round",
2405
- strokeLinejoin: "round",
2406
- className: cn(
2407
- "opacity-40",
2408
- filters[col.key] && "opacity-100 text-tollerud-yellow"
2409
- ),
2410
- children: /* @__PURE__ */ jsx("path", { d: "M4 4h16v2.172a2 2 0 0 1-.586 1.414L15 12v7l-6 2v-8.5L4.52 7.53A2 2 0 0 1 4 6.16V4z" })
2411
- }
2412
- )
2413
- ] })
2414
- },
2415
- col.key
2416
- )) }),
2417
- filterableColumns.length > 0 && /* @__PURE__ */ jsx("tr", { className: "border-b border-tollerud-border/20", children: columns.map((col) => /* @__PURE__ */ jsx(
2418
- "th",
2419
- {
2420
- className: cn(
2421
- "px-1.5 py-1",
2422
- col.align === "right" && "text-right",
2423
- col.align === "center" && "text-center"
2424
- ),
2425
- children: col.filterable ? /* @__PURE__ */ jsx(
2426
- "input",
2427
- {
2428
- type: "text",
2429
- placeholder: `Filter ${col.label.toLowerCase()}\u2026`,
2430
- value: filters[col.key] ?? "",
2431
- onChange: (e) => updateFilter(col.key, e.target.value),
2432
- className: cn(
2433
- "w-full px-2 py-1 text-xs rounded border transition-colors outline-none",
2434
- "bg-tollerud-noir-900/50 border-tollerud-border/20 text-tollerud-text-primary placeholder:text-tollerud-text-muted/40",
2435
- "focus:border-tollerud-yellow/40 focus:ring-1 focus:ring-tollerud-yellow/20"
2436
- )
2437
- }
2438
- ) : null
2439
- },
2440
- `filter-${col.key}`
2441
- )) })
2442
- ] }),
2443
- /* @__PURE__ */ jsx("tbody", { children: sorted.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
2444
- "td",
2445
- {
2446
- colSpan: columns.length,
2447
- className: "px-3 py-8 text-center text-sm text-tollerud-text-muted",
2448
- children: hasActiveFilters ? "No matching rows" : emptyMessage
2449
- }
2450
- ) }) : sorted.map((row, i) => /* @__PURE__ */ jsx(
2451
- "tr",
2452
- {
2453
- className: cn(
2454
- "border-b border-tollerud-border/20 transition-colors",
2455
- onRowClick && "cursor-pointer hover:bg-tollerud-surface-raised/50"
2456
- ),
2457
- onClick: () => onRowClick?.(row),
2458
- children: columns.map((col) => {
2459
- const value = row[col.key];
2460
- return /* @__PURE__ */ jsx(
2461
- "td",
2462
- {
2463
- className: cn(
2464
- "px-3 py-2.5 text-tollerud-text-secondary",
2465
- col.align === "right" && "text-right",
2466
- col.align === "center" && "text-center",
2467
- "font-mono text-xs"
2468
- ),
2469
- children: col.render ? col.render(value, row) : String(value ?? "\u2014")
2470
- },
2471
- col.key
2472
- );
2473
- })
2474
- },
2475
- getRowKey(row, i)
2476
- )) })
2477
- ] }) });
2478
- }
2479
- var DataTable = forwardRef((props, ref) => /* @__PURE__ */ jsx(DataTableInner, { ...props, forwardedRef: ref }));
2480
- DataTable.displayName = "DataTable";
2481
- function GlowCard({
2482
- children,
2483
- className,
2484
- glowColor = "var(--tollerud-accent, #FFFF00)",
2485
- intensity = 0.15
2486
- }) {
2487
- const ref = useRef(null);
2488
- const [pos, setPos] = useState({ x: 0, y: 0 });
2489
- const [isHovered, setIsHovered] = useState(false);
2490
- const handleMouseMove = (e) => {
2491
- if (!ref.current) return;
2492
- const rect = ref.current.getBoundingClientRect();
2493
- setPos({
2494
- x: (e.clientX - rect.left) / rect.width * 100,
2495
- y: (e.clientY - rect.top) / rect.height * 100
2496
- });
2497
- };
2498
- return /* @__PURE__ */ jsxs(
2499
- "div",
2500
- {
2501
- ref,
2502
- className: cn("relative overflow-hidden", className),
2503
- onMouseMove: handleMouseMove,
2504
- onMouseEnter: () => setIsHovered(true),
2505
- onMouseLeave: () => setIsHovered(false),
2506
- children: [
2507
- /* @__PURE__ */ jsx(
2508
- "div",
2509
- {
2510
- className: "pointer-events-none absolute inset-0 transition-opacity duration-300",
2511
- style: {
2512
- opacity: isHovered ? 1 : 0,
2513
- background: `radial-gradient(600px circle at ${pos.x}% ${pos.y}%, ${glowColor} ${intensity * 100}%, transparent 70%)`
2514
- }
2515
- }
2516
- ),
2517
- /* @__PURE__ */ jsx("div", { className: "relative z-10", children })
2518
- ]
2519
- }
2520
- );
2521
- }
2522
- function BentoDashboard({
2523
- title,
2524
- hosts = [],
2525
- metrics = [],
2526
- services = [],
2527
- incidents = [],
2528
- className
2529
- }) {
2530
- return /* @__PURE__ */ jsxs("div", { className: cn("space-y-4", className), children: [
2531
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxs("div", { children: [
2532
- /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-tollerud-text-primary", children: title }),
2533
- /* @__PURE__ */ jsxs("p", { className: "text-xs text-tollerud-text-muted", children: [
2534
- hosts.length,
2535
- " hosts \xB7 ",
2536
- services.length,
2537
- " services",
2538
- incidents.length > 0 && ` \xB7 ${incidents.length} active incident${incidents.length > 1 ? "s" : ""}`
2539
- ] })
2540
- ] }) }),
2541
- hosts.length > 0 && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
2542
- /* @__PURE__ */ jsx("div", { className: "md:col-span-2 lg:col-span-1", children: /* @__PURE__ */ jsx(HostCardComponent, { host: hosts[0] }) }),
2543
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-3 md:col-span-2 lg:col-span-1", children: hosts.slice(1).map((h, i) => /* @__PURE__ */ jsx(HostCardComponent, { host: h }, h.hostname ?? i)) })
2544
- ] }),
2545
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-3", children: [
2546
- metrics.length > 0 && /* @__PURE__ */ jsxs("div", { className: "lg:col-span-2", children: [
2547
- /* @__PURE__ */ jsx(SectionLabel, { children: "Metrics" }),
2548
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-2", children: metrics.map((m, i) => /* @__PURE__ */ jsx(StatCardComponent, { stat: m }, m.label ?? i)) })
2549
- ] }),
2550
- services.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
2551
- /* @__PURE__ */ jsx(SectionLabel, { children: "Services" }),
2552
- /* @__PURE__ */ jsx("div", { className: "space-y-2", children: services.slice(0, 4).map((s, i) => /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-tollerud-border/20 bg-tollerud-surface p-3", children: [
2553
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2554
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-tollerud-text-primary", children: s.service }),
2555
- /* @__PURE__ */ jsx("span", { className: cn(
2556
- "text-xs px-1.5 py-0.5 rounded-full font-medium",
2557
- s.status === "online" && "text-tollerud-accent bg-tollerud-accent/10",
2558
- s.status === "warning" && "text-tollerud-warning bg-tollerud-warning/10",
2559
- s.status === "offline" && "text-tollerud-error bg-tollerud-error/10",
2560
- s.status === "idle" && "text-tollerud-text-muted bg-tollerud-noir-800"
2561
- ), children: s.status })
2562
- ] }),
2563
- s.responseTime && /* @__PURE__ */ jsxs("p", { className: "text-xs text-tollerud-text-muted mt-1", children: [
2564
- s.responseTime,
2565
- " response"
2566
- ] })
2567
- ] }, s.service ?? i)) })
2568
- ] })
2569
- ] }),
2570
- incidents.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
2571
- /* @__PURE__ */ jsx(SectionLabel, { children: "Recent Incidents" }),
2572
- /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: incidents.slice(0, 4).map((inc, i) => /* @__PURE__ */ jsx(IncidentCardItem, { incident: inc }, inc.title + i)) })
2573
- ] })
2574
- ] });
2575
- }
2576
- function SectionLabel({ children }) {
2577
- return /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold text-tollerud-text-muted uppercase tracking-wider mb-2", children });
2578
- }
2579
- function HostCardComponent({ host }) {
2580
- return /* @__PURE__ */ jsxs("div", { className: cn(
2581
- "rounded-xl border p-4",
2582
- host.status === "online" ? "border-tollerud-border/30 bg-tollerud-surface" : host.status === "warning" ? "border-tollerud-warning/30 bg-tollerud-warning/5" : "border-tollerud-border/20 bg-tollerud-surface opacity-70"
2583
- ), children: [
2584
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
2585
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2586
- /* @__PURE__ */ jsx(StatusDotComp, { status: host.status }),
2587
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-tollerud-text-primary", children: host.hostname })
2588
- ] }),
2589
- /* @__PURE__ */ jsx("span", { className: "text-xs text-tollerud-text-muted font-mono", children: host.ip })
2590
- ] }),
2591
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 text-xs", children: [
2592
- host.cpu && /* @__PURE__ */ jsx(MetricBadge, { label: "CPU", value: host.cpu }),
2593
- host.memory && /* @__PURE__ */ jsx(MetricBadge, { label: "Mem", value: host.memory }),
2594
- host.disk && /* @__PURE__ */ jsx(MetricBadge, { label: "Disk", value: host.disk }),
2595
- host.uptime && /* @__PURE__ */ jsx(MetricBadge, { label: "Up", value: host.uptime })
2596
- ] })
2597
- ] });
2598
- }
2599
- function StatCardComponent({ stat }) {
2600
- return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-tollerud-border/20 bg-tollerud-surface p-3", children: [
2601
- /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-text-muted", children: stat.label }),
2602
- /* @__PURE__ */ jsx("p", { className: "text-lg font-semibold text-tollerud-text-primary mt-0.5", children: stat.value }),
2603
- stat.change && /* @__PURE__ */ jsx("span", { className: cn(
2604
- "text-xs font-medium",
2605
- stat.change.direction === "up" ? "text-tollerud-accent" : "text-tollerud-error"
2606
- ), children: stat.change.value })
2607
- ] });
2608
- }
2609
- function IncidentCardItem({ incident }) {
2610
- return /* @__PURE__ */ jsxs("div", { className: cn(
2611
- "flex items-start gap-3 rounded-lg border p-3",
2612
- incident.acknowledged ? "border-tollerud-border/10 bg-tollerud-noir-900/50 opacity-60" : "border-tollerud-border/20 bg-tollerud-surface"
2613
- ), children: [
2614
- /* @__PURE__ */ jsx(SeverityDot, { severity: incident.severity }),
2615
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2616
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2617
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-tollerud-text-primary truncate", children: incident.title }),
2618
- incident.acknowledged && /* @__PURE__ */ jsx("span", { className: "text-xs text-tollerud-text-muted", children: "(acknowledged)" })
2619
- ] }),
2620
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-tollerud-text-muted mt-0.5", children: [
2621
- /* @__PURE__ */ jsx("span", { children: incident.service }),
2622
- /* @__PURE__ */ jsx("span", { children: "\xB7" }),
2623
- /* @__PURE__ */ jsx("span", { children: incident.timestamp })
2624
- ] }),
2625
- incident.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-text-secondary mt-1", children: incident.description })
2626
- ] })
2627
- ] });
2628
- }
2629
- function StatusDotComp({ status }) {
2630
- return /* @__PURE__ */ jsx("span", { className: cn(
2631
- "inline-block w-2 h-2 rounded-full",
2632
- status === "online" && "bg-tollerud-accent shadow-[0_0_4px_var(--tollerud-accent)]",
2633
- status === "warning" && "bg-tollerud-warning",
2634
- status === "offline" && "bg-tollerud-error"
2635
- ) });
2636
- }
2637
- function SeverityDot({ severity }) {
2638
- return /* @__PURE__ */ jsx("span", { className: cn(
2639
- "inline-block w-2 h-2 rounded-full mt-1 shrink-0",
2640
- severity === "critical" && "bg-tollerud-error shadow-[0_0_4px_var(--tollerud-error)]",
2641
- severity === "high" && "bg-tollerud-warning",
2642
- severity === "medium" && "bg-tollerud-accent",
2643
- severity === "low" && "bg-tollerud-text-muted",
2644
- severity === "info" && "bg-tollerud-info"
2645
- ) });
2646
- }
2647
- function MetricBadge({ label, value }) {
2648
- return /* @__PURE__ */ jsxs("div", { className: "rounded bg-tollerud-noir-800 px-2 py-1.5", children: [
2649
- /* @__PURE__ */ jsx("span", { className: "text-tollerud-text-muted", children: label }),
2650
- /* @__PURE__ */ jsx("span", { className: "float-right text-tollerud-text-primary font-mono", children: value })
2651
- ] });
2652
- }
2653
- var Divider = forwardRef(
2654
- ({ className, orientation = "horizontal", label, ...props }, ref) => {
2655
- if (orientation === "vertical") {
2656
- return /* @__PURE__ */ jsx(
2657
- "div",
2658
- {
2659
- ref,
2660
- role: "separator",
2661
- "aria-orientation": "vertical",
2662
- className: cn("w-px self-stretch bg-tollerud-border", className),
2663
- ...props
2664
- }
2665
- );
2666
- }
2667
- if (label) {
2668
- return /* @__PURE__ */ jsxs(
2669
- "div",
2670
- {
2671
- ref,
2672
- role: "separator",
2673
- "aria-orientation": "horizontal",
2674
- className: cn("flex items-center gap-3 text-xs text-tollerud-text-muted", className),
2675
- ...props,
2676
- children: [
2677
- /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-tollerud-border" }),
2678
- /* @__PURE__ */ jsx("span", { children: label }),
2679
- /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-tollerud-border" })
2680
- ]
2681
- }
2682
- );
2683
- }
2684
- return /* @__PURE__ */ jsx(
2685
- "div",
2686
- {
2687
- ref,
2688
- role: "separator",
2689
- "aria-orientation": "horizontal",
2690
- className: cn("h-px w-full bg-tollerud-border", className),
2691
- ...props
2692
- }
2693
- );
2694
- }
2695
- );
2696
- Divider.displayName = "Divider";
2697
- var pillVariants = {
2698
- outline: "bg-transparent border border-tollerud-border text-tollerud-text-secondary",
2699
- solid: "bg-tollerud-surface-raised text-tollerud-text-primary",
2700
- accent: "bg-tollerud-yellow/15 border border-tollerud-yellow/30 text-tollerud-yellow"
2701
- };
2702
- var Pill = forwardRef(
2703
- ({ className, variant = "outline", ...props }, ref) => {
2704
- return /* @__PURE__ */ jsx(
2705
- "span",
2706
- {
2707
- ref,
2708
- className: cn(
2709
- "inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium rounded-full leading-none",
2710
- pillVariants[variant],
2711
- className
2712
- ),
2713
- ...props
2714
- }
2715
- );
2716
- }
2717
- );
2718
- Pill.displayName = "Pill";
2719
- var avatarSizes = {
2720
- sm: "h-6 w-6 text-[10px]",
2721
- md: "h-8 w-8 text-xs",
2722
- lg: "h-11 w-11 text-sm"
2723
- };
2724
- function initialsFrom(name) {
2725
- const parts = name.trim().split(/\s+/).filter(Boolean);
2726
- if (parts.length === 0) return "";
2727
- if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
2728
- return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
2729
- }
2730
- var Avatar = forwardRef(
2731
- ({ className, src, name, fallback, size = "md", ...props }, ref) => {
2732
- const [errored, setErrored] = useState(false);
2733
- const showImage = !!src && !errored;
2734
- return /* @__PURE__ */ jsx(
2735
- "span",
2736
- {
2737
- ref,
2738
- className: cn(
2739
- "relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full select-none",
2740
- "bg-tollerud-surface-raised text-tollerud-text-secondary font-medium",
2741
- "ring-1 ring-tollerud-border",
2742
- avatarSizes[size],
2743
- className
2744
- ),
2745
- ...props,
2746
- children: showImage ? (
2747
- // eslint-disable-next-line @next/next/no-img-element
2748
- /* @__PURE__ */ jsx(
2749
- "img",
2750
- {
2751
- src,
2752
- alt: name ?? "",
2753
- className: "h-full w-full object-cover",
2754
- onError: () => setErrored(true)
2755
- }
2756
- )
2757
- ) : /* @__PURE__ */ jsx("span", { "aria-hidden": !!name, children: fallback ?? (name ? initialsFrom(name) : null) })
2758
- }
2759
- );
2760
- }
2761
- );
2762
- Avatar.displayName = "Avatar";
2763
- var AvatarGroup = forwardRef(
2764
- ({ className, max, size = "md", children, ...props }, ref) => {
2765
- const items = Array.isArray(children) ? children : [children];
2766
- const visible = max ? items.slice(0, max) : items;
2767
- const overflow = max ? items.length - max : 0;
2768
- return /* @__PURE__ */ jsxs(
2769
- "div",
2770
- {
2771
- ref,
2772
- className: cn("flex items-center -space-x-2", className),
2773
- ...props,
2774
- children: [
2775
- visible.map((child, i) => /* @__PURE__ */ jsx("span", { className: "ring-2 ring-tollerud-surface rounded-full", children: child }, i)),
2776
- overflow > 0 && /* @__PURE__ */ jsxs(
2777
- "span",
2778
- {
2779
- className: cn(
2780
- "relative inline-flex shrink-0 items-center justify-center rounded-full select-none",
2781
- "bg-tollerud-surface-raised text-tollerud-text-muted font-medium",
2782
- "ring-2 ring-tollerud-surface",
2783
- avatarSizes[size]
2784
- ),
2785
- children: [
2786
- "+",
2787
- overflow
2788
- ]
2789
- }
2790
- )
2791
- ]
2792
- }
2793
- );
2794
- }
2795
- );
2796
- AvatarGroup.displayName = "AvatarGroup";
2797
- var Breadcrumb = forwardRef(
2798
- ({ className, items, separator, ...props }, ref) => {
2799
- return /* @__PURE__ */ jsx("nav", { ref, "aria-label": "Breadcrumb", className: cn("text-sm", className), ...props, children: /* @__PURE__ */ jsx("ol", { className: "flex items-center gap-1.5 flex-wrap", children: items.map((item, i) => {
2800
- const isLast = i === items.length - 1;
2801
- const content = !isLast && (item.href || item.onClick) ? /* @__PURE__ */ jsx(
2802
- "a",
2803
- {
2804
- href: item.href,
2805
- onClick: item.onClick,
2806
- className: "text-tollerud-text-secondary hover:text-tollerud-text-primary transition-colors duration-[150ms]",
2807
- children: item.label
2808
- }
2809
- ) : /* @__PURE__ */ jsx(
2810
- "span",
2811
- {
2812
- "aria-current": isLast ? "page" : void 0,
2813
- className: isLast ? "text-tollerud-text-primary font-medium" : "text-tollerud-text-secondary",
2814
- children: item.label
2815
- }
2816
- );
2817
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [
2818
- /* @__PURE__ */ jsx("li", { className: "flex items-center gap-1.5", children: content }),
2819
- !isLast && /* @__PURE__ */ jsx("li", { "aria-hidden": "true", className: "flex items-center text-tollerud-text-muted", children: separator ?? /* @__PURE__ */ jsx(ChevronRight, { size: 14 }) })
2820
- ] }, i);
2821
- }) }) });
2822
- }
2823
- );
2824
- Breadcrumb.displayName = "Breadcrumb";
2825
- function getPageRange(page, pageCount, siblingCount) {
2826
- const totalVisible = siblingCount * 2 + 5;
2827
- if (pageCount <= totalVisible) {
2828
- return Array.from({ length: pageCount }, (_, i) => i + 1);
2829
- }
2830
- const left = Math.max(page - siblingCount, 1);
2831
- const right = Math.min(page + siblingCount, pageCount);
2832
- const range = [1];
2833
- if (left > 2) range.push("ellipsis");
2834
- for (let p = left === 1 ? 2 : left; p <= (right === pageCount ? pageCount - 1 : right); p++) {
2835
- range.push(p);
2836
- }
2837
- if (right < pageCount - 1) range.push("ellipsis");
2838
- if (pageCount > 1) range.push(pageCount);
2839
- return range;
2840
- }
2841
- var navButtonClasses = "inline-flex h-8 min-w-8 items-center justify-center rounded px-2 text-sm transition-colors duration-[150ms] disabled:opacity-40 disabled:pointer-events-none";
2842
- var Pagination = forwardRef(
2843
- ({ className, page, pageCount, onChange, siblingCount = 1, ...props }, ref) => {
2844
- const range = getPageRange(page, pageCount, siblingCount);
2845
- return /* @__PURE__ */ jsxs("nav", { ref, "aria-label": "Pagination", className: cn("flex items-center gap-1", className), ...props, children: [
2846
- /* @__PURE__ */ jsx(
2847
- "button",
2848
- {
2849
- type: "button",
2850
- "aria-label": "Previous page",
2851
- disabled: page <= 1,
2852
- onClick: () => onChange(page - 1),
2853
- className: cn(navButtonClasses, "text-tollerud-text-secondary hover:bg-tollerud-surface-hover"),
2854
- children: /* @__PURE__ */ jsx(ChevronLeft, { size: 16 })
2855
- }
2856
- ),
2857
- range.map(
2858
- (item, i) => item === "ellipsis" ? /* @__PURE__ */ jsx("span", { className: "inline-flex h-8 w-8 items-center justify-center text-tollerud-text-muted", children: /* @__PURE__ */ jsx(MoreHorizontal, { size: 16 }) }, `e-${i}`) : /* @__PURE__ */ jsx(
2859
- "button",
2860
- {
2861
- type: "button",
2862
- "aria-current": item === page ? "page" : void 0,
2863
- onClick: () => onChange(item),
2864
- className: cn(
2865
- navButtonClasses,
2866
- item === page ? "bg-tollerud-yellow text-tollerud-noir-black font-medium" : "text-tollerud-text-secondary hover:bg-tollerud-surface-hover"
2867
- ),
2868
- children: item
2869
- },
2870
- item
2871
- )
2872
- ),
2873
- /* @__PURE__ */ jsx(
2874
- "button",
2875
- {
2876
- type: "button",
2877
- "aria-label": "Next page",
2878
- disabled: page >= pageCount,
2879
- onClick: () => onChange(page + 1),
2880
- className: cn(navButtonClasses, "text-tollerud-text-secondary hover:bg-tollerud-surface-hover"),
2881
- children: /* @__PURE__ */ jsx(ChevronRight, { size: 16 })
2882
- }
2883
- )
2884
- ] });
2885
- }
2886
- );
2887
- Pagination.displayName = "Pagination";
2888
- var Segmented = forwardRef(
2889
- ({ className, options, value, onChange, size = "md", ...props }, ref) => {
2890
- return /* @__PURE__ */ jsx(
2891
- "div",
2892
- {
2893
- ref,
2894
- role: "radiogroup",
2895
- className: cn(
2896
- "inline-flex items-center gap-0.5 rounded-lg p-1 bg-tollerud-surface-raised border border-tollerud-border",
2897
- className
2898
- ),
2899
- ...props,
2900
- children: options.map((opt) => {
2901
- const active = opt.value === value;
2902
- return /* @__PURE__ */ jsx(
2903
- "button",
2904
- {
2905
- type: "button",
2906
- role: "radio",
2907
- "aria-checked": active,
2908
- disabled: opt.disabled,
2909
- onClick: () => !opt.disabled && onChange(opt.value),
2910
- className: cn(
2911
- "rounded-md font-medium transition-colors duration-[150ms]",
2912
- size === "sm" ? "px-2.5 py-1 text-xs" : "px-3.5 py-1.5 text-sm",
2913
- active ? "bg-tollerud-yellow text-tollerud-noir-black" : "text-tollerud-text-secondary hover:text-tollerud-text-primary",
2914
- opt.disabled && "opacity-40 pointer-events-none"
2915
- ),
2916
- children: opt.label
2917
- },
2918
- opt.value
2919
- );
2920
- })
2921
- }
2922
- );
2923
- }
2924
- );
2925
- Segmented.displayName = "Segmented";
2926
- var Stepper = forwardRef(
2927
- ({ className, steps, current, orientation = "horizontal", ...props }, ref) => {
2928
- const vertical = orientation === "vertical";
2929
- return /* @__PURE__ */ jsx(
2930
- "ol",
2931
- {
2932
- ref,
2933
- className: cn("flex", vertical ? "flex-col gap-0" : "items-start gap-0 w-full", className),
2934
- ...props,
2935
- children: steps.map((step, i) => {
2936
- const status = i < current ? "complete" : i === current ? "active" : "upcoming";
2937
- const isLast = i === steps.length - 1;
2938
- return /* @__PURE__ */ jsxs(
2939
- "li",
2940
- {
2941
- className: cn(
2942
- "flex",
2943
- vertical ? "flex-row gap-3" : "flex-col flex-1 gap-2",
2944
- !vertical && !isLast && "pr-2"
2945
- ),
2946
- children: [
2947
- /* @__PURE__ */ jsxs("div", { className: cn("flex items-center", vertical ? "flex-col" : "flex-row gap-2 w-full"), children: [
2948
- /* @__PURE__ */ jsx(
2949
- "span",
2950
- {
2951
- className: cn(
2952
- "flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-xs font-medium transition-colors duration-[150ms]",
2953
- status === "complete" && "bg-tollerud-yellow text-tollerud-noir-black",
2954
- status === "active" && "border-2 border-tollerud-yellow text-tollerud-yellow",
2955
- status === "upcoming" && "border border-tollerud-border text-tollerud-text-muted"
2956
- ),
2957
- children: status === "complete" ? /* @__PURE__ */ jsx(Check, { size: 14 }) : i + 1
2958
- }
2959
- ),
2960
- !isLast && /* @__PURE__ */ jsx(
2961
- "span",
2962
- {
2963
- "aria-hidden": "true",
2964
- className: cn(
2965
- "bg-tollerud-border",
2966
- vertical ? "w-px flex-1 my-1" : "h-px flex-1",
2967
- status === "complete" && "bg-tollerud-yellow"
2968
- )
2969
- }
2970
- )
2971
- ] }),
2972
- /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col", vertical && "pb-6"), children: [
2973
- /* @__PURE__ */ jsx(
2974
- "span",
2975
- {
2976
- className: cn(
2977
- "text-sm font-medium",
2978
- status === "upcoming" ? "text-tollerud-text-muted" : "text-tollerud-text-primary"
2979
- ),
2980
- children: step.label
2981
- }
2982
- ),
2983
- step.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-tollerud-text-muted", children: step.description })
2984
- ] })
2985
- ]
2986
- },
2987
- i
2988
- );
2989
- })
2990
- }
2991
- );
2992
- }
2993
- );
2994
- Stepper.displayName = "Stepper";
2995
- var Panel = forwardRef(
2996
- ({ className, title, description, actions, children, ...props }, ref) => {
2997
- const hasHeader = title || description || actions;
2998
- return /* @__PURE__ */ jsxs(
2999
- "div",
3000
- {
3001
- ref,
3002
- className: cn(
3003
- "rounded-lg border border-tollerud-border bg-tollerud-surface overflow-hidden",
3004
- className
3005
- ),
3006
- ...props,
3007
- children: [
3008
- hasHeader && /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4 px-5 py-4 border-b border-tollerud-border", children: [
3009
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
3010
- title && /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-tollerud-text-primary", children: title }),
3011
- description && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-text-muted", children: description })
3012
- ] }),
3013
- actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 shrink-0", children: actions })
3014
- ] }),
3015
- children && /* @__PURE__ */ jsx("div", { className: "px-5 py-4", children })
3016
- ]
3017
- }
3018
- );
3019
- }
3020
- );
3021
- Panel.displayName = "Panel";
3022
- var meterTones = {
3023
- default: "bg-tollerud-yellow",
3024
- success: "bg-tollerud-success",
3025
- warning: "bg-tollerud-warning",
3026
- error: "bg-tollerud-error"
3027
- };
3028
- var Meter = forwardRef(
3029
- ({ className, value, max = 100, label, showValue, tone = "default", ...props }, ref) => {
3030
- const pct = Math.min(100, Math.max(0, value / max * 100));
3031
- return /* @__PURE__ */ jsxs("div", { ref, className: cn("flex flex-col gap-1.5", className), ...props, children: [
3032
- (label || showValue) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
3033
- label && /* @__PURE__ */ jsx("span", { className: "text-tollerud-text-secondary", children: label }),
3034
- showValue && /* @__PURE__ */ jsxs("span", { className: "text-tollerud-text-muted tabular-nums", children: [
3035
- Math.round(pct),
3036
- "%"
3037
- ] })
3038
- ] }),
3039
- /* @__PURE__ */ jsx(
3040
- "div",
3041
- {
3042
- role: "meter",
3043
- "aria-valuenow": value,
3044
- "aria-valuemin": 0,
3045
- "aria-valuemax": max,
3046
- className: "h-1.5 w-full overflow-hidden rounded-full bg-tollerud-surface-raised",
3047
- children: /* @__PURE__ */ jsx(
3048
- "div",
3049
- {
3050
- className: cn("h-full rounded-full transition-[width] duration-300", meterTones[tone]),
3051
- style: { width: `${pct}%` }
3052
- }
3053
- )
3054
- }
3055
- )
3056
- ] });
3057
- }
3058
- );
3059
- Meter.displayName = "Meter";
3060
- var FormRow = forwardRef(
3061
- ({ className, label, description, error, required, htmlFor, children, ...props }, ref) => {
3062
- const autoId = useId();
3063
- const descriptionId = description ? `${autoId}-description` : void 0;
3064
- const errorId = error ? `${autoId}-error` : void 0;
3065
- return /* @__PURE__ */ jsxs("div", { ref, className: cn("flex flex-col gap-1.5", className), ...props, children: [
3066
- label && /* @__PURE__ */ jsxs("label", { htmlFor, className: "text-sm font-medium text-tollerud-text-primary", children: [
3067
- label,
3068
- required && /* @__PURE__ */ jsx("span", { className: "ml-0.5 text-tollerud-error", children: "*" })
3069
- ] }),
3070
- description && /* @__PURE__ */ jsx("p", { id: descriptionId, className: "text-xs text-tollerud-text-muted", children: description }),
3071
- /* @__PURE__ */ jsx("div", { "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || void 0, children }),
3072
- error && /* @__PURE__ */ jsx("p", { id: errorId, className: "text-xs text-tollerud-error", children: error })
3073
- ] });
3074
- }
3075
- );
3076
- FormRow.displayName = "FormRow";
3077
- var PricingCard = forwardRef(
3078
- ({
3079
- className,
3080
- name,
3081
- price,
3082
- period,
3083
- description,
3084
- features = [],
3085
- ctaLabel = "Get started",
3086
- onCtaClick,
3087
- featured,
3088
- badge,
3089
- ...props
3090
- }, ref) => {
3091
- return /* @__PURE__ */ jsxs(
3092
- "div",
3093
- {
3094
- ref,
3095
- className: cn(
3096
- "flex flex-col gap-5 rounded-xl border p-6",
3097
- featured ? "border-tollerud-yellow bg-tollerud-yellow/[0.04] shadow-[0_0_0_1px_rgba(255,255,0,0.15)]" : "border-tollerud-border bg-tollerud-surface",
3098
- className
3099
- ),
3100
- ...props,
3101
- children: [
3102
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3103
- badge && /* @__PURE__ */ jsx("span", { className: "inline-flex w-fit items-center rounded-full bg-tollerud-yellow/15 px-2.5 py-0.5 text-xs font-medium text-tollerud-yellow", children: badge }),
3104
- /* @__PURE__ */ jsx("h3", { className: "text-base font-medium text-tollerud-text-primary", children: name }),
3105
- description && /* @__PURE__ */ jsx("p", { className: "text-sm text-tollerud-text-muted", children: description })
3106
- ] }),
3107
- /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-1", children: [
3108
- /* @__PURE__ */ jsx("span", { className: "text-3xl font-semibold tracking-tight text-tollerud-text-primary", children: price }),
3109
- period && /* @__PURE__ */ jsx("span", { className: "text-sm text-tollerud-text-muted", children: period })
3110
- ] }),
3111
- features.length > 0 && /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-2.5", children: features.map((feature, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2.5 text-sm text-tollerud-text-secondary", children: [
3112
- /* @__PURE__ */ jsx(Check, { size: 16, className: "mt-0.5 shrink-0 text-tollerud-yellow" }),
3113
- /* @__PURE__ */ jsx("span", { children: feature })
3114
- ] }, i)) }),
3115
- /* @__PURE__ */ jsx(Button, { variant: featured ? "primary" : "secondary", onClick: onCtaClick, className: "mt-auto w-full", children: ctaLabel })
3116
- ]
3117
- }
3118
- );
3119
- }
3120
- );
3121
- PricingCard.displayName = "PricingCard";
3122
- var AccordionContext = createContext(null);
3123
- function useAccordionContext(component) {
3124
- const ctx = useContext(AccordionContext);
3125
- if (!ctx) throw new Error(`<${component}> must be used within <Accordion>`);
3126
- return ctx;
3127
- }
3128
- var Accordion = forwardRef(
3129
- ({ className, multiple = false, defaultOpen, children, ...props }, ref) => {
3130
- const [openItems, setOpenItems] = useState(() => {
3131
- if (!defaultOpen) return /* @__PURE__ */ new Set();
3132
- return new Set(Array.isArray(defaultOpen) ? defaultOpen : [defaultOpen]);
3133
- });
3134
- const toggle = (value) => {
3135
- setOpenItems((prev) => {
3136
- const next = multiple ? new Set(prev) : /* @__PURE__ */ new Set();
3137
- if (prev.has(value)) {
3138
- next.delete(value);
3139
- } else {
3140
- next.add(value);
3141
- }
3142
- return next;
3143
- });
3144
- };
3145
- return /* @__PURE__ */ jsx(AccordionContext.Provider, { value: { openItems, toggle }, children: /* @__PURE__ */ jsx("div", { ref, className: cn("flex flex-col divide-y divide-tollerud-border rounded-lg border border-tollerud-border", className), ...props, children }) });
3146
- }
3147
- );
3148
- Accordion.displayName = "Accordion";
3149
- var AccordionItemContext = createContext(null);
3150
- var AccordionItem = forwardRef(
3151
- ({ className, value, children, ...props }, ref) => {
3152
- const { openItems } = useAccordionContext("AccordionItem");
3153
- const autoId = useId();
3154
- const open = openItems.has(value);
3155
- return /* @__PURE__ */ jsx(
3156
- AccordionItemContext.Provider,
3157
- {
3158
- value: { value, open, triggerId: `${autoId}-trigger`, contentId: `${autoId}-content` },
3159
- children: /* @__PURE__ */ jsx("div", { ref, className: cn("first:rounded-t-lg last:rounded-b-lg", className), ...props, children })
3160
- }
3161
- );
3162
- }
3163
- );
3164
- AccordionItem.displayName = "AccordionItem";
3165
- function useAccordionItemContext(component) {
3166
- const ctx = useContext(AccordionItemContext);
3167
- if (!ctx) throw new Error(`<${component}> must be used within <AccordionItem>`);
3168
- return ctx;
3169
- }
3170
- var AccordionTrigger = forwardRef(
3171
- ({ className, children, ...props }, ref) => {
3172
- const { toggle } = useAccordionContext("AccordionTrigger");
3173
- const { value, open, triggerId, contentId } = useAccordionItemContext("AccordionTrigger");
3174
- return /* @__PURE__ */ jsxs(
3175
- "button",
3176
- {
3177
- ref,
3178
- id: triggerId,
3179
- type: "button",
3180
- "aria-expanded": open,
3181
- "aria-controls": contentId,
3182
- onClick: () => toggle(value),
3183
- className: cn(
3184
- "flex w-full items-center justify-between gap-4 px-4 py-3.5 text-left text-sm font-medium",
3185
- "text-tollerud-text-primary hover:bg-tollerud-surface-hover transition-colors duration-[150ms]",
3186
- className
3187
- ),
3188
- ...props,
3189
- children: [
3190
- children,
3191
- /* @__PURE__ */ jsx(
3192
- ChevronDown,
3193
- {
3194
- size: 16,
3195
- className: cn("shrink-0 text-tollerud-text-muted transition-transform duration-[200ms]", open && "rotate-180")
3196
- }
3197
- )
3198
- ]
3199
- }
3200
- );
3201
- }
3202
- );
3203
- AccordionTrigger.displayName = "AccordionTrigger";
3204
- var AccordionContent = forwardRef(
3205
- ({ className, children, ...props }, ref) => {
3206
- const { open, triggerId, contentId } = useAccordionItemContext("AccordionContent");
3207
- return /* @__PURE__ */ jsx(
3208
- "div",
3209
- {
3210
- ref,
3211
- id: contentId,
3212
- role: "region",
3213
- "aria-labelledby": triggerId,
3214
- hidden: !open,
3215
- className: cn("px-4 pb-4 text-sm text-tollerud-text-secondary", className),
3216
- ...props,
3217
- children
3218
- }
3219
- );
3220
- }
3221
- );
3222
- AccordionContent.displayName = "AccordionContent";
3223
- var Slider = forwardRef(
3224
- ({ className, label, showValue, id: idProp, value, defaultValue, min = 0, max = 100, onChange, ...props }, ref) => {
3225
- const autoId = useId();
3226
- const id = idProp ?? autoId;
3227
- const current = value ?? defaultValue ?? min;
3228
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
3229
- (label || showValue) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
3230
- label && /* @__PURE__ */ jsx("label", { htmlFor: id, className: "font-medium text-tollerud-text-muted", children: label }),
3231
- showValue && /* @__PURE__ */ jsx("span", { className: "text-tollerud-text-secondary tabular-nums", children: current })
3232
- ] }),
3233
- /* @__PURE__ */ jsx(
3234
- "input",
3235
- {
3236
- ref,
3237
- id,
3238
- type: "range",
3239
- min,
3240
- max,
3241
- value,
3242
- defaultValue,
3243
- onChange: (e) => onChange?.(Number(e.target.value)),
3244
- className: cn(
3245
- "h-1.5 w-full cursor-pointer appearance-none rounded-full bg-tollerud-surface-raised accent-tollerud-yellow",
3246
- "[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4",
3247
- "[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-tollerud-yellow [&::-webkit-slider-thumb]:cursor-pointer",
3248
- "[&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-tollerud-noir-black",
3249
- "[&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:rounded-full",
3250
- "[&::-moz-range-thumb]:bg-tollerud-yellow [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-tollerud-noir-black [&::-moz-range-thumb]:cursor-pointer",
3251
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-tollerud-yellow/50",
3252
- "disabled:opacity-40 disabled:pointer-events-none",
3253
- className
3254
- ),
3255
- ...props
3256
- }
3257
- )
3258
- ] });
3259
- }
3260
- );
3261
- Slider.displayName = "Slider";
3262
- var PasswordInput = forwardRef(
3263
- ({ className, label, error, id, ...props }, ref) => {
3264
- const [visible, setVisible] = useState(false);
3265
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3266
- label && /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-xs font-medium text-tollerud-text-muted", children: label }),
3267
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
3268
- /* @__PURE__ */ jsx(
3269
- "input",
3270
- {
3271
- ref,
3272
- id,
3273
- type: visible ? "text" : "password",
3274
- className: cn(
3275
- "w-full font-sans text-base px-3 py-2 pr-10 rounded",
3276
- "bg-tollerud-surface-raised border",
3277
- "text-tollerud-text-primary",
3278
- "placeholder:text-tollerud-text-muted",
3279
- "transition-[border-color] duration-[150ms]",
3280
- "focus:outline-none focus:border-tollerud-yellow focus:shadow-[0_0_0_1px_#E8D500]",
3281
- error ? "border-tollerud-error" : "border-tollerud-border",
3282
- className
3283
- ),
3284
- ...props
3285
- }
3286
- ),
3287
- /* @__PURE__ */ jsx(
3288
- "button",
3289
- {
3290
- type: "button",
3291
- onClick: () => setVisible((v) => !v),
3292
- "aria-label": visible ? "Hide password" : "Show password",
3293
- "aria-pressed": visible,
3294
- className: "absolute right-2.5 top-1/2 -translate-y-1/2 text-tollerud-text-muted hover:text-tollerud-text-secondary transition-colors duration-[150ms]",
3295
- children: visible ? /* @__PURE__ */ jsx(EyeOff, { size: 16 }) : /* @__PURE__ */ jsx(Eye, { size: 16 })
3296
- }
3297
- )
3298
- ] }),
3299
- error && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-error mt-0.5", children: error })
3300
- ] });
3301
- }
3302
- );
3303
- PasswordInput.displayName = "PasswordInput";
3304
- var defaultFilter = (option, query) => option.label.toLowerCase().includes(query.toLowerCase());
3305
- function Combobox({
3306
- options,
3307
- value: valueProp,
3308
- defaultValue,
3309
- onChange,
3310
- placeholder = "Search\u2026",
3311
- label,
3312
- error,
3313
- filter = defaultFilter,
3314
- className,
3315
- disabled
3316
- }) {
3317
- const id = useId();
3318
- const rootRef = useRef(null);
3319
- const isControlled = valueProp !== void 0;
3320
- const [internalValue, setInternalValue] = useState(defaultValue);
3321
- const value = isControlled ? valueProp : internalValue;
3322
- const [open, setOpen] = useState(false);
3323
- const [query, setQuery] = useState("");
3324
- const [activeIndex, setActiveIndex] = useState(0);
3325
- const selected = options.find((o) => o.value === value);
3326
- const filtered = useMemo(() => {
3327
- if (!query) return options;
3328
- return options.filter((o) => filter(o, query));
3329
- }, [options, query, filter]);
3330
- useEffect(() => {
3331
- if (!open) return;
3332
- function onClickOutside(e) {
3333
- if (rootRef.current && !rootRef.current.contains(e.target)) {
3334
- setOpen(false);
3335
- setQuery("");
3336
- }
3337
- }
3338
- function onResize() {
3339
- setOpen(false);
3340
- setQuery("");
3341
- }
3342
- document.addEventListener("mousedown", onClickOutside);
3343
- window.addEventListener("resize", onResize);
3344
- return () => {
3345
- document.removeEventListener("mousedown", onClickOutside);
3346
- window.removeEventListener("resize", onResize);
3347
- };
3348
- }, [open]);
3349
- const commit = (option) => {
3350
- if (option.disabled) return;
3351
- if (!isControlled) setInternalValue(option.value);
3352
- onChange?.(option.value);
3353
- setOpen(false);
3354
- setQuery("");
3355
- };
3356
- const onKeyDown = (e) => {
3357
- if (e.key === "ArrowDown") {
3358
- e.preventDefault();
3359
- setOpen(true);
3360
- setActiveIndex((i) => Math.min(i + 1, filtered.length - 1));
3361
- } else if (e.key === "ArrowUp") {
3362
- e.preventDefault();
3363
- setActiveIndex((i) => Math.max(i - 1, 0));
3364
- } else if (e.key === "Enter") {
3365
- e.preventDefault();
3366
- const opt = filtered[activeIndex];
3367
- if (opt) commit(opt);
3368
- } else if (e.key === "Escape") {
3369
- setOpen(false);
3370
- setQuery("");
3371
- }
3372
- };
3373
- return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn("relative flex flex-col gap-1", className), children: [
3374
- label && /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-xs font-medium text-tollerud-text-muted", children: label }),
3375
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
3376
- /* @__PURE__ */ jsx(
3377
- "input",
3378
- {
3379
- id,
3380
- role: "combobox",
3381
- "aria-expanded": open,
3382
- "aria-autocomplete": "list",
3383
- "aria-controls": `${id}-listbox`,
3384
- disabled,
3385
- value: open ? query : selected?.label ?? "",
3386
- placeholder: selected ? selected.label : placeholder,
3387
- onFocus: () => {
3388
- setOpen(true);
3389
- setActiveIndex(0);
3390
- },
3391
- onChange: (e) => {
3392
- setQuery(e.target.value);
3393
- setActiveIndex(0);
3394
- if (!open) setOpen(true);
3395
- },
3396
- onKeyDown,
3397
- className: cn(
3398
- "w-full font-sans text-base px-3 py-2 pr-9 rounded",
3399
- "bg-tollerud-surface-raised border",
3400
- "text-tollerud-text-primary placeholder:text-tollerud-text-muted",
3401
- "transition-[border-color] duration-[150ms]",
3402
- "focus:outline-none focus:border-tollerud-yellow focus:shadow-[0_0_0_1px_#E8D500]",
3403
- error ? "border-tollerud-error" : "border-tollerud-border",
3404
- disabled && "opacity-50 pointer-events-none"
3405
- )
3406
- }
3407
- ),
3408
- /* @__PURE__ */ jsx(
3409
- ChevronDown,
3410
- {
3411
- size: 15,
3412
- className: cn(
3413
- "pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-tollerud-text-muted transition-transform duration-[150ms]",
3414
- open && "rotate-180"
3415
- )
3416
- }
3417
- )
3418
- ] }),
3419
- open && /* @__PURE__ */ jsxs(
3420
- "ul",
3421
- {
3422
- id: `${id}-listbox`,
3423
- role: "listbox",
3424
- className: "absolute top-full z-20 mt-1 max-h-64 w-full overflow-auto rounded-lg border border-tollerud-border bg-tollerud-surface-overlay py-1 shadow-lg",
3425
- children: [
3426
- filtered.length === 0 && /* @__PURE__ */ jsx("li", { className: "px-3 py-2 text-sm text-tollerud-text-muted", children: "No results" }),
3427
- filtered.map((option, i) => {
3428
- const isSelected = option.value === value;
3429
- return /* @__PURE__ */ jsxs(
3430
- "li",
3431
- {
3432
- role: "option",
3433
- "aria-selected": isSelected,
3434
- onMouseDown: (e) => {
3435
- e.preventDefault();
3436
- commit(option);
3437
- },
3438
- onMouseEnter: () => setActiveIndex(i),
3439
- className: cn(
3440
- "flex items-center justify-between gap-2 px-3 py-2 text-sm cursor-pointer",
3441
- i === activeIndex ? "bg-tollerud-surface-hover text-tollerud-text-primary" : "text-tollerud-text-secondary",
3442
- option.disabled && "opacity-40 pointer-events-none"
3443
- ),
3444
- children: [
3445
- option.label,
3446
- isSelected && /* @__PURE__ */ jsx(Check, { size: 14, className: "text-tollerud-yellow" })
3447
- ]
3448
- },
3449
- option.value
3450
- );
3451
- })
3452
- ]
3453
- }
3454
- ),
3455
- error && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-error mt-0.5", children: error })
3456
- ] });
3457
- }
3458
- Combobox.displayName = "Combobox";
3459
- var defaultFormat = (date) => date.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
3460
- function isSameDay(a, b) {
3461
- return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
3462
- }
3463
- function startOfMonth(date) {
3464
- return new Date(date.getFullYear(), date.getMonth(), 1);
3465
- }
3466
- function buildCalendarGrid(monthDate) {
3467
- const first = startOfMonth(monthDate);
3468
- const startWeekday = first.getDay();
3469
- const daysInMonth = new Date(monthDate.getFullYear(), monthDate.getMonth() + 1, 0).getDate();
3470
- const cells = [];
3471
- for (let i = 0; i < startWeekday; i++) cells.push(null);
3472
- for (let d = 1; d <= daysInMonth; d++) cells.push(new Date(monthDate.getFullYear(), monthDate.getMonth(), d));
3473
- return cells;
3474
- }
3475
- var WEEKDAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
3476
- function DatePicker({
3477
- value: valueProp,
3478
- defaultValue = null,
3479
- onChange,
3480
- label,
3481
- error,
3482
- placeholder = "Select a date",
3483
- formatDate = defaultFormat,
3484
- className,
3485
- disabled
3486
- }) {
3487
- const id = useId();
3488
- const rootRef = useRef(null);
3489
- const isControlled = valueProp !== void 0;
3490
- const [internalValue, setInternalValue] = useState(defaultValue);
3491
- const value = isControlled ? valueProp ?? null : internalValue;
3492
- const [open, setOpen] = useState(false);
3493
- const [viewMonth, setViewMonth] = useState(() => startOfMonth(value ?? /* @__PURE__ */ new Date()));
3494
- const cells = useMemo(() => buildCalendarGrid(viewMonth), [viewMonth]);
3495
- useEffect(() => {
3496
- if (!open) return;
3497
- function onClickOutside(e) {
3498
- if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);
3499
- }
3500
- function onResize() {
3501
- setOpen(false);
3502
- }
3503
- document.addEventListener("mousedown", onClickOutside);
3504
- window.addEventListener("resize", onResize);
3505
- return () => {
3506
- document.removeEventListener("mousedown", onClickOutside);
3507
- window.removeEventListener("resize", onResize);
3508
- };
3509
- }, [open]);
3510
- const select = (date) => {
3511
- if (!isControlled) setInternalValue(date);
3512
- onChange?.(date);
3513
- setOpen(false);
3514
- };
3515
- return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn("relative flex flex-col gap-1", className), children: [
3516
- label && /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-xs font-medium text-tollerud-text-muted", children: label }),
3517
- /* @__PURE__ */ jsxs(
3518
- "button",
3519
- {
3520
- id,
3521
- type: "button",
3522
- disabled,
3523
- onClick: () => {
3524
- setViewMonth(startOfMonth(value ?? /* @__PURE__ */ new Date()));
3525
- setOpen((o) => !o);
3526
- },
3527
- "aria-haspopup": "dialog",
3528
- "aria-expanded": open,
3529
- className: cn(
3530
- "flex w-full items-center justify-between gap-2 rounded px-3 py-2 text-left text-base",
3531
- "bg-tollerud-surface-raised border",
3532
- "transition-[border-color] duration-[150ms]",
3533
- "focus:outline-none focus:border-tollerud-yellow focus:shadow-[0_0_0_1px_#E8D500]",
3534
- error ? "border-tollerud-error" : "border-tollerud-border",
3535
- value ? "text-tollerud-text-primary" : "text-tollerud-text-muted",
3536
- disabled && "opacity-50 pointer-events-none"
3537
- ),
3538
- children: [
3539
- /* @__PURE__ */ jsx("span", { children: value ? formatDate(value) : placeholder }),
3540
- /* @__PURE__ */ jsx(Calendar, { size: 15, className: "text-tollerud-text-muted" })
3541
- ]
3542
- }
3543
- ),
3544
- open && /* @__PURE__ */ jsxs(
3545
- "div",
3546
- {
3547
- role: "dialog",
3548
- "aria-label": "Choose date",
3549
- className: "absolute top-full z-20 mt-1 w-72 rounded-lg border border-tollerud-border bg-tollerud-surface-overlay p-3 shadow-lg",
3550
- children: [
3551
- /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
3552
- /* @__PURE__ */ jsx(
3553
- "button",
3554
- {
3555
- type: "button",
3556
- "aria-label": "Previous month",
3557
- onClick: () => setViewMonth((m) => new Date(m.getFullYear(), m.getMonth() - 1, 1)),
3558
- className: "rounded p-1 text-tollerud-text-secondary hover:bg-tollerud-surface-hover",
3559
- children: /* @__PURE__ */ jsx(ChevronLeft, { size: 16 })
3560
- }
3561
- ),
3562
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-tollerud-text-primary", children: viewMonth.toLocaleDateString(void 0, { month: "long", year: "numeric" }) }),
3563
- /* @__PURE__ */ jsx(
3564
- "button",
3565
- {
3566
- type: "button",
3567
- "aria-label": "Next month",
3568
- onClick: () => setViewMonth((m) => new Date(m.getFullYear(), m.getMonth() + 1, 1)),
3569
- className: "rounded p-1 text-tollerud-text-secondary hover:bg-tollerud-surface-hover",
3570
- children: /* @__PURE__ */ jsx(ChevronRight, { size: 16 })
3571
- }
3572
- )
3573
- ] }),
3574
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-7 gap-1 text-center", children: [
3575
- WEEKDAYS.map((d) => /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-tollerud-text-muted py-1", children: d }, d)),
3576
- cells.map((date, i) => {
3577
- if (!date) return /* @__PURE__ */ jsx("span", {}, i);
3578
- const selected = value ? isSameDay(date, value) : false;
3579
- const today = isSameDay(date, /* @__PURE__ */ new Date());
3580
- return /* @__PURE__ */ jsx(
3581
- "button",
3582
- {
3583
- type: "button",
3584
- onClick: () => select(date),
3585
- className: cn(
3586
- "h-8 w-8 rounded-full text-sm transition-colors duration-[150ms]",
3587
- selected ? "bg-tollerud-yellow text-tollerud-noir-black font-medium" : "text-tollerud-text-secondary hover:bg-tollerud-surface-hover",
3588
- !selected && today && "ring-1 ring-tollerud-yellow/40"
3589
- ),
3590
- children: date.getDate()
3591
- },
3592
- i
3593
- );
3594
- })
3595
- ] })
3596
- ]
3597
- }
3598
- ),
3599
- error && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-error mt-0.5", children: error })
3600
- ] });
3601
- }
3602
- DatePicker.displayName = "DatePicker";
3603
- function formatBytes(bytes) {
3604
- if (bytes < 1024) return `${bytes} B`;
3605
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
3606
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
3607
- }
3608
- function FileUpload({
3609
- label,
3610
- description,
3611
- error,
3612
- accept,
3613
- multiple,
3614
- onFilesChange,
3615
- className,
3616
- disabled
3617
- }) {
3618
- const id = useId();
3619
- const inputRef = useRef(null);
3620
- const [files, setFiles] = useState([]);
3621
- const [dragging, setDragging] = useState(false);
3622
- const setAndNotify = (next) => {
3623
- setFiles(next);
3624
- onFilesChange?.(next);
3625
- };
3626
- const addFiles = (incoming) => {
3627
- if (!incoming || incoming.length === 0) return;
3628
- const incomingArr = Array.from(incoming);
3629
- setAndNotify(multiple ? [...files, ...incomingArr] : [incomingArr[0]]);
3630
- };
3631
- const removeAt = (index) => {
3632
- setAndNotify(files.filter((_, i) => i !== index));
3633
- };
3634
- const onDrop = (e) => {
3635
- e.preventDefault();
3636
- setDragging(false);
3637
- if (disabled) return;
3638
- addFiles(e.dataTransfer.files);
3639
- };
3640
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", className), children: [
3641
- label && /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-xs font-medium text-tollerud-text-muted", children: label }),
3642
- /* @__PURE__ */ jsxs(
3643
- "div",
3644
- {
3645
- role: "button",
3646
- tabIndex: disabled ? -1 : 0,
3647
- "aria-disabled": disabled,
3648
- onClick: () => !disabled && inputRef.current?.click(),
3649
- onKeyDown: (e) => {
3650
- if (!disabled && (e.key === "Enter" || e.key === " ")) {
3651
- e.preventDefault();
3652
- inputRef.current?.click();
3653
- }
3654
- },
3655
- onDragOver: (e) => {
3656
- e.preventDefault();
3657
- if (!disabled) setDragging(true);
3658
- },
3659
- onDragLeave: () => setDragging(false),
3660
- onDrop,
3661
- className: cn(
3662
- "flex flex-col items-center justify-center gap-2 rounded-lg border border-dashed px-6 py-8 text-center cursor-pointer transition-colors duration-[150ms]",
3663
- dragging ? "border-tollerud-yellow bg-tollerud-yellow/[0.06]" : "border-tollerud-border bg-tollerud-surface-raised hover:border-tollerud-text-secondary",
3664
- error && "border-tollerud-error",
3665
- disabled && "opacity-50 pointer-events-none"
3666
- ),
3667
- children: [
3668
- /* @__PURE__ */ jsx(Upload, { size: 20, className: "text-tollerud-text-muted" }),
3669
- /* @__PURE__ */ jsxs("div", { className: "text-sm text-tollerud-text-secondary", children: [
3670
- /* @__PURE__ */ jsx("span", { className: "font-medium text-tollerud-yellow", children: "Click to upload" }),
3671
- " or drag and drop"
3672
- ] }),
3673
- description && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-text-muted", children: description }),
3674
- /* @__PURE__ */ jsx(
3675
- "input",
3676
- {
3677
- ref: inputRef,
3678
- id,
3679
- type: "file",
3680
- accept,
3681
- multiple,
3682
- disabled,
3683
- onChange: (e) => addFiles(e.target.files),
3684
- className: "sr-only"
3685
- }
3686
- )
3687
- ]
3688
- }
3689
- ),
3690
- files.length > 0 && /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-1.5", children: files.map((file, i) => /* @__PURE__ */ jsxs(
3691
- "li",
3692
- {
3693
- className: "flex items-center gap-2.5 rounded-md border border-tollerud-border bg-tollerud-surface-raised px-3 py-2 text-sm",
3694
- children: [
3695
- /* @__PURE__ */ jsx(File, { size: 15, className: "shrink-0 text-tollerud-text-muted" }),
3696
- /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-tollerud-text-primary", children: file.name }),
3697
- /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-tollerud-text-muted", children: formatBytes(file.size) }),
3698
- /* @__PURE__ */ jsx(
3699
- "button",
3700
- {
3701
- type: "button",
3702
- "aria-label": `Remove ${file.name}`,
3703
- onClick: () => removeAt(i),
3704
- className: "shrink-0 text-tollerud-text-muted hover:text-tollerud-text-primary transition-colors duration-[150ms]",
3705
- children: /* @__PURE__ */ jsx(X, { size: 14 })
3706
- }
3707
- )
3708
- ]
3709
- },
3710
- `${file.name}-${i}`
3711
- )) }),
3712
- error && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-error", children: error })
3713
- ] });
3714
- }
3715
- FileUpload.displayName = "FileUpload";
3716
- function TagInput({
3717
- value: valueProp,
3718
- defaultValue = [],
3719
- onChange,
3720
- label,
3721
- error,
3722
- placeholder = "Add a tag\u2026",
3723
- max,
3724
- className,
3725
- disabled
3726
- }) {
3727
- const id = useId();
3728
- const isControlled = valueProp !== void 0;
3729
- const [internalTags, setInternalTags] = useState(defaultValue);
3730
- const tags = isControlled ? valueProp : internalTags;
3731
- const [draft, setDraft] = useState("");
3732
- const setAndNotify = (next) => {
3733
- if (!isControlled) setInternalTags(next);
3734
- onChange?.(next);
3735
- };
3736
- const addTag = (raw) => {
3737
- const tag = raw.trim();
3738
- if (!tag || tags.includes(tag)) return;
3739
- if (max && tags.length >= max) return;
3740
- setAndNotify([...tags, tag]);
3741
- setDraft("");
3742
- };
3743
- const removeTag = (index) => {
3744
- setAndNotify(tags.filter((_, i) => i !== index));
3745
- };
3746
- const onKeyDown = (e) => {
3747
- if (e.key === "Enter" || e.key === ",") {
3748
- e.preventDefault();
3749
- addTag(draft);
3750
- } else if (e.key === "Backspace" && draft === "" && tags.length > 0) {
3751
- removeTag(tags.length - 1);
3752
- }
3753
- };
3754
- const atMax = max ? tags.length >= max : false;
3755
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1", className), children: [
3756
- label && /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-xs font-medium text-tollerud-text-muted", children: label }),
3757
- /* @__PURE__ */ jsxs(
3758
- "div",
3759
- {
3760
- className: cn(
3761
- "flex flex-wrap items-center gap-1.5 rounded px-2.5 py-1.5",
3762
- "bg-tollerud-surface-raised border",
3763
- "transition-[border-color] duration-[150ms]",
3764
- "focus-within:border-tollerud-yellow focus-within:shadow-[0_0_0_1px_#E8D500]",
3765
- error ? "border-tollerud-error" : "border-tollerud-border",
3766
- disabled && "opacity-50 pointer-events-none"
3767
- ),
3768
- children: [
3769
- tags.map((tag, i) => /* @__PURE__ */ jsxs(
3770
- "span",
3771
- {
3772
- className: "inline-flex items-center gap-1 rounded-full bg-tollerud-surface-hover px-2.5 py-0.5 text-xs font-medium text-tollerud-text-primary",
3773
- children: [
3774
- tag,
3775
- /* @__PURE__ */ jsx(
3776
- "button",
3777
- {
3778
- type: "button",
3779
- "aria-label": `Remove ${tag}`,
3780
- onClick: () => removeTag(i),
3781
- className: "text-tollerud-text-muted hover:text-tollerud-text-primary transition-colors duration-[150ms]",
3782
- children: /* @__PURE__ */ jsx(X, { size: 12 })
3783
- }
3784
- )
3785
- ]
3786
- },
3787
- `${tag}-${i}`
3788
- )),
3789
- /* @__PURE__ */ jsx(
3790
- "input",
3791
- {
3792
- id,
3793
- value: draft,
3794
- disabled: disabled || atMax,
3795
- onChange: (e) => setDraft(e.target.value),
3796
- onKeyDown,
3797
- onBlur: () => addTag(draft),
3798
- placeholder: atMax ? "" : placeholder,
3799
- className: cn(
3800
- "min-w-[6rem] flex-1 bg-transparent py-0.5 text-sm text-tollerud-text-primary",
3801
- "placeholder:text-tollerud-text-muted focus:outline-none"
3802
- )
3803
- }
3804
- )
3805
- ]
3806
- }
3807
- ),
3808
- error && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-error mt-0.5", children: error })
3809
- ] });
3810
- }
3811
- TagInput.displayName = "TagInput";
3812
-
3813
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, ActionDiff, ActionRow, Alert, AlertInbox, ApprovalCard, Avatar, AvatarGroup, BackupStatusPanel, Badge, BentoDashboard, Breadcrumb, Button, Card, Checkbox, CodeBlock, Combobox, CommandMenu, Container, DataTable, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Divider, DockerStackCard, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyIcon, EmptyTitle, FileUpload, Footer, FormRow, GlowCard, HostCard, IncidentCard, Input, Kbd, LogViewer, Meter, NoirGlowBackground, Pagination, Panel, PasswordInput, Pill, PricingCard, Progress, Radio, RadioGroup, RollbackPlan, Segmented, Select, ServiceHealthCard, Sheet, SheetClose, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger, Skeleton, Slider, StatCard, StatusDot, Stepper, Switch, Tabs, TabsContent, TabsList, TabsTrigger, TagInput, Textarea, Timeline, Toaster, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, buttonVariants, cn };
2
+ export { Textarea } from './chunk-HWJVRTWO.js';
3
+ export { Timeline } from './chunk-7TOT5ME3.js';
4
+ export { Toaster } from './chunk-CDI7353B.js';
5
+ export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './chunk-6UXW5YUC.js';
6
+ export { Slider } from './chunk-OONIUDST.js';
7
+ export { Sparkline } from './chunk-EVHZFYWX.js';
8
+ export { StatCard } from './chunk-LUM2YJBH.js';
9
+ export { Stepper } from './chunk-2QWKOCWF.js';
10
+ export { Switch } from './chunk-O57QMLNI.js';
11
+ export { Tabs, TabsContent, TabsList, TabsTrigger } from './chunk-T56TTOI6.js';
12
+ export { TagInput } from './chunk-6IS2AYYG.js';
13
+ export { Progress } from './chunk-5GWHUJ5D.js';
14
+ export { Radio, RadioGroup } from './chunk-6SKTH45H.js';
15
+ export { RollbackPlan } from './chunk-WDANALHD.js';
16
+ export { Select } from './chunk-GTM2DE4C.js';
17
+ export { ServiceHealthCard } from './chunk-7EP2T3OW.js';
18
+ export { Sheet, SheetClose, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger } from './chunk-ILADNTUB.js';
19
+ export { LogViewer } from './chunk-RZK2S2OO.js';
20
+ export { Meter } from './chunk-A6L5C3IJ.js';
21
+ export { Panel } from './chunk-T7EFDE2L.js';
22
+ export { PasswordInput } from './chunk-NOLWJJHT.js';
23
+ export { PricingCard } from './chunk-XR5QBVEV.js';
24
+ export { Footer } from './chunk-HYQGOC2E.js';
25
+ export { FormRow } from './chunk-Q74VRQEX.js';
26
+ export { GlowCard } from './chunk-ZOXO3G3I.js';
27
+ export { HeroBlock } from './chunk-DFM7UUKB.js';
28
+ export { NoirGlowBackground } from './chunk-CBQ63EBL.js';
29
+ export { Pill } from './chunk-ISHZ6ZPJ.js';
30
+ export { HostCard } from './chunk-DOUDJU4P.js';
31
+ export { Input } from './chunk-BPCH5LJ3.js';
32
+ export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './chunk-KI6OTVID.js';
33
+ export { Divider } from './chunk-CKNWXYMA.js';
34
+ export { DockerStackCard } from './chunk-G2VKWNZA.js';
35
+ export { Donut } from './chunk-O5SWPHUQ.js';
36
+ export { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyIcon, EmptyTitle } from './chunk-SAP7JSSO.js';
37
+ export { FeatureCard } from './chunk-NPVINX3Q.js';
38
+ export { FileUpload } from './chunk-6FUKJD3W.js';
39
+ export { Card } from './chunk-DZOBXK2S.js';
40
+ export { CodeBlock } from './chunk-DRCMGIQ6.js';
41
+ export { Combobox } from './chunk-H3ZVGTJM.js';
42
+ export { CommandMenu } from './chunk-RQ3RXKAZ.js';
43
+ export { Container } from './chunk-DNJI65VQ.js';
44
+ export { DataTable } from './chunk-3TGMGBKM.js';
45
+ export { Segmented } from './chunk-NSMU66ZX.js';
46
+ export { Skeleton } from './chunk-FGXOV2QH.js';
47
+ export { Pagination } from './chunk-RJTDQOT2.js';
48
+ export { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from './chunk-435JHF7G.js';
49
+ export { Checkbox } from './chunk-T3TQPOVM.js';
50
+ export { DatePicker } from './chunk-V3P5QLLX.js';
51
+ export { Avatar, AvatarGroup } from './chunk-DGCRHVWW.js';
52
+ export { BackupStatusPanel } from './chunk-JRFSUVSO.js';
53
+ export { StatusDot } from './chunk-NHPISZWS.js';
54
+ export { Badge } from './chunk-QEHTPQHL.js';
55
+ export { BarChart } from './chunk-4PA2ACNF.js';
56
+ export { BentoDashboard } from './chunk-PLF3BBQI.js';
57
+ export { Breadcrumb } from './chunk-7J5QXUQN.js';
58
+ export { Button, buttonVariants } from './chunk-RWJELAS6.js';
59
+ export { CTABand } from './chunk-VTRUUT5K.js';
60
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './chunk-YYWODLER.js';
61
+ export { ActionDiff } from './chunk-3XTZPDNV.js';
62
+ export { ActionRow } from './chunk-OGVSZ7NV.js';
63
+ export { Kbd } from './chunk-HWAWUEHC.js';
64
+ export { Alert } from './chunk-ANW6J6PV.js';
65
+ export { AlertInbox } from './chunk-AZADSX4Z.js';
66
+ export { IncidentCard } from './chunk-EN4OJCEF.js';
67
+ export { ApprovalCard } from './chunk-APFFKNPS.js';
68
+ export { AreaChart } from './chunk-6PZKU6ZL.js';
69
+ export { cn } from './chunk-WSQNPRGN.js';
3814
70
  //# sourceMappingURL=index.js.map
3815
71
  //# sourceMappingURL=index.js.map