@omnifyjp/ui 0.1.1

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 (354) hide show
  1. package/README.md +230 -0
  2. package/dist/chunk-23SALQ3G.js +219 -0
  3. package/dist/chunk-23SALQ3G.js.map +1 -0
  4. package/dist/chunk-3TGN2DFB.js +41 -0
  5. package/dist/chunk-3TGN2DFB.js.map +1 -0
  6. package/dist/chunk-3TV2IR7L.js +65 -0
  7. package/dist/chunk-3TV2IR7L.js.map +1 -0
  8. package/dist/chunk-4CT5SCAH.js +54 -0
  9. package/dist/chunk-4CT5SCAH.js.map +1 -0
  10. package/dist/chunk-4D6FDXCG.js +41 -0
  11. package/dist/chunk-4D6FDXCG.js.map +1 -0
  12. package/dist/chunk-4HCORCR2.js +114 -0
  13. package/dist/chunk-4HCORCR2.js.map +1 -0
  14. package/dist/chunk-4N357E44.js +119 -0
  15. package/dist/chunk-4N357E44.js.map +1 -0
  16. package/dist/chunk-4Q2FLTAW.js +23 -0
  17. package/dist/chunk-4Q2FLTAW.js.map +1 -0
  18. package/dist/chunk-5M67ZEPM.js +33 -0
  19. package/dist/chunk-5M67ZEPM.js.map +1 -0
  20. package/dist/chunk-5WCL47ZW.js +30 -0
  21. package/dist/chunk-5WCL47ZW.js.map +1 -0
  22. package/dist/chunk-5Y3SQ3EA.js +52 -0
  23. package/dist/chunk-5Y3SQ3EA.js.map +1 -0
  24. package/dist/chunk-6GCAG5FH.js +46 -0
  25. package/dist/chunk-6GCAG5FH.js.map +1 -0
  26. package/dist/chunk-6MVBERQJ.js +44 -0
  27. package/dist/chunk-6MVBERQJ.js.map +1 -0
  28. package/dist/chunk-725ICC47.js +44 -0
  29. package/dist/chunk-725ICC47.js.map +1 -0
  30. package/dist/chunk-7ALADSN3.js +56 -0
  31. package/dist/chunk-7ALADSN3.js.map +1 -0
  32. package/dist/chunk-7NMWBCF4.js +171 -0
  33. package/dist/chunk-7NMWBCF4.js.map +1 -0
  34. package/dist/chunk-7ZFYPC74.js +155 -0
  35. package/dist/chunk-7ZFYPC74.js.map +1 -0
  36. package/dist/chunk-ANTYNEUU.js +35 -0
  37. package/dist/chunk-ANTYNEUU.js.map +1 -0
  38. package/dist/chunk-AZARDPXB.js +43 -0
  39. package/dist/chunk-AZARDPXB.js.map +1 -0
  40. package/dist/chunk-BJO5JCFB.js +111 -0
  41. package/dist/chunk-BJO5JCFB.js.map +1 -0
  42. package/dist/chunk-BOYSXIM3.js +160 -0
  43. package/dist/chunk-BOYSXIM3.js.map +1 -0
  44. package/dist/chunk-CDARHMTL.js +25 -0
  45. package/dist/chunk-CDARHMTL.js.map +1 -0
  46. package/dist/chunk-CESZTYQQ.js +93 -0
  47. package/dist/chunk-CESZTYQQ.js.map +1 -0
  48. package/dist/chunk-D3GCOO74.js +90 -0
  49. package/dist/chunk-D3GCOO74.js.map +1 -0
  50. package/dist/chunk-DGPY4WP3.js +11 -0
  51. package/dist/chunk-DGPY4WP3.js.map +1 -0
  52. package/dist/chunk-DIS42JLG.js +13 -0
  53. package/dist/chunk-DIS42JLG.js.map +1 -0
  54. package/dist/chunk-DQGDQEXD.js +617 -0
  55. package/dist/chunk-DQGDQEXD.js.map +1 -0
  56. package/dist/chunk-DZENMCRL.js +63 -0
  57. package/dist/chunk-DZENMCRL.js.map +1 -0
  58. package/dist/chunk-EIF6WZAZ.js +38 -0
  59. package/dist/chunk-EIF6WZAZ.js.map +1 -0
  60. package/dist/chunk-F6VQCMYH.js +81 -0
  61. package/dist/chunk-F6VQCMYH.js.map +1 -0
  62. package/dist/chunk-FBNG2KGO.js +66 -0
  63. package/dist/chunk-FBNG2KGO.js.map +1 -0
  64. package/dist/chunk-FO7J3PYY.js +131 -0
  65. package/dist/chunk-FO7J3PYY.js.map +1 -0
  66. package/dist/chunk-FSFXDD6P.js +196 -0
  67. package/dist/chunk-FSFXDD6P.js.map +1 -0
  68. package/dist/chunk-IDRQ6BNQ.js +63 -0
  69. package/dist/chunk-IDRQ6BNQ.js.map +1 -0
  70. package/dist/chunk-IJIGJGL5.js +48 -0
  71. package/dist/chunk-IJIGJGL5.js.map +1 -0
  72. package/dist/chunk-JPTN62BV.js +128 -0
  73. package/dist/chunk-JPTN62BV.js.map +1 -0
  74. package/dist/chunk-KABLXGWK.js +66 -0
  75. package/dist/chunk-KABLXGWK.js.map +1 -0
  76. package/dist/chunk-KOGOYUEE.js +121 -0
  77. package/dist/chunk-KOGOYUEE.js.map +1 -0
  78. package/dist/chunk-KULHYNE2.js +138 -0
  79. package/dist/chunk-KULHYNE2.js.map +1 -0
  80. package/dist/chunk-KXT75MXF.js +164 -0
  81. package/dist/chunk-KXT75MXF.js.map +1 -0
  82. package/dist/chunk-KXZ7IND6.js +24 -0
  83. package/dist/chunk-KXZ7IND6.js.map +1 -0
  84. package/dist/chunk-L46XUK4O.js +33 -0
  85. package/dist/chunk-L46XUK4O.js.map +1 -0
  86. package/dist/chunk-LI7CKURD.js +65 -0
  87. package/dist/chunk-LI7CKURD.js.map +1 -0
  88. package/dist/chunk-LW5PTU7D.js +211 -0
  89. package/dist/chunk-LW5PTU7D.js.map +1 -0
  90. package/dist/chunk-MNAT3ZF6.js +106 -0
  91. package/dist/chunk-MNAT3ZF6.js.map +1 -0
  92. package/dist/chunk-NFAXCC73.js +239 -0
  93. package/dist/chunk-NFAXCC73.js.map +1 -0
  94. package/dist/chunk-OHBCYKNT.js +63 -0
  95. package/dist/chunk-OHBCYKNT.js.map +1 -0
  96. package/dist/chunk-ONAUEREV.js +28 -0
  97. package/dist/chunk-ONAUEREV.js.map +1 -0
  98. package/dist/chunk-OXQNDQJW.js +86 -0
  99. package/dist/chunk-OXQNDQJW.js.map +1 -0
  100. package/dist/chunk-PCQSHXOQ.js +104 -0
  101. package/dist/chunk-PCQSHXOQ.js.map +1 -0
  102. package/dist/chunk-PH6P53QX.js +48 -0
  103. package/dist/chunk-PH6P53QX.js.map +1 -0
  104. package/dist/chunk-PPZSGU2L.js +33 -0
  105. package/dist/chunk-PPZSGU2L.js.map +1 -0
  106. package/dist/chunk-QCGYYBDZ.js +25 -0
  107. package/dist/chunk-QCGYYBDZ.js.map +1 -0
  108. package/dist/chunk-QMAMDYRD.js +65 -0
  109. package/dist/chunk-QMAMDYRD.js.map +1 -0
  110. package/dist/chunk-RVJDDGQW.js +112 -0
  111. package/dist/chunk-RVJDDGQW.js.map +1 -0
  112. package/dist/chunk-SABAKV4J.js +238 -0
  113. package/dist/chunk-SABAKV4J.js.map +1 -0
  114. package/dist/chunk-TEYOLOZY.js +18 -0
  115. package/dist/chunk-TEYOLOZY.js.map +1 -0
  116. package/dist/chunk-TMFQJ7E3.js +61 -0
  117. package/dist/chunk-TMFQJ7E3.js.map +1 -0
  118. package/dist/chunk-UCEUTKTQ.js +116 -0
  119. package/dist/chunk-UCEUTKTQ.js.map +1 -0
  120. package/dist/chunk-UV6UVSCF.js +187 -0
  121. package/dist/chunk-UV6UVSCF.js.map +1 -0
  122. package/dist/chunk-VGQC333M.js +17 -0
  123. package/dist/chunk-VGQC333M.js.map +1 -0
  124. package/dist/chunk-WAPGZIAL.js +99 -0
  125. package/dist/chunk-WAPGZIAL.js.map +1 -0
  126. package/dist/chunk-WRCHR4AK.js +23 -0
  127. package/dist/chunk-WRCHR4AK.js.map +1 -0
  128. package/dist/chunk-XKVHX75G.js +51 -0
  129. package/dist/chunk-XKVHX75G.js.map +1 -0
  130. package/dist/chunk-YF6WRCTG.js +41 -0
  131. package/dist/chunk-YF6WRCTG.js.map +1 -0
  132. package/dist/chunk-YGBYH4EO.js +28 -0
  133. package/dist/chunk-YGBYH4EO.js.map +1 -0
  134. package/dist/chunk-YKJZV2JK.js +109 -0
  135. package/dist/chunk-YKJZV2JK.js.map +1 -0
  136. package/dist/chunk-YUYC6Y6E.js +143 -0
  137. package/dist/chunk-YUYC6Y6E.js.map +1 -0
  138. package/dist/chunk-Z47W426M.js +53 -0
  139. package/dist/chunk-Z47W426M.js.map +1 -0
  140. package/dist/components/accordion.d.ts +10 -0
  141. package/dist/components/accordion.js +4 -0
  142. package/dist/components/accordion.js.map +1 -0
  143. package/dist/components/alert-dialog.d.ts +17 -0
  144. package/dist/components/alert-dialog.js +5 -0
  145. package/dist/components/alert-dialog.js.map +1 -0
  146. package/dist/components/alert.d.ts +13 -0
  147. package/dist/components/alert.js +4 -0
  148. package/dist/components/alert.js.map +1 -0
  149. package/dist/components/aspect-ratio.d.ts +6 -0
  150. package/dist/components/aspect-ratio.js +3 -0
  151. package/dist/components/aspect-ratio.js.map +1 -0
  152. package/dist/components/avatar.d.ts +9 -0
  153. package/dist/components/avatar.js +4 -0
  154. package/dist/components/avatar.js.map +1 -0
  155. package/dist/components/badge.d.ts +13 -0
  156. package/dist/components/badge.js +4 -0
  157. package/dist/components/badge.js.map +1 -0
  158. package/dist/components/breadcrumb.d.ts +14 -0
  159. package/dist/components/breadcrumb.js +4 -0
  160. package/dist/components/breadcrumb.js.map +1 -0
  161. package/dist/components/button.d.ts +16 -0
  162. package/dist/components/button.js +4 -0
  163. package/dist/components/button.js.map +1 -0
  164. package/dist/components/calendar-category-badge.d.ts +10 -0
  165. package/dist/components/calendar-category-badge.js +5 -0
  166. package/dist/components/calendar-category-badge.js.map +1 -0
  167. package/dist/components/calendar-event-chip.d.ts +18 -0
  168. package/dist/components/calendar-event-chip.js +4 -0
  169. package/dist/components/calendar-event-chip.js.map +1 -0
  170. package/dist/components/calendar-event-sheet.d.ts +31 -0
  171. package/dist/components/calendar-event-sheet.js +9 -0
  172. package/dist/components/calendar-event-sheet.js.map +1 -0
  173. package/dist/components/calendar-mini.d.ts +29 -0
  174. package/dist/components/calendar-mini.js +6 -0
  175. package/dist/components/calendar-mini.js.map +1 -0
  176. package/dist/components/calendar-toolbar.d.ts +25 -0
  177. package/dist/components/calendar-toolbar.js +7 -0
  178. package/dist/components/calendar-toolbar.js.map +1 -0
  179. package/dist/components/calendar.d.ts +7 -0
  180. package/dist/components/calendar.js +5 -0
  181. package/dist/components/calendar.js.map +1 -0
  182. package/dist/components/card.d.ts +12 -0
  183. package/dist/components/card.js +4 -0
  184. package/dist/components/card.js.map +1 -0
  185. package/dist/components/carousel.d.ts +24 -0
  186. package/dist/components/carousel.js +5 -0
  187. package/dist/components/carousel.js.map +1 -0
  188. package/dist/components/chart.d.ts +43 -0
  189. package/dist/components/chart.js +4 -0
  190. package/dist/components/chart.js.map +1 -0
  191. package/dist/components/checkbox.d.ts +6 -0
  192. package/dist/components/checkbox.js +4 -0
  193. package/dist/components/checkbox.js.map +1 -0
  194. package/dist/components/collapsible.d.ts +8 -0
  195. package/dist/components/collapsible.js +3 -0
  196. package/dist/components/collapsible.js.map +1 -0
  197. package/dist/components/color-picker.d.ts +13 -0
  198. package/dist/components/color-picker.js +7 -0
  199. package/dist/components/color-picker.js.map +1 -0
  200. package/dist/components/combobox.d.ts +33 -0
  201. package/dist/components/combobox.js +8 -0
  202. package/dist/components/combobox.js.map +1 -0
  203. package/dist/components/command.d.ts +20 -0
  204. package/dist/components/command.js +5 -0
  205. package/dist/components/command.js.map +1 -0
  206. package/dist/components/context-menu.d.ts +28 -0
  207. package/dist/components/context-menu.js +4 -0
  208. package/dist/components/context-menu.js.map +1 -0
  209. package/dist/components/date-picker.d.ts +31 -0
  210. package/dist/components/date-picker.js +7 -0
  211. package/dist/components/date-picker.js.map +1 -0
  212. package/dist/components/dialog.d.ts +16 -0
  213. package/dist/components/dialog.js +4 -0
  214. package/dist/components/dialog.js.map +1 -0
  215. package/dist/components/drawer.d.ts +17 -0
  216. package/dist/components/drawer.js +4 -0
  217. package/dist/components/drawer.js.map +1 -0
  218. package/dist/components/dropdown-menu.d.ts +28 -0
  219. package/dist/components/dropdown-menu.js +4 -0
  220. package/dist/components/dropdown-menu.js.map +1 -0
  221. package/dist/components/file-upload.d.ts +17 -0
  222. package/dist/components/file-upload.js +5 -0
  223. package/dist/components/file-upload.js.map +1 -0
  224. package/dist/components/form.d.ts +28 -0
  225. package/dist/components/form.js +5 -0
  226. package/dist/components/form.js.map +1 -0
  227. package/dist/components/hover-card.d.ts +9 -0
  228. package/dist/components/hover-card.js +4 -0
  229. package/dist/components/hover-card.js.map +1 -0
  230. package/dist/components/input-otp.d.ts +14 -0
  231. package/dist/components/input-otp.js +4 -0
  232. package/dist/components/input-otp.js.map +1 -0
  233. package/dist/components/input.d.ts +5 -0
  234. package/dist/components/input.js +4 -0
  235. package/dist/components/input.js.map +1 -0
  236. package/dist/components/label.d.ts +6 -0
  237. package/dist/components/label.js +4 -0
  238. package/dist/components/label.js.map +1 -0
  239. package/dist/components/menubar.d.ts +29 -0
  240. package/dist/components/menubar.js +4 -0
  241. package/dist/components/menubar.js.map +1 -0
  242. package/dist/components/navigation-menu.d.ts +18 -0
  243. package/dist/components/navigation-menu.js +4 -0
  244. package/dist/components/navigation-menu.js.map +1 -0
  245. package/dist/components/pagination.d.ts +18 -0
  246. package/dist/components/pagination.js +5 -0
  247. package/dist/components/pagination.js.map +1 -0
  248. package/dist/components/permission-grid.d.ts +30 -0
  249. package/dist/components/permission-grid.js +5 -0
  250. package/dist/components/permission-grid.js.map +1 -0
  251. package/dist/components/popover.d.ts +10 -0
  252. package/dist/components/popover.js +4 -0
  253. package/dist/components/popover.js.map +1 -0
  254. package/dist/components/progress.d.ts +7 -0
  255. package/dist/components/progress.js +4 -0
  256. package/dist/components/progress.js.map +1 -0
  257. package/dist/components/radio-group.d.ts +8 -0
  258. package/dist/components/radio-group.js +4 -0
  259. package/dist/components/radio-group.js.map +1 -0
  260. package/dist/components/rating.d.ts +14 -0
  261. package/dist/components/rating.js +4 -0
  262. package/dist/components/rating.js.map +1 -0
  263. package/dist/components/resizable.d.ts +11 -0
  264. package/dist/components/resizable.js +4 -0
  265. package/dist/components/resizable.js.map +1 -0
  266. package/dist/components/scope-tree.d.ts +35 -0
  267. package/dist/components/scope-tree.js +5 -0
  268. package/dist/components/scope-tree.js.map +1 -0
  269. package/dist/components/scope-type-badge.d.ts +20 -0
  270. package/dist/components/scope-type-badge.js +5 -0
  271. package/dist/components/scope-type-badge.js.map +1 -0
  272. package/dist/components/scroll-area.d.ts +8 -0
  273. package/dist/components/scroll-area.js +4 -0
  274. package/dist/components/scroll-area.js.map +1 -0
  275. package/dist/components/select.d.ts +18 -0
  276. package/dist/components/select.js +4 -0
  277. package/dist/components/select.js.map +1 -0
  278. package/dist/components/separator.d.ts +7 -0
  279. package/dist/components/separator.js +4 -0
  280. package/dist/components/separator.js.map +1 -0
  281. package/dist/components/sheet.d.ts +16 -0
  282. package/dist/components/sheet.js +4 -0
  283. package/dist/components/sheet.js.map +1 -0
  284. package/dist/components/sidebar.d.ts +75 -0
  285. package/dist/components/sidebar.js +11 -0
  286. package/dist/components/sidebar.js.map +1 -0
  287. package/dist/components/skeleton.d.ts +5 -0
  288. package/dist/components/skeleton.js +4 -0
  289. package/dist/components/skeleton.js.map +1 -0
  290. package/dist/components/slider.d.ts +7 -0
  291. package/dist/components/slider.js +4 -0
  292. package/dist/components/slider.js.map +1 -0
  293. package/dist/components/slug-input.d.ts +22 -0
  294. package/dist/components/slug-input.js +6 -0
  295. package/dist/components/slug-input.js.map +1 -0
  296. package/dist/components/sonner.d.ts +6 -0
  297. package/dist/components/sonner.js +3 -0
  298. package/dist/components/sonner.js.map +1 -0
  299. package/dist/components/stage-type-badge.d.ts +24 -0
  300. package/dist/components/stage-type-badge.js +5 -0
  301. package/dist/components/stage-type-badge.js.map +1 -0
  302. package/dist/components/switch.d.ts +7 -0
  303. package/dist/components/switch.js +4 -0
  304. package/dist/components/switch.js.map +1 -0
  305. package/dist/components/table.d.ts +13 -0
  306. package/dist/components/table.js +4 -0
  307. package/dist/components/table.js.map +1 -0
  308. package/dist/components/tabs.d.ts +10 -0
  309. package/dist/components/tabs.js +4 -0
  310. package/dist/components/tabs.js.map +1 -0
  311. package/dist/components/tag-input.d.ts +15 -0
  312. package/dist/components/tag-input.js +5 -0
  313. package/dist/components/tag-input.js.map +1 -0
  314. package/dist/components/textarea.d.ts +5 -0
  315. package/dist/components/textarea.js +4 -0
  316. package/dist/components/textarea.js.map +1 -0
  317. package/dist/components/time-picker.d.ts +20 -0
  318. package/dist/components/time-picker.js +8 -0
  319. package/dist/components/time-picker.js.map +1 -0
  320. package/dist/components/toggle-group.d.ts +12 -0
  321. package/dist/components/toggle-group.js +5 -0
  322. package/dist/components/toggle-group.js.map +1 -0
  323. package/dist/components/toggle.d.ts +13 -0
  324. package/dist/components/toggle.js +4 -0
  325. package/dist/components/toggle.js.map +1 -0
  326. package/dist/components/tooltip.d.ts +10 -0
  327. package/dist/components/tooltip.js +4 -0
  328. package/dist/components/tooltip.js.map +1 -0
  329. package/dist/components/workflow-category-badge.d.ts +26 -0
  330. package/dist/components/workflow-category-badge.js +5 -0
  331. package/dist/components/workflow-category-badge.js.map +1 -0
  332. package/dist/components/workflow-diagram.d.ts +43 -0
  333. package/dist/components/workflow-diagram.js +5 -0
  334. package/dist/components/workflow-diagram.js.map +1 -0
  335. package/dist/components/workflow-status-badge.d.ts +24 -0
  336. package/dist/components/workflow-status-badge.js +5 -0
  337. package/dist/components/workflow-status-badge.js.map +1 -0
  338. package/dist/components/workflow-stepper.d.ts +34 -0
  339. package/dist/components/workflow-stepper.js +4 -0
  340. package/dist/components/workflow-stepper.js.map +1 -0
  341. package/dist/hooks/use-mobile.d.ts +3 -0
  342. package/dist/hooks/use-mobile.js +3 -0
  343. package/dist/hooks/use-mobile.js.map +1 -0
  344. package/dist/index.d.ts +111 -0
  345. package/dist/index.js +71 -0
  346. package/dist/index.js.map +1 -0
  347. package/dist/lib/utils.d.ts +5 -0
  348. package/dist/lib/utils.js +3 -0
  349. package/dist/lib/utils.js.map +1 -0
  350. package/package.json +101 -0
  351. package/src/styles/fonts.css +0 -0
  352. package/src/styles/index.css +3 -0
  353. package/src/styles/tailwind.css +4 -0
  354. package/src/styles/theme.css +447 -0
