includio-cms 0.1.4 → 0.5.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 (296) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/ROADMAP.md +18 -13
  3. package/dist/admin/api/accept-invite.js +1 -5
  4. package/dist/admin/api/invite.js +7 -16
  5. package/dist/admin/client/account/account-page.svelte +20 -50
  6. package/dist/admin/client/account/lang.d.ts +15 -23
  7. package/dist/admin/client/account/lang.js +51 -67
  8. package/dist/admin/client/account/preferences-section.svelte +26 -84
  9. package/dist/admin/client/account/profile-section.svelte +60 -40
  10. package/dist/admin/client/account/schema.d.ts +11 -3
  11. package/dist/admin/client/account/schema.js +25 -16
  12. package/dist/admin/client/account/security-section.svelte +139 -105
  13. package/dist/admin/client/account/sessions-section.svelte +35 -34
  14. package/dist/admin/client/admin/admin-after-login-layout-content.svelte +3 -5
  15. package/dist/admin/client/admin/admin-layout.svelte +3 -2
  16. package/dist/admin/client/admin/admin-preloader.svelte +36 -0
  17. package/dist/admin/client/admin/admin-preloader.svelte.d.ts +18 -0
  18. package/dist/admin/client/admin/dashboard-page.svelte +55 -41
  19. package/dist/admin/client/collection/a11y-score-cell.svelte +45 -0
  20. package/dist/admin/client/collection/a11y-score-cell.svelte.d.ts +6 -0
  21. package/dist/admin/client/collection/bulk-actions-bar.svelte +83 -0
  22. package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +9 -0
  23. package/dist/admin/client/collection/collection-entries.svelte +255 -260
  24. package/dist/admin/client/collection/collection-view.svelte.d.ts +4 -3
  25. package/dist/admin/client/collection/collection-view.svelte.js +9 -5
  26. package/dist/admin/client/collection/collection.svelte +22 -12
  27. package/dist/admin/client/collection/data-table.svelte +50 -39
  28. package/dist/admin/client/collection/data-table.svelte.d.ts +1 -0
  29. package/dist/admin/client/collection/date-cell.svelte +7 -5
  30. package/dist/admin/client/collection/date-cell.svelte.d.ts +1 -1
  31. package/dist/admin/client/collection/empty-state.svelte +28 -0
  32. package/dist/admin/client/collection/empty-state.svelte.d.ts +9 -0
  33. package/dist/admin/client/collection/entry-link.svelte +10 -4
  34. package/dist/admin/client/collection/entry-link.svelte.d.ts +1 -0
  35. package/dist/admin/client/collection/grid-view.svelte +21 -23
  36. package/dist/admin/client/collection/grid-view.svelte.d.ts +1 -2
  37. package/dist/admin/client/collection/row-actions.svelte +60 -0
  38. package/dist/admin/client/collection/row-actions.svelte.d.ts +9 -0
  39. package/dist/admin/client/collection/status-badge.svelte +7 -8
  40. package/dist/admin/client/collection/table-pagination.svelte +122 -79
  41. package/dist/admin/client/collection/table-pagination.svelte.d.ts +1 -0
  42. package/dist/admin/client/collection/table-toolbar.svelte +108 -88
  43. package/dist/admin/client/collection/table-toolbar.svelte.d.ts +8 -9
  44. package/dist/admin/client/entry/entry-form.svelte +109 -1
  45. package/dist/admin/client/entry/entry-header.svelte +96 -37
  46. package/dist/admin/client/entry/entry-header.svelte.d.ts +5 -0
  47. package/dist/admin/client/entry/entry.svelte +171 -60
  48. package/dist/admin/client/entry/header/a11y-validator.d.ts +46 -0
  49. package/dist/admin/client/entry/header/a11y-validator.js +311 -0
  50. package/dist/admin/client/entry/header/publish-panel.svelte +373 -131
  51. package/dist/admin/client/entry/header/publish-panel.svelte.d.ts +4 -0
  52. package/dist/admin/client/entry/header/save-indicator.svelte +33 -23
  53. package/dist/admin/client/entry/header/schedule-popover.svelte +1 -1
  54. package/dist/admin/client/entry/header/status-badge.svelte +25 -118
  55. package/dist/admin/client/entry/header/version-history-sheet.svelte +314 -98
  56. package/dist/admin/client/form/form-submission/form-submission.svelte +271 -83
  57. package/dist/admin/client/form/form-submission/submission-field.svelte +12 -12
  58. package/dist/admin/client/form/form-submissions.svelte +421 -139
  59. package/dist/admin/client/form/submission-link.svelte +8 -2
  60. package/dist/admin/client/form/submission-link.svelte.d.ts +1 -0
  61. package/dist/admin/client/form/submission-status-badge.svelte +18 -4
  62. package/dist/admin/client/form/submission-status-badge.svelte.d.ts +1 -0
  63. package/dist/admin/client/login/lang.d.ts +32 -0
  64. package/dist/admin/client/login/lang.js +66 -2
  65. package/dist/admin/client/login/login-form.svelte +237 -95
  66. package/dist/admin/client/login/login-form.svelte.d.ts +2 -17
  67. package/dist/admin/client/login/login-page.svelte +34 -98
  68. package/dist/admin/client/login/reset-password-page.svelte +235 -0
  69. package/dist/admin/client/login/reset-password-page.svelte.d.ts +4 -0
  70. package/dist/admin/client/login/schema.d.ts +15 -0
  71. package/dist/admin/client/login/schema.js +21 -0
  72. package/dist/admin/client/users/accept-invite-page.svelte +166 -37
  73. package/dist/admin/client/users/create-user-dialog.svelte +15 -7
  74. package/dist/admin/client/users/delete-user-dialog.svelte +81 -16
  75. package/dist/admin/client/users/delete-user-dialog.svelte.d.ts +4 -1
  76. package/dist/admin/client/users/edit-user-dialog.svelte +3 -0
  77. package/dist/admin/client/users/invite-user-dialog.svelte +16 -3
  78. package/dist/admin/client/users/lang.d.ts +27 -0
  79. package/dist/admin/client/users/lang.js +64 -10
  80. package/dist/admin/client/users/pending-invitations.svelte +59 -23
  81. package/dist/admin/client/users/users-page.svelte +471 -72
  82. package/dist/admin/components/accessibility/accessibility-overview.svelte +2 -7
  83. package/dist/admin/components/dashboard/a11y-gauge.svelte +90 -0
  84. package/dist/admin/components/dashboard/a11y-gauge.svelte.d.ts +18 -0
  85. package/dist/admin/components/dashboard/accessibility-hub.svelte +13 -12
  86. package/dist/admin/components/dashboard/form-submissions-widget.svelte +71 -113
  87. package/dist/admin/components/dashboard/index.d.ts +4 -2
  88. package/dist/admin/components/dashboard/index.js +4 -2
  89. package/dist/admin/components/dashboard/recent-activity.svelte +53 -75
  90. package/dist/admin/components/dashboard/recent-entries.svelte +94 -0
  91. package/dist/admin/components/dashboard/recent-entries.svelte.d.ts +18 -0
  92. package/dist/admin/components/dashboard/stat-card.svelte +2 -2
  93. package/dist/admin/components/dashboard/tip-of-the-day.svelte +109 -0
  94. package/dist/admin/components/dashboard/tip-of-the-day.svelte.d.ts +3 -0
  95. package/dist/admin/components/dashboard/welcome-header.svelte +45 -0
  96. package/dist/admin/components/dashboard/welcome-header.svelte.d.ts +3 -0
  97. package/dist/admin/components/fields/{array-field.svelte → blocks-field.svelte} +4 -4
  98. package/dist/admin/components/fields/{array-field.svelte.d.ts → blocks-field.svelte.d.ts} +5 -5
  99. package/dist/admin/components/fields/content-field.svelte +27 -0
  100. package/dist/admin/components/fields/content-field.svelte.d.ts +31 -0
  101. package/dist/admin/components/fields/field-renderer.svelte +9 -7
  102. package/dist/admin/components/fields/image-field.svelte +2 -2
  103. package/dist/admin/components/fields/media-field.svelte +2 -2
  104. package/dist/admin/components/fields/seo-field.svelte +205 -25
  105. package/dist/admin/components/fields/simple-array-field.svelte +289 -0
  106. package/dist/admin/components/fields/simple-array-field.svelte.d.ts +30 -0
  107. package/dist/admin/components/fields/slug-field.svelte +3 -2
  108. package/dist/admin/components/fields/standalone-field-renderer.svelte +148 -0
  109. package/dist/admin/components/fields/standalone-field-renderer.svelte.d.ts +9 -0
  110. package/dist/admin/components/fields/text-field-wrapper.svelte +13 -1
  111. package/dist/admin/components/fields/text-field-wrapper.svelte.d.ts +2 -2
  112. package/dist/admin/components/fields/url-field.svelte +5 -4
  113. package/dist/admin/components/layout/app-sidebar.svelte +27 -24
  114. package/dist/admin/components/layout/lang.d.ts +6 -0
  115. package/dist/admin/components/layout/lang.js +13 -1
  116. package/dist/admin/components/layout/layout-renderer.svelte +352 -0
  117. package/dist/admin/components/layout/layout-renderer.svelte.d.ts +14 -0
  118. package/dist/admin/components/layout/nav-breadcrumbs.svelte +4 -4
  119. package/dist/admin/components/layout/nav-collections.svelte +65 -36
  120. package/dist/admin/components/layout/nav-footer.svelte +31 -0
  121. package/dist/admin/components/layout/nav-footer.svelte.d.ts +18 -0
  122. package/dist/admin/components/layout/nav-forms.svelte +55 -30
  123. package/dist/admin/components/layout/nav-main.svelte +14 -52
  124. package/dist/admin/components/layout/nav-search.svelte +4 -3
  125. package/dist/admin/components/layout/nav-singletons.svelte +59 -17
  126. package/dist/admin/components/layout/nav-singletons.svelte.d.ts +17 -8
  127. package/dist/admin/components/layout/site-header.svelte +74 -13
  128. package/dist/admin/components/media/alt-input.svelte +32 -22
  129. package/dist/admin/components/media/bulk-action-bar.svelte +139 -150
  130. package/dist/admin/components/media/file/file-details.svelte +299 -217
  131. package/dist/admin/components/media/file/file-miniature.svelte +54 -41
  132. package/dist/admin/components/media/file/file-miniature.svelte.d.ts +1 -0
  133. package/dist/admin/components/media/file/file-preview.svelte +1 -1
  134. package/dist/admin/components/media/file-upload.svelte +24 -26
  135. package/dist/admin/components/media/files-list.svelte +112 -40
  136. package/dist/admin/components/media/files-list.svelte.d.ts +2 -0
  137. package/dist/admin/components/media/focal-point-input.svelte +122 -26
  138. package/dist/admin/components/media/media-library.svelte +127 -70
  139. package/dist/admin/components/media/media-search.svelte +6 -6
  140. package/dist/admin/components/media/media-sort.svelte +3 -1
  141. package/dist/admin/components/media/multi-file-summary.svelte +88 -68
  142. package/dist/admin/components/media/tag-combobox.svelte +141 -66
  143. package/dist/admin/components/media/tag-combobox.svelte.d.ts +1 -0
  144. package/dist/admin/components/media/tag-sidebar.svelte +139 -121
  145. package/dist/admin/components/tiptap/FigureNodeView.svelte +144 -15
  146. package/dist/admin/components/tiptap/InlineBlockNodeView.svelte +254 -0
  147. package/dist/admin/components/tiptap/InlineBlockNodeView.svelte.d.ts +4 -0
  148. package/dist/admin/components/tiptap/SlashCommandPopup.svelte +212 -0
  149. package/dist/admin/components/tiptap/SlashCommandPopup.svelte.d.ts +8 -0
  150. package/dist/admin/components/tiptap/content-editor.svelte +280 -0
  151. package/dist/admin/components/tiptap/content-editor.svelte.d.ts +9 -0
  152. package/dist/admin/components/tiptap/editor-toolbar.svelte +230 -0
  153. package/dist/admin/components/tiptap/editor-toolbar.svelte.d.ts +16 -0
  154. package/dist/admin/components/tiptap/heading-a11y-plugin.d.ts +2 -0
  155. package/dist/admin/components/tiptap/heading-a11y-plugin.js +67 -0
  156. package/dist/admin/components/tiptap/image-dialog.svelte +172 -11
  157. package/dist/admin/components/tiptap/inline-block-node.d.ts +19 -0
  158. package/dist/admin/components/tiptap/inline-block-node.js +98 -0
  159. package/dist/admin/components/tiptap/link-dialog.svelte +9 -4
  160. package/dist/admin/components/tiptap/slash-command.d.ts +17 -0
  161. package/dist/admin/components/tiptap/slash-command.js +181 -0
  162. package/dist/admin/components/tiptap/structured-content-utils.d.ts +21 -0
  163. package/dist/admin/components/tiptap/structured-content-utils.js +150 -0
  164. package/dist/admin/components/tiptap/tiptap-editor.svelte +18 -190
  165. package/dist/admin/email/invite-template.d.ts +8 -0
  166. package/dist/admin/email/invite-template.js +99 -0
  167. package/dist/admin/email/reset-password-template.d.ts +7 -0
  168. package/dist/admin/email/reset-password-template.js +96 -0
  169. package/dist/admin/remote/ai.remote.d.ts +1 -0
  170. package/dist/admin/remote/ai.remote.js +4 -1
  171. package/dist/admin/remote/entry.remote.d.ts +8 -0
  172. package/dist/admin/remote/entry.remote.js +53 -4
  173. package/dist/admin/remote/preview.remote.js +2 -1
  174. package/dist/admin/shared/password-schema.d.ts +5 -0
  175. package/dist/admin/shared/password-schema.js +10 -0
  176. package/dist/admin/styles/admin.css +1530 -151
  177. package/dist/admin/utils/formatDate.d.ts +1 -0
  178. package/dist/admin/utils/formatDate.js +8 -0
  179. package/dist/admin/utils/roleLabel.d.ts +2 -0
  180. package/dist/admin/utils/roleLabel.js +13 -0
  181. package/dist/ai-claude/index.d.ts +2 -0
  182. package/dist/ai-claude/index.js +56 -0
  183. package/dist/cms/runtime/api.d.ts +6 -1
  184. package/dist/cms/runtime/api.js +3 -0
  185. package/dist/cms/runtime/schemas.d.ts +9 -1
  186. package/dist/cms/runtime/schemas.js +8 -0
  187. package/dist/cms/runtime/types.d.ts +82 -10
  188. package/dist/cms/runtime/types.js +4 -0
  189. package/dist/components/ui/accordion/accordion.stories.svelte +39 -0
  190. package/dist/components/ui/accordion/accordion.stories.svelte.d.ts +27 -0
  191. package/dist/components/ui/alert/alert.stories.svelte +53 -0
  192. package/dist/components/ui/alert/alert.stories.svelte.d.ts +27 -0
  193. package/dist/components/ui/alert/alert.svelte +5 -0
  194. package/dist/components/ui/alert/alert.svelte.d.ts +9 -0
  195. package/dist/components/ui/avatar/avatar.stories.svelte +16 -0
  196. package/dist/components/ui/avatar/avatar.stories.svelte.d.ts +27 -0
  197. package/dist/components/ui/badge/badge.stories.svelte +33 -0
  198. package/dist/components/ui/badge/badge.stories.svelte.d.ts +27 -0
  199. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte +33 -0
  200. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte.d.ts +27 -0
  201. package/dist/components/ui/button/button.stories.svelte +43 -0
  202. package/dist/components/ui/button/button.stories.svelte.d.ts +27 -0
  203. package/dist/components/ui/button/button.svelte +1 -2
  204. package/dist/components/ui/button/button.svelte.d.ts +0 -3
  205. package/dist/components/ui/button-group/button-group-separator.svelte.d.ts +1 -1
  206. package/dist/components/ui/card/card.stories.svelte +42 -0
  207. package/dist/components/ui/card/card.stories.svelte.d.ts +27 -0
  208. package/dist/components/ui/command/command.stories.svelte +51 -0
  209. package/dist/components/ui/command/command.stories.svelte.d.ts +27 -0
  210. package/dist/components/ui/dialog/dialog.stories.svelte +29 -0
  211. package/dist/components/ui/dialog/dialog.stories.svelte.d.ts +27 -0
  212. package/dist/components/ui/field/field-label.svelte.d.ts +1 -1
  213. package/dist/components/ui/field/field.stories.svelte +21 -0
  214. package/dist/components/ui/field/field.stories.svelte.d.ts +27 -0
  215. package/dist/components/ui/input/input.stories.svelte +40 -0
  216. package/dist/components/ui/input/input.stories.svelte.d.ts +27 -0
  217. package/dist/components/ui/input/input.svelte +2 -4
  218. package/dist/components/ui/item/item-separator.svelte.d.ts +1 -1
  219. package/dist/components/ui/label/label.stories.svelte +20 -0
  220. package/dist/components/ui/label/label.stories.svelte.d.ts +27 -0
  221. package/dist/components/ui/popover/popover.stories.svelte +29 -0
  222. package/dist/components/ui/popover/popover.stories.svelte.d.ts +27 -0
  223. package/dist/components/ui/select/select-group-heading.svelte.d.ts +1 -1
  224. package/dist/components/ui/select/select.stories.svelte +23 -0
  225. package/dist/components/ui/select/select.stories.svelte.d.ts +27 -0
  226. package/dist/components/ui/separator/separator.stories.svelte +24 -0
  227. package/dist/components/ui/separator/separator.stories.svelte.d.ts +27 -0
  228. package/dist/components/ui/sheet/sheet.stories.svelte +29 -0
  229. package/dist/components/ui/sheet/sheet.stories.svelte.d.ts +27 -0
  230. package/dist/components/ui/sidebar/sidebar-group.svelte +3 -3
  231. package/dist/components/ui/sidebar/sidebar-group.svelte.d.ts +2 -2
  232. package/dist/components/ui/sidebar/sidebar-menu-button.svelte +28 -30
  233. package/dist/components/ui/sidebar/sidebar-menu-button.svelte.d.ts +7 -7
  234. package/dist/components/ui/sidebar/sidebar-separator.svelte.d.ts +1 -1
  235. package/dist/components/ui/sidebar/sidebar-trigger.svelte +4 -4
  236. package/dist/components/ui/sonner/sonner.stories.svelte +22 -0
  237. package/dist/components/ui/sonner/sonner.stories.svelte.d.ts +26 -0
  238. package/dist/components/ui/sonner/sonner.svelte +8 -2
  239. package/dist/components/ui/sonner/toast-demo.svelte +29 -0
  240. package/dist/components/ui/sonner/toast-demo.svelte.d.ts +6 -0
  241. package/dist/components/ui/textarea/textarea.stories.svelte +22 -0
  242. package/dist/components/ui/textarea/textarea.stories.svelte.d.ts +27 -0
  243. package/dist/components/ui/textarea/textarea.svelte +0 -2
  244. package/dist/components/ui/toggle/toggle.stories.svelte +22 -0
  245. package/dist/components/ui/toggle/toggle.stories.svelte.d.ts +27 -0
  246. package/dist/components/ui/toggle-group/toggle-group.stories.svelte +17 -0
  247. package/dist/components/ui/toggle-group/toggle-group.stories.svelte.d.ts +27 -0
  248. package/dist/components/ui/tooltip/tooltip.stories.svelte +26 -0
  249. package/dist/components/ui/tooltip/tooltip.stories.svelte.d.ts +27 -0
  250. package/dist/core/fields/fieldSchemaToTs.d.ts +1 -0
  251. package/dist/core/fields/fieldSchemaToTs.js +133 -1
  252. package/dist/core/fields/layoutUtils.d.ts +17 -0
  253. package/dist/core/fields/layoutUtils.js +149 -0
  254. package/dist/core/fields/structuredToHtml.d.ts +9 -0
  255. package/dist/core/fields/structuredToHtml.js +161 -0
  256. package/dist/core/server/entries/operations/create.js +2 -1
  257. package/dist/core/server/entries/operations/get.js +8 -6
  258. package/dist/core/server/entries/operations/update.d.ts +3 -0
  259. package/dist/core/server/entries/operations/update.js +30 -2
  260. package/dist/core/server/fields/queryStructuredContent.d.ts +15 -0
  261. package/dist/core/server/fields/queryStructuredContent.js +65 -0
  262. package/dist/core/server/fields/resolveImageFields.js +51 -2
  263. package/dist/core/server/fields/resolveRelationFields.js +2 -2
  264. package/dist/core/server/fields/resolveRichtextLinks.js +80 -13
  265. package/dist/core/server/fields/resolveUrlFields.js +57 -6
  266. package/dist/core/server/fields/slugResolver.d.ts +10 -0
  267. package/dist/core/server/fields/slugResolver.js +34 -0
  268. package/dist/core/server/generator/fields.js +15 -4
  269. package/dist/core/server/generator/generator.js +3 -2
  270. package/dist/files-local/index.js +126 -64
  271. package/dist/server/auth.d.ts +5 -0
  272. package/dist/server/auth.js +12 -1
  273. package/dist/sveltekit/components/structured-content.svelte +204 -0
  274. package/dist/sveltekit/components/structured-content.svelte.d.ts +21 -0
  275. package/dist/sveltekit/config.d.ts +13 -3
  276. package/dist/sveltekit/index.d.ts +3 -0
  277. package/dist/sveltekit/index.js +3 -0
  278. package/dist/sveltekit/server/handle.js +1 -0
  279. package/dist/types/config.d.ts +3 -0
  280. package/dist/types/fields.d.ts +19 -2
  281. package/dist/types/index.d.ts +2 -0
  282. package/dist/types/index.js +2 -0
  283. package/dist/types/layout.d.ts +54 -0
  284. package/dist/types/layout.js +6 -0
  285. package/dist/types/structured-content.d.ts +63 -0
  286. package/dist/types/structured-content.js +1 -0
  287. package/dist/updates/0.1.5/index.d.ts +2 -0
  288. package/dist/updates/0.1.5/index.js +18 -0
  289. package/dist/updates/0.2.0/index.d.ts +2 -0
  290. package/dist/updates/0.2.0/index.js +11 -0
  291. package/dist/updates/0.2.2/index.d.ts +2 -0
  292. package/dist/updates/0.2.2/index.js +13 -0
  293. package/dist/updates/0.5.0/index.d.ts +2 -0
  294. package/dist/updates/0.5.0/index.js +14 -0
  295. package/dist/updates/index.js +5 -1
  296. package/package.json +16 -9
