@happyvertical/smrt-svelte 0.55.6 → 0.55.8

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 (318) hide show
  1. package/AGENTS.md +9 -31
  2. package/README.md +195 -5
  3. package/agents/browser-ai.md +47 -0
  4. package/agents/command-palette.md +85 -0
  5. package/agents/import-export.md +62 -0
  6. package/agents/overview-surfaces.md +255 -0
  7. package/agents/screens.md +57 -0
  8. package/agents/workspace.md +202 -5
  9. package/dist/browser-ai/adapters/stt/dictation-source.d.ts.map +1 -1
  10. package/dist/browser-ai/adapters/stt/dictation-source.js +8 -2
  11. package/dist/browser-ai/adapters/stt/factory.d.ts +6 -3
  12. package/dist/browser-ai/adapters/stt/factory.d.ts.map +1 -1
  13. package/dist/browser-ai/adapters/stt/factory.js +19 -9
  14. package/dist/browser-ai/adapters/stt/index.d.ts +3 -1
  15. package/dist/browser-ai/adapters/stt/index.d.ts.map +1 -1
  16. package/dist/browser-ai/adapters/stt/index.js +3 -1
  17. package/dist/browser-ai/adapters/stt/local-speech-model.d.ts +111 -0
  18. package/dist/browser-ai/adapters/stt/local-speech-model.d.ts.map +1 -0
  19. package/dist/browser-ai/adapters/stt/local-speech-model.js +377 -0
  20. package/dist/browser-ai/adapters/stt/local-speech.d.ts +82 -0
  21. package/dist/browser-ai/adapters/stt/local-speech.d.ts.map +1 -0
  22. package/dist/browser-ai/adapters/stt/local-speech.js +317 -0
  23. package/dist/browser-ai/adapters/stt/local-speech.worker.d.ts +2 -0
  24. package/dist/browser-ai/adapters/stt/local-speech.worker.d.ts.map +1 -0
  25. package/dist/browser-ai/adapters/stt/local-speech.worker.js +32 -0
  26. package/dist/browser-ai/adapters/stt/transformers-env.d.ts +8 -0
  27. package/dist/browser-ai/adapters/stt/transformers-env.d.ts.map +1 -0
  28. package/dist/browser-ai/adapters/stt/transformers-env.js +17 -0
  29. package/dist/browser-ai/adapters/stt/types.d.ts +54 -9
  30. package/dist/browser-ai/adapters/stt/types.d.ts.map +1 -1
  31. package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts +5 -0
  32. package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts.map +1 -1
  33. package/dist/browser-ai/adapters/tts/browser-synthesis.js +83 -55
  34. package/dist/browser-ai/capabilities/speech-probe.d.ts +29 -0
  35. package/dist/browser-ai/capabilities/speech-probe.d.ts.map +1 -0
  36. package/dist/browser-ai/capabilities/speech-probe.js +19 -0
  37. package/dist/browser-ai/core/errors.d.ts +9 -0
  38. package/dist/browser-ai/core/errors.d.ts.map +1 -1
  39. package/dist/browser-ai/core/errors.js +12 -0
  40. package/dist/browser-ai/index.d.ts +1 -0
  41. package/dist/browser-ai/index.d.ts.map +1 -1
  42. package/dist/browser-ai/index.js +1 -0
  43. package/dist/components/app/AppShell.svelte +587 -33
  44. package/dist/components/app/AppShell.svelte.d.ts +75 -4
  45. package/dist/components/app/AppShell.svelte.d.ts.map +1 -1
  46. package/dist/components/app/DockToggles.svelte +0 -1
  47. package/dist/components/app/dock-toggle.d.ts +7 -1
  48. package/dist/components/app/dock-toggle.d.ts.map +1 -1
  49. package/dist/components/app/index.d.ts +2 -1
  50. package/dist/components/app/index.d.ts.map +1 -1
  51. package/dist/components/app/slot-item.d.ts +21 -0
  52. package/dist/components/app/slot-item.d.ts.map +1 -0
  53. package/dist/components/app/slot-item.js +1 -0
  54. package/dist/components/command-palette/CommandPalette.svelte +75 -0
  55. package/dist/components/command-palette/CommandPalette.svelte.d.ts +22 -0
  56. package/dist/components/command-palette/CommandPalette.svelte.d.ts.map +1 -0
  57. package/dist/components/command-palette/CommandPaletteDialog.svelte +406 -0
  58. package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts +18 -0
  59. package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts.map +1 -0
  60. package/dist/components/command-palette/CommandPaletteTrigger.svelte +91 -0
  61. package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts +17 -0
  62. package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts.map +1 -0
  63. package/dist/components/command-palette/context.d.ts +18 -0
  64. package/dist/components/command-palette/context.d.ts.map +1 -0
  65. package/dist/components/command-palette/context.js +38 -0
  66. package/dist/components/command-palette/controller.svelte.d.ts +70 -0
  67. package/dist/components/command-palette/controller.svelte.d.ts.map +1 -0
  68. package/dist/components/command-palette/controller.svelte.js +379 -0
  69. package/dist/components/command-palette/hotkeys.d.ts +30 -0
  70. package/dist/components/command-palette/hotkeys.d.ts.map +1 -0
  71. package/dist/components/command-palette/hotkeys.js +161 -0
  72. package/dist/components/command-palette/index.d.ts +19 -0
  73. package/dist/components/command-palette/index.d.ts.map +1 -0
  74. package/dist/components/command-palette/index.js +17 -0
  75. package/dist/components/command-palette/match.d.ts +38 -0
  76. package/dist/components/command-palette/match.d.ts.map +1 -0
  77. package/dist/components/command-palette/match.js +172 -0
  78. package/dist/components/command-palette/providers.d.ts +159 -0
  79. package/dist/components/command-palette/providers.d.ts.map +1 -0
  80. package/dist/components/command-palette/providers.js +345 -0
  81. package/dist/components/command-palette/rank.d.ts +20 -0
  82. package/dist/components/command-palette/rank.d.ts.map +1 -0
  83. package/dist/components/command-palette/rank.js +74 -0
  84. package/dist/components/command-palette/types.d.ts +119 -0
  85. package/dist/components/command-palette/types.d.ts.map +1 -0
  86. package/dist/components/command-palette/types.js +10 -0
  87. package/dist/components/command-palette/use-provider.svelte.d.ts +14 -0
  88. package/dist/components/command-palette/use-provider.svelte.d.ts.map +1 -0
  89. package/dist/components/command-palette/use-provider.svelte.js +23 -0
  90. package/dist/components/forms/AddressInput.svelte +2 -15
  91. package/dist/components/forms/AddressInput.svelte.d.ts.map +1 -1
  92. package/dist/components/forms/DateRangeInput.svelte +2 -15
  93. package/dist/components/forms/DateRangeInput.svelte.d.ts.map +1 -1
  94. package/dist/components/forms/DateTimeInput.svelte +8 -15
  95. package/dist/components/forms/DateTimeInput.svelte.d.ts.map +1 -1
  96. package/dist/components/forms/MeasurementInput.svelte +2 -15
  97. package/dist/components/forms/MeasurementInput.svelte.d.ts.map +1 -1
  98. package/dist/components/forms/MoneyInput.svelte +8 -25
  99. package/dist/components/forms/MoneyInput.svelte.d.ts.map +1 -1
  100. package/dist/components/forms/NumberInput.svelte +7 -15
  101. package/dist/components/forms/NumberInput.svelte.d.ts.map +1 -1
  102. package/dist/components/forms/PhoneInput.svelte +7 -15
  103. package/dist/components/forms/PhoneInput.svelte.d.ts.map +1 -1
  104. package/dist/components/forms/SelectInput.svelte +34 -40
  105. package/dist/components/forms/SelectInput.svelte.d.ts.map +1 -1
  106. package/dist/components/forms/TextInput.svelte +20 -37
  107. package/dist/components/forms/TextInput.svelte.d.ts.map +1 -1
  108. package/dist/components/forms/TextareaInput.svelte +19 -35
  109. package/dist/components/forms/TextareaInput.svelte.d.ts.map +1 -1
  110. package/dist/components/import-export/ImportExport.svelte +678 -0
  111. package/dist/components/import-export/ImportExport.svelte.d.ts +5 -0
  112. package/dist/components/import-export/ImportExport.svelte.d.ts.map +1 -0
  113. package/dist/components/import-export/collection-adapter.d.ts +35 -0
  114. package/dist/components/import-export/collection-adapter.d.ts.map +1 -0
  115. package/dist/components/import-export/collection-adapter.js +42 -0
  116. package/dist/components/import-export/csv.d.ts +60 -0
  117. package/dist/components/import-export/csv.d.ts.map +1 -0
  118. package/dist/components/import-export/csv.js +192 -0
  119. package/dist/components/import-export/download.d.ts +4 -0
  120. package/dist/components/import-export/download.d.ts.map +1 -0
  121. package/dist/components/import-export/download.js +17 -0
  122. package/dist/components/import-export/export.d.ts +25 -0
  123. package/dist/components/import-export/export.d.ts.map +1 -0
  124. package/dist/components/import-export/export.js +68 -0
  125. package/dist/components/import-export/fields.d.ts +48 -0
  126. package/dist/components/import-export/fields.d.ts.map +1 -0
  127. package/dist/components/import-export/fields.js +103 -0
  128. package/dist/components/import-export/index.d.ts +12 -0
  129. package/dist/components/import-export/index.d.ts.map +1 -0
  130. package/dist/components/import-export/index.js +9 -0
  131. package/dist/components/import-export/mapping.d.ts +12 -0
  132. package/dist/components/import-export/mapping.d.ts.map +1 -0
  133. package/dist/components/import-export/mapping.js +38 -0
  134. package/dist/components/import-export/props.d.ts +34 -0
  135. package/dist/components/import-export/props.d.ts.map +1 -0
  136. package/dist/components/import-export/props.js +1 -0
  137. package/dist/components/import-export/report.d.ts +13 -0
  138. package/dist/components/import-export/report.d.ts.map +1 -0
  139. package/dist/components/import-export/report.js +50 -0
  140. package/dist/components/import-export/runner.d.ts +17 -0
  141. package/dist/components/import-export/runner.d.ts.map +1 -0
  142. package/dist/components/import-export/runner.js +39 -0
  143. package/dist/components/import-export/types.d.ts +100 -0
  144. package/dist/components/import-export/types.d.ts.map +1 -0
  145. package/dist/components/import-export/types.js +6 -0
  146. package/dist/components/import-export/validate.d.ts +39 -0
  147. package/dist/components/import-export/validate.d.ts.map +1 -0
  148. package/dist/components/import-export/validate.js +268 -0
  149. package/dist/components/overview/OverviewGrid.svelte +579 -0
  150. package/dist/components/overview/OverviewGrid.svelte.d.ts +5 -0
  151. package/dist/components/overview/OverviewGrid.svelte.d.ts.map +1 -0
  152. package/dist/components/overview/WidgetOptionsForm.svelte +193 -0
  153. package/dist/components/overview/WidgetOptionsForm.svelte.d.ts +5 -0
  154. package/dist/components/overview/WidgetOptionsForm.svelte.d.ts.map +1 -0
  155. package/dist/components/overview/controller.svelte.d.ts +92 -0
  156. package/dist/components/overview/controller.svelte.d.ts.map +1 -0
  157. package/dist/components/overview/controller.svelte.js +336 -0
  158. package/dist/components/overview/format.d.ts +13 -0
  159. package/dist/components/overview/format.d.ts.map +1 -0
  160. package/dist/components/overview/format.js +45 -0
  161. package/dist/components/overview/grid-types.d.ts +52 -0
  162. package/dist/components/overview/grid-types.d.ts.map +1 -0
  163. package/dist/components/overview/grid-types.js +1 -0
  164. package/dist/components/overview/index.d.ts +24 -0
  165. package/dist/components/overview/index.d.ts.map +1 -0
  166. package/dist/components/overview/index.js +22 -0
  167. package/dist/components/overview/load.d.ts +30 -0
  168. package/dist/components/overview/load.d.ts.map +1 -0
  169. package/dist/components/overview/load.js +92 -0
  170. package/dist/components/overview/markdown.d.ts +53 -0
  171. package/dist/components/overview/markdown.d.ts.map +1 -0
  172. package/dist/components/overview/markdown.js +203 -0
  173. package/dist/components/overview/model.d.ts +100 -0
  174. package/dist/components/overview/model.d.ts.map +1 -0
  175. package/dist/components/overview/model.js +460 -0
  176. package/dist/components/overview/recipe-widgets.d.ts +77 -0
  177. package/dist/components/overview/recipe-widgets.d.ts.map +1 -0
  178. package/dist/components/overview/recipe-widgets.js +151 -0
  179. package/dist/components/overview/registry.d.ts +45 -0
  180. package/dist/components/overview/registry.d.ts.map +1 -0
  181. package/dist/components/overview/registry.js +112 -0
  182. package/dist/components/overview/resize.d.ts +25 -0
  183. package/dist/components/overview/resize.d.ts.map +1 -0
  184. package/dist/components/overview/resize.js +41 -0
  185. package/dist/components/overview/schema.d.ts +34 -0
  186. package/dist/components/overview/schema.d.ts.map +1 -0
  187. package/dist/components/overview/schema.js +180 -0
  188. package/dist/components/overview/server.d.ts +14 -0
  189. package/dist/components/overview/server.d.ts.map +1 -0
  190. package/dist/components/overview/server.js +13 -0
  191. package/dist/components/overview/types.d.ts +235 -0
  192. package/dist/components/overview/types.d.ts.map +1 -0
  193. package/dist/components/overview/types.js +17 -0
  194. package/dist/components/overview/widgets/ChartWidget.svelte +111 -0
  195. package/dist/components/overview/widgets/ChartWidget.svelte.d.ts +6 -0
  196. package/dist/components/overview/widgets/ChartWidget.svelte.d.ts.map +1 -0
  197. package/dist/components/overview/widgets/MetricWidget.svelte +86 -0
  198. package/dist/components/overview/widgets/MetricWidget.svelte.d.ts +6 -0
  199. package/dist/components/overview/widgets/MetricWidget.svelte.d.ts.map +1 -0
  200. package/dist/components/overview/widgets/NoteWidget.svelte +61 -0
  201. package/dist/components/overview/widgets/NoteWidget.svelte.d.ts +5 -0
  202. package/dist/components/overview/widgets/NoteWidget.svelte.d.ts.map +1 -0
  203. package/dist/components/overview/widgets/RecordListWidget.svelte +91 -0
  204. package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts +6 -0
  205. package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts.map +1 -0
  206. package/dist/components/overview/widgets/ShortcutsWidget.svelte +80 -0
  207. package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts +6 -0
  208. package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts.map +1 -0
  209. package/dist/components/overview/widgets/core.d.ts +44 -0
  210. package/dist/components/overview/widgets/core.d.ts.map +1 -0
  211. package/dist/components/overview/widgets/core.js +222 -0
  212. package/dist/components/overview/widgets/data.d.ts +76 -0
  213. package/dist/components/overview/widgets/data.d.ts.map +1 -0
  214. package/dist/components/overview/widgets/data.js +40 -0
  215. package/dist/components/screens/DetailScreen.svelte +220 -0
  216. package/dist/components/screens/DetailScreen.svelte.d.ts +5 -0
  217. package/dist/components/screens/DetailScreen.svelte.d.ts.map +1 -0
  218. package/dist/components/screens/EditForm.svelte +313 -0
  219. package/dist/components/screens/EditForm.svelte.d.ts +5 -0
  220. package/dist/components/screens/EditForm.svelte.d.ts.map +1 -0
  221. package/dist/components/screens/ListScreen.svelte +191 -0
  222. package/dist/components/screens/ListScreen.svelte.d.ts +5 -0
  223. package/dist/components/screens/ListScreen.svelte.d.ts.map +1 -0
  224. package/dist/components/screens/RecipeScreens.svelte +237 -0
  225. package/dist/components/screens/RecipeScreens.svelte.d.ts +5 -0
  226. package/dist/components/screens/RecipeScreens.svelte.d.ts.map +1 -0
  227. package/dist/components/screens/fields.d.ts +54 -0
  228. package/dist/components/screens/fields.d.ts.map +1 -0
  229. package/dist/components/screens/fields.js +229 -0
  230. package/dist/components/screens/index.d.ts +8 -0
  231. package/dist/components/screens/index.d.ts.map +1 -0
  232. package/dist/components/screens/index.js +6 -0
  233. package/dist/components/screens/types.d.ts +215 -0
  234. package/dist/components/screens/types.d.ts.map +1 -0
  235. package/dist/components/screens/types.js +1 -0
  236. package/dist/components/screens/values.d.ts +62 -0
  237. package/dist/components/screens/values.d.ts.map +1 -0
  238. package/dist/components/screens/values.js +289 -0
  239. package/dist/components/sortable/Sortable.svelte +6 -33
  240. package/dist/components/sortable/Sortable.svelte.d.ts.map +1 -1
  241. package/dist/components/sortable/announce.d.ts +5 -0
  242. package/dist/components/sortable/announce.d.ts.map +1 -0
  243. package/dist/components/sortable/announce.js +33 -0
  244. package/dist/components/sortable/controller.svelte.d.ts +10 -0
  245. package/dist/components/sortable/controller.svelte.d.ts.map +1 -1
  246. package/dist/components/sortable/controller.svelte.js +29 -7
  247. package/dist/components/workspace/admin-shell/AdminShell.svelte +424 -58
  248. package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts +27 -2
  249. package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts.map +1 -1
  250. package/dist/components/workspace/admin-shell/ShellBrand.svelte +86 -0
  251. package/dist/components/workspace/admin-shell/ShellBrand.svelte.d.ts +18 -0
  252. package/dist/components/workspace/admin-shell/ShellBrand.svelte.d.ts.map +1 -0
  253. package/dist/components/workspace/admin-shell/ShellIconButton.svelte +77 -0
  254. package/dist/components/workspace/admin-shell/ShellIconButton.svelte.d.ts +26 -0
  255. package/dist/components/workspace/admin-shell/ShellIconButton.svelte.d.ts.map +1 -0
  256. package/dist/components/workspace/admin-shell/ShellLayoutEditor.svelte +88 -16
  257. package/dist/components/workspace/admin-shell/ShellLayoutEditor.svelte.d.ts.map +1 -1
  258. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte +531 -0
  259. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts +26 -0
  260. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts.map +1 -0
  261. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte +57 -0
  262. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte.d.ts +22 -0
  263. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte.d.ts.map +1 -0
  264. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte +290 -0
  265. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte.d.ts +32 -0
  266. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte.d.ts.map +1 -0
  267. package/dist/components/workspace/admin-shell/TenantNav.svelte +67 -2
  268. package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts +8 -0
  269. package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts.map +1 -1
  270. package/dist/components/workspace/admin-shell/layout-controller.svelte.d.ts +67 -0
  271. package/dist/components/workspace/admin-shell/layout-controller.svelte.d.ts.map +1 -1
  272. package/dist/components/workspace/admin-shell/layout-controller.svelte.js +129 -1
  273. package/dist/components/workspace/admin-shell/layout.d.ts +122 -0
  274. package/dist/components/workspace/admin-shell/layout.d.ts.map +1 -1
  275. package/dist/components/workspace/admin-shell/layout.js +410 -10
  276. package/dist/components/workspace/admin-shell/settings.js +4 -4
  277. package/dist/components/workspace/admin-shell/shell-icons.d.ts +45 -0
  278. package/dist/components/workspace/admin-shell/shell-icons.d.ts.map +1 -0
  279. package/dist/components/workspace/admin-shell/shell-icons.js +66 -0
  280. package/dist/components/workspace/admin-shell/slot-labels.d.ts +33 -0
  281. package/dist/components/workspace/admin-shell/slot-labels.d.ts.map +1 -0
  282. package/dist/components/workspace/admin-shell/slot-labels.js +33 -0
  283. package/dist/components/workspace/admin-shell/slots.d.ts +50 -0
  284. package/dist/components/workspace/admin-shell/slots.d.ts.map +1 -0
  285. package/dist/components/workspace/admin-shell/slots.js +77 -0
  286. package/dist/components/workspace/admin-shell/state.svelte.d.ts +35 -0
  287. package/dist/components/workspace/admin-shell/state.svelte.d.ts.map +1 -1
  288. package/dist/components/workspace/admin-shell/state.svelte.js +111 -0
  289. package/dist/components/workspace/admin-shell/types.d.ts +101 -1
  290. package/dist/components/workspace/admin-shell/types.d.ts.map +1 -1
  291. package/dist/components/workspace/index.d.ts +9 -2
  292. package/dist/components/workspace/index.d.ts.map +1 -1
  293. package/dist/components/workspace/index.js +6 -0
  294. package/dist/components/workspace/manifest-nav.d.ts +20 -0
  295. package/dist/components/workspace/manifest-nav.d.ts.map +1 -1
  296. package/dist/components/workspace/manifest-nav.js +42 -13
  297. package/dist/i18n/server.d.ts +6 -0
  298. package/dist/i18n/server.d.ts.map +1 -1
  299. package/dist/i18n/server.js +6 -0
  300. package/dist/i18n/strings.import-export.d.ts +88 -0
  301. package/dist/i18n/strings.import-export.d.ts.map +1 -0
  302. package/dist/i18n/strings.import-export.js +88 -0
  303. package/dist/i18n/strings.overview.d.ts +100 -0
  304. package/dist/i18n/strings.overview.d.ts.map +1 -0
  305. package/dist/i18n/strings.overview.js +107 -0
  306. package/dist/i18n/strings.palette.d.ts +18 -0
  307. package/dist/i18n/strings.palette.d.ts.map +1 -0
  308. package/dist/i18n/strings.palette.js +18 -0
  309. package/dist/i18n/strings.screens.d.ts +31 -0
  310. package/dist/i18n/strings.screens.d.ts.map +1 -0
  311. package/dist/i18n/strings.screens.js +31 -0
  312. package/dist/i18n/strings.workspace.d.ts +49 -0
  313. package/dist/i18n/strings.workspace.d.ts.map +1 -1
  314. package/dist/i18n/strings.workspace.js +49 -0
  315. package/package.json +59 -19
  316. package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts +0 -51
  317. package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts.map +0 -1
  318. package/dist/browser-ai/adapters/stt/whisper-wasm.js +0 -380
