@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
@@ -0,0 +1,65 @@
1
+ 'use client';
2
+ import { cn } from './chunk-WSQNPRGN.js';
3
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
4
+ import { forwardRef } from 'react';
5
+ import { jsx } from 'react/jsx-runtime';
6
+
7
+ var DropdownMenu = DropdownMenuPrimitive.Root;
8
+ var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
9
+ var DropdownMenuContent = forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(
10
+ DropdownMenuPrimitive.Content,
11
+ {
12
+ ref,
13
+ sideOffset,
14
+ className: cn(
15
+ "z-50 min-w-[9rem] overflow-hidden rounded-lg border p-1 shadow-md",
16
+ "bg-tollerud-noir-850 border-tollerud-border/30 text-tollerud-text-primary",
17
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
18
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
19
+ "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
20
+ "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
21
+ "data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
22
+ className
23
+ ),
24
+ ...props
25
+ }
26
+ ) }));
27
+ DropdownMenuContent.displayName = "DropdownMenuContent";
28
+ var DropdownMenuItem = forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(
29
+ DropdownMenuPrimitive.Item,
30
+ {
31
+ ref,
32
+ className: cn(
33
+ "relative flex cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm outline-none",
34
+ "text-tollerud-text-secondary data-[highlighted]:text-tollerud-text-primary",
35
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
36
+ "data-[highlighted]:bg-tollerud-surface-raised",
37
+ inset && "pl-8",
38
+ className
39
+ ),
40
+ ...props
41
+ }
42
+ ));
43
+ DropdownMenuItem.displayName = "DropdownMenuItem";
44
+ var DropdownMenuSeparator = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
45
+ DropdownMenuPrimitive.Separator,
46
+ {
47
+ ref,
48
+ className: cn("-mx-1 my-1 h-px bg-tollerud-border/30", className),
49
+ ...props
50
+ }
51
+ ));
52
+ DropdownMenuSeparator.displayName = "DropdownMenuSeparator";
53
+ var DropdownMenuLabel = forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(
54
+ DropdownMenuPrimitive.Label,
55
+ {
56
+ ref,
57
+ className: cn("px-2 py-1.5 text-xs font-semibold text-tollerud-text-muted", inset && "pl-8", className),
58
+ ...props
59
+ }
60
+ ));
61
+ DropdownMenuLabel.displayName = "DropdownMenuLabel";
62
+
63
+ export { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger };
64
+ //# sourceMappingURL=chunk-435JHF7G.js.map
65
+ //# sourceMappingURL=chunk-435JHF7G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../components/DropdownMenu.tsx"],"names":[],"mappings":";;;;;AAQA,IAAM,YAAA,GAAqC,qBAAA,CAAA;AAC3C,IAAM,mBAAA,GAA4C,qBAAA,CAAA;AAElD,IAAM,mBAAA,GAAsB,UAAA,CAG1B,CAAC,EAAE,SAAA,EAAW,UAAA,GAAa,CAAA,EAAG,GAAG,KAAA,EAAM,EAAG,GAAA,qBAC1C,GAAA,CAAuB,8BAAtB,EACC,QAAA,kBAAA,GAAA;AAAA,EAAuB,qBAAA,CAAA,OAAA;AAAA,EAAtB;AAAA,IACC,GAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA,EAAW,EAAA;AAAA,MACT,mEAAA;AAAA,MACA,2EAAA;AAAA,MACA,8DAAA;AAAA,MACA,4DAAA;AAAA,MACA,8DAAA;AAAA,MACA,+EAAA;AAAA,MACA,+EAAA;AAAA,MACA;AAAA,KACF;AAAA,IACC,GAAG;AAAA;AACN,CAAA,EACF,CACD;AACD,mBAAA,CAAoB,WAAA,GAAc,qBAAA;AAElC,IAAM,gBAAA,GAAmB,WAKvB,CAAC,EAAE,WAAW,KAAA,EAAO,GAAG,KAAA,EAAM,EAAG,GAAA,qBACjC,GAAA;AAAA,EAAuB,qBAAA,CAAA,IAAA;AAAA,EAAtB;AAAA,IACC,GAAA;AAAA,IACA,SAAA,EAAW,EAAA;AAAA,MACT,mGAAA;AAAA,MACA,4EAAA;AAAA,MACA,gEAAA;AAAA,MACA,+CAAA;AAAA,MACA,KAAA,IAAS,MAAA;AAAA,MACT;AAAA,KACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,gBAAA,CAAiB,WAAA,GAAc,kBAAA;AAE/B,IAAM,qBAAA,GAAwB,WAG5B,CAAC,EAAE,WAAW,GAAG,KAAA,IAAS,GAAA,qBAC1B,GAAA;AAAA,EAAuB,qBAAA,CAAA,SAAA;AAAA,EAAtB;AAAA,IACC,GAAA;AAAA,IACA,SAAA,EAAW,EAAA,CAAG,uCAAA,EAAyC,SAAS,CAAA;AAAA,IAC/D,GAAG;AAAA;AACN,CACD;AACD,qBAAA,CAAsB,WAAA,GAAc,uBAAA;AAEpC,IAAM,iBAAA,GAAoB,WAKxB,CAAC,EAAE,WAAW,KAAA,EAAO,GAAG,KAAA,EAAM,EAAG,GAAA,qBACjC,GAAA;AAAA,EAAuB,qBAAA,CAAA,KAAA;AAAA,EAAtB;AAAA,IACC,GAAA;AAAA,IACA,SAAA,EAAW,EAAA,CAAG,4DAAA,EAA8D,KAAA,IAAS,QAAQ,SAAS,CAAA;AAAA,IACrG,GAAG;AAAA;AACN,CACD;AACD,iBAAA,CAAkB,WAAA,GAAc,mBAAA","file":"chunk-435JHF7G.js","sourcesContent":["'use client'\n\nimport * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'\nimport { forwardRef } from 'react'\nimport { cn } from '@/lib/utils'\n\n/* ──────────────────── DropdownMenu ──────────────────── */\n\nconst DropdownMenu = DropdownMenuPrimitive.Root\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger\n\nconst DropdownMenuContent = forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n 'z-50 min-w-[9rem] overflow-hidden rounded-lg border p-1 shadow-md',\n 'bg-tollerud-noir-850 border-tollerud-border/30 text-tollerud-text-primary',\n 'data-[state=open]:animate-in data-[state=closed]:animate-out',\n 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',\n 'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2',\n 'data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',\n className\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n))\nDropdownMenuContent.displayName = 'DropdownMenuContent'\n\nconst DropdownMenuItem = forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm outline-none',\n 'text-tollerud-text-secondary data-[highlighted]:text-tollerud-text-primary',\n 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n 'data-[highlighted]:bg-tollerud-surface-raised',\n inset && 'pl-8',\n className\n )}\n {...props}\n />\n))\nDropdownMenuItem.displayName = 'DropdownMenuItem'\n\nconst DropdownMenuSeparator = forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn('-mx-1 my-1 h-px bg-tollerud-border/30', className)}\n {...props}\n />\n))\nDropdownMenuSeparator.displayName = 'DropdownMenuSeparator'\n\nconst DropdownMenuLabel = forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn('px-2 py-1.5 text-xs font-semibold text-tollerud-text-muted', inset && 'pl-8', className)}\n {...props}\n />\n))\nDropdownMenuLabel.displayName = 'DropdownMenuLabel'\n\nexport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuLabel,\n}"]}
@@ -0,0 +1,52 @@
1
+ 'use client';
2
+ import { cn } from './chunk-WSQNPRGN.js';
3
+ import { forwardRef } from 'react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ var BarChart = forwardRef(
7
+ ({ className, data, height = 180, ...props }, ref) => {
8
+ const max = Math.max(...data.map((d) => d.value), 1);
9
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("w-full", className), ...props, children: [
10
+ /* @__PURE__ */ jsx(
11
+ "div",
12
+ {
13
+ className: "flex items-end gap-2.5 px-1",
14
+ style: { height, borderBottom: "1px solid var(--chart-grid)" },
15
+ children: data.map((d, i) => /* @__PURE__ */ jsxs(
16
+ "div",
17
+ {
18
+ className: "flex flex-1 flex-col items-center justify-end h-full",
19
+ children: [
20
+ /* @__PURE__ */ jsx("span", { className: "mb-1.5 font-mono text-[11px] text-tollerud-text-secondary", children: d.value }),
21
+ /* @__PURE__ */ jsx(
22
+ "div",
23
+ {
24
+ className: cn(
25
+ "w-full max-w-[38px] rounded-t-[3px] transition-[height] duration-500 ease-out",
26
+ d.accent ? "bg-tollerud-yellow" : "bg-tollerud-noir-600"
27
+ ),
28
+ style: { height: `${d.value / max * 100}%` }
29
+ }
30
+ )
31
+ ]
32
+ },
33
+ i
34
+ ))
35
+ }
36
+ ),
37
+ /* @__PURE__ */ jsx("div", { className: "flex gap-2.5 px-1 pt-2", children: data.map((d, i) => /* @__PURE__ */ jsx(
38
+ "div",
39
+ {
40
+ className: "flex-1 text-center text-[11px] text-tollerud-text-muted",
41
+ children: d.label
42
+ },
43
+ i
44
+ )) })
45
+ ] });
46
+ }
47
+ );
48
+ BarChart.displayName = "BarChart";
49
+
50
+ export { BarChart };
51
+ //# sourceMappingURL=chunk-4PA2ACNF.js.map
52
+ //# sourceMappingURL=chunk-4PA2ACNF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../components/BarChart.tsx"],"names":[],"mappings":";;;;AAcA,IAAM,QAAA,GAAW,UAAA;AAAA,EACf,CAAC,EAAE,SAAA,EAAW,IAAA,EAAM,SAAS,GAAA,EAAK,GAAG,KAAA,EAAM,EAAG,GAAA,KAAQ;AACpD,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,GAAG,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,CAAA,EAAG,CAAC,CAAA;AAEnD,IAAA,uBACE,IAAA,CAAC,SAAI,GAAA,EAAU,SAAA,EAAW,GAAG,QAAA,EAAU,SAAS,CAAA,EAAI,GAAG,KAAA,EACrD,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAU,6BAAA;AAAA,UACV,KAAA,EAAO,EAAE,MAAA,EAAQ,YAAA,EAAc,6BAAA,EAA8B;AAAA,UAE5D,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,qBACZ,IAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cAEC,SAAA,EAAU,sDAAA;AAAA,cAEV,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,2DAAA,EACb,QAAA,EAAA,CAAA,CAAE,KAAA,EACL,CAAA;AAAA,gCACA,GAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAW,EAAA;AAAA,sBACT,+EAAA;AAAA,sBACA,CAAA,CAAE,SAAS,oBAAA,GAAuB;AAAA,qBACpC;AAAA,oBACA,KAAA,EAAO,EAAE,MAAA,EAAQ,CAAA,EAAI,EAAE,KAAA,GAAQ,GAAA,GAAO,GAAG,CAAA,CAAA,CAAA;AAAI;AAAA;AAC/C;AAAA,aAAA;AAAA,YAZK;AAAA,WAcR;AAAA;AAAA,OACH;AAAA,sBACA,GAAA,CAAC,SAAI,SAAA,EAAU,wBAAA,EACZ,eAAK,GAAA,CAAI,CAAC,GAAG,CAAA,qBACZ,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UAEC,SAAA,EAAU,yDAAA;AAAA,UAET,QAAA,EAAA,CAAA,CAAE;AAAA,SAAA;AAAA,QAHE;AAAA,OAKR,CAAA,EACH;AAAA,KAAA,EACF,CAAA;AAAA,EAEJ;AACF;AACA,QAAA,CAAS,WAAA,GAAc,UAAA","file":"chunk-4PA2ACNF.js","sourcesContent":["import { type HTMLAttributes, forwardRef } from 'react'\nimport { cn } from '@/lib/utils'\n\nexport interface BarChartDatum {\n label: string\n value: number\n accent?: boolean\n}\n\nexport interface BarChartProps extends HTMLAttributes<HTMLDivElement> {\n data: BarChartDatum[]\n height?: number\n}\n\nconst BarChart = forwardRef<HTMLDivElement, BarChartProps>(\n ({ className, data, height = 180, ...props }, ref) => {\n const max = Math.max(...data.map((d) => d.value), 1)\n\n return (\n <div ref={ref} className={cn('w-full', className)} {...props}>\n <div\n className=\"flex items-end gap-2.5 px-1\"\n style={{ height, borderBottom: '1px solid var(--chart-grid)' }}\n >\n {data.map((d, i) => (\n <div\n key={i}\n className=\"flex flex-1 flex-col items-center justify-end h-full\"\n >\n <span className=\"mb-1.5 font-mono text-[11px] text-tollerud-text-secondary\">\n {d.value}\n </span>\n <div\n className={cn(\n 'w-full max-w-[38px] rounded-t-[3px] transition-[height] duration-500 ease-out',\n d.accent ? 'bg-tollerud-yellow' : 'bg-tollerud-noir-600'\n )}\n style={{ height: `${(d.value / max) * 100}%` }}\n />\n </div>\n ))}\n </div>\n <div className=\"flex gap-2.5 px-1 pt-2\">\n {data.map((d, i) => (\n <div\n key={i}\n className=\"flex-1 text-center text-[11px] text-tollerud-text-muted\"\n >\n {d.label}\n </div>\n ))}\n </div>\n </div>\n )\n }\n)\nBarChart.displayName = 'BarChart'\n\nexport { BarChart }\n"]}
@@ -0,0 +1,29 @@
1
+ 'use client';
2
+ import { cn } from './chunk-WSQNPRGN.js';
3
+ import * as React from 'react';
4
+ import * as ProgressPrimitive from '@radix-ui/react-progress';
5
+ import { jsx } from 'react/jsx-runtime';
6
+
7
+ var Progress = React.forwardRef(({ className, value, ...props }, ref) => /* @__PURE__ */ jsx(
8
+ ProgressPrimitive.Root,
9
+ {
10
+ ref,
11
+ className: cn(
12
+ "relative h-2 w-full overflow-hidden rounded-full bg-tollerud-noir-800",
13
+ className
14
+ ),
15
+ ...props,
16
+ children: /* @__PURE__ */ jsx(
17
+ ProgressPrimitive.Indicator,
18
+ {
19
+ className: "h-full w-full flex-1 rounded-full bg-tollerud-yellow transition-all duration-300 ease-in-out",
20
+ style: { transform: `translateX(-${100 - (value || 0)}%)` }
21
+ }
22
+ )
23
+ }
24
+ ));
25
+ Progress.displayName = "Progress";
26
+
27
+ export { Progress };
28
+ //# sourceMappingURL=chunk-5GWHUJ5D.js.map
29
+ //# sourceMappingURL=chunk-5GWHUJ5D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../components/Progress.tsx"],"names":[],"mappings":";;;;;AAMA,IAAM,QAAA,GAAiB,iBAGrB,CAAC,EAAE,WAAW,KAAA,EAAO,GAAG,KAAA,EAAM,EAAG,GAAA,qBACjC,GAAA;AAAA,EAAmB,iBAAA,CAAA,IAAA;AAAA,EAAlB;AAAA,IACC,GAAA;AAAA,IACA,SAAA,EAAW,EAAA;AAAA,MACT,uEAAA;AAAA,MACA;AAAA,KACF;AAAA,IACC,GAAG,KAAA;AAAA,IAEJ,QAAA,kBAAA,GAAA;AAAA,MAAmB,iBAAA,CAAA,SAAA;AAAA,MAAlB;AAAA,QACC,SAAA,EAAU,8FAAA;AAAA,QACV,OAAO,EAAE,SAAA,EAAW,eAAe,GAAA,IAAO,KAAA,IAAS,EAAE,CAAA,EAAA,CAAA;AAAK;AAAA;AAC5D;AACF,CACD;AACD,QAAA,CAAS,WAAA,GAAc,UAAA","file":"chunk-5GWHUJ5D.js","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as ProgressPrimitive from '@radix-ui/react-progress'\nimport { cn } from '@/lib/utils'\n\nconst Progress = React.forwardRef<\n React.ComponentRef<typeof ProgressPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>\n>(({ className, value, ...props }, ref) => (\n <ProgressPrimitive.Root\n ref={ref}\n className={cn(\n 'relative h-2 w-full overflow-hidden rounded-full bg-tollerud-noir-800',\n className\n )}\n {...props}\n >\n <ProgressPrimitive.Indicator\n className=\"h-full w-full flex-1 rounded-full bg-tollerud-yellow transition-all duration-300 ease-in-out\"\n style={{ transform: `translateX(-${100 - (value || 0)}%)` }}\n />\n </ProgressPrimitive.Root>\n))\nProgress.displayName = 'Progress'\n\nexport { Progress }"]}
@@ -0,0 +1,123 @@
1
+ 'use client';
2
+ import { cn } from './chunk-WSQNPRGN.js';
3
+ import { useId, useRef, useState } from 'react';
4
+ import { Upload, File, X } from 'lucide-react';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ function formatBytes(bytes) {
8
+ if (bytes < 1024) return `${bytes} B`;
9
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
10
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
11
+ }
12
+ function FileUpload({
13
+ label,
14
+ description,
15
+ error,
16
+ accept,
17
+ multiple,
18
+ onFilesChange,
19
+ className,
20
+ disabled
21
+ }) {
22
+ const id = useId();
23
+ const inputRef = useRef(null);
24
+ const [files, setFiles] = useState([]);
25
+ const [dragging, setDragging] = useState(false);
26
+ const setAndNotify = (next) => {
27
+ setFiles(next);
28
+ onFilesChange?.(next);
29
+ };
30
+ const addFiles = (incoming) => {
31
+ if (!incoming || incoming.length === 0) return;
32
+ const incomingArr = Array.from(incoming);
33
+ setAndNotify(multiple ? [...files, ...incomingArr] : [incomingArr[0]]);
34
+ };
35
+ const removeAt = (index) => {
36
+ setAndNotify(files.filter((_, i) => i !== index));
37
+ };
38
+ const onDrop = (e) => {
39
+ e.preventDefault();
40
+ setDragging(false);
41
+ if (disabled) return;
42
+ addFiles(e.dataTransfer.files);
43
+ };
44
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", className), children: [
45
+ label && /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-xs font-medium text-tollerud-text-muted", children: label }),
46
+ /* @__PURE__ */ jsxs(
47
+ "div",
48
+ {
49
+ role: "button",
50
+ tabIndex: disabled ? -1 : 0,
51
+ "aria-disabled": disabled,
52
+ onClick: () => !disabled && inputRef.current?.click(),
53
+ onKeyDown: (e) => {
54
+ if (!disabled && (e.key === "Enter" || e.key === " ")) {
55
+ e.preventDefault();
56
+ inputRef.current?.click();
57
+ }
58
+ },
59
+ onDragOver: (e) => {
60
+ e.preventDefault();
61
+ if (!disabled) setDragging(true);
62
+ },
63
+ onDragLeave: () => setDragging(false),
64
+ onDrop,
65
+ className: cn(
66
+ "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]",
67
+ dragging ? "border-tollerud-yellow bg-tollerud-yellow/[0.06]" : "border-tollerud-border bg-tollerud-surface-raised hover:border-tollerud-text-secondary",
68
+ error && "border-tollerud-error",
69
+ disabled && "opacity-50 pointer-events-none"
70
+ ),
71
+ children: [
72
+ /* @__PURE__ */ jsx(Upload, { size: 20, className: "text-tollerud-text-muted" }),
73
+ /* @__PURE__ */ jsxs("div", { className: "text-sm text-tollerud-text-secondary", children: [
74
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-tollerud-yellow", children: "Click to upload" }),
75
+ " or drag and drop"
76
+ ] }),
77
+ description && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-text-muted", children: description }),
78
+ /* @__PURE__ */ jsx(
79
+ "input",
80
+ {
81
+ ref: inputRef,
82
+ id,
83
+ type: "file",
84
+ accept,
85
+ multiple,
86
+ disabled,
87
+ onChange: (e) => addFiles(e.target.files),
88
+ className: "sr-only"
89
+ }
90
+ )
91
+ ]
92
+ }
93
+ ),
94
+ files.length > 0 && /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-1.5", children: files.map((file, i) => /* @__PURE__ */ jsxs(
95
+ "li",
96
+ {
97
+ className: "flex items-center gap-2.5 rounded-md border border-tollerud-border bg-tollerud-surface-raised px-3 py-2 text-sm",
98
+ children: [
99
+ /* @__PURE__ */ jsx(File, { size: 15, className: "shrink-0 text-tollerud-text-muted" }),
100
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-tollerud-text-primary", children: file.name }),
101
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-tollerud-text-muted", children: formatBytes(file.size) }),
102
+ /* @__PURE__ */ jsx(
103
+ "button",
104
+ {
105
+ type: "button",
106
+ "aria-label": `Remove ${file.name}`,
107
+ onClick: () => removeAt(i),
108
+ className: "shrink-0 text-tollerud-text-muted hover:text-tollerud-text-primary transition-colors duration-[150ms]",
109
+ children: /* @__PURE__ */ jsx(X, { size: 14 })
110
+ }
111
+ )
112
+ ]
113
+ },
114
+ `${file.name}-${i}`
115
+ )) }),
116
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-error", children: error })
117
+ ] });
118
+ }
119
+ FileUpload.displayName = "FileUpload";
120
+
121
+ export { FileUpload };
122
+ //# sourceMappingURL=chunk-6FUKJD3W.js.map
123
+ //# sourceMappingURL=chunk-6FUKJD3W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../components/FileUpload.tsx"],"names":["FileIcon"],"mappings":"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","file":"chunk-6FUKJD3W.js","sourcesContent":["'use client'\n\nimport { type DragEvent, useId, useRef, useState } from 'react'\nimport { Upload, X, File as FileIcon } from 'lucide-react'\nimport { cn } from '@/lib/utils'\n\nexport interface FileUploadProps {\n label?: string\n description?: React.ReactNode\n error?: string\n /** Forwarded to the underlying `<input accept>` */\n accept?: string\n multiple?: boolean\n /** Called whenever the selected file list changes */\n onFilesChange?: (files: File[]) => void\n className?: string\n disabled?: boolean\n}\n\nfunction formatBytes(bytes: number) {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nfunction FileUpload({\n label,\n description,\n error,\n accept,\n multiple,\n onFilesChange,\n className,\n disabled,\n}: FileUploadProps) {\n const id = useId()\n const inputRef = useRef<HTMLInputElement>(null)\n const [files, setFiles] = useState<File[]>([])\n const [dragging, setDragging] = useState(false)\n\n const setAndNotify = (next: File[]) => {\n setFiles(next)\n onFilesChange?.(next)\n }\n\n const addFiles = (incoming: FileList | null) => {\n if (!incoming || incoming.length === 0) return\n const incomingArr = Array.from(incoming)\n setAndNotify(multiple ? [...files, ...incomingArr] : [incomingArr[0]!])\n }\n\n const removeAt = (index: number) => {\n setAndNotify(files.filter((_, i) => i !== index))\n }\n\n const onDrop = (e: DragEvent<HTMLDivElement>) => {\n e.preventDefault()\n setDragging(false)\n if (disabled) return\n addFiles(e.dataTransfer.files)\n }\n\n return (\n <div className={cn('flex flex-col gap-1.5', className)}>\n {label && (\n <label htmlFor={id} className=\"text-xs font-medium text-tollerud-text-muted\">\n {label}\n </label>\n )}\n\n <div\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n aria-disabled={disabled}\n onClick={() => !disabled && inputRef.current?.click()}\n onKeyDown={(e) => {\n if (!disabled && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault()\n inputRef.current?.click()\n }\n }}\n onDragOver={(e) => {\n e.preventDefault()\n if (!disabled) setDragging(true)\n }}\n onDragLeave={() => setDragging(false)}\n onDrop={onDrop}\n className={cn(\n '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]',\n dragging\n ? 'border-tollerud-yellow bg-tollerud-yellow/[0.06]'\n : 'border-tollerud-border bg-tollerud-surface-raised hover:border-tollerud-text-secondary',\n error && 'border-tollerud-error',\n disabled && 'opacity-50 pointer-events-none'\n )}\n >\n <Upload size={20} className=\"text-tollerud-text-muted\" />\n <div className=\"text-sm text-tollerud-text-secondary\">\n <span className=\"font-medium text-tollerud-yellow\">Click to upload</span> or drag and drop\n </div>\n {description && <p className=\"text-xs text-tollerud-text-muted\">{description}</p>}\n <input\n ref={inputRef}\n id={id}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n disabled={disabled}\n onChange={(e) => addFiles(e.target.files)}\n className=\"sr-only\"\n />\n </div>\n\n {files.length > 0 && (\n <ul className=\"flex flex-col gap-1.5\">\n {files.map((file, i) => (\n <li\n key={`${file.name}-${i}`}\n className=\"flex items-center gap-2.5 rounded-md border border-tollerud-border bg-tollerud-surface-raised px-3 py-2 text-sm\"\n >\n <FileIcon size={15} className=\"shrink-0 text-tollerud-text-muted\" />\n <span className=\"flex-1 truncate text-tollerud-text-primary\">{file.name}</span>\n <span className=\"shrink-0 text-xs text-tollerud-text-muted\">{formatBytes(file.size)}</span>\n <button\n type=\"button\"\n aria-label={`Remove ${file.name}`}\n onClick={() => removeAt(i)}\n className=\"shrink-0 text-tollerud-text-muted hover:text-tollerud-text-primary transition-colors duration-[150ms]\"\n >\n <X size={14} />\n </button>\n </li>\n ))}\n </ul>\n )}\n\n {error && <p className=\"text-xs text-tollerud-error\">{error}</p>}\n </div>\n )\n}\nFileUpload.displayName = 'FileUpload'\n\nexport { FileUpload }\n"]}
@@ -0,0 +1,106 @@
1
+ 'use client';
2
+ import { cn } from './chunk-WSQNPRGN.js';
3
+ import { useId, useState } from 'react';
4
+ import { X } from 'lucide-react';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ function TagInput({
8
+ value: valueProp,
9
+ defaultValue = [],
10
+ onChange,
11
+ label,
12
+ error,
13
+ placeholder = "Add a tag\u2026",
14
+ max,
15
+ className,
16
+ disabled
17
+ }) {
18
+ const id = useId();
19
+ const isControlled = valueProp !== void 0;
20
+ const [internalTags, setInternalTags] = useState(defaultValue);
21
+ const tags = isControlled ? valueProp : internalTags;
22
+ const [draft, setDraft] = useState("");
23
+ const setAndNotify = (next) => {
24
+ if (!isControlled) setInternalTags(next);
25
+ onChange?.(next);
26
+ };
27
+ const addTag = (raw) => {
28
+ const tag = raw.trim();
29
+ if (!tag || tags.includes(tag)) return;
30
+ if (max && tags.length >= max) return;
31
+ setAndNotify([...tags, tag]);
32
+ setDraft("");
33
+ };
34
+ const removeTag = (index) => {
35
+ setAndNotify(tags.filter((_, i) => i !== index));
36
+ };
37
+ const onKeyDown = (e) => {
38
+ if (e.key === "Enter" || e.key === ",") {
39
+ e.preventDefault();
40
+ addTag(draft);
41
+ } else if (e.key === "Backspace" && draft === "" && tags.length > 0) {
42
+ removeTag(tags.length - 1);
43
+ }
44
+ };
45
+ const atMax = max ? tags.length >= max : false;
46
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1", className), children: [
47
+ label && /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-xs font-medium text-tollerud-text-muted", children: label }),
48
+ /* @__PURE__ */ jsxs(
49
+ "div",
50
+ {
51
+ className: cn(
52
+ "flex flex-wrap items-center gap-1.5 rounded px-2.5 py-1.5",
53
+ "bg-tollerud-surface-raised border",
54
+ "transition-[border-color] duration-[150ms]",
55
+ "focus-within:border-tollerud-yellow focus-within:shadow-[0_0_0_1px_#E8D500]",
56
+ error ? "border-tollerud-error" : "border-tollerud-border",
57
+ disabled && "opacity-50 pointer-events-none"
58
+ ),
59
+ children: [
60
+ tags.map((tag, i) => /* @__PURE__ */ jsxs(
61
+ "span",
62
+ {
63
+ 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",
64
+ children: [
65
+ tag,
66
+ /* @__PURE__ */ jsx(
67
+ "button",
68
+ {
69
+ type: "button",
70
+ "aria-label": `Remove ${tag}`,
71
+ onClick: () => removeTag(i),
72
+ className: "text-tollerud-text-muted hover:text-tollerud-text-primary transition-colors duration-[150ms]",
73
+ children: /* @__PURE__ */ jsx(X, { size: 12 })
74
+ }
75
+ )
76
+ ]
77
+ },
78
+ `${tag}-${i}`
79
+ )),
80
+ /* @__PURE__ */ jsx(
81
+ "input",
82
+ {
83
+ id,
84
+ value: draft,
85
+ disabled: disabled || atMax,
86
+ onChange: (e) => setDraft(e.target.value),
87
+ onKeyDown,
88
+ onBlur: () => addTag(draft),
89
+ placeholder: atMax ? "" : placeholder,
90
+ className: cn(
91
+ "min-w-[6rem] flex-1 bg-transparent py-0.5 text-sm text-tollerud-text-primary",
92
+ "placeholder:text-tollerud-text-muted focus:outline-none"
93
+ )
94
+ }
95
+ )
96
+ ]
97
+ }
98
+ ),
99
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-error mt-0.5", children: error })
100
+ ] });
101
+ }
102
+ TagInput.displayName = "TagInput";
103
+
104
+ export { TagInput };
105
+ //# sourceMappingURL=chunk-6IS2AYYG.js.map
106
+ //# sourceMappingURL=chunk-6IS2AYYG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../components/TagInput.tsx"],"names":[],"mappings":"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","file":"chunk-6IS2AYYG.js","sourcesContent":["'use client'\n\nimport { type KeyboardEvent, useId, useState } from 'react'\nimport { X } from 'lucide-react'\nimport { cn } from '@/lib/utils'\n\nexport interface TagInputProps {\n value?: string[]\n defaultValue?: string[]\n onChange?: (tags: string[]) => void\n label?: string\n error?: string\n placeholder?: string\n /** Maximum number of tags allowed */\n max?: number\n className?: string\n disabled?: boolean\n}\n\nfunction TagInput({\n value: valueProp,\n defaultValue = [],\n onChange,\n label,\n error,\n placeholder = 'Add a tag…',\n max,\n className,\n disabled,\n}: TagInputProps) {\n const id = useId()\n const isControlled = valueProp !== undefined\n const [internalTags, setInternalTags] = useState<string[]>(defaultValue)\n const tags = isControlled ? valueProp : internalTags\n const [draft, setDraft] = useState('')\n\n const setAndNotify = (next: string[]) => {\n if (!isControlled) setInternalTags(next)\n onChange?.(next)\n }\n\n const addTag = (raw: string) => {\n const tag = raw.trim()\n if (!tag || tags.includes(tag)) return\n if (max && tags.length >= max) return\n setAndNotify([...tags, tag])\n setDraft('')\n }\n\n const removeTag = (index: number) => {\n setAndNotify(tags.filter((_, i) => i !== index))\n }\n\n const onKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter' || e.key === ',') {\n e.preventDefault()\n addTag(draft)\n } else if (e.key === 'Backspace' && draft === '' && tags.length > 0) {\n removeTag(tags.length - 1)\n }\n }\n\n const atMax = max ? tags.length >= max : false\n\n return (\n <div className={cn('flex flex-col gap-1', className)}>\n {label && (\n <label htmlFor={id} className=\"text-xs font-medium text-tollerud-text-muted\">\n {label}\n </label>\n )}\n <div\n className={cn(\n 'flex flex-wrap items-center gap-1.5 rounded px-2.5 py-1.5',\n 'bg-tollerud-surface-raised border',\n 'transition-[border-color] duration-[150ms]',\n 'focus-within:border-tollerud-yellow focus-within:shadow-[0_0_0_1px_#E8D500]',\n error ? 'border-tollerud-error' : 'border-tollerud-border',\n disabled && 'opacity-50 pointer-events-none'\n )}\n >\n {tags.map((tag, i) => (\n <span\n key={`${tag}-${i}`}\n 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\"\n >\n {tag}\n <button\n type=\"button\"\n aria-label={`Remove ${tag}`}\n onClick={() => removeTag(i)}\n className=\"text-tollerud-text-muted hover:text-tollerud-text-primary transition-colors duration-[150ms]\"\n >\n <X size={12} />\n </button>\n </span>\n ))}\n <input\n id={id}\n value={draft}\n disabled={disabled || atMax}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={onKeyDown}\n onBlur={() => addTag(draft)}\n placeholder={atMax ? '' : placeholder}\n className={cn(\n 'min-w-[6rem] flex-1 bg-transparent py-0.5 text-sm text-tollerud-text-primary',\n 'placeholder:text-tollerud-text-muted focus:outline-none'\n )}\n />\n </div>\n {error && <p className=\"text-xs text-tollerud-error mt-0.5\">{error}</p>}\n </div>\n )\n}\nTagInput.displayName = 'TagInput'\n\nexport { TagInput }\n"]}
@@ -0,0 +1,78 @@
1
+ 'use client';
2
+ import { cn } from './chunk-WSQNPRGN.js';
3
+ import { forwardRef, useId } from 'react';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ var AreaChart = forwardRef(
7
+ ({ className, data, height = 180, ...props }, ref) => {
8
+ const gradientId = useId().replace(/:/g, "");
9
+ const w = 520;
10
+ const h = height;
11
+ const pad = 8;
12
+ const max = Math.max(...data) * 1.1;
13
+ const min = Math.min(...data, 0);
14
+ const span = Math.max(data.length - 1, 1);
15
+ const x = (i) => pad + i / span * (w - pad * 2);
16
+ const y = (v) => h - pad - (v - min) / (max - min || 1) * (h - pad * 2);
17
+ const line = data.map((v, i) => `${x(i)},${y(v)}`).join(" ");
18
+ const area = `${pad},${h - pad} ${line} ${w - pad},${h - pad}`;
19
+ return /* @__PURE__ */ jsx("div", { ref, className: cn("w-full", className), ...props, children: /* @__PURE__ */ jsxs(
20
+ "svg",
21
+ {
22
+ viewBox: `0 0 ${w} ${h}`,
23
+ className: "w-full",
24
+ style: { height },
25
+ preserveAspectRatio: "none",
26
+ role: "img",
27
+ "aria-hidden": "true",
28
+ children: [
29
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
30
+ /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "#E8D500", stopOpacity: "0.30" }),
31
+ /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "#E8D500", stopOpacity: "0" })
32
+ ] }) }),
33
+ [0.25, 0.5, 0.75].map((g, i) => /* @__PURE__ */ jsx(
34
+ "line",
35
+ {
36
+ x1: pad,
37
+ x2: w - pad,
38
+ y1: h * g,
39
+ y2: h * g,
40
+ stroke: "var(--chart-grid)",
41
+ strokeWidth: "1"
42
+ },
43
+ i
44
+ )),
45
+ /* @__PURE__ */ jsx("polygon", { points: area, fill: `url(#${gradientId})` }),
46
+ /* @__PURE__ */ jsx(
47
+ "polyline",
48
+ {
49
+ points: line,
50
+ fill: "none",
51
+ stroke: "#E8D500",
52
+ strokeWidth: "2",
53
+ strokeLinecap: "round",
54
+ strokeLinejoin: "round"
55
+ }
56
+ ),
57
+ data.map((v, i) => /* @__PURE__ */ jsx(
58
+ "circle",
59
+ {
60
+ cx: x(i),
61
+ cy: y(v),
62
+ r: "2.5",
63
+ fill: "var(--card)",
64
+ stroke: "#E8D500",
65
+ strokeWidth: "1.5"
66
+ },
67
+ i
68
+ ))
69
+ ]
70
+ }
71
+ ) });
72
+ }
73
+ );
74
+ AreaChart.displayName = "AreaChart";
75
+
76
+ export { AreaChart };
77
+ //# sourceMappingURL=chunk-6PZKU6ZL.js.map
78
+ //# sourceMappingURL=chunk-6PZKU6ZL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../components/AreaChart.tsx"],"names":[],"mappings":"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","file":"chunk-6PZKU6ZL.js","sourcesContent":["import { type HTMLAttributes, forwardRef, useId } from 'react'\nimport { cn } from '@/lib/utils'\n\nexport interface AreaChartProps extends HTMLAttributes<HTMLDivElement> {\n data: number[]\n height?: number\n}\n\nconst AreaChart = forwardRef<HTMLDivElement, AreaChartProps>(\n ({ className, data, height = 180, ...props }, ref) => {\n const gradientId = useId().replace(/:/g, '')\n const w = 520\n const h = height\n const pad = 8\n const max = Math.max(...data) * 1.1\n const min = Math.min(...data, 0)\n const span = Math.max(data.length - 1, 1)\n const x = (i: number) => pad + (i / span) * (w - pad * 2)\n const y = (v: number) => h - pad - ((v - min) / (max - min || 1)) * (h - pad * 2)\n const line = data.map((v, i) => `${x(i)},${y(v)}`).join(' ')\n const area = `${pad},${h - pad} ${line} ${w - pad},${h - pad}`\n\n return (\n <div ref={ref} className={cn('w-full', className)} {...props}>\n <svg\n viewBox={`0 0 ${w} ${h}`}\n className=\"w-full\"\n style={{ height }}\n preserveAspectRatio=\"none\"\n role=\"img\"\n aria-hidden=\"true\"\n >\n <defs>\n <linearGradient id={gradientId} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"#E8D500\" stopOpacity=\"0.30\" />\n <stop offset=\"100%\" stopColor=\"#E8D500\" stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n {[0.25, 0.5, 0.75].map((g, i) => (\n <line\n key={i}\n x1={pad}\n x2={w - pad}\n y1={h * g}\n y2={h * g}\n stroke=\"var(--chart-grid)\"\n strokeWidth=\"1\"\n />\n ))}\n <polygon points={area} fill={`url(#${gradientId})`} />\n <polyline\n points={line}\n fill=\"none\"\n stroke=\"#E8D500\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n {data.map((v, i) => (\n <circle\n key={i}\n cx={x(i)}\n cy={y(v)}\n r=\"2.5\"\n fill=\"var(--card)\"\n stroke=\"#E8D500\"\n strokeWidth=\"1.5\"\n />\n ))}\n </svg>\n </div>\n )\n }\n)\nAreaChart.displayName = 'AreaChart'\n\nexport { AreaChart }\n"]}
@@ -0,0 +1,75 @@
1
+ 'use client';
2
+ import { cn } from './chunk-WSQNPRGN.js';
3
+ import { forwardRef, useId } from 'react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ var RadioGroup = forwardRef(
7
+ ({ label, error, children, className }, ref) => {
8
+ return /* @__PURE__ */ jsxs("fieldset", { ref, className: cn("flex flex-col gap-1", className), children: [
9
+ label && /* @__PURE__ */ jsx("legend", { className: "text-xs font-medium text-tollerud-text-muted mb-1", children: label }),
10
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children }),
11
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-error mt-0.5", children: error })
12
+ ] });
13
+ }
14
+ );
15
+ RadioGroup.displayName = "RadioGroup";
16
+ var Radio = forwardRef(
17
+ ({ className, label, id: idProp, ...props }, ref) => {
18
+ const autoId = useId();
19
+ const id = idProp ?? autoId;
20
+ return /* @__PURE__ */ jsxs(
21
+ "label",
22
+ {
23
+ htmlFor: id,
24
+ className: cn(
25
+ "inline-flex items-center gap-2 cursor-pointer select-none group",
26
+ "text-sm text-tollerud-text-primary",
27
+ props.disabled && "opacity-50 pointer-events-none",
28
+ className
29
+ ),
30
+ children: [
31
+ /* @__PURE__ */ jsxs("span", { className: "relative flex items-center justify-center", children: [
32
+ /* @__PURE__ */ jsx(
33
+ "input",
34
+ {
35
+ ref,
36
+ id,
37
+ type: "radio",
38
+ className: "peer sr-only",
39
+ ...props
40
+ }
41
+ ),
42
+ /* @__PURE__ */ jsx(
43
+ "span",
44
+ {
45
+ className: cn(
46
+ "h-4 w-4 rounded-full border transition-all duration-[150ms]",
47
+ "bg-tollerud-surface-raised border-tollerud-border",
48
+ "peer-focus-visible:outline-2 peer-focus-visible:outline-tollerud-yellow",
49
+ "peer-checked:border-tollerud-yellow",
50
+ "group-hover:border-tollerud-text-secondary",
51
+ "flex items-center justify-center"
52
+ ),
53
+ children: /* @__PURE__ */ jsx(
54
+ "span",
55
+ {
56
+ className: cn(
57
+ "h-2 w-2 rounded-full bg-tollerud-yellow transition-opacity duration-[150ms]",
58
+ props.checked ? "opacity-100" : "opacity-0"
59
+ )
60
+ }
61
+ )
62
+ }
63
+ )
64
+ ] }),
65
+ label && /* @__PURE__ */ jsx("span", { children: label })
66
+ ]
67
+ }
68
+ );
69
+ }
70
+ );
71
+ Radio.displayName = "Radio";
72
+
73
+ export { Radio, RadioGroup };
74
+ //# sourceMappingURL=chunk-6SKTH45H.js.map
75
+ //# sourceMappingURL=chunk-6SKTH45H.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../components/RadioGroup.tsx"],"names":[],"mappings":";;;;AAcA,IAAM,UAAA,GAAa,UAAA;AAAA,EACjB,CAAC,EAAE,KAAA,EAAO,OAAO,QAAA,EAAU,SAAA,IAAa,GAAA,KAAQ;AAC9C,IAAA,4BACG,UAAA,EAAA,EAAS,GAAA,EAAU,WAAW,EAAA,CAAG,qBAAA,EAAuB,SAAS,CAAA,EAC/D,QAAA,EAAA;AAAA,MAAA,KAAA,oBACC,GAAA,CAAC,QAAA,EAAA,EAAO,SAAA,EAAU,mDAAA,EACf,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,sBAEF,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qBAAA,EAAuB,QAAA,EAAS,CAAA;AAAA,MAC9C,KAAA,oBACC,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,sCAAsC,QAAA,EAAA,KAAA,EAAM;AAAA,KAAA,EAE7D,CAAA;AAAA,EAEJ;AACF;AACA,UAAA,CAAW,WAAA,GAAc,YAAA;AAMzB,IAAM,KAAA,GAAQ,UAAA;AAAA,EACZ,CAAC,EAAE,SAAA,EAAW,KAAA,EAAO,IAAI,MAAA,EAAQ,GAAG,KAAA,EAAM,EAAG,GAAA,KAAQ;AACnD,IAAA,MAAM,SAAS,KAAA,EAAM;AACrB,IAAA,MAAM,KAAK,MAAA,IAAU,MAAA;AAErB,IAAA,uBACE,IAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAS,EAAA;AAAA,QACT,SAAA,EAAW,EAAA;AAAA,UACT,iEAAA;AAAA,UACA,oCAAA;AAAA,UACA,MAAM,QAAA,IAAY,gCAAA;AAAA,UAClB;AAAA,SACF;AAAA,QAEA,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,2CAAA,EACd,QAAA,EAAA;AAAA,4BAAA,GAAA;AAAA,cAAC,OAAA;AAAA,cAAA;AAAA,gBACC,GAAA;AAAA,gBACA,EAAA;AAAA,gBACA,IAAA,EAAK,OAAA;AAAA,gBACL,SAAA,EAAU,cAAA;AAAA,gBACT,GAAG;AAAA;AAAA,aACN;AAAA,4BAEA,GAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAW,EAAA;AAAA,kBACT,6DAAA;AAAA,kBACA,mDAAA;AAAA,kBACA,yEAAA;AAAA,kBACA,qCAAA;AAAA,kBACA,4CAAA;AAAA,kBACA;AAAA,iBACF;AAAA,gBAGA,QAAA,kBAAA,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAW,EAAA;AAAA,sBACT,6EAAA;AAAA,sBACA,KAAA,CAAM,UAAU,aAAA,GAAgB;AAAA;AAClC;AAAA;AACF;AAAA;AACF,WAAA,EACF,CAAA;AAAA,UACC,KAAA,oBAAS,GAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA;AAAA,KACzB;AAAA,EAEJ;AACF;AACA,KAAA,CAAM,WAAA,GAAc,OAAA","file":"chunk-6SKTH45H.js","sourcesContent":["'use client'\n\nimport { type InputHTMLAttributes, forwardRef, useId } from 'react'\nimport { cn } from '@/lib/utils'\n\nexport interface RadioGroupProps {\n /** Group label */\n label?: string\n /** Error message */\n error?: string\n children?: React.ReactNode\n className?: string\n}\n\nconst RadioGroup = forwardRef<HTMLFieldSetElement, RadioGroupProps>(\n ({ label, error, children, className }, ref) => {\n return (\n <fieldset ref={ref} className={cn('flex flex-col gap-1', className)}>\n {label && (\n <legend className=\"text-xs font-medium text-tollerud-text-muted mb-1\">\n {label}\n </legend>\n )}\n <div className=\"flex flex-col gap-2\">{children}</div>\n {error && (\n <p className=\"text-xs text-tollerud-error mt-0.5\">{error}</p>\n )}\n </fieldset>\n )\n }\n)\nRadioGroup.displayName = 'RadioGroup'\n\nexport interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {\n label?: string\n}\n\nconst Radio = forwardRef<HTMLInputElement, RadioProps>(\n ({ className, label, id: idProp, ...props }, ref) => {\n const autoId = useId()\n const id = idProp ?? autoId\n\n return (\n <label\n htmlFor={id}\n className={cn(\n 'inline-flex items-center gap-2 cursor-pointer select-none group',\n 'text-sm text-tollerud-text-primary',\n props.disabled && 'opacity-50 pointer-events-none',\n className\n )}\n >\n <span className=\"relative flex items-center justify-center\">\n <input\n ref={ref}\n id={id}\n type=\"radio\"\n className=\"peer sr-only\"\n {...props}\n />\n {/* Custom radio circle */}\n <span\n className={cn(\n 'h-4 w-4 rounded-full border transition-all duration-[150ms]',\n 'bg-tollerud-surface-raised border-tollerud-border',\n 'peer-focus-visible:outline-2 peer-focus-visible:outline-tollerud-yellow',\n 'peer-checked:border-tollerud-yellow',\n 'group-hover:border-tollerud-text-secondary',\n 'flex items-center justify-center'\n )}\n >\n {/* Inner dot */}\n <span\n className={cn(\n 'h-2 w-2 rounded-full bg-tollerud-yellow transition-opacity duration-[150ms]',\n props.checked ? 'opacity-100' : 'opacity-0'\n )}\n />\n </span>\n </span>\n {label && <span>{label}</span>}\n </label>\n )\n }\n)\nRadio.displayName = 'Radio'\n\nexport { RadioGroup, Radio }"]}