@@ -3,11 +3,17 @@
3
3
  name: string;
4
4
  url: string;
5
5
  isRead?: boolean;
6
+ onclick?: (e: MouseEvent) => void;
6
7
  };
7
8
 
8
- let { name, url, isRead = true }: Props = $props();
9
+ let { name, url, isRead = true, onclick }: Props = $props();
9
10
  </script>
10
11
 
11
- <a href={url} class="hover:underline" class:font-semibold={!isRead}>
12
+ <a
13
+ href={url}
14
+ class="hover:underline"
15
+ class:font-semibold={!isRead}
16
+ onclick={onclick}
17
+ >
12
18
  {name}
13
19
  </a>
@@ -2,6 +2,7 @@ type Props = {
2
2
  name: string;
3
3
  url: string;
4
4
  isRead?: boolean;
5
+ onclick?: (e: MouseEvent) => void;
5
6
  };
6
7
  declare const SubmissionLink: import("svelte").Component<Props, {}, "">;
7
8
  type SubmissionLink = ReturnType<typeof SubmissionLink>;
@@ -4,9 +4,10 @@
4
4
 
5
5
  type Props = {
6
6
  isRead: boolean;
7
+ variant?: 'badge' | 'dot';
7
8
  };
8
9
 
9
- let { isRead }: Props = $props();
10
+ let { isRead, variant = 'badge' }: Props = $props();
10
11
 
