@goplusvn/core 0.1.0 → 0.1.2

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 (591) hide show
  1. package/package.json +31 -175
  2. package/src/assets/erp_wallpaper.png +0 -0
  3. package/src/assets/goeat_logo.png +0 -0
  4. package/src/audit/audit-manager.ts +139 -0
  5. package/src/audit/index.ts +11 -0
  6. package/src/audit/memory-audit-logger.ts +86 -0
  7. package/src/audit/types.ts +50 -0
  8. package/src/auth/auth-service.ts +97 -0
  9. package/src/auth/index.ts +266 -0
  10. package/src/code-generation/index.ts +69 -0
  11. package/src/configs/auth-routes.ts +17 -0
  12. package/src/configs/crud.ts +136 -0
  13. package/src/configs/data/navigations.ts +781 -0
  14. package/src/configs/data/oauth-links.ts +10 -0
  15. package/src/configs/entities/material-categories.config.ts +125 -0
  16. package/src/configs/i18n.ts +12 -0
  17. package/src/configs/index.ts +26 -0
  18. package/src/configs/status.ts +25 -0
  19. package/src/configs/themes.ts +100 -0
  20. package/src/crud/components/crud-bulk-actions.tsx +91 -0
  21. package/src/crud/components/crud-card-view.tsx +241 -0
  22. package/src/crud/components/crud-context.tsx +122 -0
  23. package/src/crud/components/crud-delete-dialog.tsx +145 -0
  24. package/src/crud/components/crud-dialog.tsx +406 -0
  25. package/src/crud/components/crud-empty-state.tsx +104 -0
  26. package/src/crud/components/crud-export-button.tsx +170 -0
  27. package/src/crud/components/crud-field-renderer.tsx +653 -0
  28. package/src/crud/components/crud-filter-chips.tsx +102 -0
  29. package/src/crud/components/crud-filters/checkbox-filter.tsx +97 -0
  30. package/src/crud/components/crud-filters/datetime-filter.tsx +83 -0
  31. package/src/crud/components/crud-filters/filter-builder.tsx +66 -0
  32. package/src/crud/components/crud-filters/index.tsx +76 -0
  33. package/src/crud/components/crud-filters/radio-filter.tsx +86 -0
  34. package/src/crud/components/crud-filters/select-filter.tsx +141 -0
  35. package/src/crud/components/crud-filters/text-filter.tsx +86 -0
  36. package/src/crud/components/crud-form.tsx +642 -0
  37. package/src/crud/components/crud-import-dialog.tsx +440 -0
  38. package/src/crud/components/crud-infinite-scroll.tsx +116 -0
  39. package/src/crud/components/crud-page.tsx +1017 -0
  40. package/src/crud/components/crud-provider.tsx +277 -0
  41. package/src/crud/components/crud-row-actions.tsx +189 -0
  42. package/src/crud/components/crud-search.tsx +82 -0
  43. package/src/crud/components/crud-sheet.tsx +336 -0
  44. package/src/crud/components/crud-table-skeleton.tsx +26 -0
  45. package/src/crud/components/crud-table-toolbar.tsx +91 -0
  46. package/src/crud/components/crud-table.tsx +352 -0
  47. package/src/crud/components/crud-virtual-table.tsx +55 -0
  48. package/src/crud/components/index.tsx +20 -0
  49. package/src/crud/crud-filters/checkbox-filter.tsx +87 -0
  50. package/src/crud/crud-filters/datetime-filter.tsx +82 -0
  51. package/src/crud/crud-filters/filter-builder.tsx +64 -0
  52. package/src/crud/crud-filters/index.tsx +78 -0
  53. package/src/crud/crud-filters/radio-filter.tsx +79 -0
  54. package/src/crud/crud-filters/select-filter.tsx +148 -0
  55. package/src/crud/crud-filters/text-filter.tsx +81 -0
  56. package/src/crud/index.ts +43 -0
  57. package/src/crud/lib/crud-service.test.ts +334 -0
  58. package/src/crud/lib/crud-service.ts +358 -0
  59. package/src/crud/lib/crud-utils.test.ts +354 -0
  60. package/src/crud/lib/crud-utils.ts +299 -0
  61. package/src/crud/lib/crud-validator.ts +247 -0
  62. package/src/crud/lib/data-loader.ts +234 -0
  63. package/src/crud/lib/field-calculator.ts +241 -0
  64. package/src/crud/lib/field-formatter.ts +240 -0
  65. package/src/crud/lib/import-export-service.test.ts +290 -0
  66. package/src/crud/lib/import-export-service.ts +352 -0
  67. package/src/crud/lib/import-server-utils.ts +109 -0
  68. package/src/crud/lib/lazy-loader.ts +241 -0
  69. package/src/crud/lib/parse-filters.ts +85 -0
  70. package/src/crud/lib/permissions.ts +52 -0
  71. package/src/crud/lib/serialize-config.ts +60 -0
  72. package/src/crud/lib/stream-loader.ts +145 -0
  73. package/src/crud/lib/translate-config.ts +335 -0
  74. package/src/crud/lib/types.ts +11 -0
  75. package/src/crud/pages/entity-crud-page.tsx +144 -0
  76. package/src/crud/server.ts +8 -0
  77. package/src/home/constants.tsx +142 -0
  78. package/src/home/feature-showcase.tsx +171 -0
  79. package/src/home/home-page.tsx +191 -0
  80. package/src/home/hooks/index.ts +1 -0
  81. package/src/home/hooks/useWidgetPreferences.ts +167 -0
  82. package/src/home/index.ts +33 -0
  83. package/src/home/quick-access-dialog.tsx +271 -0
  84. package/src/home/quick-access-menu.tsx +267 -0
  85. package/src/home/types.ts +140 -0
  86. package/src/home/welcome-card.tsx +92 -0
  87. package/src/home/widget-container.tsx +258 -0
  88. package/src/home/widgets/base-widget.tsx +200 -0
  89. package/src/home/widgets/customers-widget.tsx +74 -0
  90. package/src/home/widgets/index.ts +6 -0
  91. package/src/home/widgets/orders-widget.tsx +87 -0
  92. package/src/home/widgets/revenue-widget.tsx +71 -0
  93. package/src/home/widgets/stock-widget.tsx +109 -0
  94. package/src/hooks/index.tsx +598 -0
  95. package/src/hooks/use-tenant.test.tsx +30 -0
  96. package/src/hooks/use-tenant.ts +5 -0
  97. package/src/index.ts +17 -0
  98. package/src/infrastructure/__tests__/architecture-verification.spec.ts +103 -0
  99. package/src/infrastructure/api-service.ts +317 -0
  100. package/src/infrastructure/cache/cache-manager.ts +107 -0
  101. package/src/infrastructure/cache/cache.ts +120 -0
  102. package/src/infrastructure/cache/index.ts +8 -0
  103. package/src/infrastructure/cache/types.ts +48 -0
  104. package/src/infrastructure/cron/cron-manager.ts +239 -0
  105. package/src/infrastructure/cron/index.ts +6 -0
  106. package/src/infrastructure/cron/types.ts +41 -0
  107. package/src/infrastructure/event-bus/event-bus.ts +145 -0
  108. package/src/infrastructure/event-bus/index.ts +2 -0
  109. package/src/infrastructure/event-bus/types.ts +22 -0
  110. package/src/infrastructure/index.ts +32 -0
  111. package/src/infrastructure/lock/decorators.ts +67 -0
  112. package/src/infrastructure/lock/index.ts +2 -0
  113. package/src/infrastructure/lock/lock-manager.ts +33 -0
  114. package/src/infrastructure/logger/index.ts +2 -0
  115. package/src/infrastructure/logger/logger.ts +96 -0
  116. package/src/infrastructure/logger/types.ts +25 -0
  117. package/src/layout/index.tsx +185 -0
  118. package/src/navigation/index.ts +91 -0
  119. package/src/notification/index.ts +14 -0
  120. package/src/notification/notification-service.ts +120 -0
  121. package/src/notification/storage/in-memory.ts +56 -0
  122. package/src/notification/storage/index.ts +1 -0
  123. package/src/notification/types.ts +51 -0
  124. package/src/organization/branch-service.ts +299 -0
  125. package/src/organization/branches.config.ts +154 -0
  126. package/src/organization/index.ts +5 -0
  127. package/src/plugin/apps-registry.ts +97 -0
  128. package/src/plugin/index.ts +5 -0
  129. package/src/plugin/types.ts +41 -0
  130. package/src/providers/index.tsx +109 -0
  131. package/src/providers/tenant-provider.tsx +45 -0
  132. package/src/rbac/components/roles/role-card.tsx +158 -0
  133. package/src/rbac/components/roles/role-stats-cards.tsx +29 -0
  134. package/src/rbac/components/roles/role-toolbar.tsx +123 -0
  135. package/src/rbac/hooks/use-role-operations.ts +159 -0
  136. package/src/rbac/hooks/use-roles-data.ts +59 -0
  137. package/src/rbac/index.ts +297 -0
  138. package/src/rbac/lib/permission-helpers.ts +63 -0
  139. package/src/rbac/pages/action-list-page.tsx +25 -0
  140. package/src/rbac/pages/resource-list-page.tsx +25 -0
  141. package/src/rbac/pages/role-list-page.tsx +378 -0
  142. package/src/rbac/permission-service.ts +140 -0
  143. package/src/rbac/permissions.ts +135 -0
  144. package/src/rbac/resource-service.ts +115 -0
  145. package/src/rbac/resource-validator.ts +119 -0
  146. package/src/rbac/role-service.ts +165 -0
  147. package/src/rbac/server.ts +16 -0
  148. package/src/rbac/types.ts +38 -0
  149. package/src/schemas/action.schema.ts +66 -0
  150. package/src/schemas/branch.schema.ts +52 -0
  151. package/src/schemas/coming-soon-schema.ts +9 -0
  152. package/src/schemas/company.schema.ts +44 -0
  153. package/src/schemas/forgot-passward-schema.ts +9 -0
  154. package/src/schemas/index.ts +30 -0
  155. package/src/schemas/material-category.schema.ts +43 -0
  156. package/src/schemas/material-pricing.schema.ts +74 -0
  157. package/src/schemas/material.schema.ts +76 -0
  158. package/src/schemas/materials.ts +52 -0
  159. package/src/schemas/new-passward-schema.ts +15 -0
  160. package/src/schemas/partner-company.schema.ts +149 -0
  161. package/src/schemas/register-schema.ts +36 -0
  162. package/src/schemas/resource.schema.ts +133 -0
  163. package/src/schemas/role.schema.ts +11 -0
  164. package/src/schemas/sign-in-schema.ts +24 -0
  165. package/src/schemas/supplier-pricing.schema.ts +15 -0
  166. package/src/schemas/supplier.schema.ts +120 -0
  167. package/src/schemas/system-category-group.schema.ts +67 -0
  168. package/src/schemas/system-category.schema.ts +77 -0
  169. package/src/schemas/system-config.schema.ts +118 -0
  170. package/src/schemas/uom.schema.ts +75 -0
  171. package/src/schemas/user-supplier.schema.ts +179 -0
  172. package/src/schemas/user.schema.ts +18 -0
  173. package/src/schemas/verify-email-schema.ts +9 -0
  174. package/src/schemas/warehouse.schema.ts +49 -0
  175. package/src/system/components/categories/category-list.tsx +529 -0
  176. package/src/system/components/categories/category-manager.tsx +89 -0
  177. package/src/system/components/categories/group-sidebar.tsx +308 -0
  178. package/src/system/components/settings/setting-dialogs.tsx +197 -0
  179. package/src/system/components/settings/setting-field.tsx +291 -0
  180. package/src/system/components/settings/setting-form-dialog.tsx +308 -0
  181. package/src/system/components/settings/settings-groups.ts +80 -0
  182. package/src/system/components/settings/settings-search.tsx +71 -0
  183. package/src/system/components/settings/settings-section.tsx +74 -0
  184. package/src/system/components/settings/settings-sidebar.tsx +81 -0
  185. package/src/system/constants.ts +3 -0
  186. package/src/system/index.ts +150 -0
  187. package/src/system/job-manager.ts +176 -0
  188. package/src/system/pages/components/categories/category-list.tsx +537 -0
  189. package/src/system/pages/components/categories/category-manager.tsx +90 -0
  190. package/src/system/pages/components/categories/group-sidebar.tsx +311 -0
  191. package/src/system/pages/components/settings/sales-rules-settings.tsx +222 -0
  192. package/src/system/pages/components/settings/setting-dialogs.tsx +197 -0
  193. package/src/system/pages/components/settings/setting-field.tsx +292 -0
  194. package/src/system/pages/components/settings/setting-form-dialog.tsx +308 -0
  195. package/src/system/pages/components/settings/settings-groups.ts +87 -0
  196. package/src/system/pages/components/settings/settings-page.tsx +372 -0
  197. package/src/system/pages/components/settings/settings-search.tsx +71 -0
  198. package/src/system/pages/components/settings/settings-section.tsx +74 -0
  199. package/src/system/pages/components/settings/settings-sidebar.tsx +81 -0
  200. package/src/system/pages/components/settings/system-settings.tsx +244 -0
  201. package/src/system/pages/system-category-page.tsx +15 -0
  202. package/src/system/pages/system-settings-page.tsx +380 -0
  203. package/src/system/schemas/system-category-group.schema.ts +46 -0
  204. package/src/system/schemas/system-category.schema.ts +56 -0
  205. package/src/system/services/settings-service.ts +127 -0
  206. package/src/system/services/system-category-service.ts +63 -0
  207. package/src/system/types.ts +45 -0
  208. package/src/types/index.ts +703 -0
  209. package/src/ui/auth/auth-layout.tsx +135 -0
  210. package/src/ui/auth/forgot-password-form.tsx +98 -0
  211. package/src/ui/auth/index.tsx +7 -0
  212. package/src/ui/auth/new-password-form.tsx +107 -0
  213. package/src/ui/auth/oauth-links.tsx +30 -0
  214. package/src/ui/auth/register-form.tsx +202 -0
  215. package/src/ui/auth/sign-in-form.tsx +238 -0
  216. package/src/ui/auth/verify-email-form.tsx +104 -0
  217. package/src/ui/crud/index.tsx +10 -0
  218. package/src/ui/data-display/accordion.tsx +65 -0
  219. package/src/ui/data-display/aspect-ratio.tsx +11 -0
  220. package/src/ui/data-display/avatar.tsx +163 -0
  221. package/src/ui/data-display/bento-grid.tsx +77 -0
  222. package/src/ui/data-display/carousel.tsx +249 -0
  223. package/src/ui/data-display/chart.tsx +363 -0
  224. package/src/ui/data-display/code-block-highlight.tsx +54 -0
  225. package/src/ui/data-display/collapsible.tsx +42 -0
  226. package/src/ui/data-display/compact-stat-bar.tsx +149 -0
  227. package/src/ui/data-display/data-table/data-table-context.tsx +255 -0
  228. package/src/ui/data-display/data-table/data-table-empty-state.tsx +133 -0
  229. package/src/ui/data-display/data-table/data-table-skeleton.tsx +145 -0
  230. package/src/ui/data-display/data-table/data-table-toolbar.tsx +353 -0
  231. package/src/ui/data-display/data-table/data-table.tsx +597 -0
  232. package/src/ui/data-display/data-table/index.ts +44 -0
  233. package/src/ui/data-display/data-table-column-header.tsx +75 -0
  234. package/src/ui/data-display/data-table-pagination.tsx +130 -0
  235. package/src/ui/data-display/data-table-view-options.tsx +59 -0
  236. package/src/ui/data-display/formatted-number-input.tsx +210 -0
  237. package/src/ui/data-display/highlight.tsx +20 -0
  238. package/src/ui/data-display/hover-card.tsx +48 -0
  239. package/src/ui/data-display/index.tsx +50 -0
  240. package/src/ui/data-display/iphone-15-pro.tsx +114 -0
  241. package/src/ui/data-display/kanban/index.ts +4 -0
  242. package/src/ui/data-display/kanban/kanban-board.tsx +192 -0
  243. package/src/ui/data-display/kanban/kanban-column.tsx +74 -0
  244. package/src/ui/data-display/kanban/kanban-item.tsx +50 -0
  245. package/src/ui/data-display/kanban/kanban-types.ts +21 -0
  246. package/src/ui/data-display/kpi-card.tsx +68 -0
  247. package/src/ui/data-display/media-grid.tsx +110 -0
  248. package/src/ui/data-display/safari.tsx +175 -0
  249. package/src/ui/data-display/show-more-text.tsx +55 -0
  250. package/src/ui/data-display/tabs.tsx +68 -0
  251. package/src/ui/data-display/timeline.tsx +256 -0
  252. package/src/ui/feedback/alert.tsx +60 -0
  253. package/src/ui/feedback/context-menu.tsx +245 -0
  254. package/src/ui/feedback/drawer.tsx +132 -0
  255. package/src/ui/feedback/error-dialog.tsx +273 -0
  256. package/src/ui/feedback/index.tsx +183 -0
  257. package/src/ui/feedback/progress.tsx +32 -0
  258. package/src/ui/feedback/sheet.tsx +148 -0
  259. package/src/ui/feedback/sonner.tsx +36 -0
  260. package/src/ui/forms/command.tsx +157 -0
  261. package/src/ui/forms/date-picker.tsx +73 -0
  262. package/src/ui/forms/date-range-picker.tsx +76 -0
  263. package/src/ui/forms/date-time-picker.tsx +109 -0
  264. package/src/ui/forms/editor/editor-menu-bar.tsx +394 -0
  265. package/src/ui/forms/editor/index.tsx +130 -0
  266. package/src/ui/forms/editor/multi-select-example.tsx +1234 -0
  267. package/src/ui/forms/emoji-picker.tsx +109 -0
  268. package/src/ui/forms/file-dropzone.tsx +169 -0
  269. package/src/ui/forms/file-thumbnail.tsx +29 -0
  270. package/src/ui/forms/index.tsx +201 -0
  271. package/src/ui/forms/input-file.tsx +99 -0
  272. package/src/ui/forms/input-group.tsx +46 -0
  273. package/src/ui/forms/input-otp.tsx +81 -0
  274. package/src/ui/forms/input-phone.tsx +172 -0
  275. package/src/ui/forms/input-spin.tsx +116 -0
  276. package/src/ui/forms/input-tags.tsx +219 -0
  277. package/src/ui/forms/input-time.tsx +42 -0
  278. package/src/ui/forms/multi-select.tsx +629 -0
  279. package/src/ui/forms/multiple-date-picker.tsx +74 -0
  280. package/src/ui/forms/radio-group.tsx +42 -0
  281. package/src/ui/forms/rating.tsx +158 -0
  282. package/src/ui/forms/time-picker.tsx +57 -0
  283. package/src/ui/index.tsx +17 -0
  284. package/src/ui/layout/animated-list.tsx +77 -0
  285. package/src/ui/layout/animated-sidebar.tsx +294 -0
  286. package/src/ui/layout/command-menu.tsx +355 -0
  287. package/src/ui/layout/customizer.tsx +324 -0
  288. package/src/ui/layout/footer.tsx +43 -0
  289. package/src/ui/layout/full-screen-toggle.tsx +52 -0
  290. package/src/ui/layout/header-breadcrumb.tsx +77 -0
  291. package/src/ui/layout/horizontal-layout-header.tsx +83 -0
  292. package/src/ui/layout/horizontal-layout.tsx +50 -0
  293. package/src/ui/layout/index.tsx +25 -0
  294. package/src/ui/layout/language-dropdown.tsx +103 -0
  295. package/src/ui/layout/logo.tsx +63 -0
  296. package/src/ui/layout/main-layout.tsx +57 -0
  297. package/src/ui/layout/mode-dropdown.tsx +58 -0
  298. package/src/ui/layout/notification-dropdown.tsx +127 -0
  299. package/src/ui/layout/page-tabs.tsx +306 -0
  300. package/src/ui/layout/route-cache.tsx +214 -0
  301. package/src/ui/layout/sidebar-group-icon-menu.tsx +195 -0
  302. package/src/ui/layout/sidebar.tsx +279 -0
  303. package/src/ui/layout/tab-content-cache.tsx +201 -0
  304. package/src/ui/layout/tab-navigation-provider.tsx +536 -0
  305. package/src/ui/layout/toggle-mobile-sidebar.tsx +33 -0
  306. package/src/ui/layout/top-bar-header-menubar.tsx +412 -0
  307. package/src/ui/layout/user-dropdown.tsx +188 -0
  308. package/src/ui/layout/vertical-layout-header.tsx +65 -0
  309. package/src/ui/layout/vertical-layout.tsx +47 -0
  310. package/src/ui/management/audit-log-page.tsx +209 -0
  311. package/src/ui/management/cache-management.tsx +349 -0
  312. package/src/ui/management/index.ts +3 -0
  313. package/src/ui/management/job-management.tsx +308 -0
  314. package/src/ui/pages/not-found.tsx +30 -0
  315. package/src/ui/primitives/badge.tsx +66 -0
  316. package/src/ui/primitives/breadcrumb.tsx +103 -0
  317. package/src/ui/primitives/button.tsx +129 -0
  318. package/src/ui/primitives/calendar.tsx +74 -0
  319. package/src/ui/primitives/card.tsx +86 -0
  320. package/src/ui/primitives/checkbox.tsx +31 -0
  321. package/src/ui/primitives/client.ts +30 -0
  322. package/src/ui/primitives/combobox.tsx +290 -0
  323. package/src/ui/primitives/dialog.tsx +121 -0
  324. package/src/ui/primitives/dropdown-menu.tsx +239 -0
  325. package/src/ui/primitives/dynamic-icon.tsx +24 -0
  326. package/src/ui/primitives/index.tsx +134 -0
  327. package/src/ui/primitives/input-number.tsx +131 -0
  328. package/src/ui/primitives/input.tsx +22 -0
  329. package/src/ui/primitives/keyboard.tsx +23 -0
  330. package/src/ui/primitives/label.tsx +24 -0
  331. package/src/ui/primitives/menubar.tsx +262 -0
  332. package/src/ui/primitives/navigation-menu.tsx +157 -0
  333. package/src/ui/primitives/pagination.tsx +118 -0
  334. package/src/ui/primitives/popover.tsx +56 -0
  335. package/src/ui/primitives/prefetch-link.tsx +60 -0
  336. package/src/ui/primitives/resizable.tsx +59 -0
  337. package/src/ui/primitives/scroll-area.tsx +63 -0
  338. package/src/ui/primitives/select.tsx +172 -0
  339. package/src/ui/primitives/separator.tsx +51 -0
  340. package/src/ui/primitives/sidebar.tsx +844 -0
  341. package/src/ui/primitives/slider.tsx +27 -0
  342. package/src/ui/primitives/status-badge.tsx +47 -0
  343. package/src/ui/primitives/sticky-layout.tsx +50 -0
  344. package/src/ui/primitives/switch.tsx +29 -0
  345. package/src/ui/primitives/table.tsx +116 -0
  346. package/src/ui/primitives/tabs.tsx +55 -0
  347. package/src/ui/primitives/toggle-group.tsx +70 -0
  348. package/src/ui/primitives/toggle.tsx +47 -0
  349. package/src/ui/primitives/tooltip.tsx +59 -0
  350. package/src/user/components/dangerous-zone.tsx +34 -0
  351. package/src/user/components/delete-account-form.tsx +40 -0
  352. package/src/user/components/index.ts +4 -0
  353. package/src/user/components/profile-info-form.tsx +390 -0
  354. package/src/user/components/profile-info.tsx +32 -0
  355. package/src/user/components/unified-profile-dialog.tsx +1019 -0
  356. package/src/user/components/user-stats.tsx +27 -0
  357. package/src/user/components/user-toolbar.tsx +137 -0
  358. package/src/user/components/users-card-view.tsx +253 -0
  359. package/src/user/index.ts +11 -0
  360. package/src/user/pages/user-list-page.tsx +234 -0
  361. package/src/user/pages/users-client-page.tsx +385 -0
  362. package/src/user/profile-page.tsx +19 -0
  363. package/src/user/schemas.ts +68 -0
  364. package/src/user/types.ts +34 -0
  365. package/src/user/user-service.ts +538 -0
  366. package/src/utils/index.ts +906 -0
  367. package/src/workflow/activity-timeline.tsx +412 -0
  368. package/src/workflow/approval-workflow.tsx +31 -0
  369. package/src/workflow/index.ts +2 -0
  370. package/dist/audit/index.d.mts +0 -115
  371. package/dist/audit/index.d.ts +0 -115
  372. package/dist/audit/index.js +0 -204
  373. package/dist/audit/index.js.map +0 -1
  374. package/dist/audit/index.mjs +0 -200
  375. package/dist/audit/index.mjs.map +0 -1
  376. package/dist/auth/index.d.mts +0 -86
  377. package/dist/auth/index.d.ts +0 -86
  378. package/dist/auth/index.js +0 -210
  379. package/dist/auth/index.js.map +0 -1
  380. package/dist/auth/index.mjs +0 -198
  381. package/dist/auth/index.mjs.map +0 -1
  382. package/dist/button-1dWvP9Ib.d.mts +0 -30
  383. package/dist/button-1dWvP9Ib.d.ts +0 -30
  384. package/dist/calendar-2QzdEo1z.d.mts +0 -20
  385. package/dist/calendar-2QzdEo1z.d.ts +0 -20
  386. package/dist/code-generation/index.d.mts +0 -30
  387. package/dist/code-generation/index.d.ts +0 -30
  388. package/dist/code-generation/index.js +0 -31
  389. package/dist/code-generation/index.js.map +0 -1
  390. package/dist/code-generation/index.mjs +0 -28
  391. package/dist/code-generation/index.mjs.map +0 -1
  392. package/dist/configs/index.d.mts +0 -175
  393. package/dist/configs/index.d.ts +0 -175
  394. package/dist/configs/index.js +0 -254
  395. package/dist/configs/index.js.map +0 -1
  396. package/dist/configs/index.mjs +0 -233
  397. package/dist/configs/index.mjs.map +0 -1
  398. package/dist/crud/index.d.mts +0 -646
  399. package/dist/crud/index.d.ts +0 -646
  400. package/dist/crud/index.js +0 -11772
  401. package/dist/crud/index.js.map +0 -1
  402. package/dist/crud/index.mjs +0 -11665
  403. package/dist/crud/index.mjs.map +0 -1
  404. package/dist/crud/server.d.mts +0 -20
  405. package/dist/crud/server.d.ts +0 -20
  406. package/dist/crud/server.js +0 -123
  407. package/dist/crud/server.js.map +0 -1
  408. package/dist/crud/server.mjs +0 -120
  409. package/dist/crud/server.mjs.map +0 -1
  410. package/dist/data-table-skeleton-12NA8Mjx.d.mts +0 -39
  411. package/dist/data-table-skeleton-12NA8Mjx.d.ts +0 -39
  412. package/dist/dialog-bKfjZMTd.d.mts +0 -22
  413. package/dist/dialog-bKfjZMTd.d.ts +0 -22
  414. package/dist/dynamic-icon-DrGIiu2N.d.mts +0 -10
  415. package/dist/dynamic-icon-DrGIiu2N.d.ts +0 -10
  416. package/dist/home/index.d.mts +0 -269
  417. package/dist/home/index.d.ts +0 -269
  418. package/dist/home/index.js +0 -1678
  419. package/dist/home/index.js.map +0 -1
  420. package/dist/home/index.mjs +0 -1635
  421. package/dist/home/index.mjs.map +0 -1
  422. package/dist/hooks/index.d.mts +0 -7
  423. package/dist/hooks/index.d.ts +0 -7
  424. package/dist/hooks/index.js +0 -8316
  425. package/dist/hooks/index.js.map +0 -1
  426. package/dist/hooks/index.mjs +0 -8255
  427. package/dist/hooks/index.mjs.map +0 -1
  428. package/dist/index-50hpiPrV.d.ts +0 -116
  429. package/dist/index-B9zQVEVi.d.mts +0 -116
  430. package/dist/index.d.mts +0 -5
  431. package/dist/index.d.ts +0 -5
  432. package/dist/index.js +0 -123
  433. package/dist/index.js.map +0 -1
  434. package/dist/index.mjs +0 -118
  435. package/dist/index.mjs.map +0 -1
  436. package/dist/infrastructure/index.d.mts +0 -423
  437. package/dist/infrastructure/index.d.ts +0 -423
  438. package/dist/infrastructure/index.js +0 -633
  439. package/dist/infrastructure/index.js.map +0 -1
  440. package/dist/infrastructure/index.mjs +0 -619
  441. package/dist/infrastructure/index.mjs.map +0 -1
  442. package/dist/label-DWTEkNPo.d.ts +0 -226
  443. package/dist/label-LPpdcoBx.d.mts +0 -226
  444. package/dist/layout/index.d.mts +0 -48
  445. package/dist/layout/index.d.ts +0 -48
  446. package/dist/layout/index.js +0 -117
  447. package/dist/layout/index.js.map +0 -1
  448. package/dist/layout/index.mjs +0 -90
  449. package/dist/layout/index.mjs.map +0 -1
  450. package/dist/navigation/index.d.mts +0 -16
  451. package/dist/navigation/index.d.ts +0 -16
  452. package/dist/navigation/index.js +0 -53
  453. package/dist/navigation/index.js.map +0 -1
  454. package/dist/navigation/index.mjs +0 -50
  455. package/dist/navigation/index.mjs.map +0 -1
  456. package/dist/notification/index.d.mts +0 -105
  457. package/dist/notification/index.d.ts +0 -105
  458. package/dist/notification/index.js +0 -278
  459. package/dist/notification/index.js.map +0 -1
  460. package/dist/notification/index.mjs +0 -274
  461. package/dist/notification/index.mjs.map +0 -1
  462. package/dist/organization/index.d.mts +0 -99
  463. package/dist/organization/index.d.ts +0 -99
  464. package/dist/organization/index.js +0 -360
  465. package/dist/organization/index.js.map +0 -1
  466. package/dist/organization/index.mjs +0 -352
  467. package/dist/organization/index.mjs.map +0 -1
  468. package/dist/plugin/index.d.mts +0 -83
  469. package/dist/plugin/index.d.ts +0 -83
  470. package/dist/plugin/index.js +0 -86
  471. package/dist/plugin/index.js.map +0 -1
  472. package/dist/plugin/index.mjs +0 -84
  473. package/dist/plugin/index.mjs.map +0 -1
  474. package/dist/providers/index.d.mts +0 -25
  475. package/dist/providers/index.d.ts +0 -25
  476. package/dist/providers/index.js +0 -84
  477. package/dist/providers/index.js.map +0 -1
  478. package/dist/providers/index.mjs +0 -77
  479. package/dist/providers/index.mjs.map +0 -1
  480. package/dist/rbac/index.d.mts +0 -226
  481. package/dist/rbac/index.d.ts +0 -226
  482. package/dist/rbac/index.js +0 -4784
  483. package/dist/rbac/index.js.map +0 -1
  484. package/dist/rbac/index.mjs +0 -4722
  485. package/dist/rbac/index.mjs.map +0 -1
  486. package/dist/rbac/permissions.d.mts +0 -26
  487. package/dist/rbac/permissions.d.ts +0 -26
  488. package/dist/rbac/permissions.js +0 -94
  489. package/dist/rbac/permissions.js.map +0 -1
  490. package/dist/rbac/permissions.mjs +0 -90
  491. package/dist/rbac/permissions.mjs.map +0 -1
  492. package/dist/rbac/server.d.mts +0 -1
  493. package/dist/rbac/server.d.ts +0 -1
  494. package/dist/rbac/server.js +0 -128
  495. package/dist/rbac/server.js.map +0 -1
  496. package/dist/rbac/server.mjs +0 -124
  497. package/dist/rbac/server.mjs.map +0 -1
  498. package/dist/schemas/index.d.mts +0 -1257
  499. package/dist/schemas/index.d.ts +0 -1257
  500. package/dist/schemas/index.js +0 -572
  501. package/dist/schemas/index.js.map +0 -1
  502. package/dist/schemas/index.mjs +0 -523
  503. package/dist/schemas/index.mjs.map +0 -1
  504. package/dist/server-QuYCTa89.d.mts +0 -83
  505. package/dist/server-QuYCTa89.d.ts +0 -83
  506. package/dist/sonner-C74GlRDQ.d.mts +0 -71
  507. package/dist/sonner-C74GlRDQ.d.ts +0 -71
  508. package/dist/status-BOXZgIqX.d.mts +0 -12
  509. package/dist/status-BOXZgIqX.d.ts +0 -12
  510. package/dist/system/index.d.mts +0 -77
  511. package/dist/system/index.d.ts +0 -77
  512. package/dist/system/index.js +0 -102
  513. package/dist/system/index.js.map +0 -1
  514. package/dist/system/index.mjs +0 -100
  515. package/dist/system/index.mjs.map +0 -1
  516. package/dist/tabs-C6FfBwPY.d.mts +0 -18
  517. package/dist/tabs-C6FfBwPY.d.ts +0 -18
  518. package/dist/tenant-provider-B8eC_Wpb.d.mts +0 -27
  519. package/dist/tenant-provider-B8eC_Wpb.d.ts +0 -27
  520. package/dist/types/index.d.mts +0 -469
  521. package/dist/types/index.d.ts +0 -469
  522. package/dist/types/index.js +0 -25
  523. package/dist/types/index.js.map +0 -1
  524. package/dist/types/index.mjs +0 -21
  525. package/dist/types/index.mjs.map +0 -1
  526. package/dist/ui/auth.d.mts +0 -39
  527. package/dist/ui/auth.d.ts +0 -39
  528. package/dist/ui/auth.js +0 -4941
  529. package/dist/ui/auth.js.map +0 -1
  530. package/dist/ui/auth.mjs +0 -4896
  531. package/dist/ui/auth.mjs.map +0 -1
  532. package/dist/ui/crud.d.mts +0 -2
  533. package/dist/ui/crud.d.ts +0 -2
  534. package/dist/ui/crud.js +0 -4
  535. package/dist/ui/crud.js.map +0 -1
  536. package/dist/ui/crud.mjs +0 -3
  537. package/dist/ui/crud.mjs.map +0 -1
  538. package/dist/ui/data-display.d.mts +0 -596
  539. package/dist/ui/data-display.d.ts +0 -596
  540. package/dist/ui/data-display.js +0 -5307
  541. package/dist/ui/data-display.js.map +0 -1
  542. package/dist/ui/data-display.mjs +0 -5212
  543. package/dist/ui/data-display.mjs.map +0 -1
  544. package/dist/ui/feedback.d.mts +0 -55
  545. package/dist/ui/feedback.d.ts +0 -55
  546. package/dist/ui/feedback.js +0 -2608
  547. package/dist/ui/feedback.js.map +0 -1
  548. package/dist/ui/feedback.mjs +0 -2526
  549. package/dist/ui/feedback.mjs.map +0 -1
  550. package/dist/ui/forms.d.mts +0 -309
  551. package/dist/ui/forms.d.ts +0 -309
  552. package/dist/ui/forms.js +0 -4656
  553. package/dist/ui/forms.js.map +0 -1
  554. package/dist/ui/forms.mjs +0 -4571
  555. package/dist/ui/forms.mjs.map +0 -1
  556. package/dist/ui/index.d.mts +0 -331
  557. package/dist/ui/index.d.ts +0 -331
  558. package/dist/ui/index.js +0 -16953
  559. package/dist/ui/index.js.map +0 -1
  560. package/dist/ui/index.mjs +0 -16598
  561. package/dist/ui/index.mjs.map +0 -1
  562. package/dist/ui/primitives/client.d.mts +0 -61
  563. package/dist/ui/primitives/client.d.ts +0 -61
  564. package/dist/ui/primitives/client.js +0 -3408
  565. package/dist/ui/primitives/client.js.map +0 -1
  566. package/dist/ui/primitives/client.mjs +0 -3256
  567. package/dist/ui/primitives/client.mjs.map +0 -1
  568. package/dist/ui/primitives.d.mts +0 -113
  569. package/dist/ui/primitives.d.ts +0 -113
  570. package/dist/ui/primitives.js +0 -3356
  571. package/dist/ui/primitives.js.map +0 -1
  572. package/dist/ui/primitives.mjs +0 -3227
  573. package/dist/ui/primitives.mjs.map +0 -1
  574. package/dist/user/index.d.mts +0 -228
  575. package/dist/user/index.d.ts +0 -228
  576. package/dist/user/index.js +0 -4306
  577. package/dist/user/index.js.map +0 -1
  578. package/dist/user/index.mjs +0 -4260
  579. package/dist/user/index.mjs.map +0 -1
  580. package/dist/utils/index.d.mts +0 -205
  581. package/dist/utils/index.d.ts +0 -205
  582. package/dist/utils/index.js +0 -574
  583. package/dist/utils/index.js.map +0 -1
  584. package/dist/utils/index.mjs +0 -514
  585. package/dist/utils/index.mjs.map +0 -1
  586. package/dist/workflow/index.d.mts +0 -40
  587. package/dist/workflow/index.d.ts +0 -40
  588. package/dist/workflow/index.js +0 -3710
  589. package/dist/workflow/index.js.map +0 -1
  590. package/dist/workflow/index.mjs +0 -3677
  591. package/dist/workflow/index.mjs.map +0 -1
