@pattern-stack/frontend-patterns 0.0.3 → 0.0.5

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 (406) hide show
  1. package/dist/frontend-patterns.css +1 -1
  2. package/dist/index.es.js +1918 -3
  3. package/dist/index.es.js.map +1 -1
  4. package/dist/index.js +1917 -1
  5. package/dist/index.js.map +1 -1
  6. package/package.json +10 -5
  7. package/src/App.css +42 -0
  8. package/src/App.tsx +64 -0
  9. package/src/__tests__/README.md +221 -0
  10. package/src/__tests__/atoms/hooks/simple-hooks.test.ts +44 -0
  11. package/src/__tests__/atoms/ui/button.test.tsx +68 -0
  12. package/src/__tests__/atoms/utils/simple.test.ts +18 -0
  13. package/src/__tests__/atoms/utils/utils.test.ts +77 -0
  14. package/src/__tests__/features/auth/simple-auth.test.tsx +40 -0
  15. package/src/__tests__/molecules/layout/simple-layout.test.tsx +81 -0
  16. package/src/__tests__/organisms/showcase/simple-showcase.test.tsx +167 -0
  17. package/src/__tests__/setup.ts +51 -0
  18. package/src/__tests__/utils.tsx +123 -0
  19. package/src/atoms/composed/Accordion/Accordion.tsx +271 -0
  20. package/{dist/atoms/composed/Accordion/index.d.ts → src/atoms/composed/Accordion/index.ts} +1 -2
  21. package/src/atoms/composed/Alert/Alert.tsx +132 -0
  22. package/src/atoms/composed/Alert/index.ts +1 -0
  23. package/src/atoms/composed/Breadcrumb/Breadcrumb.tsx +83 -0
  24. package/src/atoms/composed/Breadcrumb/index.ts +1 -0
  25. package/src/atoms/composed/Chart/Chart.tsx +425 -0
  26. package/{dist/atoms/composed/Chart/index.d.ts → src/atoms/composed/Chart/index.ts} +1 -2
  27. package/src/atoms/composed/ColorSwatch/ColorSwatch.tsx +72 -0
  28. package/{dist/atoms/composed/ColorSwatch/index.d.ts → src/atoms/composed/ColorSwatch/index.ts} +1 -2
  29. package/src/atoms/composed/DarkModeToggle.tsx +66 -0
  30. package/src/atoms/composed/DataBadge/DataBadge.tsx +81 -0
  31. package/src/atoms/composed/DataBadge/index.ts +1 -0
  32. package/src/atoms/composed/DataTable/DataTable.tsx +394 -0
  33. package/src/atoms/composed/DataTable/TableCellWithTooltip.tsx +41 -0
  34. package/src/atoms/composed/DataTable/index.ts +2 -0
  35. package/src/atoms/composed/DateTimePicker/DateTimePicker.tsx +611 -0
  36. package/src/atoms/composed/DateTimePicker/index.ts +2 -0
  37. package/src/atoms/composed/DetailedCard/DetailedCard.tsx +181 -0
  38. package/src/atoms/composed/DetailedCard/index.ts +2 -0
  39. package/src/atoms/composed/EmptyState/EmptyState.tsx +90 -0
  40. package/src/atoms/composed/EmptyState/index.ts +1 -0
  41. package/src/atoms/composed/FileUpload/FileUpload.tsx +477 -0
  42. package/{dist/atoms/composed/FileUpload/index.d.ts → src/atoms/composed/FileUpload/index.ts} +1 -2
  43. package/src/atoms/composed/FormField/FormField.tsx +92 -0
  44. package/src/atoms/composed/FormField/index.ts +1 -0
  45. package/src/atoms/composed/GlobalSearch/GlobalSearch.tsx +37 -0
  46. package/src/atoms/composed/GlobalSearch/index.ts +1 -0
  47. package/src/atoms/composed/IconBadge/IconBadge.tsx +95 -0
  48. package/src/atoms/composed/IconBadge/index.ts +2 -0
  49. package/src/atoms/composed/Modal/Modal.tsx +223 -0
  50. package/src/atoms/composed/Modal/index.ts +2 -0
  51. package/src/atoms/composed/PaletteSwitcher.tsx +386 -0
  52. package/src/atoms/composed/ProgressBar/ProgressBar.tsx +116 -0
  53. package/{dist/atoms/composed/ProgressBar/index.d.ts → src/atoms/composed/ProgressBar/index.ts} +1 -2
  54. package/src/atoms/composed/SalesPanel/SalesPanel.tsx +116 -0
  55. package/src/atoms/composed/SalesPanel/index.ts +1 -0
  56. package/src/atoms/composed/SalesPanel/mockSalesData.ts +151 -0
  57. package/src/atoms/composed/StatCard/StatCard.tsx +219 -0
  58. package/src/atoms/composed/StatCard/index.ts +1 -0
  59. package/src/atoms/composed/StyleGuide.tsx +717 -0
  60. package/src/atoms/composed/Toast/Toast.tsx +219 -0
  61. package/{dist/atoms/composed/Toast/index.d.ts → src/atoms/composed/Toast/index.ts} +1 -2
  62. package/src/atoms/composed/Tooltip/Tooltip.tsx +213 -0
  63. package/src/atoms/composed/Tooltip/index.ts +1 -0
  64. package/src/atoms/composed/UserAvatar/UserAvatar.tsx +139 -0
  65. package/src/atoms/composed/UserAvatar/index.ts +1 -0
  66. package/src/atoms/composed/UserMenu/UserMenu.tsx +16 -0
  67. package/src/atoms/composed/UserMenu/index.ts +1 -0
  68. package/{dist/atoms/composed/index.d.ts → src/atoms/composed/index.ts} +7 -2
  69. package/src/atoms/hooks/useApi.ts +80 -0
  70. package/src/atoms/hooks/useHealth.ts +17 -0
  71. package/{dist/atoms/index.d.ts → src/atoms/index.ts} +6 -2
  72. package/src/atoms/services/api/client.ts +134 -0
  73. package/src/atoms/services/auth-service.ts +248 -0
  74. package/src/atoms/services/health.ts +15 -0
  75. package/{dist/atoms/services/index.d.ts → src/atoms/services/index.ts} +1 -2
  76. package/src/atoms/shared/config/constants.ts +17 -0
  77. package/src/atoms/shared/config/dashboard-sizes.ts +111 -0
  78. package/src/atoms/shared/config/environment.ts +10 -0
  79. package/src/atoms/shared/index.ts +4 -0
  80. package/src/atoms/shared/styles/color-palettes.css +566 -0
  81. package/src/atoms/types/auth.ts +62 -0
  82. package/src/atoms/types/entity-config.ts +127 -0
  83. package/{dist/atoms/types/generated.d.ts → src/atoms/types/generated.ts} +1 -1
  84. package/{dist/atoms/types/index.d.ts → src/atoms/types/index.ts} +2 -1
  85. package/{dist/atoms/types/loading.d.ts → src/atoms/types/loading.ts} +10 -8
  86. package/src/atoms/ui/Badge.tsx +30 -0
  87. package/src/atoms/ui/ErrorBoundary.tsx +59 -0
  88. package/src/atoms/ui/Select.tsx +53 -0
  89. package/src/atoms/ui/Switch.tsx +42 -0
  90. package/src/atoms/ui/Tabs.tsx +118 -0
  91. package/src/atoms/ui/avatar.tsx +48 -0
  92. package/src/atoms/ui/button.tsx +70 -0
  93. package/src/atoms/ui/card.tsx +76 -0
  94. package/src/atoms/ui/dropdown-menu.tsx +199 -0
  95. package/{dist/atoms/ui/index.d.ts → src/atoms/ui/index.ts} +27 -3
  96. package/src/atoms/ui/input.tsx +23 -0
  97. package/src/atoms/ui/label.tsx +23 -0
  98. package/src/atoms/ui/skeleton.tsx +13 -0
  99. package/src/atoms/ui/spinner.tsx +49 -0
  100. package/src/atoms/ui/table.tsx +116 -0
  101. package/src/atoms/utils/animations.ts +135 -0
  102. package/src/atoms/utils/metric-engine.ts +236 -0
  103. package/src/atoms/utils/tooltip-helpers.ts +140 -0
  104. package/src/atoms/utils/utils.ts +10 -0
  105. package/src/features/auth/components/LoginForm.tsx +168 -0
  106. package/src/features/auth/components/LogoutButton.tsx +19 -0
  107. package/src/features/auth/components/ProtectedRoute.tsx +60 -0
  108. package/{dist/features/auth/components/index.d.ts → src/features/auth/components/index.ts} +1 -1
  109. package/src/features/auth/hooks/index.ts +2 -0
  110. package/src/features/auth/hooks/useAuth.tsx +205 -0
  111. package/src/features/auth/hooks/usePermissions.ts +35 -0
  112. package/src/features/auth/index.ts +2 -0
  113. package/src/features/index.ts +2 -0
  114. package/src/index.css +704 -0
  115. package/{dist/index.d.ts → src/index.ts} +5 -2
  116. package/src/main.tsx +48 -0
  117. package/src/molecules/.gitkeep +0 -0
  118. package/src/molecules/forms/FormGroup.tsx +75 -0
  119. package/src/molecules/forms/SearchInput.tsx +259 -0
  120. package/src/molecules/forms/index.ts +4 -0
  121. package/src/molecules/index.ts +4 -0
  122. package/src/molecules/layout/AppHeader/AppHeader.tsx +42 -0
  123. package/src/molecules/layout/AppHeader/index.ts +1 -0
  124. package/src/molecules/layout/AppLayout.tsx +29 -0
  125. package/src/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.tsx +42 -0
  126. package/src/molecules/layout/DashboardWithSidePanel/index.ts +1 -0
  127. package/src/molecules/layout/PageTemplate.tsx +87 -0
  128. package/src/molecules/layout/SectionHeader/SectionHeader.tsx +87 -0
  129. package/{dist/molecules/layout/SectionHeader/index.d.ts → src/molecules/layout/SectionHeader/index.ts} +1 -2
  130. package/src/molecules/layout/ShowcaseSection.tsx +57 -0
  131. package/src/molecules/layout/Sidebar.tsx +152 -0
  132. package/src/molecules/layout/SidebarButton/SidebarButton.tsx +99 -0
  133. package/src/molecules/layout/SidebarButton/index.ts +1 -0
  134. package/src/molecules/layout/SidebarContext.tsx +31 -0
  135. package/{dist/molecules/layout/index.d.ts → src/molecules/layout/index.ts} +2 -2
  136. package/src/molecules/navigation/NavMenu.tsx +188 -0
  137. package/src/molecules/navigation/Pagination.tsx +172 -0
  138. package/src/molecules/navigation/index.ts +4 -0
  139. package/src/organisms/entity/CategoryBreakdownPanel.tsx +427 -0
  140. package/src/organisms/entity/EntityListPanel.tsx +339 -0
  141. package/src/organisms/entity/MetricsOverviewPanel.tsx +236 -0
  142. package/src/organisms/entity/TrendAnalysisPanel.tsx +337 -0
  143. package/src/organisms/entity/index.ts +4 -0
  144. package/src/organisms/index.ts +8 -0
  145. package/src/organisms/showcase/ComponentShowcasePage.tsx +2496 -0
  146. package/src/organisms/showcase/index.ts +1 -0
  147. package/src/pages/AdminShowcase/AdminCRUDShowcase.tsx +242 -0
  148. package/src/pages/AdminShowcase/AdminDashboardShowcase.tsx +173 -0
  149. package/src/pages/AdminShowcase/AdminDetailShowcase.tsx +385 -0
  150. package/src/pages/AdminShowcase/SalesPerformanceDashboard.tsx +158 -0
  151. package/src/pages/AdminShowcase/index.tsx +4 -0
  152. package/src/pages/ComponentShowcase/BadgesShowcase.tsx +188 -0
  153. package/src/pages/ComponentShowcase/CardsShowcase.tsx +392 -0
  154. package/src/pages/ComponentShowcase/PalettesShowcase.tsx +207 -0
  155. package/src/pages/ComponentShowcase/StatesShowcase.tsx +485 -0
  156. package/src/pages/ComponentShowcase/TablesShowcase.tsx +134 -0
  157. package/src/pages/ComponentShowcase/TypographyShowcase.tsx +255 -0
  158. package/src/pages/ComponentShowcase/index.tsx +188 -0
  159. package/src/pages/EntityShowcase/EntityManagementShowcase.tsx +137 -0
  160. package/src/pages/EntityShowcase/EntityPerformanceShowcase.tsx +117 -0
  161. package/src/pages/EntityShowcase/index.ts +2 -0
  162. package/src/pages/EntityTemplateExample.tsx +229 -0
  163. package/src/pages/TestEntityTemplate.tsx +40 -0
  164. package/src/pages/index.ts +3 -0
  165. package/src/templates/AuthTemplate.tsx +216 -0
  166. package/src/templates/ComponentShowcaseTemplate.tsx +173 -0
  167. package/src/templates/DashboardTemplate.tsx +232 -0
  168. package/src/templates/DataTemplate.tsx +319 -0
  169. package/src/templates/admin/AdminCRUDTemplate.tsx +630 -0
  170. package/src/templates/admin/AdminDashboardTemplate.tsx +351 -0
  171. package/src/templates/admin/AdminDetailTemplate.tsx +563 -0
  172. package/src/templates/admin/index.ts +29 -0
  173. package/src/templates/entity/EntityManagementTemplate.tsx +430 -0
  174. package/src/templates/entity/EntityPerformanceDashboardTemplate.tsx +277 -0
  175. package/src/templates/entity/configs/financial-config.ts +141 -0
  176. package/src/templates/entity/configs/index.ts +1 -0
  177. package/src/templates/entity/index.ts +3 -0
  178. package/src/templates/factory.tsx +169 -0
  179. package/src/templates/financial/FinancialDashboardTemplate.tsx +326 -0
  180. package/src/templates/index.ts +40 -0
  181. package/src/vite-env.d.ts +1 -0
  182. package/dist/atoms/composed/Accordion/Accordion.d.ts +0 -20
  183. package/dist/atoms/composed/Accordion/Accordion.d.ts.map +0 -1
  184. package/dist/atoms/composed/Accordion/index.d.ts.map +0 -1
  185. package/dist/atoms/composed/Alert/Alert.d.ts +0 -25
  186. package/dist/atoms/composed/Alert/Alert.d.ts.map +0 -1
  187. package/dist/atoms/composed/Alert/index.d.ts +0 -2
  188. package/dist/atoms/composed/Alert/index.d.ts.map +0 -1
  189. package/dist/atoms/composed/Breadcrumb/Breadcrumb.d.ts +0 -17
  190. package/dist/atoms/composed/Breadcrumb/Breadcrumb.d.ts.map +0 -1
  191. package/dist/atoms/composed/Breadcrumb/index.d.ts +0 -2
  192. package/dist/atoms/composed/Breadcrumb/index.d.ts.map +0 -1
  193. package/dist/atoms/composed/Chart/Chart.d.ts +0 -37
  194. package/dist/atoms/composed/Chart/Chart.d.ts.map +0 -1
  195. package/dist/atoms/composed/Chart/index.d.ts.map +0 -1
  196. package/dist/atoms/composed/ColorSwatch/ColorSwatch.d.ts +0 -19
  197. package/dist/atoms/composed/ColorSwatch/ColorSwatch.d.ts.map +0 -1
  198. package/dist/atoms/composed/ColorSwatch/index.d.ts.map +0 -1
  199. package/dist/atoms/composed/DarkModeToggle.d.ts +0 -4
  200. package/dist/atoms/composed/DarkModeToggle.d.ts.map +0 -1
  201. package/dist/atoms/composed/DataBadge/DataBadge.d.ts +0 -13
  202. package/dist/atoms/composed/DataBadge/DataBadge.d.ts.map +0 -1
  203. package/dist/atoms/composed/DataBadge/index.d.ts +0 -2
  204. package/dist/atoms/composed/DataBadge/index.d.ts.map +0 -1
  205. package/dist/atoms/composed/DataTable/DataTable.d.ts +0 -28
  206. package/dist/atoms/composed/DataTable/DataTable.d.ts.map +0 -1
  207. package/dist/atoms/composed/DataTable/TableCellWithTooltip.d.ts +0 -10
  208. package/dist/atoms/composed/DataTable/TableCellWithTooltip.d.ts.map +0 -1
  209. package/dist/atoms/composed/DataTable/index.d.ts +0 -3
  210. package/dist/atoms/composed/DataTable/index.d.ts.map +0 -1
  211. package/dist/atoms/composed/DateTimePicker/DateTimePicker.d.ts +0 -45
  212. package/dist/atoms/composed/DateTimePicker/DateTimePicker.d.ts.map +0 -1
  213. package/dist/atoms/composed/DateTimePicker/index.d.ts +0 -3
  214. package/dist/atoms/composed/DateTimePicker/index.d.ts.map +0 -1
  215. package/dist/atoms/composed/DetailedCard/DetailedCard.d.ts +0 -30
  216. package/dist/atoms/composed/DetailedCard/DetailedCard.d.ts.map +0 -1
  217. package/dist/atoms/composed/DetailedCard/index.d.ts +0 -3
  218. package/dist/atoms/composed/DetailedCard/index.d.ts.map +0 -1
  219. package/dist/atoms/composed/EmptyState/EmptyState.d.ts +0 -18
  220. package/dist/atoms/composed/EmptyState/EmptyState.d.ts.map +0 -1
  221. package/dist/atoms/composed/EmptyState/index.d.ts +0 -2
  222. package/dist/atoms/composed/EmptyState/index.d.ts.map +0 -1
  223. package/dist/atoms/composed/FileUpload/FileUpload.d.ts +0 -46
  224. package/dist/atoms/composed/FileUpload/FileUpload.d.ts.map +0 -1
  225. package/dist/atoms/composed/FileUpload/index.d.ts.map +0 -1
  226. package/dist/atoms/composed/FormField/FormField.d.ts +0 -23
  227. package/dist/atoms/composed/FormField/FormField.d.ts.map +0 -1
  228. package/dist/atoms/composed/FormField/index.d.ts +0 -2
  229. package/dist/atoms/composed/FormField/index.d.ts.map +0 -1
  230. package/dist/atoms/composed/GlobalSearch/GlobalSearch.d.ts +0 -8
  231. package/dist/atoms/composed/GlobalSearch/GlobalSearch.d.ts.map +0 -1
  232. package/dist/atoms/composed/GlobalSearch/index.d.ts +0 -2
  233. package/dist/atoms/composed/GlobalSearch/index.d.ts.map +0 -1
  234. package/dist/atoms/composed/IconBadge/IconBadge.d.ts +0 -16
  235. package/dist/atoms/composed/IconBadge/IconBadge.d.ts.map +0 -1
  236. package/dist/atoms/composed/IconBadge/index.d.ts +0 -3
  237. package/dist/atoms/composed/IconBadge/index.d.ts.map +0 -1
  238. package/dist/atoms/composed/Modal/Modal.d.ts +0 -18
  239. package/dist/atoms/composed/Modal/Modal.d.ts.map +0 -1
  240. package/dist/atoms/composed/Modal/index.d.ts +0 -3
  241. package/dist/atoms/composed/Modal/index.d.ts.map +0 -1
  242. package/dist/atoms/composed/PaletteSwitcher.d.ts +0 -7
  243. package/dist/atoms/composed/PaletteSwitcher.d.ts.map +0 -1
  244. package/dist/atoms/composed/ProgressBar/ProgressBar.d.ts +0 -25
  245. package/dist/atoms/composed/ProgressBar/ProgressBar.d.ts.map +0 -1
  246. package/dist/atoms/composed/ProgressBar/index.d.ts.map +0 -1
  247. package/dist/atoms/composed/StatCard/StatCard.d.ts +0 -21
  248. package/dist/atoms/composed/StatCard/StatCard.d.ts.map +0 -1
  249. package/dist/atoms/composed/StatCard/index.d.ts +0 -2
  250. package/dist/atoms/composed/StatCard/index.d.ts.map +0 -1
  251. package/dist/atoms/composed/StyleGuide.d.ts +0 -3
  252. package/dist/atoms/composed/StyleGuide.d.ts.map +0 -1
  253. package/dist/atoms/composed/Toast/Toast.d.ts +0 -40
  254. package/dist/atoms/composed/Toast/Toast.d.ts.map +0 -1
  255. package/dist/atoms/composed/Toast/index.d.ts.map +0 -1
  256. package/dist/atoms/composed/Tooltip/Tooltip.d.ts +0 -16
  257. package/dist/atoms/composed/Tooltip/Tooltip.d.ts.map +0 -1
  258. package/dist/atoms/composed/Tooltip/index.d.ts +0 -2
  259. package/dist/atoms/composed/Tooltip/index.d.ts.map +0 -1
  260. package/dist/atoms/composed/UserAvatar/UserAvatar.d.ts +0 -8
  261. package/dist/atoms/composed/UserAvatar/UserAvatar.d.ts.map +0 -1
  262. package/dist/atoms/composed/UserAvatar/index.d.ts +0 -2
  263. package/dist/atoms/composed/UserAvatar/index.d.ts.map +0 -1
  264. package/dist/atoms/composed/UserMenu/UserMenu.d.ts +0 -8
  265. package/dist/atoms/composed/UserMenu/UserMenu.d.ts.map +0 -1
  266. package/dist/atoms/composed/UserMenu/index.d.ts +0 -2
  267. package/dist/atoms/composed/UserMenu/index.d.ts.map +0 -1
  268. package/dist/atoms/composed/index.d.ts.map +0 -1
  269. package/dist/atoms/hooks/useApi.d.ts +0 -25
  270. package/dist/atoms/hooks/useApi.d.ts.map +0 -1
  271. package/dist/atoms/hooks/useHealth.d.ts +0 -19
  272. package/dist/atoms/hooks/useHealth.d.ts.map +0 -1
  273. package/dist/atoms/index.d.ts.map +0 -1
  274. package/dist/atoms/services/api/client.d.ts +0 -20
  275. package/dist/atoms/services/api/client.d.ts.map +0 -1
  276. package/dist/atoms/services/auth-service.d.ts +0 -24
  277. package/dist/atoms/services/auth-service.d.ts.map +0 -1
  278. package/dist/atoms/services/health.d.ts +0 -7
  279. package/dist/atoms/services/health.d.ts.map +0 -1
  280. package/dist/atoms/services/index.d.ts.map +0 -1
  281. package/dist/atoms/shared/config/constants.d.ts +0 -15
  282. package/dist/atoms/shared/config/constants.d.ts.map +0 -1
  283. package/dist/atoms/shared/config/dashboard-sizes.d.ts +0 -83
  284. package/dist/atoms/shared/config/dashboard-sizes.d.ts.map +0 -1
  285. package/dist/atoms/shared/config/environment.d.ts +0 -10
  286. package/dist/atoms/shared/config/environment.d.ts.map +0 -1
  287. package/dist/atoms/shared/index.d.ts +0 -4
  288. package/dist/atoms/shared/index.d.ts.map +0 -1
  289. package/dist/atoms/types/auth.d.ts +0 -56
  290. package/dist/atoms/types/auth.d.ts.map +0 -1
  291. package/dist/atoms/types/generated.d.ts.map +0 -1
  292. package/dist/atoms/types/index.d.ts.map +0 -1
  293. package/dist/atoms/types/loading.d.ts.map +0 -1
  294. package/dist/atoms/ui/Badge.d.ts +0 -10
  295. package/dist/atoms/ui/Badge.d.ts.map +0 -1
  296. package/dist/atoms/ui/ErrorBoundary.d.ts +0 -18
  297. package/dist/atoms/ui/ErrorBoundary.d.ts.map +0 -1
  298. package/dist/atoms/ui/Select.d.ts +0 -28
  299. package/dist/atoms/ui/Select.d.ts.map +0 -1
  300. package/dist/atoms/ui/Switch.d.ts +0 -9
  301. package/dist/atoms/ui/Switch.d.ts.map +0 -1
  302. package/dist/atoms/ui/Tabs.d.ts +0 -30
  303. package/dist/atoms/ui/Tabs.d.ts.map +0 -1
  304. package/dist/atoms/ui/avatar.d.ts +0 -7
  305. package/dist/atoms/ui/avatar.d.ts.map +0 -1
  306. package/dist/atoms/ui/button.d.ts +0 -14
  307. package/dist/atoms/ui/button.d.ts.map +0 -1
  308. package/dist/atoms/ui/card.d.ts +0 -12
  309. package/dist/atoms/ui/card.d.ts.map +0 -1
  310. package/dist/atoms/ui/dropdown-menu.d.ts +0 -28
  311. package/dist/atoms/ui/dropdown-menu.d.ts.map +0 -1
  312. package/dist/atoms/ui/index.d.ts.map +0 -1
  313. package/dist/atoms/ui/input.d.ts +0 -5
  314. package/dist/atoms/ui/input.d.ts.map +0 -1
  315. package/dist/atoms/ui/label.d.ts +0 -6
  316. package/dist/atoms/ui/label.d.ts.map +0 -1
  317. package/dist/atoms/ui/skeleton.d.ts +0 -3
  318. package/dist/atoms/ui/skeleton.d.ts.map +0 -1
  319. package/dist/atoms/ui/spinner.d.ts +0 -14
  320. package/dist/atoms/ui/spinner.d.ts.map +0 -1
  321. package/dist/atoms/ui/table.d.ts +0 -11
  322. package/dist/atoms/ui/table.d.ts.map +0 -1
  323. package/dist/atoms/utils/animations.d.ts +0 -65
  324. package/dist/atoms/utils/animations.d.ts.map +0 -1
  325. package/dist/atoms/utils/tooltip-helpers.d.ts +0 -71
  326. package/dist/atoms/utils/tooltip-helpers.d.ts.map +0 -1
  327. package/dist/atoms/utils/utils.d.ts +0 -4
  328. package/dist/atoms/utils/utils.d.ts.map +0 -1
  329. package/dist/features/auth/components/LoginForm.d.ts +0 -2
  330. package/dist/features/auth/components/LoginForm.d.ts.map +0 -1
  331. package/dist/features/auth/components/LogoutButton.d.ts +0 -2
  332. package/dist/features/auth/components/LogoutButton.d.ts.map +0 -1
  333. package/dist/features/auth/components/ProtectedRoute.d.ts +0 -10
  334. package/dist/features/auth/components/ProtectedRoute.d.ts.map +0 -1
  335. package/dist/features/auth/components/index.d.ts.map +0 -1
  336. package/dist/features/auth/hooks/index.d.ts +0 -3
  337. package/dist/features/auth/hooks/index.d.ts.map +0 -1
  338. package/dist/features/auth/hooks/useAuth.d.ts +0 -10
  339. package/dist/features/auth/hooks/useAuth.d.ts.map +0 -1
  340. package/dist/features/auth/hooks/usePermissions.d.ts +0 -13
  341. package/dist/features/auth/hooks/usePermissions.d.ts.map +0 -1
  342. package/dist/features/auth/index.d.ts +0 -3
  343. package/dist/features/auth/index.d.ts.map +0 -1
  344. package/dist/features/index.d.ts +0 -2
  345. package/dist/features/index.d.ts.map +0 -1
  346. package/dist/index.d.ts.map +0 -1
  347. package/dist/molecules/forms/FormGroup.d.ts +0 -17
  348. package/dist/molecules/forms/FormGroup.d.ts.map +0 -1
  349. package/dist/molecules/forms/SearchInput.d.ts +0 -36
  350. package/dist/molecules/forms/SearchInput.d.ts.map +0 -1
  351. package/dist/molecules/forms/index.d.ts +0 -3
  352. package/dist/molecules/forms/index.d.ts.map +0 -1
  353. package/dist/molecules/index.d.ts +0 -4
  354. package/dist/molecules/index.d.ts.map +0 -1
  355. package/dist/molecules/layout/AppHeader/AppHeader.d.ts +0 -7
  356. package/dist/molecules/layout/AppHeader/AppHeader.d.ts.map +0 -1
  357. package/dist/molecules/layout/AppHeader/index.d.ts +0 -2
  358. package/dist/molecules/layout/AppHeader/index.d.ts.map +0 -1
  359. package/dist/molecules/layout/AppLayout.d.ts +0 -2
  360. package/dist/molecules/layout/AppLayout.d.ts.map +0 -1
  361. package/dist/molecules/layout/PageTemplate.d.ts +0 -19
  362. package/dist/molecules/layout/PageTemplate.d.ts.map +0 -1
  363. package/dist/molecules/layout/SectionHeader/SectionHeader.d.ts +0 -24
  364. package/dist/molecules/layout/SectionHeader/SectionHeader.d.ts.map +0 -1
  365. package/dist/molecules/layout/SectionHeader/index.d.ts.map +0 -1
  366. package/dist/molecules/layout/ShowcaseSection.d.ts +0 -22
  367. package/dist/molecules/layout/ShowcaseSection.d.ts.map +0 -1
  368. package/dist/molecules/layout/Sidebar.d.ts +0 -6
  369. package/dist/molecules/layout/Sidebar.d.ts.map +0 -1
  370. package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts +0 -13
  371. package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts.map +0 -1
  372. package/dist/molecules/layout/SidebarButton/index.d.ts +0 -2
  373. package/dist/molecules/layout/SidebarButton/index.d.ts.map +0 -1
  374. package/dist/molecules/layout/SidebarContext.d.ts +0 -12
  375. package/dist/molecules/layout/SidebarContext.d.ts.map +0 -1
  376. package/dist/molecules/layout/index.d.ts.map +0 -1
  377. package/dist/molecules/navigation/NavMenu.d.ts +0 -20
  378. package/dist/molecules/navigation/NavMenu.d.ts.map +0 -1
  379. package/dist/molecules/navigation/Pagination.d.ts +0 -14
  380. package/dist/molecules/navigation/Pagination.d.ts.map +0 -1
  381. package/dist/molecules/navigation/index.d.ts +0 -3
  382. package/dist/molecules/navigation/index.d.ts.map +0 -1
  383. package/dist/organisms/index.d.ts +0 -2
  384. package/dist/organisms/index.d.ts.map +0 -1
  385. package/dist/organisms/showcase/ComponentShowcasePage.d.ts +0 -3
  386. package/dist/organisms/showcase/ComponentShowcasePage.d.ts.map +0 -1
  387. package/dist/templates/AuthTemplate.d.ts +0 -68
  388. package/dist/templates/AuthTemplate.d.ts.map +0 -1
  389. package/dist/templates/ComponentShowcaseTemplate.d.ts +0 -53
  390. package/dist/templates/ComponentShowcaseTemplate.d.ts.map +0 -1
  391. package/dist/templates/DashboardTemplate.d.ts +0 -62
  392. package/dist/templates/DashboardTemplate.d.ts.map +0 -1
  393. package/dist/templates/DataTemplate.d.ts +0 -78
  394. package/dist/templates/DataTemplate.d.ts.map +0 -1
  395. package/dist/templates/admin/AdminCRUDTemplate.d.ts +0 -105
  396. package/dist/templates/admin/AdminCRUDTemplate.d.ts.map +0 -1
  397. package/dist/templates/admin/AdminDashboardTemplate.d.ts +0 -89
  398. package/dist/templates/admin/AdminDashboardTemplate.d.ts.map +0 -1
  399. package/dist/templates/admin/AdminDetailTemplate.d.ts +0 -132
  400. package/dist/templates/admin/AdminDetailTemplate.d.ts.map +0 -1
  401. package/dist/templates/admin/index.d.ts +0 -4
  402. package/dist/templates/admin/index.d.ts.map +0 -1
  403. package/dist/templates/factory.d.ts +0 -28
  404. package/dist/templates/factory.d.ts.map +0 -1
  405. package/dist/templates/index.d.ts +0 -7
  406. package/dist/templates/index.d.ts.map +0 -1
