@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,24 +1,19 @@
1
1
  <script lang="ts">
2
- import { useLocation } from "@hvniel/svelte-router";
3
- import { onMount, tick } from "svelte";
2
+ import { useNavigation } from "@hvniel/svelte-router";
3
+ import { tick, untrack } from "svelte";
4
4
 
5
5
  import { getAdminRuntime } from "@admin/core/runtime/admin-runtime.svelte";
6
6
 
7
7
  const revealDelayMilliseconds = 160;
8
8
  const minimumVisibleMilliseconds = 180;
9
9
  const completionMilliseconds = 150;
10
- const fallbackIntentMilliseconds = 140;
11
10
  const runtime = getAdminRuntime();
12
- const routeLocation = $derived(useLocation());
13
- const routeKey = $derived(
14
- `${routeLocation.pathname}${routeLocation.search}${routeLocation.hash}`
15
- );
11
+ const navigation = useNavigation();
16
12
 
17
13
  type ProgressPhase = "idle" | "pending" | "running" | "finishing";
18
14
 
19
15
  let phase = $state<ProgressPhase>("idle");
20
16
  let progress = $state(0);
21
- let observedRouteKey = "";
22
17
  let startedAt = 0;
23
18
  let generation = 0;
24
19
  let revealTimer: number | undefined;
@@ -26,7 +21,6 @@
26
21
  let finishTimer: number | undefined;
27
22
  let hideTimer: number | undefined;
28
23
  let resetTimer: number | undefined;
29
- let intentTimer: number | undefined;
30
24
 
31
25
  function clearTimer(timer: number | undefined) {
32
26
  if (timer !== undefined) window.clearTimeout(timer);
@@ -52,16 +46,12 @@
52
46
 
53
47
  function start() {
54
48
  clearCompletionTimers();
55
- clearTimer(intentTimer);
56
- intentTimer = undefined;
57
-
58
- if (phase === "pending") return;
59
- if (phase === "running") {
60
- generation += 1;
49
+ generation += 1;
50
+ // Progress phase is an output of this navigation synchronization, not one of its inputs.
51
+ if (untrack(() => phase) === "running") {
61
52
  return;
62
53
  }
63
54
 
64
- generation += 1;
65
55
  const activeGeneration = generation;
66
56
  phase = "pending";
67
57
  progress = 0;
@@ -77,6 +67,8 @@
77
67
  }
78
68
 
79
69
  function afterDestinationPaint() {
70
+ // The destination DOM flushes at tick; two frames keep the progress bar visible until that
71
+ // DOM has reached a browser paint rather than finishing over the retained outgoing page.
80
72
  return new Promise<void>((resolve) => {
81
73
  requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
82
74
  });
@@ -112,74 +104,16 @@
112
104
  }, remaining);
113
105
  }
114
106
 
115
- function startIntent() {
116
- const routeBeforeIntent = routeKey;
117
- start();
118
- intentTimer = window.setTimeout(() => {
119
- intentTimer = undefined;
120
- if (routeKey === routeBeforeIntent) void finish();
121
- }, fallbackIntentMilliseconds);
122
- }
123
-
124
- function handleLinkIntent(event: MouseEvent) {
125
- if (
126
- event.defaultPrevented ||
127
- event.button !== 0 ||
128
- event.metaKey ||
129
- event.ctrlKey ||
130
- event.shiftKey ||
131
- event.altKey ||
132
- !(event.target instanceof Element)
133
- ) {
134
- return;
135
- }
136
-
137
- const anchor = event.target.closest<HTMLAnchorElement>("a[href]");
138
- if (
139
- anchor === null ||
140
- anchor.hasAttribute("download") ||
141
- (anchor.target !== "" && anchor.target !== "_self")
142
- ) {
143
- return;
144
- }
145
-
146
- const destination = new URL(anchor.href, window.location.href);
147
- if (
148
- destination.origin !== window.location.origin ||
149
- `${destination.pathname}${destination.search}${destination.hash}` ===
150
- `${window.location.pathname}${window.location.search}${window.location.hash}`
151
- ) {
152
- return;
153
- }
154
-
155
- startIntent();
156
- }
157
-
158
107
  $effect(() => {
159
- const nextRouteKey = routeKey;
160
- if (observedRouteKey === "") {
161
- observedRouteKey = nextRouteKey;
162
- return;
163
- }
164
- if (nextRouteKey === observedRouteKey) return;
165
-
166
- observedRouteKey = nextRouteKey;
167
- start();
168
- void finish();
108
+ if (navigation.current.state === "idle") void finish();
109
+ else start();
169
110
  });
