@rebasepro/app 0.0.1-canary.4829d6e

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 (268) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -0
  3. package/dist/auth/api.d.ts +66 -0
  4. package/dist/auth/index.d.ts +13 -0
  5. package/dist/auth/types.d.ts +127 -0
  6. package/dist/auth/useRebaseAuthController.d.ts +13 -0
  7. package/dist/components/AIIcon.d.ts +17 -0
  8. package/dist/components/AuthSimulationMenu.d.ts +0 -0
  9. package/dist/components/ConfirmationDialog.d.ts +9 -0
  10. package/dist/components/Debug/UIReferenceView.d.ts +13 -0
  11. package/dist/components/Debug/UIStyleGuide.d.ts +2 -0
  12. package/dist/components/Debug/collection-views/CardViewDemo.d.ts +2 -0
  13. package/dist/components/Debug/collection-views/CollectionTableDemo.d.ts +2 -0
  14. package/dist/components/Debug/collection-views/KanbanBoardDemo.d.ts +2 -0
  15. package/dist/components/Debug/collection-views/index.d.ts +3 -0
  16. package/dist/components/Debug/collection-views/sample_data.d.ts +23 -0
  17. package/dist/components/Debug/crm-dashboard/CalendarWidget.d.ts +22 -0
  18. package/dist/components/Debug/crm-dashboard/CrmDashboardDemo.d.ts +2 -0
  19. package/dist/components/Debug/crm-dashboard/DashboardMetrics.d.ts +15 -0
  20. package/dist/components/Debug/crm-dashboard/PipelineOverview.d.ts +34 -0
  21. package/dist/components/Debug/crm-dashboard/RecentActivity.d.ts +19 -0
  22. package/dist/components/Debug/crm-dashboard/TaskFilters.d.ts +30 -0
  23. package/dist/components/Debug/crm-dashboard/TaskTable.d.ts +50 -0
  24. package/dist/components/Debug/crm-dashboard/TasksView.d.ts +41 -0
  25. package/dist/components/ErrorTooltip.d.ts +3 -0
  26. package/dist/components/ErrorView.d.ts +21 -0
  27. package/dist/components/LanguageToggle.d.ts +2 -0
  28. package/dist/components/LoginView/LoginView.d.ts +113 -0
  29. package/dist/components/LoginView/index.d.ts +2 -0
  30. package/dist/components/NotFoundPage.d.ts +2 -0
  31. package/dist/components/RebaseAuth.d.ts +10 -0
  32. package/dist/components/RebaseLogo.d.ts +7 -0
  33. package/dist/components/SchemaDriftBanner.d.ts +27 -0
  34. package/dist/components/UnsavedChangesDialog.d.ts +9 -0
  35. package/dist/components/UserDisplay.d.ts +7 -0
  36. package/dist/components/UserSelectPopover.d.ts +63 -0
  37. package/dist/components/UserSettingsView.d.ts +2 -0
  38. package/dist/components/common/index.d.ts +6 -0
  39. package/dist/components/common/table_height.d.ts +5 -0
  40. package/dist/components/common/types.d.ts +66 -0
  41. package/dist/components/common/useColumnsIds.d.ts +9 -0
  42. package/dist/components/common/useDataTableController.d.ts +45 -0
  43. package/dist/components/common/useDebouncedData.d.ts +9 -0
  44. package/dist/components/common/useScrollRestoration.d.ts +14 -0
  45. package/dist/components/index.d.ts +18 -0
  46. package/dist/contexts/AdminModeController.d.ts +4 -0
  47. package/dist/contexts/AnalyticsContext.d.ts +3 -0
  48. package/dist/contexts/AuthControllerContext.d.ts +3 -0
  49. package/dist/contexts/CollectionScopeContext.d.ts +50 -0
  50. package/dist/contexts/ComponentOverrideContext.d.ts +42 -0
  51. package/dist/contexts/CustomizationControllerContext.d.ts +3 -0
  52. package/dist/contexts/DataDriverContext.d.ts +3 -0
  53. package/dist/contexts/DataSourcesContext.d.ts +31 -0
  54. package/dist/contexts/DatabaseAdminContext.d.ts +3 -0
  55. package/dist/contexts/DialogsProvider.d.ts +4 -0
  56. package/dist/contexts/EffectiveRoleController.d.ts +4 -0
  57. package/dist/contexts/ModeController.d.ts +4 -0
  58. package/dist/contexts/RebaseClientInstanceContext.d.ts +6 -0
  59. package/dist/contexts/RebaseDataContext.d.ts +3 -0
  60. package/dist/contexts/SnackbarProvider.d.ts +2 -0
  61. package/dist/contexts/StorageSourceContext.d.ts +3 -0
  62. package/dist/contexts/StorageSourcesContext.d.ts +25 -0
  63. package/dist/contexts/UserConfigurationPersistenceContext.d.ts +3 -0
  64. package/dist/contexts/index.d.ts +17 -0
  65. package/dist/core/PluginLifecycleManager.d.ts +17 -0
  66. package/dist/core/PluginProviderStack.d.ts +21 -0
  67. package/dist/core/Rebase.d.ts +15 -0
  68. package/dist/core/RebaseProps.d.ts +291 -0
  69. package/dist/core/RebaseRouter.d.ts +4 -0
  70. package/dist/core/RebaseRoutes.d.ts +17 -0
  71. package/dist/core/index.d.ts +4 -0
  72. package/dist/hooks/ApiConfigContext.d.ts +24 -0
  73. package/dist/hooks/data/delete.d.ts +33 -0
  74. package/dist/hooks/data/save.d.ts +40 -0
  75. package/dist/hooks/data/useCollection.d.ts +62 -0
  76. package/dist/hooks/data/useData.d.ts +13 -0
  77. package/dist/hooks/data/useDataOrder.d.ts +12 -0
  78. package/dist/hooks/data/useFetch.d.ts +43 -0
  79. package/dist/hooks/data/useRelationSelector.d.ts +52 -0
  80. package/dist/hooks/index.d.ts +36 -0
  81. package/dist/hooks/useAdminModeController.d.ts +19 -0
  82. package/dist/hooks/useAnalyticsController.d.ts +5 -0
  83. package/dist/hooks/useAuthController.d.ts +11 -0
  84. package/dist/hooks/useAuthSubscription.d.ts +2 -0
  85. package/dist/hooks/useBackendStorageSource.d.ts +30 -0
  86. package/dist/hooks/useBridgeRegistration.d.ts +18 -0
  87. package/dist/hooks/useBrowserTitleAndIcon.d.ts +6 -0
  88. package/dist/hooks/useBuildAdminModeController.d.ts +6 -0
  89. package/dist/hooks/useBuildEffectiveRoleController.d.ts +8 -0
  90. package/dist/hooks/useBuildLocalConfigurationPersistence.d.ts +2 -0
  91. package/dist/hooks/useBuildModeController.d.ts +6 -0
  92. package/dist/hooks/useClipboard.d.ts +57 -0
  93. package/dist/hooks/useCollapsedGroups.d.ts +27 -0
  94. package/dist/hooks/useComponentOverride.d.ts +32 -0
  95. package/dist/hooks/useCustomizationController.d.ts +11 -0
  96. package/dist/hooks/useDialogsController.d.ts +11 -0
  97. package/dist/hooks/useEffectiveRoleController.d.ts +7 -0
  98. package/dist/hooks/useLargeLayout.d.ts +1 -0
  99. package/dist/hooks/useModeController.d.ts +19 -0
  100. package/dist/hooks/usePermissions.d.ts +12 -0
  101. package/dist/hooks/useRebaseClient.d.ts +5 -0
  102. package/dist/hooks/useRebaseContext.d.ts +11 -0
  103. package/dist/hooks/useRebaseRegistry.d.ts +34 -0
  104. package/dist/hooks/useResolvedComponent.d.ts +47 -0
  105. package/dist/hooks/useSlot.d.ts +18 -0
  106. package/dist/hooks/useSnackbarController.d.ts +20 -0
  107. package/dist/hooks/useStorageSource.d.ts +6 -0
  108. package/dist/hooks/useStudioBridge.d.ts +79 -0
  109. package/dist/hooks/useTranslation.d.ts +17 -0
  110. package/dist/hooks/useUnsavedChangesDialog.d.ts +12 -0
  111. package/dist/hooks/useUserConfigurationPersistence.d.ts +8 -0
  112. package/dist/i18n/RebaseI18nProvider.d.ts +33 -0
  113. package/dist/index.d.ts +16 -0
  114. package/dist/index.es.js +16843 -0
  115. package/dist/index.es.js.map +1 -0
  116. package/dist/index.umd.js +17021 -0
  117. package/dist/index.umd.js.map +1 -0
  118. package/dist/internal/common.d.ts +14 -0
  119. package/dist/internal/useRestoreScroll.d.ts +15 -0
  120. package/dist/locales/de.d.ts +2 -0
  121. package/dist/locales/en.d.ts +10 -0
  122. package/dist/locales/es.d.ts +10 -0
  123. package/dist/locales/fr.d.ts +2 -0
  124. package/dist/locales/hi.d.ts +2 -0
  125. package/dist/locales/it.d.ts +2 -0
  126. package/dist/locales/pt.d.ts +7 -0
  127. package/dist/util/constants.d.ts +1 -0
  128. package/dist/util/createFormexStub.d.ts +2 -0
  129. package/dist/util/entity_cache.d.ts +22 -0
  130. package/dist/util/enums.d.ts +5 -0
  131. package/dist/util/icon_list.d.ts +5 -0
  132. package/dist/util/icons.d.ts +20 -0
  133. package/dist/util/index.d.ts +8 -0
  134. package/dist/util/previews.d.ts +4 -0
  135. package/dist/util/useStorageUploadController.d.ts +44 -0
  136. package/dist/vitePlugin.d.ts +60 -0
  137. package/dist/vitePlugin.js +113 -0
  138. package/package.json +145 -0
  139. package/src/auth/api.ts +148 -0
  140. package/src/auth/index.ts +25 -0
  141. package/src/auth/types.ts +115 -0
  142. package/src/auth/useRebaseAuthController.ts +328 -0
  143. package/src/components/AIIcon.tsx +47 -0
  144. package/src/components/AuthSimulationMenu.tsx +0 -0
  145. package/src/components/ConfirmationDialog.tsx +48 -0
  146. package/src/components/Debug/UIReferenceView.tsx +958 -0
  147. package/src/components/Debug/UIStyleGuide.tsx +156 -0
  148. package/src/components/Debug/collection-views/CardViewDemo.tsx +85 -0
  149. package/src/components/Debug/collection-views/CollectionTableDemo.tsx +107 -0
  150. package/src/components/Debug/collection-views/KanbanBoardDemo.tsx +90 -0
  151. package/src/components/Debug/collection-views/index.ts +3 -0
  152. package/src/components/Debug/collection-views/sample_data.ts +42 -0
  153. package/src/components/Debug/crm-dashboard/CalendarWidget.tsx +389 -0
  154. package/src/components/Debug/crm-dashboard/CrmDashboardDemo.tsx +1102 -0
  155. package/src/components/Debug/crm-dashboard/DashboardMetrics.tsx +133 -0
  156. package/src/components/Debug/crm-dashboard/PipelineOverview.tsx +290 -0
  157. package/src/components/Debug/crm-dashboard/RecentActivity.tsx +215 -0
  158. package/src/components/Debug/crm-dashboard/TaskFilters.tsx +184 -0
  159. package/src/components/Debug/crm-dashboard/TaskTable.tsx +427 -0
  160. package/src/components/Debug/crm-dashboard/TasksView.tsx +234 -0
  161. package/src/components/ErrorTooltip.tsx +12 -0
  162. package/src/components/ErrorView.tsx +94 -0
  163. package/src/components/LanguageToggle.tsx +59 -0
  164. package/src/components/LoginView/LoginView.tsx +932 -0
  165. package/src/components/LoginView/index.ts +2 -0
  166. package/src/components/NotFoundPage.tsx +27 -0
  167. package/src/components/RebaseAuth.tsx +27 -0
  168. package/src/components/RebaseLogo.tsx +29 -0
  169. package/src/components/SchemaDriftBanner.tsx +102 -0
  170. package/src/components/UnsavedChangesDialog.tsx +46 -0
  171. package/src/components/UserDisplay.tsx +54 -0
  172. package/src/components/UserSelectPopover.tsx +399 -0
  173. package/src/components/UserSettingsView.tsx +318 -0
  174. package/src/components/common/index.ts +6 -0
  175. package/src/components/common/table_height.tsx +21 -0
  176. package/src/components/common/types.tsx +66 -0
  177. package/src/components/common/useColumnsIds.tsx +222 -0
  178. package/src/components/common/useDataTableController.tsx +514 -0
  179. package/src/components/common/useDebouncedData.ts +49 -0
  180. package/src/components/common/useScrollRestoration.tsx +68 -0
  181. package/src/components/index.tsx +26 -0
  182. package/src/contexts/AdminModeController.tsx +11 -0
  183. package/src/contexts/AnalyticsContext.tsx +4 -0
  184. package/src/contexts/AuthControllerContext.tsx +4 -0
  185. package/src/contexts/CollectionScopeContext.tsx +67 -0
  186. package/src/contexts/ComponentOverrideContext.tsx +81 -0
  187. package/src/contexts/CustomizationControllerContext.tsx +4 -0
  188. package/src/contexts/DataDriverContext.tsx +4 -0
  189. package/src/contexts/DataSourcesContext.tsx +36 -0
  190. package/src/contexts/DatabaseAdminContext.tsx +4 -0
  191. package/src/contexts/DialogsProvider.tsx +56 -0
  192. package/src/contexts/EffectiveRoleController.tsx +12 -0
  193. package/src/contexts/ModeController.tsx +11 -0
  194. package/src/contexts/RebaseClientInstanceContext.tsx +7 -0
  195. package/src/contexts/RebaseDataContext.tsx +4 -0
  196. package/src/contexts/SnackbarProvider.tsx +15 -0
  197. package/src/contexts/StorageSourceContext.tsx +4 -0
  198. package/src/contexts/StorageSourcesContext.tsx +30 -0
  199. package/src/contexts/UserConfigurationPersistenceContext.tsx +4 -0
  200. package/src/contexts/index.ts +17 -0
  201. package/src/core/PluginLifecycleManager.tsx +95 -0
  202. package/src/core/PluginProviderStack.tsx +40 -0
  203. package/src/core/Rebase.tsx +439 -0
  204. package/src/core/RebaseProps.tsx +320 -0
  205. package/src/core/RebaseRouter.tsx +17 -0
  206. package/src/core/RebaseRoutes.tsx +24 -0
  207. package/src/core/index.tsx +5 -0
  208. package/src/hooks/ApiConfigContext.tsx +41 -0
  209. package/src/hooks/data/delete.ts +55 -0
  210. package/src/hooks/data/save.ts +77 -0
  211. package/src/hooks/data/useCollection.tsx +176 -0
  212. package/src/hooks/data/useData.tsx +18 -0
  213. package/src/hooks/data/useDataOrder.ts +26 -0
  214. package/src/hooks/data/useFetch.tsx +140 -0
  215. package/src/hooks/data/useRelationSelector.tsx +234 -0
  216. package/src/hooks/index.tsx +45 -0
  217. package/src/hooks/useAdminModeController.tsx +23 -0
  218. package/src/hooks/useAnalyticsController.tsx +8 -0
  219. package/src/hooks/useAuthController.tsx +14 -0
  220. package/src/hooks/useAuthSubscription.ts +87 -0
  221. package/src/hooks/useBackendStorageSource.ts +288 -0
  222. package/src/hooks/useBridgeRegistration.tsx +32 -0
  223. package/src/hooks/useBrowserTitleAndIcon.tsx +23 -0
  224. package/src/hooks/useBuildAdminModeController.tsx +24 -0
  225. package/src/hooks/useBuildEffectiveRoleController.tsx +31 -0
  226. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +75 -0
  227. package/src/hooks/useBuildModeController.tsx +71 -0
  228. package/src/hooks/useClipboard.tsx +158 -0
  229. package/src/hooks/useCollapsedGroups.ts +116 -0
  230. package/src/hooks/useComponentOverride.tsx +59 -0
  231. package/src/hooks/useCustomizationController.tsx +14 -0
  232. package/src/hooks/useDialogsController.tsx +15 -0
  233. package/src/hooks/useEffectiveRoleController.tsx +10 -0
  234. package/src/hooks/useLargeLayout.tsx +65 -0
  235. package/src/hooks/useModeController.tsx +23 -0
  236. package/src/hooks/usePermissions.ts +44 -0
  237. package/src/hooks/useRebaseClient.tsx +10 -0
  238. package/src/hooks/useRebaseContext.tsx +83 -0
  239. package/src/hooks/useRebaseRegistry.tsx +91 -0
  240. package/src/hooks/useResolvedComponent.tsx +159 -0
  241. package/src/hooks/useSlot.tsx +64 -0
  242. package/src/hooks/useSnackbarController.tsx +52 -0
  243. package/src/hooks/useStorageSource.tsx +11 -0
  244. package/src/hooks/useStudioBridge.tsx +209 -0
  245. package/src/hooks/useTranslation.ts +33 -0
  246. package/src/hooks/useUnsavedChangesDialog.tsx +64 -0
  247. package/src/hooks/useUserConfigurationPersistence.tsx +11 -0
  248. package/src/i18n/RebaseI18nProvider.tsx +160 -0
  249. package/src/index.ts +25 -0
  250. package/src/internal/common.tsx +16 -0
  251. package/src/internal/useRestoreScroll.tsx +69 -0
  252. package/src/locales/de.ts +902 -0
  253. package/src/locales/en.ts +980 -0
  254. package/src/locales/es.ts +922 -0
  255. package/src/locales/fr.ts +901 -0
  256. package/src/locales/hi.ts +901 -0
  257. package/src/locales/it.ts +901 -0
  258. package/src/locales/pt.ts +909 -0
  259. package/src/util/constants.ts +7 -0
  260. package/src/util/createFormexStub.tsx +66 -0
  261. package/src/util/entity_cache.ts +239 -0
  262. package/src/util/enums.ts +32 -0
  263. package/src/util/icon_list.ts +22 -0
  264. package/src/util/icons.tsx +149 -0
  265. package/src/util/index.ts +12 -0
  266. package/src/util/previews.ts +105 -0
  267. package/src/util/useStorageUploadController.tsx +350 -0
  268. package/src/vitePlugin.ts +196 -0
