@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
@@ -5,21 +5,13 @@ import {
5
5
  type ResolvedAdminConfig,
6
6
  } from "@riducms/plugin/admin";
7
7
  import {
8
- type AdminDashboardPanel,
9
- type AdminLoginComponent,
10
- type AdminAccountComponent,
11
- type AdminNavigationComponent,
12
- type AdminLogoutButton,
13
- type AdminCoreView,
14
- type AdminBrandComponent,
15
- type AdminShellComponent,
16
- type AdminProvider,
17
- type AdminDocumentAction,
18
- type AdminDocumentView,
19
- type AdminListCell,
20
- type AdminRoute,
21
- } from "@riducms/plugin";
22
- import type { AuthSession, OperationCapabilities, SchemaManifest } from "@riducms/protocol";
8
+ bindSchemaManifest,
9
+ type AdminPreparedNavigationV1,
10
+ type AdminPreparedRuntimeV1,
11
+ type AuthSession,
12
+ type OperationCapabilities,
13
+ type SchemaManifest,
14
+ } from "@riducms/protocol";
23
15
  import { RiduError } from "@riducms/sdk";
24
16
  import { createContext } from "svelte";
25
17
 
@@ -61,9 +53,11 @@ export class AdminRuntime {
61
53
  manifestRefreshError = $state<string>();
62
54
  collectionOperations = $state.raw<Record<string, OperationCapabilities>>({});
63
55
  globalOperations = $state.raw<Record<string, OperationCapabilities>>({});
56
+ preparedPreferences = $state.raw<Record<string, unknown>>({});
64
57
  themePreference = $state<ThemePreference>("system");
65
58
  resolvedTheme = $state<"light" | "dark">("dark");
66
59
  contentLocale = $state<string>();
60
+ contentLocaleTransitioning = $state(false);
67
61
  #confirmedThemePreference: ThemePreference = "system";
68
62
  #confirmedThemeOwnerID = "";
69
63
  #confirmedContentLocale?: string;
@@ -75,6 +69,10 @@ export class AdminRuntime {
75
69
  #contentLocaleBlockers = new Map<symbol, () => boolean>();
76
70
  #contentLocaleBlockerSequence = 0;
77
71
  #contentLocaleBlockerRevision = $state(0);
72
+ #systemThemeQuery?: MediaQueryList;
73
+ readonly #handleSystemThemeChange = () => {
74
+ if (this.themePreference === "system") this.#applyTheme();
75
+ };
78
76
  #preferenceReset?: {
79
77
  sessionID: string | undefined;
80
78
  ownerID: string;
@@ -141,58 +139,20 @@ export class AdminRuntime {
141
139
  };
142
140
  }
143
141
 
144
- adoptContentLocale(locale: string) {
145
- if (!this.contentLocales.some((candidate) => candidate.code === locale)) return false;
146
- if (this.contentLocaleSwitchBlocked) return false;
147
- if (this.contentLocale === locale) return true;
148
- this.contentLocale = locale;
149
- void this.refreshAccess(locale).catch(() => {
150
- // Route adoption is best-effort; retain the last complete access snapshot on failure.
151
- });
152
- return true;
153
- }
154
-
155
- readonly pluginRoutes: readonly AdminRoute[];
156
- readonly dashboardPanels: readonly AdminDashboardPanel[];
157
- readonly loginComponents: readonly AdminLoginComponent[];
158
- readonly accountComponents: readonly AdminAccountComponent[];
159
- readonly navigationComponents: readonly AdminNavigationComponent[];
160
- readonly logoutButton?: AdminLogoutButton;
161
- readonly coreViews: readonly AdminCoreView[];
162
- readonly brandComponents: readonly AdminBrandComponent[];
163
- readonly shellComponents: readonly AdminShellComponent[];
164
- readonly providers: readonly AdminProvider[];
165
- readonly listCells: readonly AdminListCell[];
166
- readonly documentActions: readonly AdminDocumentAction[];
167
- readonly documentViews: readonly AdminDocumentView[];
168
142
  readonly rowLabels: RowLabelRegistry;
