@riducms/admin 0.2.2 → 0.3.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 (352) hide show
  1. package/THIRD_PARTY_NOTICES.md +60 -37
  2. package/package.json +27 -15
  3. package/src/app/admin-core-view-route.svelte +38 -53
  4. package/src/app/admin-extension-route.svelte +19 -0
  5. package/src/app/admin-layout.scss +175 -0
  6. package/src/app/admin-layout.svelte +144 -410
  7. package/src/app/admin-navigation-progress.svelte +11 -77
  8. package/src/app/admin-page-title.svelte +17 -85
  9. package/src/app/admin-page-title.ts +136 -0
  10. package/src/app/admin-route-error.svelte +24 -0
  11. package/src/app/admin-router-provider.svelte +34 -0
  12. package/src/app/admin-router-root.svelte +41 -0
  13. package/src/app/admin-routes.svelte +56 -19
  14. package/src/app/loading-boundary.svelte +3 -1
  15. package/src/app-meta.ts +13 -0
  16. package/src/app.css +138 -496
  17. package/src/app.svelte +60 -26
  18. package/src/components/brand/ridu-logo.svelte +19 -5
  19. package/src/components/data/list-table.scss +63 -0
  20. package/src/components/icons/LICENSE.md +24 -0
  21. package/src/components/icons/chevron.svelte +8 -0
  22. package/src/components/icons/plus.svelte +12 -0
  23. package/src/components/icons/search.svelte +12 -0
  24. package/src/components/icons/x.svelte +8 -0
  25. package/src/components/json-tree/json-tree-node.svelte +61 -67
  26. package/src/components/json-tree/json-viewer.scss +153 -0
  27. package/src/components/json-tree/json-viewer.svelte +57 -96
  28. package/src/components/ui/banner/banner.scss +28 -0
  29. package/src/components/ui/banner/banner.svelte +9 -8
  30. package/src/components/ui/banner/index.ts +1 -5
  31. package/src/components/ui/code-editor/code-editor.scss +20 -0
  32. package/src/components/ui/code-editor/code-editor.svelte +71 -0
  33. package/src/components/ui/code-editor/code-editor.ts +151 -0
  34. package/src/components/ui/code-editor/code-languages.ts +29 -0
  35. package/src/components/ui/collapsible-panel/collapsible-panel.scss +38 -0
  36. package/src/components/ui/collapsible-panel/collapsible-panel.svelte +13 -0
  37. package/src/components/ui/collapsible-panel/index.ts +1 -0
  38. package/src/components/ui/combobox/combobox.scss +163 -0
  39. package/src/components/ui/combobox/index.ts +22 -0
  40. package/src/components/ui/date-value-control/date-value-calendar.svelte +128 -16
  41. package/src/components/ui/date-value-control/date-value-control-loader.scss +26 -0
  42. package/src/components/ui/date-value-control/date-value-control-loader.svelte +35 -13
  43. package/src/components/ui/date-value-control/date-value-control.scss +223 -0
  44. package/src/components/ui/date-value-control/date-value-control.svelte +62 -44
  45. package/src/components/ui/drawer/drawer-depth.ts +8 -0
  46. package/src/components/ui/dropdown-menu/dropdown-menu-content.svelte +2 -5
  47. package/src/components/ui/dropdown-menu/dropdown-menu-item.svelte +2 -5
  48. package/src/components/ui/dropdown-menu/dropdown-menu-separator.svelte +2 -2
  49. package/src/components/ui/dropdown-menu/dropdown-menu.scss +62 -0
  50. package/src/components/ui/kbd/kbd.scss +17 -0
  51. package/src/components/ui/kbd/kbd.svelte +3 -10
  52. package/src/components/ui/navigation-drawer/navigation-drawer.scss +40 -0
  53. package/src/components/ui/navigation-drawer/navigation-drawer.svelte +38 -0
  54. package/src/components/ui/popover/popover-content.svelte +3 -5
  55. package/src/components/ui/popover/popover.scss +18 -0
  56. package/src/components/ui/radio-group/index.ts +0 -1
  57. package/src/components/ui/radio-group/radio-card-item.svelte +7 -12
  58. package/src/components/ui/radio-group/radio-group.svelte +2 -2
  59. package/src/components/ui/radio-group/radio.scss +45 -0
  60. package/src/components/ui/select/select-content.svelte +5 -6
  61. package/src/components/ui/select/select-item.svelte +8 -8
  62. package/src/components/ui/select/select-scroll-down-button.svelte +3 -5
  63. package/src/components/ui/select/select-scroll-up-button.svelte +3 -5
  64. package/src/components/ui/select/select-trigger.svelte +6 -7
  65. package/src/components/ui/select/select.scss +126 -0
  66. package/src/components/ui/sheet/sheet-content.svelte +6 -34
  67. package/src/components/ui/sheet/sheet-description.svelte +2 -2
  68. package/src/components/ui/sheet/sheet-overlay.svelte +2 -21
  69. package/src/components/ui/sheet/sheet-title.svelte +2 -2
  70. package/src/components/ui/sheet/sheet.scss +221 -0
  71. package/src/components/ui/skeleton/skeleton.scss +20 -0
  72. package/src/components/ui/skeleton/skeleton.svelte +4 -16
  73. package/src/components/ui/sonner/sonner.scss +121 -0
  74. package/src/components/ui/sonner/sonner.svelte +11 -10
  75. package/src/components/ui/status-indicator/status-indicator.scss +48 -0
  76. package/src/components/ui/status-indicator/status-indicator.svelte +14 -14
  77. package/src/components/ui/tabs/tabs-content.svelte +2 -2
  78. package/src/components/ui/tabs/tabs-list.svelte +7 -7
  79. package/src/components/ui/tabs/tabs-trigger.svelte +2 -8
  80. package/src/components/ui/tabs/tabs.scss +86 -0
  81. package/src/components/ui/tabs/tabs.svelte +2 -2
  82. package/src/components/ui/timezone-picker/timezone-picker.svelte +152 -0
  83. package/src/core/api/admin-client.ts +2 -2
  84. package/src/core/bootstrap/admin-bootstrap.ts +396 -0
  85. package/src/core/bootstrap/admin-prepared-state.ts +213 -0
  86. package/src/core/bootstrap/admin-route-modules.ts +66 -0
  87. package/src/core/clipboard/copy-feedback.svelte.ts +43 -0
  88. package/src/core/forms/embedded-fields.ts +4 -8
  89. package/src/core/forms/field-editor-authoring.ts +8 -0
  90. package/src/core/forms/field-issue-focus.ts +4 -4
  91. package/src/core/forms/field-occurrence.ts +4 -7
  92. package/src/core/forms/form-controller.svelte.ts +14 -21
  93. package/src/core/forms/form-draft-recovery.ts +17 -4
  94. package/src/core/forms/form-issue-correlation.ts +13 -13
  95. package/src/core/forms/form-path.ts +17 -0
  96. package/src/core/forms/form-schema.ts +12 -43
  97. package/src/core/forms/form-validation.ts +7 -46
  98. package/src/core/forms/plugin-field-authoring.ts +6 -2
  99. package/src/core/forms/plugin-field-write.ts +2 -6
  100. package/src/core/i18n/admin-i18n.svelte.ts +18 -0
  101. package/src/core/i18n/format-admin-date-time.ts +19 -0
  102. package/src/core/i18n/humanize-identifier.ts +5 -0
  103. package/src/core/i18n/time-zone-label.ts +20 -0
  104. package/src/core/loaders/admin-view-host.svelte +72 -0
  105. package/src/core/loaders/admin-view-loader.svelte.ts +90 -0
  106. package/src/core/notifications/validation-toast.svelte +2 -2
  107. package/src/core/plugins/field-registry.ts +7 -8
  108. package/src/core/routing/admin-paths.ts +53 -2
  109. package/src/core/routing/admin-scroll.svelte.ts +74 -0
  110. package/src/core/routing/admin-view-selection.ts +78 -0
  111. package/src/core/runtime/admin-runtime.svelte.ts +121 -124
  112. package/src/core/schema/field-default.ts +33 -0
  113. package/src/core/schema/field-localization.ts +15 -0
  114. package/src/core/schema/read-document-path.ts +11 -0
  115. package/src/features/account/account-menu.scss +37 -0
  116. package/src/features/account/account-menu.svelte +115 -0
  117. package/src/features/{auth → account}/account-navigation.svelte +16 -19
  118. package/src/features/{auth → account}/account-route.svelte +206 -49
  119. package/src/features/account/account-security-controller.svelte.ts +157 -0
  120. package/src/features/{auth → account}/account-security-route.svelte +140 -42
  121. package/src/features/api-reference/api-reference-code.svelte +64 -0
  122. package/src/features/api-reference/api-reference-content.svelte +258 -0
  123. package/src/features/api-reference/api-reference-drawer.scss +74 -0
  124. package/src/features/api-reference/api-reference-examples.ts +381 -0
  125. package/src/features/api-reference/api-reference-schema.ts +332 -0
  126. package/src/features/api-reference/api-reference.scss +190 -0
  127. package/src/features/api-reference/api-reference.svelte +74 -0
  128. package/src/features/auth/auth-brand.svelte +5 -3
  129. package/src/features/auth/auth-field.svelte +92 -0
  130. package/src/features/auth/auth-frame.svelte +5 -8
  131. package/src/features/auth/auth.scss +122 -0
  132. package/src/features/auth/create-first-user-controller.svelte.ts +20 -51
  133. package/src/features/auth/create-first-user-route.svelte +83 -122
  134. package/src/features/auth/forgot-password-route.svelte +31 -23
  135. package/src/features/auth/login-route.svelte +68 -116
  136. package/src/features/auth/logout-button.scss +34 -0
  137. package/src/features/auth/logout-button.svelte +52 -0
  138. package/src/features/auth/request-verification-route.svelte +27 -22
  139. package/src/features/auth/reset-password-route.svelte +108 -41
  140. package/src/features/auth/verify-email-route.svelte +49 -15
  141. package/src/features/bulk-edit/bulk-edit-fields.ts +23 -0
  142. package/src/features/bulk-edit/bulk-edit.scss +152 -0
  143. package/src/features/bulk-edit/field-picker.svelte +176 -0
  144. package/src/features/collections/bulk/bulk-actions.svelte +148 -0
  145. package/src/features/collections/bulk/bulk-confirmation.svelte +153 -0
  146. package/src/features/collections/bulk/bulk-editor-loader.svelte +95 -0
  147. package/src/features/collections/bulk/bulk-editor.svelte +186 -0
  148. package/src/features/collections/collection-list-cell-values.ts +144 -0
  149. package/src/features/collections/collection-list-controller.svelte.ts +268 -379
  150. package/src/features/collections/collection-list-preferences-controller.svelte.ts +54 -40
  151. package/src/features/collections/collection-list-query.ts +223 -0
  152. package/src/features/collections/collection-list-results.svelte +205 -329
  153. package/src/features/collections/collection-list-route.svelte +143 -884
  154. package/src/features/collections/collection-list.scss +261 -0
  155. package/src/features/collections/collection-list.svelte.ts +362 -0
  156. package/src/features/collections/controls/column-picker.svelte +110 -0
  157. package/src/features/collections/controls/column-pill.svelte +62 -0
  158. package/src/features/collections/controls/filter-builder.svelte +193 -0
  159. package/src/features/collections/controls/filter-row.svelte +142 -0
  160. package/src/features/collections/controls/list-controls.scss +196 -0
  161. package/src/features/collections/controls/list-options.svelte +203 -0
  162. package/src/features/collections/controls/list-pagination.scss +78 -0
  163. package/src/features/collections/controls/list-pagination.svelte +115 -0
  164. package/src/features/collections/controls/list-toolbar.svelte +132 -0
  165. package/src/features/collections/controls/sort-heading.scss +52 -0
  166. package/src/features/collections/controls/sort-heading.svelte +78 -0
  167. package/src/features/collections/list-columns.ts +43 -0
  168. package/src/features/collections/list-workspace.ts +155 -54
  169. package/src/features/dashboard/dashboard-route.svelte +82 -86
  170. package/src/features/dashboard/dashboard.scss +131 -0
  171. package/src/features/development/development-tools.svelte +20 -36
  172. package/src/features/documents/document-action-bar.svelte +438 -0
  173. package/src/features/documents/document-api-view-loader.svelte +17 -6
  174. package/src/features/documents/document-api-view.scss +120 -0
  175. package/src/features/documents/document-api-view.svelte +169 -454
  176. package/src/features/documents/document-controller.svelte.ts +526 -613
  177. package/src/features/documents/document-credentials.scss +37 -0
  178. package/src/features/documents/document-credentials.svelte +72 -0
  179. package/src/features/documents/{document-route-dirty.ts → document-credentials.ts} +25 -0
  180. package/src/features/documents/document-field-sections.scss +39 -0
  181. package/src/features/documents/document-field-sections.svelte +4 -13
  182. package/src/features/documents/document-loading.scss +24 -0
  183. package/src/features/documents/document-lock-controller.svelte.ts +187 -0
  184. package/src/features/documents/document-operation-dialogs.svelte +110 -0
  185. package/src/features/documents/document-route-loader.svelte +17 -5
  186. package/src/features/documents/document-route.svelte +305 -811
  187. package/src/features/documents/document-schedule.scss +127 -0
  188. package/src/features/documents/document-schedule.svelte +323 -0
  189. package/src/features/documents/document-title.ts +25 -0
  190. package/src/features/documents/document.scss +274 -0
  191. package/src/features/documents/live-preview-panel.scss +117 -0
  192. package/src/features/documents/live-preview-panel.svelte +167 -168
  193. package/src/features/documents/live-preview.ts +2 -10
  194. package/src/features/documents/upload-document-preview-loader.svelte +26 -23
  195. package/src/features/localization/content-locale-switcher.scss +43 -0
  196. package/src/features/localization/content-locale-switcher.svelte +24 -17
  197. package/src/features/navigation/admin-breadcrumbs.scss +56 -0
  198. package/src/features/navigation/admin-breadcrumbs.svelte +102 -37
  199. package/src/features/navigation/admin-command-menu.svelte +38 -15
  200. package/src/features/navigation/admin-navigation.scss +133 -0
  201. package/src/features/navigation/admin-navigation.svelte +169 -0
  202. package/src/features/navigation/breadcrumb-context.svelte.ts +15 -0
  203. package/src/features/navigation/navigation-preference.svelte.ts +70 -0
  204. package/src/features/reference-browser/reference-browser-editor.svelte +180 -0
  205. package/src/features/reference-browser/reference-browser-list.scss +113 -0
  206. package/src/features/reference-browser/reference-browser-list.svelte +370 -0
  207. package/src/features/reference-browser/reference-browser-loader.svelte +26 -8
  208. package/src/features/reference-browser/reference-browser-workflow.svelte.ts +335 -236
  209. package/src/features/reference-browser/reference-browser.scss +217 -0
  210. package/src/features/reference-browser/reference-browser.svelte +154 -797
  211. package/src/features/reference-browser/reference-collection-picker.svelte +116 -0
  212. package/src/features/reference-browser/reference-list-query.ts +35 -0
  213. package/src/features/uploads/bulk-upload-controller.svelte.ts +604 -0
  214. package/src/features/uploads/bulk-upload-edit-all.svelte +92 -0
  215. package/src/features/uploads/bulk-upload-editor.svelte +191 -0
  216. package/src/features/uploads/bulk-upload-file-picker.svelte +70 -0
  217. package/src/features/uploads/bulk-upload-remote.svelte +100 -0
  218. package/src/features/uploads/bulk-upload-route-loader.svelte +54 -0
  219. package/src/features/uploads/bulk-upload-route.svelte +172 -592
  220. package/src/features/uploads/bulk-upload-sidebar.svelte +125 -0
  221. package/src/features/uploads/bulk-upload.scss +526 -0
  222. package/src/features/uploads/bulk-upload.ts +105 -14
  223. package/src/features/uploads/crop-surface.ts +150 -0
  224. package/src/features/uploads/image-editor.svelte +231 -0
  225. package/src/features/uploads/rendition-preview.svelte +64 -0
  226. package/src/features/uploads/upload-control.svelte +340 -0
  227. package/src/features/uploads/upload-document-contracts.ts +30 -0
  228. package/src/features/uploads/upload-draft.svelte.ts +294 -0
  229. package/src/features/uploads/upload-metadata-fields.scss +32 -0
  230. package/src/features/uploads/upload-metadata-fields.svelte +8 -7
  231. package/src/features/uploads/upload-thumbnail.svelte +47 -0
  232. package/src/features/uploads/upload.scss +361 -0
  233. package/src/features/versions/version-comparison.svelte +361 -0
  234. package/src/features/versions/version-diff-fields.svelte +136 -0
  235. package/src/features/versions/version-diff.ts +296 -41
  236. package/src/features/versions/version-history-controller.svelte.ts +311 -0
  237. package/src/features/versions/version-history-route-loader.svelte +32 -0
  238. package/src/features/versions/version-history-route.svelte +157 -522
  239. package/src/features/versions/version-history.scss +444 -0
  240. package/src/features/versions/version-history.ts +45 -0
  241. package/src/features/versions/version-table.svelte +91 -0
  242. package/src/fields/embedded-schema-draft-editor.scss +48 -0
  243. package/src/fields/embedded-schema-draft-editor.svelte +24 -16
  244. package/src/fields/field-collapsible.svelte +14 -8
  245. package/src/fields/field-layout.scss +171 -0
  246. package/src/fields/field-layout.svelte +3 -5
  247. package/src/fields/field-renderer.svelte +17 -29
  248. package/src/fields/field-shell.svelte +1 -1
  249. package/src/fields/field-tab-layout.svelte +25 -19
  250. package/src/fields/join/join-field-controller.svelte.ts +513 -0
  251. package/src/fields/join/join-field-values.ts +111 -0
  252. package/src/fields/join/join-field.scss +189 -0
  253. package/src/fields/join/join-field.svelte +164 -332
  254. package/src/fields/live-validation-feedback.svelte +4 -3
  255. package/src/fields/local-field-editor.svelte +2 -2
  256. package/src/fields/nested/block-name-input.svelte +11 -12
  257. package/src/fields/nested/block-picker.scss +128 -0
  258. package/src/fields/nested/block-picker.svelte +81 -0
  259. package/src/fields/nested/block-placeholder.svg +2 -0
  260. package/src/fields/nested/nested-field.scss +331 -0
  261. package/src/fields/nested/nested-field.svelte +265 -245
  262. package/src/fields/nested/sortable-row.svelte +9 -7
  263. package/src/fields/plugin-field.svelte +4 -6
  264. package/src/fields/point/point-field.svelte +51 -38
  265. package/src/fields/primitive-list/primitive-list-field.svelte +63 -19
  266. package/src/fields/primitive-list/primitive-list.scss +109 -0
  267. package/src/fields/radio/radio-field.svelte +2 -1
  268. package/src/fields/relationship/relationship-field-controller.svelte.ts +81 -41
  269. package/src/fields/relationship/relationship-field.svelte +144 -175
  270. package/src/fields/relationship/relationship-lookup-controller.svelte.ts +58 -30
  271. package/src/fields/relationship/relationship-query.ts +2 -10
  272. package/src/fields/relationship/relationship-quick-picker-controller.svelte.ts +36 -62
  273. package/src/fields/relationship/relationship-quick-picker.svelte +178 -227
  274. package/src/fields/relationship/relationship-selection.svelte +120 -0
  275. package/src/fields/relationship/relationship-value.ts +46 -7
  276. package/src/fields/relationship/relationship.scss +182 -0
  277. package/src/fields/scalar/code-field.svelte +101 -0
  278. package/src/fields/scalar/date-control-value.ts +13 -0
  279. package/src/fields/scalar/scalar-field.svelte +25 -67
  280. package/src/fields/select/select-field.svelte +132 -94
  281. package/src/fields/text/slug-field.scss +28 -0
  282. package/src/fields/text/slug-field.svelte +19 -15
  283. package/src/fields/text/text-field.svelte +1 -2
  284. package/src/fields/ui/ui-field.svelte +7 -4
  285. package/src/fields/virtual/virtual-field.svelte +2 -5
  286. package/src/index.ts +1 -2
  287. package/src/routing.ts +2 -0
  288. package/src/app/deferred-redirect.svelte +0 -23
  289. package/src/components/code-block/code-block.svelte +0 -107
  290. package/src/components/ui/bulk-action-bar/bulk-action-bar.svelte +0 -50
  291. package/src/components/ui/bulk-action-bar/index.ts +0 -1
  292. package/src/components/ui/button/index.ts +0 -8
  293. package/src/components/ui/calendar/calendar-caption.svelte +0 -72
  294. package/src/components/ui/calendar/calendar-cell.svelte +0 -20
  295. package/src/components/ui/calendar/calendar-day.svelte +0 -27
  296. package/src/components/ui/calendar/calendar-grid-row.svelte +0 -13
  297. package/src/components/ui/calendar/calendar-grid.svelte +0 -17
  298. package/src/components/ui/calendar/calendar-head-cell.svelte +0 -20
  299. package/src/components/ui/calendar/calendar-header.svelte +0 -20
  300. package/src/components/ui/calendar/calendar-heading.svelte +0 -17
  301. package/src/components/ui/calendar/calendar-month-select.svelte +0 -45
  302. package/src/components/ui/calendar/calendar-month.svelte +0 -16
  303. package/src/components/ui/calendar/calendar-months.svelte +0 -20
  304. package/src/components/ui/calendar/calendar-nav.svelte +0 -20
  305. package/src/components/ui/calendar/calendar-next-button.svelte +0 -30
  306. package/src/components/ui/calendar/calendar-prev-button.svelte +0 -30
  307. package/src/components/ui/calendar/calendar-year-select.svelte +0 -44
  308. package/src/components/ui/calendar/calendar.svelte +0 -118
  309. package/src/components/ui/calendar/index.ts +0 -1
  310. package/src/components/ui/checkbox/checkbox.svelte +0 -35
  311. package/src/components/ui/checkbox/index.ts +0 -1
  312. package/src/components/ui/dialog/dialog-close.svelte +0 -11
  313. package/src/components/ui/dialog/dialog-content.svelte +0 -52
  314. package/src/components/ui/dialog/dialog-description.svelte +0 -20
  315. package/src/components/ui/dialog/dialog-footer.svelte +0 -20
  316. package/src/components/ui/dialog/dialog-header.svelte +0 -20
  317. package/src/components/ui/dialog/dialog-overlay.svelte +0 -20
  318. package/src/components/ui/dialog/dialog-title.svelte +0 -17
  319. package/src/components/ui/dialog/dialog-trigger.svelte +0 -11
  320. package/src/components/ui/dialog/dialog.svelte +0 -7
  321. package/src/components/ui/dialog/index.ts +0 -8
  322. package/src/components/ui/empty-state/empty-state.svelte +0 -34
  323. package/src/components/ui/empty-state/index.ts +0 -1
  324. package/src/components/ui/input/index.ts +0 -1
  325. package/src/components/ui/pagination/index.ts +0 -1
  326. package/src/components/ui/pagination/pagination.svelte +0 -88
  327. package/src/components/ui/radio-group/radio-group-item.svelte +0 -17
  328. package/src/components/ui/slider/index.ts +0 -3
  329. package/src/components/ui/slider/slider-content.svelte +0 -59
  330. package/src/components/ui/slider/slider.svelte +0 -35
  331. package/src/components/ui/table/index.ts +0 -6
  332. package/src/components/ui/table/table-body.svelte +0 -20
  333. package/src/components/ui/table/table-cell.svelte +0 -23
  334. package/src/components/ui/table/table-head.svelte +0 -23
  335. package/src/components/ui/table/table-header.svelte +0 -20
  336. package/src/components/ui/table/table-row.svelte +0 -23
  337. package/src/components/ui/table/table.svelte +0 -22
  338. package/src/components/ui/textarea/index.ts +0 -1
  339. package/src/components/ui/tooltip/index.ts +0 -4
  340. package/src/components/ui/tooltip/tooltip-content.svelte +0 -50
  341. package/src/components/ui/tooltip/tooltip-provider.svelte +0 -7
  342. package/src/components/ui/tooltip/tooltip-trigger.svelte +0 -7
  343. package/src/components/ui/tooltip/tooltip.svelte +0 -7
  344. package/src/features/auth/account-menu.svelte +0 -159
  345. package/src/features/auth/account-security-controller.svelte.ts +0 -119
  346. package/src/features/collections/collection-list-bulk-actions.svelte +0 -143
  347. package/src/features/collections/collection-list-bulk-editor.svelte +0 -157
  348. package/src/features/collections/collection-list-filter-popover.svelte +0 -238
  349. package/src/features/collections/collection-list-workspace-toolbar.svelte +0 -409
  350. package/src/features/collections/collection-table-skeleton.svelte +0 -44
  351. package/src/features/documents/document-heading.ts +0 -20
  352. package/src/features/documents/upload-document-preview.svelte +0 -525