@@ -0,0 +1,290 @@
1
+ <script lang="ts">
2
+ /**
3
+ * A section's entries as a menu: one row per navigation item, in the layout's
4
+ * order with the user's renames (hidden entries are left out). Used on a
5
+ * section's own page when the shell shows only sections
6
+ * (`navMode: 'sections'`). Hosts add per-row content with `meta(entry)`
7
+ * (e.g. "8 records") and `actions(entry)` (e.g. a "New course" link).
8
+ *
9
+ * While the layout is being edited the rows get the same chrome as the nav
10
+ * editor: a grip (drag, or Space plus arrows), an inline rename, and a
11
+ * show/hide toggle, all driving the layout controller. Rows are plain text
12
+ * then, not links.
13
+ */
14
+ import { Input } from '@happyvertical/smrt-ui/forms';
15
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
16
+ import { type Component, type Snippet, tick, untrack } from 'svelte';
17
+ import { M } from '../../../i18n/strings.workspace.js';
18
+ import Sortable from '../../sortable/Sortable.svelte';
19
+ import type { SortableItem, SortableItemMove } from '../../sortable/types.js';
20
+ import { useShellLayout } from './layout-context.js';
21
+ import type { ShellLayoutController } from './layout-controller.svelte.js';
22
+ import ShellIconButton from './ShellIconButton.svelte';
23
+ import ShellSectionIcon from './ShellSectionIcon.svelte';
24
+ import { SHELL_DEFAULT_SECTION_ICON, SHELL_ICON_PATHS } from './shell-icons.js';
25
+ import type { ShellSectionMenuEntry } from './types.js';
26
+
27
+ interface Props {
28
+ /** The section's id (`ShellNavGroup.id ?? heading`). */
29
+ sectionId: string;
30
+ /** The layout API; defaults to the nearest `AppShell`'s. */
31
+ controller?: ShellLayoutController;
32
+ /** Accessible name for the list (default "<section> entries"). */
33
+ 'aria-label'?: string;
34
+ /** Renders host icon names, as for `TenantNav`. */
35
+ iconComponent?: Component<{ name: string; size?: number }>;
36
+ /** Content after the label, e.g. a record count. */
37
+ meta?: Snippet<[ShellSectionMenuEntry]>;
38
+ /** Trailing links or buttons, e.g. "New <noun>". Not shown while editing. */
39
+ actions?: Snippet<[ShellSectionMenuEntry]>;
40
+ /**
41
+ * `list` (default): compact rows. `cards`: a responsive grid of cards, each
42
+ * with a large icon, the label, the item's `description`, then `meta` and
43
+ * `actions` along the bottom.
44
+ */
45
+ layout?: 'list' | 'cards';
46
+ /** Called when the user follows a row link. */
47
+ onNavigate?: () => void;
48
+ }
49
+
50
+ let {
51
+ sectionId,
52
+ controller: provided,
53
+ 'aria-label': ariaLabel,
54
+ iconComponent: IconComponent,
55
+ meta,
56
+ actions,
57
+ layout: layoutMode = 'list',
58
+ onNavigate,
59
+ }: Props = $props();
60
+
61
+ const { t } = useI18n();
62
+ const layout = untrack(() => provided ?? useShellLayout());
63
+
64
+ const section = $derived(layout.sections.find((s) => s.id === sectionId));
65
+ const editing = $derived(layout.editing);
66
+ const label = $derived(section?.heading ?? sectionId);
67
+ const entries = $derived<ShellSectionMenuEntry[]>(
68
+ (section?.items ?? [])
69
+ .filter((entry) => editing || !entry.hidden)
70
+ .map((entry) => ({
71
+ id: entry.id,
72
+ href: entry.item.href,
73
+ label: entry.label,
74
+ defaultLabel: entry.defaultLabel,
75
+ icon: entry.item.icon,
76
+ hidden: entry.hidden,
77
+ item: entry.item,
78
+ })),
79
+ );
80
+ const listLabel = $derived(
81
+ ariaLabel || t(M['ui.section_menu.label'], { label }),
82
+ );
83
+ const containers = $derived([{ id: sectionId, label: listLabel }]);
84
+ const sortableItems = $derived<SortableItem[]>(
85
+ entries.map((entry) => ({
86
+ id: entry.id,
87
+ containerId: sectionId,
88
+ label: entry.label,
89
+ })),
90
+ );
91
+ const entryById = $derived(new Map(entries.map((entry) => [entry.id, entry])));
92
+
93
+ let rootEl: HTMLElement | undefined = $state();
94
+ let renaming = $state<string | null>(null);
95
+
96
+ async function startRename(id: string): Promise<void> {
97
+ renaming = id;
98
+ await tick();
99
+ const input = rootEl?.querySelector<HTMLInputElement>(
100
+ `input[data-item-name="${CSS.escape(id)}"]`,
101
+ );
102
+ input?.focus();
103
+ input?.select();
104
+ }
105
+
106
+ function commitRename(id: string, value: string): void {
107
+ if (renaming !== id) return;
108
+ renaming = null;
109
+ layout.renameItem(id, value);
110
+ }
111
+
112
+ function cancelRename(id: string): void {
113
+ renaming = null;
114
+ rootEl
115
+ ?.querySelector<HTMLElement>(`button[data-item-rename="${CSS.escape(id)}"]`)
116
+ ?.focus();
117
+ }
118
+
119
+ function setShown(id: string, shown: boolean): void {
120
+ if (shown) layout.show(id);
121
+ else layout.hide(id);
122
+ }
123
+
124
+ function onmove(move: SortableItemMove<SortableItem>): void {
125
+ layout.moveItem(move.item.id, sectionId, move.target.index);
126
+ }
127
+ </script>
128
+
129
+ <div
130
+ class="smrt-section-menu"
131
+ class:smrt-section-menu--cards={layoutMode === 'cards'}
132
+ bind:this={rootEl}
133
+ data-editing={editing ? '' : undefined}
134
+ >
135
+ {#if editing}
136
+ <Sortable
137
+ {containers}
138
+ items={sortableItems}
139
+ label={listLabel}
140
+ {onmove}
141
+ >
142
+ {#snippet item({ item: sortable })}
143
+ {@const entry = entryById.get(sortable.id)}
144
+ {#if entry}
145
+ <span class="smrt-section-menu__row" class:smrt-section-menu__row--muted={entry.hidden}>
146
+ {#if entry.icon}
147
+ <ShellSectionIcon name={entry.icon} iconComponent={IconComponent} />
148
+ {/if}
149
+ {#if renaming === entry.id}
150
+ <Input
151
+ class="smrt-section-menu__name"
152
+ interaction={false}
153
+ data-item-name={entry.id}
154
+ aria-label={t(M['ui.shell_layout_editor.item_name'], { label: entry.label })}
155
+ value={entry.label}
156
+ onblur={(event) => commitRename(entry.id, event.currentTarget.value)}
157
+ onkeydown={(event) => {
158
+ if (event.key === 'Enter') {
159
+ event.preventDefault();
160
+ event.stopPropagation();
161
+ const value = event.currentTarget.value;
162
+ commitRename(entry.id, value);
163
+ cancelRename(entry.id);
164
+ } else if (event.key === 'Escape') {
165
+ event.preventDefault();
166
+ event.stopPropagation();
167
+ cancelRename(entry.id);
168
+ }
169
+ }}
170
+ />
171
+ {:else}
172
+ <strong title={entry.defaultLabel !== entry.label ? entry.defaultLabel : undefined}>{entry.label}</strong>
173
+ {/if}
174
+ {@render meta?.(entry)}
175
+ {#if layoutMode === 'cards' && entry.item.description}
176
+ <span class="smrt-section-menu__desc">{entry.item.description}</span>
177
+ {/if}
178
+ </span>
179
+ <ShellIconButton
180
+ icon="edit"
181
+ data-item-rename={entry.id}
182
+ label={t(M['ui.shell_layout_editor.rename_item'], { label: entry.label })}
183
+ onclick={() => startRename(entry.id)}
184
+ />
185
+ {#if entry.defaultLabel !== entry.label}
186
+ <ShellIconButton
187
+ icon="undo"
188
+ label={t(M['ui.shell_layout_editor.reset_item'], { label: entry.label, original: entry.defaultLabel })}
189
+ onclick={() => layout.renameItem(entry.id, null)}
190
+ />
191
+ {/if}
192
+ <ShellIconButton
193
+ icon={entry.hidden ? 'eyeOff' : 'eye'}
194
+ pressed={!entry.hidden}
195
+ label={t(M['ui.shell_layout_editor.show_entry'], { label: entry.label })}
196
+ onclick={() => setShown(entry.id, entry.hidden)}
197
+ />
198
+ {/if}
199
+ {/snippet}
200
+ </Sortable>
201
+ {:else if entries.length === 0}
202
+ <p class="smrt-section-menu__empty">{t(M['ui.section_menu.empty'])}</p>
203
+ {:else if layoutMode === 'cards'}
204
+ <ul class="smrt-section-menu__cards" aria-label={listLabel}>
205
+ {#each entries as entry (entry.id)}
206
+ <li class="smrt-section-menu__card">
207
+ <a class="smrt-section-menu__card-link" href={entry.href} onclick={onNavigate}>
208
+ <span class="smrt-section-menu__card-icon">
209
+ <ShellSectionIcon name={entry.icon ?? SHELL_DEFAULT_SECTION_ICON} size={32} iconComponent={IconComponent} />
210
+ </span>
211
+ <span class="smrt-section-menu__card-title">{entry.label}</span>
212
+ {#if entry.item.description}
213
+ <span class="smrt-section-menu__desc">{entry.item.description}</span>
214
+ {/if}
215
+ </a>
216
+ {#if meta || actions}
217
+ <div class="smrt-section-menu__card-foot">
218
+ {#if meta}<span class="smrt-section-menu__meta">{@render meta(entry)}</span>{/if}
219
+ {#if actions}<span class="smrt-section-menu__actions">{@render actions(entry)}</span>{/if}
220
+ </div>
221
+ {/if}
222
+ </li>
223
+ {/each}
224
+ </ul>
225
+ {:else}
226
+ <ul class="smrt-section-menu__list" aria-label={listLabel}>
227
+ {#each entries as entry (entry.id)}
228
+ <li class="smrt-section-menu__item">
229
+ <a class="smrt-section-menu__link" href={entry.href} onclick={onNavigate}>
230
+ {#if entry.icon}
231
+ <ShellSectionIcon name={entry.icon} iconComponent={IconComponent} />
232
+ {/if}
233
+ <span class="smrt-section-menu__label">{entry.label}</span>
234
+ </a>
235
+ {#if meta}<span class="smrt-section-menu__meta">{@render meta(entry)}</span>{/if}
236
+ {#if actions}<span class="smrt-section-menu__actions">{@render actions(entry)}</span>{/if}
237
+ <svg class="smrt-section-menu__chevron" viewBox="0 0 24 24" width="18" height="18" fill="currentColor" aria-hidden="true" focusable="false"><path d={SHELL_ICON_PATHS.chevronRight} /></svg>
238
+ </li>
239
+ {/each}
240
+ </ul>
241
+ {/if}
242
+ </div>
243
+
244
+ <style>
245
+ .smrt-section-menu { min-inline-size: 0; }
246
+ .smrt-section-menu__list { display: grid; gap: var(--smrt-spacing-1); margin: 0; padding: 0; list-style: none; }
247
+ .smrt-section-menu__item { position: relative; display: flex; align-items: center; gap: var(--smrt-spacing-3); min-inline-size: 0; padding: var(--smrt-spacing-2) var(--smrt-spacing-3); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-medium); background: var(--smrt-color-surface); color: var(--smrt-color-on-surface); }
248
+ .smrt-section-menu__item:hover { background: var(--smrt-color-surface-container-high); }
249
+ .smrt-section-menu__link { flex: 1 1 auto; display: flex; align-items: center; gap: var(--smrt-spacing-3); min-inline-size: 0; min-block-size: var(--smrt-control-target-min, 2rem); color: inherit; text-decoration: none; }
250
+ /* The whole row follows the link; actions sit above the stretched target. */
251
+ .smrt-section-menu__link::after { content: ''; position: absolute; inset: 0; border-radius: inherit; }
252
+ .smrt-section-menu__link:focus-visible { outline: none; }
253
+ .smrt-section-menu__link:focus-visible::after { outline: 2px solid var(--smrt-color-primary); outline-offset: 2px; }
254
+ .smrt-section-menu__label { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: var(--smrt-typography-weight-medium, 500); }
255
+ .smrt-section-menu__meta { flex: 0 0 auto; color: var(--smrt-color-on-surface-variant); font-size: var(--smrt-typography-label-large-size); }
256
+ .smrt-section-menu__actions { position: relative; z-index: 1; flex: 0 0 auto; display: inline-flex; align-items: center; gap: var(--smrt-spacing-1); }
257
+ .smrt-section-menu__chevron { flex: 0 0 auto; color: var(--smrt-color-on-surface-variant); }
258
+ /* Fixed icon column so labels align whatever the glyph (or a missing one). */
259
+ .smrt-section-menu :global(.smrt-shell-section-icon) { inline-size: 20px; block-size: 20px; }
260
+ /* Cards draw a 32px icon: its box must match, or the glyph spills out of
261
+ the centred circle. */
262
+ .smrt-section-menu__card-icon :global(.smrt-shell-section-icon) { inline-size: 32px; block-size: 32px; }
263
+ /* Cards: a responsive grid; the whole card is one stretched link. */
264
+ .smrt-section-menu__cards, .smrt-section-menu--cards :global(.smrt-sortable__items) { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr)); gap: var(--smrt-spacing-3); margin: 0; padding: 0; list-style: none; }
265
+ .smrt-section-menu__card { position: relative; display: flex; flex-direction: column; gap: var(--smrt-spacing-3); min-inline-size: 0; padding: var(--smrt-spacing-4); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-large, var(--smrt-radius-medium)); background: var(--smrt-color-surface); color: var(--smrt-color-on-surface); transition: background-color 120ms, border-color 120ms, transform 120ms; }
266
+ .smrt-section-menu__card:hover { background: var(--smrt-color-surface-container-high); border-color: var(--smrt-color-outline); transform: translateY(-2px); }
267
+ .smrt-section-menu__card-link { flex: 1 1 auto; display: flex; flex-direction: column; gap: var(--smrt-spacing-2); color: inherit; text-decoration: none; }
268
+ .smrt-section-menu__card-link::after { content: ''; position: absolute; inset: 0; border-radius: inherit; }
269
+ .smrt-section-menu__card-link:focus-visible { outline: none; }
270
+ .smrt-section-menu__card-link:focus-visible::after { outline: 2px solid var(--smrt-color-primary); outline-offset: 2px; }
271
+ .smrt-section-menu__card-icon { display: inline-grid; place-items: center; inline-size: 56px; block-size: 56px; border-radius: var(--smrt-radius-full, 9999px); background: var(--smrt-color-primary-container); color: var(--smrt-color-on-primary-container); }
272
+ .smrt-section-menu__card-title { font-size: var(--smrt-typography-title-medium-size, 1rem); font-weight: var(--smrt-typography-weight-medium, 500); overflow-wrap: anywhere; }
273
+ .smrt-section-menu__desc { display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; color: var(--smrt-color-on-surface-variant); font-size: var(--smrt-typography-body-medium-size, 0.875rem); }
274
+ .smrt-section-menu__card-foot { position: relative; z-index: 1; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--smrt-spacing-2); }
275
+ .smrt-section-menu--cards :global(.smrt-sortable__item) { align-items: flex-start; }
276
+ .smrt-section-menu--cards .smrt-section-menu__row { flex-wrap: wrap; }
277
+ .smrt-section-menu--cards .smrt-section-menu__row .smrt-section-menu__desc { flex: 1 1 100%; }
278
+ .smrt-section-menu__empty { margin: 0; color: var(--smrt-color-on-surface-variant); }
279
+
280
+ /* Edit mode: the generic Sortable reads as the same rows. */
281
+ .smrt-section-menu :global(.smrt-sortable__container) { padding: 0; border: 0; background: transparent; gap: var(--smrt-spacing-1); }
282
+ .smrt-section-menu :global(.smrt-sortable__header) { display: none; }
283
+ .smrt-section-menu :global(.smrt-sortable__items) { gap: var(--smrt-spacing-1); }
284
+ .smrt-section-menu :global(.smrt-sortable__item) { border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-medium); background: var(--smrt-color-surface); }
285
+ .smrt-section-menu :global(.smrt-sortable__handle) { inline-size: 1.5rem; block-size: 2rem; }
286
+ .smrt-section-menu__row { flex: 1 1 auto; min-inline-size: 0; display: flex; align-items: center; gap: var(--smrt-spacing-3); padding: var(--smrt-spacing-2) var(--smrt-spacing-1); }
287
+ .smrt-section-menu__row--muted { opacity: 0.55; }
288
+ .smrt-section-menu__row strong { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: var(--smrt-typography-weight-medium, 500); }
289
+ :global(.smrt-section-menu__name) { flex: 1 1 auto; min-inline-size: 0; }
290
+ </style>
@@ -0,0 +1,32 @@
1
+ import { type Component, type Snippet } from 'svelte';
2
+ import type { ShellLayoutController } from './layout-controller.svelte.js';
3
+ import type { ShellSectionMenuEntry } from './types.js';
4
+ interface Props {
5
+ /** The section's id (`ShellNavGroup.id ?? heading`). */
6
+ sectionId: string;
7
+ /** The layout API; defaults to the nearest `AppShell`'s. */
8
+ controller?: ShellLayoutController;
9
+ /** Accessible name for the list (default "<section> entries"). */
10
+ 'aria-label'?: string;
11
+ /** Renders host icon names, as for `TenantNav`. */
12
+ iconComponent?: Component<{
13
+ name: string;
14
+ size?: number;
15
+ }>;
16
+ /** Content after the label, e.g. a record count. */
17
+ meta?: Snippet<[ShellSectionMenuEntry]>;
18
+ /** Trailing links or buttons, e.g. "New <noun>". Not shown while editing. */
19
+ actions?: Snippet<[ShellSectionMenuEntry]>;
20
+ /**
21
+ * `list` (default): compact rows. `cards`: a responsive grid of cards, each
22
+ * with a large icon, the label, the item's `description`, then `meta` and
23
+ * `actions` along the bottom.
24
+ */
25
+ layout?: 'list' | 'cards';
26
+ /** Called when the user follows a row link. */
27
+ onNavigate?: () => void;
28
+ }
29
+ declare const ShellSectionMenu: Component<Props, {}, "">;
30
+ type ShellSectionMenu = ReturnType<typeof ShellSectionMenu>;
31
+ export default ShellSectionMenu;
32
+ //# sourceMappingURL=ShellSectionMenu.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ShellSectionMenu.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/workspace/admin-shell/ShellSectionMenu.svelte.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,OAAO,EAAiB,MAAM,QAAQ,CAAC;AAKrE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAI3E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAGxD,UAAU,KAAK;IACb,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,qBAAqB,CAAC;IACnC,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,aAAa,CAAC,EAAE,SAAS,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,oDAAoD;IACpD,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC;IACxC,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAC3C;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAuLD,QAAA,MAAM,gBAAgB,0BAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
@@ -2,10 +2,11 @@
2
2
  import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
3
  import type { Component } from 'svelte';
4
4
  import { M } from '../../../i18n/strings.workspace.js';
5
+ import ShellSectionIcon from './ShellSectionIcon.svelte';
6
+ import { SHELL_DEFAULT_SECTION_ICON, SHELL_ICON_PATHS } from './shell-icons.js';
5
7
  import type { ShellNavGroup, ShellNavItem } from './types.js';
6
8
 
7
9
  const DEFAULT_ACTION_ICON = 'settings';
8
- const DEFAULT_ACTION_GLYPH = '\u2699';
9
10
 
10
11
  interface Props {
11
12
  /** Navigation items with href, label, icon, and optional children. */
@@ -24,6 +25,14 @@ interface Props {
24
25
  collapsed?: boolean;
25
26
  /** Called when the user clicks a navigation link. */
26
27
  onNavigate?: () => void;
28
+ /**
29
+ * `'items'` (default) lists every group's entries. `'sections'` shows only
30
+ * the sections, one icon link each, to the section's own page
31
+ * (`ShellNavGroup.href`, else `sectionHref(id)`, else its first entry).
32
+ */
33
+ navMode?: 'items' | 'sections';
34
+ /** Section page for groups without an `href` (e.g. user-created ones). */
35
+ sectionHref?: (sectionId: string) => string | undefined;
27
36
  }
28
37
 
29
38
  let {
@@ -35,6 +44,8 @@ let {
35
44
  iconComponent: IconComponent,
36
45
  collapsed = false,
37
46
  onNavigate,
47
+ navMode = 'items',
48
+ sectionHref,
38
49
  }: Props = $props();
39
50
  const { t } = useI18n();
40
51
 
@@ -55,6 +66,23 @@ function isGroupCurrent(group: ShellNavGroup): boolean {
55
66
  return group.items.some(isItemCurrent);
56
67
  }
57
68
 
69
+ function groupId(group: ShellNavGroup): string {
70
+ return group.id ?? group.heading;
71
+ }
72
+
73
+ function groupHref(group: ShellNavGroup): string | undefined {
74
+ return group.href ?? sectionHref?.(groupId(group)) ?? group.items[0]?.href;
75
+ }
76
+
77
+ /** A section is current on its own page or on any of its entries' pages. */
78
+ function isSectionCurrent(group: ShellNavGroup): boolean {
79
+ const href = groupHref(group);
80
+ return (
81
+ (!!href && (href === currentHref || currentHref.startsWith(`${href}/`))) ||
82
+ isGroupCurrent(group)
83
+ );
84
+ }
85
+
58
86
  function showAction(item: ShellNavItem, sectionCurrent: boolean): boolean {
59
87
  if (collapsed || !item.action) return false;
60
88
  return item.action.visibility !== 'active' || sectionCurrent;
@@ -142,8 +170,10 @@ function fallbackIcon(label: string): string {
142
170
  <span class="smrt-tenant-nav__icon" aria-hidden="true">
143
171
  {#if IconComponent}
144
172
  <IconComponent name={action.icon ?? DEFAULT_ACTION_ICON} size={16} />
173
+ {:else if action.icon}
174
+ {action.icon}
145
175
  {:else}
146
- {action.icon ?? DEFAULT_ACTION_GLYPH}
176
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d={SHELL_ICON_PATHS.settings} /></svg>
147
177
  {/if}
148
178
  </span>
149
179
  </a>
@@ -188,6 +218,40 @@ function fallbackIcon(label: string): string {
188
218
 
189
219
  {@render navItems(items)}
190
220
  {#each groups as group}
221
+ {#if navMode === 'sections'}
222
+ {@const href = groupHref(group)}
223
+ {#if href}
224
+ <div class="smrt-tenant-nav__section" data-nav-section={groupId(group)}>
225
+ <div class="smrt-tenant-nav__row">
226
+ <a
227
+ {href}
228
+ class="smrt-tenant-nav__section-link"
229
+ class:smrt-tenant-nav__link--visible-active={isSectionCurrent(group)}
230
+ aria-current={href === currentHref ? 'page' : isSectionCurrent(group) ? 'true' : undefined}
231
+ title={collapsed ? group.heading : undefined}
232
+ onclick={onNavigate}
233
+ >
234
+ <span class="smrt-tenant-nav__icon" aria-hidden="true">
235
+ <ShellSectionIcon
236
+ name={group.icon ?? SHELL_DEFAULT_SECTION_ICON}
237
+ size={18}
238
+ iconComponent={IconComponent}
239
+ />
240
+ </span>
241
+ {#if collapsed}
242
+ <span class="smrt-tenant-nav__sr-only">{group.heading}</span>
243
+ {:else}
244
+ <strong>{group.heading}</strong>
245
+ {/if}
246
+ </a>
247
+ </div>
248
+ </div>
249
+ {/if}
250
+ {:else if group.showTitle === false}
251
+ <div class="smrt-tenant-nav__group smrt-tenant-nav__group--flat" role="group" aria-label={group.heading}>
252
+ <div class="smrt-tenant-nav__group-items">{@render navItems(group.items, isGroupCurrent(group))}</div>
253
+ </div>
254
+ {:else}
191
255
  <details class="smrt-tenant-nav__group" aria-label={group.heading} open>
192
256
  <summary class="smrt-tenant-nav__heading">
193
257
  {#if collapsed}
@@ -199,6 +263,7 @@ function fallbackIcon(label: string): string {
199
263
  </summary>
200
264
  <div class="smrt-tenant-nav__group-items">{@render navItems(group.items, isGroupCurrent(group))}</div>
201
265
  </details>
266
+ {/if}
202
267
  {/each}
203
268
  </nav>
204
269
 
@@ -20,6 +20,14 @@ interface Props {
20
20
  collapsed?: boolean;
21
21
  /** Called when the user clicks a navigation link. */
22
22
  onNavigate?: () => void;
23
+ /**
24
+ * `'items'` (default) lists every group's entries. `'sections'` shows only
25
+ * the sections, one icon link each, to the section's own page
26
+ * (`ShellNavGroup.href`, else `sectionHref(id)`, else its first entry).
27
+ */
28
+ navMode?: 'items' | 'sections';
29
+ /** Section page for groups without an `href` (e.g. user-created ones). */
30
+ sectionHref?: (sectionId: string) => string | undefined;
23
31
  }
24
32
  declare const TenantNav: Component<Props, {}, "">;
25
33
  type TenantNav = ReturnType<typeof TenantNav>;
@@ -1 +1 @@
1
- {"version":3,"file":"TenantNav.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/workspace/admin-shell/TenantNav.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG9D,UAAU,KAAK;IACb,sEAAsE;IACtE,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;IACvB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yDAAyD;IACzD,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;IAClC,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,aAAa,CAAC,EAAE,SAAS,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,2DAA2D;IAC3D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAkKD,QAAA,MAAM,SAAS,0BAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"TenantNav.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/workspace/admin-shell/TenantNav.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAIxC,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG9D,UAAU,KAAK;IACb,sEAAsE;IACtE,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;IACvB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yDAAyD;IACzD,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;IAClC,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,aAAa,CAAC,EAAE,SAAS,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,2DAA2D;IAC3D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IAC/B,0EAA0E;IAC1E,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CACzD;AAgND,QAAA,MAAM,SAAS,0BAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { type ShellLayout, type ShellNavModelSection } from './layout.js';
2
+ import { type ShellPlacementItem, type ShellRegion, type ShellSlot } from './slots.js';
2
3
  import type { PanelEdge, ShellNavGroup, ShellNavItem, ShellPanelDefaults } from './types.js';
3
4
  export interface ShellLayoutControllerOptions {
4
5
  /** The host's flat navigation, before any layout. */
@@ -9,6 +10,16 @@ export interface ShellLayoutControllerOptions {
9
10
  panels: () => ShellPanelDefaults | undefined;
10
11
  /** The layout currently in force (host-owned, or stored by the shell). */
11
12
  layout: () => ShellLayout | null | undefined;
13
+ /**
14
+ * The movable shell items (dock toggles, host items) with their default
15
+ * slots. Omit when the shell has none.
16
+ */
17
+ items?: () => ShellPlacementItem[];
18
+ /**
19
+ * Whether in-place layout editing is offered (the host opted in). Omit for
20
+ * "not offered": `editing` stays false and `setEditing(true)` is refused.
21
+ */
22
+ editable?: () => boolean;
12
23
  /** Store the next layout (and notify the host). */
13
24
  commit: (layout: ShellLayout) => void;
14
25
  }
@@ -21,6 +32,17 @@ export interface ShellLayoutPanelView {
21
32
  visible: boolean;
22
33
  initial: 'collapsed' | 'expanded';
23
34
  }
35
+ /** One movable shell item as an editor presents it. */
36
+ export interface ShellPlacementView {
37
+ id: string;
38
+ label: string;
39
+ /** The slot the item lives in unless the user moved it. */
40
+ defaultSlot: ShellSlot;
41
+ /** The slot the layout puts it in (before any hidden-region fallback). */
42
+ slot: ShellSlot;
43
+ /** The user moved it away from its default slot. */
44
+ moved: boolean;
45
+ }
24
46
  /**
25
47
  * The layout API: the same changes the `ShellLayoutEditor` makes, as plain
26
48
  * calls an assistant (or any host code) can make. Obtain it with
@@ -30,7 +52,17 @@ export interface ShellLayoutPanelView {
30
52
  */
31
53
  export declare class ShellLayoutController {
32
54
  private readonly options;
55
+ private editingState;
33
56
  constructor(options: ShellLayoutControllerOptions);
57
+ /** Whether in-place layout editing is offered by the host. */
58
+ get editable(): boolean;
59
+ /** Whether the shell is in layout edit mode (always false if not `editable`). */
60
+ get editing(): boolean;
61
+ /**
62
+ * Enter or leave layout edit mode. Returns whether the mode changed; entering
63
+ * is refused (`false`) when the host did not opt in.
64
+ */
65
+ setEditing(editing: boolean): boolean;
34
66
  /** The layout in force, normalized. */
35
67
  get layout(): ShellLayout;
36
68
  /** Every section and item in display order, hidden ones flagged. */
@@ -42,6 +74,12 @@ export declare class ShellLayoutController {
42
74
  };
43
75
  /** Each edge panel with its effective visibility and starting state. */
44
76
  get panels(): ShellLayoutPanelView[];
77
+ /** The movable shell items with their default and current slots. */
78
+ get placementItems(): ShellPlacementView[];
79
+ /** Items per slot in display order (every slot present, possibly empty). */
80
+ get placements(): Record<ShellSlot, ShellPlacementView[]>;
81
+ /** Whether a region is shown (its edge is available and not hidden). */
82
+ isRegionVisible(region: ShellRegion): boolean;
45
83
  /** Whether a customization is in force. */
46
84
  get customized(): boolean;
47
85
  /** Whether a section or item is hidden by the layout. */
@@ -63,6 +101,35 @@ export declare class ShellLayoutController {
63
101
  visible?: boolean;
64
102
  initial?: 'collapsed' | 'expanded';
65
103
  }): boolean;
104
+ /**
105
+ * Rename a section (host or custom). A blank label restores the host's
106
+ * suggested heading (custom sections ignore blank labels).
107
+ */
108
+ renameSection(sectionId: string, label: string): boolean;
109
+ /**
110
+ * Rename a navigation item (by its id). `null` or a blank label restores
111
+ * the host's label. Returns whether the layout changed.
112
+ */
113
+ renameItem(itemId: string, label: string | null): boolean;
114
+ /**
115
+ * Set a section's icon (a shell or host icon name). `null` or blank
116
+ * restores the host's suggested icon.
117
+ */
118
+ setSectionIcon(sectionId: string, icon: string | null): boolean;
119
+ /** Show or hide a section's title; hidden titles render its items flat. */
120
+ setSectionTitleVisible(sectionId: string, visible: boolean): boolean;
121
+ /** Create an empty custom section; returns its id, or `null` when blank. */
122
+ createSection(label: string): string | null;
123
+ /** Delete a custom section; its items return to their default sections. */
124
+ deleteSection(sectionId: string): boolean;
125
+ /**
126
+ * Move a shell item (`dock:<tool>`, `slot:<slot>`, or a host item id) to
127
+ * `slot`. Unknown ids and slots are no-ops. If the slot's region is hidden
128
+ * the item still renders, via the slot's fallback chain.
129
+ */
130
+ placeItem(itemId: string, slot: ShellSlot): boolean;
131
+ /** Return a shell item to its default slot. */
132
+ resetItem(itemId: string): boolean;
66
133
  /** Drop every customization. */
67
134
  reset(): boolean;
68
135
  }
@@ -1 +1 @@
1
- {"version":3,"file":"layout-controller.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/workspace/admin-shell/layout-controller.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EAG1B,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EACb,YAAY,EACZ,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,4BAA4B;IAC3C,qDAAqD;IACrD,GAAG,EAAE,MAAM,YAAY,EAAE,CAAC;IAC1B,uDAAuD;IACvD,MAAM,EAAE,MAAM,aAAa,EAAE,CAAC;IAC9B,oDAAoD;IACpD,MAAM,EAAE,MAAM,kBAAkB,GAAG,SAAS,CAAC;IAC7C,0EAA0E;IAC1E,MAAM,EAAE,MAAM,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC;IAC7C,mDAAmD;IACnD,MAAM,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CACvC;AAED,+CAA+C;AAC/C,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,WAAW,GAAG,UAAU,CAAC;CACnC;AAED;;;;;;GAMG;AACH,qBAAa,qBAAqB;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,4BAA4B;IAElE,uCAAuC;IACvC,IAAI,MAAM,IAAI,WAAW,CAIxB;IAED,oEAAoE;IACpE,IAAI,QAAQ,IAAI,oBAAoB,EAAE,CAMrC;IAED,uEAAuE;IACvE,IAAI,OAAO,IAAI;QAAE,GAAG,EAAE,YAAY,EAAE,CAAC;QAAC,MAAM,EAAE,aAAa,EAAE,CAAA;KAAE,CAQ9D;IAED,wEAAwE;IACxE,IAAI,MAAM,IAAI,oBAAoB,EAAE,CAgBnC;IAED,2CAA2C;IAC3C,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,yDAAyD;IACzD,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAI7B,OAAO,CAAC,KAAK;IAOb,sEAAsE;IACtE,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAYxD;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO;IAaxE,8BAA8B;IAC9B,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAWzB,qCAAqC;IACrC,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIzB,uEAAuE;IACvE,QAAQ,CACN,IAAI,EAAE,SAAS,EACf,KAAK,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,WAAW,GAAG,UAAU,CAAA;KAAE,GAC/D,OAAO;IAQV,gCAAgC;IAChC,KAAK,IAAI,OAAO;CAGjB"}
1
+ {"version":3,"file":"layout-controller.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/workspace/admin-shell/layout-controller.svelte.ts"],"names":[],"mappings":"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"}