@wakastellar/ui 2.0.0 → 2.1.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 (290) hide show
  1. package/dist/cli/commands/add.d.ts +7 -0
  2. package/dist/cli/commands/init.d.ts +6 -0
  3. package/dist/cli/commands/list.d.ts +5 -0
  4. package/dist/cli/commands/search.d.ts +1 -0
  5. package/dist/cli/index.cjs +4844 -0
  6. package/dist/cli/index.d.ts +1 -0
  7. package/dist/cli/utils/config.d.ts +29 -0
  8. package/dist/cli/utils/logger.d.ts +20 -0
  9. package/dist/cli/utils/registry.d.ts +23 -0
  10. package/package.json +14 -3
  11. package/src/blocks/activity-timeline/index.tsx +586 -0
  12. package/src/blocks/calendar-view/index.tsx +756 -0
  13. package/src/blocks/chat/index.tsx +1018 -0
  14. package/src/blocks/chat/widget.tsx +504 -0
  15. package/src/blocks/dashboard/index.tsx +522 -0
  16. package/src/blocks/empty-states/index.tsx +452 -0
  17. package/src/blocks/error-pages/index.tsx +426 -0
  18. package/src/blocks/faq/index.tsx +479 -0
  19. package/src/blocks/file-manager/index.tsx +890 -0
  20. package/src/blocks/footer/index.tsx +133 -0
  21. package/src/blocks/header/index.tsx +357 -0
  22. package/src/blocks/headtab/index.tsx +139 -0
  23. package/src/blocks/i18n-editor/index.tsx +1016 -0
  24. package/src/blocks/index.ts +80 -0
  25. package/src/blocks/kanban-board/index.tsx +779 -0
  26. package/src/blocks/landing/index.tsx +677 -0
  27. package/src/blocks/language-selector/index.tsx +88 -0
  28. package/src/blocks/layout/index.tsx +159 -0
  29. package/src/blocks/login/index.tsx +339 -0
  30. package/src/blocks/login/types.ts +131 -0
  31. package/src/blocks/pricing/index.tsx +564 -0
  32. package/src/blocks/profile/index.tsx +746 -0
  33. package/src/blocks/settings/index.tsx +558 -0
  34. package/src/blocks/sidebar/index.tsx +713 -0
  35. package/src/blocks/theme-creator-block/index.tsx +835 -0
  36. package/src/blocks/user-management/index.tsx +1037 -0
  37. package/src/blocks/wizard/index.tsx +719 -0
  38. package/src/components/DataTable/DataTable.tsx +406 -0
  39. package/src/components/DataTable/DataTableAdvanced.tsx +720 -0
  40. package/src/components/DataTable/DataTableBody.tsx +216 -0
  41. package/src/components/DataTable/DataTableCell.tsx +172 -0
  42. package/src/components/DataTable/DataTableColumnResizer.tsx +62 -0
  43. package/src/components/DataTable/DataTableConflictResolver.tsx +478 -0
  44. package/src/components/DataTable/DataTableContextMenu.tsx +219 -0
  45. package/src/components/DataTable/DataTableEditCell.tsx +279 -0
  46. package/src/components/DataTable/DataTableFilterBuilder.tsx +519 -0
  47. package/src/components/DataTable/DataTableFilters.tsx +535 -0
  48. package/src/components/DataTable/DataTableGrouping.tsx +147 -0
  49. package/src/components/DataTable/DataTableHeader.tsx +172 -0
  50. package/src/components/DataTable/DataTablePagination.tsx +125 -0
  51. package/src/components/DataTable/DataTableSelection.tsx +269 -0
  52. package/src/components/DataTable/DataTableSyncStatus.tsx +281 -0
  53. package/src/components/DataTable/DataTableToolbar.tsx +262 -0
  54. package/src/components/DataTable/README.md +446 -0
  55. package/src/components/DataTable/__tests__/DataTableAdvanced.test.tsx +426 -0
  56. package/src/components/DataTable/__tests__/DataTableEdit.test.tsx +329 -0
  57. package/src/components/DataTable/__tests__/useDataTableAdvanced.test.ts +455 -0
  58. package/src/components/DataTable/examples/EditExample.tsx +166 -0
  59. package/src/components/DataTable/formatters/index.ts +335 -0
  60. package/src/components/DataTable/hooks/__tests__/useDataTableEdit.test.ts +239 -0
  61. package/src/components/DataTable/hooks/useDataTable.ts +145 -0
  62. package/src/components/DataTable/hooks/useDataTableAdvanced.ts +342 -0
  63. package/src/components/DataTable/hooks/useDataTableAdvancedFilters.ts +637 -0
  64. package/src/components/DataTable/hooks/useDataTableColumnTemplates.ts +186 -0
  65. package/src/components/DataTable/hooks/useDataTableEdit.ts +167 -0
  66. package/src/components/DataTable/hooks/useDataTableExport.ts +227 -0
  67. package/src/components/DataTable/hooks/useDataTableImport.ts +216 -0
  68. package/src/components/DataTable/hooks/useDataTableOffline.ts +481 -0
  69. package/src/components/DataTable/hooks/useDataTableTheme.ts +213 -0
  70. package/src/components/DataTable/hooks/useDataTableVirtualization.ts +99 -0
  71. package/src/components/DataTable/hooks/useTableLayout.ts +85 -0
  72. package/src/components/DataTable/index.ts +81 -0
  73. package/src/components/DataTable/services/IndexedDBService.ts +504 -0
  74. package/src/components/DataTable/templates/index.tsx +803 -0
  75. package/src/components/DataTable/types.ts +504 -0
  76. package/src/components/DataTable/utils.ts +164 -0
  77. package/src/components/DataTable/workers/exportWorker.ts +213 -0
  78. package/src/components/accordion/index.tsx +61 -0
  79. package/src/components/alert/index.tsx +61 -0
  80. package/src/components/alert-dialog/index.tsx +146 -0
  81. package/src/components/aspect-ratio/index.tsx +12 -0
  82. package/src/components/avatar/index.tsx +54 -0
  83. package/src/components/badge/Badge.stories.tsx +64 -0
  84. package/src/components/badge/index.tsx +38 -0
  85. package/src/components/button/Button.stories.tsx +173 -0
  86. package/src/components/button/index.tsx +56 -0
  87. package/src/components/calendar/index.tsx +73 -0
  88. package/src/components/card/index.tsx +78 -0
  89. package/src/components/checkbox/index.tsx +34 -0
  90. package/src/components/code/index.tsx +229 -0
  91. package/src/components/collapsible/index.tsx +16 -0
  92. package/src/components/command/index.tsx +162 -0
  93. package/src/components/context-menu/index.tsx +204 -0
  94. package/src/components/dialog/index.tsx +126 -0
  95. package/src/components/dropdown-menu/index.tsx +204 -0
  96. package/src/components/error-boundary/ErrorBoundary.tsx +281 -0
  97. package/src/components/error-boundary/index.ts +7 -0
  98. package/src/components/form/index.tsx +183 -0
  99. package/src/components/hover-card/index.tsx +33 -0
  100. package/src/components/index.ts +368 -0
  101. package/src/components/input/Input.stories.tsx +100 -0
  102. package/src/components/input/index.tsx +27 -0
  103. package/src/components/input-otp/index.tsx +277 -0
  104. package/src/components/label/index.tsx +30 -0
  105. package/src/components/language-selector/index.tsx +341 -0
  106. package/src/components/menubar/index.tsx +240 -0
  107. package/src/components/navigation-menu/index.tsx +134 -0
  108. package/src/components/popover/index.tsx +35 -0
  109. package/src/components/progress/index.tsx +32 -0
  110. package/src/components/radio-group/index.tsx +48 -0
  111. package/src/components/scroll-area/index.tsx +52 -0
  112. package/src/components/select/index.tsx +164 -0
  113. package/src/components/separator/index.tsx +35 -0
  114. package/src/components/sheet/index.tsx +147 -0
  115. package/src/components/skeleton/index.tsx +22 -0
  116. package/src/components/slider/index.tsx +32 -0
  117. package/src/components/switch/index.tsx +33 -0
  118. package/src/components/table/index.tsx +117 -0
  119. package/src/components/tabs/index.tsx +59 -0
  120. package/src/components/textarea/index.tsx +30 -0
  121. package/src/components/theme-selector/index.tsx +327 -0
  122. package/src/components/toast/index.tsx +133 -0
  123. package/src/components/toaster/index.tsx +34 -0
  124. package/src/components/toggle/index.tsx +49 -0
  125. package/src/components/tooltip/index.tsx +34 -0
  126. package/src/components/typography/index.tsx +276 -0
  127. package/src/components/waka-3d-pie-chart/index.tsx +486 -0
  128. package/src/components/waka-achievement-unlock/index.tsx +716 -0
  129. package/src/components/waka-activity-feed/index.tsx +686 -0
  130. package/src/components/waka-address-autocomplete/index.tsx +1202 -0
  131. package/src/components/waka-admincrumb/index.tsx +349 -0
  132. package/src/components/waka-alert-stack/index.tsx +827 -0
  133. package/src/components/waka-allocation-matrix/index.tsx +1278 -0
  134. package/src/components/waka-approval-chain/index.tsx +766 -0
  135. package/src/components/waka-audit-log/index.tsx +1475 -0
  136. package/src/components/waka-autocomplete/index.tsx +358 -0
  137. package/src/components/waka-badge-showcase/index.tsx +704 -0
  138. package/src/components/waka-barcode/index.tsx +260 -0
  139. package/src/components/waka-biometric-prompt/index.tsx +765 -0
  140. package/src/components/waka-bottom-sheet/index.tsx +495 -0
  141. package/src/components/waka-breadcrumb/index.tsx +376 -0
  142. package/src/components/waka-breadcrumb-path/index.tsx +513 -0
  143. package/src/components/waka-budget-burn/index.tsx +1234 -0
  144. package/src/components/waka-capacity-planner/index.tsx +1107 -0
  145. package/src/components/waka-carousel/index.tsx +893 -0
  146. package/src/components/waka-cart-summary/index.tsx +1055 -0
  147. package/src/components/waka-challenge-timer/index.tsx +1044 -0
  148. package/src/components/waka-charts/WakaAreaChart.tsx +251 -0
  149. package/src/components/waka-charts/WakaBarChart.tsx +222 -0
  150. package/src/components/waka-charts/WakaChart.tsx +124 -0
  151. package/src/components/waka-charts/WakaLineChart.tsx +219 -0
  152. package/src/components/waka-charts/WakaMiniChart.tsx +133 -0
  153. package/src/components/waka-charts/WakaPieChart.tsx +214 -0
  154. package/src/components/waka-charts/WakaSparkline.tsx +229 -0
  155. package/src/components/waka-charts/dataTableHelpers.ts +109 -0
  156. package/src/components/waka-charts/hooks/useChartTheme.ts +123 -0
  157. package/src/components/waka-charts/hooks/useRechartsLoader.ts +234 -0
  158. package/src/components/waka-charts/index.ts +90 -0
  159. package/src/components/waka-charts/types.ts +330 -0
  160. package/src/components/waka-chat-bubble/index.tsx +1060 -0
  161. package/src/components/waka-checklist/index.tsx +1067 -0
  162. package/src/components/waka-checkout-stepper/index.tsx +976 -0
  163. package/src/components/waka-cohort-table/index.tsx +1011 -0
  164. package/src/components/waka-color-picker/index.tsx +447 -0
  165. package/src/components/waka-combo-counter/index.tsx +864 -0
  166. package/src/components/waka-combobox/index.tsx +497 -0
  167. package/src/components/waka-command-bar/index.tsx +403 -0
  168. package/src/components/waka-compare-period/index.tsx +1230 -0
  169. package/src/components/waka-connection-matrix/index.tsx +1053 -0
  170. package/src/components/waka-contribution-graph/index.tsx +552 -0
  171. package/src/components/waka-cost-breakdown/index.tsx +1065 -0
  172. package/src/components/waka-coupon-input/index.tsx +592 -0
  173. package/src/components/waka-credit-card-input/index.tsx +982 -0
  174. package/src/components/waka-daily-reward/index.tsx +762 -0
  175. package/src/components/waka-date-range-picker/index.tsx +378 -0
  176. package/src/components/waka-datetime-picker/index.tsx +793 -0
  177. package/src/components/waka-datetime-picker.form-integration/index.tsx +402 -0
  178. package/src/components/waka-deployment-lane/index.tsx +673 -0
  179. package/src/components/waka-device-trust/index.tsx +1259 -0
  180. package/src/components/waka-dock/index.tsx +285 -0
  181. package/src/components/waka-drawer/index.tsx +319 -0
  182. package/src/components/waka-empty-state/index.tsx +545 -0
  183. package/src/components/waka-error-shake/index.tsx +398 -0
  184. package/src/components/waka-feature-announcement/index.tsx +991 -0
  185. package/src/components/waka-file-upload/index.tsx +437 -0
  186. package/src/components/waka-floating-nav/index.tsx +413 -0
  187. package/src/components/waka-flow-diagram/index.tsx +508 -0
  188. package/src/components/waka-funnel-chart/index.tsx +823 -0
  189. package/src/components/waka-glow-card/index.tsx +246 -0
  190. package/src/components/waka-goal-progress/index.tsx +1025 -0
  191. package/src/components/waka-haptic-button/index.tsx +388 -0
  192. package/src/components/waka-health-pulse/index.tsx +451 -0
  193. package/src/components/waka-heatmap/index.tsx +1026 -0
  194. package/src/components/waka-hotspot/index.tsx +682 -0
  195. package/src/components/waka-image/index.tsx +373 -0
  196. package/src/components/waka-incident-timeline/index.tsx +686 -0
  197. package/src/components/waka-invoice-preview/index.tsx +829 -0
  198. package/src/components/waka-kanban/index.tsx +646 -0
  199. package/src/components/waka-kpi-dashboard/index.tsx +755 -0
  200. package/src/components/waka-leaderboard/index.tsx +746 -0
  201. package/src/components/waka-level-progress/index.tsx +665 -0
  202. package/src/components/waka-liquid-button/index.tsx +520 -0
  203. package/src/components/waka-loading-orbit/index.tsx +478 -0
  204. package/src/components/waka-loot-box/index.tsx +1091 -0
  205. package/src/components/waka-magic-link/index.tsx +321 -0
  206. package/src/components/waka-magnetic-button/index.tsx +567 -0
  207. package/src/components/waka-mention-input/index.tsx +953 -0
  208. package/src/components/waka-metric-sparkline/index.tsx +627 -0
  209. package/src/components/waka-milestone-road/index.tsx +1064 -0
  210. package/src/components/waka-modal/index.tsx +374 -0
  211. package/src/components/waka-morph-button/index.tsx +495 -0
  212. package/src/components/waka-network-topology/index.tsx +801 -0
  213. package/src/components/waka-notifications/index.tsx +414 -0
  214. package/src/components/waka-number-input/index.tsx +373 -0
  215. package/src/components/waka-orbital-menu/index.tsx +445 -0
  216. package/src/components/waka-order-tracker/index.tsx +1041 -0
  217. package/src/components/waka-pagination/index.tsx +393 -0
  218. package/src/components/waka-password-strength/index.tsx +824 -0
  219. package/src/components/waka-payment-method-picker/index.tsx +715 -0
  220. package/src/components/waka-permission-matrix/index.tsx +1302 -0
  221. package/src/components/waka-phone-input/index.tsx +801 -0
  222. package/src/components/waka-pipeline-view/index.tsx +604 -0
  223. package/src/components/waka-player-card/index.tsx +691 -0
  224. package/src/components/waka-points-popup/index.tsx +366 -0
  225. package/src/components/waka-power-up/index.tsx +1155 -0
  226. package/src/components/waka-presence-indicator/index.tsx +1181 -0
  227. package/src/components/waka-pricing-table/index.tsx +755 -0
  228. package/src/components/waka-product-card/index.tsx +786 -0
  229. package/src/components/waka-progress-onboarding/index.tsx +878 -0
  230. package/src/components/waka-pull-to-refresh/index.tsx +451 -0
  231. package/src/components/waka-qrcode/index.tsx +232 -0
  232. package/src/components/waka-quest-card/index.tsx +1275 -0
  233. package/src/components/waka-quota-bar/index.tsx +693 -0
  234. package/src/components/waka-radar-score/index.tsx +512 -0
  235. package/src/components/waka-rank-badge/index.tsx +813 -0
  236. package/src/components/waka-rating-input/index.tsx +560 -0
  237. package/src/components/waka-reaction-picker/index.tsx +1062 -0
  238. package/src/components/waka-region-map/index.tsx +730 -0
  239. package/src/components/waka-resource-gauge/index.tsx +654 -0
  240. package/src/components/waka-resource-pool/index.tsx +1035 -0
  241. package/src/components/waka-rich-text-editor/index.tsx +594 -0
  242. package/src/components/waka-rollback-slider/index.tsx +891 -0
  243. package/src/components/waka-sankey-diagram/index.tsx +1032 -0
  244. package/src/components/waka-schedule-picker/index.tsx +1060 -0
  245. package/src/components/waka-scratch-card/index.tsx +914 -0
  246. package/src/components/waka-season-pass/index.tsx +886 -0
  247. package/src/components/waka-security-score/index.tsx +1126 -0
  248. package/src/components/waka-segmented-control/index.tsx +238 -0
  249. package/src/components/waka-server-rack/index.tsx +764 -0
  250. package/src/components/waka-session-manager/index.tsx +815 -0
  251. package/src/components/waka-signature-pad/index.tsx +744 -0
  252. package/src/components/waka-skeleton-wave/index.tsx +454 -0
  253. package/src/components/waka-skill-tree/index.tsx +1031 -0
  254. package/src/components/waka-sla-tracker/index.tsx +798 -0
  255. package/src/components/waka-slider-range/index.tsx +765 -0
  256. package/src/components/waka-spin-wheel/index.tsx +671 -0
  257. package/src/components/waka-spinner/index.tsx +284 -0
  258. package/src/components/waka-spotlight/index.tsx +410 -0
  259. package/src/components/waka-stat/index.tsx +428 -0
  260. package/src/components/waka-stats-hexagon/index.tsx +824 -0
  261. package/src/components/waka-status-matrix/index.tsx +565 -0
  262. package/src/components/waka-stepper/index.tsx +489 -0
  263. package/src/components/waka-streak-counter/index.tsx +334 -0
  264. package/src/components/waka-success-explosion/index.tsx +453 -0
  265. package/src/components/waka-swipe-card/index.tsx +574 -0
  266. package/src/components/waka-tabs-morph/index.tsx +509 -0
  267. package/src/components/waka-tag-input/index.tsx +877 -0
  268. package/src/components/waka-team-banner/index.tsx +1183 -0
  269. package/src/components/waka-terminal-output/index.tsx +836 -0
  270. package/src/components/waka-theme-creator/index.tsx +762 -0
  271. package/src/components/waka-theme-manager/index.tsx +654 -0
  272. package/src/components/waka-thread-view/index.tsx +874 -0
  273. package/src/components/waka-tilt-card/index.tsx +250 -0
  274. package/src/components/waka-time-picker/index.tsx +479 -0
  275. package/src/components/waka-timeline/index.tsx +385 -0
  276. package/src/components/waka-tooltip-tour/index.tsx +855 -0
  277. package/src/components/waka-tour-guide/index.tsx +920 -0
  278. package/src/components/waka-tournament-bracket/index.tsx +1276 -0
  279. package/src/components/waka-tree/index.tsx +557 -0
  280. package/src/components/waka-treemap-chart/index.tsx +1031 -0
  281. package/src/components/waka-two-factor-setup/index.tsx +995 -0
  282. package/src/components/waka-typewriter/index.tsx +566 -0
  283. package/src/components/waka-typing-indicator/index.tsx +649 -0
  284. package/src/components/waka-versus-card/index.tsx +1026 -0
  285. package/src/components/waka-video/index.tsx +557 -0
  286. package/src/components/waka-video-call/index.tsx +1087 -0
  287. package/src/components/waka-virtual-list/index.tsx +327 -0
  288. package/src/components/waka-voice-message/index.tsx +1019 -0
  289. package/src/components/waka-welcome-modal/index.tsx +790 -0
  290. package/src/components/waka-xp-bar/index.tsx +799 -0