@@ -0,0 +1,127 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { Bell } from "lucide-react";
5
+
6
+ import type { DictionaryType } from "../../hooks";
7
+
8
+ import { cn, formatDistance, formatUnreadCount } from "../../utils";
9
+
10
+ import { Badge, Button, buttonVariants, Card, CardFooter } from "../index";
11
+ import {
12
+ Popover,
13
+ PopoverContent,
14
+ PopoverTrigger,
15
+ DynamicIcon,
16
+ ScrollArea,
17
+ Tooltip,
18
+ TooltipTrigger,
19
+ TooltipContent,
20
+ } from "../primitives/client";
21
+
22
+ interface NotificationItem {
23
+ id: string;
24
+ url: string;
25
+ iconName: string;
26
+ content: string;
27
+ date: string | Date;
28
+ isRead: boolean;
29
+ }
30
+
31
+ interface NotificationDropdownProps {
32
+ dictionary: DictionaryType;
33
+ notifications?: NotificationItem[];
34
+ unreadCount?: number;
35
+ }
36
+
37
+ export function NotificationDropdown({
38
+ dictionary,
39
+ notifications = [],
40
+ unreadCount = 0,
41
+ }: NotificationDropdownProps) {
42
+ const displayCount = formatUnreadCount(unreadCount);
43
+
44
+ return (
45
+ <Popover modal>
46
+ <Tooltip>
47
+ <PopoverTrigger asChild>
48
+ <TooltipTrigger asChild>
49
+ <Button
50
+ variant="ghost"
51
+ size="icon"
52
+ className="relative"
53
+ >
54
+ <Bell className="size-4" />
55
+ <span className="sr-only">Notification</span>
56
+ {!!unreadCount && (
57
+ <Badge
58
+ className="absolute -top-1 -end-1 h-4 max-w-8 flex justify-center"
59
+ aria-live="polite"
60
+ aria-atomic="true"
61
+ role="status"
62
+ aria-label={`${displayCount} unread`}
63
+ >
64
+ {displayCount}
65
+ </Badge>
66
+ )}
67
+ </Button>
68
+ </TooltipTrigger>
69
+ </PopoverTrigger>
70
+ <TooltipContent>Notifications</TooltipContent>
71
+ </Tooltip>
72
+ <PopoverContent className="w-[380px] p-0">
73
+ <Card className="border-0 shadow-none">
74
+ <div className="flex items-center justify-between border-b border-border p-3">
75
+ <h3 className="text-sm font-semibold">
76
+ {dictionary.navigation.notifications.notifications}
77
+ </h3>
78
+ <Button variant="link" className="text-primary h-auto p-0">
79
+ {dictionary.navigation.notifications.dismissAll}
80
+ </Button>
81
+ </div>
82
+ <ScrollArea className="max-h-[300px]">
83
+ <ul>
84
+ {notifications.map((notification) => (
85
+ <li key={notification.id}>
86
+ <Link
87
+ href={notification.url}
88
+ className="flex items-center gap-2 py-4 px-6 hover:bg-accent hover:text-accent-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring"
89
+ >
90
+ <Badge className="h-10 w-10 flex items-center justify-center">
91
+ <DynamicIcon
92
+ name={notification.iconName as any}
93
+ className="h-5 w-5"
94
+ />
95
+ </Badge>
96
+ <div className="flex-1 w-0">
97
+ <p className="text-sm break-all truncate">
98
+ {notification.content}
99
+ </p>
100
+ <p className="text-sm text-muted-foreground">
101
+ {formatDistance(notification.date)}
102
+ </p>
103
+ </div>
104
+ {!notification.isRead && (
105
+ <div className="h-2 w-2 rounded-full bg-primary" />
106
+ )}
107
+ </Link>
108
+ </li>
109
+ ))}
110
+ </ul>
111
+ </ScrollArea>
112
+ <CardFooter className="justify-center border-t border-border p-0 min-h-12 flex items-center">
113
+ <Link
114
+ href=""
115
+ className={cn(
116
+ buttonVariants({ variant: "link" }),
117
+ "text-primary text-center",
118
+ )}
119
+ >
120
+ {dictionary.navigation.notifications.seeAllNotifications}
121
+ </Link>
122
+ </CardFooter>
123
+ </Card>
124
+ </PopoverContent>
125
+ </Popover>
126
+ );
127
+ }
@@ -0,0 +1,306 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { X, MoreHorizontal, Loader2, Pin } from "lucide-react";
5
+ import { useParams, useRouter } from "next/navigation";
6
+ import type { DictionaryType } from "../../hooks";
7
+ import type { LocaleType } from "../../types";
8
+
9
+ import { cn } from "../../utils";
10
+ import { Button, Badge } from "../index";
11
+ import {
12
+ DynamicIcon,
13
+ ScrollArea,
14
+ ScrollBar,
15
+ ContextMenu,
16
+ ContextMenuContent,
17
+ ContextMenuItem,
18
+ ContextMenuSeparator,
19
+ ContextMenuTrigger,
20
+ } from "../primitives/client";
21
+
22
+ import { useTabNavigation } from "./tab-navigation-provider";
23
+ import { useRouteCache } from "./route-cache";
24
+
25
+ interface PageTabsProps {
26
+ dictionary?: DictionaryType;
27
+ className?: string;
28
+ variant?: "default" | "header";
29
+ }
30
+
31
+ export function PageTabs({
32
+ dictionary,
33
+ className,
34
+ variant = "default",
35
+ }: PageTabsProps) {
36
+ const {
37
+ tabs,
38
+ activeTabId,
39
+ removeTab,
40
+ setActiveTab,
41
+ removeOtherTabs,
42
+ removeTabsToRight,
43
+ clearTabs,
44
+ } = useTabNavigation();
45
+ const { reloadTab } = useRouteCache();
46
+ const params = useParams();
47
+ const router = useRouter();
48
+ const locale = params?.lang as LocaleType | undefined;
49
+ const [contextMenuTabId, setContextMenuTabId] = useState<string | null>(null);
50
+
51
+ // Don't render if no tabs
52
+ if (tabs.length === 0) {
53
+ return null;
54
+ }
55
+
56
+ const handleTabClick = (tabId: string) => {
57
+ setActiveTab(tabId);
58
+ };
59
+
60
+ const handleReloadTab = (path: string) => {
61
+ reloadTab(path);
62
+ router.refresh();
63
+ };
64
+
65
+ const handleCloseTab = (e: React.MouseEvent, tabId: string) => {
66
+ e.stopPropagation();
67
+ removeTab(tabId);
68
+ };
69
+
70
+ const handleContextMenu = (tabId: string) => {
71
+ setContextMenuTabId(tabId);
72
+ };
73
+
74
+ // Sort tabs: pinned first, then by creation time
75
+ const sortedTabs = [...tabs].sort((a, b) => {
76
+ if (a.isPinned && !b.isPinned) return -1;
77
+ if (!a.isPinned && b.isPinned) return 1;
78
+ return a.createdAt - b.createdAt;
79
+ });
80
+
81
+ const currentTabIndex = sortedTabs.findIndex(
82
+ (tab) => tab.id === contextMenuTabId,
83
+ );
84
+ const hasTabsToRight =
85
+ currentTabIndex >= 0 && currentTabIndex < sortedTabs.length - 1;
86
+ const hasOtherTabs = sortedTabs.length > 1;
87
+
88
+ // Generate unique gradient background for each tab based on path
89
+ const getTabBackgroundColor = (path: string, isActive: boolean) => {
90
+ if (isActive) return "bg-background";
91
+
92
+ // Generate consistent hash from path
93
+ const normalizedPath = path.replace(/^\/[a-z]{2}(\/|$)/, "/");
94
+ const hash = normalizedPath.split("").reduce((acc, char) => {
95
+ return (acc << 5) - acc + char.charCodeAt(0);
96
+ }, 0);
97
+
98
+ // Refined gradient palette - darker and more visible (using dark theme colors for both modes)
99
+ const gradients = [
100
+ "bg-gradient-to-r from-slate-700 to-slate-600",
101
+ "bg-gradient-to-r from-zinc-700 to-zinc-600",
102
+ "bg-gradient-to-r from-stone-700 to-stone-600",
103
+ "bg-gradient-to-r from-neutral-700 to-neutral-600",
104
+ "bg-gradient-to-r from-blue-700 to-blue-600",
105
+ "bg-gradient-to-r from-indigo-700 to-indigo-600",
106
+ "bg-gradient-to-r from-purple-700 to-purple-600",
107
+ "bg-gradient-to-r from-violet-700 to-violet-600",
108
+ "bg-gradient-to-r from-fuchsia-700 to-fuchsia-600",
109
+ "bg-gradient-to-r from-pink-700 to-pink-600",
110
+ "bg-gradient-to-r from-rose-700 to-rose-600",
111
+ "bg-gradient-to-r from-red-700 to-red-600",
112
+ "bg-gradient-to-r from-orange-700 to-orange-600",
113
+ "bg-gradient-to-r from-amber-700 to-amber-600",
114
+ "bg-gradient-to-r from-yellow-700 to-yellow-600",
115
+ "bg-gradient-to-r from-lime-700 to-lime-600",
116
+ "bg-gradient-to-r from-green-700 to-green-600",
117
+ "bg-gradient-to-r from-emerald-700 to-emerald-600",
118
+ "bg-gradient-to-r from-teal-700 to-teal-600",
119
+ "bg-gradient-to-r from-cyan-700 to-cyan-600",
120
+ "bg-gradient-to-r from-sky-700 to-sky-600",
121
+ ];
122
+
123
+ // Select gradient based on hash to ensure consistency
124
+ const gradientIndex = Math.abs(hash) % gradients.length;
125
+ return gradients[gradientIndex];
126
+ };
127
+
128
+ return (
129
+ <div className={cn("w-full", variant === "header" && "py-0", className)}>
130
+ <ScrollArea className={cn("w-full", variant === "header" && "h-8")}>
131
+ <div
132
+ className={cn(
133
+ "flex items-end gap-0 px-2 py-0.5",
134
+ variant === "header" && "items-center py-0",
135
+ )}
136
+ >
137
+ {sortedTabs.map((tab, index) => {
138
+ const isActive = tab.id === activeTabId;
139
+ const isLast = index === sortedTabs.length - 1;
140
+ return (
141
+ <ContextMenu
142
+ key={tab.id}
143
+ onOpenChange={(open) => !open && setContextMenuTabId(null)}
144
+ >
145
+ <ContextMenuTrigger asChild>
146
+ <div
147
+ role="button"
148
+ tabIndex={0}
149
+ onClick={() => handleTabClick(tab.id)}
150
+ onContextMenu={() => handleContextMenu(tab.id)}
151
+ onMouseEnter={() => {
152
+ // Prefetch route when hovering over tab
153
+ if (!isActive && tab.path) {
154
+ router.prefetch(tab.path);
155
+ }
156
+ }}
157
+ onKeyDown={(e) => {
158
+ if (e.key === "Enter" || e.key === " ") {
159
+ e.preventDefault();
160
+ handleTabClick(tab.id);
161
+ }
162
+ }}
163
+ className={cn(
164
+ "group relative flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium transition-all duration-200",
165
+ "border border-transparent",
166
+ "hover:brightness-105 cursor-pointer",
167
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
168
+ getTabBackgroundColor(tab.path, isActive),
169
+ variant === "default" &&
170
+ (isActive
171
+ ? "bg-background text-foreground border-b-2 border-primary shadow-sm shadow-primary/10 border-t border-x border-b-0 rounded-t-md -mb-px z-10"
172
+ : "text-white hover:text-white border-b border-white/10 rounded-t-md"),
173
+ variant === "header" &&
174
+ (isActive
175
+ ? "bg-background text-foreground border-b-2 border-primary shadow-sm shadow-primary/10 border-t border-x rounded-t-md z-10"
176
+ : "text-white hover:text-white border-b border-white/10 rounded-t-md"),
177
+ !isLast &&
178
+ !isActive &&
179
+ variant === "default" &&
180
+ "border-r border-white/10",
181
+ )}
182
+ >
183
+ {/* Tab number indicator (for keyboard shortcuts) */}
184
+ {index < 9 && (
185
+ <span
186
+ className={cn(
187
+ "text-[10px] font-bold shrink-0 w-3 text-center opacity-50",
188
+ isActive && "opacity-70 text-primary",
189
+ )}
190
+ >
191
+ {index + 1}
192
+ </span>
193
+ )}
194
+ {/* Icon or status indicator */}
195
+ <div className="flex items-center gap-1 shrink-0">
196
+ {tab.isPinned && (
197
+ <Pin className="h-3 w-3 text-primary fill-current shrink-0" />
198
+ )}
199
+ {tab.isLoading ? (
200
+ <Loader2 className="h-3 w-3 animate-spin text-primary shrink-0" />
201
+ ) : tab.hasUnsavedChanges ? (
202
+ <div className="h-1.5 w-1.5 rounded-full bg-warning shrink-0" />
203
+ ) : tab.iconName ? (
204
+ <DynamicIcon
205
+ name={tab.iconName}
206
+ className={cn(
207
+ "h-3.5 w-3.5 shrink-0 transition-colors",
208
+ isActive
209
+ ? "text-primary"
210
+ : "text-white/70 group-hover:text-white",
211
+ )}
212
+ />
213
+ ) : null}
214
+ </div>
215
+ <span
216
+ className={cn(
217
+ "truncate max-w-[150px]",
218
+ isActive ? "font-semibold" : "font-medium",
219
+ )}
220
+ >
221
+ {tab.title}
222
+ </span>
223
+ {tab.badge !== undefined && (
224
+ <Badge
225
+ variant={isActive ? "default" : "secondary"}
226
+ className={cn(
227
+ "h-4 min-w-4 px-1.5 text-[10px] font-semibold shrink-0",
228
+ isActive &&
229
+ "bg-primary/20 text-primary border-primary/30",
230
+ )}
231
+ >
232
+ {typeof tab.badge === "number" && tab.badge > 99
233
+ ? "99+"
234
+ : tab.badge}
235
+ </Badge>
236
+ )}
237
+ <Button
238
+ variant="ghost"
239
+ size="icon"
240
+ className={cn(
241
+ "h-4 w-4 ml-0.5 opacity-0 group-hover:opacity-100 transition-opacity shrink-0",
242
+ "hover:bg-destructive/10 hover:text-destructive",
243
+ isActive && "opacity-100",
244
+ )}
245
+ onClick={(e) => handleCloseTab(e, tab.id)}
246
+ aria-label={`Close ${tab.title}`}
247
+ >
248
+ <X className="h-2.5 w-2.5" />
249
+ </Button>
250
+ </div>
251
+ </ContextMenuTrigger>
252
+ <ContextMenuContent>
253
+ <ContextMenuItem onClick={() => handleReloadTab(tab.path)}>
254
+ Reload Tab
255
+ </ContextMenuItem>
256
+ <ContextMenuItem onClick={() => handleTabClick(tab.id)}>
257
+ Switch to Tab
258
+ </ContextMenuItem>
259
+ <ContextMenuItem onClick={() => removeTab(tab.id)}>
260
+ Close Tab
261
+ </ContextMenuItem>
262
+ {hasOtherTabs && (
263
+ <>
264
+ <ContextMenuSeparator />
265
+ <ContextMenuItem onClick={() => removeOtherTabs(tab.id)}>
266
+ Close Other Tabs
267
+ </ContextMenuItem>
268
+ {hasTabsToRight && (
269
+ <ContextMenuItem
270
+ onClick={() => removeTabsToRight(tab.id)}
271
+ >
272
+ Close Tabs to the Right
273
+ </ContextMenuItem>
274
+ )}
275
+ </>
276
+ )}
277
+ {tabs.length > 1 && (
278
+ <>
279
+ <ContextMenuSeparator />
280
+ <ContextMenuItem onClick={() => clearTabs()}>
281
+ Close All Tabs
282
+ </ContextMenuItem>
283
+ </>
284
+ )}
285
+ </ContextMenuContent>
286
+ </ContextMenu>
287
+ );
288
+ })}
289
+ {sortedTabs.length > 3 && (
290
+ <Button
291
+ variant="ghost"
292
+ size="sm"
293
+ className="h-6 px-2 text-xs ml-1"
294
+ onClick={() => clearTabs()}
295
+ title="Close all tabs"
296
+ >
297
+ <MoreHorizontal className="h-3 w-3 mr-1" />
298
+ Close All
299
+ </Button>
300
+ )}
301
+ </div>
302
+ <ScrollBar orientation="horizontal" />
303
+ </ScrollArea>
304
+ </div>
305
+ );
306
+ }
@@ -0,0 +1,214 @@
1
+ "use client";
2
+
3
+ import {
4
+ createContext,
5
+ useContext,
6
+ useEffect,
7
+ useRef,
8
+ useState,
9
+ useCallback,
10
+ } from "react";
11
+ import { usePathname } from "next/navigation";
12
+ import { useTabNavigation } from "./tab-navigation-provider";
13
+
14
+ interface RouteCacheContextType {
15
+ reloadTab: (path: string) => void;
16
+ }
17
+
18
+ const RouteCacheContext = createContext<RouteCacheContextType | undefined>(
19
+ undefined,
20
+ );
21
+
22
+ interface CacheEntry {
23
+ node: React.ReactNode;
24
+ lastActive: number;
25
+ path: string;
26
+ }
27
+
28
+ const CACHE_TIMEOUT = 3 * 60 * 1000; // 3 minutes
29
+
30
+ export function RouteCacheProvider({
31
+ children,
32
+ }: {
33
+ children: React.ReactNode;
34
+ }) {
35
+ const pathname = usePathname();
36
+ const { tabs } = useTabNavigation();
37
+ const [cache, setCache] = useState<Map<string, CacheEntry>>(new Map());
38
+ // We need a ref to access the latest cache in effects/callbacks without triggering re-renders
39
+ const cacheRef = useRef<Map<string, CacheEntry>>(new Map());
40
+
41
+ // Update ref when state changes
42
+ useEffect(() => {
43
+ cacheRef.current = cache;
44
+ }, [cache]);
45
+
46
+ // Function to manually reload a tab
47
+ const reloadTab = useCallback((path: string) => {
48
+ setCache((prev) => {
49
+ const newCache = new Map(prev);
50
+ newCache.delete(path);
51
+ return newCache;
52
+ });
53
+ }, []);
54
+
55
+ // 1. Handle Pathname Change (Add/Update Cache)
56
+ useEffect(() => {
57
+ if (!pathname) return;
58
+
59
+ setCache((prev) => {
60
+ const now = Date.now();
61
+ // Check if we need to update
62
+ const existing = prev.get(pathname);
63
+
64
+ // If exists and was active recently (e.g. < 1s), skip update to avoid spam
65
+ // But we need to update lastActive.
66
+ // However, if we just updated it, maybe we don't need to trigger a re-render?
67
+ // Let's just update if it's NOT in cache, or if we want to refresh the timestamp.
68
+
69
+ if (existing) {
70
+ // If it exists, we only update timestamp.
71
+ // To avoid re-renders on every render (if this effect runs often),
72
+ // we could check if timestamp is significantly different?
73
+ // But this effect only runs on [pathname]. So it runs once per navigation.
74
+ // This is fine.
75
+ const newCache = new Map(prev);
76
+ newCache.set(pathname, {
77
+ ...existing,
78
+ lastActive: now,
79
+ });
80
+ return newCache;
81
+ }
82
+
83
+ // If not in cache, add it.
84
+ const newCache = new Map(prev);
85
+ newCache.set(pathname, {
86
+ node: children,
87
+ lastActive: now,
88
+ path: pathname,
89
+ });
90
+ return newCache;
91
+ });
92
+ }, [pathname, children]); // Removed 'tabs' dependency
93
+
94
+ // 2. Handle Tab Closing (Cleanup)
95
+ useEffect(() => {
96
+ // We only want to run this when 'tabs' changes (specifically when a tab is removed)
97
+ // We can check if any cached path is NOT in tabs (and not current path)
98
+
99
+ setCache((prev) => {
100
+ const tabPaths = new Set(tabs.map((t) => t.path));
101
+ let hasChanges = false;
102
+
103
+ // Check if we need to remove anything
104
+ for (const key of prev.keys()) {
105
+ if (key !== pathname && !tabPaths.has(key)) {
106
+ hasChanges = true;
107
+ break;
108
+ }
109
+ }
110
+
111
+ if (!hasChanges) return prev; // Return same reference to avoid re-render
112
+
113
+ const newCache = new Map(prev);
114
+ for (const key of newCache.keys()) {
115
+ if (key !== pathname && !tabPaths.has(key)) {
116
+ newCache.delete(key);
117
+ }
118
+ }
119
+ return newCache;
120
+ });
121
+ }, [tabs, pathname]);
122
+
123
+ // 3. Periodic cleanup for timeouts
124
+ useEffect(() => {
125
+ const interval = setInterval(() => {
126
+ setCache((prev) => {
127
+ const now = Date.now();
128
+ let hasChanges = false;
129
+
130
+ for (const [key, entry] of prev.entries()) {
131
+ if (key === pathname) continue;
132
+ if (now - entry.lastActive > CACHE_TIMEOUT) {
133
+ hasChanges = true;
134
+ break;
135
+ }
136
+ }
137
+
138
+ if (!hasChanges) return prev;
139
+
140
+ const newCache = new Map(prev);
141
+ for (const [key, entry] of newCache.entries()) {
142
+ if (key === pathname) continue;
143
+ if (now - entry.lastActive > CACHE_TIMEOUT) {
144
+ newCache.delete(key);
145
+ }
146
+ }
147
+ return newCache;
148
+ });
149
+ }, 10000);
150
+
151
+ return () => clearInterval(interval);
152
+ }, [pathname]);
153
+
154
+ // Render Logic
155
+ // We render ALL cached items.
156
+ // The one matching `pathname` gets the *fresh* `children` if it wasn't cached,
157
+ // OR the *cached* node if it was.
158
+ // Actually, the logic in the effect above sets the cache.
159
+ // Here we just iterate and render.
160
+
161
+ // WAIT: The `children` passed to this component is the content of the CURRENT route.
162
+ // If we want to cache it, we must save it.
163
+ // But `children` changes on every route change.
164
+
165
+ // Correct Approach for Next.js App Router "Keep Alive":
166
+ // We need to "freeze" the children at the moment they are first mounted for a path.
167
+
168
+ // Let's refine the render:
169
+ // We iterate through the `cache`.
170
+ // For each entry, we render `entry.node`.
171
+ // We control visibility with `display: none`.
172
+
173
+ // BUT: What if the current page is NOT in the cache yet (first render)?
174
+ // The effect hasn't run yet.
175
+ // We should render `children` directly for the current path, and THEN cache it.
176
+
177
+ // Let's try a simpler approach for the render loop:
178
+ const itemsToRender = Array.from(cache.entries());
179
+
180
+ // If current path is not in cache, we must render it too (and it will be added to cache by effect)
181
+ const isCurrentInCache = cache.has(pathname);
182
+
183
+ return (
184
+ <RouteCacheContext.Provider value={{ reloadTab }}>
185
+ <div className="flex-1 w-full h-full relative">
186
+ {itemsToRender.map(([path, entry]) => (
187
+ <div
188
+ key={path}
189
+ className="w-full h-full"
190
+ style={{ display: path === pathname ? "block" : "none" }}
191
+ >
192
+ {entry.node}
193
+ </div>
194
+ ))}
195
+
196
+ {!isCurrentInCache && (
197
+ <div key={pathname} className="w-full h-full">
198
+ {children}
199
+ </div>
200
+ )}
201
+ </div>
202
+ </RouteCacheContext.Provider>
203
+ );
204
+ }
205
+
206
+ export function useRouteCache() {
207
+ const context = useContext(RouteCacheContext);
208
+ if (!context) {
209
+ // It's optional, so we can return a dummy if not found, or throw.
210
+ // Let's return a dummy to avoid breaking if used outside.
211
+ return { reloadTab: () => {} };
212
+ }
213
+ return context;
214
+ }