@@ -1,457 +1,191 @@
1
1
  <script lang="ts">
2
- import { Link, NavLink, Outlet, useLocation } from "@hvniel/svelte-router";
3
- import type { AdminNavigationComponent } from "@riducms/plugin";
2
+ import { Outlet, useHref, useLocation, useNavigation } from "@hvniel/svelte-router";
4
3
  import { tick } from "svelte";
5
4
  import { MediaQuery } from "svelte/reactivity";
6
- import ChevronDownIcon from "~icons/lucide/chevron-down";
7
5
  import ChevronLeftIcon from "~icons/lucide/chevron-left";
8
6
  import MenuIcon from "~icons/lucide/menu";
9
7
  import SearchIcon from "~icons/lucide/search";
10
8
 
11
- import { Button, buttonVariants } from "@admin/components/ui/button";
12
- import {
13
- Sheet,
14
- SheetClose,
15
- SheetContent,
16
- SheetDescription,
17
- SheetTitle,
18
- SheetTrigger,
19
- } from "@admin/components/ui/sheet";
20
- import {
21
- getPreferenceWriteQueue,
22
- preferenceOwnerID,
23
- } from "@admin/core/preferences/preference-write-queue";
24
- import { collectionPath, globalPath } from "@admin/core/routing/admin-paths";
9
+ import NavigationDrawer from "@admin/components/ui/navigation-drawer/navigation-drawer.svelte";
10
+ import "@admin/app/admin-layout.scss";
11
+ import { adminLayoutRouteBehavior } from "@admin/core/routing/admin-paths";
12
+ import { useAdminScrollRestoration } from "@admin/core/routing/admin-scroll.svelte";
25
13
  import { getAdminRuntime } from "@admin/core/runtime/admin-runtime.svelte";