170
111
 
171
- onMount(() => {
172
- const handleHistoryIntent = () => startIntent();
173
- document.addEventListener("click", handleLinkIntent, true);
174
- window.addEventListener("popstate", handleHistoryIntent);
175
-
112
+ $effect(() => {
176
113
  return () => {
177
114
  generation += 1;
178
- document.removeEventListener("click", handleLinkIntent, true);
179
- window.removeEventListener("popstate", handleHistoryIntent);
180
115
  clearTimer(revealTimer);
181
116
  clearTimer(trickleTimer);
182
- clearTimer(intentTimer);
183
117
  clearCompletionTimers();
184
118
  };
185
119
  });
@@ -1,94 +1,26 @@
1
1
  <script lang="ts">
2
2
  import { useLocation } from "@hvniel/svelte-router";
3
3
 
4
- import { ADMIN_NAME } from "@admin/app-meta";
4
+ import { ADMIN_NAME, adminApplicationName } from "@admin/app-meta";
5
+ import { resolveAdminPageLabel } from "@admin/app/admin-page-title";
5
6
  import { getAdminRuntime } from "@admin/core/runtime/admin-runtime.svelte";
6
7
 
7
8
  const runtime = getAdminRuntime();
8
- const location = $derived(useLocation());
9
- const pageTitle = $derived.by(resolvePageTitle);
10
-
11
- function resolvePageTitle() {
12
- const segments = location.pathname.split("/").filter(Boolean);
13
- if (segments.length === 0) return titled(runtime.i18n.t("dashboard:heading"));
14
- if (segments[0] === "create-first-user") return titled(runtime.i18n.t("auth:createFirstUser"));
15
- if (segments[0] === "login") return titled(runtime.i18n.t("auth:login"));
16
- if (segments[0] === "forgot-password") return titled(runtime.i18n.t("auth:forgotPassword"));
17
- if (segments[0] === "reset-password") return titled(runtime.i18n.t("auth:resetPassword"));
18
- if (segments[0] === "request-verification")
19
- return titled(runtime.i18n.t("auth:requestVerification"));
20
- if (segments[0] === "verify-email") return titled(runtime.i18n.t("auth:verifyEmail"));
21
- if (segments[0] === "account") {
22
- return titled(
23
- segments[1] === "security"
24
- ? runtime.i18n.t("account:accountSecurity")
25
- : runtime.i18n.t("account:account")
26
- );
27
- }
28
- if (segments[0] === "collections" && segments[1] !== undefined) {
29
- const collection = runtime.manifest?.collections.find(
30
- (candidate) => candidate.slug === segments[1]
31
- );
32
- const singular =
33
- collection === undefined
34
- ? humanize(segments[1])
35
- : runtime.i18n.text(collection.labels.singular, collection.labels.singularTranslations);
36
- const plural =
37
- collection === undefined
38
- ? singular
39
- : runtime.i18n.text(collection.labels.plural, collection.labels.pluralTranslations);
40
- if (segments[2] === undefined) return titled(plural);
41
- if (segments[2] === "create") {
42
- return titled(
43
- segments[3] === "api"
44
- ? runtime.i18n.t("documents:apiFor", { label: singular })
45
- : runtime.i18n.t("collections:createNew", { label: singular })
46
- );
47
- }
48
- if (segments[2] === "trash")
49
- return titled(
50
- runtime.i18n.t("collections:trashFor", {
51
- label: plural,
52
- })
53
- );
54
- if (segments[3] === "api")
55
- return titled(runtime.i18n.t("documents:apiFor", { label: singular }));
56
- if (segments[3] === "versions")
57
- return titled(runtime.i18n.t("documents:versionsFor", { label: singular }));
58
- return titled(runtime.i18n.t("documents:editing", { label: singular }));
59
- }
60
- if (segments[0] === "globals" && segments[1] !== undefined) {
61
- const global = runtime.manifest?.globals?.find((candidate) => candidate.slug === segments[1]);
62
- const label =
63
- global === undefined
64
- ? humanize(segments[1])
65
- : runtime.i18n.text(global.labels.singular, global.labels.singularTranslations);
66
- if (segments[2] === "api") return titled(runtime.i18n.t("documents:apiFor", { label }));
67
- if (segments[2] === "versions")
68
- return titled(runtime.i18n.t("documents:versionsFor", { label }));
69
- return titled(label);
70
- }
71
- const pluginPath = segments.join("/");
72
- const pluginRoute = runtime.pluginRoutes.find((route) => route.path === pluginPath);
73
- if (pluginRoute?.navigation?.labelKey !== undefined)
74
- return titled(runtime.i18n.t(pluginRoute.navigation.labelKey));
75
- if (pluginRoute?.navigation?.label !== undefined) return titled(pluginRoute.navigation.label);
76
- return titled(humanize(segments.at(-1) ?? runtime.i18n.t("navigation:page")));
77
- }
78
-
79
- function titled(value: string) {
80
- const application = runtime.manifest?.application;
81
- const name =
82
- application === undefined
83
- ? ADMIN_NAME
84
- : runtime.i18n.text(application.name, application.nameTranslations);
85
- return `${value} - ${name}`;
86
- }
87
-
88
- function humanize(value: string) {
89
- const decoded = decodeURIComponent(value).replaceAll("-", " ");
90
- return decoded.charAt(0).toLocaleUpperCase(runtime.i18n.language) + decoded.slice(1);
91
- }
9
+ const location = useLocation();
10
+ const extensions = runtime.config.extensions;
11
+ const pageLabel = $derived(
12
+ resolveAdminPageLabel({
13
+ pathname: location.current.pathname,
14
+ manifest: runtime.manifest,
15
+ routes: extensions.routes,
16
+ documentViews: extensions.documentViews,
17
+ i18n: runtime.i18n,
18
+ })
19
+ );
20
+ const applicationName = $derived(
21
+ adminApplicationName(runtime.manifest, runtime.i18n, ADMIN_NAME)
22
+ );
23
+ const pageTitle = $derived(`${pageLabel} - ${applicationName}`);
92
24
  </script>
93
25
 
94
26
  <svelte:head><title>{pageTitle}</title></svelte:head>
@@ -0,0 +1,136 @@
1
+ import type { AdminDocumentView, AdminRoute } from "@riducms/plugin";
2
+ import type { SchemaManifest } from "@riducms/protocol";
3
+ import type { AdminI18n, ExtensionTranslationKey } from "@riducms/translations";
4
+
5
+ import { adminPathSegments, humanizeAdminPathSegment } from "@admin/core/routing/admin-paths";
6
+
7
+ type PageTitleI18n = Pick<AdminI18n, "language" | "t" | "text">;
8
+
9
+ interface AdminPageLabelOptions {
10
+ pathname: string;
11
+ manifest: SchemaManifest | undefined;
12
+ routes: readonly AdminRoute[];
13
+ documentViews: readonly AdminDocumentView[];
14
+ i18n: PageTitleI18n;
15
+ }
16
+
17
+ export function resolveAdminPageLabel(options: AdminPageLabelOptions): string {
18
+ const segments = adminPathSegments(options.pathname);
19
+ const [root, resource, action, view] = segments;
20
+
21
+ switch (root) {
22
+ case undefined:
23
+ return options.i18n.t("dashboard:heading");
24
+ case "create-first-user":
25
+ return options.i18n.t("auth:createFirstUser");
26
+ case "login":
27
+ return options.i18n.t("auth:login");
28
+ case "forgot-password":
29
+ return options.i18n.t("auth:forgotPassword");
30
+ case "reset-password":
31
+ return options.i18n.t("auth:resetPassword");
32
+ case "request-verification":
33
+ return options.i18n.t("auth:requestVerification");
34
+ case "verify-email":
35
+ return options.i18n.t("auth:verifyEmail");
36
+ case "account":
37
+ return options.i18n.t(
38
+ resource === "security" ? "account:accountSecurity" : "account:account"
39
+ );
40
+ case "collections":
41
+ return resolveCollectionLabel(options, resource, action, view);
42
+ case "globals":
43
+ return resolveGlobalLabel(options, resource, action);
44
+ default:
45
+ return resolvePluginOrFallbackLabel(options, segments);
46
+ }
47
+ }
48
+
49
+ function resolveCollectionLabel(
50
+ options: AdminPageLabelOptions,
51
+ resource: string | undefined,
52
+ action: string | undefined,
53
+ view: string | undefined
54
+ ) {
55
+ if (resource === undefined) return humanize("collections", options.i18n);
56
+
57
+ const collection = options.manifest?.collections.find((candidate) => candidate.slug === resource);
58
+ const singular =
59
+ collection === undefined
60
+ ? humanize(resource, options.i18n)
61
+ : options.i18n.text(collection.labels.singular, collection.labels.singularTranslations);
62
+ const plural =
63
+ collection === undefined
64
+ ? singular
65
+ : options.i18n.text(collection.labels.plural, collection.labels.pluralTranslations);
66
+
67
+ if (action === undefined) return plural;
68
+ if (action === "create") {
69
+ return view === "api"
70
+ ? options.i18n.t("documents:apiFor", { label: singular })
71
+ : options.i18n.t("collections:createNew", { label: singular });
72
+ }
73
+ if (action === "trash") return options.i18n.t("collections:trashFor", { label: plural });
74
+ if (action === "upload") return options.i18n.t("uploads:bulkUpload");
75
+ if (view === "api") return options.i18n.t("documents:apiFor", { label: singular });
76
+ if (view === "versions") return options.i18n.t("documents:versionsFor", { label: singular });
77
+
78
+ return (
79
+ resolveDocumentViewLabel(options, resource, view) ??
80
+ options.i18n.t("documents:editing", { label: singular })
81
+ );
82
+ }
83
+
84
+ function resolveGlobalLabel(
85
+ options: AdminPageLabelOptions,
86
+ resource: string | undefined,
87
+ view: string | undefined
88
+ ) {
89
+ if (resource === undefined) return humanize("globals", options.i18n);
90
+
91
+ const global = options.manifest?.globals?.find((candidate) => candidate.slug === resource);
92
+ const label =
93
+ global === undefined
94
+ ? humanize(resource, options.i18n)
95
+ : options.i18n.text(global.labels.singular, global.labels.singularTranslations);
96
+
97
+ if (view === "api") return options.i18n.t("documents:apiFor", { label });
98
+ if (view === "versions") return options.i18n.t("documents:versionsFor", { label });
99
+ return resolveDocumentViewLabel(options, resource, view) ?? label;
100
+ }
101
+
102
+ function resolveDocumentViewLabel(
103
+ options: AdminPageLabelOptions,
104
+ resource: string,
105
+ view: string | undefined
106
+ ) {
107
+ if (view === undefined) return undefined;
108
+ return resolveExtensionLabel(
109
+ options.documentViews.find(
110
+ (candidate) =>
111
+ candidate.key === view &&
112
+ (candidate.collection === undefined || candidate.collection === resource)
113
+ ),
114
+ options.i18n
115
+ );
116
+ }
117
+
118
+ function resolvePluginOrFallbackLabel(options: AdminPageLabelOptions, segments: string[]) {
119
+ const route = options.routes.find((candidate) => candidate.path === segments.join("/"));
120
+ return (
121
+ resolveExtensionLabel(route?.navigation, options.i18n) ??
122
+ humanize(segments.at(-1) ?? options.i18n.t("navigation:page"), options.i18n)
123
+ );
124
+ }
125
+
126
+ function resolveExtensionLabel(
127
+ extension: { label: string; labelKey?: ExtensionTranslationKey } | undefined,
128
+ i18n: PageTitleI18n
129
+ ) {
130
+ if (extension?.labelKey !== undefined) return i18n.t(extension.labelKey);
131
+ return extension?.label;
132
+ }
133
+
134
+ function humanize(value: string, i18n: PageTitleI18n) {
135
+ return humanizeAdminPathSegment(value, i18n.language);
136
+ }
@@ -0,0 +1,24 @@
1
+ <script lang="ts">
2
+ import { Link, useRouteError } from "@hvniel/svelte-router";
3
+ import { getAdminI18n } from "@riducms/plugin";
4
+ import { Button, buttonVariants } from "@riducms/ui";
5
+
6
+ const i18n = getAdminI18n();
7
+ const error = useRouteError();
8
+
9
+ $effect(() => {
10
+ console.error("Ridu admin route failed", error.current);
11
+ });
12
+ </script>
13
+
14
+ <main class="grid min-h-screen place-items-center p-6">
15
+ <section class="grid max-w-lg justify-items-start gap-5" role="alert">
16
+ <h1 class="text-2xl font-semibold">{i18n.t("errors:unknown")}</h1>
17
+ <div class="flex flex-wrap gap-3">
18
+ <Button onclick={() => window.location.reload()}>{i18n.t("general:reloadPage")}</Button>
19
+ <Link to="/" replace class={buttonVariants({ variant: "outline" })}>
20
+ {i18n.t("errors:returnDashboard")}
21
+ </Link>
22
+ </div>
23
+ </section>
24
+ </main>
@@ -0,0 +1,34 @@
1
+ <script lang="ts">
2
+ import { createBrowserRouter, RouterProvider } from "@hvniel/svelte-router";
3
+
4
+ import AdminRouteError from "@admin/app/admin-route-error.svelte";
5
+ import AdminRouterRoot from "@admin/app/admin-router-root.svelte";
6
+ import type { AdminBootstrapCoordinator } from "@admin/core/bootstrap/admin-bootstrap";
7
+
8
+ let {
9
+ coordinator,
10
+ adminBasePath,
11
+ }: { coordinator: AdminBootstrapCoordinator; adminBasePath: string } = $props();
12
+ // One router owns the coordinator and base path selected when this provider mounts.
13
+ // svelte-ignore state_referenced_locally
14
+ const router = createBrowserRouter(
15
+ [
16
+ {
17
+ id: "admin-root",
18
+ path: "*",
19
+ Component: AdminRouterRoot,
20
+ ErrorBoundary: AdminRouteError,
21
+ loader: coordinator.loader,
22
+ shouldRevalidate: coordinator.shouldRevalidate,
23
+ },
24
+ ],
25
+ {
26
+ basename: adminBasePath,
27
+ hydrationData: { loaderData: { "admin-root": coordinator.initialState ?? null } },
28
+ }
29
+ );
30
+
31
+ $effect(() => () => router.dispose());
32
+ </script>
33
+
34
+ <RouterProvider {router} />
@@ -1,7 +1,48 @@
1
1
  <script lang="ts">
2
+ import { useLoaderData, useLocation } from "@hvniel/svelte-router";
3
+ import type { AdminPreparedRouteStateV1 } from "@riducms/protocol";
4
+ import { tick } from "svelte";
5
+
6
+ import { createAdminScroll } from "@admin/core/routing/admin-scroll.svelte";
7
+ import { getAdminBootstrapCoordinator } from "@admin/core/bootstrap/admin-bootstrap";
8
+ import { normalizedURLIdentity } from "@admin/core/bootstrap/admin-prepared-state";
2
9
  import AdminNavigationProgress from "@admin/app/admin-navigation-progress.svelte";
3
10
  import AdminPageTitle from "@admin/app/admin-page-title.svelte";
4
11
  import AdminRoutes from "@admin/app/admin-routes.svelte";
12
+
13
+ const coordinator = getAdminBootstrapCoordinator();
14
+ const location = useLocation();
15
+ const loaderData = useLoaderData<AdminPreparedRouteStateV1 | null>();
16
+ createAdminScroll();
17
+ let committedStateKey = "";
18
+ let markedIdentity = "";
19
+
20
+ $effect.pre(() => {
21
+ const routedIdentity = normalizedURLIdentity(location.current);
22
+ const state = loaderData.current;
23
+ const stateKey = `${routedIdentity}:${state?.fingerprint ?? "none"}:${state?.outcome ?? "none"}`;
24
+ if (stateKey === committedStateKey) return;
25
+
26
+ committedStateKey = stateKey;
27
+ if (state == null) return;
28
+
29
+ const stateIdentity = `${state.pathname}${state.search}`;
30
+ const url = new URL(stateIdentity, window.location.origin);
31
+ const preparedRoute = coordinator.commit(state, url);
32
+ if (preparedRoute !== true) return;
33
+
34
+ // Descendant controllers adopt the staged seed during this update. Discard it only after
35
+ // their pre-effects and the resulting DOM have committed.
36
+ tick().then(() => {
37
+ if (!coordinator.isRouteStaged(state)) return;
38
+ coordinator.discardRouteData(state);
39
+
40
+ if (stateIdentity !== markedIdentity) {
41
+ markedIdentity = stateIdentity;
42
+ performance.mark("ridu:admin-route-ready");
43
+ }
44
+ });
45
+ });
5
46
  </script>
6
47
 
7
48
  <AdminNavigationProgress />
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { Route, Routes, useLocation } from "@hvniel/svelte-router";
2
+ import { Navigate, Route, Routes, useLocation } from "@hvniel/svelte-router";
3
3
 
4
4
  import {
5
5
  adminCreateFirstUserPath,
@@ -9,40 +9,42 @@
9
9
  } from "@admin/core/routing/admin-paths";
10
10
  import { getAdminRuntime } from "@admin/core/runtime/admin-runtime.svelte";
11
11
  import CollectionListRoute from "@admin/features/collections/collection-list-route.svelte";
12
- import BulkUploadRoute from "@admin/features/uploads/bulk-upload-route.svelte";
12
+ import BulkUploadRoute from "@admin/features/uploads/bulk-upload-route-loader.svelte";
13
13
  import LoginRoute from "@admin/features/auth/login-route.svelte";
14
14
  import CreateFirstUserRoute from "@admin/features/auth/create-first-user-route.svelte";
15
15
  import ForgotPasswordRoute from "@admin/features/auth/forgot-password-route.svelte";
16
16
  import ResetPasswordRoute from "@admin/features/auth/reset-password-route.svelte";
17
17
  import RequestVerificationRoute from "@admin/features/auth/request-verification-route.svelte";
18
18
  import VerifyEmailRoute from "@admin/features/auth/verify-email-route.svelte";
19
- import AccountSecurityRoute from "@admin/features/auth/account-security-route.svelte";
20
- import AccountRoute from "@admin/features/auth/account-route.svelte";
19
+ import AccountSecurityRoute from "@admin/features/account/account-security-route.svelte";
20
+ import AccountRoute from "@admin/features/account/account-route.svelte";
21
21
  import DashboardRoute from "@admin/features/dashboard/dashboard-route.svelte";
22
22
  import DocumentRoute from "@admin/features/documents/document-route-loader.svelte";
23
- import VersionHistoryRoute from "@admin/features/versions/version-history-route.svelte";
23
+ import VersionHistoryRoute from "@admin/features/versions/version-history-route-loader.svelte";
24
24
 
25
25
  import AdminLayout from "@admin/app/admin-layout.svelte";
26
26
  import AdminCoreViewRoute from "@admin/app/admin-core-view-route.svelte";
27
- import DeferredRedirect from "@admin/app/deferred-redirect.svelte";
27
+ import AdminExtensionRoute from "@admin/app/admin-extension-route.svelte";
28
28
  import NotFoundRoute from "@admin/app/not-found-route.svelte";
29
29
 
30
30
  const runtime = getAdminRuntime();
31
- const location = $derived(useLocation());
32
- const requestedPath = $derived(`${location.pathname}${location.search}${location.hash}`);
33
- const postLoginPath = $derived(adminRedirectFromSearch(location.search));
31
+ const location = useLocation();
32
+ const requestedPath = $derived(
33
+ `${location.current.pathname}${location.current.search}${location.current.hash}`
34
+ );
35
+ const postLoginPath = $derived(adminRedirectFromSearch(location.current.search));
34
36
  </script>
35
37
 
36
38
  {#if runtime.authenticated}
37
39
  <Routes>
38
40
  <Route path="login">
39
41
  {#snippet element()}
40
- <DeferredRedirect to={postLoginPath} replace />
42
+ <Navigate to={postLoginPath} replace />
41
43
  {/snippet}
42
44
  </Route>
43
45
  <Route path="create-first-user">
44
46
  {#snippet element()}
45
- <DeferredRedirect to={adminRoutePatterns.home} replace />
47
+ <Navigate to={adminRoutePatterns.home} replace />
46
48
  {/snippet}
47
49
  </Route>
48
50
  <Route Component={AdminLayout}>
@@ -56,7 +58,12 @@
56
58
  </Route>
57
59
  <Route path="collections/:collection/trash" Component={CollectionListRoute} />
58
60
  <Route path="collections/:collection/upload" Component={BulkUploadRoute} />
59
- <Route path="collections/:collection/create/:view?">
61
+ <Route path="collections/:collection/create">
62
+ {#snippet element()}
63
+ <AdminCoreViewRoute surface="collectionCreate" DefaultView={DocumentRoute} />
64
+ {/snippet}
65
+ </Route>
66
+ <Route path="collections/:collection/create/api">
60
67
  {#snippet element()}
61
68
  <AdminCoreViewRoute surface="collectionCreate" DefaultView={DocumentRoute} />
62
69
  {/snippet}
@@ -65,19 +72,49 @@
65
72
  path="collections/:collection/:document/versions/:revision?"
66
73
  Component={VersionHistoryRoute}
67
74
  />
68
- <Route path="collections/:collection/:document/:view?">
75
+ <Route path="collections/:collection/:document">
76
+ {#snippet element()}
77
+ <AdminCoreViewRoute surface="collectionEdit" DefaultView={DocumentRoute} />
78
+ {/snippet}
79
+ </Route>
80
+ <Route path="collections/:collection/:document/api">
69
81
  {#snippet element()}
70
82
  <AdminCoreViewRoute surface="collectionEdit" DefaultView={DocumentRoute} />
71
83
  {/snippet}
72
84
  </Route>
85
+ {#each runtime.config.extensions.documentViews as view (`${view.collection ?? "*"}:${view.key}`)}
86
+ <Route
87
+ path={view.collection === undefined
88
+ ? `collections/:collection/:document/${view.key}`
89
+ : `collections/${view.collection}/:document/${view.key}`}
90
+ Component={DocumentRoute}
91
+ />
92
+ {/each}
73
93
  <Route path="globals/:global/versions/:revision?" Component={VersionHistoryRoute} />
74
- <Route path="globals/:global/:view?">
94
+ <Route path="globals/:global">
75
95
  {#snippet element()}
76
96
  <AdminCoreViewRoute surface="global" DefaultView={DocumentRoute} />
77
97
  {/snippet}
78
98
  </Route>
79
- {#each runtime.pluginRoutes as pluginRoute (pluginRoute.path)}
80
- <Route path={pluginRoute.path} Component={pluginRoute.component} />
99
+ <Route path="globals/:global/api">
100
+ {#snippet element()}
101
+ <AdminCoreViewRoute surface="global" DefaultView={DocumentRoute} />
102
+ {/snippet}
103
+ </Route>
104
+ {#each runtime.config.extensions.documentViews as view (`${view.collection ?? "*"}:${view.key}`)}
105
+ <Route
106
+ path={view.collection === undefined
107
+ ? `globals/:global/${view.key}`
108
+ : `globals/${view.collection}/${view.key}`}
109
+ Component={DocumentRoute}
110
+ />
111
+ {/each}
112
+ {#each runtime.config.extensions.routes as pluginRoute (pluginRoute.path)}
113
+ <Route path={pluginRoute.path}>
114
+ {#snippet element()}
115
+ <AdminExtensionRoute route={pluginRoute} />
116
+ {/snippet}
117
+ </Route>
81
118
  {/each}
82
119
  <Route path="*">
83
120
  {#snippet element()}
@@ -91,7 +128,7 @@
91
128
  <Route path="create-first-user" Component={CreateFirstUserRoute} />
92
129
  <Route path="*">
93
130
  {#snippet element()}
94
- <DeferredRedirect to={adminCreateFirstUserPath()} replace />
131
+ <Navigate to={adminCreateFirstUserPath()} replace />
95
132
  {/snippet}
96
133
  </Route>
97
134
  </Routes>
@@ -99,7 +136,7 @@
99
136
  <Routes>
100
137
  <Route path="create-first-user">
101
138
  {#snippet element()}
102
- <DeferredRedirect to={adminRoutePatterns.login} replace />
139
+ <Navigate to={adminRoutePatterns.login} replace />
103
140
  {/snippet}
104
141
  </Route>
105
142
  <Route path="login" Component={LoginRoute} />
@@ -109,7 +146,7 @@
109
146
  <Route path="verify-email" Component={VerifyEmailRoute} />
110
147
  <Route path="*">
111
148
  {#snippet element()}
112
- <DeferredRedirect to={adminLoginPath(requestedPath)} replace />
149
+ <Navigate to={adminLoginPath(requestedPath)} replace />
113
150
  {/snippet}
114
151
  </Route>
115
152
  </Routes>
@@ -3,10 +3,11 @@
3
3
 
4
4
  import RiduLogo from "@admin/components/brand/ridu-logo.svelte";
5
5
  import { Banner } from "@admin/components/ui/banner";
6
- import { Button } from "@admin/components/ui/button";
6
+ import { Button } from "@riducms/ui";
7
7
  import { getAdminRuntime } from "@admin/core/runtime/admin-runtime.svelte";
8
8
 
9
9
  let { children }: { children: Snippet } = $props();
10
+
10
11
  const runtime = getAdminRuntime();
11
12
  const development = import.meta.hot !== undefined;
12
13
  </script>
@@ -14,6 +15,7 @@
14
15
  {#if runtime.loading}
15
16
  <main
16
17
  class="ridu-surface-grid grid min-h-screen place-items-center"
18
+ data-ridu-loading-surface="runtime"
17
19
  aria-label={runtime.i18n.t("general:loadingSchema")}
18
20
  >
19
21
  <div class="grid justify-items-center gap-4 text-[13px] text-foreground-muted">