@@ -0,0 +1,187 @@
1
+ import { Button } from './chunk-PH6P53QX.js';
2
+ import { cn } from './chunk-DGPY4WP3.js';
3
+ import * as React from 'react';
4
+ import { Upload, X, FileImage, FileVideo, FileText, File } from 'lucide-react';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ function FileUpload({
8
+ value = [],
9
+ onChange,
10
+ accept,
11
+ multiple = false,
12
+ maxSize = 10 * 1024 * 1024,
13
+ // 10MB default
14
+ maxFiles,
15
+ disabled,
16
+ className,
17
+ showPreview = true
18
+ }) {
19
+ const inputRef = React.useRef(null);
20
+ const [dragActive, setDragActive] = React.useState(false);
21
+ const [error, setError] = React.useState("");
22
+ const handleDrag = (e) => {
23
+ e.preventDefault();
24
+ e.stopPropagation();
25
+ if (e.type === "dragenter" || e.type === "dragover") {
26
+ setDragActive(true);
27
+ } else if (e.type === "dragleave") {
28
+ setDragActive(false);
29
+ }
30
+ };
31
+ const validateFiles = (files) => {
32
+ setError("");
33
+ if (maxFiles && value.length + files.length > maxFiles) {
34
+ return {
35
+ valid: [],
36
+ error: `Ch\u1EC9 \u0111\u01B0\u1EE3c ch\u1ECDn t\u1ED1i \u0111a ${maxFiles} file`
37
+ };
38
+ }
39
+ const oversizedFiles = files.filter((file) => file.size > maxSize);
40
+ if (oversizedFiles.length > 0) {
41
+ return {
42
+ valid: [],
43
+ error: `File v\u01B0\u1EE3t qu\xE1 dung l\u01B0\u1EE3ng cho ph\xE9p (${Math.round(maxSize / 1024 / 1024)}MB)`
44
+ };
45
+ }
46
+ return { valid: files };
47
+ };
48
+ const handleDrop = (e) => {
49
+ e.preventDefault();
50
+ e.stopPropagation();
51
+ setDragActive(false);
52
+ if (disabled) return;
53
+ const droppedFiles = Array.from(e.dataTransfer.files);
54
+ const { valid, error: error2 } = validateFiles(droppedFiles);
55
+ if (error2) {
56
+ setError(error2);
57
+ return;
58
+ }
59
+ onChange?.([...value, ...valid]);
60
+ };
61
+ const handleChange = (e) => {
62
+ if (disabled) return;
63
+ const selectedFiles = Array.from(e.target.files || []);
64
+ const { valid, error: error2 } = validateFiles(selectedFiles);
65
+ if (error2) {
66
+ setError(error2);
67
+ return;
68
+ }
69
+ onChange?.([...value, ...valid]);
70
+ if (inputRef.current) {
71
+ inputRef.current.value = "";
72
+ }
73
+ };
74
+ const handleRemove = (index) => {
75
+ onChange?.(value.filter((_, i) => i !== index));
76
+ };
77
+ const getFileIcon = (file) => {
78
+ if (file.type.startsWith("image/")) return FileImage;
79
+ if (file.type.startsWith("video/")) return FileVideo;
80
+ if (file.type.startsWith("text/")) return FileText;
81
+ return File;
82
+ };
83
+ const formatFileSize = (bytes) => {
84
+ if (bytes === 0) return "0 Bytes";
85
+ const k = 1024;
86
+ const sizes = ["Bytes", "KB", "MB", "GB"];
87
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
88
+ return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
89
+ };
90
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full", className), children: [
91
+ /* @__PURE__ */ jsx(
92
+ "input",
93
+ {
94
+ ref: inputRef,
95
+ type: "file",
96
+ accept,
97
+ multiple,
98
+ onChange: handleChange,
99
+ disabled,
100
+ className: "hidden"
101
+ }
102
+ ),
103
+ /* @__PURE__ */ jsxs(
104
+ "div",
105
+ {
106
+ onDragEnter: handleDrag,
107
+ onDragLeave: handleDrag,
108
+ onDragOver: handleDrag,
109
+ onDrop: handleDrop,
110
+ onClick: () => !disabled && inputRef.current?.click(),
111
+ className: cn(
112
+ "relative border-2 border-dashed rounded-lg p-8 text-center cursor-pointer transition-colors",
113
+ dragActive ? "border-blue-500 bg-blue-50" : "border-gray-300 hover:border-gray-400",
114
+ disabled && "opacity-50 cursor-not-allowed",
115
+ error && "border-red-500"
116
+ ),
117
+ children: [
118
+ /* @__PURE__ */ jsx(Upload, { className: "mx-auto h-12 w-12 text-gray-400 mb-4" }),
119
+ /* @__PURE__ */ jsxs("div", { className: "text-sm text-gray-600 mb-2", children: [
120
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-blue-600", children: "Nh\u1EA5p \u0111\u1EC3 ch\u1ECDn file" }),
121
+ " ",
122
+ "ho\u1EB7c k\xE9o th\u1EA3 file v\xE0o \u0111\xE2y"
123
+ ] }),
124
+ /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-500", children: [
125
+ accept && /* @__PURE__ */ jsxs("div", { children: [
126
+ "\u0110\u1ECBnh d\u1EA1ng: ",
127
+ accept
128
+ ] }),
129
+ /* @__PURE__ */ jsxs("div", { children: [
130
+ "Dung l\u01B0\u1EE3ng t\u1ED1i \u0111a: ",
131
+ Math.round(maxSize / 1024 / 1024),
132
+ "MB"
133
+ ] }),
134
+ maxFiles && /* @__PURE__ */ jsxs("div", { children: [
135
+ "S\u1ED1 l\u01B0\u1EE3ng t\u1ED1i \u0111a: ",
136
+ maxFiles,
137
+ " file"
138
+ ] })
139
+ ] })
140
+ ]
141
+ }
142
+ ),
143
+ error && /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm text-red-600", children: error }),
144
+ showPreview && value.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-2", children: value.map((file, index) => {
145
+ const FileIcon = getFileIcon(file);
146
+ const isImage = file.type.startsWith("image/");
147
+ const previewUrl = isImage ? URL.createObjectURL(file) : null;
148
+ return /* @__PURE__ */ jsxs(
149
+ "div",
150
+ {
151
+ className: "flex items-center gap-3 p-3 border rounded-lg bg-gray-50",
152
+ children: [
153
+ previewUrl ? /* @__PURE__ */ jsx(
154
+ "img",
155
+ {
156
+ src: previewUrl,
157
+ alt: file.name,
158
+ className: "w-10 h-10 rounded object-cover"
159
+ }
160
+ ) : /* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded bg-gray-200 flex items-center justify-center", children: /* @__PURE__ */ jsx(FileIcon, { className: "w-5 h-5 text-gray-600" }) }),
161
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
162
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-medium truncate", children: file.name }),
163
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: formatFileSize(file.size) })
164
+ ] }),
165
+ /* @__PURE__ */ jsx(
166
+ Button,
167
+ {
168
+ type: "button",
169
+ variant: "ghost",
170
+ size: "sm",
171
+ onClick: () => handleRemove(index),
172
+ disabled,
173
+ className: "flex-shrink-0",
174
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
175
+ }
176
+ )
177
+ ]
178
+ },
179
+ `${file.name}-${index}`
180
+ );
181
+ }) })
182
+ ] });
183
+ }
184
+
185
+ export { FileUpload };
186
+ //# sourceMappingURL=chunk-UV6UVSCF.js.map
187
+ //# sourceMappingURL=chunk-UV6UVSCF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/file-upload.tsx"],"names":["error"],"mappings":"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","file":"chunk-UV6UVSCF.js","sourcesContent":["import * as React from \"react\";\nimport { Upload, X, File, FileImage, FileText, FileVideo } from \"lucide-react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"./button\";\n\ninterface FileUploadProps {\n value?: File[];\n onChange?: (files: File[]) => void;\n accept?: string;\n multiple?: boolean;\n maxSize?: number; // in bytes\n maxFiles?: number;\n disabled?: boolean;\n className?: string;\n showPreview?: boolean;\n}\n\nexport function FileUpload({\n value = [],\n onChange,\n accept,\n multiple = false,\n maxSize = 10 * 1024 * 1024, // 10MB default\n maxFiles,\n disabled,\n className,\n showPreview = true,\n}: FileUploadProps) {\n const inputRef = React.useRef<HTMLInputElement>(null);\n const [dragActive, setDragActive] = React.useState(false);\n const [error, setError] = React.useState<string>(\"\");\n\n const handleDrag = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (e.type === \"dragenter\" || e.type === \"dragover\") {\n setDragActive(true);\n } else if (e.type === \"dragleave\") {\n setDragActive(false);\n }\n };\n\n const validateFiles = (files: File[]): { valid: File[]; error?: string } => {\n setError(\"\");\n\n // Check max files\n if (maxFiles && value.length + files.length > maxFiles) {\n return {\n valid: [],\n error: `Chỉ được chọn tối đa ${maxFiles} file`,\n };\n }\n\n // Check file size\n const oversizedFiles = files.filter((file) => file.size > maxSize);\n if (oversizedFiles.length > 0) {\n return {\n valid: [],\n error: `File vượt quá dung lượng cho phép (${Math.round(maxSize / 1024 / 1024)}MB)`,\n };\n }\n\n return { valid: files };\n };\n\n const handleDrop = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setDragActive(false);\n\n if (disabled) return;\n\n const droppedFiles = Array.from(e.dataTransfer.files);\n const { valid, error } = validateFiles(droppedFiles);\n\n if (error) {\n setError(error);\n return;\n }\n\n onChange?.([...value, ...valid]);\n };\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n if (disabled) return;\n\n const selectedFiles = Array.from(e.target.files || []);\n const { valid, error } = validateFiles(selectedFiles);\n\n if (error) {\n setError(error);\n return;\n }\n\n onChange?.([...value, ...valid]);\n\n // Reset input\n if (inputRef.current) {\n inputRef.current.value = \"\";\n }\n };\n\n const handleRemove = (index: number) => {\n onChange?.(value.filter((_, i) => i !== index));\n };\n\n const getFileIcon = (file: File) => {\n if (file.type.startsWith(\"image/\")) return FileImage;\n if (file.type.startsWith(\"video/\")) return FileVideo;\n if (file.type.startsWith(\"text/\")) return FileText;\n return File;\n };\n\n const formatFileSize = (bytes: number) => {\n if (bytes === 0) return \"0 Bytes\";\n const k = 1024;\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return Math.round(bytes / Math.pow(k, i) * 100) / 100 + \" \" + sizes[i];\n };\n\n return (\n <div className={cn(\"w-full\", className)}>\n <input\n ref={inputRef}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n onChange={handleChange}\n disabled={disabled}\n className=\"hidden\"\n />\n\n {/* Upload Area */}\n <div\n onDragEnter={handleDrag}\n onDragLeave={handleDrag}\n onDragOver={handleDrag}\n onDrop={handleDrop}\n onClick={() => !disabled && inputRef.current?.click()}\n className={cn(\n \"relative border-2 border-dashed rounded-lg p-8 text-center cursor-pointer transition-colors\",\n dragActive\n ? \"border-blue-500 bg-blue-50\"\n : \"border-gray-300 hover:border-gray-400\",\n disabled && \"opacity-50 cursor-not-allowed\",\n error && \"border-red-500\"\n )}\n >\n <Upload className=\"mx-auto h-12 w-12 text-gray-400 mb-4\" />\n <div className=\"text-sm text-gray-600 mb-2\">\n <span className=\"font-semibold text-blue-600\">Nhấp để chọn file</span>\n {\" \"}hoặc kéo thả file vào đây\n </div>\n <div className=\"text-xs text-gray-500\">\n {accept && <div>Định dạng: {accept}</div>}\n <div>Dung lượng tối đa: {Math.round(maxSize / 1024 / 1024)}MB</div>\n {maxFiles && <div>Số lượng tối đa: {maxFiles} file</div>}\n </div>\n </div>\n\n {/* Error Message */}\n {error && (\n <div className=\"mt-2 text-sm text-red-600\">{error}</div>\n )}\n\n {/* File List */}\n {showPreview && value.length > 0 && (\n <div className=\"mt-4 space-y-2\">\n {value.map((file, index) => {\n const FileIcon = getFileIcon(file);\n const isImage = file.type.startsWith(\"image/\");\n const previewUrl = isImage ? URL.createObjectURL(file) : null;\n\n return (\n <div\n key={`${file.name}-${index}`}\n className=\"flex items-center gap-3 p-3 border rounded-lg bg-gray-50\"\n >\n {previewUrl ? (\n <img\n src={previewUrl}\n alt={file.name}\n className=\"w-10 h-10 rounded object-cover\"\n />\n ) : (\n <div className=\"w-10 h-10 rounded bg-gray-200 flex items-center justify-center\">\n <FileIcon className=\"w-5 h-5 text-gray-600\" />\n </div>\n )}\n\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium truncate\">{file.name}</div>\n <div className=\"text-xs text-gray-500\">\n {formatFileSize(file.size)}\n </div>\n </div>\n\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => handleRemove(index)}\n disabled={disabled}\n className=\"flex-shrink-0\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n"]}
@@ -0,0 +1,17 @@
1
+ import { cn } from './chunk-DGPY4WP3.js';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ function Skeleton({ className, ...props }) {
5
+ return /* @__PURE__ */ jsx(
6
+ "div",
7
+ {
8
+ "data-slot": "skeleton",
9
+ className: cn("bg-accent animate-pulse rounded-md", className),
10
+ ...props
11
+ }
12
+ );
13
+ }
14
+
15
+ export { Skeleton };
16
+ //# sourceMappingURL=chunk-VGQC333M.js.map
17
+ //# sourceMappingURL=chunk-VGQC333M.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/skeleton.tsx"],"names":[],"mappings":";;;AAEA,SAAS,QAAA,CAAS,EAAE,SAAA,EAAW,GAAG,OAAM,EAAgC;AACtE,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,UAAA;AAAA,MACV,SAAA,EAAW,EAAA,CAAG,oCAAA,EAAsC,SAAS,CAAA;AAAA,MAC5D,GAAG;AAAA;AAAA,GACN;AAEJ","file":"chunk-VGQC333M.js","sourcesContent":["import { cn } from \"../lib/utils\";\n\nfunction Skeleton({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"skeleton\"\n className={cn(\"bg-accent animate-pulse rounded-md\", className)}\n {...props}\n />\n );\n}\n\nexport { Skeleton };\n"]}
@@ -0,0 +1,99 @@
1
+ import { cn } from './chunk-DGPY4WP3.js';
2
+ import { Slot } from '@radix-ui/react-slot';
3
+ import { ChevronRight, MoreHorizontal } from 'lucide-react';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ function Breadcrumb({ ...props }) {
7
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "breadcrumb", "data-slot": "breadcrumb", ...props });
8
+ }
9
+ function BreadcrumbList({ className, ...props }) {
10
+ return /* @__PURE__ */ jsx(
11
+ "ol",
12
+ {
13
+ "data-slot": "breadcrumb-list",
14
+ className: cn(
15
+ "text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
16
+ className
17
+ ),
18
+ ...props
19
+ }
20
+ );
21
+ }
22
+ function BreadcrumbItem({ className, ...props }) {
23
+ return /* @__PURE__ */ jsx(
24
+ "li",
25
+ {
26
+ "data-slot": "breadcrumb-item",
27
+ className: cn("inline-flex items-center gap-1.5", className),
28
+ ...props
29
+ }
30
+ );
31
+ }
32
+ function BreadcrumbLink({
33
+ asChild,
34
+ className,
35
+ ...props
36
+ }) {
37
+ const Comp = asChild ? Slot : "a";
38
+ return /* @__PURE__ */ jsx(
39
+ Comp,
40
+ {
41
+ "data-slot": "breadcrumb-link",
42
+ className: cn("hover:text-foreground transition-colors", className),
43
+ ...props
44
+ }
45
+ );
46
+ }
47
+ function BreadcrumbPage({ className, ...props }) {
48
+ return /* @__PURE__ */ jsx(
49
+ "span",
50
+ {
51
+ "data-slot": "breadcrumb-page",
52
+ role: "link",
53
+ "aria-disabled": "true",
54
+ "aria-current": "page",
55
+ className: cn("text-foreground font-normal", className),
56
+ ...props
57
+ }
58
+ );
59
+ }
60
+ function BreadcrumbSeparator({
61
+ children,
62
+ className,
63
+ ...props
64
+ }) {
65
+ return /* @__PURE__ */ jsx(
66
+ "li",
67
+ {
68
+ "data-slot": "breadcrumb-separator",
69
+ role: "presentation",
70
+ "aria-hidden": "true",
71
+ className: cn("[&>svg]:size-3.5", className),
72
+ ...props,
73
+ children: children ?? /* @__PURE__ */ jsx(ChevronRight, {})
74
+ }
75
+ );
76
+ }
77
+ function BreadcrumbEllipsis({
78
+ className,
79
+ ...props
80
+ }) {
81
+ return /* @__PURE__ */ jsxs(
82
+ "span",
83
+ {
84
+ "data-slot": "breadcrumb-ellipsis",
85
+ role: "presentation",
86
+ "aria-hidden": "true",
87
+ className: cn("flex size-9 items-center justify-center", className),
88
+ ...props,
89
+ children: [
90
+ /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-4" }),
91
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "More" })
92
+ ]
93
+ }
94
+ );
95
+ }
96
+
97
+ export { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator };
98
+ //# sourceMappingURL=chunk-WAPGZIAL.js.map
99
+ //# sourceMappingURL=chunk-WAPGZIAL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/breadcrumb.tsx"],"names":[],"mappings":";;;;;AAMA,SAAS,UAAA,CAAW,EAAE,GAAG,KAAA,EAAM,EAAgC;AAC7D,EAAA,2BAAQ,KAAA,EAAA,EAAI,YAAA,EAAW,cAAa,WAAA,EAAU,YAAA,EAAc,GAAG,KAAA,EAAO,CAAA;AACxE;AAEA,SAAS,cAAA,CAAe,EAAE,SAAA,EAAW,GAAG,OAAM,EAA+B;AAC3E,EAAA,uBACE,GAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,iBAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,QACT,0FAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ;AAEA,SAAS,cAAA,CAAe,EAAE,SAAA,EAAW,GAAG,OAAM,EAA+B;AAC3E,EAAA,uBACE,GAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,iBAAA;AAAA,MACV,SAAA,EAAW,EAAA,CAAG,kCAAA,EAAoC,SAAS,CAAA;AAAA,MAC1D,GAAG;AAAA;AAAA,GACN;AAEJ;AAEA,SAAS,cAAA,CAAe;AAAA,EACtB,OAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAG;AACL,CAAA,EAEG;AACD,EAAA,MAAM,IAAA,GAAO,UAAU,IAAA,GAAO,GAAA;AAE9B,EAAA,uBACE,GAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,iBAAA;AAAA,MACV,SAAA,EAAW,EAAA,CAAG,yCAAA,EAA2C,SAAS,CAAA;AAAA,MACjE,GAAG;AAAA;AAAA,GACN;AAEJ;AAEA,SAAS,cAAA,CAAe,EAAE,SAAA,EAAW,GAAG,OAAM,EAAiC;AAC7E,EAAA,uBACE,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,iBAAA;AAAA,MACV,IAAA,EAAK,MAAA;AAAA,MACL,eAAA,EAAc,MAAA;AAAA,MACd,cAAA,EAAa,MAAA;AAAA,MACb,SAAA,EAAW,EAAA,CAAG,6BAAA,EAA+B,SAAS,CAAA;AAAA,MACrD,GAAG;AAAA;AAAA,GACN;AAEJ;AAEA,SAAS,mBAAA,CAAoB;AAAA,EAC3B,QAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAG;AACL,CAAA,EAA+B;AAC7B,EAAA,uBACE,GAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,sBAAA;AAAA,MACV,IAAA,EAAK,cAAA;AAAA,MACL,aAAA,EAAY,MAAA;AAAA,MACZ,SAAA,EAAW,EAAA,CAAG,kBAAA,EAAoB,SAAS,CAAA;AAAA,MAC1C,GAAG,KAAA;AAAA,MAEH,QAAA,EAAA,QAAA,wBAAa,YAAA,EAAA,EAAa;AAAA;AAAA,GAC7B;AAEJ;AAEA,SAAS,kBAAA,CAAmB;AAAA,EAC1B,SAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAiC;AAC/B,EAAA,uBACE,IAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,qBAAA;AAAA,MACV,IAAA,EAAK,cAAA;AAAA,MACL,aAAA,EAAY,MAAA;AAAA,MACZ,SAAA,EAAW,EAAA,CAAG,yCAAA,EAA2C,SAAS,CAAA;AAAA,MACjE,GAAG,KAAA;AAAA,MAEJ,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,cAAA,EAAA,EAAe,WAAU,QAAA,EAAS,CAAA;AAAA,wBACnC,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAU,QAAA,EAAA,MAAA,EAAI;AAAA;AAAA;AAAA,GAChC;AAEJ","file":"chunk-WAPGZIAL.js","sourcesContent":["import * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { ChevronRight, MoreHorizontal } from \"lucide-react\";\n\nimport { cn } from \"../lib/utils\";\n\nfunction Breadcrumb({ ...props }: React.ComponentProps<\"nav\">) {\n return <nav aria-label=\"breadcrumb\" data-slot=\"breadcrumb\" {...props} />;\n}\n\nfunction BreadcrumbList({ className, ...props }: React.ComponentProps<\"ol\">) {\n return (\n <ol\n data-slot=\"breadcrumb-list\"\n className={cn(\n \"text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbItem({ className, ...props }: React.ComponentProps<\"li\">) {\n return (\n <li\n data-slot=\"breadcrumb-item\"\n className={cn(\"inline-flex items-center gap-1.5\", className)}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbLink({\n asChild,\n className,\n ...props\n}: React.ComponentProps<\"a\"> & {\n asChild?: boolean;\n}) {\n const Comp = asChild ? Slot : \"a\";\n\n return (\n <Comp\n data-slot=\"breadcrumb-link\"\n className={cn(\"hover:text-foreground transition-colors\", className)}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbPage({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"breadcrumb-page\"\n role=\"link\"\n aria-disabled=\"true\"\n aria-current=\"page\"\n className={cn(\"text-foreground font-normal\", className)}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbSeparator({\n children,\n className,\n ...props\n}: React.ComponentProps<\"li\">) {\n return (\n <li\n data-slot=\"breadcrumb-separator\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn(\"[&>svg]:size-3.5\", className)}\n {...props}\n >\n {children ?? <ChevronRight />}\n </li>\n );\n}\n\nfunction BreadcrumbEllipsis({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"breadcrumb-ellipsis\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn(\"flex size-9 items-center justify-center\", className)}\n {...props}\n >\n <MoreHorizontal className=\"size-4\" />\n <span className=\"sr-only\">More</span>\n </span>\n );\n}\n\nexport {\n Breadcrumb,\n BreadcrumbList,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbPage,\n BreadcrumbSeparator,\n BreadcrumbEllipsis,\n};\n"]}
@@ -0,0 +1,23 @@
1
+ import * as React from 'react';
2
+
3
+ // src/hooks/use-mobile.ts
4
+ var MOBILE_BREAKPOINT = 768;
5
+ function useIsMobile() {
6
+ const [isMobile, setIsMobile] = React.useState(
7
+ void 0
8
+ );
9
+ React.useEffect(() => {
10
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
11
+ const onChange = () => {
12
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
13
+ };
14
+ mql.addEventListener("change", onChange);
15
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
16
+ return () => mql.removeEventListener("change", onChange);
17
+ }, []);
18
+ return !!isMobile;
19
+ }
20
+
21
+ export { useIsMobile };
22
+ //# sourceMappingURL=chunk-WRCHR4AK.js.map
23
+ //# sourceMappingURL=chunk-WRCHR4AK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/use-mobile.ts"],"names":[],"mappings":";;;AAEA,IAAM,iBAAA,GAAoB,GAAA;AAEnB,SAAS,WAAA,GAAc;AAC5B,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAU,KAAA,CAAA,QAAA;AAAA,IACpC;AAAA,GACF;AAEA,EAAM,gBAAU,MAAM;AACpB,IAAA,MAAM,MAAM,MAAA,CAAO,UAAA,CAAW,CAAA,YAAA,EAAe,iBAAA,GAAoB,CAAC,CAAA,GAAA,CAAK,CAAA;AACvE,IAAA,MAAM,WAAW,MAAM;AACrB,MAAA,WAAA,CAAY,MAAA,CAAO,aAAa,iBAAiB,CAAA;AAAA,IACnD,CAAA;AACA,IAAA,GAAA,CAAI,gBAAA,CAAiB,UAAU,QAAQ,CAAA;AACvC,IAAA,WAAA,CAAY,MAAA,CAAO,aAAa,iBAAiB,CAAA;AACjD,IAAA,OAAO,MAAM,GAAA,CAAI,mBAAA,CAAoB,QAAA,EAAU,QAAQ,CAAA;AAAA,EACzD,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,CAAC,CAAC,QAAA;AACX","file":"chunk-WRCHR4AK.js","sourcesContent":["import * as React from \"react\";\n\nconst MOBILE_BREAKPOINT = 768;\n\nexport function useIsMobile() {\n const [isMobile, setIsMobile] = React.useState<boolean | undefined>(\n undefined,\n );\n\n React.useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);\n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n };\n mql.addEventListener(\"change\", onChange);\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n return () => mql.removeEventListener(\"change\", onChange);\n }, []);\n\n return !!isMobile;\n}\n"]}
@@ -0,0 +1,51 @@
1
+ import { Badge } from './chunk-3TGN2DFB.js';
2
+ import { cn } from './chunk-DGPY4WP3.js';
3
+ import { MoreHorizontal, FileText, FileSignature, ShoppingCart, Receipt, Calendar } from 'lucide-react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ var categoryConfig = {
7
+ leave: {
8
+ icon: Calendar,
9
+ style: "bg-blue-50 dark:bg-blue-500/15 text-blue-600 dark:text-blue-400 border-blue-200 dark:border-blue-500/30"
10
+ },
11
+ expense: {
12
+ icon: Receipt,
13
+ style: "bg-green-50 dark:bg-green-500/15 text-green-600 dark:text-green-400 border-green-200 dark:border-green-500/30"
14
+ },
15
+ purchase: {
16
+ icon: ShoppingCart,
17
+ style: "bg-amber-50 dark:bg-amber-500/15 text-amber-600 dark:text-amber-400 border-amber-200 dark:border-amber-500/30"
18
+ },
19
+ contract: {
20
+ icon: FileSignature,
21
+ style: "bg-purple-50 dark:bg-purple-500/15 text-purple-600 dark:text-purple-400 border-purple-200 dark:border-purple-500/30"
22
+ },
23
+ document: {
24
+ icon: FileText,
25
+ style: "bg-cyan-50 dark:bg-cyan-500/15 text-cyan-600 dark:text-cyan-400 border-cyan-200 dark:border-cyan-500/30"
26
+ },
27
+ other: {
28
+ icon: MoreHorizontal,
29
+ style: "bg-muted text-muted-foreground"
30
+ }
31
+ };
32
+ var defaultLabels = {
33
+ leave: "Leave",
34
+ expense: "Expense",
35
+ purchase: "Purchase",
36
+ contract: "Contract",
37
+ document: "Document",
38
+ other: "Other"
39
+ };
40
+ function WorkflowCategoryBadge({ category, label, className }) {
41
+ const config = categoryConfig[category];
42
+ const Icon = config.icon;
43
+ return /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: cn(config.style, className), children: [
44
+ /* @__PURE__ */ jsx(Icon, { className: "w-3 h-3 mr-1" }),
45
+ label ?? defaultLabels[category]
46
+ ] });
47
+ }
48
+
49
+ export { WorkflowCategoryBadge };
50
+ //# sourceMappingURL=chunk-XKVHX75G.js.map
51
+ //# sourceMappingURL=chunk-XKVHX75G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/workflow-category-badge.tsx"],"names":[],"mappings":";;;;;AA6BA,IAAM,cAAA,GAAqF;AAAA,EACzF,KAAA,EAAO;AAAA,IACL,IAAA,EAAM,QAAA;AAAA,IACN,KAAA,EACE;AAAA,GACJ;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,OAAA;AAAA,IACN,KAAA,EACE;AAAA,GACJ;AAAA,EACA,QAAA,EAAU;AAAA,IACR,IAAA,EAAM,YAAA;AAAA,IACN,KAAA,EACE;AAAA,GACJ;AAAA,EACA,QAAA,EAAU;AAAA,IACR,IAAA,EAAM,aAAA;AAAA,IACN,KAAA,EACE;AAAA,GACJ;AAAA,EACA,QAAA,EAAU;AAAA,IACR,IAAA,EAAM,QAAA;AAAA,IACN,KAAA,EACE;AAAA,GACJ;AAAA,EACA,KAAA,EAAO;AAAA,IACL,IAAA,EAAM,cAAA;AAAA,IACN,KAAA,EAAO;AAAA;AAEX,CAAA;AAEA,IAAM,aAAA,GAAkD;AAAA,EACtD,KAAA,EAAO,OAAA;AAAA,EACP,OAAA,EAAS,SAAA;AAAA,EACT,QAAA,EAAU,UAAA;AAAA,EACV,QAAA,EAAU,UAAA;AAAA,EACV,QAAA,EAAU,UAAA;AAAA,EACV,KAAA,EAAO;AACT,CAAA;AAaO,SAAS,qBAAA,CAAsB,EAAE,QAAA,EAAU,KAAA,EAAO,WAAU,EAA+B;AAChG,EAAA,MAAM,MAAA,GAAS,eAAe,QAAQ,CAAA;AACtC,EAAA,MAAM,OAAO,MAAA,CAAO,IAAA;AAEpB,EAAA,uBACE,IAAA,CAAC,SAAM,OAAA,EAAQ,SAAA,EAAU,WAAW,EAAA,CAAG,MAAA,CAAO,KAAA,EAAO,SAAS,CAAA,EAC5D,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,WAAU,cAAA,EAAe,CAAA;AAAA,IAC9B,KAAA,IAAS,cAAc,QAAQ;AAAA,GAAA,EAClC,CAAA;AAEJ","file":"chunk-XKVHX75G.js","sourcesContent":["import {\n Calendar,\n Receipt,\n ShoppingCart,\n FileSignature,\n FileText,\n MoreHorizontal,\n} from 'lucide-react';\nimport { cn } from '../lib/utils';\nimport { Badge } from './badge';\n\n/** Supported workflow categories with built-in icon and color mappings. */\nexport type WorkflowCategory =\n | 'leave'\n | 'expense'\n | 'purchase'\n | 'contract'\n | 'document'\n | 'other';\n\nexport interface WorkflowCategoryBadgeProps {\n /** The category key. Determines the icon and color. */\n category: WorkflowCategory;\n /** The displayed label text. Defaults to a capitalized version of the category. */\n label?: string;\n /** Optional additional className. */\n className?: string;\n}\n\nconst categoryConfig: Record<WorkflowCategory, { icon: typeof Calendar; style: string }> = {\n leave: {\n icon: Calendar,\n style:\n 'bg-blue-50 dark:bg-blue-500/15 text-blue-600 dark:text-blue-400 border-blue-200 dark:border-blue-500/30',\n },\n expense: {\n icon: Receipt,\n style:\n 'bg-green-50 dark:bg-green-500/15 text-green-600 dark:text-green-400 border-green-200 dark:border-green-500/30',\n },\n purchase: {\n icon: ShoppingCart,\n style:\n 'bg-amber-50 dark:bg-amber-500/15 text-amber-600 dark:text-amber-400 border-amber-200 dark:border-amber-500/30',\n },\n contract: {\n icon: FileSignature,\n style:\n 'bg-purple-50 dark:bg-purple-500/15 text-purple-600 dark:text-purple-400 border-purple-200 dark:border-purple-500/30',\n },\n document: {\n icon: FileText,\n style:\n 'bg-cyan-50 dark:bg-cyan-500/15 text-cyan-600 dark:text-cyan-400 border-cyan-200 dark:border-cyan-500/30',\n },\n other: {\n icon: MoreHorizontal,\n style: 'bg-muted text-muted-foreground',\n },\n};\n\nconst defaultLabels: Record<WorkflowCategory, string> = {\n leave: 'Leave',\n expense: 'Expense',\n purchase: 'Purchase',\n contract: 'Contract',\n document: 'Document',\n other: 'Other',\n};\n\n/**\n * WorkflowCategoryBadge renders a badge with an icon and color for a workflow category.\n *\n * Each category has a dedicated icon and color scheme:\n * - leave: Calendar (blue)\n * - expense: Receipt (green)\n * - purchase: ShoppingCart (amber)\n * - contract: FileSignature (purple)\n * - document: FileText (cyan)\n * - other: MoreHorizontal (muted)\n */\nexport function WorkflowCategoryBadge({ category, label, className }: WorkflowCategoryBadgeProps) {\n const config = categoryConfig[category];\n const Icon = config.icon;\n\n return (\n <Badge variant=\"outline\" className={cn(config.style, className)}>\n <Icon className=\"w-3 h-3 mr-1\" />\n {label ?? defaultLabels[category]}\n </Badge>\n );\n}\n"]}
@@ -0,0 +1,41 @@
1
+ import { Badge } from './chunk-3TGN2DFB.js';
2
+ import { cn } from './chunk-DGPY4WP3.js';
3
+ import { GitBranch, Bell, Eye, CheckCircle } from 'lucide-react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ var stageConfig = {
7
+ approval: {
8
+ icon: CheckCircle,
9
+ style: "bg-green-50 dark:bg-green-500/15 text-green-600 dark:text-green-400 border-green-200 dark:border-green-500/30"
10
+ },
11
+ review: {
12
+ icon: Eye,
13
+ style: "bg-blue-50 dark:bg-blue-500/15 text-blue-600 dark:text-blue-400 border-blue-200 dark:border-blue-500/30"
14
+ },
15
+ notification: {
16
+ icon: Bell,
17
+ style: "bg-amber-50 dark:bg-amber-500/15 text-amber-600 dark:text-amber-400 border-amber-200 dark:border-amber-500/30"
18
+ },
19
+ conditional: {
20
+ icon: GitBranch,
21
+ style: "bg-purple-50 dark:bg-purple-500/15 text-purple-600 dark:text-purple-400 border-purple-200 dark:border-purple-500/30"
22
+ }
23
+ };
24
+ var defaultLabels = {
25
+ approval: "Approval",
26
+ review: "Review",
27
+ notification: "Notification",
28
+ conditional: "Conditional"
29
+ };
30
+ function StageTypeBadge({ type, label, className }) {
31
+ const config = stageConfig[type];
32
+ const Icon = config.icon;
33
+ return /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: cn(config.style, className), children: [
34
+ /* @__PURE__ */ jsx(Icon, { className: "w-3 h-3 mr-1" }),
35
+ label ?? defaultLabels[type]
36
+ ] });
37
+ }
38
+
39
+ export { StageTypeBadge };
40
+ //# sourceMappingURL=chunk-YF6WRCTG.js.map
41
+ //# sourceMappingURL=chunk-YF6WRCTG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/stage-type-badge.tsx"],"names":[],"mappings":";;;;;AAgBA,IAAM,WAAA,GAA8E;AAAA,EAClF,QAAA,EAAU;AAAA,IACR,IAAA,EAAM,WAAA;AAAA,IACN,KAAA,EACE;AAAA,GACJ;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,GAAA;AAAA,IACN,KAAA,EACE;AAAA,GACJ;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,IAAA,EAAM,IAAA;AAAA,IACN,KAAA,EACE;AAAA,GACJ;AAAA,EACA,WAAA,EAAa;AAAA,IACX,IAAA,EAAM,SAAA;AAAA,IACN,KAAA,EACE;AAAA;AAEN,CAAA;AAEA,IAAM,aAAA,GAA2C;AAAA,EAC/C,QAAA,EAAU,UAAA;AAAA,EACV,MAAA,EAAQ,QAAA;AAAA,EACR,YAAA,EAAc,cAAA;AAAA,EACd,WAAA,EAAa;AACf,CAAA;AAWO,SAAS,cAAA,CAAe,EAAE,IAAA,EAAM,KAAA,EAAO,WAAU,EAAwB;AAC9E,EAAA,MAAM,MAAA,GAAS,YAAY,IAAI,CAAA;AAC/B,EAAA,MAAM,OAAO,MAAA,CAAO,IAAA;AAEpB,EAAA,uBACE,IAAA,CAAC,SAAM,OAAA,EAAQ,SAAA,EAAU,WAAW,EAAA,CAAG,MAAA,CAAO,KAAA,EAAO,SAAS,CAAA,EAC5D,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,WAAU,cAAA,EAAe,CAAA;AAAA,IAC9B,KAAA,IAAS,cAAc,IAAI;AAAA,GAAA,EAC9B,CAAA;AAEJ","file":"chunk-YF6WRCTG.js","sourcesContent":["import { CheckCircle, Eye, Bell, GitBranch } from 'lucide-react';\nimport { cn } from '../lib/utils';\nimport { Badge } from './badge';\n\n/** Supported stage types with built-in icon and color mappings. */\nexport type StageType = 'approval' | 'review' | 'notification' | 'conditional';\n\nexport interface StageTypeBadgeProps {\n /** The stage type key. Determines the icon and color. */\n type: StageType;\n /** The displayed label text. Defaults to a capitalized version of the type. */\n label?: string;\n /** Optional additional className. */\n className?: string;\n}\n\nconst stageConfig: Record<StageType, { icon: typeof CheckCircle; style: string }> = {\n approval: {\n icon: CheckCircle,\n style:\n 'bg-green-50 dark:bg-green-500/15 text-green-600 dark:text-green-400 border-green-200 dark:border-green-500/30',\n },\n review: {\n icon: Eye,\n style:\n 'bg-blue-50 dark:bg-blue-500/15 text-blue-600 dark:text-blue-400 border-blue-200 dark:border-blue-500/30',\n },\n notification: {\n icon: Bell,\n style:\n 'bg-amber-50 dark:bg-amber-500/15 text-amber-600 dark:text-amber-400 border-amber-200 dark:border-amber-500/30',\n },\n conditional: {\n icon: GitBranch,\n style:\n 'bg-purple-50 dark:bg-purple-500/15 text-purple-600 dark:text-purple-400 border-purple-200 dark:border-purple-500/30',\n },\n};\n\nconst defaultLabels: Record<StageType, string> = {\n approval: 'Approval',\n review: 'Review',\n notification: 'Notification',\n conditional: 'Conditional',\n};\n\n/**\n * StageTypeBadge renders a badge with an icon and color for a workflow stage type.\n *\n * Each type has a dedicated icon and color scheme:\n * - approval: CheckCircle (green)\n * - review: Eye (blue)\n * - notification: Bell (amber)\n * - conditional: GitBranch (purple)\n */\nexport function StageTypeBadge({ type, label, className }: StageTypeBadgeProps) {\n const config = stageConfig[type];\n const Icon = config.icon;\n\n return (\n <Badge variant=\"outline\" className={cn(config.style, className)}>\n <Icon className=\"w-3 h-3 mr-1\" />\n {label ?? defaultLabels[type]}\n </Badge>\n );\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import { cn } from './chunk-DGPY4WP3.js';
2
+ import * as React from 'react';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ var Input = React.forwardRef(
6
+ ({ className, type, ...props }, ref) => {
7
+ return /* @__PURE__ */ jsx(
8
+ "input",
9
+ {
10
+ type,
11
+ ref,
12
+ "data-slot": "input",
13
+ className: cn(
14
+ "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-element w-full min-w-0 rounded-md border px-3 py-1 text-base bg-input-background transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
15
+ "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
16
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
17
+ className
18
+ ),
19
+ ...props
20
+ }
21
+ );
22
+ }
23
+ );
24
+ Input.displayName = "Input";
25
+
26
+ export { Input };
27
+ //# sourceMappingURL=chunk-YGBYH4EO.js.map
28
+ //# sourceMappingURL=chunk-YGBYH4EO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/input.tsx"],"names":[],"mappings":";;;;AAIA,IAAM,KAAA,GAAc,KAAA,CAAA,UAAA;AAAA,EAClB,CAAC,EAAE,SAAA,EAAW,MAAM,GAAG,KAAA,IAAS,GAAA,KAAQ;AACtC,IAAA,uBACE,GAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,IAAA;AAAA,QACA,GAAA;AAAA,QACA,WAAA,EAAU,OAAA;AAAA,QACV,SAAA,EAAW,EAAA;AAAA,UACT,kcAAA;AAAA,UACA,+EAAA;AAAA,UACA,wGAAA;AAAA,UACA;AAAA,SACF;AAAA,QACC,GAAG;AAAA;AAAA,KACN;AAAA,EAEJ;AACF;AACA,KAAA,CAAM,WAAA,GAAc,OAAA","file":"chunk-YGBYH4EO.js","sourcesContent":["import * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nconst Input = React.forwardRef<HTMLInputElement, React.ComponentProps<\"input\">>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n ref={ref}\n data-slot=\"input\"\n className={cn(\n \"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-element w-full min-w-0 rounded-md border px-3 py-1 text-base bg-input-background transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n \"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]\",\n \"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n className,\n )}\n {...props}\n />\n );\n }\n);\nInput.displayName = \"Input\";\n\nexport { Input };"]}
@@ -0,0 +1,109 @@
1
+ import { cn } from './chunk-DGPY4WP3.js';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ function Table({ className, ...props }) {
5
+ return /* @__PURE__ */ jsx(
6
+ "div",
7
+ {
8
+ "data-slot": "table-container",
9
+ className: "relative w-full overflow-x-auto",
10
+ children: /* @__PURE__ */ jsx(
11
+ "table",
12
+ {
13
+ "data-slot": "table",
14
+ className: cn("w-full caption-bottom text-sm", className),
15
+ ...props
16
+ }
17
+ )
18
+ }
19
+ );
20
+ }
21
+ function TableHeader({ className, ...props }) {
22
+ return /* @__PURE__ */ jsx(
23
+ "thead",
24
+ {
25
+ "data-slot": "table-header",
26
+ className: cn("[&_tr]:border-b", className),
27
+ ...props
28
+ }
29
+ );
30
+ }
31
+ function TableBody({ className, ...props }) {
32
+ return /* @__PURE__ */ jsx(
33
+ "tbody",
34
+ {
35
+ "data-slot": "table-body",
36
+ className: cn("[&_tr:last-child]:border-0", className),
37
+ ...props
38
+ }
39
+ );
40
+ }
41
+ function TableFooter({ className, ...props }) {
42
+ return /* @__PURE__ */ jsx(
43
+ "tfoot",
44
+ {
45
+ "data-slot": "table-footer",
46
+ className: cn(
47
+ "bg-muted/50 border-t font-medium [&>tr]:last:border-b-0",
48
+ className
49
+ ),
50
+ ...props
51
+ }
52
+ );
53
+ }
54
+ function TableRow({ className, ...props }) {
55
+ return /* @__PURE__ */ jsx(
56
+ "tr",
57
+ {
58
+ "data-slot": "table-row",
59
+ className: cn(
60
+ "hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
61
+ className
62
+ ),
63
+ ...props
64
+ }
65
+ );
66
+ }
67
+ function TableHead({ className, ...props }) {
68
+ return /* @__PURE__ */ jsx(
69
+ "th",
70
+ {
71
+ "data-slot": "table-head",
72
+ className: cn(
73
+ "text-foreground h-table-head px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
74
+ className
75
+ ),
76
+ ...props
77
+ }
78
+ );
79
+ }
80
+ function TableCell({ className, ...props }) {
81
+ return /* @__PURE__ */ jsx(
82
+ "td",
83
+ {
84
+ "data-slot": "table-cell",
85
+ className: cn(
86
+ "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
87
+ className
88
+ ),
89
+ ...props
90
+ }
91
+ );
92
+ }
93
+ function TableCaption({
94
+ className,
95
+ ...props
96
+ }) {
97
+ return /* @__PURE__ */ jsx(
98
+ "caption",
99
+ {
100
+ "data-slot": "table-caption",
101
+ className: cn("text-muted-foreground mt-4 text-sm", className),
102
+ ...props
103
+ }
104
+ );
105
+ }
106
+
107
+ export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow };
108
+ //# sourceMappingURL=chunk-YKJZV2JK.js.map
109
+ //# sourceMappingURL=chunk-YKJZV2JK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/table.tsx"],"names":[],"mappings":";;;AAIA,SAAS,KAAA,CAAM,EAAE,SAAA,EAAW,GAAG,OAAM,EAAkC;AACrE,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,iBAAA;AAAA,MACV,SAAA,EAAU,iCAAA;AAAA,MAEV,QAAA,kBAAA,GAAA;AAAA,QAAC,OAAA;AAAA,QAAA;AAAA,UACC,WAAA,EAAU,OAAA;AAAA,UACV,SAAA,EAAW,EAAA,CAAG,+BAAA,EAAiC,SAAS,CAAA;AAAA,UACvD,GAAG;AAAA;AAAA;AACN;AAAA,GACF;AAEJ;AAEA,SAAS,WAAA,CAAY,EAAE,SAAA,EAAW,GAAG,OAAM,EAAkC;AAC3E,EAAA,uBACE,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,cAAA;AAAA,MACV,SAAA,EAAW,EAAA,CAAG,iBAAA,EAAmB,SAAS,CAAA;AAAA,MACzC,GAAG;AAAA;AAAA,GACN;AAEJ;AAEA,SAAS,SAAA,CAAU,EAAE,SAAA,EAAW,GAAG,OAAM,EAAkC;AACzE,EAAA,uBACE,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,YAAA;AAAA,MACV,SAAA,EAAW,EAAA,CAAG,4BAAA,EAA8B,SAAS,CAAA;AAAA,MACpD,GAAG;AAAA;AAAA,GACN;AAEJ;AAEA,SAAS,WAAA,CAAY,EAAE,SAAA,EAAW,GAAG,OAAM,EAAkC;AAC3E,EAAA,uBACE,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,cAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,QACT,yDAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ;AAEA,SAAS,QAAA,CAAS,EAAE,SAAA,EAAW,GAAG,OAAM,EAA+B;AACrE,EAAA,uBACE,GAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,WAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,QACT,6EAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ;AAEA,SAAS,SAAA,CAAU,EAAE,SAAA,EAAW,GAAG,OAAM,EAA+B;AACtE,EAAA,uBACE,GAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,YAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,QACT,4JAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ;AAEA,SAAS,SAAA,CAAU,EAAE,SAAA,EAAW,GAAG,OAAM,EAA+B;AACtE,EAAA,uBACE,GAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,YAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,QACT,wGAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ;AAEA,SAAS,YAAA,CAAa;AAAA,EACpB,SAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAoC;AAClC,EAAA,uBACE,GAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,eAAA;AAAA,MACV,SAAA,EAAW,EAAA,CAAG,oCAAA,EAAsC,SAAS,CAAA;AAAA,MAC5D,GAAG;AAAA;AAAA,GACN;AAEJ","file":"chunk-YKJZV2JK.js","sourcesContent":["import * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nfunction Table({ className, ...props }: React.ComponentProps<\"table\">) {\n return (\n <div\n data-slot=\"table-container\"\n className=\"relative w-full overflow-x-auto\"\n >\n <table\n data-slot=\"table\"\n className={cn(\"w-full caption-bottom text-sm\", className)}\n {...props}\n />\n </div>\n );\n}\n\nfunction TableHeader({ className, ...props }: React.ComponentProps<\"thead\">) {\n return (\n <thead\n data-slot=\"table-header\"\n className={cn(\"[&_tr]:border-b\", className)}\n {...props}\n />\n );\n}\n\nfunction TableBody({ className, ...props }: React.ComponentProps<\"tbody\">) {\n return (\n <tbody\n data-slot=\"table-body\"\n className={cn(\"[&_tr:last-child]:border-0\", className)}\n {...props}\n />\n );\n}\n\nfunction TableFooter({ className, ...props }: React.ComponentProps<\"tfoot\">) {\n return (\n <tfoot\n data-slot=\"table-footer\"\n className={cn(\n \"bg-muted/50 border-t font-medium [&>tr]:last:border-b-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableRow({ className, ...props }: React.ComponentProps<\"tr\">) {\n return (\n <tr\n data-slot=\"table-row\"\n className={cn(\n \"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableHead({ className, ...props }: React.ComponentProps<\"th\">) {\n return (\n <th\n data-slot=\"table-head\"\n className={cn(\n \"text-foreground h-table-head px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableCell({ className, ...props }: React.ComponentProps<\"td\">) {\n return (\n <td\n data-slot=\"table-cell\"\n className={cn(\n \"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableCaption({\n className,\n ...props\n}: React.ComponentProps<\"caption\">) {\n return (\n <caption\n data-slot=\"table-caption\"\n className={cn(\"text-muted-foreground mt-4 text-sm\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Table,\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n TableCaption,\n};"]}