11
12
  const interfaceLanguage = useInterfaceLanguage();
12
13
 
@@ -16,12 +17,25 @@
16
17
  };
17
18
  </script>
18
19
 
19
- {#if isRead}
20
- <span class="inline-flex items-center rounded-full bg-slate-100 px-2 py-0.5 text-xs font-medium text-slate-600 dark:bg-slate-800 dark:text-slate-300">
20
+ {#if variant === 'dot'}
21
+ {#if !isRead}
22
+ <span
23
+ class="bg-primary inline-block size-2 rounded-full"
24
+ aria-label={lang[interfaceLanguage.current].new}
25
+ ></span>
26
+ {:else}
27
+ <span class="inline-block size-2" aria-label={lang[interfaceLanguage.current].read}></span>
28
+ {/if}
29
+ {:else if isRead}
30
+ <span
31
+ class="bg-muted text-muted-foreground inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium"
32
+ >
21
33
  {lang[interfaceLanguage.current].read}
22
34
  </span>
23
35
  {:else}
24
- <span class="inline-flex items-center rounded-full bg-blue-100 px-2 py-0.5 text-xs font-medium text-blue-700 dark:bg-blue-900/30 dark:text-blue-400">
36
+ <span
37
+ class="inline-flex items-center rounded-full bg-blue-100 px-2 py-0.5 text-xs font-medium text-blue-700 dark:bg-blue-900/30 dark:text-blue-400"
38
+ >
25
39
  {lang[interfaceLanguage.current].new}
26
40
  </span>
27
41
  {/if}
@@ -1,5 +1,6 @@
1
1
  type Props = {
2
2
  isRead: boolean;
3
+ variant?: 'badge' | 'dot';
3
4
  };
4
5
  declare const SubmissionStatusBadge: import("svelte").Component<Props, {}, "">;
5
6
  type SubmissionStatusBadge = ReturnType<typeof SubmissionStatusBadge>;
@@ -5,5 +5,37 @@ export declare const loginLang: Record<string, {
5
5
  email: string;
6
6
  password: string;
7
7
  login_button: string;
8
+ tagline: string;
9
+ forgot_password: string;
10
+ footer_credit: string;
11
+ skip_to_content: string;
12
+ form_label: string;
13
+ login_error: string;
14
+ login_success: string;
15
+ };
16
+ forgot: {
17
+ heading: string;
18
+ description: string;
19
+ send_link: string;
20
+ back_to_login: string;
21
+ sent_heading: string;
22
+ sent_description: string;
23
+ email_not_configured: string;
24
+ form_label: string;
25
+ };
26
+ reset: {
27
+ heading: string;
28
+ description: string;
29
+ new_password: string;
30
+ confirm_password: string;
31
+ submit: string;
32
+ success: string;
33
+ go_to_login: string;
34
+ invalid_link: string;
35
+ password_mismatch: string;
36
+ form_label: string;
37
+ passwordHint: string;
38
+ passwordMinLength: string;
39
+ passwordRequirements: string;
8
40
  };
9
41
  }>;
@@ -5,7 +5,39 @@ export const loginLang = {
5
5
  please_login: 'Zaloguj się na swoje konto',
6
6
  email: 'Adres e-mail',
7
7
  password: 'Hasło',
8
- login_button: 'Zaloguj się'
8
+ login_button: 'Zaloguj się',
9
+ tagline: 'Treści dostępne dla każdego',
10
+ forgot_password: 'Nie pamiętasz hasła?',
11
+ footer_credit: 'Stworzone przez Includio',
12
+ skip_to_content: 'Przejdź do treści',
13
+ form_label: 'Logowanie',
14
+ login_error: 'Nieprawidłowy e-mail lub hasło. Spróbuj ponownie.',
15
+ login_success: 'Zalogowano pomyślnie'
16
+ },
17
+ forgot: {
18
+ heading: 'Przypomnij hasło',
19
+ description: 'Podaj adres e-mail, a wyślemy Ci link do zmiany hasła.',
20
+ send_link: 'Wyślij link',
21
+ back_to_login: 'Wróć do logowania',
22
+ sent_heading: 'Sprawdź skrzynkę',
23
+ sent_description: 'Jeśli konto z tym adresem istnieje, wysłaliśmy link do zmiany hasła.',
24
+ email_not_configured: 'Wysyłka e-maili nie jest skonfigurowana. Skontaktuj się z administratorem.',
25
+ form_label: 'Przypomnienie hasła'
26
+ },
27
+ reset: {
28
+ heading: 'Ustaw nowe hasło',
29
+ description: 'Wpisz nowe hasło do swojego konta.',
30
+ new_password: 'Nowe hasło',
31
+ confirm_password: 'Potwierdź hasło',
32
+ submit: 'Zmień hasło',
33
+ success: 'Hasło zostało zmienione.',
34
+ go_to_login: 'Przejdź do logowania',
35
+ invalid_link: 'Nieprawidłowy lub wygasły link. Spróbuj ponownie.',
36
+ password_mismatch: 'Hasła nie są takie same.',
37
+ form_label: 'Zmiana hasła',
38
+ passwordHint: 'Min. 8 znaków, wielka litera, cyfra i znak specjalny',
39
+ passwordMinLength: 'Hasło musi mieć min. 8 znaków',
40
+ passwordRequirements: 'Hasło musi zawierać wielką literę, cyfrę i znak specjalny'
9
41
  }
10
42
  },
11
43
  en: {
@@ -14,7 +46,39 @@ export const loginLang = {
14
46
  please_login: 'Login to your account',
15
47
  email: 'Email Address',
16
48
  password: 'Password',
17
- login_button: 'Login'
49
+ login_button: 'Login',
50
+ tagline: 'Content accessible to everyone',
51
+ forgot_password: 'Forgot your password?',
52
+ footer_credit: 'Created by Includio',
53
+ skip_to_content: 'Skip to content',
54
+ form_label: 'Login',
55
+ login_error: 'Invalid email or password. Please try again.',
56
+ login_success: 'Logged in successfully'
57
+ },
58
+ forgot: {
59
+ heading: 'Forgot password',
60
+ description: "Enter your email and we'll send you a link to reset your password.",
61
+ send_link: 'Send reset link',
62
+ back_to_login: 'Back to login',
63
+ sent_heading: 'Check your inbox',
64
+ sent_description: "If an account with that email exists, we've sent a password reset link.",
65
+ email_not_configured: 'Email sending is not configured. Contact your administrator.',
66
+ form_label: 'Forgot password'
67
+ },
68
+ reset: {
69
+ heading: 'Set new password',
70
+ description: 'Enter a new password for your account.',
71
+ new_password: 'New password',
72
+ confirm_password: 'Confirm password',
73
+ submit: 'Reset password',
74
+ success: 'Password changed successfully.',
75
+ go_to_login: 'Go to login',
76
+ invalid_link: 'Invalid or expired link. Please try again.',
77
+ password_mismatch: 'Passwords do not match.',
78
+ form_label: 'Reset password',
79
+ passwordHint: 'Min. 8 characters, uppercase, number and special character',
80
+ passwordMinLength: 'Password must be at least 8 characters',
81
+ passwordRequirements: 'Password must contain an uppercase letter, a number and a special character'
18
82
  }
19
83
  }
20
84
  };