@@ -0,0 +1,156 @@
1
+
2
+ import React from "react";
3
+ import { Button, cls, Container, IconButton, Paper, Separator, Trash2Icon, Typography } from "@rebasepro/ui";
4
+
5
+ export const UIStyleGuide = () => {
6
+ const typographyVariants = [
7
+ "h1", "h2", "h3", "h4", "h5", "h6",
8
+ "subtitle1", "subtitle2",
9
+ "body1", "body2",
10
+ "caption", "label", "button"
11
+ ] as const;
12
+
13
+ const colors = ["primary", "secondary", "disabled", "error"] as const;
14
+ const buttonVariants = ["filled", "text"] as const;
15
+ const buttonColors = ["primary", "secondary", "text", "error", "neutral"] as const;
16
+ const buttonSizes = ["small", "medium", "large", "xl", "2xl"] as const;
17
+
18
+ const IconExample = () => (
19
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
20
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6"/>
21
+ </svg>
22
+ );
23
+
24
+ return (
25
+ <Container className="py-10 max-w-5xl">
26
+ <Typography variant="h2" gutterBottom>Rebase UI Style Guide</Typography>
27
+ <Typography variant="body1" color="secondary" className="mb-8">
28
+ A showcase of all typography and button variants available in the @rebasepro/ui library.
29
+ </Typography>
30
+
31
+ <section className="mb-12">
32
+ <Typography variant="h4" gutterBottom className="border-b pb-2 mb-6">Typography Variants</Typography>
33
+ <Paper className="p-6 space-y-6">
34
+ {typographyVariants.map(variant => (
35
+ <div key={variant} className="flex items-center gap-4 border-b border-surface-100 dark:border-surface-950 pb-4 last:border-0">
36
+ <span className="w-24 text-[10px] uppercase tracking-wider text-text-disabled font-mono">{variant}</span>
37
+ <Typography variant={variant}>
38
+ The quick brown fox jumps over the lazy dog ({variant})
39
+ </Typography>
40
+ </div>
41
+ ))}
42
+ </Paper>
43
+ </section>
44
+
45
+ <section className="mb-12">
46
+ <Typography variant="h4" gutterBottom className="border-b pb-2 mb-6">Typography Colors</Typography>
47
+ <Paper className="p-6 space-y-4">
48
+ {colors.map(color => (
49
+ <div key={color} className="flex items-center gap-4">
50
+ <span className="w-24 text-[10px] uppercase tracking-wider text-text-disabled font-mono">{color}</span>
51
+ <Typography color={color}>
52
+ This text is rendered with color=&quot;{color}&quot;
53
+ </Typography>
54
+ </div>
55
+ ))}
56
+ </Paper>
57
+ </section>
58
+
59
+ <section className="mb-12">
60
+ <Typography variant="h4" gutterBottom className="border-b pb-2 mb-6">Button Discovery</Typography>
61
+
62
+ <div className="space-y-8">
63
+ {buttonVariants.map(variant => (
64
+ <div key={variant}>
65
+ <Typography variant="h6" gutterBottom className="capitalize mb-4">{variant} Buttons</Typography>
66
+ <Paper className="p-6">
67
+ <div className="flex flex-wrap gap-4">
68
+ {buttonColors.map(color => (
69
+ <div key={color} className="flex flex-col items-center gap-2">
70
+ <Button variant={variant} color={color}>
71
+ {color}
72
+ </Button>
73
+ <span className="text-[10px] text-text-disabled font-mono">{color}</span>
74
+ </div>
75
+ ))}
76
+ <div className="flex flex-col items-center gap-2">
77
+ <Button variant={variant} color="primary" disabled>
78
+ Disabled
79
+ </Button>
80
+ <span className="text-[10px] text-text-disabled font-mono">disabled</span>
81
+ </div>
82
+ </div>
83
+ </Paper>
84
+ </div>
85
+ ))}
86
+ </div>
87
+ </section>
88
+
89
+ <section className="mb-12">
90
+ <Typography variant="h4" gutterBottom className="border-b pb-2 mb-6">Button Sizes</Typography>
91
+ <Paper className="p-6">
92
+ <div className="flex flex-wrap items-end gap-6 text-center">
93
+ {buttonSizes.map(size => (
94
+ <div key={size} className="flex flex-col items-center gap-4">
95
+ <Button size={size} color="primary">
96
+ {size}
97
+ </Button>
98
+ <span className="text-[10px] text-text-disabled font-mono">{size}</span>
99
+ </div>
100
+ ))}
101
+ </div>
102
+ </Paper>
103
+ </section>
104
+
105
+ <section className="mb-12">
106
+ <Typography variant="h4" gutterBottom className="border-b pb-2 mb-6">Icon Buttons</Typography>
107
+ <Paper className="p-6">
108
+ <div className="flex flex-wrap gap-8 items-center">
109
+ <div className="flex flex-col items-center gap-2">
110
+ <IconButton color="primary">
111
+ <IconExample/>
112
+ </IconButton>
113
+ <span className="text-[10px] text-text-disabled font-mono">primary</span>
114
+ </div>
115
+ <div className="flex flex-col items-center gap-2">
116
+ <IconButton color="secondary">
117
+ <IconExample/>
118
+ </IconButton>
119
+ <span className="text-[10px] text-text-disabled font-mono">secondary</span>
120
+ </div>
121
+ <div className="flex flex-col items-center gap-2">
122
+ <IconButton size="small">
123
+ <IconExample/>
124
+ </IconButton>
125
+ <span className="text-[10px] text-text-disabled font-mono">small</span>
126
+ </div>
127
+ <div className="flex flex-col items-center gap-2">
128
+ <IconButton disabled>
129
+ <IconExample/>
130
+ </IconButton>
131
+ <span className="text-[10px] text-text-disabled font-mono">disabled</span>
132
+ </div>
133
+ <div className="flex flex-col items-center gap-2">
134
+ <IconButton size="small" color="error">
135
+ <Trash2Icon/>
136
+ </IconButton>
137
+ <span className="text-[10px] text-text-disabled font-mono">delete</span>
138
+ </div>
139
+ </div>
140
+ </Paper>
141
+ </section>
142
+
143
+ <section className="mb-12">
144
+ <div className="flex justify-between items-center bg-surface-100 dark:bg-surface-950 p-8 rounded-xl border border-dashed border-surface-400">
145
+ <div>
146
+ <Typography variant="h5">Dark Mode Check</Typography>
147
+ <Typography variant="body2" color="secondary">Typography and buttons should adapt automatically.</Typography>
148
+ </div>
149
+ <Button variant="filled" color="neutral" startIcon={<IconExample/>}>
150
+ Sample Action
151
+ </Button>
152
+ </div>
153
+ </section>
154
+ </Container>
155
+ );
156
+ };
@@ -0,0 +1,85 @@
1
+ import React, { useState, useMemo } from "react";
2
+ import { Card, Typography, Chip, cls, defaultBorderMixin, SearchBar, ToggleButtonGroup } from "@rebasepro/ui";
3
+ import { LayoutGridIcon, ListIcon, FolderKanbanIcon } from "lucide-react";
4
+ import { SAMPLE_PROJECTS, STATUS_CONFIG, PRIORITY_CONFIG } from "./sample_data";
5
+ import type { SampleProject } from "./sample_data";
6
+
7
+ type CardSize = "sm" | "md" | "lg";
8
+
9
+ export function CardViewDemo() {
10
+ const [searchTerm, setSearchTerm] = useState("");
11
+ const [cardSize, setCardSize] = useState<CardSize>("md");
12
+
13
+ const filtered = useMemo(() => {
14
+ if (!searchTerm) return SAMPLE_PROJECTS;
15
+ const lower = searchTerm.toLowerCase();
16
+ return SAMPLE_PROJECTS.filter(p =>
17
+ p.name.toLowerCase().includes(lower) || p.assignee.toLowerCase().includes(lower) || p.tags.some(t => t.toLowerCase().includes(lower))
18
+ );
19
+ }, [searchTerm]);
20
+
21
+ const gridClass = useMemo(() => {
22
+ switch (cardSize) {
23
+ case "sm": return "grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5";
24
+ case "md": return "grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4";
25
+ case "lg": return "grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3";
26
+ }
27
+ }, [cardSize]);
28
+
29
+ return (
30
+ <div className="space-y-3">
31
+ <div className="flex items-center gap-3 flex-wrap">
32
+ <SearchBar onTextSearch={(term) => setSearchTerm(term ?? "")} placeholder="Search cards…" size="small" />
33
+ <ToggleButtonGroup value={cardSize} onValueChange={setCardSize} options={[
34
+ { value: "sm" as const, label: "Small", icon: <LayoutGridIcon size={14} /> },
35
+ { value: "md" as const, label: "Medium", icon: <ListIcon size={14} /> },
36
+ { value: "lg" as const, label: "Large", icon: <FolderKanbanIcon size={14} /> }
37
+ ]} />
38
+ <Typography variant="caption" color="secondary" className="ml-auto">{filtered.length} projects</Typography>
39
+ </div>
40
+ <div className={cls("grid gap-4", gridClass)}>
41
+ {filtered.map(project => <ProjectCard key={project.id} project={project} compact={cardSize === "sm"} />)}
42
+ </div>
43
+ {filtered.length === 0 && <div className="flex items-center justify-center py-8"><Typography variant="label" color="secondary">No projects match your search</Typography></div>}
44
+ </div>
45
+ );
46
+ }
47
+
48
+ function ProjectCard({ project, compact }: { project: SampleProject; compact?: boolean }) {
49
+ const statusCfg = STATUS_CONFIG[project.status];
50
+ const priorityCfg = PRIORITY_CONFIG[project.priority];
51
+ const isOverdue = new Date(project.dueDate) < new Date() && project.status !== "done";
52
+
53
+ return (
54
+ <Card className={cls("cursor-pointer overflow-hidden group relative", "transition-all duration-200", "hover:shadow-lg hover:-translate-y-0.5")}>
55
+ <div className={cls("relative overflow-hidden bg-surface-100 dark:bg-surface-900", compact ? "h-20" : "aspect-[5/2]")}>
56
+ <div className="absolute inset-0 opacity-20 transition-all duration-300" style={{ background: `linear-gradient(90deg, var(--color-primary) ${project.progress}%, transparent ${project.progress}%)` }} />
57
+ <div className="absolute inset-0 flex flex-col items-center justify-center gap-1">
58
+ <FolderKanbanIcon size={compact ? 20 : 28} className="text-surface-400 dark:text-surface-500" />
59
+ {!compact && <Typography variant="caption" color="secondary" className="font-mono text-[10px]">{project.progress}% complete</Typography>}
60
+ </div>
61
+ <div className="absolute inset-0 bg-black/0 group-hover:bg-black/10 transition-colors duration-200" />
62
+ <div className="absolute top-2 right-2"><Chip colorScheme={priorityCfg.color} size="smallest" outlined>{priorityCfg.label}</Chip></div>
63
+ </div>
64
+ <div className={compact ? "p-2" : "p-3"}>
65
+ <Typography variant="caption" color="disabled" className="font-mono truncate block text-[10px]">{project.id}</Typography>
66
+ <div className="truncate my-1"><Typography variant={compact ? "caption" : "body2"} className="font-medium">{project.name}</Typography></div>
67
+ {!compact && <Typography variant="caption" color="secondary" className="line-clamp-2 mb-2">{project.description}</Typography>}
68
+ <div className="flex items-center gap-1.5 flex-wrap">
69
+ <Chip colorScheme={statusCfg.color} size="smallest">{statusCfg.label}</Chip>
70
+ {!compact && project.tags.slice(0, 2).map(tag => <Chip key={tag} size="smallest" colorScheme="cyan" className="!text-[10px]">{tag}</Chip>)}
71
+ {!compact && project.tags.length > 2 && <span className="text-[10px] text-surface-400">+{project.tags.length - 2}</span>}
72
+ </div>
73
+ {!compact && (
74
+ <div className={cls("flex items-center justify-between mt-2 pt-2 border-t", defaultBorderMixin)}>
75
+ <div className="flex items-center gap-1.5">
76
+ <div className="w-5 h-5 rounded-full bg-surface-200 dark:bg-surface-700 text-surface-500 flex items-center justify-center text-[9px] font-bold">{project.assignee[0]}</div>
77
+ <Typography variant="caption" color="secondary" className="truncate max-w-[100px]">{project.assignee}</Typography>
78
+ </div>
79
+ <Typography variant="caption" className={cls("font-mono text-[10px]", isOverdue ? "text-red-500 font-semibold" : "text-surface-400")}>{project.dueDate}</Typography>
80
+ </div>
81
+ )}
82
+ </div>
83
+ </Card>
84
+ );
85
+ }
@@ -0,0 +1,107 @@
1
+ import React, { useState, useMemo } from "react";
2
+ import {
3
+ Typography, Chip, cls, defaultBorderMixin,
4
+ Table, TableHeader, TableBody, TableRow, TableCell,
5
+ SearchBar, IconButton, Tooltip, Checkbox, iconSize,
6
+ Select, SelectItem
7
+ } from "@rebasepro/ui";
8
+ import { Trash2Icon, PencilIcon, ArrowUpDownIcon, ArrowUpIcon, ArrowDownIcon } from "lucide-react";
9
+ import { SAMPLE_PROJECTS, STATUS_CONFIG, PRIORITY_CONFIG } from "./sample_data";
10
+ import type { ProjectStatus } from "./sample_data";
11
+
12
+ type SortField = "name" | "status" | "priority" | "dueDate";
13
+ type SortDirection = "asc" | "desc";
14
+
15
+ export function CollectionTableDemo() {
16
+ const [searchTerm, setSearchTerm] = useState("");
17
+ const [sortField, setSortField] = useState<SortField>("name");
18
+ const [sortDirection, setSortDirection] = useState<SortDirection>("asc");
19
+ const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
20
+ const [statusFilter, setStatusFilter] = useState<string>("all");
21
+
22
+ const filteredAndSorted = useMemo(() => {
23
+ let results = SAMPLE_PROJECTS.filter(p => {
24
+ const matchesSearch = !searchTerm ||
25
+ p.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
26
+ p.assignee.toLowerCase().includes(searchTerm.toLowerCase());
27
+ const matchesStatus = statusFilter === "all" || p.status === statusFilter;
28
+ return matchesSearch && matchesStatus;
29
+ });
30
+ results = [...results].sort((a, b) => {
31
+ const cmp = String(a[sortField]).localeCompare(String(b[sortField]));
32
+ return sortDirection === "asc" ? cmp : -cmp;
33
+ });
34
+ return results;
35
+ }, [searchTerm, sortField, sortDirection, statusFilter]);
36
+
37
+ const toggleSort = (field: SortField) => {
38
+ if (sortField === field) setSortDirection(d => d === "asc" ? "desc" : "asc");
39
+ else { setSortField(field); setSortDirection("asc"); }
40
+ };
41
+
42
+ const toggleSelect = (id: string) => {
43
+ setSelectedIds(prev => {
44
+ const next = new Set(prev);
45
+ if (next.has(id)) next.delete(id); else next.add(id);
46
+ return next;
47
+ });
48
+ };
49
+
50
+ const toggleSelectAll = (checked: boolean) => {
51
+ setSelectedIds(checked ? new Set(filteredAndSorted.map(p => p.id)) : new Set());
52
+ };
53
+
54
+ const allSelected = filteredAndSorted.length > 0 && filteredAndSorted.every(p => selectedIds.has(p.id));
55
+
56
+ const SortIcon = ({ field }: { field: SortField }) => {
57
+ if (sortField !== field) return <ArrowUpDownIcon size={12} className="text-surface-400" />;
58
+ return sortDirection === "asc"
59
+ ? <ArrowUpIcon size={12} className="text-primary" />
60
+ : <ArrowDownIcon size={12} className="text-primary" />;
61
+ };
62
+
63
+ return (
64
+ <div className="space-y-3">
65
+ <div className="flex items-center gap-3 flex-wrap">
66
+ <SearchBar onTextSearch={(term) => setSearchTerm(term ?? "")} placeholder="Search projects…" size="small" />
67
+ <Select value={statusFilter} onValueChange={setStatusFilter} size="small" placeholder="Status">
68
+ <SelectItem value="all">All Statuses</SelectItem>
69
+ {(Object.entries(STATUS_CONFIG) as [ProjectStatus, { label: string }][]).map(([key, { label }]) => (
70
+ <SelectItem key={key} value={key}>{label}</SelectItem>
71
+ ))}
72
+ </Select>
73
+ {selectedIds.size > 0 && <Typography variant="caption" color="secondary">{selectedIds.size} selected</Typography>}
74
+ </div>
75
+ <div className={cls("rounded-lg border overflow-hidden", defaultBorderMixin)}>
76
+ <Table className="w-full">
77
+ <TableHeader>
78
+ <TableCell header style={{ width: "40px" }}><Checkbox checked={allSelected} onCheckedChange={toggleSelectAll} size="small" /></TableCell>
79
+ <TableCell header><button onClick={() => toggleSort("name")} className="flex items-center gap-1 cursor-pointer"><Typography variant="caption" className="font-semibold">Name</Typography><SortIcon field="name" /></button></TableCell>
80
+ <TableCell header><button onClick={() => toggleSort("status")} className="flex items-center gap-1 cursor-pointer"><Typography variant="caption" className="font-semibold">Status</Typography><SortIcon field="status" /></button></TableCell>
81
+ <TableCell header><button onClick={() => toggleSort("priority")} className="flex items-center gap-1 cursor-pointer"><Typography variant="caption" className="font-semibold">Priority</Typography><SortIcon field="priority" /></button></TableCell>
82
+ <TableCell header><Typography variant="caption" className="font-semibold">Assignee</Typography></TableCell>
83
+ <TableCell header><Typography variant="caption" className="font-semibold">Tags</Typography></TableCell>
84
+ <TableCell header><button onClick={() => toggleSort("dueDate")} className="flex items-center gap-1 cursor-pointer"><Typography variant="caption" className="font-semibold">Due Date</Typography><SortIcon field="dueDate" /></button></TableCell>
85
+ <TableCell header style={{ width: "80px" }}><Typography variant="caption" className="font-semibold">Actions</Typography></TableCell>
86
+ </TableHeader>
87
+ <TableBody>
88
+ {filteredAndSorted.map(project => (
89
+ <TableRow key={project.id} className={cls(selectedIds.has(project.id) && "bg-primary/[0.03] dark:bg-primary/[0.06]")}>
90
+ <TableCell style={{ width: "40px" }}><Checkbox checked={selectedIds.has(project.id)} onCheckedChange={() => toggleSelect(project.id)} size="small" /></TableCell>
91
+ <TableCell><div><Typography variant="body2" className="font-medium">{project.name}</Typography><Typography variant="caption" color="secondary" className="line-clamp-1">{project.description}</Typography></div></TableCell>
92
+ <TableCell><Chip colorScheme={STATUS_CONFIG[project.status].color} size="small">{STATUS_CONFIG[project.status].label}</Chip></TableCell>
93
+ <TableCell><Chip colorScheme={PRIORITY_CONFIG[project.priority].color} size="smallest" outlined>{PRIORITY_CONFIG[project.priority].label}</Chip></TableCell>
94
+ <TableCell><div className="flex items-center gap-2"><div className="w-6 h-6 rounded-full bg-surface-200 dark:bg-surface-700 text-surface-500 flex items-center justify-center text-[10px] font-bold shrink-0">{project.assignee[0]}</div><Typography variant="body2" className="truncate">{project.assignee}</Typography></div></TableCell>
95
+ <TableCell><div className="flex flex-wrap gap-1">{project.tags.map(tag => (<Chip key={tag} size="smallest" colorScheme="cyan">{tag}</Chip>))}</div></TableCell>
96
+ <TableCell><Typography variant="body2" className="font-mono text-xs">{project.dueDate}</Typography></TableCell>
97
+ <TableCell style={{ width: "80px" }}><div className="flex gap-1"><Tooltip title="Edit" asChild><IconButton size="smallest"><PencilIcon size={iconSize.smallest} /></IconButton></Tooltip><Tooltip title="Delete" asChild><IconButton size="smallest"><Trash2Icon size={iconSize.smallest} /></IconButton></Tooltip></div></TableCell>
98
+ </TableRow>
99
+ ))}
100
+ </TableBody>
101
+ </Table>
102
+ {filteredAndSorted.length === 0 && <div className="flex items-center justify-center py-8"><Typography variant="label" color="secondary">No projects match your filters</Typography></div>}
103
+ </div>
104
+ <Typography variant="caption" color="secondary">{filteredAndSorted.length} of {SAMPLE_PROJECTS.length} projects</Typography>
105
+ </div>
106
+ );
107
+ }
@@ -0,0 +1,90 @@
1
+ import React, { useState, useCallback, useMemo } from "react";
2
+ import { Typography, Chip, cls, defaultBorderMixin, KanbanView, Alert } from "@rebasepro/ui";
3
+ import type { BoardItem, BoardItemViewProps } from "@rebasepro/ui";
4
+ import { FolderKanbanIcon } from "lucide-react";
5
+ import { SAMPLE_PROJECTS, PRIORITY_CONFIG } from "./sample_data";
6
+ import type { SampleProject, ProjectStatus } from "./sample_data";
7
+
8
+ const STATUS_COLUMNS: ProjectStatus[] = ["backlog", "in_progress", "in_review", "done"];
9
+ const COLUMN_LABELS: Record<ProjectStatus, string> = { backlog: "Backlog", in_progress: "In Progress", in_review: "In Review", done: "Done" };
10
+ const COLUMN_COLORS: Record<ProjectStatus, string> = { backlog: "#6b7280", in_progress: "#3b82f6", in_review: "#8b5cf6", done: "#22c55e" };
11
+
12
+ function KanbanProjectCard({ item, isDragging, isGroupedOver, style }: BoardItemViewProps<SampleProject>) {
13
+ const project = item.data;
14
+ const priorityCfg = PRIORITY_CONFIG[project.priority];
15
+ const isOverdue = new Date(project.dueDate) < new Date() && project.status !== "done";
16
+
17
+ const backgroundColor = useMemo((): string => {
18
+ if (isDragging) return "bg-surface-100 dark:bg-surface-800";
19
+ if (isGroupedOver) return "bg-surface-200 dark:bg-surface-700";
20
+ return "bg-white dark:bg-surface-800 hover:bg-surface-50 dark:hover:bg-surface-700";
21
+ }, [isDragging, isGroupedOver]);
22
+
23
+ const borderColor = useMemo((): string => isDragging ? "ring-2 ring-primary" : "", [isDragging]);
24
+
25
+ return (
26
+ <div style={style} className="py-1" data-testid={item.id}>
27
+ <div className={cls("group/card p-2 flex items-start border rounded-lg cursor-pointer transition-all duration-200", defaultBorderMixin, borderColor, backgroundColor, "hover:shadow-sm")}>
28
+ <div className="w-10 h-10 rounded-md shrink-0 mr-2 bg-surface-100 dark:bg-surface-900 flex items-center justify-center">
29
+ <FolderKanbanIcon size={16} className="text-surface-400" />
30
+ </div>
31
+ <div className="flex-1 min-w-0">
32
+ <div className="line-clamp-2 text-sm font-medium">{project.name}</div>
33
+ <div className="text-xs text-surface-500 mt-1 line-clamp-2 opacity-80">{project.description}</div>
34
+ <div className="flex items-center gap-1 mt-1.5 flex-wrap">
35
+ <Chip colorScheme={priorityCfg.color} size="smallest" outlined className="!text-[10px] !leading-tight !py-0">{priorityCfg.label}</Chip>
36
+ {project.tags.slice(0, 2).map(tag => <Chip key={tag} size="smallest" colorScheme="cyan" className="!text-[10px] !leading-tight !py-0 max-w-[80px] truncate">{tag}</Chip>)}
37
+ </div>
38
+ <div className="flex items-center justify-between mt-1.5">
39
+ <div className="flex items-center gap-1">
40
+ <div className="w-4 h-4 rounded-full bg-surface-200 dark:bg-surface-700 text-surface-500 flex items-center justify-center text-[8px] font-bold">{project.assignee[0]}</div>
41
+ <Typography variant="caption" color="secondary" className="truncate max-w-[80px] text-[10px]">{project.assignee}</Typography>
42
+ </div>
43
+ <Typography variant="caption" className={cls("font-mono text-[10px]", isOverdue ? "text-red-500 font-semibold" : "text-surface-400")}>{project.dueDate}</Typography>
44
+ </div>
45
+ </div>
46
+ </div>
47
+ </div>
48
+ );
49
+ }
50
+
51
+ export function KanbanBoardDemo() {
52
+ const [boardData, setBoardData] = useState<BoardItem<SampleProject>[]>(() => SAMPLE_PROJECTS.map(p => ({ id: p.id, data: p })));
53
+ const [columns, setColumns] = useState<ProjectStatus[]>(STATUS_COLUMNS);
54
+
55
+ const assignColumn = useCallback((item: BoardItem<SampleProject>): ProjectStatus => item.data.status, []);
56
+
57
+ const handleItemsReorder = useCallback((items: BoardItem<SampleProject>[], moveInfo?: { itemId: string; sourceColumn: ProjectStatus; targetColumn: ProjectStatus }) => {
58
+ const updatedItems = items.map(item => {
59
+ if (moveInfo && item.id === moveInfo.itemId && moveInfo.sourceColumn !== moveInfo.targetColumn) {
60
+ return { ...item, data: { ...item.data, status: moveInfo.targetColumn, progress: moveInfo.targetColumn === "done" ? 100 : item.data.progress } };
61
+ }
62
+ return item;
63
+ });
64
+ setBoardData(updatedItems);
65
+ }, []);
66
+
67
+ const handleColumnReorder = useCallback((reordered: ProjectStatus[]) => setColumns(reordered), []);
68
+
69
+ const columnLoadingState = useMemo(() => {
70
+ const state: Record<string, { loading: boolean; hasMore: boolean; itemCount: number; totalCount: number }> = {};
71
+ for (const col of columns) {
72
+ const count = boardData.filter(item => item.data.status === col).length;
73
+ state[col] = { loading: false, hasMore: false, itemCount: count, totalCount: count };
74
+ }
75
+ return state;
76
+ }, [boardData, columns]);
77
+
78
+ return (
79
+ <div className="space-y-3">
80
+ <Alert color="info" size="small">Drag and drop cards between columns to change status. Columns are also reorderable.</Alert>
81
+ <div className={cls("rounded-lg border overflow-hidden", defaultBorderMixin)} style={{ height: 520 }}>
82
+ <KanbanView<SampleProject, ProjectStatus>
83
+ data={boardData} columns={columns} columnLabels={COLUMN_LABELS} columnColors={COLUMN_COLORS}
84
+ assignColumn={assignColumn} allowColumnReorder={true} onColumnReorder={handleColumnReorder}
85
+ onItemsReorder={handleItemsReorder} ItemComponent={KanbanProjectCard} columnLoadingState={columnLoadingState}
86
+ />
87
+ </div>
88
+ </div>
89
+ );
90
+ }
@@ -0,0 +1,3 @@
1
+ export { CollectionTableDemo } from "./CollectionTableDemo";
2
+ export { CardViewDemo } from "./CardViewDemo";
3
+ export { KanbanBoardDemo } from "./KanbanBoardDemo";
@@ -0,0 +1,42 @@
1
+ export type ProjectStatus = "backlog" | "in_progress" | "in_review" | "done";
2
+ export type ProjectPriority = "low" | "medium" | "high" | "critical";
3
+
4
+ export interface SampleProject {
5
+ id: string;
6
+ name: string;
7
+ description: string;
8
+ status: ProjectStatus;
9
+ priority: ProjectPriority;
10
+ assignee: string;
11
+ tags: string[];
12
+ dueDate: string;
13
+ progress: number;
14
+ createdAt: string;
15
+ }
16
+
17
+ export const STATUS_CONFIG: Record<ProjectStatus, { label: string; color: string }> = {
18
+ backlog: { label: "Backlog", color: "gray" },
19
+ in_progress: { label: "In Progress", color: "blue" },
20
+ in_review: { label: "In Review", color: "purple" },
21
+ done: { label: "Done", color: "green" }
22
+ };
23
+
24
+ export const PRIORITY_CONFIG: Record<ProjectPriority, { label: string; color: string }> = {
25
+ low: { label: "Low", color: "gray" },
26
+ medium: { label: "Medium", color: "yellow" },
27
+ high: { label: "High", color: "orange" },
28
+ critical: { label: "Critical", color: "red" }
29
+ };
30
+
31
+ export const SAMPLE_PROJECTS: SampleProject[] = [
32
+ { id: "proj-1", name: "Website Redesign", description: "Complete overhaul of the marketing website with new brand guidelines", status: "in_progress", priority: "high", assignee: "Alice Johnson", tags: ["frontend", "design"], dueDate: new Date(Date.now() + 7 * 86400000).toISOString().split("T")[0], progress: 65, createdAt: new Date(Date.now() - 14 * 86400000).toISOString() },
33
+ { id: "proj-2", name: "API Rate Limiting", description: "Implement token-bucket rate limiting across all public endpoints", status: "in_review", priority: "critical", assignee: "Bob Smith", tags: ["backend", "security"], dueDate: new Date(Date.now() + 2 * 86400000).toISOString().split("T")[0], progress: 90, createdAt: new Date(Date.now() - 10 * 86400000).toISOString() },
34
+ { id: "proj-3", name: "Mobile Push Notifications", description: "Add support for push notifications on iOS and Android clients", status: "backlog", priority: "medium", assignee: "Carol White", tags: ["mobile", "backend"], dueDate: new Date(Date.now() + 21 * 86400000).toISOString().split("T")[0], progress: 0, createdAt: new Date(Date.now() - 3 * 86400000).toISOString() },
35
+ { id: "proj-4", name: "Dashboard Analytics", description: "Build real-time analytics dashboard with charts and KPI widgets", status: "in_progress", priority: "high", assignee: "David Brown", tags: ["frontend", "data"], dueDate: new Date(Date.now() + 5 * 86400000).toISOString().split("T")[0], progress: 40, createdAt: new Date(Date.now() - 7 * 86400000).toISOString() },
36
+ { id: "proj-5", name: "User Onboarding Flow", description: "Multi-step onboarding wizard with progress tracking and email triggers", status: "done", priority: "medium", assignee: "Eva Green", tags: ["frontend", "ux"], dueDate: new Date(Date.now() - 2 * 86400000).toISOString().split("T")[0], progress: 100, createdAt: new Date(Date.now() - 21 * 86400000).toISOString() },
37
+ { id: "proj-6", name: "Database Migration v3", description: "Migrate from PostgreSQL 14 to 16 with zero-downtime strategy", status: "backlog", priority: "low", assignee: "Frank Miller", tags: ["backend", "infrastructure"], dueDate: new Date(Date.now() + 30 * 86400000).toISOString().split("T")[0], progress: 0, createdAt: new Date(Date.now() - 1 * 86400000).toISOString() },
38
+ { id: "proj-7", name: "SSO Integration", description: "SAML 2.0 and OIDC single sign-on for enterprise customers", status: "in_progress", priority: "critical", assignee: "Alice Johnson", tags: ["backend", "security", "enterprise"], dueDate: new Date(Date.now() + 3 * 86400000).toISOString().split("T")[0], progress: 75, createdAt: new Date(Date.now() - 12 * 86400000).toISOString() },
39
+ { id: "proj-8", name: "E2E Test Suite", description: "Playwright-based end-to-end tests covering critical user journeys", status: "in_review", priority: "medium", assignee: "Bob Smith", tags: ["testing", "devops"], dueDate: new Date(Date.now() + 1 * 86400000).toISOString().split("T")[0], progress: 85, createdAt: new Date(Date.now() - 8 * 86400000).toISOString() },
40
+ { id: "proj-9", name: "Billing System Upgrade", description: "Stripe integration upgrade with metered billing and invoice PDF generation", status: "done", priority: "high", assignee: "Carol White", tags: ["backend", "payments"], dueDate: new Date(Date.now() - 5 * 86400000).toISOString().split("T")[0], progress: 100, createdAt: new Date(Date.now() - 28 * 86400000).toISOString() },
41
+ { id: "proj-10", name: "Dark Mode Polish", description: "Audit and fix all remaining dark mode inconsistencies across the app", status: "backlog", priority: "low", assignee: "David Brown", tags: ["frontend", "design"], dueDate: new Date(Date.now() + 14 * 86400000).toISOString().split("T")[0], progress: 0, createdAt: new Date(Date.now() - 2 * 86400000).toISOString() }
42
+ ];