@@ -0,0 +1,890 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "../../utils"
5
+ import { Button } from "../../components/button"
6
+ import { Input } from "../../components/input"
7
+ import { Badge } from "../../components/badge"
8
+ import { Checkbox } from "../../components/checkbox"
9
+ import {
10
+ DropdownMenu,
11
+ DropdownMenuContent,
12
+ DropdownMenuItem,
13
+ DropdownMenuSeparator,
14
+ DropdownMenuTrigger,
15
+ } from "../../components/dropdown-menu"
16
+ import {
17
+ Dialog,
18
+ DialogContent,
19
+ DialogDescription,
20
+ DialogFooter,
21
+ DialogHeader,
22
+ DialogTitle,
23
+ } from "../../components/dialog"
24
+ import {
25
+ AlertDialog,
26
+ AlertDialogAction,
27
+ AlertDialogCancel,
28
+ AlertDialogContent,
29
+ AlertDialogDescription,
30
+ AlertDialogFooter,
31
+ AlertDialogHeader,
32
+ AlertDialogTitle,
33
+ } from "../../components/alert-dialog"
34
+ import {
35
+ Table,
36
+ TableBody,
37
+ TableCell,
38
+ TableHead,
39
+ TableHeader,
40
+ TableRow,
41
+ } from "../../components/table"
42
+ import {
43
+ Folder,
44
+ File,
45
+ FileText,
46
+ FileImage,
47
+ FileVideo,
48
+ FileAudio,
49
+ FileArchive,
50
+ FileCode,
51
+ FilePlus,
52
+ FolderPlus,
53
+ Upload,
54
+ Download,
55
+ Trash2,
56
+ Edit,
57
+ Copy,
58
+ Move,
59
+ Share2,
60
+ MoreHorizontal,
61
+ Grid,
62
+ List,
63
+ Search,
64
+ ChevronRight,
65
+ Home,
66
+ ArrowUp,
67
+ RefreshCw,
68
+ Star,
69
+ StarOff,
70
+ Eye,
71
+ X,
72
+ } from "lucide-react"
73
+
74
+ // ============================================
75
+ // TYPES
76
+ // ============================================
77
+
78
+ export type FileType =
79
+ | "folder"
80
+ | "document"
81
+ | "image"
82
+ | "video"
83
+ | "audio"
84
+ | "archive"
85
+ | "code"
86
+ | "other"
87
+
88
+ export interface FileItem {
89
+ id: string
90
+ name: string
91
+ type: FileType
92
+ size?: number
93
+ mimeType?: string
94
+ path: string
95
+ parentId?: string | null
96
+ createdAt: Date | string
97
+ modifiedAt: Date | string
98
+ createdBy?: { id: string; name: string }
99
+ starred?: boolean
100
+ shared?: boolean
101
+ thumbnail?: string
102
+ metadata?: Record<string, unknown>
103
+ }
104
+
105
+ export interface BreadcrumbItem {
106
+ id: string
107
+ name: string
108
+ path: string
109
+ }
110
+
111
+ export interface WakaFileManagerProps {
112
+ /** Fichiers et dossiers */
113
+ files: FileItem[]
114
+ /** Chemin courant */
115
+ currentPath?: string
116
+ /** Fil d'Ariane */
117
+ breadcrumbs?: BreadcrumbItem[]
118
+ /** Fichiers sélectionnés */
119
+ selectedFiles?: string[]
120
+ /** Callback sélection */
121
+ onSelectionChange?: (fileIds: string[]) => void
122
+ /** Callback navigation */
123
+ onNavigate?: (path: string, folderId?: string) => void
124
+ /** Callback ouvrir fichier */
125
+ onFileOpen?: (file: FileItem) => void
126
+ /** Callback télécharger */
127
+ onDownload?: (fileIds: string[]) => void
128
+ /** Callback supprimer */
129
+ onDelete?: (fileIds: string[]) => void
130
+ /** Callback renommer */
131
+ onRename?: (fileId: string, newName: string) => void
132
+ /** Callback copier */
133
+ onCopy?: (fileIds: string[], targetPath: string) => void
134
+ /** Callback déplacer */
135
+ onMove?: (fileIds: string[], targetPath: string) => void
136
+ /** Callback créer dossier */
137
+ onCreateFolder?: (name: string, parentPath: string) => void
138
+ /** Callback upload */
139
+ onUpload?: (files: File[], targetPath: string) => void
140
+ /** Callback partager */
141
+ onShare?: (fileId: string) => void
142
+ /** Callback favori */
143
+ onToggleStar?: (fileId: string) => void
144
+ /** Callback rafraîchir */
145
+ onRefresh?: () => void
146
+ /** Mode d'affichage */
147
+ viewMode?: "grid" | "list"
148
+ /** Callback changement de mode */
149
+ onViewModeChange?: (mode: "grid" | "list") => void
150
+ /** Afficher la recherche */
151
+ showSearch?: boolean
152
+ /** Callback recherche */
153
+ onSearch?: (query: string) => void
154
+ /** Afficher le header */
155
+ showHeader?: boolean
156
+ /** Afficher les actions */
157
+ showActions?: boolean
158
+ /** En cours de chargement */
159
+ loading?: boolean
160
+ /** Classes CSS additionnelles */
161
+ className?: string
162
+ }
163
+
164
+ // ============================================
165
+ // FILE TYPE CONFIG
166
+ // ============================================
167
+
168
+ const fileTypeConfig: Record<FileType, { icon: React.ElementType; color: string }> = {
169
+ folder: { icon: Folder, color: "text-yellow-500" },
170
+ document: { icon: FileText, color: "text-blue-500" },
171
+ image: { icon: FileImage, color: "text-green-500" },
172
+ video: { icon: FileVideo, color: "text-purple-500" },
173
+ audio: { icon: FileAudio, color: "text-pink-500" },
174
+ archive: { icon: FileArchive, color: "text-orange-500" },
175
+ code: { icon: FileCode, color: "text-cyan-500" },
176
+ other: { icon: File, color: "text-gray-500" },
177
+ }
178
+
179
+ // ============================================
180
+ // HELPERS
181
+ // ============================================
182
+
183
+ function formatFileSize(bytes?: number): string {
184
+ if (!bytes) return "-"
185
+ const units = ["B", "KB", "MB", "GB", "TB"]
186
+ let unitIndex = 0
187
+ let size = bytes
188
+
189
+ while (size >= 1024 && unitIndex < units.length - 1) {
190
+ size /= 1024
191
+ unitIndex++
192
+ }
193
+
194
+ return `${size.toFixed(1)} ${units[unitIndex]}`
195
+ }
196
+
197
+ function getFileType(mimeType?: string, name?: string): FileType {
198
+ if (!mimeType && !name) return "other"
199
+
200
+ if (mimeType) {
201
+ if (mimeType.startsWith("image/")) return "image"
202
+ if (mimeType.startsWith("video/")) return "video"
203
+ if (mimeType.startsWith("audio/")) return "audio"
204
+ if (mimeType.includes("zip") || mimeType.includes("archive") || mimeType.includes("compressed")) return "archive"
205
+ if (mimeType.includes("text") || mimeType.includes("document") || mimeType.includes("pdf")) return "document"
206
+ if (mimeType.includes("javascript") || mimeType.includes("json") || mimeType.includes("xml")) return "code"
207
+ }
208
+
209
+ if (name) {
210
+ const ext = name.split(".").pop()?.toLowerCase()
211
+ if (["jpg", "jpeg", "png", "gif", "svg", "webp"].includes(ext || "")) return "image"
212
+ if (["mp4", "avi", "mov", "mkv", "webm"].includes(ext || "")) return "video"
213
+ if (["mp3", "wav", "ogg", "flac"].includes(ext || "")) return "audio"
214
+ if (["zip", "rar", "7z", "tar", "gz"].includes(ext || "")) return "archive"
215
+ if (["pdf", "doc", "docx", "txt", "rtf"].includes(ext || "")) return "document"
216
+ if (["js", "ts", "jsx", "tsx", "py", "java", "cpp", "c", "go", "rs"].includes(ext || "")) return "code"
217
+ }
218
+
219
+ return "other"
220
+ }
221
+
222
+ // ============================================
223
+ // SUB-COMPONENTS
224
+ // ============================================
225
+
226
+ interface FileManagerHeaderProps {
227
+ breadcrumbs: BreadcrumbItem[]
228
+ viewMode: "grid" | "list"
229
+ onViewModeChange: (mode: "grid" | "list") => void
230
+ onNavigate: (path: string) => void
231
+ onCreateFolder?: () => void
232
+ onUpload?: () => void
233
+ onRefresh?: () => void
234
+ showSearch: boolean
235
+ onSearch?: (query: string) => void
236
+ selectedCount: number
237
+ onDeleteSelected?: () => void
238
+ onDownloadSelected?: () => void
239
+ }
240
+
241
+ function FileManagerHeader({
242
+ breadcrumbs,
243
+ viewMode,
244
+ onViewModeChange,
245
+ onNavigate,
246
+ onCreateFolder,
247
+ onUpload,
248
+ onRefresh,
249
+ showSearch,
250
+ onSearch,
251
+ selectedCount,
252
+ onDeleteSelected,
253
+ onDownloadSelected,
254
+ }: FileManagerHeaderProps) {
255
+ const [searchQuery, setSearchQuery] = React.useState("")
256
+
257
+ return (
258
+ <div className="space-y-4">
259
+ {/* Top bar */}
260
+ <div className="flex items-center justify-between">
261
+ <div className="flex items-center gap-2">
262
+ {onRefresh && (
263
+ <Button variant="outline" size="icon" onClick={onRefresh}>
264
+ <RefreshCw className="h-4 w-4" />
265
+ </Button>
266
+ )}
267
+ {onUpload && (
268
+ <Button variant="outline" onClick={onUpload}>
269
+ <Upload className="h-4 w-4 mr-2" />
270
+ Importer
271
+ </Button>
272
+ )}
273
+ {onCreateFolder && (
274
+ <Button variant="outline" onClick={onCreateFolder}>
275
+ <FolderPlus className="h-4 w-4 mr-2" />
276
+ Nouveau dossier
277
+ </Button>
278
+ )}
279
+ </div>
280
+
281
+ <div className="flex items-center gap-2">
282
+ {showSearch && onSearch && (
283
+ <div className="relative w-64">
284
+ <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
285
+ <Input
286
+ placeholder="Rechercher..."
287
+ value={searchQuery}
288
+ onChange={(e) => {
289
+ setSearchQuery(e.target.value)
290
+ onSearch(e.target.value)
291
+ }}
292
+ className="pl-9"
293
+ />
294
+ </div>
295
+ )}
296
+ <Button
297
+ variant={viewMode === "grid" ? "secondary" : "ghost"}
298
+ size="icon"
299
+ onClick={() => onViewModeChange("grid")}
300
+ >
301
+ <Grid className="h-4 w-4" />
302
+ </Button>
303
+ <Button
304
+ variant={viewMode === "list" ? "secondary" : "ghost"}
305
+ size="icon"
306
+ onClick={() => onViewModeChange("list")}
307
+ >
308
+ <List className="h-4 w-4" />
309
+ </Button>
310
+ </div>
311
+ </div>
312
+
313
+ {/* Breadcrumbs */}
314
+ <div className="flex items-center gap-1 text-sm">
315
+ <button
316
+ onClick={() => onNavigate("/")}
317
+ className="flex items-center gap-1 hover:text-primary"
318
+ >
319
+ <Home className="h-4 w-4" />
320
+ </button>
321
+ {breadcrumbs.map((item, index) => (
322
+ <React.Fragment key={item.id}>
323
+ <ChevronRight className="h-4 w-4 text-muted-foreground" />
324
+ <button
325
+ onClick={() => onNavigate(item.path)}
326
+ className={cn(
327
+ "hover:text-primary",
328
+ index === breadcrumbs.length - 1 && "font-medium"
329
+ )}
330
+ >
331
+ {item.name}
332
+ </button>
333
+ </React.Fragment>
334
+ ))}
335
+ </div>
336
+
337
+ {/* Selection actions */}
338
+ {selectedCount > 0 && (
339
+ <div className="flex items-center gap-4 p-3 bg-muted rounded-lg">
340
+ <span className="text-sm font-medium">
341
+ {selectedCount} élément(s) sélectionné(s)
342
+ </span>
343
+ {onDownloadSelected && (
344
+ <Button variant="outline" size="sm" onClick={onDownloadSelected}>
345
+ <Download className="h-4 w-4 mr-2" />
346
+ Télécharger
347
+ </Button>
348
+ )}
349
+ {onDeleteSelected && (
350
+ <Button variant="destructive" size="sm" onClick={onDeleteSelected}>
351
+ <Trash2 className="h-4 w-4 mr-2" />
352
+ Supprimer
353
+ </Button>
354
+ )}
355
+ </div>
356
+ )}
357
+ </div>
358
+ )
359
+ }
360
+
361
+ interface FileItemComponentProps {
362
+ file: FileItem
363
+ viewMode: "grid" | "list"
364
+ isSelected: boolean
365
+ onSelect: (selected: boolean) => void
366
+ onOpen: () => void
367
+ onRename?: () => void
368
+ onDelete?: () => void
369
+ onDownload?: () => void
370
+ onShare?: () => void
371
+ onToggleStar?: () => void
372
+ }
373
+
374
+ function FileItemComponent({
375
+ file,
376
+ viewMode,
377
+ isSelected,
378
+ onSelect,
379
+ onOpen,
380
+ onRename,
381
+ onDelete,
382
+ onDownload,
383
+ onShare,
384
+ onToggleStar,
385
+ }: FileItemComponentProps) {
386
+ const config = fileTypeConfig[file.type]
387
+ const Icon = config.icon
388
+ const modifiedAt = typeof file.modifiedAt === "string" ? new Date(file.modifiedAt) : file.modifiedAt
389
+
390
+ const handleDoubleClick = () => {
391
+ if (file.type === "folder") {
392
+ onOpen()
393
+ }
394
+ }
395
+
396
+ if (viewMode === "grid") {
397
+ return (
398
+ <div
399
+ className={cn(
400
+ "relative group p-4 rounded-lg border cursor-pointer transition-colors",
401
+ isSelected ? "bg-primary/10 border-primary" : "hover:bg-muted"
402
+ )}
403
+ onClick={() => onSelect(!isSelected)}
404
+ onDoubleClick={handleDoubleClick}
405
+ >
406
+ {/* Checkbox */}
407
+ <div className="absolute top-2 left-2 opacity-0 group-hover:opacity-100 transition-opacity">
408
+ <Checkbox
409
+ checked={isSelected}
410
+ onCheckedChange={(checked) => onSelect(checked as boolean)}
411
+ onClick={(e) => e.stopPropagation()}
412
+ />
413
+ </div>
414
+
415
+ {/* Star */}
416
+ {file.starred && (
417
+ <Star className="absolute top-2 right-2 h-4 w-4 text-yellow-500 fill-yellow-500" />
418
+ )}
419
+
420
+ {/* Icon */}
421
+ <div className="flex flex-col items-center gap-2">
422
+ {file.thumbnail && file.type === "image" ? (
423
+ <img
424
+ src={file.thumbnail}
425
+ alt={file.name}
426
+ className="w-16 h-16 object-cover rounded"
427
+ />
428
+ ) : (
429
+ <Icon className={cn("h-12 w-12", config.color)} />
430
+ )}
431
+ <span className="text-sm font-medium text-center line-clamp-2">
432
+ {file.name}
433
+ </span>
434
+ {file.type !== "folder" && (
435
+ <span className="text-xs text-muted-foreground">
436
+ {formatFileSize(file.size)}
437
+ </span>
438
+ )}
439
+ </div>
440
+
441
+ {/* Actions */}
442
+ <div className="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity">
443
+ <DropdownMenu>
444
+ <DropdownMenuTrigger asChild onClick={(e) => e.stopPropagation()}>
445
+ <Button variant="ghost" size="icon" className="h-7 w-7">
446
+ <MoreHorizontal className="h-4 w-4" />
447
+ </Button>
448
+ </DropdownMenuTrigger>
449
+ <DropdownMenuContent align="end">
450
+ <DropdownMenuItem onClick={onOpen}>
451
+ <Eye className="mr-2 h-4 w-4" />
452
+ Ouvrir
453
+ </DropdownMenuItem>
454
+ {onRename && (
455
+ <DropdownMenuItem onClick={onRename}>
456
+ <Edit className="mr-2 h-4 w-4" />
457
+ Renommer
458
+ </DropdownMenuItem>
459
+ )}
460
+ {onDownload && file.type !== "folder" && (
461
+ <DropdownMenuItem onClick={onDownload}>
462
+ <Download className="mr-2 h-4 w-4" />
463
+ Télécharger
464
+ </DropdownMenuItem>
465
+ )}
466
+ {onShare && (
467
+ <DropdownMenuItem onClick={onShare}>
468
+ <Share2 className="mr-2 h-4 w-4" />
469
+ Partager
470
+ </DropdownMenuItem>
471
+ )}
472
+ {onToggleStar && (
473
+ <DropdownMenuItem onClick={onToggleStar}>
474
+ {file.starred ? (
475
+ <>
476
+ <StarOff className="mr-2 h-4 w-4" />
477
+ Retirer des favoris
478
+ </>
479
+ ) : (
480
+ <>
481
+ <Star className="mr-2 h-4 w-4" />
482
+ Ajouter aux favoris
483
+ </>
484
+ )}
485
+ </DropdownMenuItem>
486
+ )}
487
+ {onDelete && (
488
+ <>
489
+ <DropdownMenuSeparator />
490
+ <DropdownMenuItem onClick={onDelete} className="text-destructive">
491
+ <Trash2 className="mr-2 h-4 w-4" />
492
+ Supprimer
493
+ </DropdownMenuItem>
494
+ </>
495
+ )}
496
+ </DropdownMenuContent>
497
+ </DropdownMenu>
498
+ </div>
499
+ </div>
500
+ )
501
+ }
502
+
503
+ // List view
504
+ return (
505
+ <TableRow
506
+ className={cn("cursor-pointer", isSelected && "bg-primary/10")}
507
+ onClick={() => onSelect(!isSelected)}
508
+ onDoubleClick={handleDoubleClick}
509
+ >
510
+ <TableCell className="w-12">
511
+ <Checkbox
512
+ checked={isSelected}
513
+ onCheckedChange={(checked) => onSelect(checked as boolean)}
514
+ onClick={(e) => e.stopPropagation()}
515
+ />
516
+ </TableCell>
517
+ <TableCell>
518
+ <div className="flex items-center gap-3">
519
+ <Icon className={cn("h-5 w-5", config.color)} />
520
+ <span className="font-medium">{file.name}</span>
521
+ {file.starred && (
522
+ <Star className="h-4 w-4 text-yellow-500 fill-yellow-500" />
523
+ )}
524
+ {file.shared && (
525
+ <Badge variant="secondary" className="text-xs">
526
+ Partagé
527
+ </Badge>
528
+ )}
529
+ </div>
530
+ </TableCell>
531
+ <TableCell className="text-muted-foreground">
532
+ {formatFileSize(file.size)}
533
+ </TableCell>
534
+ <TableCell className="text-muted-foreground">
535
+ {modifiedAt.toLocaleDateString("fr-FR")}
536
+ </TableCell>
537
+ <TableCell>
538
+ <DropdownMenu>
539
+ <DropdownMenuTrigger asChild onClick={(e) => e.stopPropagation()}>
540
+ <Button variant="ghost" size="icon" className="h-8 w-8">
541
+ <MoreHorizontal className="h-4 w-4" />
542
+ </Button>
543
+ </DropdownMenuTrigger>
544
+ <DropdownMenuContent align="end">
545
+ <DropdownMenuItem onClick={onOpen}>
546
+ <Eye className="mr-2 h-4 w-4" />
547
+ Ouvrir
548
+ </DropdownMenuItem>
549
+ {onRename && (
550
+ <DropdownMenuItem onClick={onRename}>
551
+ <Edit className="mr-2 h-4 w-4" />
552
+ Renommer
553
+ </DropdownMenuItem>
554
+ )}
555
+ {onDownload && file.type !== "folder" && (
556
+ <DropdownMenuItem onClick={onDownload}>
557
+ <Download className="mr-2 h-4 w-4" />
558
+ Télécharger
559
+ </DropdownMenuItem>
560
+ )}
561
+ {onDelete && (
562
+ <>
563
+ <DropdownMenuSeparator />
564
+ <DropdownMenuItem onClick={onDelete} className="text-destructive">
565
+ <Trash2 className="mr-2 h-4 w-4" />
566
+ Supprimer
567
+ </DropdownMenuItem>
568
+ </>
569
+ )}
570
+ </DropdownMenuContent>
571
+ </DropdownMenu>
572
+ </TableCell>
573
+ </TableRow>
574
+ )
575
+ }
576
+
577
+ // ============================================
578
+ // MAIN COMPONENT
579
+ // ============================================
580
+
581
+ export function WakaFileManager({
582
+ files,
583
+ currentPath = "/",
584
+ breadcrumbs = [],
585
+ selectedFiles = [],
586
+ onSelectionChange,
587
+ onNavigate,
588
+ onFileOpen,
589
+ onDownload,
590
+ onDelete,
591
+ onRename,
592
+ onCopy,
593
+ onMove,
594
+ onCreateFolder,
595
+ onUpload,
596
+ onShare,
597
+ onToggleStar,
598
+ onRefresh,
599
+ viewMode: externalViewMode,
600
+ onViewModeChange,
601
+ showSearch = true,
602
+ onSearch,
603
+ showHeader = true,
604
+ showActions = true,
605
+ loading = false,
606
+ className,
607
+ }: WakaFileManagerProps) {
608
+ const [internalViewMode, setInternalViewMode] = React.useState<"grid" | "list">("grid")
609
+ const [renameDialogOpen, setRenameDialogOpen] = React.useState(false)
610
+ const [renamingFile, setRenamingFile] = React.useState<FileItem | null>(null)
611
+ const [newName, setNewName] = React.useState("")
612
+ const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false)
613
+ const [deletingFiles, setDeletingFiles] = React.useState<string[]>([])
614
+ const [createFolderDialogOpen, setCreateFolderDialogOpen] = React.useState(false)
615
+ const [newFolderName, setNewFolderName] = React.useState("")
616
+
617
+ const viewMode = externalViewMode ?? internalViewMode
618
+
619
+ const handleViewModeChange = (mode: "grid" | "list") => {
620
+ if (onViewModeChange) {
621
+ onViewModeChange(mode)
622
+ } else {
623
+ setInternalViewMode(mode)
624
+ }
625
+ }
626
+
627
+ const handleSelect = (fileId: string, selected: boolean) => {
628
+ if (selected) {
629
+ onSelectionChange?.([...selectedFiles, fileId])
630
+ } else {
631
+ onSelectionChange?.(selectedFiles.filter((id) => id !== fileId))
632
+ }
633
+ }
634
+
635
+ const handleOpen = (file: FileItem) => {
636
+ if (file.type === "folder") {
637
+ onNavigate?.(file.path, file.id)
638
+ } else {
639
+ onFileOpen?.(file)
640
+ }
641
+ }
642
+
643
+ const handleRename = (file: FileItem) => {
644
+ setRenamingFile(file)
645
+ setNewName(file.name)
646
+ setRenameDialogOpen(true)
647
+ }
648
+
649
+ const confirmRename = () => {
650
+ if (renamingFile && newName.trim() && newName !== renamingFile.name) {
651
+ onRename?.(renamingFile.id, newName.trim())
652
+ }
653
+ setRenameDialogOpen(false)
654
+ setRenamingFile(null)
655
+ }
656
+
657
+ const handleDeleteSelected = () => {
658
+ setDeletingFiles(selectedFiles)
659
+ setDeleteDialogOpen(true)
660
+ }
661
+
662
+ const confirmDelete = () => {
663
+ onDelete?.(deletingFiles)
664
+ setDeleteDialogOpen(false)
665
+ setDeletingFiles([])
666
+ onSelectionChange?.([])
667
+ }
668
+
669
+ const handleCreateFolder = () => {
670
+ if (newFolderName.trim()) {
671
+ onCreateFolder?.(newFolderName.trim(), currentPath)
672
+ setCreateFolderDialogOpen(false)
673
+ setNewFolderName("")
674
+ }
675
+ }
676
+
677
+ // Sort files: folders first, then by name
678
+ const sortedFiles = [...files].sort((a, b) => {
679
+ if (a.type === "folder" && b.type !== "folder") return -1
680
+ if (a.type !== "folder" && b.type === "folder") return 1
681
+ return a.name.localeCompare(b.name)
682
+ })
683
+
684
+ return (
685
+ <div className={cn("space-y-4", className)}>
686
+ {showHeader && (
687
+ <FileManagerHeader
688
+ breadcrumbs={breadcrumbs}
689
+ viewMode={viewMode}
690
+ onViewModeChange={handleViewModeChange}
691
+ onNavigate={(path) => onNavigate?.(path)}
692
+ onCreateFolder={onCreateFolder ? () => setCreateFolderDialogOpen(true) : undefined}
693
+ onUpload={onUpload ? () => {} : undefined}
694
+ onRefresh={onRefresh}
695
+ showSearch={showSearch}
696
+ onSearch={onSearch}
697
+ selectedCount={selectedFiles.length}
698
+ onDeleteSelected={onDelete ? handleDeleteSelected : undefined}
699
+ onDownloadSelected={onDownload ? () => onDownload(selectedFiles) : undefined}
700
+ />
701
+ )}
702
+
703
+ {loading ? (
704
+ <div className="flex items-center justify-center py-12">
705
+ <RefreshCw className="h-6 w-6 animate-spin text-muted-foreground" />
706
+ </div>
707
+ ) : sortedFiles.length === 0 ? (
708
+ <div className="flex flex-col items-center justify-center py-12 text-muted-foreground">
709
+ <Folder className="h-12 w-12 mb-4" />
710
+ <p>Ce dossier est vide</p>
711
+ </div>
712
+ ) : viewMode === "grid" ? (
713
+ <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4">
714
+ {sortedFiles.map((file) => (
715
+ <FileItemComponent
716
+ key={file.id}
717
+ file={file}
718
+ viewMode="grid"
719
+ isSelected={selectedFiles.includes(file.id)}
720
+ onSelect={(selected) => handleSelect(file.id, selected)}
721
+ onOpen={() => handleOpen(file)}
722
+ onRename={onRename ? () => handleRename(file) : undefined}
723
+ onDelete={onDelete ? () => { setDeletingFiles([file.id]); setDeleteDialogOpen(true); } : undefined}
724
+ onDownload={onDownload ? () => onDownload([file.id]) : undefined}
725
+ onShare={onShare ? () => onShare(file.id) : undefined}
726
+ onToggleStar={onToggleStar ? () => onToggleStar(file.id) : undefined}
727
+ />
728
+ ))}
729
+ </div>
730
+ ) : (
731
+ <Table>
732
+ <TableHeader>
733
+ <TableRow>
734
+ <TableHead className="w-12">
735
+ <Checkbox
736
+ checked={selectedFiles.length === files.length && files.length > 0}
737
+ onCheckedChange={(checked) => {
738
+ if (checked) {
739
+ onSelectionChange?.(files.map((f) => f.id))
740
+ } else {
741
+ onSelectionChange?.([])
742
+ }
743
+ }}
744
+ />
745
+ </TableHead>
746
+ <TableHead>Nom</TableHead>
747
+ <TableHead>Taille</TableHead>
748
+ <TableHead>Modifié</TableHead>
749
+ <TableHead className="w-12"></TableHead>
750
+ </TableRow>
751
+ </TableHeader>
752
+ <TableBody>
753
+ {sortedFiles.map((file) => (
754
+ <FileItemComponent
755
+ key={file.id}
756
+ file={file}
757
+ viewMode="list"
758
+ isSelected={selectedFiles.includes(file.id)}
759
+ onSelect={(selected) => handleSelect(file.id, selected)}
760
+ onOpen={() => handleOpen(file)}
761
+ onRename={onRename ? () => handleRename(file) : undefined}
762
+ onDelete={onDelete ? () => { setDeletingFiles([file.id]); setDeleteDialogOpen(true); } : undefined}
763
+ onDownload={onDownload ? () => onDownload([file.id]) : undefined}
764
+ onShare={onShare ? () => onShare(file.id) : undefined}
765
+ onToggleStar={onToggleStar ? () => onToggleStar(file.id) : undefined}
766
+ />
767
+ ))}
768
+ </TableBody>
769
+ </Table>
770
+ )}
771
+
772
+ {/* Rename Dialog */}
773
+ <Dialog open={renameDialogOpen} onOpenChange={setRenameDialogOpen}>
774
+ <DialogContent>
775
+ <DialogHeader>
776
+ <DialogTitle>Renommer</DialogTitle>
777
+ </DialogHeader>
778
+ <Input
779
+ value={newName}
780
+ onChange={(e) => setNewName(e.target.value)}
781
+ placeholder="Nouveau nom"
782
+ onKeyDown={(e) => e.key === "Enter" && confirmRename()}
783
+ />
784
+ <DialogFooter>
785
+ <Button variant="outline" onClick={() => setRenameDialogOpen(false)}>
786
+ Annuler
787
+ </Button>
788
+ <Button onClick={confirmRename}>Renommer</Button>
789
+ </DialogFooter>
790
+ </DialogContent>
791
+ </Dialog>
792
+
793
+ {/* Delete Dialog */}
794
+ <AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
795
+ <AlertDialogContent>
796
+ <AlertDialogHeader>
797
+ <AlertDialogTitle>Supprimer ?</AlertDialogTitle>
798
+ <AlertDialogDescription>
799
+ Êtes-vous sûr de vouloir supprimer {deletingFiles.length} élément(s) ?
800
+ Cette action est irréversible.
801
+ </AlertDialogDescription>
802
+ </AlertDialogHeader>
803
+ <AlertDialogFooter>
804
+ <AlertDialogCancel>Annuler</AlertDialogCancel>
805
+ <AlertDialogAction onClick={confirmDelete}>Supprimer</AlertDialogAction>
806
+ </AlertDialogFooter>
807
+ </AlertDialogContent>
808
+ </AlertDialog>
809
+
810
+ {/* Create Folder Dialog */}
811
+ <Dialog open={createFolderDialogOpen} onOpenChange={setCreateFolderDialogOpen}>
812
+ <DialogContent>
813
+ <DialogHeader>
814
+ <DialogTitle>Nouveau dossier</DialogTitle>
815
+ </DialogHeader>
816
+ <Input
817
+ value={newFolderName}
818
+ onChange={(e) => setNewFolderName(e.target.value)}
819
+ placeholder="Nom du dossier"
820
+ onKeyDown={(e) => e.key === "Enter" && handleCreateFolder()}
821
+ />
822
+ <DialogFooter>
823
+ <Button variant="outline" onClick={() => setCreateFolderDialogOpen(false)}>
824
+ Annuler
825
+ </Button>
826
+ <Button onClick={handleCreateFolder}>Créer</Button>
827
+ </DialogFooter>
828
+ </DialogContent>
829
+ </Dialog>
830
+ </div>
831
+ )
832
+ }
833
+
834
+ // ============================================
835
+ // PRESETS
836
+ // ============================================
837
+
838
+ export const defaultFiles: FileItem[] = [
839
+ {
840
+ id: "1",
841
+ name: "Documents",
842
+ type: "folder",
843
+ path: "/Documents",
844
+ createdAt: new Date("2024-01-01"),
845
+ modifiedAt: new Date("2024-01-15"),
846
+ },
847
+ {
848
+ id: "2",
849
+ name: "Images",
850
+ type: "folder",
851
+ path: "/Images",
852
+ createdAt: new Date("2024-01-01"),
853
+ modifiedAt: new Date("2024-01-10"),
854
+ starred: true,
855
+ },
856
+ {
857
+ id: "3",
858
+ name: "Rapport Q4.pdf",
859
+ type: "document",
860
+ path: "/Rapport Q4.pdf",
861
+ size: 2456000,
862
+ createdAt: new Date("2024-01-05"),
863
+ modifiedAt: new Date("2024-01-05"),
864
+ },
865
+ {
866
+ id: "4",
867
+ name: "Photo vacances.jpg",
868
+ type: "image",
869
+ path: "/Photo vacances.jpg",
870
+ size: 5670000,
871
+ createdAt: new Date("2024-01-08"),
872
+ modifiedAt: new Date("2024-01-08"),
873
+ },
874
+ {
875
+ id: "5",
876
+ name: "Présentation.pptx",
877
+ type: "document",
878
+ path: "/Présentation.pptx",
879
+ size: 8900000,
880
+ createdAt: new Date("2024-01-12"),
881
+ modifiedAt: new Date("2024-01-14"),
882
+ shared: true,
883
+ },
884
+ ]
885
+
886
+ export const defaultBreadcrumbs: BreadcrumbItem[] = [
887
+ { id: "root", name: "Mes fichiers", path: "/" },
888
+ ]
889
+
890
+ export default WakaFileManager