@trackany-device/components 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/package.json +185 -0
  2. package/src/assets/logo.png +0 -0
  3. package/src/assets/map/arrows/map-arrow-blue.png +0 -0
  4. package/src/assets/map/arrows/map-arrow-green.png +0 -0
  5. package/src/assets/map/arrows/map-arrow-purple.png +0 -0
  6. package/src/assets/map/arrows/map-arrow-red.png +0 -0
  7. package/src/assets/map/flags/flag-blue.png +0 -0
  8. package/src/assets/map/flags/flag-green.png +0 -0
  9. package/src/assets/map/flags/flag-red.png +0 -0
  10. package/src/assets/map/flags/flag-yellow.png +0 -0
  11. package/src/assets/map/pins/map-pin-blue.png +0 -0
  12. package/src/assets/map/pins/map-pin-green.png +0 -0
  13. package/src/assets/map/pins/map-pin-purple.png +0 -0
  14. package/src/assets/map/pins/map-pin-red.png +0 -0
  15. package/src/components/Card.tsx +9 -0
  16. package/src/components/alert-error.tsx +24 -0
  17. package/src/components/app-content.tsx +22 -0
  18. package/src/components/app-header.tsx +153 -0
  19. package/src/components/app-logo-icon.tsx +13 -0
  20. package/src/components/app-logo.tsx +21 -0
  21. package/src/components/app-shell.tsx +19 -0
  22. package/src/components/app-sidebar-header.tsx +68 -0
  23. package/src/components/app-sidebar.tsx +106 -0
  24. package/src/components/appearance-tabs.tsx +46 -0
  25. package/src/components/breadcrumbs.tsx +50 -0
  26. package/src/components/cms/blurred-image.tsx +111 -0
  27. package/src/components/cms/section-bg.tsx +473 -0
  28. package/src/components/cms/section-button.tsx +127 -0
  29. package/src/components/cms/sections/banner-5050-section.tsx +135 -0
  30. package/src/components/cms/sections/blogs-listing-section.tsx +270 -0
  31. package/src/components/cms/sections/cards-grid-section.tsx +185 -0
  32. package/src/components/cms/sections/contact-form-section.tsx +157 -0
  33. package/src/components/cms/sections/cta-section.tsx +101 -0
  34. package/src/components/cms/sections/featured-blog-slider-section.tsx +256 -0
  35. package/src/components/cms/sections/featured-products-grid-section.tsx +173 -0
  36. package/src/components/cms/sections/featured-solutions-grid-section.tsx +183 -0
  37. package/src/components/cms/sections/hero-section.tsx +180 -0
  38. package/src/components/cms/sections/solutions-with-filter-section.tsx +234 -0
  39. package/src/components/cms/sections/text-section.tsx +77 -0
  40. package/src/components/cutout-image.tsx +228 -0
  41. package/src/components/devices/devices-mini-map.tsx +275 -0
  42. package/src/components/docs/docs-shell.tsx +280 -0
  43. package/src/components/fleet-hero-animated.tsx +383 -0
  44. package/src/components/input-error.tsx +17 -0
  45. package/src/components/keenicons/assets/duotone/Read Me.txt +7 -0
  46. package/src/components/keenicons/assets/duotone/demo-files/demo.css +160 -0
  47. package/src/components/keenicons/assets/duotone/demo-files/demo.js +32 -0
  48. package/src/components/keenicons/assets/duotone/demo.html +12424 -0
  49. package/src/components/keenicons/assets/duotone/fonts/keenicons-duotone.svg +1109 -0
  50. package/src/components/keenicons/assets/duotone/fonts/keenicons-duotone.ttf +0 -0
  51. package/src/components/keenicons/assets/duotone/fonts/keenicons-duotone.woff +0 -0
  52. package/src/components/keenicons/assets/duotone/selection.json +17313 -0
  53. package/src/components/keenicons/assets/duotone/style.css +4931 -0
  54. package/src/components/keenicons/assets/filled/Read Me.txt +7 -0
  55. package/src/components/keenicons/assets/filled/demo-files/demo.css +160 -0
  56. package/src/components/keenicons/assets/filled/demo-files/demo.js +32 -0
  57. package/src/components/keenicons/assets/filled/demo.html +12370 -0
  58. package/src/components/keenicons/assets/filled/fonts/keenicons-filled.svg +1082 -0
  59. package/src/components/keenicons/assets/filled/fonts/keenicons-filled.ttf +0 -0
  60. package/src/components/keenicons/assets/filled/fonts/keenicons-filled.woff +0 -0
  61. package/src/components/keenicons/assets/filled/selection.json +17096 -0
  62. package/src/components/keenicons/assets/filled/style.css +4769 -0
  63. package/src/components/keenicons/assets/outline/Read Me.txt +7 -0
  64. package/src/components/keenicons/assets/outline/demo-files/demo.css +160 -0
  65. package/src/components/keenicons/assets/outline/demo-files/demo.js +32 -0
  66. package/src/components/keenicons/assets/outline/demo.html +11356 -0
  67. package/src/components/keenicons/assets/outline/fonts/keenicons-outline.svg +575 -0
  68. package/src/components/keenicons/assets/outline/fonts/keenicons-outline.ttf +0 -0
  69. package/src/components/keenicons/assets/outline/fonts/keenicons-outline.woff +0 -0
  70. package/src/components/keenicons/assets/outline/selection.json +13054 -0
  71. package/src/components/keenicons/assets/outline/style.css +1721 -0
  72. package/src/components/keenicons/assets/solid/Read Me.txt +7 -0
  73. package/src/components/keenicons/assets/solid/demo-files/demo.css +160 -0
  74. package/src/components/keenicons/assets/solid/demo-files/demo.js +32 -0
  75. package/src/components/keenicons/assets/solid/demo.html +11356 -0
  76. package/src/components/keenicons/assets/solid/fonts/keenicons-solid.svg +575 -0
  77. package/src/components/keenicons/assets/solid/fonts/keenicons-solid.ttf +0 -0
  78. package/src/components/keenicons/assets/solid/fonts/keenicons-solid.woff +0 -0
  79. package/src/components/keenicons/assets/solid/selection.json +13048 -0
  80. package/src/components/keenicons/assets/solid/style.css +1721 -0
  81. package/src/components/keenicons/assets/styles.css +4 -0
  82. package/src/components/keenicons/index.ts +2 -0
  83. package/src/components/keenicons/keenicons.tsx +16 -0
  84. package/src/components/keenicons/types.ts +7 -0
  85. package/src/components/nav-footer.tsx +49 -0
  86. package/src/components/nav-main.tsx +53 -0
  87. package/src/components/nav-user.tsx +59 -0
  88. package/src/components/notification-bell.tsx +190 -0
  89. package/src/components/products/product-card.tsx +159 -0
  90. package/src/components/text-link.tsx +23 -0
  91. package/src/components/ui/accordion-menu.tsx +322 -0
  92. package/src/components/ui/accordion.tsx +133 -0
  93. package/src/components/ui/alert-dialog.tsx +82 -0
  94. package/src/components/ui/alert.tsx +63 -0
  95. package/src/components/ui/avatar-group.tsx +129 -0
  96. package/src/components/ui/avatar.tsx +67 -0
  97. package/src/components/ui/badge.tsx +230 -0
  98. package/src/components/ui/breadcrumb.tsx +88 -0
  99. package/src/components/ui/button.tsx +412 -0
  100. package/src/components/ui/calendar.tsx +56 -0
  101. package/src/components/ui/card.tsx +147 -0
  102. package/src/components/ui/chart.tsx +290 -0
  103. package/src/components/ui/checkbox.tsx +47 -0
  104. package/src/components/ui/code.tsx +45 -0
  105. package/src/components/ui/collapsible.tsx +31 -0
  106. package/src/components/ui/command-palette.tsx +189 -0
  107. package/src/components/ui/command.tsx +138 -0
  108. package/src/components/ui/cookie-banner.tsx +220 -0
  109. package/src/components/ui/copy-button.tsx +60 -0
  110. package/src/components/ui/data-grid-column-filter.tsx +124 -0
  111. package/src/components/ui/data-grid-column-header.tsx +284 -0
  112. package/src/components/ui/data-grid-column-visibility.tsx +38 -0
  113. package/src/components/ui/data-grid-pagination.tsx +206 -0
  114. package/src/components/ui/data-grid-table-dnd-rows.tsx +147 -0
  115. package/src/components/ui/data-grid-table-dnd.tsx +175 -0
  116. package/src/components/ui/data-grid-table.tsx +500 -0
  117. package/src/components/ui/data-grid.tsx +193 -0
  118. package/src/components/ui/data-list.tsx +76 -0
  119. package/src/components/ui/datefield.tsx +91 -0
  120. package/src/components/ui/dialog.tsx +139 -0
  121. package/src/components/ui/divider.tsx +41 -0
  122. package/src/components/ui/drawer.tsx +59 -0
  123. package/src/components/ui/dropdown-menu.tsx +224 -0
  124. package/src/components/ui/empty-state.tsx +54 -0
  125. package/src/components/ui/file-upload.tsx +152 -0
  126. package/src/components/ui/form.tsx +88 -0
  127. package/src/components/ui/icon.tsx +14 -0
  128. package/src/components/ui/input-otp.tsx +71 -0
  129. package/src/components/ui/input.tsx +155 -0
  130. package/src/components/ui/kbd.tsx +26 -0
  131. package/src/components/ui/label.tsx +31 -0
  132. package/src/components/ui/navigation-menu.tsx +168 -0
  133. package/src/components/ui/pagination.tsx +37 -0
  134. package/src/components/ui/placeholder-pattern.tsx +21 -0
  135. package/src/components/ui/popover.tsx +50 -0
  136. package/src/components/ui/progress.tsx +65 -0
  137. package/src/components/ui/radio-group.tsx +73 -0
  138. package/src/components/ui/resizable.tsx +39 -0
  139. package/src/components/ui/scroll-area.tsx +50 -0
  140. package/src/components/ui/select.tsx +234 -0
  141. package/src/components/ui/separator.tsx +24 -0
  142. package/src/components/ui/sheet.tsx +147 -0
  143. package/src/components/ui/sidebar.tsx +721 -0
  144. package/src/components/ui/skeleton.tsx +15 -0
  145. package/src/components/ui/slider.tsx +35 -0
  146. package/src/components/ui/sonner.tsx +28 -0
  147. package/src/components/ui/sortable.tsx +724 -0
  148. package/src/components/ui/spinner.tsx +17 -0
  149. package/src/components/ui/stat-card.tsx +82 -0
  150. package/src/components/ui/stepper.tsx +410 -0
  151. package/src/components/ui/switch.tsx +68 -0
  152. package/src/components/ui/table.tsx +42 -0
  153. package/src/components/ui/tabs.tsx +196 -0
  154. package/src/components/ui/timeline.tsx +90 -0
  155. package/src/components/ui/toggle-group.tsx +73 -0
  156. package/src/components/ui/toggle.tsx +45 -0
  157. package/src/components/ui/tooltip.tsx +55 -0
  158. package/src/components/user-info.tsx +33 -0
  159. package/src/components/user-menu-content.tsx +53 -0
  160. package/src/components/web/SiteFooter.tsx +154 -0
  161. package/src/components/web/SiteHeader.tsx +159 -0
  162. package/src/components/workflows/workflow-canvas.tsx +321 -0
  163. package/src/controls/Blockquote.tsx +25 -0
  164. package/src/controls/Button.tsx +101 -0
  165. package/src/controls/Checkbox.tsx +29 -0
  166. package/src/controls/DateField.tsx +37 -0
  167. package/src/controls/FormField.tsx +20 -0
  168. package/src/controls/Heading.tsx +28 -0
  169. package/src/controls/Input.tsx +21 -0
  170. package/src/controls/Label.tsx +18 -0
  171. package/src/controls/Paragraph.tsx +39 -0
  172. package/src/controls/PasswordInput.tsx +40 -0
  173. package/src/controls/RadioGroup.tsx +70 -0
  174. package/src/controls/Select.tsx +24 -0
  175. package/src/controls/Slider.tsx +33 -0
  176. package/src/controls/Switch.tsx +31 -0
  177. package/src/controls/Textarea.tsx +22 -0
  178. package/src/elements/ConfirmPasswordForm.tsx +43 -0
  179. package/src/elements/DeviceStatusBadge.tsx +38 -0
  180. package/src/elements/DriverCard.tsx +67 -0
  181. package/src/elements/ForgotPasswordForm.tsx +64 -0
  182. package/src/elements/IncidentCard.tsx +67 -0
  183. package/src/elements/LoginForm.tsx +100 -0
  184. package/src/elements/OtpForm.tsx +71 -0
  185. package/src/elements/RegisterForm.tsx +150 -0
  186. package/src/elements/ResetPasswordForm.tsx +72 -0
  187. package/src/elements/SmsChallengeForm.tsx +104 -0
  188. package/src/elements/VehicleCard.tsx +73 -0
  189. package/src/elements/VerifyEmailForm.tsx +39 -0
  190. package/src/hooks/use-appearance.tsx +117 -0
  191. package/src/hooks/use-applied-theme.ts +98 -0
  192. package/src/hooks/use-clipboard.ts +34 -0
  193. package/src/hooks/use-current-url.ts +83 -0
  194. package/src/hooks/use-dark-mode.ts +48 -0
  195. package/src/hooks/use-flash-toast.ts +29 -0
  196. package/src/hooks/use-initials.tsx +24 -0
  197. package/src/hooks/use-mobile-navigation.ts +12 -0
  198. package/src/hooks/use-mobile.tsx +38 -0
  199. package/src/index.ts +408 -0
  200. package/src/layouts/AppLayout.tsx +60 -0
  201. package/src/layouts/AuthLayout.tsx +32 -0
  202. package/src/layouts/SettingsLayout.tsx +21 -0
  203. package/src/layouts/app/AIChatLayout.tsx +73 -0
  204. package/src/layouts/app/AsideSidebarLayout.tsx +3 -0
  205. package/src/layouts/app/CalendarSidebarLayout.tsx +69 -0
  206. package/src/layouts/app/CommunitiesNavbarLayout.tsx +3 -0
  207. package/src/layouts/app/DualNavbarSidebarLayout.tsx +3 -0
  208. package/src/layouts/app/FocusSidebarLayout.tsx +75 -0
  209. package/src/layouts/app/MailLayout.tsx +69 -0
  210. package/src/layouts/app/MegaMenuHeaderLayout.tsx +3 -0
  211. package/src/layouts/app/MegaMenuLayout.tsx +81 -0
  212. package/src/layouts/app/MegaMenuNavbarLayout.tsx +88 -0
  213. package/src/layouts/app/MegaMenuSearchNavbarLayout.tsx +3 -0
  214. package/src/layouts/app/NavbarCollapsibleLayout.tsx +88 -0
  215. package/src/layouts/app/NavbarCollapsibleLinksLayout.tsx +3 -0
  216. package/src/layouts/app/NavbarMinimalLayout.tsx +3 -0
  217. package/src/layouts/app/NavbarMinimalSidebarLayout.tsx +3 -0
  218. package/src/layouts/app/NavbarSidebarDashboardLayout.tsx +3 -0
  219. package/src/layouts/app/NavbarSidebarLayout.tsx +92 -0
  220. package/src/layouts/app/NavbarSimpleSidebarLayout.tsx +3 -0
  221. package/src/layouts/app/NavbarTitledSidebarLayout.tsx +3 -0
  222. package/src/layouts/app/PanelSidebarLayout.tsx +3 -0
  223. package/src/layouts/app/SearchNavbarSidebarLayout.tsx +3 -0
  224. package/src/layouts/app/SidebarBreadcrumbLayout.tsx +3 -0
  225. package/src/layouts/app/SidebarCleanLayout.tsx +3 -0
  226. package/src/layouts/app/SidebarCommunitiesLayout.tsx +3 -0
  227. package/src/layouts/app/SidebarContentLayout.tsx +3 -0
  228. package/src/layouts/app/SidebarDualMenuLayout.tsx +104 -0
  229. package/src/layouts/app/SidebarFixedLayout.tsx +166 -0
  230. package/src/layouts/app/SidebarFooterNavbarLayout.tsx +3 -0
  231. package/src/layouts/app/SidebarHeaderMenuLayout.tsx +3 -0
  232. package/src/layouts/app/SidebarMegaMenuLayout.tsx +4 -0
  233. package/src/layouts/app/SidebarMinimalLayout.tsx +70 -0
  234. package/src/layouts/app/SidebarMobileSearchLayout.tsx +3 -0
  235. package/src/layouts/app/SidebarMultiPanelLayout.tsx +3 -0
  236. package/src/layouts/app/SidebarPrimarySecondaryLayout.tsx +3 -0
  237. package/src/layouts/app/SidebarSearchHeaderLayout.tsx +103 -0
  238. package/src/layouts/app/SidebarSearchToolbarLayout.tsx +3 -0
  239. package/src/layouts/app/SidebarTabsDualLayout.tsx +3 -0
  240. package/src/layouts/app/SidebarTabsLayout.tsx +98 -0
  241. package/src/layouts/app/SidebarTreeLayout.tsx +3 -0
  242. package/src/layouts/app/SplitNavbarLayout.tsx +3 -0
  243. package/src/layouts/app/SplitSidebarDashboardLayout.tsx +3 -0
  244. package/src/layouts/app/SplitSidebarLayout.tsx +99 -0
  245. package/src/layouts/app/TopNavLayout.tsx +105 -0
  246. package/src/layouts/app/TopNavLinksLayout.tsx +3 -0
  247. package/src/layouts/app/WorkspaceBreadcrumbLayout.tsx +3 -0
  248. package/src/layouts/app/WorkspaceCommunitiesLayout.tsx +3 -0
  249. package/src/layouts/app/WorkspaceNavbarLayout.tsx +3 -0
  250. package/src/layouts/app/WorkspaceSidebarLayout.tsx +98 -0
  251. package/src/layouts/app/WorkspaceSidebarTitleLayout.tsx +3 -0
  252. package/src/layouts/app/app-header-layout.tsx +45 -0
  253. package/src/layouts/app/app-sidebar-layout.tsx +56 -0
  254. package/src/layouts/app/layout-context.tsx +44 -0
  255. package/src/layouts/app/layout-types.ts +47 -0
  256. package/src/layouts/app/partials/Footer.tsx +35 -0
  257. package/src/layouts/app/partials/HeaderTopbar.tsx +96 -0
  258. package/src/layouts/app/partials/Navbar.tsx +85 -0
  259. package/src/layouts/app/partials/Toolbar.tsx +47 -0
  260. package/src/layouts/app-layout.tsx +29 -0
  261. package/src/layouts/auth/AuthBrandedLayout.tsx +58 -0
  262. package/src/layouts/auth/AuthCardLayout.tsx +31 -0
  263. package/src/layouts/auth/AuthCenteredLayout.tsx +41 -0
  264. package/src/layouts/auth/AuthClassicLayout.tsx +41 -0
  265. package/src/layouts/auth/AuthSimpleLayout.tsx +33 -0
  266. package/src/layouts/auth/AuthSplitLayout.tsx +89 -0
  267. package/src/layouts/web-app-layout.tsx +162 -0
  268. package/src/layouts/web-layout.tsx +23 -0
  269. package/src/lib/datetime.ts +188 -0
  270. package/src/lib/google-maps-loader.ts +99 -0
  271. package/src/lib/location.ts +127 -0
  272. package/src/lib/lucide-icon-map.ts +132 -0
  273. package/src/lib/map-markers.ts +124 -0
  274. package/src/lib/map-styles.ts +351 -0
  275. package/src/lib/utils.ts +11 -0
  276. package/src/platform/adapters/default.tsx +156 -0
  277. package/src/platform/adapters/inertia.tsx +88 -0
  278. package/src/platform/adapters/nextjs.ts +86 -0
  279. package/src/platform/context.tsx +106 -0
  280. package/src/platform/index.ts +27 -0
  281. package/src/platform/types.ts +105 -0
  282. package/src/styles/layouts/sidebar-fixed.css +161 -0
  283. package/src/styles/themes.css +583 -0
  284. package/src/types/assets.d.ts +5 -0
  285. package/src/types/auth.ts +25 -0
  286. package/src/types/global.d.ts +13 -0
  287. package/src/types/index.ts +9 -0
  288. package/src/types/navigation.ts +15 -0
  289. package/src/types/ui.ts +32 -0