26
- import AccountMenu from "@admin/features/auth/account-menu.svelte";
14
+ import AccountMenu from "@admin/features/account/account-menu.svelte";
15
+ import AdminNavigation from "@admin/features/navigation/admin-navigation.svelte";
16
+ import { createNavigationPreference } from "@admin/features/navigation/navigation-preference.svelte";
17
+ import { provideBreadcrumbs } from "@admin/features/navigation/breadcrumb-context.svelte";
27
18
  import AdminBreadcrumbs from "@admin/features/navigation/admin-breadcrumbs.svelte";
28
- import { groupAdminResources } from "@admin/features/navigation/admin-resource-groups";
29
19
  import AdminCommandMenu from "@admin/features/navigation/admin-command-menu.svelte";
30
20
  import ContentLocaleSwitcher from "@admin/features/localization/content-locale-switcher.svelte";
31
- import { cn } from "@riducms/ui";
32
21
 
33
- const navigationPreferenceKey = "navigation";
22
+ provideBreadcrumbs();
34
23
  const runtime = getAdminRuntime();
35
- const location = $derived(useLocation());
36
- const routeSegments = $derived(location.pathname.split("/").filter(Boolean));
37
- const routeOwnsViewport = $derived(
38
- (routeSegments[0] === "collections" &&
39
- routeSegments.length > 2 &&
40
- routeSegments[2] !== "trash" &&
41
- routeSegments[2] !== "upload" &&
42
- routeSegments[3] !== "versions") ||
43
- (routeSegments[0] === "globals" &&
44
- routeSegments.length > 1 &&
45
- routeSegments[2] !== "versions")
46
- );
47
- const narrowNavigation = new MediaQuery("(max-width: 1023px)");
48
- const applicationName = $derived(
49
- runtime.manifest === undefined
50
- ? runtime.i18n.t("general:riduApplication")
51
- : runtime.i18n.text(
52
- runtime.manifest.application.name,
53
- runtime.manifest.application.nameTranslations
54
- )
55
- );
56
- const resourceGroups = $derived(
57
- groupAdminResources(runtime.visibleCollections, runtime.visibleGlobals, {
58
- collections: runtime.i18n.t("navigation:collections"),
59
- globals: runtime.i18n.t("navigation:globals"),
60
- })
24
+ const extensions = runtime.config.extensions;
25
+ const location = useLocation();
26
+ const navigation = useNavigation();
27
+ const currentPath = useHref(() => location.current.pathname);
28
+
29
+ const routePending = $derived(
30
+ navigation.current.state !== "idle" || runtime.contentLocaleTransitioning
61
31
  );
62
- const navigationPluginRoutes = $derived(
63
- runtime.pluginRoutes.filter((route) => route.navigation !== undefined)
32
+ const routeChanging = $derived.by(() => {
33
+ if (runtime.contentLocaleTransitioning) return true;
34
+
35
+ const destination = navigation.current.location;
36
+ if (destination === undefined) return false;
37
+
38
+ // Query controls stay usable within the same page and locale. The feature owns
39
+ // disabling stale results; leaving the page still disables its whole surface.
40
+ return (
41
+ destination.pathname !== currentPath.current ||
42
+ new URLSearchParams(destination.search).get("locale") !==
43
+ new URLSearchParams(location.current.search).get("locale")
44
+ );
45
+ });
46
+
47
+ let viewport = $state<HTMLElement | null>(null);
48
+ const containedViewport = new MediaQuery("(min-width: 769px)");
49
+ const routeBehavior = $derived(adminLayoutRouteBehavior(location.current.pathname));
50
+ useAdminScrollRestoration(
51
+ () => (containedViewport.current ? viewport : window),
52
+ () => routeBehavior.waitsForPage
64
53
  );
54
+
55
+ const narrowNavigation = new MediaQuery("(max-width: 768px)");
65
56
  let commandOpen = $state(false);
66
- let desktopNavigationOpen = $state(true);
67
- let mobileNavigationOpen = $state(false);
68
- let desktopToggle = $state<HTMLButtonElement | null>(null);
69
- let preferenceGeneration = 0;
70
- const navigationReplacement = $derived(
71
- runtime.navigationComponents.find((component) => component.position === "replace")
72
- );
73
- const navigationBefore = $derived(
74
- runtime.navigationComponents.filter((component) => component.position === "before")
75
- );
76
- const navigationBeforeLinks = $derived(
77
- runtime.navigationComponents.filter((component) => component.position === "beforeLinks")
78
- );
79
- const navigationAfterLinks = $derived(
80
- runtime.navigationComponents.filter((component) => component.position === "afterLinks")
81
- );
82
- const navigationAfter = $derived(
83
- runtime.navigationComponents.filter((component) => component.position === "after")
84
- );
85
- const navigationLogo = $derived(
86
- runtime.brandComponents.find((component) => component.surface === "navigationLogo")
87
- );
88
- const shellHeaders = $derived(
89
- runtime.shellComponents.filter((component) => component.position === "header")
90
- );
91
- const shellActions = $derived(
92
- runtime.shellComponents.filter((component) => component.position === "actions")
57
+
58
+ const navigationPreference = createNavigationPreference(runtime);
59
+
60
+ let mobileNavigationRoute = $state<string>();
61
+ const mobileNavigationOpen = $derived(
62
+ narrowNavigation.current && mobileNavigationRoute === location.current.key
93
63
  );
94
- const hasShellHeader = $derived(runtime.manifest !== undefined && shellHeaders.length > 0);
95
64
 
96
65
  $effect(() => {
97
- const owner = preferenceOwnerID(runtime.session);
98
- if (owner === "") return;
99
- const generation = ++preferenceGeneration;
100
- const request = new AbortController();
101
- void runtime.client
102
- .preference<unknown>(navigationPreferenceKey, { signal: request.signal })
103
- .then((preference) => {
104
- if (
105
- request.signal.aborted ||
106
- generation !== preferenceGeneration ||
107
- typeof preference !== "object" ||
108
- preference === null ||
109
- typeof (preference as { open?: unknown }).open !== "boolean"
110
- ) {
111
- return;
112
- }
113
- desktopNavigationOpen = (preference as { open: boolean }).open;
114
- })
115
- .catch(() => undefined);
116
- return () => request.abort();
66
+ if (!narrowNavigation.current) mobileNavigationRoute = undefined;
117
67
  });
118
68
 
119
- async function toggleDesktopNavigation() {
120
- preferenceGeneration += 1;
121
- const next = !desktopNavigationOpen;
122
- desktopNavigationOpen = next;
123
- const owner = preferenceOwnerID(runtime.session);
124
- if (owner !== "") {
125
- void getPreferenceWriteQueue()
126
- .enqueue(
127
- navigationPreferenceKey,
128
- owner,
129
- () => preferenceOwnerID(runtime.session) === owner,
130
- () => runtime.client.setPreference(navigationPreferenceKey, { open: next })
131
- )
132
- .catch(() => undefined);
133
- }
134
- await tick();
135
- desktopToggle?.focus();
136
- }
69
+ const shellHeaders = extensions.shellSlots.filter((component) => component.position === "header");
70
+ const shellActions = extensions.shellSlots.filter(
71
+ (component) => component.position === "actions"
72
+ );
73
+ const hasShellHeader = $derived(runtime.manifest !== undefined && shellHeaders.length > 0);
137
74
 
138
75
  function closeMobileNavigation() {
139
- if (narrowNavigation.current) mobileNavigationOpen = false;
76
+ if (narrowNavigation.current) mobileNavigationRoute = undefined;
140
77
  }
141
78
 
142
79
  async function openCommandMenu() {
143
80
  if (narrowNavigation.current) {
144
- mobileNavigationOpen = false;
81
+ mobileNavigationRoute = undefined;
145
82
  await tick();
146
83
  }
84
+
147
85
  commandOpen = true;
148
86
  }
149
87
  </script>
150
88
 
151
- {#snippet navigationContributions(components: readonly AdminNavigationComponent[])}
152
- {#if runtime.manifest !== undefined}
153
- {#each components as component (component.key)}
154
- <component.component
155
- manifest={runtime.manifest}
156
- user={runtime.session?.user}
157
- defaultView={defaultNavigation}
158
- i18n={runtime.i18n}
159
- />
160
- {/each}
161
- {/if}
162
- {/snippet}
163
-
164
- {#snippet defaultNavigation()}
165
- {@render navigationContributions(navigationBefore)}
166
-
167
- <nav
168
- aria-label={runtime.i18n.t("navigation:adminNavigation")}
169
- class="grid flex-1 content-start overflow-y-auto px-5 pb-5"
170
- >
171
- {@render navigationContributions(navigationBeforeLinks)}
172
-
173
- {#each resourceGroups as group (group.key)}
174
- <details open class="group/resource mb-3">
175
- <summary
176
- class="flex cursor-pointer list-none items-center justify-between gap-3 py-1 text-[12.5px] text-foreground-faint transition-colors hover:text-foreground-strong [&::-webkit-details-marker]:hidden"
177
- >
178
- <span>{runtime.i18n.text(group.label, group.translations)}</span>
179
- <ChevronDownIcon
180
- class="size-2.5 rotate-[-90deg] text-foreground-soft transition-transform group-open/resource:rotate-0"
181
- aria-hidden="true"
182
- />
183
- </summary>
184
- <div class="grid">
185
- {#each group.collections as collection (collection.id)}
186
- <NavLink
187
- to={collectionPath(collection.slug)}
188
- class={({ isActive, isPending }) =>
189
- cn(
190
- "relative flex min-h-7 items-center text-[13px] transition-colors after:absolute after:top-1 after:bottom-1 after:-start-5 after:w-0.5",
191
- isActive
192
- ? "font-medium text-foreground-strong after:bg-foreground-strong"
193
- : "text-sidebar-foreground hover:text-foreground",
194
- isPending && "opacity-60"
195
- )}
196
- onclick={closeMobileNavigation}
197
- >
198
- <span class="truncate">
199
- {runtime.i18n.text(collection.labels.plural, collection.labels.pluralTranslations)}
200
- </span>
201
- </NavLink>
202
- {/each}
203
- {#each group.globals as global (global.id)}
204
- <NavLink
205
- to={globalPath(global.slug)}
206
- class={({ isActive, isPending }) =>
207
- cn(
208
- "relative flex min-h-7 items-center text-[13px] transition-colors after:absolute after:top-1 after:bottom-1 after:-start-5 after:w-0.5",
209
- isActive
210
- ? "font-medium text-foreground-strong after:bg-foreground-strong"
211
- : "text-sidebar-foreground hover:text-foreground",
212
- isPending && "opacity-60"
213
- )}
214
- onclick={closeMobileNavigation}
215
- >
216
- <span class="truncate">
217
- {runtime.i18n.text(global.labels.singular, global.labels.singularTranslations)}
218
- </span>
219
- </NavLink>
220
- {/each}
221
- </div>
222
- </details>
223
- {/each}
224
-
225
- {#if navigationPluginRoutes.length > 0}
226
- <details open class="group/resource mb-3">
227
- <summary
228
- class="flex cursor-pointer list-none items-center justify-between gap-3 py-1 text-[12.5px] text-foreground-faint transition-colors hover:text-foreground-strong [&::-webkit-details-marker]:hidden"
229
- >
230
- <span>{runtime.i18n.t("navigation:plugins")}</span>
231
- <ChevronDownIcon
232
- class="size-2.5 rotate-[-90deg] text-foreground-soft transition-transform group-open/resource:rotate-0"
233
- aria-hidden="true"
234
- />
235
- </summary>
236
- <div class="grid">
237
- {#each navigationPluginRoutes as pluginRoute (pluginRoute.path)}
238
- <NavLink
239
- to={`/${pluginRoute.path}`}
240
- class={({ isActive }) =>
241
- cn(
242
- "relative flex min-h-7 items-center text-[13px] transition-colors after:absolute after:top-1 after:bottom-1 after:-start-5 after:w-0.5",
243
- isActive
244
- ? "font-medium text-foreground-strong after:bg-foreground-strong"
245
- : "text-sidebar-foreground hover:text-foreground"
246
- )}
247
- onclick={closeMobileNavigation}
248
- >
249
- {pluginRoute.navigation?.labelKey === undefined
250
- ? pluginRoute.navigation?.label
251
- : runtime.i18n.t(pluginRoute.navigation.labelKey)}
252
- </NavLink>
253
- {/each}
254
- </div>
255
- </details>
256
- {/if}
257
-
258
- {@render navigationContributions(navigationAfterLinks)}
259
- </nav>
260
-
261
- {@render navigationContributions(navigationAfter)}
262
-
263
- {#if runtime.session !== undefined}
264
- <div class="mt-auto px-5 py-4">
265
- <AccountMenu compact />
266
- </div>
267
- {/if}
268
- {/snippet}
269
-
270
- {#snippet navigationSurface(mobile = false)}
271
- <div class={["flex h-14 shrink-0 items-center gap-2 pe-4", mobile ? "ps-4" : "ps-16"]}>
272
- {#if mobile}
273
- <SheetClose
274
- class={buttonVariants({ variant: "outline", size: "icon-sm" })}
275
- aria-label={runtime.i18n.t("navigation:closeMenu")}
276
- >
277
- <ChevronLeftIcon class="size-4 rtl:rotate-180" aria-hidden="true" />
278
- </SheetClose>
279
- {/if}
280
-
281
- <Link
282
- class="ms-1 min-w-0 flex-1 truncate text-[13px] font-medium text-foreground"
283
- to="/"
284
- title={applicationName}
285
- aria-label={applicationName}
286
- onclick={closeMobileNavigation}
89
+ <div class={["ridu-shell", { "ridu-shell--nav-open": navigationPreference.open }]}>
90
+ {#if hasShellHeader && runtime.manifest !== undefined}
91
+ <header
92
+ class="ridu-shell__extension-header"
93
+ aria-label={runtime.i18n.t("navigation:pluginShellHeader")}
287
94
  >
288
- {#if navigationLogo !== undefined && runtime.manifest !== undefined}
289
- <navigationLogo.component
95
+ {#each shellHeaders as component (component.key)}
96
+ <component.component
290
97
  manifest={runtime.manifest}
291
98
  user={runtime.session?.user}
292
- surface="navigationLogo"
99
+ position="header"
293
100
  i18n={runtime.i18n}
294
101
  />
295
- {/if}
296
- </Link>
297
-
298
- <Button
299
- variant="ghost"
300
- size="icon-sm"
301
- onclick={openCommandMenu}
302
- aria-label={runtime.i18n.t("navigation:searchAndNavigate")}
303
- tooltip={runtime.i18n.t("navigation:searchAndNavigateShortcut")}
304
- >
305
- <SearchIcon class="size-3.5" aria-hidden="true" />
306
- </Button>
307
- </div>
308
-
309
- {#if runtime.manifest !== undefined && navigationReplacement !== undefined}
310
- <navigationReplacement.component
311
- manifest={runtime.manifest}
312
- user={runtime.session?.user}
313
- defaultView={defaultNavigation}
314
- i18n={runtime.i18n}
315
- />
316
- {:else}
317
- {@render defaultNavigation()}
318
- {/if}
319
- {/snippet}
320
-
321
- {#snippet adminHeaderActions()}
322
- {#if runtime.manifest !== undefined}
323
- {#each shellActions as component (component.key)}
324
- <component.component
325
- manifest={runtime.manifest}
326
- user={runtime.session?.user}
327
- position="actions"
328
- i18n={runtime.i18n}
329
- />
330
- {/each}
331
- {/if}
332
- <ContentLocaleSwitcher />
333
- {#if runtime.session !== undefined}
334
- <div class="lg:hidden">
335
- <AccountMenu compact />
336
- </div>
102
+ {/each}
103
+ </header>
337
104
  {/if}
338
- {/snippet}
339
-
340
- {#if hasShellHeader && runtime.manifest !== undefined}
341
- <header
342
- class="flex min-h-5 items-center gap-3 bg-background-surface px-5 text-[12px] sm:px-8 lg:px-15"
343
- aria-label={runtime.i18n.t("navigation:pluginShellHeader")}
344
- >
345
- {#each shellHeaders as component (component.key)}
346
- <component.component
347
- manifest={runtime.manifest}
348
- user={runtime.session?.user}
349
- position="header"
350
- i18n={runtime.i18n}
351
- />
352
- {/each}
353
- </header>
354
- {/if}
355
105
 
356
- <div
357
- class={[
358
- "transition-[grid-template-columns] duration-300 ease-out motion-reduce:transition-none md:grid md:overflow-hidden",
359
- hasShellHeader
360
- ? "min-h-[calc(100vh-1.25rem)] md:h-[calc(100vh-1.25rem)]"
361
- : "min-h-screen md:h-screen",
362
- desktopNavigationOpen ? "lg:grid-cols-[275px_minmax(0,1fr)]" : "lg:grid-cols-[0_minmax(0,1fr)]",
363
- ]}
364
- >
365
- {#if narrowNavigation.current}
366
- <Sheet bind:open={mobileNavigationOpen}>
367
- <SheetTrigger
368
- class={buttonVariants({
369
- variant: "outline",
370
- size: "icon-sm",
371
- class: hasShellHeader ? "fixed top-7 start-2 z-30" : "fixed top-2.5 start-2 z-30",
372
- })}
373
- aria-label={runtime.i18n.t("navigation:openMenu")}
374
- title={runtime.i18n.t("navigation:openMenu")}
375
- >
376
- <MenuIcon class="size-4" aria-hidden="true" />
377
- </SheetTrigger>
378
- <SheetContent
379
- side={runtime.i18n.direction === "rtl" ? "right" : "left"}
380
- showCloseButton={false}
381
- class="w-[min(275px,calc(100vw-40px))] border-sidebar-border bg-sidebar p-0 text-sidebar-foreground sm:max-w-none"
382
- >
383
- <SheetTitle class="sr-only">
384
- {runtime.i18n.t("navigation:adminNavigation")}
385
- </SheetTitle>
386
- <SheetDescription class="sr-only">
387
- {runtime.i18n.t("navigation:adminNavigationDescription")}
388
- </SheetDescription>
389
- <aside class="flex h-full min-h-0 flex-col">
390
- {@render navigationSurface(true)}
106
+ <div class="ridu-shell__body">
107
+ {#if !narrowNavigation.current}
108
+ <div class="ridu-shell__sidebar">
109
+ <aside
110
+ id="ridu-admin-navigation"
111
+ inert={!navigationPreference.open}
112
+ aria-hidden={!navigationPreference.open}
113
+ class="ridu-nav"
114
+ >
115
+ <AdminNavigation onNavigate={closeMobileNavigation} />
391
116
  </aside>
392
- </SheetContent>
393
- </Sheet>
394
- {:else}
395
- <div class="relative h-full min-h-0 bg-sidebar text-sidebar-foreground">
396
- <aside
397
- id="ridu-admin-navigation"
398
- inert={!desktopNavigationOpen}
399
- aria-hidden={!desktopNavigationOpen}
400
- class={[
401
- "absolute inset-y-0 start-0 flex w-[275px] min-h-0 flex-col border-e border-sidebar-border bg-sidebar transition-[transform,opacity] duration-300 ease-out motion-reduce:transition-none",
402
- desktopNavigationOpen
403
- ? "translate-x-0 opacity-100"
404
- : runtime.i18n.direction === "rtl"
405
- ? "pointer-events-none translate-x-full opacity-0"
406
- : "pointer-events-none -translate-x-full opacity-0",
407
- ]}
408
- >
409
- {@render navigationSurface()}
410
- </aside>
411
- </div>
117
+ </div>
412
118
 
413
- <Button
414
- bind:ref={desktopToggle}
415
- variant="outline"
416
- size="icon-sm"
417
- class={cn(
418
- "fixed z-40",
419
- hasShellHeader ? "top-[34px]" : "top-3.5",
420
- desktopNavigationOpen ? "start-4" : "start-2"
421
- )}
422
- onclick={toggleDesktopNavigation}
423
- aria-label={runtime.i18n.t(
424
- desktopNavigationOpen ? "navigation:closeMenu" : "navigation:openMenu"
425
- )}
426
- aria-controls="ridu-admin-navigation"
427
- aria-expanded={desktopNavigationOpen}
428
- title={runtime.i18n.t(desktopNavigationOpen ? "navigation:closeMenu" : "navigation:openMenu")}
429
- >
430
- {#if desktopNavigationOpen}
431
- <ChevronLeftIcon class="size-4 rtl:rotate-180" aria-hidden="true" />
432
- {:else}
433
- <MenuIcon class="size-4" aria-hidden="true" />
434
- {/if}
435
- </Button>
436
- {/if}
119
+ <div class="ridu-shell__toggle">
120
+ <button
121
+ type="button"
122
+ class="ridu-nav-toggle"
123
+ onclick={navigationPreference.toggle}
124
+ aria-label={runtime.i18n.t(
125
+ navigationPreference.open ? "navigation:closeMenu" : "navigation:openMenu"
126
+ )}
127
+ aria-controls="ridu-admin-navigation"
128
+ aria-expanded={navigationPreference.open}
129
+ >
130
+ {#if navigationPreference.open}
131
+ <ChevronLeftIcon class="ridu-nav-toggle__collapse" aria-hidden="true" />
132
+ {:else}
133
+ <MenuIcon aria-hidden="true" />
134
+ {/if}
135
+ </button>
136
+ </div>
137
+ {/if}
437
138
 
438
- <main
439
- class={[
440
- "relative min-w-0 bg-background max-lg:ps-11 md:flex md:h-full md:flex-col",
441
- routeOwnsViewport ? "md:overflow-hidden" : "md:overflow-y-auto",
442
- ]}
443
- >
444
- <header
445
- class="flex h-14 shrink-0 items-center justify-between gap-4 bg-background px-5 sm:px-8 lg:px-15"
446
- aria-label={runtime.i18n.t("navigation:adminHeader")}
139
+ <main
140
+ bind:this={viewport}
141
+ inert={routeChanging}
142
+ aria-busy={routePending}
143
+ class={["ridu-shell__main", { "ridu-shell__main--contained": routeBehavior.ownsViewport }]}
447
144
  >
448
- <AdminBreadcrumbs />
449
- <div class="flex shrink-0 items-center gap-2">
450
- {@render adminHeaderActions()}
451
- </div>
452
- </header>
453
- <Outlet />
454
- </main>
145
+ <header class="ridu-shell__header" aria-label={runtime.i18n.t("navigation:adminHeader")}>
146
+ {#if narrowNavigation.current}
147
+ <NavigationDrawer
148
+ bind:open={
149
+ () => mobileNavigationOpen,
150
+ (open) => (mobileNavigationRoute = open ? location.current.key : undefined)
151
+ }
152
+ >
153
+ <AdminNavigation onNavigate={closeMobileNavigation} />
154
+ </NavigationDrawer>
155
+ {/if}
156
+
157
+ <AdminBreadcrumbs />
158
+
159
+ <div class="ridu-shell__actions">
160
+ {#if runtime.manifest !== undefined}
161
+ {#each shellActions as component (component.key)}
162
+ <component.component
163
+ manifest={runtime.manifest}
164
+ user={runtime.session?.user}
165
+ position="actions"
166
+ i18n={runtime.i18n}
167
+ />
168
+ {/each}
169
+ {/if}
170
+ <button
171
+ type="button"
172
+ class="ridu-shell__search"
173
+ onclick={openCommandMenu}
174
+ aria-label={runtime.i18n.t("navigation:searchAndNavigate")}
175
+ title={runtime.i18n.t("navigation:searchAndNavigateShortcut")}
176
+ >
177
+ <SearchIcon aria-hidden="true" />
178
+ </button>
179
+ <ContentLocaleSwitcher />
180
+ {#if runtime.session !== undefined}
181
+ <AccountMenu />
182
+ {/if}
183
+ </div>
184
+ </header>
185
+
186
+ <Outlet />
187
+ </main>
188
+ </div>
455
189
  </div>
456
190
 
457
191
  <AdminCommandMenu bind:open={commandOpen} collections={runtime.visibleCollections} />