@svadmin/ui 0.29.3 → 0.30.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 (444) hide show
  1. package/dist/README.md +18 -0
  2. package/dist/actions.d.ts +35 -0
  3. package/dist/actions.js +84 -0
  4. package/dist/app.css +673 -0
  5. package/dist/component-registry.svelte.d.ts +36 -0
  6. package/dist/component-registry.svelte.js +20 -0
  7. package/dist/components/AICommandBar.svelte +180 -0
  8. package/dist/components/AICommandBar.svelte.d.ts +6 -0
  9. package/dist/components/AboutSettings.svelte +106 -0
  10. package/dist/components/AboutSettings.svelte.d.ts +18 -0
  11. package/dist/components/AdminApp.svelte +205 -0
  12. package/dist/components/AdminApp.svelte.d.ts +28 -0
  13. package/dist/components/AnimatedCounter.svelte +46 -0
  14. package/dist/components/AnimatedCounter.svelte.d.ts +11 -0
  15. package/dist/components/AnomalyBadge.svelte +65 -0
  16. package/dist/components/AnomalyBadge.svelte.d.ts +16 -0
  17. package/dist/components/AppearanceSettings.svelte +183 -0
  18. package/dist/components/AppearanceSettings.svelte.d.ts +3 -0
  19. package/dist/components/AuditLogDrawer.svelte +93 -0
  20. package/dist/components/AuditLogDrawer.svelte.d.ts +8 -0
  21. package/dist/components/AuditLogViewer.svelte +226 -0
  22. package/dist/components/AuditLogViewer.svelte.d.ts +3 -0
  23. package/dist/components/Authenticated.svelte +51 -0
  24. package/dist/components/Authenticated.svelte.d.ts +11 -0
  25. package/dist/components/AutoForm.svelte +244 -0
  26. package/dist/components/AutoForm.svelte.d.ts +20 -0
  27. package/dist/components/AutoSaveIndicator.svelte +35 -0
  28. package/dist/components/AutoSaveIndicator.svelte.d.ts +9 -0
  29. package/dist/components/AutoTable.svelte +839 -0
  30. package/dist/components/AutoTable.svelte.d.ts +44 -0
  31. package/dist/components/Breadcrumbs.svelte +58 -0
  32. package/dist/components/Breadcrumbs.svelte.d.ts +3 -0
  33. package/dist/components/CanAccess.svelte +23 -0
  34. package/dist/components/CanAccess.svelte.d.ts +12 -0
  35. package/dist/components/CatchAllNavigate.svelte +21 -0
  36. package/dist/components/CatchAllNavigate.svelte.d.ts +3 -0
  37. package/dist/components/ChatDialog.svelte +535 -0
  38. package/dist/components/ChatDialog.svelte.d.ts +14 -0
  39. package/dist/components/ComboboxField.svelte +129 -0
  40. package/dist/components/ComboboxField.svelte.d.ts +17 -0
  41. package/dist/components/CommandPalette.svelte +135 -0
  42. package/dist/components/CommandPalette.svelte.d.ts +8 -0
  43. package/dist/components/ConfigErrorScreen.svelte +126 -0
  44. package/dist/components/ConfigErrorScreen.svelte.d.ts +11 -0
  45. package/dist/components/ConfirmDialog.svelte +53 -0
  46. package/dist/components/ConfirmDialog.svelte.d.ts +13 -0
  47. package/dist/components/CopilotPanel.svelte +163 -0
  48. package/dist/components/CopilotPanel.svelte.d.ts +6 -0
  49. package/dist/components/CreatePage.svelte +39 -0
  50. package/dist/components/CreatePage.svelte.d.ts +10 -0
  51. package/dist/components/DevTools.svelte +149 -0
  52. package/dist/components/DevTools.svelte.d.ts +3 -0
  53. package/dist/components/DraggableGrid.svelte +86 -0
  54. package/dist/components/DraggableGrid.svelte.d.ts +17 -0
  55. package/dist/components/DraggableHeader.svelte +112 -0
  56. package/dist/components/DraggableHeader.svelte.d.ts +25 -0
  57. package/dist/components/DrawerForm.svelte +35 -0
  58. package/dist/components/DrawerForm.svelte.d.ts +11 -0
  59. package/dist/components/EditPage.svelte +52 -0
  60. package/dist/components/EditPage.svelte.d.ts +12 -0
  61. package/dist/components/EmptyState.svelte +31 -0
  62. package/dist/components/EmptyState.svelte.d.ts +8 -0
  63. package/dist/components/ErrorBoundary.svelte +49 -0
  64. package/dist/components/ErrorBoundary.svelte.d.ts +12 -0
  65. package/dist/components/ErrorComponent.svelte +36 -0
  66. package/dist/components/ErrorComponent.svelte.d.ts +9 -0
  67. package/dist/components/FieldRenderer.svelte +357 -0
  68. package/dist/components/FieldRenderer.svelte.d.ts +13 -0
  69. package/dist/components/ForgotPasswordPage.svelte +112 -0
  70. package/dist/components/ForgotPasswordPage.svelte.d.ts +6 -0
  71. package/dist/components/Header.svelte +94 -0
  72. package/dist/components/Header.svelte.d.ts +12 -0
  73. package/dist/components/InferencerPanel.svelte +192 -0
  74. package/dist/components/InferencerPanel.svelte.d.ts +3 -0
  75. package/dist/components/InfiniteList.svelte +93 -0
  76. package/dist/components/InfiniteList.svelte.d.ts +20 -0
  77. package/dist/components/InlineEdit.svelte +88 -0
  78. package/dist/components/InlineEdit.svelte.d.ts +12 -0
  79. package/dist/components/InsightCard.svelte +98 -0
  80. package/dist/components/InsightCard.svelte.d.ts +11 -0
  81. package/dist/components/KeyboardShortcuts.svelte +61 -0
  82. package/dist/components/KeyboardShortcuts.svelte.d.ts +6 -0
  83. package/dist/components/Layout.svelte +167 -0
  84. package/dist/components/Layout.svelte.d.ts +12 -0
  85. package/dist/components/ListPage.svelte +71 -0
  86. package/dist/components/ListPage.svelte.d.ts +32 -0
  87. package/dist/components/LiveIndicator.svelte +58 -0
  88. package/dist/components/LiveIndicator.svelte.d.ts +12 -0
  89. package/dist/components/LoginPage.svelte +163 -0
  90. package/dist/components/LoginPage.svelte.d.ts +28 -0
  91. package/dist/components/MarkdownRenderer.svelte +127 -0
  92. package/dist/components/MarkdownRenderer.svelte.d.ts +11 -0
  93. package/dist/components/ModalForm.svelte +38 -0
  94. package/dist/components/ModalForm.svelte.d.ts +10 -0
  95. package/dist/components/NavigateToResource.svelte +20 -0
  96. package/dist/components/NavigateToResource.svelte.d.ts +3 -0
  97. package/dist/components/PageHeader.svelte +39 -0
  98. package/dist/components/PageHeader.svelte.d.ts +11 -0
  99. package/dist/components/PageSkeleton.svelte +71 -0
  100. package/dist/components/PageSkeleton.svelte.d.ts +7 -0
  101. package/dist/components/PasswordInput.svelte +96 -0
  102. package/dist/components/PasswordInput.svelte.d.ts +12 -0
  103. package/dist/components/PermissionMatrix.svelte +185 -0
  104. package/dist/components/PermissionMatrix.svelte.d.ts +19 -0
  105. package/dist/components/ProfilePage.svelte +284 -0
  106. package/dist/components/ProfilePage.svelte.d.ts +3 -0
  107. package/dist/components/RegisterPage.svelte +112 -0
  108. package/dist/components/RegisterPage.svelte.d.ts +7 -0
  109. package/dist/components/RolesSettings.svelte +146 -0
  110. package/dist/components/RolesSettings.svelte.d.ts +3 -0
  111. package/dist/components/SettingsPage.svelte +113 -0
  112. package/dist/components/SettingsPage.svelte.d.ts +3 -0
  113. package/dist/components/ShowPage.svelte +73 -0
  114. package/dist/components/ShowPage.svelte.d.ts +7 -0
  115. package/dist/components/Sidebar.svelte +417 -0
  116. package/dist/components/Sidebar.svelte.d.ts +14 -0
  117. package/dist/components/SidebarItem.svelte +129 -0
  118. package/dist/components/SidebarItem.svelte.d.ts +11 -0
  119. package/dist/components/SmartSuggest.svelte +158 -0
  120. package/dist/components/SmartSuggest.svelte.d.ts +19 -0
  121. package/dist/components/StatsCard.svelte +79 -0
  122. package/dist/components/StatsCard.svelte.d.ts +23 -0
  123. package/dist/components/StepsForm.svelte +194 -0
  124. package/dist/components/StepsForm.svelte.d.ts +13 -0
  125. package/dist/components/TaskQueueDrawer.svelte +158 -0
  126. package/dist/components/TaskQueueDrawer.svelte.d.ts +11 -0
  127. package/dist/components/TenantSwitcher.svelte +84 -0
  128. package/dist/components/TenantSwitcher.svelte.d.ts +12 -0
  129. package/dist/components/ThemedTitle.svelte +32 -0
  130. package/dist/components/ThemedTitle.svelte.d.ts +9 -0
  131. package/dist/components/Toast.svelte +46 -0
  132. package/dist/components/Toast.svelte.d.ts +3 -0
  133. package/dist/components/TooltipButton.svelte +42 -0
  134. package/dist/components/TooltipButton.svelte.d.ts +14 -0
  135. package/dist/components/UndoableNotification.svelte +69 -0
  136. package/dist/components/UndoableNotification.svelte.d.ts +9 -0
  137. package/dist/components/UpdatePasswordPage.svelte +89 -0
  138. package/dist/components/UpdatePasswordPage.svelte.d.ts +6 -0
  139. package/dist/components/VirtualTable.svelte +76 -0
  140. package/dist/components/VirtualTable.svelte.d.ts +27 -0
  141. package/dist/components/VoiceInput.svelte +120 -0
  142. package/dist/components/VoiceInput.svelte.d.ts +15 -0
  143. package/dist/components/buttons/CloneButton.svelte +30 -0
  144. package/dist/components/buttons/CloneButton.svelte.d.ts +13 -0
  145. package/dist/components/buttons/CreateButton.svelte +29 -0
  146. package/dist/components/buttons/CreateButton.svelte.d.ts +12 -0
  147. package/dist/components/buttons/DeleteButton.svelte +59 -0
  148. package/dist/components/buttons/DeleteButton.svelte.d.ts +15 -0
  149. package/dist/components/buttons/EditButton.svelte +30 -0
  150. package/dist/components/buttons/EditButton.svelte.d.ts +13 -0
  151. package/dist/components/buttons/ExportButton.svelte +30 -0
  152. package/dist/components/buttons/ExportButton.svelte.d.ts +12 -0
  153. package/dist/components/buttons/ImportButton.svelte +56 -0
  154. package/dist/components/buttons/ImportButton.svelte.d.ts +19 -0
  155. package/dist/components/buttons/ListButton.svelte +23 -0
  156. package/dist/components/buttons/ListButton.svelte.d.ts +8 -0
  157. package/dist/components/buttons/RefreshButton.svelte +36 -0
  158. package/dist/components/buttons/RefreshButton.svelte.d.ts +8 -0
  159. package/dist/components/buttons/SaveButton.svelte +27 -0
  160. package/dist/components/buttons/SaveButton.svelte.d.ts +9 -0
  161. package/dist/components/buttons/ShowButton.svelte +31 -0
  162. package/dist/components/buttons/ShowButton.svelte.d.ts +13 -0
  163. package/dist/components/buttons/index.d.ts +10 -0
  164. package/dist/components/buttons/index.js +10 -0
  165. package/dist/components/charts/BarChart.svelte +69 -0
  166. package/dist/components/charts/BarChart.svelte.d.ts +15 -0
  167. package/dist/components/charts/LineChart.svelte +115 -0
  168. package/dist/components/charts/LineChart.svelte.d.ts +17 -0
  169. package/dist/components/charts/PieChart.svelte +95 -0
  170. package/dist/components/charts/PieChart.svelte.d.ts +15 -0
  171. package/dist/components/charts/index.d.ts +3 -0
  172. package/dist/components/charts/index.js +3 -0
  173. package/dist/components/fieldComponentMap.d.ts +24 -0
  174. package/dist/components/fieldComponentMap.js +65 -0
  175. package/dist/components/fields/ArrayField.svelte +86 -0
  176. package/dist/components/fields/ArrayField.svelte.d.ts +9 -0
  177. package/dist/components/fields/BooleanField.svelte +13 -0
  178. package/dist/components/fields/BooleanField.svelte.d.ts +8 -0
  179. package/dist/components/fields/DateField.svelte +6 -0
  180. package/dist/components/fields/DateField.svelte.d.ts +8 -0
  181. package/dist/components/fields/EmailField.svelte +9 -0
  182. package/dist/components/fields/EmailField.svelte.d.ts +6 -0
  183. package/dist/components/fields/FileField.svelte +14 -0
  184. package/dist/components/fields/FileField.svelte.d.ts +7 -0
  185. package/dist/components/fields/ImageField.svelte +9 -0
  186. package/dist/components/fields/ImageField.svelte.d.ts +9 -0
  187. package/dist/components/fields/JsonField.svelte +72 -0
  188. package/dist/components/fields/JsonField.svelte.d.ts +6 -0
  189. package/dist/components/fields/MarkdownField.svelte +9 -0
  190. package/dist/components/fields/MarkdownField.svelte.d.ts +6 -0
  191. package/dist/components/fields/MultiSelectField.svelte +21 -0
  192. package/dist/components/fields/MultiSelectField.svelte.d.ts +10 -0
  193. package/dist/components/fields/NumberField.svelte +6 -0
  194. package/dist/components/fields/NumberField.svelte.d.ts +8 -0
  195. package/dist/components/fields/RelationField.svelte +24 -0
  196. package/dist/components/fields/RelationField.svelte.d.ts +8 -0
  197. package/dist/components/fields/RichTextField.svelte +35 -0
  198. package/dist/components/fields/RichTextField.svelte.d.ts +7 -0
  199. package/dist/components/fields/SelectField.svelte +14 -0
  200. package/dist/components/fields/SelectField.svelte.d.ts +10 -0
  201. package/dist/components/fields/TagField.svelte +12 -0
  202. package/dist/components/fields/TagField.svelte.d.ts +6 -0
  203. package/dist/components/fields/TextField.svelte +11 -0
  204. package/dist/components/fields/TextField.svelte.d.ts +7 -0
  205. package/dist/components/fields/UrlField.svelte +14 -0
  206. package/dist/components/fields/UrlField.svelte.d.ts +7 -0
  207. package/dist/components/ui/alert/alert-description.svelte +17 -0
  208. package/dist/components/ui/alert/alert-description.svelte.d.ts +6 -0
  209. package/dist/components/ui/alert/alert-title.svelte +17 -0
  210. package/dist/components/ui/alert/alert-title.svelte.d.ts +6 -0
  211. package/dist/components/ui/alert/alert.svelte +44 -0
  212. package/dist/components/ui/alert/alert.svelte.d.ts +32 -0
  213. package/dist/components/ui/alert/index.d.ts +4 -0
  214. package/dist/components/ui/alert/index.js +5 -0
  215. package/dist/components/ui/alert-dialog/alert-dialog-content.svelte +29 -0
  216. package/dist/components/ui/alert-dialog/alert-dialog-content.svelte.d.ts +10 -0
  217. package/dist/components/ui/alert-dialog/alert-dialog-description.svelte +16 -0
  218. package/dist/components/ui/alert-dialog/alert-dialog-description.svelte.d.ts +7 -0
  219. package/dist/components/ui/alert-dialog/alert-dialog-footer.svelte +11 -0
  220. package/dist/components/ui/alert-dialog/alert-dialog-footer.svelte.d.ts +8 -0
  221. package/dist/components/ui/alert-dialog/alert-dialog-header.svelte +11 -0
  222. package/dist/components/ui/alert-dialog/alert-dialog-header.svelte.d.ts +8 -0
  223. package/dist/components/ui/alert-dialog/alert-dialog-overlay.svelte +16 -0
  224. package/dist/components/ui/alert-dialog/alert-dialog-overlay.svelte.d.ts +7 -0
  225. package/dist/components/ui/alert-dialog/alert-dialog-portal.svelte +6 -0
  226. package/dist/components/ui/alert-dialog/alert-dialog-portal.svelte.d.ts +3 -0
  227. package/dist/components/ui/alert-dialog/alert-dialog-title.svelte +16 -0
  228. package/dist/components/ui/alert-dialog/alert-dialog-title.svelte.d.ts +7 -0
  229. package/dist/components/ui/alert-dialog/index.d.ts +13 -0
  230. package/dist/components/ui/alert-dialog/index.js +13 -0
  231. package/dist/components/ui/avatar/avatar.svelte +63 -0
  232. package/dist/components/ui/avatar/avatar.svelte.d.ts +32 -0
  233. package/dist/components/ui/avatar/index.d.ts +2 -0
  234. package/dist/components/ui/avatar/index.js +2 -0
  235. package/dist/components/ui/badge/badge.svelte +49 -0
  236. package/dist/components/ui/badge/badge.svelte.d.ts +38 -0
  237. package/dist/components/ui/badge/index.d.ts +2 -0
  238. package/dist/components/ui/badge/index.js +3 -0
  239. package/dist/components/ui/breadcrumb/breadcrumb-ellipsis.svelte +18 -0
  240. package/dist/components/ui/breadcrumb/breadcrumb-ellipsis.svelte.d.ts +4 -0
  241. package/dist/components/ui/breadcrumb/breadcrumb-item.svelte +15 -0
  242. package/dist/components/ui/breadcrumb/breadcrumb-item.svelte.d.ts +8 -0
  243. package/dist/components/ui/breadcrumb/breadcrumb-link.svelte +15 -0
  244. package/dist/components/ui/breadcrumb/breadcrumb-link.svelte.d.ts +8 -0
  245. package/dist/components/ui/breadcrumb/breadcrumb-list.svelte +15 -0
  246. package/dist/components/ui/breadcrumb/breadcrumb-list.svelte.d.ts +8 -0
  247. package/dist/components/ui/breadcrumb/breadcrumb-page.svelte +18 -0
  248. package/dist/components/ui/breadcrumb/breadcrumb-page.svelte.d.ts +8 -0
  249. package/dist/components/ui/breadcrumb/breadcrumb-separator.svelte +22 -0
  250. package/dist/components/ui/breadcrumb/breadcrumb-separator.svelte.d.ts +8 -0
  251. package/dist/components/ui/breadcrumb/breadcrumb.svelte +11 -0
  252. package/dist/components/ui/breadcrumb/breadcrumb.svelte.d.ts +8 -0
  253. package/dist/components/ui/breadcrumb/index.d.ts +7 -0
  254. package/dist/components/ui/breadcrumb/index.js +7 -0
  255. package/dist/components/ui/button/button.svelte +90 -0
  256. package/dist/components/ui/button/button.svelte.d.ts +70 -0
  257. package/dist/components/ui/button/index.d.ts +2 -0
  258. package/dist/components/ui/button/index.js +5 -0
  259. package/dist/components/ui/card/card-action.svelte +23 -0
  260. package/dist/components/ui/card/card-action.svelte.d.ts +5 -0
  261. package/dist/components/ui/card/card-content.svelte +20 -0
  262. package/dist/components/ui/card/card-content.svelte.d.ts +5 -0
  263. package/dist/components/ui/card/card-description.svelte +20 -0
  264. package/dist/components/ui/card/card-description.svelte.d.ts +5 -0
  265. package/dist/components/ui/card/card-footer.svelte +20 -0
  266. package/dist/components/ui/card/card-footer.svelte.d.ts +5 -0
  267. package/dist/components/ui/card/card-header.svelte +23 -0
  268. package/dist/components/ui/card/card-header.svelte.d.ts +5 -0
  269. package/dist/components/ui/card/card-title.svelte +15 -0
  270. package/dist/components/ui/card/card-title.svelte.d.ts +5 -0
  271. package/dist/components/ui/card/card.svelte +22 -0
  272. package/dist/components/ui/card/card.svelte.d.ts +8 -0
  273. package/dist/components/ui/card/index.d.ts +8 -0
  274. package/dist/components/ui/card/index.js +10 -0
  275. package/dist/components/ui/checkbox/checkbox.svelte +39 -0
  276. package/dist/components/ui/checkbox/checkbox.svelte.d.ts +4 -0
  277. package/dist/components/ui/checkbox/index.d.ts +2 -0
  278. package/dist/components/ui/checkbox/index.js +4 -0
  279. package/dist/components/ui/collapsible/index.d.ts +5 -0
  280. package/dist/components/ui/collapsible/index.js +5 -0
  281. package/dist/components/ui/command/command-dialog.svelte +31 -0
  282. package/dist/components/ui/command/command-dialog.svelte.d.ts +10 -0
  283. package/dist/components/ui/command/index.d.ts +2 -0
  284. package/dist/components/ui/command/index.js +2 -0
  285. package/dist/components/ui/context-menu/index.d.ts +9 -0
  286. package/dist/components/ui/context-menu/index.js +9 -0
  287. package/dist/components/ui/dialog/dialog-close.svelte +11 -0
  288. package/dist/components/ui/dialog/dialog-close.svelte.d.ts +4 -0
  289. package/dist/components/ui/dialog/dialog-content.svelte +48 -0
  290. package/dist/components/ui/dialog/dialog-content.svelte.d.ts +13 -0
  291. package/dist/components/ui/dialog/dialog-description.svelte +17 -0
  292. package/dist/components/ui/dialog/dialog-description.svelte.d.ts +4 -0
  293. package/dist/components/ui/dialog/dialog-footer.svelte +32 -0
  294. package/dist/components/ui/dialog/dialog-footer.svelte.d.ts +8 -0
  295. package/dist/components/ui/dialog/dialog-header.svelte +20 -0
  296. package/dist/components/ui/dialog/dialog-header.svelte.d.ts +5 -0
  297. package/dist/components/ui/dialog/dialog-overlay.svelte +17 -0
  298. package/dist/components/ui/dialog/dialog-overlay.svelte.d.ts +4 -0
  299. package/dist/components/ui/dialog/dialog-portal.svelte +7 -0
  300. package/dist/components/ui/dialog/dialog-portal.svelte.d.ts +3 -0
  301. package/dist/components/ui/dialog/dialog-title.svelte +17 -0
  302. package/dist/components/ui/dialog/dialog-title.svelte.d.ts +4 -0
  303. package/dist/components/ui/dialog/dialog-trigger.svelte +11 -0
  304. package/dist/components/ui/dialog/dialog-trigger.svelte.d.ts +4 -0
  305. package/dist/components/ui/dialog/dialog.svelte +7 -0
  306. package/dist/components/ui/dialog/dialog.svelte.d.ts +3 -0
  307. package/dist/components/ui/dialog/index.d.ts +11 -0
  308. package/dist/components/ui/dialog/index.js +13 -0
  309. package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +43 -0
  310. package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +9 -0
  311. package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte +35 -0
  312. package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte.d.ts +8 -0
  313. package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte +36 -0
  314. package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte.d.ts +9 -0
  315. package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte +10 -0
  316. package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte.d.ts +6 -0
  317. package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +27 -0
  318. package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte.d.ts +11 -0
  319. package/dist/components/ui/dropdown-menu/dropdown-menu.svelte +45 -0
  320. package/dist/components/ui/dropdown-menu/dropdown-menu.svelte.d.ts +9 -0
  321. package/dist/components/ui/dropdown-menu/index.d.ts +7 -0
  322. package/dist/components/ui/dropdown-menu/index.js +7 -0
  323. package/dist/components/ui/input/index.d.ts +2 -0
  324. package/dist/components/ui/input/index.js +4 -0
  325. package/dist/components/ui/input/input.svelte +48 -0
  326. package/dist/components/ui/input/input.svelte.d.ts +13 -0
  327. package/dist/components/ui/label/index.d.ts +1 -0
  328. package/dist/components/ui/label/index.js +1 -0
  329. package/dist/components/ui/label/label.svelte +18 -0
  330. package/dist/components/ui/label/label.svelte.d.ts +5 -0
  331. package/dist/components/ui/pagination/index.d.ts +7 -0
  332. package/dist/components/ui/pagination/index.js +7 -0
  333. package/dist/components/ui/pagination/pagination-content.svelte +11 -0
  334. package/dist/components/ui/pagination/pagination-content.svelte.d.ts +8 -0
  335. package/dist/components/ui/pagination/pagination-ellipsis.svelte +12 -0
  336. package/dist/components/ui/pagination/pagination-ellipsis.svelte.d.ts +4 -0
  337. package/dist/components/ui/pagination/pagination-item.svelte +11 -0
  338. package/dist/components/ui/pagination/pagination-item.svelte.d.ts +8 -0
  339. package/dist/components/ui/pagination/pagination-link.svelte +26 -0
  340. package/dist/components/ui/pagination/pagination-link.svelte.d.ts +9 -0
  341. package/dist/components/ui/pagination/pagination-next.svelte +22 -0
  342. package/dist/components/ui/pagination/pagination-next.svelte.d.ts +8 -0
  343. package/dist/components/ui/pagination/pagination-previous.svelte +22 -0
  344. package/dist/components/ui/pagination/pagination-previous.svelte.d.ts +8 -0
  345. package/dist/components/ui/pagination/pagination.svelte +11 -0
  346. package/dist/components/ui/pagination/pagination.svelte.d.ts +8 -0
  347. package/dist/components/ui/popover/index.d.ts +6 -0
  348. package/dist/components/ui/popover/index.js +6 -0
  349. package/dist/components/ui/popover/popover-content.svelte +25 -0
  350. package/dist/components/ui/popover/popover-content.svelte.d.ts +7 -0
  351. package/dist/components/ui/progress/index.d.ts +1 -0
  352. package/dist/components/ui/progress/index.js +1 -0
  353. package/dist/components/ui/progress/progress.svelte +22 -0
  354. package/dist/components/ui/progress/progress.svelte.d.ts +8 -0
  355. package/dist/components/ui/scroll-area/index.d.ts +1 -0
  356. package/dist/components/ui/scroll-area/index.js +1 -0
  357. package/dist/components/ui/scroll-area/scroll-area.svelte +20 -0
  358. package/dist/components/ui/scroll-area/scroll-area.svelte.d.ts +9 -0
  359. package/dist/components/ui/select/index.d.ts +2 -0
  360. package/dist/components/ui/select/index.js +2 -0
  361. package/dist/components/ui/select/select.svelte +36 -0
  362. package/dist/components/ui/select/select.svelte.d.ts +8 -0
  363. package/dist/components/ui/separator/index.d.ts +2 -0
  364. package/dist/components/ui/separator/index.js +4 -0
  365. package/dist/components/ui/separator/separator.svelte +23 -0
  366. package/dist/components/ui/separator/separator.svelte.d.ts +4 -0
  367. package/dist/components/ui/sheet/index.d.ts +7 -0
  368. package/dist/components/ui/sheet/index.js +7 -0
  369. package/dist/components/ui/sheet/sheet-content.svelte +28 -0
  370. package/dist/components/ui/sheet/sheet-content.svelte.d.ts +8 -0
  371. package/dist/components/ui/sheet/sheet-description.svelte +22 -0
  372. package/dist/components/ui/sheet/sheet-description.svelte.d.ts +6 -0
  373. package/dist/components/ui/sheet/sheet-footer.svelte +22 -0
  374. package/dist/components/ui/sheet/sheet-footer.svelte.d.ts +6 -0
  375. package/dist/components/ui/sheet/sheet-header.svelte +22 -0
  376. package/dist/components/ui/sheet/sheet-header.svelte.d.ts +6 -0
  377. package/dist/components/ui/sheet/sheet-title.svelte +22 -0
  378. package/dist/components/ui/sheet/sheet-title.svelte.d.ts +6 -0
  379. package/dist/components/ui/sheet/sheet.svelte +78 -0
  380. package/dist/components/ui/sheet/sheet.svelte.d.ts +10 -0
  381. package/dist/components/ui/skeleton/index.d.ts +2 -0
  382. package/dist/components/ui/skeleton/index.js +2 -0
  383. package/dist/components/ui/skeleton/skeleton.svelte +21 -0
  384. package/dist/components/ui/skeleton/skeleton.svelte.d.ts +8 -0
  385. package/dist/components/ui/switch/index.d.ts +2 -0
  386. package/dist/components/ui/switch/index.js +2 -0
  387. package/dist/components/ui/switch/switch.svelte +49 -0
  388. package/dist/components/ui/switch/switch.svelte.d.ts +10 -0
  389. package/dist/components/ui/table/index.d.ts +9 -0
  390. package/dist/components/ui/table/index.js +11 -0
  391. package/dist/components/ui/table/table-body.svelte +15 -0
  392. package/dist/components/ui/table/table-body.svelte.d.ts +5 -0
  393. package/dist/components/ui/table/table-caption.svelte +20 -0
  394. package/dist/components/ui/table/table-caption.svelte.d.ts +5 -0
  395. package/dist/components/ui/table/table-cell.svelte +15 -0
  396. package/dist/components/ui/table/table-cell.svelte.d.ts +5 -0
  397. package/dist/components/ui/table/table-footer.svelte +20 -0
  398. package/dist/components/ui/table/table-footer.svelte.d.ts +5 -0
  399. package/dist/components/ui/table/table-head.svelte +15 -0
  400. package/dist/components/ui/table/table-head.svelte.d.ts +5 -0
  401. package/dist/components/ui/table/table-header.svelte +20 -0
  402. package/dist/components/ui/table/table-header.svelte.d.ts +5 -0
  403. package/dist/components/ui/table/table-row.svelte +15 -0
  404. package/dist/components/ui/table/table-row.svelte.d.ts +5 -0
  405. package/dist/components/ui/table/table.svelte +17 -0
  406. package/dist/components/ui/table/table.svelte.d.ts +5 -0
  407. package/dist/components/ui/tabs/index.d.ts +5 -0
  408. package/dist/components/ui/tabs/index.js +5 -0
  409. package/dist/components/ui/tabs/tabs-content.svelte +30 -0
  410. package/dist/components/ui/tabs/tabs-content.svelte.d.ts +9 -0
  411. package/dist/components/ui/tabs/tabs-list.svelte +26 -0
  412. package/dist/components/ui/tabs/tabs-list.svelte.d.ts +6 -0
  413. package/dist/components/ui/tabs/tabs-trigger.svelte +37 -0
  414. package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +9 -0
  415. package/dist/components/ui/tabs/tabs.svelte +27 -0
  416. package/dist/components/ui/tabs/tabs.svelte.d.ts +9 -0
  417. package/dist/components/ui/textarea/index.d.ts +2 -0
  418. package/dist/components/ui/textarea/index.js +2 -0
  419. package/dist/components/ui/textarea/textarea.svelte +24 -0
  420. package/dist/components/ui/textarea/textarea.svelte.d.ts +6 -0
  421. package/dist/components/ui/tooltip/index.d.ts +6 -0
  422. package/dist/components/ui/tooltip/index.js +8 -0
  423. package/dist/components/ui/tooltip/tooltip-content.svelte +52 -0
  424. package/dist/components/ui/tooltip/tooltip-content.svelte.d.ts +11 -0
  425. package/dist/components/ui/tooltip/tooltip-portal.svelte +7 -0
  426. package/dist/components/ui/tooltip/tooltip-portal.svelte.d.ts +4 -0
  427. package/dist/components/ui/tooltip/tooltip-provider.svelte +7 -0
  428. package/dist/components/ui/tooltip/tooltip-provider.svelte.d.ts +4 -0
  429. package/dist/components/ui/tooltip/tooltip-trigger.svelte +7 -0
  430. package/dist/components/ui/tooltip/tooltip-trigger.svelte.d.ts +4 -0
  431. package/dist/components/ui/tooltip/tooltip.svelte +10 -0
  432. package/dist/components/ui/tooltip/tooltip.svelte.d.ts +4 -0
  433. package/dist/editor-config.svelte.d.ts +15 -0
  434. package/dist/editor-config.svelte.js +19 -0
  435. package/dist/index.d.ts +117 -0
  436. package/dist/index.js +127 -0
  437. package/dist/markdown-deps.d.ts +21 -0
  438. package/dist/router-state.svelte.d.ts +5 -0
  439. package/dist/router-state.svelte.js +58 -0
  440. package/dist/types.d.ts +42 -0
  441. package/dist/types.js +1 -0
  442. package/dist/utils.d.ts +16 -0
  443. package/dist/utils.js +5 -0
  444. package/package.json +2 -2