package/package.json ADDED
@@ -0,0 +1,185 @@
1
+ {
2
+ "name": "@trackany-device/components",
3
+ "version": "1.0.0",
4
+ "description": "Shared React components for the Track Any Device platform.",
5
+ "license": "UNLICENSED",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
10
+ "sideEffects": [
11
+ "**/*.css"
12
+ ],
13
+ "main": "./src/index.ts",
14
+ "types": "./src/index.ts",
15
+ "exports": {
16
+ ".": "./src/index.ts",
17
+ "./styles/*": "./src/styles/*",
18
+ "./styles/keenicons.css": "./src/components/keenicons/assets/styles.css"
19
+ },
20
+ "files": [
21
+ "src",
22
+ "!src/**/*.test.*",
23
+ "!src/**/*.spec.*",
24
+ "!src/**/.DS_Store"
25
+ ],
26
+ "scripts": {
27
+ "storybook": "storybook dev -p 6006",
28
+ "build-storybook": "storybook build",
29
+ "types:check": "tsc --noEmit",
30
+ "types:watch": "tsc --noEmit --watch",
31
+ "release": "semantic-release",
32
+ "release:dry": "semantic-release --dry-run"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public",
36
+ "registry": "https://registry.npmjs.org"
37
+ },
38
+ "dependencies": {
39
+ "class-variance-authority": "^0.7.1",
40
+ "clsx": "^2.1.1",
41
+ "tailwind-merge": "^3.0.0"
42
+ },
43
+ "peerDependencies": {
44
+ "@dnd-kit/core": "^6.3.1",
45
+ "@dnd-kit/modifiers": "^9.0.0",
46
+ "@dnd-kit/sortable": "^10.0.0",
47
+ "@dnd-kit/utilities": "^3.2.2",
48
+ "@googlemaps/js-api-loader": "^2.0.0",
49
+ "@hookform/resolvers": "^5.2.1",
50
+ "@radix-ui/react-accordion": "^1.2.0",
51
+ "@radix-ui/react-alert-dialog": "^1.1.0",
52
+ "@radix-ui/react-aspect-ratio": "^1.1.0",
53
+ "@radix-ui/react-avatar": "^1.1.0",
54
+ "@radix-ui/react-checkbox": "^1.1.0",
55
+ "@radix-ui/react-collapsible": "^1.1.0",
56
+ "@radix-ui/react-dialog": "^1.1.0",
57
+ "@radix-ui/react-dropdown-menu": "^2.1.0",
58
+ "@radix-ui/react-hover-card": "^1.1.0",
59
+ "@radix-ui/react-label": "^2.1.0",
60
+ "@radix-ui/react-navigation-menu": "^1.2.0",
61
+ "@radix-ui/react-popover": "^1.1.0",
62
+ "@radix-ui/react-progress": "^1.1.0",
63
+ "@radix-ui/react-radio-group": "^1.2.0",
64
+ "@radix-ui/react-scroll-area": "^1.2.0",
65
+ "@radix-ui/react-select": "^2.1.0",
66
+ "@radix-ui/react-separator": "^1.1.0",
67
+ "@radix-ui/react-slider": "^1.2.0",
68
+ "@radix-ui/react-slot": "^1.1.0",
69
+ "@radix-ui/react-switch": "^1.1.0",
70
+ "@radix-ui/react-tabs": "^1.1.0",
71
+ "@radix-ui/react-toggle": "^1.1.0",
72
+ "@radix-ui/react-toggle-group": "^1.1.0",
73
+ "@radix-ui/react-tooltip": "^1.1.0",
74
+ "@tanstack/react-table": "^8.21.3",
75
+ "@xyflow/react": "^12.0.0",
76
+ "cmdk": "^1.1.1",
77
+ "date-fns": "^4.1.0",
78
+ "input-otp": "^1.4.2",
79
+ "lucide-react": "^0.541.0",
80
+ "motion": "^12.0.0",
81
+ "react": "^19.0.0",
82
+ "react-aria-components": "^1.12.0",
83
+ "react-day-picker": "^9.9.0",
84
+ "react-dom": "^19.0.0",
85
+ "react-hook-form": "^7.68.0",
86
+ "react-resizable-panels": "^3.0.5",
87
+ "recharts": "^2.15.1",
88
+ "sonner": "^2.0.7",
89
+ "tw-animate-css": "^1.4.0",
90
+ "vaul": "^1.1.2",
91
+ "zod": "^3.25.67"
92
+ },
93
+ "peerDependenciesMeta": {
94
+ "@dnd-kit/core": {
95
+ "optional": true
96
+ },
97
+ "@dnd-kit/modifiers": {
98
+ "optional": true
99
+ },
100
+ "@dnd-kit/sortable": {
101
+ "optional": true
102
+ },
103
+ "@dnd-kit/utilities": {
104
+ "optional": true
105
+ },
106
+ "@googlemaps/js-api-loader": {
107
+ "optional": true
108
+ },
109
+ "@xyflow/react": {
110
+ "optional": true
111
+ },
112
+ "recharts": {
113
+ "optional": true
114
+ },
115
+ "tw-animate-css": {
116
+ "optional": true
117
+ }
118
+ },
119
+ "devDependencies": {
120
+ "@dnd-kit/core": "^6.3.1",
121
+ "@dnd-kit/modifiers": "^9.0.0",
122
+ "@dnd-kit/sortable": "^10.0.0",
123
+ "@dnd-kit/utilities": "^3.2.2",
124
+ "@googlemaps/js-api-loader": "^2.0.0",
125
+ "@hookform/resolvers": "^5.2.1",
126
+ "@radix-ui/react-accordion": "^1.2.0",
127
+ "@radix-ui/react-alert-dialog": "^1.1.0",
128
+ "@radix-ui/react-aspect-ratio": "^1.1.0",
129
+ "@radix-ui/react-avatar": "^1.1.0",
130
+ "@radix-ui/react-checkbox": "^1.1.0",
131
+ "@radix-ui/react-collapsible": "^1.1.0",
132
+ "@radix-ui/react-dialog": "^1.1.0",
133
+ "@radix-ui/react-dropdown-menu": "^2.1.0",
134
+ "@radix-ui/react-hover-card": "^1.1.0",
135
+ "@radix-ui/react-label": "^2.1.0",
136
+ "@radix-ui/react-navigation-menu": "^1.2.0",
137
+ "@radix-ui/react-popover": "^1.1.0",
138
+ "@radix-ui/react-progress": "^1.1.0",
139
+ "@radix-ui/react-radio-group": "^1.2.0",
140
+ "@radix-ui/react-scroll-area": "^1.2.0",
141
+ "@radix-ui/react-select": "^2.1.0",
142
+ "@radix-ui/react-separator": "^1.1.0",
143
+ "@radix-ui/react-slider": "^1.2.0",
144
+ "@radix-ui/react-slot": "^1.1.0",
145
+ "@radix-ui/react-switch": "^1.1.0",
146
+ "@radix-ui/react-tabs": "^1.1.0",
147
+ "@radix-ui/react-toggle": "^1.1.0",
148
+ "@radix-ui/react-toggle-group": "^1.1.0",
149
+ "@radix-ui/react-tooltip": "^1.1.0",
150
+ "@semantic-release/changelog": "^6.0.3",
151
+ "@semantic-release/git": "^10.0.1",
152
+ "@storybook/addon-essentials": "^8.6.18",
153
+ "@storybook/addon-interactions": "^8.6.18",
154
+ "@storybook/react": "^8.6.18",
155
+ "@storybook/react-vite": "^8.6.18",
156
+ "@storybook/test": "^8.6.18",
157
+ "@tailwindcss/vite": "^4.3.0",
158
+ "@tanstack/react-table": "^8.21.3",
159
+ "@types/react": "^19.0.0",
160
+ "@types/react-dom": "^19.0.0",
161
+ "@vitejs/plugin-react": "^4.7.0",
162
+ "@xyflow/react": "^12.0.0",
163
+ "cmdk": "^1.1.1",
164
+ "date-fns": "^4.1.0",
165
+ "input-otp": "^1.4.2",
166
+ "lucide-react": "^0.541.0",
167
+ "motion": "^12.0.0",
168
+ "react": "^19.0.0",
169
+ "react-aria-components": "^1.12.0",
170
+ "react-day-picker": "^9.9.0",
171
+ "react-dom": "^19.0.0",
172
+ "react-hook-form": "^7.68.0",
173
+ "react-resizable-panels": "^3.0.5",
174
+ "recharts": "^2.15.1",
175
+ "semantic-release": "^24.2.9",
176
+ "sonner": "^2.0.7",
177
+ "storybook": "^8.6.18",
178
+ "tailwindcss": "^4.3.0",
179
+ "tw-animate-css": "^1.4.0",
180
+ "typescript": "^5.0.0",
181
+ "vaul": "^1.1.2",
182
+ "vite": "^6.4.2",
183
+ "zod": "^3.25.67"
184
+ }
185
+ }
Binary file
@@ -0,0 +1,9 @@
1
+ // Re-export the ShadCN-compatible Card primitives from ui/card
2
+ export {
3
+ Card,
4
+ CardHeader,
5
+ CardTitle,
6
+ CardDescription,
7
+ CardContent,
8
+ CardFooter,
9
+ } from './ui/card';
@@ -0,0 +1,24 @@
1
+ import { AlertCircleIcon } from 'lucide-react';
2
+ import { Alert, AlertDescription, AlertTitle } from './ui/alert';
3
+
4
+ export default function AlertError({
5
+ errors,
6
+ title,
7
+ }: {
8
+ errors: string[];
9
+ title?: string;
10
+ }) {
11
+ return (
12
+ <Alert variant="destructive">
13
+ <AlertCircleIcon />
14
+ <AlertTitle>{title || 'Something went wrong.'}</AlertTitle>
15
+ <AlertDescription>
16
+ <ul className="list-inside list-disc text-sm">
17
+ {Array.from(new Set(errors)).map((error, index) => (
18
+ <li key={index}>{error}</li>
19
+ ))}
20
+ </ul>
21
+ </AlertDescription>
22
+ </Alert>
23
+ );
24
+ }
@@ -0,0 +1,22 @@
1
+ import * as React from 'react';
2
+ import { SidebarInset } from './ui/sidebar';
3
+ import type { AppVariant } from '../types/ui';
4
+
5
+ type Props = React.ComponentProps<'main'> & {
6
+ variant?: AppVariant;
7
+ };
8
+
9
+ export function AppContent({ variant = 'sidebar', children, ...props }: Props) {
10
+ if (variant === 'sidebar') {
11
+ return <SidebarInset {...props}>{children}</SidebarInset>;
12
+ }
13
+
14
+ return (
15
+ <main
16
+ className="mx-auto flex h-full w-full max-w-7xl flex-1 flex-col gap-4 rounded-md"
17
+ {...props}
18
+ >
19
+ {children}
20
+ </main>
21
+ );
22
+ }
@@ -0,0 +1,153 @@
1
+ 'use client';
2
+ import { PlatformLink } from '../platform/context';
3
+ import { Menu, Search } from 'lucide-react';
4
+ import AppLogo from './app-logo';
5
+ import { Breadcrumbs } from './breadcrumbs';
6
+ import { NotificationBell } from './notification-bell';
7
+ import { UserMenuContent } from './user-menu-content';
8
+ import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar';
9
+ import { Button } from './ui/button';
10
+ import {
11
+ DropdownMenu,
12
+ DropdownMenuContent,
13
+ DropdownMenuTrigger,
14
+ } from './ui/dropdown-menu';
15
+ import {
16
+ NavigationMenu,
17
+ NavigationMenuItem,
18
+ NavigationMenuList,
19
+ navigationMenuTriggerStyle,
20
+ } from './ui/navigation-menu';
21
+ import {
22
+ Sheet,
23
+ SheetContent,
24
+ SheetHeader,
25
+ SheetTitle,
26
+ SheetTrigger,
27
+ } from './ui/sheet';
28
+ import { useCurrentUrl } from '../hooks/use-current-url';
29
+ import { useInitials } from '../hooks/use-initials';
30
+ import { cn } from '../lib/utils';
31
+ import type { BreadcrumbItem, NavItem } from '../types/navigation';
32
+ import type { User } from '../types/auth';
33
+
34
+ const activeItemStyles = 'text-neutral-900 dark:bg-neutral-800 dark:text-neutral-100';
35
+
36
+ type Props = {
37
+ breadcrumbs?: BreadcrumbItem[];
38
+ user?: User | null;
39
+ navItems?: NavItem[];
40
+ dashboardHref?: string;
41
+ unreadCount?: number;
42
+ settingsUrl?: string;
43
+ logoutUrl?: string;
44
+ };
45
+
46
+ export function AppHeader({
47
+ breadcrumbs = [],
48
+ user,
49
+ navItems = [],
50
+ dashboardHref = '/dashboard',
51
+ unreadCount = 0,
52
+ settingsUrl = '/settings/profile',
53
+ logoutUrl = '/logout',
54
+ }: Props) {
55
+ const getInitials = useInitials();
56
+ const { isCurrentUrl, whenCurrentUrl } = useCurrentUrl();
57
+
58
+ return (
59
+ <>
60
+ <div className="border-b border-sidebar-border/80">
61
+ <div className="mx-auto flex h-16 items-center px-4 md:max-w-7xl">
62
+ <div className="lg:hidden">
63
+ <Sheet>
64
+ <SheetTrigger asChild>
65
+ <Button variant="ghost" size="icon" className="mr-2 h-[34px] w-[34px]">
66
+ <Menu className="h-5 w-5" />
67
+ </Button>
68
+ </SheetTrigger>
69
+ <SheetContent side="left" className="flex h-full w-64 flex-col items-stretch justify-between bg-sidebar">
70
+ <SheetTitle className="sr-only">Navigation menu</SheetTitle>
71
+ <SheetHeader className="flex justify-start text-left">
72
+ <AppLogo className="h-6 w-6 fill-current text-black dark:text-white" />
73
+ </SheetHeader>
74
+ <div className="flex h-full flex-1 flex-col space-y-4 p-4">
75
+ <div className="flex flex-col space-y-4">
76
+ {navItems.map((item) => (
77
+ <PlatformLink key={item.title} href={item.href} className="flex items-center space-x-2 font-medium">
78
+ {item.icon && <item.icon className="h-5 w-5" />}
79
+ <span>{item.title}</span>
80
+ </PlatformLink>
81
+ ))}
82
+ </div>
83
+ </div>
84
+ </SheetContent>
85
+ </Sheet>
86
+ </div>
87
+
88
+ <PlatformLink href={dashboardHref} prefetch className="flex items-center space-x-2">
89
+ <AppLogo />
90
+ </PlatformLink>
91
+
92
+ <div className="ml-6 hidden h-full items-center space-x-6 lg:flex">
93
+ <NavigationMenu className="flex h-full items-stretch">
94
+ <NavigationMenuList className="flex h-full items-stretch space-x-2">
95
+ {navItems.map((item, index) => (
96
+ <NavigationMenuItem key={index} className="relative flex h-full items-center">
97
+ <PlatformLink
98
+ href={item.href}
99
+ className={cn(
100
+ navigationMenuTriggerStyle(),
101
+ whenCurrentUrl(item.href, activeItemStyles),
102
+ 'h-9 cursor-pointer px-3',
103
+ )}
104
+ >
105
+ {item.icon && <item.icon className="mr-2 h-4 w-4" />}
106
+ {item.title}
107
+ </PlatformLink>
108
+ {isCurrentUrl(item.href) && (
109
+ <div className="absolute bottom-0 left-0 h-0.5 w-full translate-y-px bg-black dark:bg-white" />
110
+ )}
111
+ </NavigationMenuItem>
112
+ ))}
113
+ </NavigationMenuList>
114
+ </NavigationMenu>
115
+ </div>
116
+
117
+ <div className="ml-auto flex items-center space-x-2">
118
+ <div className="relative flex items-center space-x-1">
119
+ <Button variant="ghost" size="icon" className="group h-9 w-9 cursor-pointer">
120
+ <Search className="!size-5 opacity-80 group-hover:opacity-100" />
121
+ </Button>
122
+ <NotificationBell unreadCount={unreadCount} />
123
+ </div>
124
+ {user && (
125
+ <DropdownMenu>
126
+ <DropdownMenuTrigger asChild>
127
+ <Button variant="ghost" className="size-10 rounded-full p-1">
128
+ <Avatar className="size-8 overflow-hidden rounded-full">
129
+ <AvatarImage src={user.avatar} alt={user.name} />
130
+ <AvatarFallback className="rounded-lg bg-neutral-200 text-black dark:bg-neutral-700 dark:text-white">
131
+ {getInitials(user.name)}
132
+ </AvatarFallback>
133
+ </Avatar>
134
+ </Button>
135
+ </DropdownMenuTrigger>
136
+ <DropdownMenuContent className="w-56" align="end">
137
+ <UserMenuContent user={user} settingsUrl={settingsUrl} logoutUrl={logoutUrl} />
138
+ </DropdownMenuContent>
139
+ </DropdownMenu>
140
+ )}
141
+ </div>
142
+ </div>
143
+ </div>
144
+ {breadcrumbs.length > 1 && (
145
+ <div className="flex w-full border-b border-sidebar-border/70">
146
+ <div className="mx-auto flex h-12 w-full items-center justify-start px-4 text-neutral-500 md:max-w-7xl">
147
+ <Breadcrumbs breadcrumbs={breadcrumbs} />
148
+ </div>
149
+ </div>
150
+ )}
151
+ </>
152
+ );
153
+ }
@@ -0,0 +1,13 @@
1
+ import type { SVGAttributes } from 'react';
2
+
3
+ export default function AppLogoIcon(props: SVGAttributes<SVGElement>) {
4
+ return (
5
+ <svg {...props} viewBox="0 0 40 42" xmlns="http://www.w3.org/2000/svg">
6
+ <path
7
+ fillRule="evenodd"
8
+ clipRule="evenodd"
9
+ d="M17.2 5.63325L8.6 0.855469L0 5.63325V32.1434L16.2 41.1434L32.4 32.1434V23.699L40 19.4767V9.85547L31.4 5.07769L22.8 9.85547V18.2999L17.2 21.411V5.63325ZM38 18.2999L32.4 21.411V15.2545L38 12.1434V18.2999ZM36.9409 10.4439L31.4 13.5221L25.8591 10.4439L31.4 7.36561L36.9409 10.4439ZM24.8 18.2999V12.1434L30.4 15.2545V21.411L24.8 18.2999ZM23.8 20.0323L29.3409 23.1105L16.2 30.411L10.6591 27.3328L23.8 20.0323ZM7.6 27.9212L15.2 32.1434V38.2999L2 30.9666V7.92116L7.6 11.0323V27.9212ZM8.6 9.29991L3.05913 6.22165L8.6 3.14339L14.1409 6.22165L8.6 9.29991ZM30.4 24.8101L17.2 32.1434V38.2999L30.4 30.9666V24.8101ZM9.6 11.0323L15.2 7.92117V22.5221L9.6 25.6333V11.0323Z"
10
+ />
11
+ </svg>
12
+ );
13
+ }
@@ -0,0 +1,21 @@
1
+ import logoUrl from '../assets/logo.png';
2
+
3
+ export default function AppLogo({
4
+ className,
5
+ src,
6
+ alt = 'Logo',
7
+ ...props
8
+ }: React.ComponentProps<'div'> & { src?: string; alt?: string }) {
9
+ return (
10
+ <div
11
+ className={`flex items-center gap-2${className ? ` ${className}` : ''}`}
12
+ {...props}
13
+ >
14
+ <img
15
+ src={src ?? logoUrl}
16
+ alt={alt}
17
+ className="h-8 max-w-[120px] object-contain group-data-[collapsible=icon]:hidden"
18
+ />
19
+ </div>
20
+ );
21
+ }
@@ -0,0 +1,19 @@
1
+ import type { ReactNode } from 'react';
2
+ import { SidebarProvider } from './ui/sidebar';
3
+ import type { AppVariant } from '../types/ui';
4
+
5
+ type Props = {
6
+ children: ReactNode;
7
+ variant?: AppVariant;
8
+ defaultOpen?: boolean;
9
+ };
10
+
11
+ export function AppShell({ children, variant = 'sidebar', defaultOpen = true }: Props) {
12
+ if (variant === 'header') {
13
+ return (
14
+ <div className="flex min-h-screen w-full flex-col">{children}</div>
15
+ );
16
+ }
17
+
18
+ return <SidebarProvider defaultOpen={defaultOpen}>{children}</SidebarProvider>;
19
+ }
@@ -0,0 +1,68 @@
1
+ 'use client';
2
+ import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar';
3
+ import {
4
+ DropdownMenu,
5
+ DropdownMenuContent,
6
+ DropdownMenuTrigger,
7
+ } from './ui/dropdown-menu';
8
+ import { SidebarTrigger } from './ui/sidebar';
9
+ import { Breadcrumbs } from './breadcrumbs';
10
+ import { NotificationBell } from './notification-bell';
11
+ import { UserMenuContent } from './user-menu-content';
12
+ import { useInitials } from '../hooks/use-initials';
13
+ import type { BreadcrumbItem } from '../types/navigation';
14
+ import type { User } from '../types/auth';
15
+
16
+ export function AppSidebarHeader({
17
+ breadcrumbs = [],
18
+ user,
19
+ unreadCount = 0,
20
+ settingsUrl = '/settings/profile',
21
+ logoutUrl = '/logout',
22
+ }: {
23
+ breadcrumbs?: BreadcrumbItem[];
24
+ user?: User | null;
25
+ unreadCount?: number;
26
+ settingsUrl?: string;
27
+ logoutUrl?: string;
28
+ }) {
29
+ const getInitials = useInitials();
30
+
31
+ return (
32
+ <header className="flex h-14 shrink-0 items-center justify-between gap-2 border-b border-border bg-background px-4 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12">
33
+ <div className="flex items-center gap-2">
34
+ <SidebarTrigger className="-ml-1 text-muted-foreground hover:text-foreground" />
35
+ <Breadcrumbs breadcrumbs={breadcrumbs} />
36
+ </div>
37
+
38
+ <div className="flex items-center gap-1">
39
+ <NotificationBell unreadCount={unreadCount} />
40
+
41
+ {user && (
42
+ <DropdownMenu>
43
+ <DropdownMenuTrigger asChild>
44
+ <button className="flex items-center gap-2 rounded-lg px-2 py-1 text-sm text-foreground hover:bg-accent hover:text-accent-foreground">
45
+ <Avatar className="size-7 overflow-hidden rounded-full">
46
+ <AvatarImage src={user.avatar} alt={user.name} />
47
+ <AvatarFallback className="rounded-full bg-primary text-[11px] font-semibold text-primary-foreground">
48
+ {getInitials(user.name)}
49
+ </AvatarFallback>
50
+ </Avatar>
51
+ <span className="hidden max-w-32 truncate font-medium sm:block">
52
+ {user.name}
53
+ </span>
54
+ </button>
55
+ </DropdownMenuTrigger>
56
+ <DropdownMenuContent className="w-56" align="end">
57
+ <UserMenuContent
58
+ user={user}
59
+ settingsUrl={settingsUrl}
60
+ logoutUrl={logoutUrl}
61
+ />
62
+ </DropdownMenuContent>
63
+ </DropdownMenu>
64
+ )}
65
+ </div>
66
+ </header>
67
+ );
68
+ }
@@ -0,0 +1,106 @@
1
+ import { PlatformLink } from '../platform/context';
2
+ import {
3
+ AlertTriangle, History, LayoutGrid, MapPin, MonitorPlay,
4
+ Settings, Shield, Smartphone, Terminal, Users, UserSquare2, Workflow,
5
+ } from 'lucide-react';
6
+ import AppLogo from './app-logo';
7
+ import { NavMain } from './nav-main';
8
+ import { NavUser } from './nav-user';
9
+ import {
10
+ Sidebar, SidebarContent, SidebarFooter, SidebarHeader,
11
+ SidebarMenu, SidebarMenuButton, SidebarMenuItem,
12
+ } from './ui/sidebar';
13
+ import type { NavItem } from '../types/navigation';
14
+ import type { User } from '../types/auth';
15
+
16
+ export const DEFAULT_TENANT_NAV: NavItem[] = [
17
+ { title: 'Live Monitoring', href: '/map', icon: MonitorPlay },
18
+ { title: 'Assignees', href: '/assignees', icon: Users },
19
+ { title: 'Alerts & Incidents', href: '/incidents', icon: AlertTriangle },
20
+ { title: 'Beats & Boundaries', href: '/beats', icon: MapPin },
21
+ { title: 'Assignments', href: '/assignments', icon: Shield },
22
+ { title: 'Playback History', href: '/playback', icon: History },
23
+ { title: 'Devices', href: '/devices', icon: Smartphone },
24
+ { title: 'Supervisors & Teams', href: '/supervisors', icon: UserSquare2 },
25
+ { title: 'Workflows', href: '/workflows', icon: Workflow },
26
+ { title: 'Device Logs', href: '/device-logs', icon: Terminal },
27
+ { title: 'Settings', href: '/settings/organization', icon: Settings },
28
+ ];
29
+
30
+ export function AppSidebar({
31
+ navItems,
32
+ dashboardItem,
33
+ user,
34
+ tenant,
35
+ settingsUrl = '/settings/profile',
36
+ logoutUrl = '/logout',
37
+ dashboardHref = '/dashboard',
38
+ }: {
39
+ navItems?: NavItem[];
40
+ dashboardItem?: NavItem;
41
+ user?: User | null;
42
+ tenant?: { display_name?: string | null; sub_brand?: string | null } | null;
43
+ settingsUrl?: string;
44
+ logoutUrl?: string;
45
+ dashboardHref?: string;
46
+ }) {
47
+ const items = navItems ?? DEFAULT_TENANT_NAV;
48
+ const dashboard: NavItem = dashboardItem ?? { title: 'Dashboard', href: dashboardHref, icon: LayoutGrid };
49
+ const allItems = [dashboard, ...items];
50
+
51
+ const appName =
52
+ (typeof window !== 'undefined' && (window as any).AppConfig?.appName) || 'Fleet Tracking';
53
+ const displayName = tenant?.display_name ?? appName;
54
+ const subBrand = tenant?.sub_brand ?? null;
55
+
56
+ return (
57
+ <Sidebar collapsible="icon" variant="floating">
58
+ <SidebarHeader className="mb-4 pt-0">
59
+ <SidebarMenu>
60
+ <SidebarMenuItem>
61
+ <SidebarMenuButton size="lg" asChild className="hover:bg-sidebar-accent">
62
+ <PlatformLink
63
+ href={dashboardHref}
64
+ className="flex-direction-col mx-auto h-[120px] max-w-[240px] items-center justify-center gap-2 rounded-lg bg-white/100 px-3 py-4 text-sm font-medium group-data-[collapsible=icon]:hidden hover:bg-white/90"
65
+ >
66
+ <AppLogo />
67
+ </PlatformLink>
68
+ </SidebarMenuButton>
69
+ </SidebarMenuItem>
70
+ </SidebarMenu>
71
+ </SidebarHeader>
72
+
73
+ <SidebarContent>
74
+ <NavMain items={allItems} />
75
+ </SidebarContent>
76
+
77
+ <SidebarFooter>
78
+ <div className="border-t border-sidebar-border px-3 py-3 group-data-[collapsible=icon]:hidden">
79
+ <ul className="flex flex-wrap gap-x-3 gap-y-1 text-[11px] text-sidebar-foreground/60">
80
+ {[['Terms', '/terms'], ['Privacy', '/privacy'], ['Cookies', '/cookies']].map(([label, href]) => (
81
+ <li key={label}>
82
+ <a href={href} className="hover:text-sidebar-foreground" target="_blank" rel="noopener noreferrer">
83
+ {label}
84
+ </a>
85
+ </li>
86
+ ))}
87
+ </ul>
88
+ <p className="mt-2 text-[11px] text-sidebar-foreground/40">
89
+ © {new Date().getFullYear()} {appName}. All rights reserved.
90
+ </p>
91
+ </div>
92
+
93
+ <div className="border-t border-sidebar-border px-3 py-3 group-data-[collapsible=icon]:hidden">
94
+ <p className="text-[11px] leading-tight text-sidebar-foreground/60">{displayName}</p>
95
+ {subBrand && (
96
+ <p className="mt-0.5 text-[11px] text-sidebar-foreground/40">{subBrand}</p>
97
+ )}
98
+ </div>
99
+
100
+ {user && (
101
+ <NavUser user={user} settingsUrl={settingsUrl} logoutUrl={logoutUrl} />
102
+ )}
103
+ </SidebarFooter>
104
+ </Sidebar>
105
+ );
106
+ }