@riducms/admin 0.2.3 → 0.4.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 +29 -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 +131 -135
  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 +159 -0
  120. package/src/features/{auth → account}/account-security-route.svelte +140 -42
  121. package/src/features/api-reference/api-reference-code.svelte +114 -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 +30 -60
  133. package/src/features/auth/create-first-user-route.svelte +83 -122
  134. package/src/features/auth/forgot-password-route.svelte +32 -24
  135. package/src/features/auth/login-route.svelte +69 -117
  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 +28 -23
  139. package/src/features/auth/reset-password-route.svelte +111 -41
  140. package/src/features/auth/verify-email-route.svelte +52 -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 +531 -617
  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 +336 -239
  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 +148 -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,42 +1,44 @@
1
1
  <script lang="ts">
2
2
  import { Link, useLocation } from "@hvniel/svelte-router";
3
- import { RiduError } from "@riducms/sdk";
4
- import EyeIcon from "~icons/lucide/eye";
5
- import EyeOffIcon from "~icons/lucide/eye-off";
6
3
 
7
4
  import { Banner } from "@admin/components/ui/banner";
8
- import { Button } from "@admin/components/ui/button";
9
- import { Input } from "@admin/components/ui/input";
5
+ import { Button } from "@riducms/ui";
10
6
  import { adminRedirectFromSearch, adminRoutePatterns } from "@admin/core/routing/admin-paths";
11
7
  import { getNotificationCenter } from "@admin/core/notifications/notification-center.svelte";
12
8
  import { getAdminRuntime } from "@admin/core/runtime/admin-runtime.svelte";
13
9
  import AuthBrand from "@admin/features/auth/auth-brand.svelte";
10
+ import AuthField from "@admin/features/auth/auth-field.svelte";
14
11
  import AuthFrame from "@admin/features/auth/auth-frame.svelte";
15
12
 
16
13
  const runtime = getAdminRuntime();
14
+ const extensions = runtime.config.extensions;
17
15
  const notifications = getNotificationCenter();
18
- const location = $derived(useLocation());
19
- const postLoginPath = $derived(adminRedirectFromSearch(location.search));
16
+ const location = useLocation();
17
+
18
+ const postLoginPath = $derived(adminRedirectFromSearch(location.current.search));
19
+ const setupNotice = $derived(new URLSearchParams(location.current.search).get("setup"));
20
+ const setupMessage = $derived(
21
+ setupNotice === "created"
22
+ ? "auth:accountReady"
23
+ : setupNotice === "completed"
24
+ ? "auth:firstAccountExists"
25
+ : setupNotice === "denied"
26
+ ? "auth:firstAccountNoAdminAccess"
27
+ : undefined
28
+ );
29
+
20
30
  let email = $state("");
21
31
  let password = $state("");
22
- let passwordVisible = $state(false);
23
32
  let pending = $state(false);
24
- let error = $state<string>();
33
+
25
34
  const authCollection = $derived(runtime.authCollection);