@@ -1,36 +1,45 @@
1
1
  <script lang="ts">
2
2
  import * as Form from '../../../components/ui/form/index.js';
3
+ import Input from '../../../components/ui/input/input.svelte';
3
4
 
4
5
  import { defaults, superForm } from 'sveltekit-superforms';
5
6
  import { zod4, zod4Client } from 'sveltekit-superforms/adapters';
6
- import { loginSchema } from './schema.js';
7
+ import { loginSchema, forgotPasswordSchema } from './schema.js';
7
8
  import { toast } from 'svelte-sonner';
8
- import { getRemotes } from '../../context/remotes.js';
9
9
  import { authClient } from '../../auth-client.js';
10
10
  import { loginLang } from './lang.js';
11
11
  import Button from '../../../components/ui/button/button.svelte';
12
12
  import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
13
+ import { goto } from '$app/navigation';
13
14
 
14
- const remotes = getRemotes();
15
15
  let interfaceLanguage = useInterfaceLanguage();
16
16
 
17
- const form = superForm(defaults(zod4(loginSchema)), {
17
+ const lang = () => loginLang[interfaceLanguage.current].login;
18
+ const forgotLang = () => loginLang[interfaceLanguage.current].forgot;
19
+
20
+ let mode: 'login' | 'forgot' | 'forgot-sent' = $state('login');
21
+ let forgotLoading = $state(false);
22
+ let forgotError = $state('');
23
+
24
+ const loginForm = superForm(defaults(zod4(loginSchema)), {
18
25
  validators: zod4Client(loginSchema),
19
26
  SPA: true,
27
+ resetForm: false,
20
28
  onUpdate: async ({ form }) => {
21
29
  if (form.valid) {
22
- const { data, error } = await authClient.signIn.email(
30
+ await authClient.signIn.email(
23
31
  {
24
32
  email: form.data.email,
25
- password: form.data.password,
26
- callbackURL: '/admin'
33
+ password: form.data.password
27
34
  },
28
35
  {
29
- onSuccess: () => {
30
- toast.success('Login successful');
36
+ onSuccess: async () => {
37
+ toast.success(lang().login_success);
38
+ goto('/admin');
31
39
  },
32
- onError: (err) => {
33
- toast.error(`Login failed`);
40
+ onError: async (error) => {
41
+ form.valid = false;
42
+ form.errors.password = [lang().login_error];
34
43
  }
35
44
  }
36
45
  );
@@ -38,99 +47,232 @@
38
47
  }
39
48
  });
40
49
 
41
- const { form: formData, enhance } = form;
50
+ const { form: formData, enhance } = loginForm;
51
+
52
+ const forgotForm = superForm(defaults(zod4(forgotPasswordSchema)), {
53
+ validators: zod4Client(forgotPasswordSchema),
54
+ SPA: true,
55
+ resetForm: false,
56
+ onUpdate: async ({ form }) => {
57
+ if (form.valid) {
58
+ forgotLoading = true;
59
+ forgotError = '';
60
+ const { error } = await authClient.forgetPassword({
61
+ email: form.data.email,
62
+ redirectTo: '/admin/reset-password'
63
+ });
64
+ forgotLoading = false;
65
+
66
+ if (error && error.message?.includes('not enabled')) {
67
+ forgotError = forgotLang().email_not_configured;
68
+ } else {
69
+ // Always show success to avoid email enumeration
70
+ mode = 'forgot-sent';
71
+ }
72
+ }
73
+ }
74
+ });
75
+
76
+ const { form: forgotFormData, enhance: forgotEnhance } = forgotForm;
42
77
  </script>
43
78
 
44
- <form method="POST" use:enhance class="p-8 md:p-12" aria-label="Login form">
45
- <div class="flex flex-col gap-8">
46
- <!-- Logo & Header -->
47
- <div class="flex flex-col items-center text-center">
48
- <!-- Logo -->
49
- <div
50
- class="mb-6 flex h-16 w-16 items-center justify-center rounded-2xl text-white"
51
- style="background: linear-gradient(135deg, #2D4A77 0%, #4975AE 100%);"
52
- aria-hidden="true"
79
+ {#if mode === 'login'}
80
+ <form
81
+ method="POST"
82
+ use:enhance
83
+ aria-label={loginLang[interfaceLanguage.current].login.form_label}
84
+ >
85
+ <div class="flex flex-col gap-5">
86
+ <!-- Brand -->
87
+ <div class="mb-2 flex flex-col items-center text-center">
88
+ <div class="mb-2 flex items-baseline gap-0.5" aria-hidden="true">
89
+ <span
90
+ class="text-primary text-[28px] leading-none font-extrabold max-[480px]:text-[24px]"
91
+ >
92
+ Aria
93
+ </span>
94
+ <span
95
+ class="text-primary text-[16px] leading-none font-light tracking-[0.15em] uppercase max-[480px]:text-[14px]"
96
+ >
97
+ CMS
98
+ </span>
99
+ </div>
100
+ <p class="text-muted-foreground text-[14px]">
101
+ {loginLang[interfaceLanguage.current].login.tagline}
102
+ </p>
103
+ </div>
104
+
105
+ <!-- Email field -->
106
+ <div class="grid gap-2">
107
+ <Form.Field name="email" form={loginForm}>
108
+ <Form.Control>
109
+ {#snippet children({ props })}
110
+ <Form.Label>
111
+ {loginLang[interfaceLanguage.current].login.email}
112
+ </Form.Label>
113
+ <Input
114
+ {...props}
115
+ bind:value={$formData.email}
116
+ autocomplete="email"
117
+ type="email"
118
+ placeholder="m@example.com"
119
+ required
120
+ class="login-input"
121
+ aria-label={loginLang[interfaceLanguage.current].login.email}
122
+ />
123
+ {/snippet}
124
+ </Form.Control>
125
+ <Form.FieldErrors class="text-destructive mt-1 text-sm" />
126
+ </Form.Field>
127
+ </div>
128
+
129
+ <!-- Password field -->
130
+ <div class="grid gap-2">
131
+ <Form.Field name="password" form={loginForm}>
132
+ <Form.Control>
133
+ {#snippet children({ props })}
134
+ <Form.Label>
135
+ {loginLang[interfaceLanguage.current].login.password}
136
+ </Form.Label>
137
+ <Input
138
+ {...props}
139
+ autocomplete="current-password"
140
+ bind:value={$formData.password}
141
+ type="password"
142
+ required
143
+ class="login-input"
144
+ aria-label={loginLang[interfaceLanguage.current].login.password}
145
+ />
146
+ {/snippet}
147
+ </Form.Control>
148
+ <Form.FieldErrors class="text-destructive mt-1 text-sm" />
149
+ </Form.Field>
150
+ </div>
151
+
152
+ <!-- Submit button -->
153
+ <Button
154
+ type="submit"
155
+ class="mt-1 h-11 w-full text-[15px] font-semibold"
156
+ aria-label={loginLang[interfaceLanguage.current].login.login_button}
53
157
  >
54
- <svg
55
- xmlns="http://www.w3.org/2000/svg"
56
- viewBox="0 0 24 24"
57
- fill="none"
58
- stroke="currentColor"
59
- stroke-width="2"
60
- stroke-linecap="round"
61
- stroke-linejoin="round"
62
- class="h-8 w-8"
158
+ {loginLang[interfaceLanguage.current].login.login_button}
159
+ </Button>
160
+
161
+ <!-- Forgot password link -->
162
+ <div class="text-center">
163
+ <button
164
+ type="button"
165
+ onclick={() => (mode = 'forgot')}
166
+ class="text-primary hover:text-plum-dark focus-visible:outline-ring rounded-md px-1 py-0.5 text-[13px] font-medium transition-colors hover:underline focus-visible:outline-2 focus-visible:outline-offset-2"
63
167
  >
64
- <path d="M12 2L2 7l10 5 10-5-10-5z" />
65
- <path d="M2 17l10 5 10-5" />
66
- <path d="M2 12l10 5 10-5" />
67
- </svg>
168
+ {loginLang[interfaceLanguage.current].login.forgot_password}
169
+ </button>
68
170
  </div>
69
-
70
- <h1 class="text-2xl font-bold text-slate-900 dark:text-white">
71
- {loginLang[interfaceLanguage.current].login.hello}
72
- </h1>
73
- <p class="mt-2 text-balance text-slate-600 dark:text-slate-400">
74
- {loginLang[interfaceLanguage.current].login.please_login}
75
- </p>
76
171
  </div>
172
+ </form>
173
+ {:else if mode === 'forgot'}
174
+ <form method="POST" use:forgotEnhance aria-label={forgotLang().form_label}>
175
+ <div class="flex flex-col gap-5">
176
+ <!-- Brand -->
177
+ <div class="mb-2 flex flex-col items-center text-center">
178
+ <div class="mb-2 flex items-baseline gap-0.5" aria-hidden="true">
179
+ <span
180
+ class="text-primary text-[28px] leading-none font-extrabold max-[480px]:text-[24px]"
181
+ >
182
+ Aria
183
+ </span>
184
+ <span
185
+ class="text-primary text-[16px] leading-none font-light tracking-[0.15em] uppercase max-[480px]:text-[14px]"
186
+ >
187
+ CMS
188
+ </span>
189
+ </div>
190
+ </div>
191
+
192
+ <div class="text-center">
193
+ <h2 class="text-foreground text-lg font-semibold">{forgotLang().heading}</h2>
194
+ <p class="text-muted-foreground mt-1 text-[14px]">{forgotLang().description}</p>
195
+ </div>
77
196
 
78
- <!-- Email field -->
79
- <div class="grid gap-2">
80
- <Form.Field name="email" {form}>
81
- <Form.Control>
82
- {#snippet children({ props })}
83
- <Form.Label class="text-sm font-medium text-slate-700 dark:text-slate-300">
84
- {loginLang[interfaceLanguage.current].login.email}
85
- </Form.Label>
86
- <input
87
- {...props}
88
- bind:value={$formData.email}
89
- autocomplete="email"
90
- type="email"
91
- placeholder="m@example.com"
92
- required
93
- aria-label={loginLang[interfaceLanguage.current].login.email}
94
- class="mt-2 w-full rounded-full border border-slate-200 bg-white px-6 py-4 text-slate-900 placeholder-slate-400 transition-all duration-200 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-[#2D4A77] focus:ring-offset-2 dark:border-slate-700 dark:bg-slate-800 dark:text-white dark:placeholder-slate-500 dark:focus:ring-[#4975AE] dark:focus:ring-offset-slate-900"
95
- />
96
- {/snippet}
97
- </Form.Control>
98
- <Form.FieldErrors class="mt-1 text-sm text-red-500" />
99
- </Form.Field>
197
+ <!-- Email field -->
198
+ <div class="grid gap-2">
199
+ <Form.Field name="email" form={forgotForm}>
200
+ <Form.Control>
201
+ {#snippet children({ props })}
202
+ <Form.Label>
203
+ {loginLang[interfaceLanguage.current].login.email}
204
+ </Form.Label>
205
+ <Input
206
+ {...props}
207
+ bind:value={$forgotFormData.email}
208
+ autocomplete="email"
209
+ type="email"
210
+ placeholder="m@example.com"
211
+ required
212
+ class="login-input"
213
+ aria-label={loginLang[interfaceLanguage.current].login.email}
214
+ />
215
+ {/snippet}
216
+ </Form.Control>
217
+ <Form.FieldErrors class="text-destructive mt-1 text-sm" />
218
+ </Form.Field>
219
+ </div>
220
+
221
+ {#if forgotError}
222
+ <p class="text-destructive text-sm">{forgotError}</p>
223
+ {/if}
224
+
225
+ <!-- Submit button -->
226
+ <Button
227
+ type="submit"
228
+ class="mt-1 h-11 w-full text-[15px] font-semibold"
229
+ disabled={forgotLoading}
230
+ >
231
+ {forgotLang().send_link}
232
+ </Button>
233
+
234
+ <!-- Back to login -->
235
+ <div class="text-center">
236
+ <button
237
+ type="button"
238
+ onclick={() => (mode = 'login')}
239
+ class="text-primary hover:text-plum-dark focus-visible:outline-ring rounded-md px-1 py-0.5 text-[13px] font-medium transition-colors hover:underline focus-visible:outline-2 focus-visible:outline-offset-2"
240
+ >
241
+ {forgotLang().back_to_login}
242
+ </button>
243
+ </div>
244
+ </div>
245
+ </form>
246
+ {:else}
247
+ <!-- forgot-sent -->
248
+ <div class="flex flex-col gap-5">
249
+ <!-- Brand -->
250
+ <div class="mb-2 flex flex-col items-center text-center">
251
+ <div class="mb-2 flex items-baseline gap-0.5" aria-hidden="true">
252
+ <span class="text-primary text-[28px] leading-none font-extrabold max-[480px]:text-[24px]">
253
+ Aria
254
+ </span>
255
+ <span
256
+ class="text-primary text-[16px] leading-none font-light tracking-[0.15em] uppercase max-[480px]:text-[14px]"
257
+ >
258
+ CMS
259
+ </span>
260
+ </div>
100
261
  </div>
101
262
 
102
- <!-- Password field -->
103
- <div class="grid gap-2">
104
- <Form.Field name="password" {form}>
105
- <Form.Control>
106
- {#snippet children({ props })}
107
- <Form.Label class="text-sm font-medium text-slate-700 dark:text-slate-300">
108
- {loginLang[interfaceLanguage.current].login.password}
109
- </Form.Label>
110
- <input
111
- {...props}
112
- autocomplete="current-password"
113
- bind:value={$formData.password}
114
- type="password"
115
- required
116
- aria-label={loginLang[interfaceLanguage.current].login.password}
117
- class="mt-2 w-full rounded-full border border-slate-200 bg-white px-6 py-4 text-slate-900 placeholder-slate-400 transition-all duration-200 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-[#2D4A77] focus:ring-offset-2 dark:border-slate-700 dark:bg-slate-800 dark:text-white dark:placeholder-slate-500 dark:focus:ring-[#4975AE] dark:focus:ring-offset-slate-900"
118
- />
119
- {/snippet}
120
- </Form.Control>
121
- <Form.FieldErrors class="mt-1 text-sm text-red-500" />
122
- </Form.Field>
263
+ <div class="text-center">
264
+ <h2 class="text-foreground text-lg font-semibold">{forgotLang().sent_heading}</h2>
265
+ <p class="text-muted-foreground mt-2 text-[14px]">{forgotLang().sent_description}</p>
123
266
  </div>
124
267
 
125
- <!-- Submit button -->
126
- <Button
127
- type="submit"
128
- variant="gradient"
129
- size="lg"
130
- class="w-full px-6 py-4 text-base font-semibold"
131
- aria-label={loginLang[interfaceLanguage.current].login.login_button}
132
- >
133
- {loginLang[interfaceLanguage.current].login.login_button}
134
- </Button>
268
+ <div class="text-center">
269
+ <button
270
+ type="button"
271
+ onclick={() => (mode = 'login')}
272
+ class="text-primary hover:text-plum-dark focus-visible:outline-ring rounded-md px-1 py-0.5 text-[13px] font-medium transition-colors hover:underline focus-visible:outline-2 focus-visible:outline-offset-2"
273
+ >
274
+ {forgotLang().back_to_login}
275
+ </button>
276
+ </div>
135
277
  </div>
136
- </form>
278
+ {/if}
@@ -1,18 +1,3 @@
1
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
- $$bindings?: Bindings;
4
- } & Exports;
5
- (internal: unknown, props: {
6
- $$events?: Events;
7
- $$slots?: Slots;
8
- }): Exports & {
9
- $set?: any;
10
- $on?: any;
11
- };
12
- z_$$bindings?: Bindings;
13
- }
14
- declare const LoginForm: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
- [evt: string]: CustomEvent<any>;
16
- }, {}, {}, string>;
17
- type LoginForm = InstanceType<typeof LoginForm>;
1
+ declare const LoginForm: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type LoginForm = ReturnType<typeof LoginForm>;
18
3
  export default LoginForm;