169
143
  readonly i18n: AdminI18nController;
170
144
 
171
145
  readonly config: ResolvedAdminConfig;
172
146
  readonly fields: FieldRegistry;
173
- readonly editors: ResolvedAdminConfig["editors"];
174
147
 
175
148
  constructor(
176
149
  readonly client: AdminClient,
177
- config: AdminConfig = {}
150
+ config: AdminConfig = {},
151
+ readonly adminBasePath = "/admin"
178
152
  ) {
179
153
  this.config = resolveAdminConfig(config);
180
- this.fields = createCoreFieldRegistry(this.config.fields);
181
- this.editors = this.config.editors;
154
+ this.fields = createCoreFieldRegistry(this.config.pluginFields);
182
155
  const extensions = this.config.extensions;
183
- this.pluginRoutes = extensions.routes;
184
- this.dashboardPanels = extensions.dashboard;
185
- this.loginComponents = extensions.login;
186
- this.accountComponents = extensions.account;
187
- this.navigationComponents = extensions.navigation;
188
- this.logoutButton = extensions.logoutButton;
189
- this.coreViews = extensions.views;
190
- this.brandComponents = extensions.branding;
191
- this.shellComponents = extensions.shell;
192
- this.providers = extensions.providers;
193
- this.listCells = extensions.listCells;
194
- this.documentActions = extensions.documentActions;
195
- this.documentViews = extensions.documentViews;
196
156
  this.rowLabels = createRowLabelRegistry(extensions.rowLabels, this.config.rowLabels);
197
157
  this.i18n = new AdminI18nController(
198
158
  client,
@@ -203,10 +163,65 @@ export class AdminRuntime {
203
163
  );
204
164
  this.#applyTheme();
205
165
  if (typeof window !== "undefined") {
206
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
207
- if (this.themePreference === "system") this.#applyTheme();
208
- });
166
+ this.#systemThemeQuery = window.matchMedia("(prefers-color-scheme: dark)");
167
+ this.#systemThemeQuery.addEventListener("change", this.#handleSystemThemeChange);
168
+ }
169
+ }
170
+
171
+ hardNavigate(path: string) {
172
+ const base = `/${this.adminBasePath.split("/").filter(Boolean).join("/")}`;
173
+ const route = path.startsWith("/") ? path : `/${path}`;
174
+ window.location.assign(base === "/" ? route : `${base}${route}`);
175
+ // Keep identity-changing handlers pending until the new document takes ownership.
176
+ return new Promise<never>(() => {});
177
+ }
178
+
179
+ dispose() {
180
+ this.#systemThemeQuery?.removeEventListener("change", this.#handleSystemThemeChange);
181
+ this.#systemThemeQuery = undefined;
182
+ }
183
+
184
+ adoptPrepared(prepared: AdminPreparedRuntimeV1) {
185
+ this.#manifestRequest += 1;
186
+ this.error = undefined;
187
+ this.loading = true;
188
+ const manifest = bindSchemaManifest(prepared.manifest);
189
+ this.#installManifest(manifest);
190
+ this.session = prepared.session as AuthSession<AdminDocument> | undefined;
191
+ this.authBootstrapAvailable = prepared.authBootstrapAvailable;
192
+ this.collectionOperations = { ...prepared.collectionOperations };
193
+ this.globalOperations = { ...prepared.globalOperations };
194
+ this.preparedPreferences = { ...prepared.preferences };
195
+ this.#confirmedThemePreference = isThemePreference(prepared.theme) ? prepared.theme : "system";
196
+ this.#confirmedThemeOwnerID = preferenceOwnerID(this.session);
197
+ this.themePreference = this.#confirmedThemePreference;
198
+ this.#applyTheme();
199
+ if (
200
+ prepared.contentLocale !== undefined &&
201
+ this.contentLocales.some((candidate) => candidate.code === prepared.contentLocale)
202
+ ) {
203
+ this.contentLocale = prepared.contentLocale;
204
+ this.#confirmedContentLocale = prepared.contentLocale;
205
+ this.#confirmedContentLocaleOwnerID = preferenceOwnerID(this.session);
209
206
  }
207
+ this.i18n.adoptPreparedPreferences(prepared.adminLanguage, prepared.adminTimeZone);
208
+ this.loading = false;
209
+ }
210
+
211
+ adoptPreparedNavigation(prepared: AdminPreparedNavigationV1) {
212
+ this.collectionOperations = { ...prepared.collectionOperations };
213
+ this.globalOperations = { ...prepared.globalOperations };
214
+ if (
215
+ prepared.contentLocale !== undefined &&
216
+ this.contentLocales.some((candidate) => candidate.code === prepared.contentLocale)
217
+ ) {
218
+ this.contentLocale = prepared.contentLocale;
219
+ this.#confirmedContentLocale = prepared.contentLocale;
220
+ this.#confirmedContentLocaleOwnerID = preferenceOwnerID(this.session);
221
+ }
222
+ // The context key guarantees this is the same identity. Preferences are
223
+ // adopted once from the cold document; a navigation response may have started
224
+ // before a local theme/language/time-zone write and must not roll it back.
210
225
  }