26
- const replacement = $derived(
27
- runtime.loginComponents.find((component) => component.position === "replace")
28
- );
29
- const loginLogo = $derived(
30
- runtime.brandComponents.find((component) => component.surface === "loginLogo")
31
- );
32
- const beforeComponents = $derived(
33
- runtime.loginComponents.filter((component) => component.position === "before")
34
- );
35
- const afterComponents = $derived(
36
- runtime.loginComponents.filter(
37
- (component) => component.position === undefined || component.position === "after"
38
- )
35
+ const replacement = extensions.login.find((component) => component.position === "replace");
36
+ const loginLogo = extensions.branding.find((component) => component.surface === "loginLogo");
37
+ const beforeComponents = extensions.login.filter((component) => component.position === "before");
38
+ const afterComponents = extensions.login.filter(
39
+ (component) => component.position === undefined || component.position === "after"
39
40
  );
41
+
40
42
  const host = {
41
43
  login: signIn,
42
44
  notify: (tone: "success" | "error", title: string, message?: string) =>
@@ -47,7 +49,8 @@
47
49
  if (authCollection === undefined) {
48
50
  throw new Error(runtime.i18n.t("auth:configuredCollectionUnavailable"));
49
51
  }
50
- const session = await runtime.client.login(authCollection.slug, credentials);
52
+
53
+ await runtime.client.auth.login({ collection: authCollection.slug, ...credentials });
51
54
  const destinationLocale = runtime.contentLocaleForPath(postLoginPath);
52
55
  const destinationAccessAuthoritative = await runtime.refreshAccess(
53
56
  destinationLocale ?? runtime.contentLocale
@@ -57,58 +60,29 @@
57
60
  runtime.collectionOperations[authCollection.slug]?.admin !== true
58
61
  ) {
59
62
  try {
60
- await runtime.client.logout();
61
- } catch {
62
- // The shell remains denied even if server cleanup fails.
63
- }
64
- throw new Error(runtime.i18n.t("auth:adminAccessDenied"));
65
- }
66
- // Keep this route mounted until access and the destination are ready.
67
- // Assigning the session before the await swaps the route tree and leaves
68
- // this component's navigate function inactive.
69
- runtime.session = session;
70
- await Promise.all([
71
- runtime.loadTheme(),
72
- runtime.loadContentLocale(destinationLocale),
73
- runtime.i18n.loadPreferences(),
74
- ]);
75
- const preferredAccessAuthoritative = await runtime.refreshAccess(runtime.contentLocale);
76
- if (
77
- preferredAccessAuthoritative &&
78
- runtime.collectionOperations[authCollection.slug]?.admin !== true
79
- ) {
80
- try {
81
- await runtime.client.logout();
63
+ await runtime.client.auth.logout();
82
64
  } catch {
83
65
  // The shell remains denied even if server cleanup fails.
84
66
  }
85
- runtime.session = undefined;
86
67
  throw new Error(runtime.i18n.t("auth:adminAccessDenied"));
87
68
  }
88
- // Assigning the authenticated session swaps this route for the authenticated
89
- // route tree. Its /login route owns the deferred redirect so this component
90
- // never reads route-owned derived state after it has been destroyed.
69
+
70
+ await runtime.hardNavigate(postLoginPath);
91
71
  }
92
72
 
93
- async function login() {
73
+ async function handleSubmit(event: SubmitEvent) {
74
+ event.preventDefault();
94
75
  pending = true;
95
- error = undefined;
76
+
96
77
  try {
97
78
  await signIn({ email, password });
98
79
  } catch (cause) {
99
- error =
100
- cause instanceof RiduError || cause instanceof Error
101
- ? cause.message
102
- : runtime.i18n.t("auth:loginFailed");
80
+ const message = cause instanceof Error ? cause.message : runtime.i18n.t("auth:loginFailed");
81
+ notifications.error({ title: message });
103
82
  } finally {
104
83
  pending = false;
105
84
  }
106
85
  }
107
-
108
- async function handleSubmit(event: SubmitEvent) {
109
- event.preventDefault();
110
- await login();
111
- }
112
86
  </script>
113
87
 
114
88
  {#snippet brand()}
@@ -132,74 +106,52 @@
132
106
  {/each}
133
107
  {/if}
134
108
 
135
- <form class="grid gap-5" onsubmit={handleSubmit}>
136
- <h1 class="sr-only">{runtime.i18n.t("auth:login")}</h1>
137
-
138
- <label class="grid gap-2" for="ridu-login-email">
139
- <span class="ridu-field-label text-foreground-body">{runtime.i18n.t("auth:email")}</span>
140
- <Input
141
- id="ridu-login-email"
142
- type="email"
143
- bind:value={email}
144
- autocomplete="email"
145
- placeholder={runtime.i18n.t("auth:emailPlaceholder")}
146
- required
109
+ <form class="ridu-auth__form" onsubmit={handleSubmit}>
110
+ <h1 class="ridu-auth__sr-only">{runtime.i18n.t("auth:login")}</h1>
111
+
112
+ {#if setupMessage !== undefined}
113
+ <Banner tone={setupNotice === "denied" ? "destructive" : "neutral"}>
114
+ {runtime.i18n.t(setupMessage)}
115
+ </Banner>
116
+ {/if}
117
+
118
+ <AuthField
119
+ disabled={pending}
120
+ id="ridu-login-email"
121
+ label={runtime.i18n.t("auth:email")}
122
+ autocomplete="email"
123
+ bind:value={email}
124
+ />
125
+
126
+ <div class="ridu-auth__field">
127
+ <AuthField
128
+ disabled={pending}
129
+ id="ridu-login-password"
130
+ label={runtime.i18n.t("auth:password")}
131
+ type="password"
132
+ autocomplete="current-password"
133
+ bind:value={password}
147
134
  />
148
- </label>
149
-
150
- <div class="grid gap-2">
151
- <label class="ridu-field-label text-foreground-body" for="ridu-login-password">
152
- {runtime.i18n.t("auth:password")}
153
- </label>
154
- <span class="relative block">
155
- <Input
156
- id="ridu-login-password"
157
- class="pe-11"
158
- type={passwordVisible ? "text" : "password"}
159
- bind:value={password}
160
- autocomplete="current-password"
161
- placeholder={runtime.i18n.t("auth:passwordPlaceholder")}
162
- required
163
- />
164
- <Button
165
- variant="ghost"
166
- size="icon-sm"
167
- class="absolute top-1/2 end-2.5 -translate-y-1/2"
168
- onclick={() => (passwordVisible = !passwordVisible)}
169
- aria-label={passwordVisible
170
- ? runtime.i18n.t("auth:hidePassword")
171
- : runtime.i18n.t("auth:showPassword")}
172
- >
173
- {#if passwordVisible}
174
- <EyeOffIcon class="size-3.5" />
175
- {:else}
176
- <EyeIcon class="size-3.5" />
177
- {/if}
178
- </Button>
179
- </span>
180
135
  {#if authCollection?.authSettings?.passwordReset}
181
- <Link
182
- class="w-fit text-[12px] text-foreground underline underline-offset-2 hover:text-foreground-muted"
183
- to={adminRoutePatterns.forgotPassword}
184
- >
136
+ <Link class="ridu-auth__link" to={adminRoutePatterns.forgotPassword}>
185
137
  {runtime.i18n.t("auth:forgotPassword")}
186
138
  </Link>
187
139
  {/if}
188
140
  </div>
189
141
 
190
- {#if error !== undefined}
191
- <Banner tone="destructive">
192
- <span class="size-2 shrink-0 rounded-full bg-destructive" aria-hidden="true"></span>
193
- {error}
194
- </Banner>
195
- {/if}
196
-
197
- <Button class="mt-1 h-10 w-full" type="submit" size="lg" disabled={pending}>
142
+ <Button
143
+ class="ridu-auth__submit"
144
+ type="submit"
145
+ size="lg"
146
+ disabled={pending}
147
+ aria-busy={pending}
148
+ >
198
149
  {pending ? runtime.i18n.t("auth:signingIn") : runtime.i18n.t("auth:login")}
199
150
  </Button>
151
+
200
152
  {#if authCollection?.authSettings?.verifyEmail}
201
153
  <Link
202
- class="text-center text-[11.5px] text-foreground-muted hover:text-primary"
154
+ class="ridu-auth__link ridu-auth__secondary-link"
203
155
  to={adminRoutePatterns.requestVerification}
204
156
  >
205
157
  {runtime.i18n.t("auth:requestVerification")}
@@ -0,0 +1,34 @@
1
+ @use "@riducms/ui/styles.scss" as ui;
2
+
3
+ @layer ridu.components {
4
+ .ridu-logout {
5
+ display: grid;
6
+ place-items: center;
7
+ width: 20px;
8
+ height: 20px;
9
+ padding: 0;
10
+ border: 0;
11
+ background: transparent;
12
+ color: var(--foreground);
13
+ cursor: pointer;
14
+
15
+ svg {
16
+ width: 20px;
17
+ height: 20px;
18
+ stroke-width: 1;
19
+ }
20
+
21
+ &:focus-visible {
22
+ @include ui.focus-outline;
23
+ }
24
+
25
+ &:disabled {
26
+ opacity: 0.5;
27
+ cursor: wait;
28
+ }
29
+ }
30
+ .ridu-logout__error {
31
+ color: var(--destructive);
32
+ margin: 0;
33
+ }
34
+ }
@@ -0,0 +1,52 @@
1
+ <script lang="ts">
2
+ import LogOutIcon from "~icons/lucide/log-out";
3
+ import { adminRoutePatterns } from "@admin/core/routing/admin-paths";
4
+ import { getAdminRuntime } from "@admin/core/runtime/admin-runtime.svelte";
5
+ import "@admin/features/auth/logout-button.scss";
6
+
7
+ const runtime = getAdminRuntime();
8
+ const replacement = runtime.config.extensions.logoutButton;
9
+ const host = { logout };
10
+
11
+ let pending = $state(false);
12
+ let error = $state<string>();
13
+
14
+ async function logout() {
15
+ if (pending) return;
16
+
17
+ pending = true;
18
+ error = undefined;
19
+
20
+ try {
21
+ await runtime.client.auth.logout();
22
+ await runtime.hardNavigate(adminRoutePatterns.login);
23
+ } catch (cause) {
24
+ error = cause instanceof Error ? cause.message : runtime.i18n.t("account:signOutFailed");
25
+ } finally {
26
+ pending = false;
27
+ }
28
+ }
29
+ </script>
30
+
31
+ {#if replacement !== undefined && runtime.manifest !== undefined}
32
+ <replacement.component
33
+ manifest={runtime.manifest}
34
+ user={runtime.session?.user}
35
+ {host}
36
+ i18n={runtime.i18n}
37
+ />
38
+ {:else}
39
+ <button
40
+ type="button"
41
+ class="ridu-logout"
42
+ disabled={pending}
43
+ onclick={logout}
44
+ aria-label={pending ? runtime.i18n.t("account:signingOut") : runtime.i18n.t("auth:logout")}
45
+ title={runtime.i18n.t("auth:logout")}
46
+ >
47
+ <LogOutIcon aria-hidden="true" />
48
+ </button>
49
+ {/if}
50
+ {#if error !== undefined}
51
+ <p class="ridu-logout__error" role="alert">{error}</p>
52
+ {/if}
@@ -3,14 +3,15 @@
3
3
  import { RiduError } from "@riducms/sdk";
4
4
 
5
5
  import { Banner } from "@admin/components/ui/banner";
6
- import { Button } from "@admin/components/ui/button";
7
- import { Input } from "@admin/components/ui/input";
6
+ import { Button } from "@riducms/ui";
8
7
  import { adminRoutePatterns } from "@admin/core/routing/admin-paths";
9
8
  import { getAdminRuntime } from "@admin/core/runtime/admin-runtime.svelte";
9
+ import AuthField from "@admin/features/auth/auth-field.svelte";
10
10
  import AuthFrame from "@admin/features/auth/auth-frame.svelte";
11
11
 
12
12
  const runtime = getAdminRuntime();
13
13
  const authCollection = $derived(runtime.authCollection);
14
+
14
15
  let email = $state("");
15
16
  let pending = $state(false);
16
17
  let sent = $state(false);
@@ -19,10 +20,12 @@
19
20
  async function submit(event: SubmitEvent) {
20
21
  event.preventDefault();
21
22
  if (authCollection === undefined) return;
23
+
22
24
  pending = true;
23
25
  error = undefined;
26
+
24
27
  try {
25
- await runtime.client.requestVerification(authCollection.slug, email);
28
+ await runtime.client.auth.requestVerification({ collection: authCollection.slug, email });
26
29
  sent = true;
27
30
  } catch (cause) {
28
31
  error =
@@ -36,35 +39,37 @@
36
39
  </script>
37
40
 
38
41
  <AuthFrame>
39
- <div class="grid gap-5">
40
- <h1 class="text-[32px] leading-tight font-medium tracking-[-0.025em] text-foreground">
42
+ <div class="ridu-auth__stack">
43
+ <h1 class="ridu-auth__heading">
41
44
  {runtime.i18n.t("auth:verifyYourEmail")}
42
45
  </h1>
43
46
  {#if sent}
44
47
  <Banner>{runtime.i18n.t("auth:verificationSent")}</Banner>
45
- <Link
46
- class="w-fit text-[12.5px] text-foreground underline underline-offset-2 hover:text-foreground-muted"
47
- to={adminRoutePatterns.login}
48
- >
48
+ <Link class="ridu-auth__link" to={adminRoutePatterns.login}>
49
49
  {runtime.i18n.t("auth:backToLogin")}
50
50
  </Link>
51
51
  {:else}
52
- <form class="grid gap-4" onsubmit={submit}>
53
- <p class="text-[13px] leading-5 text-foreground-muted">
52
+ <form class="ridu-auth__form" onsubmit={submit}>
53
+ <p class="ridu-auth__description">
54
54
  {runtime.i18n.t("auth:verificationDescription")}
55
55
  </p>
56
- <label class="grid gap-2" for="verification-email">
57
- <span class="ridu-field-label">{runtime.i18n.t("auth:email")}</span>
58
- <Input
59
- id="verification-email"
60
- type="email"
61
- autocomplete="email"
62
- bind:value={email}
63
- required
64
- />
65
- </label>
66
- {#if error !== undefined}<Banner tone="destructive">{error}</Banner>{/if}
67
- <Button class="h-10 w-full" type="submit" size="lg" disabled={pending}>
56
+ <AuthField
57
+ disabled={pending}
58
+ id="verification-email"
59
+ label={runtime.i18n.t("auth:email")}
60
+ autocomplete="email"
61
+ bind:value={email}
62
+ />
63
+ {#if error !== undefined}
64
+ <Banner tone="destructive">{error}</Banner>
65
+ {/if}
66
+ <Button
67
+ class="ridu-auth__submit"
68
+ type="submit"
69
+ size="lg"
70
+ disabled={pending}
71
+ aria-busy={pending}
72
+ >
68
73
  {pending ? runtime.i18n.t("auth:sending") : runtime.i18n.t("auth:sendVerificationLink")}
69
74
  </Button>
70
75
  </form>
@@ -1,50 +1,110 @@
1
1
  <script lang="ts">
2
+ import { tick } from "svelte";
2
3
  import { Link, useLocation } from "@hvniel/svelte-router";
3
4
  import { RiduError } from "@riducms/sdk";
4
5
 
5
6
  import { Banner } from "@admin/components/ui/banner";
6
- import { Button } from "@admin/components/ui/button";
7
- import { Input } from "@admin/components/ui/input";
7
+ import { Button } from "@riducms/ui";
8
8
  import { adminRoutePatterns } from "@admin/core/routing/admin-paths";
9
9
  import { getAdminRuntime } from "@admin/core/runtime/admin-runtime.svelte";
10
+ import AuthField from "@admin/features/auth/auth-field.svelte";
10
11
  import AuthFrame from "@admin/features/auth/auth-frame.svelte";
11
12
 
12
13
  const runtime = getAdminRuntime();
13
- const location = $derived(useLocation());
14
- const token = $derived(new URLSearchParams(location.search).get("token") ?? "");
14
+ const location = useLocation();
15
+
16
+ const token = $derived(new URLSearchParams(location.current.search).get("token") ?? "");
15
17
  const authCollection = $derived(runtime.authCollection);
18
+ const owner = $derived(JSON.stringify([authCollection?.id, authCollection?.slug, token]));
19
+
16
20
  let password = $state("");
17
21
  let confirmation = $state("");
18
22
  let pending = $state(false);
19
23
  let complete = $state(false);
20
24
  let error = $state<string>();
25
+ let confirmationError = $state<string>();
26
+ let passwordErrors = $state<string[]>([]);
27
+ let request: AbortController | undefined;
28
+ let ownerGeneration = 0;
29
+
30
+ $effect.pre(() => {
31
+ // A retained route must clear credentials and outcomes before rendering a new token owner.
32
+ owner;
33
+ password = "";
34
+ confirmation = "";
35
+ pending = false;
36
+ complete = false;
37
+ error = undefined;
38
+ confirmationError = undefined;
39
+ passwordErrors = [];
40
+ return () => {
41
+ ownerGeneration += 1;
42
+ request?.abort();
43
+ request = undefined;
44
+ };
45
+ });
21
46
 
22
47
  async function submit(event: SubmitEvent) {
23
48
  event.preventDefault();
24
- if (authCollection === undefined || token === "") return;
49
+ if (authCollection === undefined || token === "" || pending || complete) return;
50
+ const generation = ownerGeneration;
51
+ const requestOwner = owner;
52
+
53
+ error = undefined;
54
+ passwordErrors = [];
55
+ confirmationError = undefined;
25
56
  if (password !== confirmation) {
26
- error = runtime.i18n.t("auth:passwordMismatch");
57
+ confirmationError = runtime.i18n.t("auth:passwordMismatch");
58
+ await tick();
59
+ if (generation === ownerGeneration && requestOwner === owner)
60
+ document.getElementById("reset-confirm")?.focus();
27
61
  return;
28
62
  }
63
+
64
+ const activeRequest = new AbortController();
65
+ request = activeRequest;
66
+ const current = () => request === activeRequest && requestOwner === owner;
29
67
  pending = true;
30
- error = undefined;
68
+
31
69
  try {
32
- await runtime.client.resetPassword(authCollection.slug, token, password);
70
+ await runtime.client.auth.resetPassword(
71
+ { collection: authCollection.slug, token, password },
72
+ {
73
+ signal: activeRequest.signal,
74
+ }
75
+ );
76
+ if (!current()) return;
33
77
  complete = true;
34
78
  password = "";
35
79
  confirmation = "";
36
80
  } catch (cause) {
37
- error =
38
- cause instanceof RiduError ? cause.message : runtime.i18n.t("auth:passwordResetFailed");
81
+ if (!current()) return;
82
+ if (cause instanceof RiduError) {
83
+ passwordErrors = cause.issues
84
+ .filter((issue) => issue.path === "password")
85
+ .map((issue) => issue.message);
86
+ }
87
+
88
+ if (passwordErrors.length === 0) {
89
+ error =
90
+ cause instanceof RiduError ? cause.message : runtime.i18n.t("auth:passwordResetFailed");
91
+ }
39
92
  } finally {
40
- pending = false;
93
+ if (current()) {
94
+ pending = false;
95
+ if (passwordErrors.length > 0) {
96
+ await tick();
97
+ if (current()) document.getElementById("reset-password")?.focus();
98
+ }
99
+ if (request === activeRequest) request = undefined;
100
+ }
41
101
  }
42
102
  }
43
103
  </script>
44
104
 
45
105
  <AuthFrame>
46
- <div class="grid gap-5">
47
- <h1 class="text-[32px] leading-tight font-medium tracking-[-0.025em] text-foreground">
106
+ <div class="ridu-auth__stack">
107
+ <h1 class="ridu-auth__heading">
48
108
  {runtime.i18n.t("auth:chooseNewPassword")}
49
109
  </h1>
50
110
  {const terminalState = $derived(
@@ -66,37 +126,47 @@
66
126
 
67
127
  {#if terminalState !== undefined}
68
128
  <Banner tone={terminalState.tone}>{terminalState.message}</Banner>
69
- <Link
70
- class="w-fit text-[12.5px] text-foreground underline underline-offset-2 hover:text-foreground-muted"
71
- to={terminalState.to}
72
- >
129
+ <Link class="ridu-auth__link" to={terminalState.to}>
73
130
  {terminalState.action}
74
131
  </Link>
75
132
  {:else}
76
- <form class="grid gap-4" onsubmit={submit}>
77
- <label class="grid gap-2" for="reset-password">
78
- <span class="ridu-field-label">{runtime.i18n.t("account:newPassword")}</span>
79
- <Input
80
- id="reset-password"
81
- type="password"
82
- autocomplete="new-password"
83
- minlength={authCollection?.authSettings?.passwordMinLength ?? 8}
84
- bind:value={password}
85
- required
86
- />
87
- </label>
88
- <label class="grid gap-2" for="reset-confirm">
89
- <span class="ridu-field-label">{runtime.i18n.t("auth:confirmPassword")}</span>
90
- <Input
91
- id="reset-confirm"
92
- type="password"
93
- autocomplete="new-password"
94
- bind:value={confirmation}
95
- required
96
- />
97
- </label>
98
- {#if error !== undefined}<Banner tone="destructive">{error}</Banner>{/if}
99
- <Button class="h-10 w-full" type="submit" size="lg" disabled={pending}>
133
+ <form class="ridu-auth__form" onsubmit={submit}>
134
+ <AuthField
135
+ disabled={pending}
136
+ id="reset-password"
137
+ label={runtime.i18n.t("account:newPassword")}
138
+ type="password"
139
+ autocomplete="new-password"
140
+ minlength={authCollection?.authSettings?.passwordMinLength ?? 8}
141
+ bind:value={password}
142
+ errors={passwordErrors}
143
+ oninput={() => {
144
+ passwordErrors = [];
145
+ confirmationError = undefined;
146
+ }}
147
+ />
148
+ <AuthField
149
+ disabled={pending}
150
+ id="reset-confirm"
151
+ label={runtime.i18n.t("auth:confirmPassword")}
152
+ type="password"
153
+ autocomplete="new-password"
154
+ bind:value={confirmation}
155
+ errors={confirmationError === undefined ? [] : [confirmationError]}
156
+ oninput={() => (confirmationError = undefined)}
157
+ showLabel={runtime.i18n.t("auth:showPasswordConfirmation")}
158
+ hideLabel={runtime.i18n.t("auth:hidePasswordConfirmation")}
159
+ />
160
+ {#if error !== undefined}
161
+ <Banner tone="destructive">{error}</Banner>
162
+ {/if}
163
+ <Button
164
+ class="ridu-auth__submit"
165
+ type="submit"
166
+ size="lg"
167
+ disabled={pending}
168
+ aria-busy={pending}
169
+ >
100
170
  {pending
101
171
  ? runtime.i18n.t("auth:resettingPassword")
102
172
  : runtime.i18n.t("auth:resetPassword")}