@@ -0,0 +1,73 @@
1
+ <script lang="ts">
2
+ import { useShow, getResource } from '@svadmin/core';
3
+ import type { FieldDefinition } from '@svadmin/core';
4
+ import { navigate } from '@svadmin/core/router';
5
+ import { t, getLocale } from '@svadmin/core/i18n';
6
+ import { Button } from './ui/button/index.js';
7
+ import * as Card from './ui/card/index.js';
8
+ import { Skeleton } from './ui/skeleton/index.js';
9
+ import PageHeader from './PageHeader.svelte';
10
+ import { getDisplayComponent } from './fieldComponentMap';
11
+ import ListButton from './buttons/ListButton.svelte';
12
+ import EditButton from './buttons/EditButton.svelte';
13
+ import DeleteButton from './buttons/DeleteButton.svelte';
14
+ import RefreshButton from './buttons/RefreshButton.svelte';
15
+
16
+ let { resourceName, id } = $props<{ resourceName: string; id: string | number }>();
17
+
18
+ const resource = $derived(getResource(resourceName));
19
+ const showFields = $derived(resource.fields.filter(f => f.showInShow !== false));
20
+
21
+ const query = useShow({ get resource() { return resourceName; }, get id() { return id; } });
22
+ </script>
23
+
24
+ <div class="space-y-6">
25
+ <PageHeader title="{resource.label} {t('common.detail')}">
26
+ {#snippet actions()}
27
+ <ListButton resource={resourceName} hideText />
28
+ {#if resource.canEdit !== false}
29
+ <EditButton resource={resourceName} recordItemId={id} hideText />
30
+ {/if}
31
+ {#if resource.canDelete !== false}
32
+ <DeleteButton resource={resourceName} recordItemId={id} hideText onSuccess={() => navigate(`/${resourceName}`)} />
33
+ {/if}
34
+ <RefreshButton resource={resourceName} hideText />
35
+ {/snippet}
36
+ </PageHeader>
37
+
38
+ {#if query.isLoading}
39
+ <Card.Root class="overflow-hidden border-border/40 shadow-sm">
40
+ <Card.Content class="p-0">
41
+ {#each showFields.slice(0, 6) as _, i}
42
+ <div class="flex flex-col sm:flex-row px-4 sm:px-6 py-3 sm:py-4 {i % 2 === 1 ? 'bg-muted/20' : ''}">
43
+ <Skeleton class="h-4 w-1/2 sm:w-1/4" />
44
+ <Skeleton class="h-4 w-3/4 sm:w-2/5 mt-1 sm:mt-0 sm:ml-auto" />
45
+ </div>
46
+ {/each}
47
+ </Card.Content>
48
+ </Card.Root>
49
+ {:else if query.data?.data}
50
+ <Card.Root class="overflow-hidden border-border/40 shadow-sm">
51
+ <Card.Content class="p-0">
52
+ {#each showFields as field, i}
53
+ {@const value = (query.data!.data as Record<string, unknown>)[field.key]}
54
+ {@const DisplayComponent = getDisplayComponent(field.type)}
55
+ <div class="flex flex-col sm:flex-row px-4 sm:px-6 py-3 sm:py-4 {i % 2 === 1 ? 'bg-muted/20' : ''}">
56
+ <div class="sm:w-1/3 text-xs sm:text-sm font-medium text-muted-foreground mb-1 sm:mb-0">{field.label}</div>
57
+ <div class="sm:w-2/3 text-sm text-foreground">
58
+ {#if DisplayComponent && value != null}
59
+ <DisplayComponent
60
+ {value}
61
+ options={field.options}
62
+ resourceName={field.resource}
63
+ />
64
+ {:else}
65
+ {value != null ? String(value) : '—'}
66
+ {/if}
67
+ </div>
68
+ </div>
69
+ {/each}
70
+ </Card.Content>
71
+ </Card.Root>
72
+ {/if}
73
+ </div>
@@ -0,0 +1,7 @@
1
+ type $$ComponentProps = {
2
+ resourceName: string;
3
+ id: string | number;
4
+ };
5
+ declare const ShowPage: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type ShowPage = ReturnType<typeof ShowPage>;
7
+ export default ShowPage;
@@ -0,0 +1,417 @@
1
+ <script lang="ts">
2
+ import { getResources, canAccessAsync } from '@svadmin/core';
3
+ import type { Identity, MenuItem } from '@svadmin/core';
4
+ import { currentPath, navigate } from '@svadmin/core/router';
5
+ import { t, getLocale, setLocale, getAvailableLocales } from '@svadmin/core/i18n';
6
+ import { toggleTheme, getResolvedTheme, colorThemes, getColorTheme, setColorTheme } from '@svadmin/core';
7
+ import { Button } from './ui/button/index.js';
8
+ import TooltipButton from './TooltipButton.svelte';
9
+ import * as Tooltip from './ui/tooltip/index.js';
10
+ import SidebarItem from './SidebarItem.svelte';
11
+
12
+ import { ScrollArea } from './ui/scroll-area/index.js';
13
+ import * as Collapsible from './ui/collapsible/index.js';
14
+ import { Avatar } from './ui/avatar/index.js';
15
+ import {
16
+ LayoutDashboard, FileText, Users, Settings, Home,
17
+ ChevronLeft, ChevronRight, ChevronDown, LogOut, Sun, Moon, Palette,
18
+ Image as ImageIcon, Layout, Folder, Type, Video,
19
+ Download, ListTodo, TrendingUp, Sparkles, Images, Bot, Key, KeyRound, CreditCard, BookOpen, Wrench
20
+ } from '@lucide/svelte';
21
+
22
+ let { collapsed, identity, title, onToggle, onLogout, menu, routeMode = 'auto' }: {
23
+ collapsed: boolean;
24
+ identity: Identity | null;
25
+ title: string;
26
+ onToggle: () => void;
27
+ onLogout: () => void;
28
+ menu?: MenuItem[];
29
+ /** 'hash' for SPA hash routing, 'path' for SvelteKit/filesystem routing, 'auto' to detect */
30
+ routeMode?: 'hash' | 'path' | 'auto';
31
+ } = $props();
32
+
33
+ const effectiveRouteMode = $derived(
34
+ routeMode === 'auto'
35
+ ? (typeof window !== 'undefined' && window.location.hash.startsWith('#/') ? 'hash' : 'path')
36
+ : routeMode
37
+ );
38
+
39
+ const resources = getResources();
40
+
41
+ const iconMap: Record<string, typeof LayoutDashboard> = {
42
+ 'dashboard': LayoutDashboard,
43
+ 'posts': FileText,
44
+ 'users': Users,
45
+ 'settings': Settings,
46
+ 'home': Home,
47
+ 'palette': Palette,
48
+ 'image': ImageIcon,
49
+ 'layout': Layout,
50
+ 'folder': Folder,
51
+ 'type': Type,
52
+ 'video': Video,
53
+ 'download': Download,
54
+ 'list-todo': ListTodo,
55
+ 'trending-up': TrendingUp,
56
+ 'sparkles': Sparkles,
57
+ 'images': Images,
58
+ 'bot': Bot,
59
+ 'key': Key,
60
+ 'key-round': KeyRound,
61
+ 'credit-card': CreditCard,
62
+ 'book-open': BookOpen,
63
+ 'wrench': Wrench,
64
+ };
65
+
66
+ interface NavItem {
67
+ path: string;
68
+ label: string;
69
+ Icon: typeof LayoutDashboard;
70
+ group?: string;
71
+ }
72
+
73
+ interface NavGroup {
74
+ name: string | null; // null = ungrouped
75
+ items: NavItem[];
76
+ }
77
+
78
+ // Use effect to build nav items, taking access control into account
79
+ let navItems = $state.raw<NavItem[]>([]);
80
+
81
+ $effect(() => {
82
+ // Re-run when locale or resources change
83
+ const localeVal = getLocale();
84
+
85
+ Promise.all(resources.map(async (r) => {
86
+ try {
87
+ const { can } = await canAccessAsync(r.name, 'list');
88
+ return { r, can };
89
+ } catch {
90
+ return { r, can: false };
91
+ }
92
+ })).then(results => {
93
+ const items: NavItem[] = [{ path: '/', label: t('common.home'), Icon: LayoutDashboard }];
94
+ for (const { r, can } of results) {
95
+ if (can) {
96
+ items.push({
97
+ path: `/${r.name}`,
98
+ label: r.label,
99
+ Icon: iconMap[r.icon ?? r.name] ?? Settings,
100
+ group: r.group,
101
+ });
102
+ }
103
+ }
104
+ navItems = items;
105
+ });
106
+ });
107
+
108
+ /** Toggle between available locales */
109
+ function toggleLocale() {
110
+ const locales = getAvailableLocales();
111
+ const current = getLocale();
112
+ const idx = locales.indexOf(current);
113
+ const next = locales[(idx + 1) % locales.length];
114
+ setLocale(next);
115
+ }
116
+
117
+ /** Short display label for current locale */
118
+ const localeLabel = $derived(getLocale() === 'zh-CN' ? '中' : 'EN');
119
+
120
+ // Track current hash for active state
121
+ let path = $state(currentPath());
122
+
123
+ function onHashChange() { path = currentPath(); }
124
+
125
+ function isActive(itemPath: string): boolean {
126
+ if (itemPath === '/') return path === '/';
127
+ return path === itemPath || path.startsWith(itemPath + "/");
128
+ }
129
+
130
+ /** Prefetch resource data on hover for instant navigation */
131
+ const prefetchedResources = new Set<string>();
132
+ function prefetchResource(resourceName: string) {
133
+ if (resourceName === '/' || prefetchedResources.has(resourceName)) return;
134
+ prefetchedResources.add(resourceName);
135
+ // Trigger a background fetch by navigating the browser cache
136
+ // The actual prefetch happens via the #key block re-creating useList in AdminApp
137
+ }
138
+
139
+ // Group nav items by group field (null = ungrouped)
140
+ const navGroups = $derived.by((): NavGroup[] => {
141
+ const groups: NavGroup[] = [];
142
+ const groupMap = new Map<string | null, NavItem[]>();
143
+
144
+ for (const item of navItems) {
145
+ const key = item.group ?? null;
146
+ if (!groupMap.has(key)) {
147
+ groupMap.set(key, []);
148
+ groups.push({ name: key, items: groupMap.get(key)! });
149
+ }
150
+ groupMap.get(key)!.push(item);
151
+ }
152
+
153
+ return groups;
154
+ });
155
+
156
+ // Track which groups are open
157
+ let openGroups = $state<Set<string>>(new Set());
158
+ let colorPickerOpen = $state(false);
159
+ let colorPickerRef = $state<HTMLDivElement | null>(null);
160
+ let colorPickerOpenedAt = 0;
161
+
162
+ // Click-outside to close color picker
163
+ $effect(() => {
164
+ if (!colorPickerOpen) return;
165
+ function handleMouseDown(e: MouseEvent) {
166
+ // Ignore if opened within last 200ms (same interaction)
167
+ if (Date.now() - colorPickerOpenedAt < 200) return;
168
+ if (colorPickerRef && !colorPickerRef.contains(e.target as Node)) {
169
+ colorPickerOpen = false;
170
+ }
171
+ }
172
+ document.addEventListener('mousedown', handleMouseDown, true);
173
+ return () => {
174
+ document.removeEventListener('mousedown', handleMouseDown, true);
175
+ };
176
+ });
177
+ </script>
178
+
179
+ <svelte:window onhashchange={onHashChange} />
180
+
181
+ <aside
182
+ aria-label="Sidebar navigation"
183
+ class="fixed inset-y-0 left-0 z-30 flex flex-col backdrop-blur-xl transition-all duration-300"
184
+ style="background-color: var(--sidebar);"
185
+ class:w-64={!collapsed}
186
+ class:w-16={collapsed}
187
+ >
188
+ <!-- Logo -->
189
+ <div class="flex h-16 items-center justify-between px-4">
190
+ {#if !collapsed}
191
+ <div class="flex items-center gap-3">
192
+ <div class="w-8 h-8 rounded-lg bg-gradient-to-tr from-primary to-purple-500 shrink-0" style="box-shadow: 0 4px 12px oklch(0.488 0.243 264.376 / 20%);"></div>
193
+ <span class="font-semibold text-lg tracking-tight text-sidebar-foreground">{title}</span>
194
+ </div>
195
+ {:else}
196
+ <div class="w-8 h-8 rounded-lg bg-gradient-to-tr from-primary to-purple-500 shrink-0 mx-auto" style="box-shadow: 0 4px 12px oklch(0.488 0.243 264.376 / 20%);"></div>
197
+ {/if}
198
+ {#if !collapsed}
199
+ <TooltipButton tooltip={t('common.toggleSidebar')} variant="ghost" size="icon-sm" onclick={onToggle}>
200
+ <ChevronLeft class="h-4 w-4" />
201
+ </TooltipButton>
202
+ {:else}
203
+ <TooltipButton tooltip={t('common.toggleSidebar')} variant="ghost" size="icon-sm" onclick={onToggle} class="mx-auto mt-2 mb-2 block">
204
+ <ChevronRight class="h-4 w-4" />
205
+ </TooltipButton>
206
+ {/if}
207
+ </div>
208
+
209
+ <ScrollArea class="flex-1">
210
+ <nav aria-label="Main menu" class="py-4 px-3 space-y-1">
211
+ {#if menu && menu.length > 0}
212
+ <!-- Custom multi-level menu -->
213
+ {#each menu as item}
214
+ <SidebarItem {item} currentPath={path} {collapsed} depth={0} />
215
+ {/each}
216
+ {:else}
217
+ <!-- Auto-generated menu from resources (fallback) -->
218
+ {#each navGroups as group}
219
+ {#if group.name && !collapsed}
220
+ <!-- Grouped section with Collapsible -->
221
+ <Collapsible.Root open={openGroups.has(group.name)} onOpenChange={(isOpen) => {
222
+ const next = new Set(openGroups);
223
+ if (isOpen) next.add(group.name!); else next.delete(group.name!);
224
+ openGroups = next;
225
+ }}>
226
+ <Collapsible.Trigger
227
+ class="flex w-full items-center justify-between px-3 py-1.5 text-sm font-semibold tracking-wider text-sidebar-foreground/60 hover:text-sidebar-foreground transition-colors"
228
+ >
229
+ <span>{group.name}</span>
230
+ <ChevronDown class="h-3 w-3 transition-transform {openGroups.has(group.name) ? 'rotate-180' : ''}" />
231
+ </Collapsible.Trigger>
232
+ <Collapsible.Content>
233
+ <div class="mt-1 space-y-1">
234
+ {#each group.items as item}
235
+ {@const active = isActive(item.path)}
236
+ <a
237
+ href={effectiveRouteMode === 'hash' ? `#${item.path}` : item.path}
238
+ class="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-all duration-200
239
+ {active
240
+ ? 'bg-sidebar-accent text-sidebar-accent-foreground sidebar-nav-active'
241
+ : 'text-sidebar-foreground/70 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground'}"
242
+ >
243
+ <item.Icon class="h-4 w-4 flex-shrink-0" />
244
+ <span>{item.label}</span>
245
+ </a>
246
+ {/each}
247
+ </div>
248
+ </Collapsible.Content>
249
+ </Collapsible.Root>
250
+ {:else}
251
+ <!-- Ungrouped items (flat) -->
252
+ {#each group.items as item}
253
+ {@const active = isActive(item.path)}
254
+ {#if collapsed}
255
+ <Tooltip.Root>
256
+ <Tooltip.Trigger>
257
+ {#snippet child({ props }: { props: Record<string, unknown> })}
258
+ <a
259
+ {...props}
260
+ href={effectiveRouteMode === 'hash' ? `#${item.path}` : item.path}
261
+ class="flex items-center justify-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-all duration-200
262
+ {active
263
+ ? 'bg-sidebar-accent text-sidebar-accent-foreground'
264
+ : 'text-sidebar-foreground/70 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground'}"
265
+ >
266
+ <item.Icon class="h-4 w-4 flex-shrink-0" />
267
+ </a>
268
+ {/snippet}
269
+ </Tooltip.Trigger>
270
+ <Tooltip.Content side="right">
271
+ {item.label}
272
+ </Tooltip.Content>
273
+ </Tooltip.Root>
274
+ {:else}
275
+ <a
276
+ href={effectiveRouteMode === 'hash' ? `#${item.path}` : item.path}
277
+ class="flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-all duration-200
278
+ {active
279
+ ? 'bg-sidebar-accent text-sidebar-accent-foreground sidebar-nav-active'
280
+ : 'text-sidebar-foreground/70 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground'}"
281
+ >
282
+ <item.Icon class="h-4 w-4 flex-shrink-0" />
283
+ <span>{item.label}</span>
284
+ </a>
285
+ {/if}
286
+ {/each}
287
+ {/if}
288
+ {/each}
289
+ {/if}
290
+ </nav>
291
+ </ScrollArea>
292
+
293
+ <!-- Footer -->
294
+ <div>
295
+ <!-- Color theme picker -->
296
+ {#if !collapsed}
297
+ <div class="px-3 pt-3 pb-1">
298
+ <div class="relative" bind:this={colorPickerRef}>
299
+ <Button
300
+ variant="ghost"
301
+ class="flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-sm text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-foreground transition-colors h-auto justify-start"
302
+ onclick={() => { if (!colorPickerOpen) colorPickerOpenedAt = Date.now(); colorPickerOpen = !colorPickerOpen; }}
303
+ >
304
+ <Palette class="h-4 w-4" />
305
+ <span class="flex-1 text-left text-xs">{t('common.toggleTheme')}</span>
306
+ <span
307
+ class="h-3.5 w-3.5 rounded-full ring-1 ring-offset-1 ring-offset-sidebar"
308
+ style="background-color: {colorThemes.find(c => c.id === getColorTheme())?.color ?? '#6366f1'}; --tw-ring-color: {colorThemes.find(c => c.id === getColorTheme())?.color ?? '#6366f1'}"
309
+ ></span>
310
+ </Button>
311
+ {#if colorPickerOpen}
312
+ <div class="absolute bottom-full left-0 mb-1 z-50 w-40 rounded-lg border bg-popover p-1 text-popover-foreground shadow-lg animate-in fade-in-0 zoom-in-95">
313
+ {#each colorThemes as ct}
314
+ <button
315
+ class="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground transition-colors"
316
+ onclick={() => { setColorTheme(ct.id as typeof ct.id & import('@svadmin/core').ColorTheme); colorPickerOpen = false; }}
317
+ >
318
+ <span
319
+ class="h-3.5 w-3.5 rounded-full {getColorTheme() === ct.id ? 'ring-2 ring-offset-1 scale-110' : 'opacity-70'}"
320
+ style="background-color: {ct.color}; {getColorTheme() === ct.id ? `--tw-ring-color: ${ct.color}` : ''}"
321
+ ></span>
322
+ <span class="text-xs">{ct.label}</span>
323
+ </button>
324
+ {/each}
325
+ </div>
326
+ {/if}
327
+ </div>
328
+ </div>
329
+ {/if}
330
+
331
+ <!-- User info -->
332
+ {#if !collapsed && identity}
333
+ <div class="px-3 pb-3 pt-1">
334
+ <div class="flex items-center gap-3 rounded-lg p-2 hover:bg-sidebar-accent/50 transition-colors">
335
+ <Avatar
336
+ src={(identity as Record<string, unknown>).avatar as string | undefined}
337
+ alt={identity.name ?? 'User'}
338
+ fallback={identity.name?.charAt(0).toUpperCase() ?? 'U'}
339
+ size="sm"
340
+ />
341
+ <div class="flex-1 min-w-0">
342
+ <p class="truncate text-sm font-medium text-sidebar-foreground">{identity.name}</p>
343
+ <p class="truncate text-[10px] text-sidebar-foreground/50">{((identity as Record<string, unknown>).role || (identity as Record<string, unknown>).roleName) ?? 'User'}</p>
344
+ </div>
345
+ </div>
346
+ <div class="flex items-center justify-between px-1 mt-1">
347
+ <TooltipButton tooltip={t('common.switchLanguage')} variant="ghost" size="icon-sm" onclick={toggleLocale} class="text-sidebar-foreground/60 hover:text-sidebar-foreground">
348
+ <span class="text-xs font-bold">{localeLabel}</span>
349
+ </TooltipButton>
350
+ <TooltipButton tooltip={t('common.toggleTheme')} variant="ghost" size="icon-sm" onclick={toggleTheme} class="text-sidebar-foreground/60 hover:text-sidebar-foreground">
351
+ {#if getResolvedTheme() === 'dark'}
352
+ <Sun class="h-4 w-4" />
353
+ {:else}
354
+ <Moon class="h-4 w-4" />
355
+ {/if}
356
+ </TooltipButton>
357
+ <TooltipButton tooltip={t('settings.title')} variant="ghost" size="icon-sm" onclick={() => navigate('/settings')} class="text-sidebar-foreground/60 hover:text-sidebar-foreground">
358
+ <Settings class="h-4 w-4" />
359
+ </TooltipButton>
360
+ <TooltipButton tooltip={t('common.logout')} variant="ghost" size="icon-sm" onclick={onLogout} class="text-sidebar-foreground/60 hover:text-destructive">
361
+ <LogOut class="h-4 w-4" />
362
+ </TooltipButton>
363
+ </div>
364
+ </div>
365
+ {:else if collapsed}
366
+ <div class="px-1 py-3 space-y-1">
367
+ <Tooltip.Root>
368
+ <Tooltip.Trigger>
369
+ {#snippet child({ props }: { props: Record<string, unknown> })}
370
+ <Button {...props} variant="ghost" size="icon" onclick={toggleLocale} class="w-full text-sidebar-foreground/60 hover:text-sidebar-foreground">
371
+ <span class="text-xs font-bold">{localeLabel}</span>
372
+ </Button>
373
+ {/snippet}
374
+ </Tooltip.Trigger>
375
+ <Tooltip.Content side="right">{t('common.switchLanguage')}</Tooltip.Content>
376
+ </Tooltip.Root>
377
+ <Tooltip.Root>
378
+ <Tooltip.Trigger>
379
+ {#snippet child({ props }: { props: Record<string, unknown> })}
380
+ <Button {...props} variant="ghost" size="icon" onclick={toggleTheme} class="w-full text-sidebar-foreground/60 hover:text-sidebar-foreground">
381
+ {#if getResolvedTheme() === 'dark'}
382
+ <Sun class="h-4 w-4" />
383
+ {:else}
384
+ <Moon class="h-4 w-4" />
385
+ {/if}
386
+ </Button>
387
+ {/snippet}
388
+ </Tooltip.Trigger>
389
+ <Tooltip.Content side="right">{t('common.toggleTheme')}</Tooltip.Content>
390
+ </Tooltip.Root>
391
+ <Tooltip.Root>
392
+ <Tooltip.Trigger>
393
+ {#snippet child({ props }: { props: Record<string, unknown> })}
394
+ <Button {...props} variant="ghost" size="icon" onclick={onLogout} class="w-full text-sidebar-foreground/60 hover:text-destructive">
395
+ <LogOut class="h-4 w-4" />
396
+ </Button>
397
+ {/snippet}
398
+ </Tooltip.Trigger>
399
+ <Tooltip.Content side="right">{t('common.logout')}</Tooltip.Content>
400
+ </Tooltip.Root>
401
+ </div>
402
+ {:else}
403
+ <div class="flex gap-1 p-3">
404
+ <TooltipButton tooltip={t('common.switchLanguage')} variant="ghost" size="icon" onclick={toggleLocale} class="flex-1 text-sidebar-foreground/60 hover:text-sidebar-foreground">
405
+ <span class="text-xs font-bold">{localeLabel}</span>
406
+ </TooltipButton>
407
+ <TooltipButton tooltip={t('common.toggleTheme')} variant="ghost" size="icon" onclick={toggleTheme} class="flex-1 text-sidebar-foreground/60 hover:text-sidebar-foreground">
408
+ {#if getResolvedTheme() === 'dark'}
409
+ <Sun class="h-4 w-4" />
410
+ {:else}
411
+ <Moon class="h-4 w-4" />
412
+ {/if}
413
+ </TooltipButton>
414
+ </div>
415
+ {/if}
416
+ </div>
417
+ </aside>
@@ -0,0 +1,14 @@
1
+ import type { Identity, MenuItem } from '@svadmin/core';
2
+ type $$ComponentProps = {
3
+ collapsed: boolean;
4
+ identity: Identity | null;
5
+ title: string;
6
+ onToggle: () => void;
7
+ onLogout: () => void;
8
+ menu?: MenuItem[];
9
+ /** 'hash' for SPA hash routing, 'path' for SvelteKit/filesystem routing, 'auto' to detect */
10
+ routeMode?: 'hash' | 'path' | 'auto';
11
+ };
12
+ declare const Sidebar: import("svelte").Component<$$ComponentProps, {}, "">;
13
+ type Sidebar = ReturnType<typeof Sidebar>;
14
+ export default Sidebar;
@@ -0,0 +1,129 @@
1
+ <script lang="ts">
2
+ import type { MenuItem } from '@svadmin/core';
3
+ import { t } from '@svadmin/core/i18n';
4
+ import * as Collapsible from './ui/collapsible/index.js';
5
+ import * as Tooltip from './ui/tooltip/index.js';
6
+ import SidebarItem from './SidebarItem.svelte';
7
+ import {
8
+ LayoutDashboard, FileText, Users, Settings, Home,
9
+ ChevronDown, Folder, ExternalLink, type Icon as LucideIcon,
10
+ } from '@lucide/svelte';
11
+
12
+ let { item, currentPath, collapsed = false, depth = 0 }: {
13
+ item: MenuItem;
14
+ currentPath: string;
15
+ collapsed?: boolean;
16
+ depth?: number;
17
+ } = $props();
18
+
19
+ const iconMap: Record<string, typeof LayoutDashboard> = {
20
+ dashboard: LayoutDashboard,
21
+ posts: FileText,
22
+ users: Users,
23
+ settings: Settings,
24
+ home: Home,
25
+ folder: Folder,
26
+ };
27
+
28
+ function getIcon(name?: string): typeof LayoutDashboard {
29
+ if (!name) return depth === 0 ? Settings : Folder;
30
+ return iconMap[name] ?? Settings;
31
+ }
32
+
33
+ function getLabel(mi: MenuItem): string {
34
+ return mi.label ?? mi.name;
35
+ }
36
+
37
+ function isActive(itemHref: string | undefined): boolean {
38
+ if (!itemHref) return false;
39
+ if (itemHref === '/') return currentPath === '/';
40
+ return currentPath.startsWith(itemHref);
41
+ }
42
+
43
+ /** Check if any child (recursively) is active — used to auto-open parent groups */
44
+ function hasActiveChild(menuItem: MenuItem): boolean {
45
+ if (isActive(menuItem.href)) return true;
46
+ return menuItem.children?.some((c: MenuItem) => hasActiveChild(c)) ?? false;
47
+ }
48
+
49
+ const hasChildren = $derived(item.children && item.children.length > 0);
50
+ const active = $derived(isActive(item.href));
51
+ const childActive = $derived(hasActiveChild(item));
52
+ const isExternal = $derived(item.target === '_blank');
53
+
54
+ // Track open state — auto-open if a child is active
55
+ let isOpen = $state(false);
56
+ $effect(() => { if (childActive) isOpen = true; });
57
+
58
+ const Icon = $derived(getIcon(item.icon));
59
+ const label = $derived(getLabel(item));
60
+ </script>
61
+
62
+ {#if item.meta?.hidden}
63
+ <!-- hidden item, render nothing -->
64
+ {:else if hasChildren && !collapsed}
65
+ <!-- Parent node with children: render as collapsible group -->
66
+ <Collapsible.Root bind:open={isOpen}>
67
+ <Collapsible.Trigger
68
+ class="flex w-full items-center justify-between rounded-lg px-3 py-2 text-sm font-medium transition-all duration-200
69
+ {childActive
70
+ ? 'text-sidebar-foreground bg-sidebar-accent/30'
71
+ : 'text-sidebar-foreground/70 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground'}"
72
+ style="padding-left: {12 + depth * 12}px"
73
+ >
74
+ <span class="flex items-center gap-3">
75
+ <Icon class="h-4 w-4 flex-shrink-0" />
76
+ <span>{label}</span>
77
+ </span>
78
+ <ChevronDown class="h-3.5 w-3.5 transition-transform duration-200 {isOpen ? 'rotate-180' : ''}" />
79
+ </Collapsible.Trigger>
80
+ <Collapsible.Content>
81
+ <div class="mt-0.5 space-y-0.5" style="padding-left: {depth > 0 ? 0 : 0}px">
82
+ {#each item.children as child}
83
+ <SidebarItem item={child} {currentPath} {collapsed} depth={depth + 1} />
84
+ {/each}
85
+ </div>
86
+ </Collapsible.Content>
87
+ </Collapsible.Root>
88
+ {:else if collapsed}
89
+ <!-- Collapsed sidebar: icon-only with tooltip -->
90
+ <Tooltip.Root>
91
+ <Tooltip.Trigger>
92
+ {#snippet child({ props }: { props: Record<string, unknown> })}
93
+ <a
94
+ {...props}
95
+ href={item.href ? `#${item.href}` : undefined}
96
+ target={isExternal ? '_blank' : undefined}
97
+ rel={isExternal ? 'noopener noreferrer' : undefined}
98
+ class="flex items-center justify-center rounded-lg px-3 py-2.5 text-sm font-medium transition-all duration-200
99
+ {active
100
+ ? 'bg-sidebar-accent text-sidebar-accent-foreground'
101
+ : 'text-sidebar-foreground/70 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground'}"
102
+ >
103
+ <Icon class="h-4 w-4 flex-shrink-0" />
104
+ </a>
105
+ {/snippet}
106
+ </Tooltip.Trigger>
107
+ <Tooltip.Content side="right">
108
+ {label}
109
+ </Tooltip.Content>
110
+ </Tooltip.Root>
111
+ {:else}
112
+ <!-- Leaf node: render as a link -->
113
+ <a
114
+ href={item.href ? `#${item.href}` : undefined}
115
+ target={isExternal ? '_blank' : undefined}
116
+ rel={isExternal ? 'noopener noreferrer' : undefined}
117
+ class="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-all duration-200
118
+ {active
119
+ ? 'bg-sidebar-accent text-sidebar-accent-foreground sidebar-nav-active'
120
+ : 'text-sidebar-foreground/70 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground'}"
121
+ style="padding-left: {12 + depth * 12}px"
122
+ >
123
+ <Icon class="h-4 w-4 flex-shrink-0" />
124
+ <span class="flex-1">{label}</span>
125
+ {#if isExternal}
126
+ <ExternalLink class="h-3 w-3 opacity-50" />
127
+ {/if}
128
+ </a>
129
+ {/if}
@@ -0,0 +1,11 @@
1
+ import type { MenuItem } from '@svadmin/core';
2
+ import SidebarItem from './SidebarItem.svelte';
3
+ type $$ComponentProps = {
4
+ item: MenuItem;
5
+ currentPath: string;
6
+ collapsed?: boolean;
7
+ depth?: number;
8
+ };
9
+ declare const SidebarItem: import("svelte").Component<$$ComponentProps, {}, "">;
10
+ type SidebarItem = ReturnType<typeof SidebarItem>;
11
+ export default SidebarItem;