211
226
 
212
227
  async loadTheme() {
@@ -240,6 +255,15 @@ export class AdminRuntime {
240
255
  return contentLocaleFromPath(path, this.contentLocales);
241
256
  }
242
257
 
258
+ /** A supported URL locale wins; otherwise retain the session's selection or the default. */
259
+ resolveContentLocale(requested: string | null | undefined) {
260
+ return (
261
+ this.contentLocales.find((locale) => locale.code === requested)?.code ??
262
+ this.contentLocale ??
263
+ this.manifest?.application.localization?.defaultLocale
264
+ );
265
+ }
266
+
243
267
  async loadContentLocale(activeLocale?: string) {
244
268
  const request = ++this.#contentLocaleRequest;
245
269
  const localization = this.manifest?.application.localization;
@@ -274,44 +298,24 @@ export class AdminRuntime {
274
298
  : this.#confirmedContentLocale;
275
299
  }
276
300
 
277
- async setContentLocale(locale: string) {
301
+ async persistContentLocalePreference(locale: string) {
278
302
  if (!this.contentLocales.some((candidate) => candidate.code === locale)) return;
279
303
  if (this.contentLocaleSwitchBlocked) throw new ContentLocaleSwitchBlockedError();
280
- if (locale === this.contentLocale && locale === this.#confirmedContentLocale) return;
281
- const request = ++this.#contentLocaleRequest;
282
304
  const sessionID = this.session?.id;
283
305
  const ownerID = preferenceOwnerID(this.session);
284
- this.contentLocale = locale;
285
- const accessRefresh = this.refreshAccess(locale);
286
- void accessRefresh.catch(() => {
287
- // The operation awaits and reconciles this failure after its preference write settles.
288
- });
289
- try {
290
- if (sessionID === undefined || ownerID === "") {
291
- await this.client.setPreference("content-locale", { locale });
292
- } else {
293
- const result = await getPreferenceWriteQueue().enqueue(
294
- JSON.stringify([ownerID, "content-locale"]),
295
- ownerID,
296
- () => this.session?.id === sessionID,
297
- () => this.client.setPreference("content-locale", { locale })
298
- );
299
- if (!result.dispatched) throw new StalePreferenceSessionError();
300
- }
301
- if (request !== this.#contentLocaleRequest) return;
302
- if (this.session?.id !== sessionID || preferenceOwnerID(this.session) !== ownerID) {
303
- throw new StalePreferenceSessionError();
304
- }
305
- await accessRefresh;
306
- this.#confirmedContentLocale = locale;
307
- this.#confirmedContentLocaleOwnerID = ownerID;
308
- } catch (error) {
309
- if (request === this.#contentLocaleRequest) {
310
- this.contentLocale = this.#confirmedContentLocale;
311
- await this.refreshAccess(this.#confirmedContentLocale);
312
- }
313
- throw error;
306
+ if (sessionID === undefined || ownerID === "") {
307
+ await this.client.setPreference("content-locale", { locale });
308
+ } else {
309
+ const result = await getPreferenceWriteQueue().enqueue(
310
+ JSON.stringify([ownerID, "content-locale"]),
311
+ ownerID,
312
+ () => this.session?.id === sessionID,
313
+ () => this.client.setPreference("content-locale", { locale })
314
+ );
315
+ if (!result.dispatched) throw new StalePreferenceSessionError();
314
316
  }
317
+ this.#confirmedContentLocale = locale;
318
+ this.#confirmedContentLocaleOwnerID = ownerID;
315
319
  }
316
320
 
317
321
  async setTheme(preference: ThemePreference) {
@@ -437,6 +441,27 @@ export class AdminRuntime {
437
441
  }
438
442
  }
439
443
 
444
+ #installManifest(manifest: SchemaManifest) {
445
+ validateAdminManifest(this.config, manifest);
446
+ this.manifest = manifest;
447
+ this.manifestRevision += 1;
448
+ this.#configureContentLocale();
449
+ this.i18n.configure(manifest.application.adminLocalization);
450
+ return manifest.application.admin;
451
+ }
452
+
453
+ async #refreshLocalizedAccess() {
454
+ await this.loadContentLocale(this.#browserRouteContentLocale());
455
+ const accessAuthoritative = await this.refreshAccess(this.contentLocale);
456
+ if (!accessAuthoritative || this.session === undefined || this.adminAccessAllowed) return;
457
+ try {
458
+ await this.client.logout();
459
+ } catch {
460
+ // The local session is still denied even if server cleanup fails.
461
+ }
462
+ this.session = undefined;
463
+ }
464
+
440
465
  async bootstrap() {
441
466
  const request = ++this.#manifestRequest;
442
467
  this.loading = true;
@@ -444,12 +469,7 @@ export class AdminRuntime {
444
469
  try {
445
470
  const manifest = await this.client.schema();
446
471
  if (request !== this.#manifestRequest) return;
447
- validateAdminManifest(this.config, manifest);
448
- this.manifest = manifest;
449
- this.manifestRevision += 1;
450
- this.#configureContentLocale();
451
- this.i18n.configure(manifest.application.adminLocalization);
452
- const admin = manifest.application.admin;
472
+ const admin = this.#installManifest(manifest);
453
473
  if (admin !== undefined) {
454
474
  const bootstrap = await this.client.authBootstrap(admin.userCollectionSlug);
455
475
  if (request !== this.#manifestRequest) return;
@@ -471,16 +491,7 @@ export class AdminRuntime {
471
491
  this.session = undefined;
472
492
  this.authBootstrapAvailable = false;
473
493
  }
474
- await this.loadContentLocale(this.#browserRouteContentLocale());
475
- const accessAuthoritative = await this.refreshAccess(this.contentLocale);
476
- if (accessAuthoritative && this.session !== undefined && !this.adminAccessAllowed) {
477
- try {
478
- await this.client.logout();
479
- } catch {
480
- // The local session is still denied even if server cleanup fails.
481
- }
482
- this.session = undefined;
483
- }
494
+ await this.#refreshLocalizedAccess();
484
495
  await Promise.all([this.loadTheme(), this.i18n.loadPreferences()]);
485
496
  } catch (error) {
486
497
  if (request !== this.#manifestRequest) return;
@@ -497,12 +508,7 @@ export class AdminRuntime {
497
508
  try {
498
509
  const manifest = await this.client.schema();
499
510
  if (request !== this.#manifestRequest) return;
500
- validateAdminManifest(this.config, manifest);
501
- this.manifest = manifest;
502
- this.manifestRevision += 1;
503
- this.#configureContentLocale();
504
- this.i18n.configure(manifest.application.adminLocalization);
505
- const admin = manifest.application.admin;
511
+ const admin = this.#installManifest(manifest);
506
512
  if (admin === undefined || this.session?.collection !== admin.userCollectionSlug) {
507
513
  this.session = undefined;
508
514
  }
@@ -513,16 +519,7 @@ export class AdminRuntime {
513
519
  } else {
514
520
  this.authBootstrapAvailable = false;
515
521
  }
516
- await this.loadContentLocale(this.#browserRouteContentLocale());
517
- const accessAuthoritative = await this.refreshAccess(this.contentLocale);
518
- if (accessAuthoritative && this.session !== undefined && !this.adminAccessAllowed) {
519
- try {
520
- await this.client.logout();
521
- } catch {
522
- // The local session is still denied even if server cleanup fails.
523
- }
524
- this.session = undefined;
525
- }
522
+ await this.#refreshLocalizedAccess();
526
523
  await this.i18n.loadPreferences();
527
524
  } catch (error) {
528
525
  if (request !== this.#manifestRequest) return;
@@ -0,0 +1,33 @@
1
+ import type { SchemaField } from "@riducms/protocol";
2
+
3
+ export type SchemaFieldDefault = { present: false } | { present: true; value: unknown };
4
+
5
+ /** Decode the literal-default representation used by the schema manifest. */
6
+ export function schemaFieldDefault(field: SchemaField): SchemaFieldDefault {
7
+ if (field.type === "select" && field.select?.hasMany === true) {
8
+ if ((field.select.defaultValues?.length ?? 0) === 0) return { present: false };
9
+ return { present: true, value: field.select.defaultValues };
10
+ }
11
+ if (field.default === undefined) return { present: false };
12
+ if (field.type === "text-list" || field.type === "number-list")
13
+ return { present: true, value: JSON.parse(field.default) };
14
+ if (field.type === "number") return { present: true, value: Number(field.default) };
15
+ if (field.type === "checkbox") return { present: true, value: field.default === "true" };
16
+ return { present: true, value: field.default };
17
+ }
18
+
19
+ /** Whether a generated create object requires this field when that object is supplied. */
20
+ export function schemaFieldRequiredOnCreate(field: SchemaField): boolean {
21
+ const inputRequired =
22
+ field.required ||
23
+ ((field.type === "text-list" || field.type === "number-list") &&
24
+ (field.list?.minRows ?? 0) > 0);
25
+ if (!inputRequired) return false;
26
+
27
+ return !(
28
+ field.default !== undefined ||
29
+ field.dynamicDefault === true ||
30
+ (field.select?.hasMany === true && (field.select.defaultValues?.length ?? 0) > 0) ||
31
+ field.text?.slug !== undefined
32
+ );
33
+ }
@@ -0,0 +1,15 @@
1
+ import { resolveBlockTypes, type SchemaField } from "@riducms/protocol";
2
+
3
+ export function fieldsUseLocalization(fields: readonly SchemaField[]): boolean {
4
+ const visited = new Set<SchemaField>();
5
+ const usesLocalization = (field: SchemaField): boolean => {
6
+ if (visited.has(field)) return false;
7
+ visited.add(field);
8
+ return (
9
+ field.localized === true ||
10
+ field.nested?.fields.some(usesLocalization) === true ||
11
+ resolveBlockTypes(field.blocks).some((block) => block.fields.some(usesLocalization))
12
+ );
13
+ };
14
+ return fields.some(usesLocalization);
15
+ }
@@ -0,0 +1,11 @@
1
+ import { isRecord } from "@riducms/protocol";
2
+
3
+ /** Read a document/group path without treating arrays as nested records. */
4
+ export function readDocumentPath(value: unknown, path: string) {
5
+ let current = value;
6
+ for (const segment of path.split(".")) {
7
+ if (!isRecord(current)) return undefined;
8
+ current = current[segment];
9
+ }
10
+ return current;
11
+ }
@@ -0,0 +1,37 @@
1
+ @use "@riducms/ui/styles.scss" as ui;
2
+
3
+ @layer ridu.components {
4
+ .ridu-account-menu__trigger {
5
+ display: grid;
6
+ place-items: center;
7
+ flex-shrink: 0;
8
+ width: 25px;
9
+ height: 25px;
10
+ border: 0;
11
+ padding: 0;
12
+ background: transparent;
13
+ color: var(--foreground);
14
+ cursor: pointer;
15
+ border-radius: 50%;
16
+
17
+ &:focus-visible {
18
+ @include ui.focus-outline;
19
+ }
20
+ }
21
+ .ridu-account-menu__avatar {
22
+ fill: var(--nav-indicator-color);
23
+ overflow: visible;
24
+ }
25
+ .ridu-account-menu__avatar-background {
26
+ fill: var(--background-surface);
27
+ stroke: var(--nav-indicator-color);
28
+ stroke-width: 1px;
29
+ }
30
+ .ridu-account-menu__trigger:hover .ridu-account-menu__avatar {
31
+ fill: var(--foreground-muted);
32
+ }
33
+ .ridu-account-menu__trigger:hover .ridu-account-menu__avatar-background {
34
+ fill: var(--background-layer);
35
+ stroke: var(--foreground-muted);
36
+ }
37
+ }
@@ -0,0 +1,115 @@
1
+ <script lang="ts">
2
+ import { Link } from "@hvniel/svelte-router";
3
+ import "@admin/features/account/account-menu.scss";
4
+ import SettingsIcon from "~icons/lucide/settings";
5
+ import UserRoundIcon from "~icons/lucide/user-round";
6
+
7
+ import { buttonVariants } from "@riducms/ui";
8
+ import { Popover, PopoverContent, PopoverTrigger } from "@admin/components/ui/popover";
9
+ import { adminRoutePatterns } from "@admin/core/routing/admin-paths";
10
+ import { getAdminRuntime } from "@admin/core/runtime/admin-runtime.svelte";
11
+
12
+ const runtime = getAdminRuntime();
13
+ const extensions = runtime.config.extensions;
14
+
15
+ let open = $state(false);
16
+
17
+ const accountAvatar = extensions.branding.find(
18
+ (component) => component.surface === "accountAvatar"
19
+ );
20
+ const settingsComponents = extensions.shellSlots.filter(
21
+ (component) => component.position === "settingsMenu"
22
+ );
23
+
24
+ function accountDetails() {
25
+ const user = runtime.session?.user;
26
+ const candidate = user?.name;
27
+ let displayName =
28
+ typeof candidate === "string" && candidate.trim().length > 0 ? candidate : undefined;
29
+
30
+ const identityField = runtime.authCollection?.authSettings?.identityField;
31
+ const identity = identityField === undefined ? undefined : user?.[identityField];
32
+ if (displayName === undefined && typeof identity === "string" && identity.trim().length > 0)
33
+ displayName = identity;
34
+ displayName ??= runtime.i18n.t("account:signedInUser");
35
+
36
+ return {
37
+ user,
38
+ displayName,
39
+ identity: typeof identity === "string" && identity !== displayName ? identity : undefined,
40
+ };
41
+ }
42
+
43
+ const account = $derived(accountDetails());
44
+ </script>
45
+
46
+ <Popover bind:open>
47
+ <PopoverTrigger
48
+ class="ridu-account-menu__trigger"
49
+ aria-label={runtime.i18n.t("account:accountMenuLabel", { name: account.displayName })}
50
+ >
51
+ {#if accountAvatar !== undefined && runtime.manifest !== undefined}
52
+ <accountAvatar.component
53
+ manifest={runtime.manifest}
54
+ user={account.user}
55
+ surface="accountAvatar"
56
+ i18n={runtime.i18n}
57
+ />
58
+ {:else}
59
+ <svg
60
+ class="ridu-account-menu__avatar"
61
+ width="25"
62
+ height="25"
63
+ viewBox="0 0 25 25"
64
+ aria-hidden="true"
65
+ >
66
+ <circle class="ridu-account-menu__avatar-background" cx="12.5" cy="12.5" r="11.5" />
67
+ <circle cx="12.5" cy="10.73" r="3.98" />
68
+ <path
69
+ d="M12.5,24a11.44,11.44,0,0,0,7.66-2.94c-.5-2.71-3.73-4.8-7.66-4.8s-7.16,2.09-7.66,4.8A11.44,11.44,0,0,0,12.5,24Z"
70
+ />
71
+ </svg>
72
+ {/if}
73
+ </PopoverTrigger>
74
+ <PopoverContent side="bottom" align="end" sideOffset={8} class="w-[212px] gap-1 p-2">
75
+ <div class="border-b border-control-border px-2.5 py-2 pb-3">
76
+ <p class="truncate text-[13px] font-medium text-foreground">{account.displayName}</p>
77
+ {#if account.identity !== undefined}
78
+ <p class="mt-0.5 truncate text-[10.5px] text-foreground-faint">{account.identity}</p>
79
+ {/if}
80
+ </div>
81
+
82
+ <Link
83
+ to={adminRoutePatterns.account}
84
+ class={buttonVariants({
85
+ variant: "ghost",
86
+ class: "h-9 w-full justify-start gap-2 px-2.5 text-[12.5px]",
87
+ })}
88
+ onclick={() => (open = false)}
89
+ >
90
+ <UserRoundIcon class="size-3.5" aria-hidden="true" />
91
+ {runtime.i18n.t("account:profileAndPreferences")}
92
+ </Link>
93
+ <Link
94
+ to={adminRoutePatterns.accountSecurity}
95
+ class={buttonVariants({
96
+ variant: "ghost",
97
+ class: "h-9 w-full justify-start gap-2 px-2.5 text-[12.5px]",
98
+ })}
99
+ onclick={() => (open = false)}
100
+ >
101
+ <SettingsIcon class="size-3.5" aria-hidden="true" />
102
+ {runtime.i18n.t("account:accountSecurity")}
103
+ </Link>
104
+ {#if runtime.manifest !== undefined}
105
+ {#each settingsComponents as component (component.key)}
106
+ <component.component
107
+ manifest={runtime.manifest}
108
+ user={account.user}
109
+ position="settingsMenu"
110
+ i18n={runtime.i18n}
111
+ />
112
+ {/each}
113
+ {/if}
114
+ </PopoverContent>
115
+ </Popover>
@@ -1,11 +1,12 @@
1
1
  <script lang="ts">
2
2
  import { Link } from "@hvniel/svelte-router";
3
3
 
4
- import { buttonVariants } from "@admin/components/ui/button";
4
+ import { buttonVariants } from "@riducms/ui";
5
5
  import { adminRoutePatterns } from "@admin/core/routing/admin-paths";
6
6
  import { getAdminRuntime } from "@admin/core/runtime/admin-runtime.svelte";
7
7
 
8
8
  const runtime = getAdminRuntime();
9
+
9
10
  let { active }: { active: "profile" | "security" } = $props();
10
11
  </script>
11
12
 
@@ -15,29 +16,25 @@
15
16
  >
16
17
  <Link
17
18
  to={adminRoutePatterns.account}
18
- class={buttonVariants({
19
- variant: "ghost",
20
- class: [
21
- "rounded-b-none border-b-2 px-3",
22
- active === "profile"
23
- ? "border-primary text-foreground-strong"
24
- : "border-transparent text-foreground-muted hover:bg-control",
25
- ],
26
- })}
19
+ class={[
20
+ buttonVariants({ variant: "ghost" }),
21
+ "rounded-b-none border-b-2 px-3",
22
+ active === "profile"
23
+ ? "border-primary text-foreground-strong"
24
+ : "border-transparent text-foreground-muted hover:bg-control",
25
+ ]}
27
26
  >
28
27
  {runtime.i18n.t("account:profileAndPreferences")}
29
28
  </Link>
30
29
  <Link
31
30
  to={adminRoutePatterns.accountSecurity}
32
- class={buttonVariants({
33
- variant: "ghost",
34
- class: [
35
- "rounded-b-none border-b-2 px-3",
36
- active === "security"
37
- ? "border-primary text-foreground-strong"
38
- : "border-transparent text-foreground-muted hover:bg-control",
39
- ],
40
- })}
31
+ class={[
32
+ buttonVariants({ variant: "ghost" }),
33
+ "rounded-b-none border-b-2 px-3",
34
+ active === "security"
35
+ ? "border-primary text-foreground-strong"
36
+ : "border-transparent text-foreground-muted hover:bg-control",
37
+ ]}
41
38
  >
42
39
  {runtime.i18n.t("account:security")}
43
40
  </Link>