@@ -0,0 +1,236 @@
1
+ import type { MetricConfig, MetricValue, EntityData, FormatConfig, TrendDataPoint } from '../types';
2
+
3
+ export class MetricCalculationEngine {
4
+ static calculateMetric(
5
+ config: MetricConfig,
6
+ data: EntityData[],
7
+ previousData?: EntityData[]
8
+ ): MetricValue {
9
+ const currentValue = this.aggregateValue(config, data);
10
+ const previousValue = previousData ? this.aggregateValue(config, previousData) : undefined;
11
+
12
+ const trend = this.calculateTrend(currentValue, previousValue);
13
+ const formattedValue = this.formatValue(currentValue, config.format, config.type);
14
+
15
+ const target = typeof config.target === 'function'
16
+ ? config.target(data)
17
+ : config.target;
18
+
19
+ return {
20
+ current: currentValue,
21
+ previous: previousValue,
22
+ trend,
23
+ target,
24
+ formattedValue
25
+ };
26
+ }
27
+
28
+ private static aggregateValue(config: MetricConfig, data: EntityData[]): number {
29
+ if (!data.length) return 0;
30
+
31
+ const values = data
32
+ .map(item => {
33
+ const value = this.extractValue(item, config.key);
34
+ return typeof value === 'number' ? value : 0;
35
+ })
36
+ .filter(value => !isNaN(value));
37
+
38
+ if (!values.length) return 0;
39
+
40
+ switch (config.aggregation || 'sum') {
41
+ case 'sum':
42
+ return values.reduce((sum, value) => sum + value, 0);
43
+ case 'avg':
44
+ return values.reduce((sum, value) => sum + value, 0) / values.length;
45
+ case 'count':
46
+ return values.length;
47
+ case 'min':
48
+ return Math.min(...values);
49
+ case 'max':
50
+ return Math.max(...values);
51
+ default:
52
+ return values.reduce((sum, value) => sum + value, 0);
53
+ }
54
+ }
55
+
56
+ private static extractValue(item: EntityData, key: string): unknown {
57
+ return key.split('.').reduce((obj: any, k: string) => obj?.[k], item);
58
+ }
59
+
60
+ private static calculateTrend(current: number, previous?: number): 'up' | 'down' | 'neutral' {
61
+ if (previous === undefined || previous === 0) return 'neutral';
62
+
63
+ const change = ((current - previous) / Math.abs(previous)) * 100;
64
+
65
+ if (change > 1) return 'up';
66
+ if (change < -1) return 'down';
67
+ return 'neutral';
68
+ }
69
+
70
+ private static formatValue(value: number, format?: FormatConfig, type?: string): string {
71
+ let formatted = value;
72
+
73
+ if (format?.decimals !== undefined) {
74
+ formatted = Number(value.toFixed(format.decimals));
75
+ }
76
+
77
+ let result = formatted.toString();
78
+
79
+ if (format?.thousands !== false && Math.abs(formatted) >= 1000) {
80
+ result = formatted.toLocaleString();
81
+ }
82
+
83
+ switch (type) {
84
+ case 'currency':
85
+ result = new Intl.NumberFormat('en-US', {
86
+ style: 'currency',
87
+ currency: 'USD',
88
+ minimumFractionDigits: format?.decimals ?? 2,
89
+ maximumFractionDigits: format?.decimals ?? 2
90
+ }).format(formatted);
91
+ break;
92
+ case 'percentage':
93
+ result = `${formatted.toFixed(format?.decimals ?? 1)}%`;
94
+ break;
95
+ case 'duration':
96
+ result = this.formatDuration(formatted);
97
+ break;
98
+ case 'ratio':
99
+ result = `${formatted.toFixed(format?.decimals ?? 2)}:1`;
100
+ break;
101
+ default:
102
+ if (format?.prefix) result = format.prefix + result;
103
+ if (format?.suffix) result = result + format.suffix;
104
+ }
105
+
106
+ return result;
107
+ }
108
+
109
+ private static formatDuration(minutes: number): string {
110
+ const hours = Math.floor(minutes / 60);
111
+ const mins = Math.floor(minutes % 60);
112
+
113
+ if (hours > 0) {
114
+ return `${hours}h ${mins}m`;
115
+ }
116
+ return `${mins}m`;
117
+ }
118
+
119
+ static calculateTrendData(
120
+ config: MetricConfig,
121
+ data: EntityData[],
122
+ dateField: string = 'date',
123
+ periods: number = 12
124
+ ): TrendDataPoint[] {
125
+ const groupedData = this.groupByPeriod(data, dateField);
126
+ const sortedDates = Object.keys(groupedData).sort();
127
+
128
+ return sortedDates.slice(-periods).map(date => ({
129
+ date,
130
+ value: this.aggregateValue(config, groupedData[date]),
131
+ label: this.formatDateLabel(date)
132
+ }));
133
+ }
134
+
135
+ private static groupByPeriod(data: EntityData[], dateField: string): Record<string, EntityData[]> {
136
+ return data.reduce((groups, item) => {
137
+ const date = this.extractValue(item, dateField);
138
+ if (!date) return groups;
139
+
140
+ const period = new Date(date as string | number | Date).toISOString().split('T')[0];
141
+
142
+ if (!groups[period]) groups[period] = [];
143
+ groups[period].push(item);
144
+
145
+ return groups;
146
+ }, {} as Record<string, EntityData[]>);
147
+ }
148
+
149
+ private static formatDateLabel(dateString: string): string {
150
+ const date = new Date(dateString);
151
+ return date.toLocaleDateString('en-US', {
152
+ month: 'short',
153
+ day: 'numeric'
154
+ });
155
+ }
156
+
157
+ static calculateCategoryBreakdown(
158
+ data: EntityData[],
159
+ categoryField: string,
160
+ valueField: string,
161
+ maxCategories: number = 8
162
+ ) {
163
+ const groups = data.reduce((acc, item) => {
164
+ const category = String(this.extractValue(item, categoryField) || 'Unknown');
165
+ const value = this.extractValue(item, valueField) || 0;
166
+
167
+ if (!acc[category]) acc[category] = 0;
168
+ acc[category] += typeof value === 'number' ? value : 0;
169
+
170
+ return acc;
171
+ }, {} as Record<string, number>);
172
+
173
+ const total = Object.values(groups).reduce((sum, value) => sum + value, 0);
174
+
175
+ let categories = Object.entries(groups)
176
+ .map(([category, value]) => ({
177
+ category,
178
+ value,
179
+ percentage: total > 0 ? (value / total) * 100 : 0
180
+ }))
181
+ .sort((a, b) => b.value - a.value);
182
+
183
+ if (categories.length > maxCategories) {
184
+ const topCategories = categories.slice(0, maxCategories - 1);
185
+ const otherValue = categories.slice(maxCategories - 1)
186
+ .reduce((sum, cat) => sum + cat.value, 0);
187
+
188
+ topCategories.push({
189
+ category: 'Other',
190
+ value: otherValue,
191
+ percentage: total > 0 ? (otherValue / total) * 100 : 0
192
+ });
193
+
194
+ categories = topCategories;
195
+ }
196
+
197
+ return categories;
198
+ }
199
+
200
+ static detectInsights(
201
+ metrics: Record<string, MetricValue>,
202
+ thresholds: Record<string, { warning: number; critical: number }> = {}
203
+ ) {
204
+ const insights = [];
205
+
206
+ for (const [key, metric] of Object.entries(metrics)) {
207
+ const threshold = thresholds[key];
208
+
209
+ if (metric.target && metric.current < metric.target * 0.8) {
210
+ insights.push({
211
+ type: 'negative' as const,
212
+ message: `${key} is significantly below target`,
213
+ value: metric.current
214
+ });
215
+ }
216
+
217
+ if (metric.trend === 'up' && metric.previous && metric.current > metric.previous * 1.2) {
218
+ insights.push({
219
+ type: 'positive' as const,
220
+ message: `${key} showing strong growth`,
221
+ value: metric.current
222
+ });
223
+ }
224
+
225
+ if (threshold && metric.current >= threshold.critical) {
226
+ insights.push({
227
+ type: 'negative' as const,
228
+ message: `${key} has reached critical threshold`,
229
+ value: metric.current
230
+ });
231
+ }
232
+ }
233
+
234
+ return insights.slice(0, 5);
235
+ }
236
+ }
@@ -0,0 +1,140 @@
1
+ import { useRef, useState, useEffect } from 'react';
2
+
3
+ /**
4
+ * Hook to detect if an element's text is truncated/overflowing
5
+ * Useful for conditionally showing tooltips only when needed
6
+ */
7
+ export const useTextOverflow = () => {
8
+ const ref = useRef<HTMLElement>(null);
9
+ const [isOverflowing, setIsOverflowing] = useState(false);
10
+
11
+ useEffect(() => {
12
+ const checkOverflow = () => {
13
+ const element = ref.current;
14
+ if (!element) return;
15
+
16
+ // Check if text is truncated
17
+ const isOverflow = element.scrollWidth > element.clientWidth ||
18
+ element.scrollHeight > element.clientHeight;
19
+ setIsOverflowing(isOverflow);
20
+ };
21
+
22
+ checkOverflow();
23
+
24
+ // Re-check on resize
25
+ window.addEventListener('resize', checkOverflow);
26
+
27
+ // Use ResizeObserver if available for more accurate detection
28
+ if (typeof ResizeObserver !== 'undefined') {
29
+ const resizeObserver = new ResizeObserver(checkOverflow);
30
+ if (ref.current) {
31
+ resizeObserver.observe(ref.current);
32
+ }
33
+ return () => {
34
+ resizeObserver.disconnect();
35
+ window.removeEventListener('resize', checkOverflow);
36
+ };
37
+ }
38
+
39
+ return () => window.removeEventListener('resize', checkOverflow);
40
+ }, []);
41
+
42
+ return { ref, isOverflowing };
43
+ };
44
+
45
+ /**
46
+ * Formats large numbers with abbreviations
47
+ * Useful for StatCard values with tooltips showing full numbers
48
+ */
49
+ export const formatNumberWithTooltip = (value: number): { display: string; tooltip: string } => {
50
+ const formatter = new Intl.NumberFormat('en-US');
51
+ const fullNumber = formatter.format(value);
52
+
53
+ if (value >= 1_000_000_000) {
54
+ return {
55
+ display: `${(value / 1_000_000_000).toFixed(1)}B`,
56
+ tooltip: fullNumber
57
+ };
58
+ } else if (value >= 1_000_000) {
59
+ return {
60
+ display: `${(value / 1_000_000).toFixed(1)}M`,
61
+ tooltip: fullNumber
62
+ };
63
+ } else if (value >= 10_000) {
64
+ return {
65
+ display: `${(value / 1_000).toFixed(1)}K`,
66
+ tooltip: fullNumber
67
+ };
68
+ }
69
+
70
+ return {
71
+ display: fullNumber,
72
+ tooltip: '' // No tooltip needed for small numbers
73
+ };
74
+ };
75
+
76
+ /**
77
+ * Standard tooltip content for common UI patterns
78
+ */
79
+ export const tooltipContent = {
80
+ // Icon button tooltips
81
+ refresh: 'Refresh data',
82
+ download: 'Download',
83
+ upload: 'Upload file',
84
+ edit: 'Edit',
85
+ delete: 'Delete',
86
+ view: 'View details',
87
+ filter: 'Filter',
88
+ search: 'Search',
89
+ settings: 'Settings',
90
+ help: 'Help',
91
+ export: 'Export data',
92
+ import: 'Import data',
93
+ add: 'Add new',
94
+ create: 'Create new',
95
+ back: 'Go back',
96
+ forward: 'Go forward',
97
+ menu: 'Open menu',
98
+ more: 'More options',
99
+ copy: 'Copy',
100
+ paste: 'Paste',
101
+ share: 'Share',
102
+ print: 'Print',
103
+
104
+ // Status tooltips
105
+ success: 'Operation completed successfully',
106
+ warning: 'Requires attention',
107
+ error: 'Error occurred',
108
+ info: 'Information',
109
+ pending: 'Pending',
110
+
111
+ // Common actions
112
+ save: 'Save changes',
113
+ cancel: 'Cancel',
114
+ close: 'Close',
115
+ expand: 'Expand',
116
+ collapse: 'Collapse',
117
+ minimize: 'Minimize',
118
+ maximize: 'Maximize',
119
+
120
+ // Navigation
121
+ previous: 'Previous',
122
+ next: 'Next',
123
+ first: 'Go to first',
124
+ last: 'Go to last',
125
+ home: 'Home',
126
+
127
+ // Data operations
128
+ sort: 'Sort',
129
+ sortAsc: 'Sort ascending',
130
+ sortDesc: 'Sort descending',
131
+ clearSort: 'Clear sorting',
132
+ clearFilters: 'Clear all filters',
133
+ clearSearch: 'Clear search',
134
+
135
+ // Authentication
136
+ login: 'Sign in',
137
+ logout: 'Sign out',
138
+ profile: 'Profile',
139
+ account: 'Account settings',
140
+ };
@@ -0,0 +1,10 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
7
+
8
+ // Re-export tooltip helpers
9
+ export * from './tooltip-helpers';
10
+ export * from './metric-engine';
@@ -0,0 +1,168 @@
1
+ import { useState } from 'react';
2
+ import { useAuth } from '../hooks/useAuth';
3
+ import { Button } from '../../../atoms/ui/button';
4
+ import { Input } from '../../../atoms/ui/input';
5
+ import { Label } from '../../../atoms/ui/label';
6
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../../../atoms/ui/card';
7
+ import { cn } from '../../../atoms/utils/utils';
8
+ import { Database, Shield, TrendingUp, Mail, Lock, Sparkles } from 'lucide-react';
9
+
10
+ export function LoginForm() {
11
+ const [email, setEmail] = useState('');
12
+ const [password, setPassword] = useState('');
13
+ const [error, setError] = useState('');
14
+ const { login, isLoading } = useAuth();
15
+
16
+ const handleSubmit = async (e: React.FormEvent) => {
17
+ e.preventDefault();
18
+ setError('');
19
+
20
+ try {
21
+ await login({ email, password });
22
+ } catch (err) {
23
+ setError(err instanceof Error ? err.message : 'Login failed');
24
+ }
25
+ };
26
+
27
+ return (
28
+ <div className="min-h-screen relative overflow-hidden bg-gradient-to-br from-muted/20 via-background to-muted/40">
29
+ {/* Background Pattern */}
30
+ <div className="absolute inset-0 bg-muted/5 opacity-5" />
31
+
32
+ {/* Floating Elements */}
33
+ <div className="absolute top-20 left-20 w-32 h-32 bg-primary/10 rounded-full blur-xl animate-pulse" />
34
+ <div className="absolute top-40 right-32 w-24 h-24 bg-secondary/10 rounded-full blur-lg animate-pulse delay-1000" />
35
+ <div className="absolute bottom-40 left-32 w-40 h-40 bg-accent/10 rounded-full blur-2xl animate-pulse delay-500" />
36
+
37
+ <div className="min-h-screen flex items-center justify-center p-4 relative z-10">
38
+ <div className="w-full max-w-md space-y-8">
39
+ {/* Header */}
40
+ <div className="text-center space-y-6 animate-slide-up">
41
+ <div className="flex justify-center">
42
+ <div className="relative">
43
+ <div className="w-16 h-16 bg-gradient-to-br from-primary to-secondary rounded flex items-center justify-center shadow">
44
+ <Database className="w-8 h-8 text-primary-foreground" />
45
+ </div>
46
+ <div className="absolute -top-1 -right-1 w-6 h-6 bg-gradient-to-br from-accent to-accent-foreground rounded-full flex items-center justify-center">
47
+ <Sparkles className="w-3 h-3 text-accent-foreground" />
48
+ </div>
49
+ </div>
50
+ </div>
51
+
52
+ <div className="space-y-2">
53
+ <h1 className="text-3xl font-bold bg-gradient-to-r from-foreground via-primary to-secondary bg-clip-text text-transparent">
54
+ Data Trust Navigator
55
+ </h1>
56
+ <p className="text-muted-foreground text-lg">
57
+ Explore, analyze, and trust your data ecosystem
58
+ </p>
59
+ </div>
60
+ </div>
61
+
62
+ {/* Login Card */}
63
+ <Card className="card-container animate-slide-up border-0 shadow bg-background/80 backdrop-blur-sm">
64
+ <CardHeader className="text-center pb-4">
65
+ <CardTitle className="text-xl font-semibold">Welcome Back</CardTitle>
66
+ <CardDescription>
67
+ Sign in to access your analytics dashboard
68
+ </CardDescription>
69
+ </CardHeader>
70
+
71
+ <CardContent className="space-y-6">
72
+ <form onSubmit={handleSubmit} className="space-y-5">
73
+ <div className="space-y-2">
74
+ <Label htmlFor="email" className="text-data-label">Email Address</Label>
75
+ <div className="relative">
76
+ <Mail className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground w-4 h-4" />
77
+ <Input
78
+ id="email"
79
+ type="email"
80
+ value={email}
81
+ onChange={(e) => setEmail(e.target.value)}
82
+ required
83
+ placeholder="Enter your email"
84
+ className="pl-10 h-11 transition-all duration-200 focus:ring-2 focus:ring-ring focus:border-ring"
85
+ />
86
+ </div>
87
+ </div>
88
+
89
+ <div className="space-y-2">
90
+ <Label htmlFor="password" className="text-data-label">Password</Label>
91
+ <div className="relative">
92
+ <Lock className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground w-4 h-4" />
93
+ <Input
94
+ id="password"
95
+ type="password"
96
+ value={password}
97
+ onChange={(e) => setPassword(e.target.value)}
98
+ required
99
+ placeholder="Enter your password"
100
+ className="pl-10 h-11 transition-all duration-200 focus:ring-2 focus:ring-ring focus:border-ring"
101
+ />
102
+ </div>
103
+ </div>
104
+
105
+ {error && (
106
+ <div className="bg-destructive/10 border border-destructive/20 text-destructive text-sm p-3 rounded animate-shake">
107
+ {error}
108
+ </div>
109
+ )}
110
+
111
+ <Button
112
+ type="submit"
113
+ className={cn(
114
+ "w-full h-11 bg-gradient-to-r from-primary to-secondary hover:from-primary/90 hover:to-secondary/90 text-primary-foreground font-medium transition-all duration-200 hover:shadow-lg hover:scale-[1.02] active:scale-[0.98]"
115
+ )}
116
+ disabled={isLoading}
117
+ >
118
+ {isLoading ? (
119
+ <div className="flex items-center gap-2">
120
+ <div className="w-4 h-4 border-2 border-primary-foreground/30 border-t-primary-foreground rounded-full animate-spin" />
121
+ Signing in...
122
+ </div>
123
+ ) : (
124
+ <div className="flex items-center gap-2">
125
+ <Shield className="w-4 h-4" />
126
+ Sign In
127
+ </div>
128
+ )}
129
+ </Button>
130
+ </form>
131
+
132
+ {/* Demo Notice */}
133
+ <div className="bg-muted/50 border border-border rounded p-4">
134
+ <div className="flex items-start gap-3">
135
+ <div className="w-6 h-6 bg-primary rounded-full flex items-center justify-center flex-shrink-0 mt-0.5">
136
+ <TrendingUp className="w-3 h-3 text-primary-foreground" />
137
+ </div>
138
+ <div className="space-y-1">
139
+ <p className="text-sm font-medium text-foreground">Demo Environment</p>
140
+ <p className="text-xs text-muted-foreground">
141
+ Use any email and password to explore the analytics platform
142
+ </p>
143
+ </div>
144
+ </div>
145
+ </div>
146
+ </CardContent>
147
+ </Card>
148
+
149
+ {/* Features */}
150
+ <div className="grid grid-cols-3 gap-4 animate-slide-up">
151
+ {[
152
+ { icon: Database, label: 'Data Models', bgClass: 'bg-primary/10', textClass: 'text-primary' },
153
+ { icon: Shield, label: 'Quality Tests', bgClass: 'bg-secondary/10', textClass: 'text-secondary-foreground' },
154
+ { icon: TrendingUp, label: 'Analytics', bgClass: 'bg-accent/10', textClass: 'text-accent-foreground' }
155
+ ].map((feature) => (
156
+ <div key={feature.label} className="text-center space-y-2">
157
+ <div className={cn('w-10 h-10 rounded-lg flex items-center justify-center mx-auto', feature.bgClass)}>
158
+ <feature.icon className={cn('w-5 h-5', feature.textClass)} />
159
+ </div>
160
+ <p className="text-xs text-muted-foreground font-medium">{feature.label}</p>
161
+ </div>
162
+ ))}
163
+ </div>
164
+ </div>
165
+ </div>
166
+ </div>
167
+ );
168
+ }
@@ -0,0 +1,19 @@
1
+ import { useAuth } from '../hooks/useAuth';
2
+ import { Button } from '../../../atoms/ui/button';
3
+
4
+ export function LogoutButton() {
5
+ const { logout, user } = useAuth();
6
+
7
+ return (
8
+ <div className="flex items-center gap-2">
9
+ <span className="text-sm text-muted-foreground">Welcome, {(user as any)?.name || user?.email}</span>
10
+ <Button
11
+ variant="outline"
12
+ size="sm"
13
+ onClick={logout}
14
+ >
15
+ Logout
16
+ </Button>
17
+ </div>
18
+ );
19
+ }
@@ -0,0 +1,60 @@
1
+ import type { ReactNode } from 'react';
2
+ import { useAuth } from '../hooks/useAuth';
3
+ import { LoginForm } from './LoginForm';
4
+
5
+ interface ProtectedRouteProps {
6
+ children: ReactNode;
7
+ requirePermission?: string;
8
+ requireRole?: string;
9
+ fallback?: ReactNode;
10
+ }
11
+
12
+ export function ProtectedRoute({
13
+ children,
14
+ requirePermission,
15
+ requireRole,
16
+ fallback
17
+ }: ProtectedRouteProps) {
18
+ const { isAuthenticated, isLoading, hasPermission, hasRole } = useAuth();
19
+
20
+ if (isLoading) {
21
+ return (
22
+ <div className="min-h-screen flex items-center justify-center">
23
+ <div className="text-center">
24
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto"></div>
25
+ <p className="mt-2 text-muted-foreground">Loading...</p>
26
+ </div>
27
+ </div>
28
+ );
29
+ }
30
+
31
+ if (!isAuthenticated) {
32
+ return <LoginForm />;
33
+ }
34
+
35
+ // Check permission if required
36
+ if (requirePermission && !hasPermission(requirePermission)) {
37
+ return fallback || (
38
+ <div className="min-h-screen flex items-center justify-center">
39
+ <div className="text-center">
40
+ <h2 className="text-xl font-semibold text-destructive mb-2">Access Denied</h2>
41
+ <p className="text-muted-foreground">You don't have permission to access this resource.</p>
42
+ </div>
43
+ </div>
44
+ );
45
+ }
46
+
47
+ // Check role if required
48
+ if (requireRole && !hasRole(requireRole)) {
49
+ return fallback || (
50
+ <div className="min-h-screen flex items-center justify-center">
51
+ <div className="text-center">
52
+ <h2 className="text-xl font-semibold text-destructive mb-2">Access Denied</h2>
53
+ <p className="text-muted-foreground">Your role doesn't have access to this resource.</p>
54
+ </div>
55
+ </div>
56
+ );
57
+ }
58
+
59
+ return <>{children}</>;
60
+ }
@@ -1,4 +1,4 @@
1
1
  export { LoginForm } from './LoginForm';
2
2
  export { ProtectedRoute } from './ProtectedRoute';
3
3
  export { LogoutButton } from './LogoutButton';
4
- //# sourceMappingURL=index.d.ts.map
4
+ // AuthProvider is exported from ../hooks/useAuth
@@ -0,0 +1,2 @@
1
+ export { useAuth, AuthProvider } from './useAuth';
2
+ export { usePermissions } from './usePermissions';