includio-cms 0.25.0 → 0.26.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 (349) hide show
  1. package/API.md +57 -4
  2. package/CHANGELOG.md +53 -0
  3. package/DOCS.md +1 -1
  4. package/README.md +2 -0
  5. package/ROADMAP.md +6 -0
  6. package/dist/admin/client/account/lang.d.ts +1 -0
  7. package/dist/admin/client/account/lang.js +4 -2
  8. package/dist/admin/client/account/profile-section.svelte +2 -2
  9. package/dist/admin/client/account/security-section.svelte +27 -4
  10. package/dist/admin/client/account/sessions-section.svelte +1 -1
  11. package/dist/admin/client/admin/admin-after-login-layout-content.svelte +1 -1
  12. package/dist/admin/client/admin/dashboard-page.svelte +34 -10
  13. package/dist/admin/client/collection/bulk-actions-bar.svelte +86 -44
  14. package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +3 -1
  15. package/dist/admin/client/collection/collection-entries.svelte +52 -36
  16. package/dist/admin/client/collection/collection-entries.svelte.d.ts +3 -0
  17. package/dist/admin/client/collection/collection.svelte +28 -14
  18. package/dist/admin/client/collection/collection.svelte.d.ts +3 -0
  19. package/dist/admin/client/collection/data-table.svelte +279 -130
  20. package/dist/admin/client/collection/data-table.svelte.d.ts +11 -0
  21. package/dist/admin/client/collection/date-cell.svelte +4 -4
  22. package/dist/admin/client/collection/row-actions.svelte +2 -1
  23. package/dist/admin/client/collection/sortable-header.svelte +33 -9
  24. package/dist/admin/client/collection/state-display.svelte +102 -0
  25. package/dist/admin/client/collection/state-display.svelte.d.ts +12 -0
  26. package/dist/admin/client/collection/status-badge.svelte +99 -11
  27. package/dist/admin/client/collection/status-badge.svelte.d.ts +15 -1
  28. package/dist/admin/client/collection/table-pagination.svelte +21 -6
  29. package/dist/admin/client/collection/table-toolbar.svelte +105 -80
  30. package/dist/admin/client/collection/table-toolbar.svelte.d.ts +11 -8
  31. package/dist/admin/client/entry/entry-form.svelte +36 -11
  32. package/dist/admin/client/entry/entry-form.svelte.d.ts +1 -0
  33. package/dist/admin/client/entry/entry-header.svelte +22 -15
  34. package/dist/admin/client/entry/entry-header.svelte.d.ts +1 -0
  35. package/dist/admin/client/entry/entry.svelte +269 -165
  36. package/dist/admin/client/entry/header/a11y-header-badge.svelte +47 -0
  37. package/dist/admin/client/entry/header/a11y-header-badge.svelte.d.ts +8 -0
  38. package/dist/admin/client/entry/header/publish-panel.svelte +69 -13
  39. package/dist/admin/client/entry/header/save-indicator.svelte +57 -28
  40. package/dist/admin/client/entry/header/save-indicator.svelte.d.ts +1 -0
  41. package/dist/admin/client/entry/header/status-badge.svelte +60 -15
  42. package/dist/admin/client/entry/header/status-badge.svelte.d.ts +1 -2
  43. package/dist/admin/client/entry/header/version-history-sheet.svelte +1 -1
  44. package/dist/admin/client/entry/hybrid/hybrid-layout.svelte +74 -23
  45. package/dist/admin/client/entry/hybrid/hybrid-preview.svelte +1 -1
  46. package/dist/admin/client/entry/utils.d.ts +14 -0
  47. package/dist/admin/client/entry/utils.js +28 -0
  48. package/dist/admin/client/form/form-submission/form-submission.svelte +2 -2
  49. package/dist/admin/client/form/form-submissions.svelte +143 -194
  50. package/dist/admin/client/form/form-submissions.svelte.d.ts +2 -0
  51. package/dist/admin/client/login/lang.d.ts +3 -0
  52. package/dist/admin/client/login/lang.js +10 -4
  53. package/dist/admin/client/login/login-form.svelte +8 -1
  54. package/dist/admin/client/login/reset-password-page.svelte +24 -3
  55. package/dist/admin/client/login/schema.d.ts +14 -2
  56. package/dist/admin/client/login/schema.js +19 -8
  57. package/dist/admin/client/maintenance/maintenance-page.svelte +16 -17
  58. package/dist/admin/client/media/media-page.svelte +1 -1
  59. package/dist/admin/client/shop/coupon-edit-page.svelte +117 -13
  60. package/dist/admin/client/shop/coupon-form.svelte +282 -138
  61. package/dist/admin/client/shop/coupon-form.svelte.d.ts +1 -9
  62. package/dist/admin/client/shop/coupon-new-page.svelte +40 -10
  63. package/dist/admin/client/shop/coupon-new-page.svelte.d.ts +2 -17
  64. package/dist/admin/client/shop/coupon-schema.d.ts +28 -0
  65. package/dist/admin/client/shop/coupon-schema.js +53 -0
  66. package/dist/admin/client/shop/coupons-list-page.svelte +262 -118
  67. package/dist/admin/client/shop/coupons-list-page.svelte.d.ts +16 -1
  68. package/dist/admin/client/shop/shipping-method-edit-page.svelte +108 -59
  69. package/dist/admin/client/shop/shipping-method-form.svelte +36 -9
  70. package/dist/admin/client/shop/shipping-method-new-page.svelte +44 -13
  71. package/dist/admin/client/shop/shipping-methods-list-page.svelte +101 -59
  72. package/dist/admin/client/shop/shop-order-detail-page.svelte +113 -84
  73. package/dist/admin/client/shop/shop-orders-list-page.svelte +302 -152
  74. package/dist/admin/client/shop/shop-orders-list-page.svelte.d.ts +18 -1
  75. package/dist/admin/client/shop/shop-products-list-page.svelte +355 -118
  76. package/dist/admin/client/shop/shop-products-list-page.svelte.d.ts +19 -1
  77. package/dist/admin/client/users/accept-invite-page.svelte +24 -3
  78. package/dist/admin/client/users/create-user-dialog.svelte +3 -8
  79. package/dist/admin/client/users/lang.d.ts +2 -0
  80. package/dist/admin/client/users/lang.js +4 -0
  81. package/dist/admin/client/users/pending-invitations.svelte +2 -9
  82. package/dist/admin/client/users/user-name-cell.svelte +20 -0
  83. package/dist/admin/client/users/user-name-cell.svelte.d.ts +9 -0
  84. package/dist/admin/client/users/user-role-badge.svelte +16 -0
  85. package/dist/admin/client/users/user-role-badge.svelte.d.ts +7 -0
  86. package/dist/admin/client/users/user-row-actions.svelte +72 -0
  87. package/dist/admin/client/users/user-row-actions.svelte.d.ts +20 -0
  88. package/dist/admin/client/users/user-sessions-sheet.svelte +2 -11
  89. package/dist/admin/client/users/users-page.svelte +283 -497
  90. package/dist/admin/client/users/users-page.svelte.d.ts +12 -1
  91. package/dist/admin/components/dashboard/form-submissions-widget.svelte +59 -74
  92. package/dist/admin/components/dashboard/recent-activity.svelte +17 -5
  93. package/dist/admin/components/dashboard/recent-entries.svelte +19 -7
  94. package/dist/admin/components/dialogs/confirmation-dialog.svelte +105 -0
  95. package/dist/admin/components/dialogs/confirmation-dialog.svelte.d.ts +13 -0
  96. package/dist/admin/components/fields/block-picker-modal.svelte +6 -0
  97. package/dist/admin/components/fields/blocks-field.svelte +46 -1
  98. package/dist/admin/components/fields/boolean-field.svelte +1 -1
  99. package/dist/admin/components/fields/field-renderer.svelte +23 -21
  100. package/dist/admin/components/fields/file-field.svelte +344 -30
  101. package/dist/admin/components/fields/media-field.svelte +16 -2
  102. package/dist/admin/components/fields/radio-field.svelte +22 -0
  103. package/dist/admin/components/fields/relation-field.svelte +123 -97
  104. package/dist/admin/components/fields/relation-picker-dialog.svelte +2 -2
  105. package/dist/admin/components/fields/seo-field.svelte +60 -30
  106. package/dist/admin/components/fields/shop-field.svelte +9 -4
  107. package/dist/admin/components/fields/simple-array-field.svelte +321 -151
  108. package/dist/admin/components/fields/simple-array-field.svelte.d.ts +3 -0
  109. package/dist/admin/components/fields/slug-field.svelte +146 -21
  110. package/dist/admin/components/fields/text-field-wrapper.svelte +37 -20
  111. package/dist/admin/components/fields/text-field.svelte +7 -2
  112. package/dist/admin/components/fields/url-field-wrapper.svelte +10 -0
  113. package/dist/admin/components/fields/url-field.svelte +36 -23
  114. package/dist/admin/components/forms/form-error-summary.svelte +143 -0
  115. package/dist/admin/components/forms/form-error-summary.svelte.d.ts +27 -0
  116. package/dist/admin/components/layout/app-sidebar.svelte +7 -2
  117. package/dist/admin/components/layout/detail-page-shell.svelte +71 -0
  118. package/dist/admin/components/layout/detail-page-shell.svelte.d.ts +24 -0
  119. package/dist/admin/components/layout/lang.d.ts +5 -0
  120. package/dist/admin/components/layout/lang.js +10 -0
  121. package/dist/admin/components/layout/layout-renderer.svelte +71 -2
  122. package/dist/admin/components/layout/layout-renderer.svelte.d.ts +1 -0
  123. package/dist/admin/components/layout/layout-tabs.svelte +172 -0
  124. package/dist/admin/components/layout/layout-tabs.svelte.d.ts +24 -0
  125. package/dist/admin/components/layout/nav-breadcrumbs.svelte +25 -7
  126. package/dist/admin/components/layout/nav-collections.svelte +23 -36
  127. package/dist/admin/components/layout/nav-forms.svelte +19 -35
  128. package/dist/admin/components/layout/nav-main.svelte +3 -28
  129. package/dist/admin/components/layout/nav-search.svelte +70 -2
  130. package/dist/admin/components/layout/nav-section.svelte +77 -0
  131. package/dist/admin/components/layout/nav-section.svelte.d.ts +22 -0
  132. package/dist/admin/components/layout/nav-shop.svelte +3 -27
  133. package/dist/admin/components/layout/nav-singletons.svelte +16 -28
  134. package/dist/admin/components/layout/page-header.stories.svelte +93 -0
  135. package/dist/admin/components/layout/page-header.stories.svelte.d.ts +27 -0
  136. package/dist/admin/components/layout/page-header.svelte +68 -0
  137. package/dist/admin/components/layout/page-header.svelte.d.ts +17 -0
  138. package/dist/admin/components/layout/site-header.svelte +9 -0
  139. package/dist/admin/components/layout/site-header.svelte.d.ts +2 -17
  140. package/dist/admin/components/media/file/file-name-input.svelte +6 -2
  141. package/dist/admin/components/media/file/file-preview.svelte +130 -17
  142. package/dist/admin/components/media/file-upload.svelte +16 -7
  143. package/dist/admin/components/media/file-upload.svelte.d.ts +1 -0
  144. package/dist/admin/components/media/files-list.svelte +153 -53
  145. package/dist/admin/components/media/files-list.svelte.d.ts +1 -0
  146. package/dist/admin/components/media/media-library.svelte +577 -198
  147. package/dist/admin/components/media/media-library.svelte.d.ts +4 -0
  148. package/dist/admin/components/media/media-selector.svelte +4 -2
  149. package/dist/admin/components/media/media-selector.svelte.d.ts +1 -0
  150. package/dist/admin/components/media/tag-sidebar.svelte +4 -4
  151. package/dist/admin/components/tiptap/FigureNodeView.svelte +10 -0
  152. package/dist/admin/components/tiptap/bubble-menu.svelte +104 -0
  153. package/dist/admin/components/tiptap/bubble-menu.svelte.d.ts +19 -0
  154. package/dist/admin/components/tiptap/content-editor.svelte +28 -24
  155. package/dist/admin/components/tiptap/editor-toolbar.svelte +7 -7
  156. package/dist/admin/components/tiptap/extensions.js +5 -1
  157. package/dist/admin/components/tiptap/image-dialog.svelte +5 -1
  158. package/dist/admin/components/tiptap/link-dialog.svelte +2 -0
  159. package/dist/admin/components/tiptap/tiptap-editor.svelte +18 -20
  160. package/dist/admin/components/tiptap/video-dialog.svelte +1 -1
  161. package/dist/admin/i18n/errors.d.ts +140 -0
  162. package/dist/admin/i18n/errors.js +151 -0
  163. package/dist/admin/remote/entry.remote.d.ts +59 -4
  164. package/dist/admin/remote/entry.remote.js +239 -62
  165. package/dist/admin/remote/shop.remote.d.ts +37 -32
  166. package/dist/admin/remote/shop.remote.js +9 -2
  167. package/dist/admin/shared/password-generate.d.ts +6 -0
  168. package/dist/admin/shared/password-generate.js +40 -0
  169. package/dist/admin/shared/password-schema.d.ts +6 -0
  170. package/dist/admin/shared/password-schema.js +10 -3
  171. package/dist/admin/styles/admin.css +23 -6
  172. package/dist/admin/styles/tokens.md +244 -0
  173. package/dist/admin/utils/accordionActivation.d.ts +13 -0
  174. package/dist/admin/utils/accordionActivation.js +35 -0
  175. package/dist/admin/utils/entryLabel.d.ts +23 -0
  176. package/dist/admin/utils/entryLabel.js +51 -12
  177. package/dist/admin/utils/field-a11y.d.ts +29 -0
  178. package/dist/admin/utils/field-a11y.js +23 -0
  179. package/dist/admin/utils/fieldPathElement.d.ts +9 -0
  180. package/dist/admin/utils/fieldPathElement.js +18 -0
  181. package/dist/admin/utils/fileDisplay.d.ts +10 -0
  182. package/dist/admin/utils/fileDisplay.js +26 -0
  183. package/dist/admin/utils/flattenFormErrors.d.ts +19 -0
  184. package/dist/admin/utils/flattenFormErrors.js +102 -0
  185. package/dist/admin/utils/formatters.d.ts +12 -0
  186. package/dist/admin/utils/{formatDate.js → formatters.js} +23 -2
  187. package/dist/admin/utils/scrollWithin.d.ts +9 -0
  188. package/dist/admin/utils/scrollWithin.js +32 -0
  189. package/dist/admin/utils/tabActivation.d.ts +12 -0
  190. package/dist/admin/utils/tabActivation.js +24 -0
  191. package/dist/cms/runtime/schema.d.ts +1 -0
  192. package/dist/cms/runtime/schema.js +1 -0
  193. package/dist/cms/runtime/types.d.ts +80 -7
  194. package/dist/components/ui/accordion/accordion-content.svelte +17 -3
  195. package/dist/components/ui/accordion/accordion.stories.svelte +21 -1
  196. package/dist/components/ui/alert/alert.stories.svelte +14 -0
  197. package/dist/components/ui/alert-dialog/alert-dialog.stories.svelte +45 -0
  198. package/dist/components/ui/alert-dialog/alert-dialog.stories.svelte.d.ts +27 -0
  199. package/dist/components/ui/avatar/avatar.stories.svelte +27 -0
  200. package/dist/components/ui/badge/badge.stories.svelte +15 -0
  201. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte +47 -0
  202. package/dist/components/ui/breadcrumb/breadcrumb.svelte +1 -1
  203. package/dist/components/ui/button/button.stories.svelte +53 -6
  204. package/dist/components/ui/button/button.svelte +39 -5
  205. package/dist/components/ui/button/button.svelte.d.ts +4 -0
  206. package/dist/components/ui/button-group/button-group.stories.svelte +44 -0
  207. package/dist/components/ui/button-group/button-group.stories.svelte.d.ts +27 -0
  208. package/dist/components/ui/calendar/calendar.stories.svelte +36 -0
  209. package/dist/components/ui/calendar/calendar.stories.svelte.d.ts +27 -0
  210. package/dist/components/ui/card/card.stories.svelte +7 -0
  211. package/dist/components/ui/carousel/carousel.stories.svelte +43 -0
  212. package/dist/components/ui/carousel/carousel.stories.svelte.d.ts +27 -0
  213. package/dist/components/ui/checkbox/checkbox.stories.svelte +67 -0
  214. package/dist/components/ui/checkbox/checkbox.stories.svelte.d.ts +27 -0
  215. package/dist/components/ui/checkbox/checkbox.svelte +3 -3
  216. package/dist/components/ui/command/command.stories.svelte +18 -0
  217. package/dist/components/ui/data-table/data-table.stories.svelte +61 -0
  218. package/dist/components/ui/data-table/data-table.stories.svelte.d.ts +18 -0
  219. package/dist/components/ui/dialog/dialog-content.svelte +5 -0
  220. package/dist/components/ui/dialog/dialog-content.svelte.d.ts +2 -0
  221. package/dist/components/ui/dialog/dialog.stories.svelte +35 -0
  222. package/dist/components/ui/dropdown-menu/dropdown-menu.stories.svelte +74 -0
  223. package/dist/components/ui/dropdown-menu/dropdown-menu.stories.svelte.d.ts +27 -0
  224. package/dist/components/ui/field/field-context.svelte.d.ts +22 -0
  225. package/dist/components/ui/field/field-context.svelte.js +9 -0
  226. package/dist/components/ui/field/field-control.svelte +18 -0
  227. package/dist/components/ui/field/field-control.svelte.d.ts +8 -0
  228. package/dist/components/ui/field/field-description.svelte +12 -0
  229. package/dist/components/ui/field/field-error.svelte +14 -6
  230. package/dist/components/ui/field/field-label.svelte +10 -0
  231. package/dist/components/ui/field/field.stories.svelte +95 -9
  232. package/dist/components/ui/field/field.svelte +57 -0
  233. package/dist/components/ui/field/field.svelte.d.ts +2 -0
  234. package/dist/components/ui/field/index.d.ts +3 -1
  235. package/dist/components/ui/field/index.js +4 -2
  236. package/dist/components/ui/form/form-field-errors.svelte +1 -1
  237. package/dist/components/ui/form/form.stories.svelte +25 -0
  238. package/dist/components/ui/form/form.stories.svelte.d.ts +26 -0
  239. package/dist/components/ui/input/input.stories.svelte +26 -0
  240. package/dist/components/ui/input-group/input-group-input.svelte.d.ts +1 -1
  241. package/dist/components/ui/input-group/input-group.stories.svelte +43 -0
  242. package/dist/components/ui/input-group/input-group.stories.svelte.d.ts +27 -0
  243. package/dist/components/ui/item/item.stories.svelte +61 -0
  244. package/dist/components/ui/item/item.stories.svelte.d.ts +27 -0
  245. package/dist/components/ui/label/label.stories.svelte +7 -0
  246. package/dist/components/ui/live-region/index.d.ts +1 -0
  247. package/dist/components/ui/live-region/index.js +1 -0
  248. package/dist/components/ui/live-region/live-region-demo.svelte +32 -0
  249. package/dist/components/ui/live-region/live-region-demo.svelte.d.ts +7 -0
  250. package/dist/components/ui/live-region/live-region.stories.svelte +23 -0
  251. package/dist/components/ui/live-region/live-region.stories.svelte.d.ts +26 -0
  252. package/dist/components/ui/live-region/live-region.svelte +12 -0
  253. package/dist/components/ui/live-region/live-region.svelte.d.ts +8 -0
  254. package/dist/components/ui/popover/popover.stories.svelte +34 -0
  255. package/dist/components/ui/radio-group/radio-group.stories.svelte +58 -0
  256. package/dist/components/ui/radio-group/radio-group.stories.svelte.d.ts +27 -0
  257. package/dist/components/ui/resizable/resizable.stories.svelte +56 -0
  258. package/dist/components/ui/resizable/resizable.stories.svelte.d.ts +27 -0
  259. package/dist/components/ui/select/select.stories.svelte +49 -0
  260. package/dist/components/ui/separator/separator.stories.svelte +18 -0
  261. package/dist/components/ui/sheet/sheet.stories.svelte +34 -0
  262. package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +1 -1
  263. package/dist/components/ui/sidebar/sidebar-menu-button.svelte +1 -0
  264. package/dist/components/ui/sidebar/sidebar-trigger.svelte +1 -1
  265. package/dist/components/ui/sidebar/sidebar.stories.svelte +72 -0
  266. package/dist/components/ui/sidebar/sidebar.stories.svelte.d.ts +27 -0
  267. package/dist/components/ui/skeleton/skeleton.stories.svelte +39 -0
  268. package/dist/components/ui/skeleton/skeleton.stories.svelte.d.ts +27 -0
  269. package/dist/components/ui/skeleton/skeleton.svelte +6 -0
  270. package/dist/components/ui/sonner/index.d.ts +1 -1
  271. package/dist/components/ui/sonner/index.js +1 -1
  272. package/dist/components/ui/sonner/sonner.stories.svelte +7 -0
  273. package/dist/components/ui/sonner/sonner.svelte +17 -1
  274. package/dist/components/ui/sonner/sonner.svelte.d.ts +6 -0
  275. package/dist/components/ui/spinner/spinner.stories.svelte +30 -0
  276. package/dist/components/ui/spinner/spinner.stories.svelte.d.ts +27 -0
  277. package/dist/components/ui/switch/switch.stories.svelte +56 -0
  278. package/dist/components/ui/switch/switch.stories.svelte.d.ts +27 -0
  279. package/dist/components/ui/table/table-cell.svelte +1 -1
  280. package/dist/components/ui/table/table-head.svelte +1 -1
  281. package/dist/components/ui/table/table.stories.svelte +68 -0
  282. package/dist/components/ui/table/table.stories.svelte.d.ts +27 -0
  283. package/dist/components/ui/table/table.svelte +1 -1
  284. package/dist/components/ui/tabs/tabs.stories.svelte +48 -0
  285. package/dist/components/ui/tabs/tabs.stories.svelte.d.ts +27 -0
  286. package/dist/components/ui/textarea/textarea.stories.svelte +21 -0
  287. package/dist/components/ui/toggle/toggle.stories.svelte +23 -0
  288. package/dist/components/ui/toggle-group/toggle-group.stories.svelte +43 -0
  289. package/dist/components/ui/tooltip/tooltip.stories.svelte +46 -6
  290. package/dist/core/fields/fieldSchemaToTs.d.ts +7 -0
  291. package/dist/core/fields/fieldSchemaToTs.js +234 -90
  292. package/dist/core/fields/layoutUtils.d.ts +4 -1
  293. package/dist/core/fields/layoutUtils.js +41 -4
  294. package/dist/core/fields/resolveSeo.d.ts +70 -0
  295. package/dist/core/fields/resolveSeo.js +88 -0
  296. package/dist/core/fields/seoFieldDescriptor.d.ts +43 -0
  297. package/dist/core/fields/seoFieldDescriptor.js +74 -0
  298. package/dist/core/fields/slugPath.d.ts +13 -0
  299. package/dist/core/fields/slugPath.js +32 -0
  300. package/dist/core/fields/urlUtils.d.ts +8 -0
  301. package/dist/core/fields/urlUtils.js +27 -0
  302. package/dist/core/index.d.ts +1 -0
  303. package/dist/core/index.js +1 -0
  304. package/dist/core/server/entries/operations/create.js +13 -0
  305. package/dist/core/server/entries/operations/get.d.ts +7 -0
  306. package/dist/core/server/entries/operations/get.js +10 -6
  307. package/dist/core/server/entries/operations/slugUniqueness.d.ts +37 -0
  308. package/dist/core/server/entries/operations/slugUniqueness.js +116 -0
  309. package/dist/core/server/entries/operations/update.d.ts +6 -1
  310. package/dist/core/server/entries/operations/update.js +24 -1
  311. package/dist/core/server/fields/slugResolver.d.ts +3 -13
  312. package/dist/core/server/fields/slugResolver.js +8 -37
  313. package/dist/core/server/generator/fields.js +10 -17
  314. package/dist/core/server/generator/formFields.js +2 -1
  315. package/dist/core/server/generator/generator.js +4 -4
  316. package/dist/core/server/generator/utils.d.ts +1 -0
  317. package/dist/core/server/generator/utils.js +4 -0
  318. package/dist/paraglide/messages/_index.d.ts +3 -36
  319. package/dist/paraglide/messages/_index.js +3 -71
  320. package/dist/paraglide/messages/hello_world.d.ts +5 -0
  321. package/dist/paraglide/messages/hello_world.js +33 -0
  322. package/dist/paraglide/messages/login_hello.d.ts +16 -0
  323. package/dist/paraglide/messages/login_hello.js +34 -0
  324. package/dist/paraglide/messages/login_please_login.d.ts +16 -0
  325. package/dist/paraglide/messages/login_please_login.js +34 -0
  326. package/dist/shop/server/orders.d.ts +1 -0
  327. package/dist/shop/server/orders.js +14 -0
  328. package/dist/shop/server/shop-data.d.ts +2 -0
  329. package/dist/shop/server/shop-data.js +20 -5
  330. package/dist/sveltekit/server/handle.js +17 -0
  331. package/dist/types/cms.schema.js +4 -2
  332. package/dist/types/fields.d.ts +35 -0
  333. package/dist/types/index.d.ts +1 -1
  334. package/dist/types/layout.d.ts +35 -2
  335. package/dist/updates/0.26.0/index.d.ts +2 -0
  336. package/dist/updates/0.26.0/index.js +51 -0
  337. package/dist/updates/index.js +3 -1
  338. package/package.json +29 -7
  339. package/dist/admin/client/collection/empty-state.svelte +0 -28
  340. package/dist/admin/client/collection/empty-state.svelte.d.ts +0 -9
  341. package/dist/admin/client/form/submission-status-badge.svelte +0 -41
  342. package/dist/admin/client/form/submission-status-badge.svelte.d.ts +0 -7
  343. package/dist/admin/components/media/file-preview.svelte +0 -51
  344. package/dist/admin/components/media/file-preview.svelte.d.ts +0 -6
  345. package/dist/admin/utils/formatDate.d.ts +0 -5
  346. package/dist/paraglide/messages/en.d.ts +0 -5
  347. package/dist/paraglide/messages/en.js +0 -14
  348. package/dist/paraglide/messages/pl.d.ts +0 -5
  349. package/dist/paraglide/messages/pl.js +0 -14
@@ -3,34 +3,41 @@
3
3
  import type { FormConfig, FormSubmission } from '../../../types/forms.js';
4
4
  import type { ColumnDef, RowSelectionState, SortingState, Table } from '@tanstack/table-core';
5
5
  import SubmissionLink from './submission-link.svelte';
6
- import SubmissionStatusBadge from './submission-status-badge.svelte';
7
6
  import DataTable from '../collection/data-table.svelte';
8
7
  import TablePagination from '../collection/table-pagination.svelte';
8
+ import TableToolbar from '../collection/table-toolbar.svelte';
9
+ import StatusBadge from '../collection/status-badge.svelte';
10
+ import StateDisplay from '../collection/state-display.svelte';
11
+ import BulkActionsBar from '../collection/bulk-actions-bar.svelte';
12
+ import PageHeader from '../../components/layout/page-header.svelte';
9
13
  import { getLocalizedLabel } from '../../utils/collectionLabel.js';
10
14
  import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
11
15
  import type { InterfaceLanguage } from '../../../types/languages.js';
12
- import { formatAbsoluteDate as formatAbsoluteDateUtil } from '../../utils/formatDate.js';
16
+ import { formatDateTime } from '../../utils/formatters.js';
13
17
  import Checkbox from '../../../components/ui/checkbox/checkbox.svelte';
14
18
  import { getRemotes } from '../../context/remotes.js';
15
19
  import { invalidateAll } from '$app/navigation';
16
- import Search from '@tabler/icons-svelte/icons/search';
17
- import FilterIcon from '@tabler/icons-svelte/icons/filter';
18
20
  import Download from '@tabler/icons-svelte/icons/download';
19
21
  import ChevronDown from '@tabler/icons-svelte/icons/chevron-down';
20
22
  import FileSpreadsheet from '@tabler/icons-svelte/icons/file-spreadsheet';
21
23
  import FileText from '@tabler/icons-svelte/icons/file-text';
22
- import Trash from '@tabler/icons-svelte/icons/trash';
23
24
  import Eye from '@tabler/icons-svelte/icons/eye';
24
25
  import EyeOff from '@tabler/icons-svelte/icons/eye-off';
25
- import X from '@tabler/icons-svelte/icons/x';
26
- import ClipboardList from '@tabler/icons-svelte/icons/clipboard-list';
27
- import Input from '../../../components/ui/input/input.svelte';
28
26
  import Button from '../../../components/ui/button/button.svelte';
29
27
  import * as Popover from '../../../components/ui/popover/index.js';
28
+ import ConfirmationDialog from '../../components/dialogs/confirmation-dialog.svelte';
30
29
 
31
30
  const interfaceLanguage = useInterfaceLanguage();
32
31
  const remotes = getRemotes();
33
32
 
33
+ function pluralPL(n: number, singular: string, few: string, many: string): string {
34
+ const mod10 = n % 10;
35
+ const mod100 = n % 100;
36
+ if (n === 1) return singular;
37
+ if (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20)) return few;
38
+ return many;
39
+ }
40
+
34
41
  type ReadFilter = 'all' | 'unread' | 'read';
35
42
 
36
43
  const lang: Record<
@@ -38,16 +45,13 @@
38
45
  {
39
46
  createdAt: string;
40
47
  status: string;
41
- new: string;
42
48
  read: string;
43
- submissions: string;
44
49
  unread: string;
45
- unreadCount: string;
46
50
  searchPlaceholder: string;
47
- all: string;
48
51
  filterAll: string;
49
52
  filterUnread: string;
50
53
  filterRead: string;
54
+ filterLabel: string;
51
55
  export: string;
52
56
  exportCsv: string;
53
57
  exportJson: string;
@@ -55,28 +59,27 @@
55
59
  noSubmissionsDesc: string;
56
60
  noResults: string;
57
61
  noResultsDesc: string;
58
- bulkSelected: (n: number) => string;
62
+ unreadDescription: (n: number) => string;
59
63
  bulkMarkRead: string;
60
64
  bulkMarkUnread: string;
61
65
  bulkExport: string;
62
- bulkDelete: string;
63
- confirmBulkDelete: (n: number) => string;
66
+ confirmBulkDeleteTitle: (n: number) => string;
67
+ confirmBulkDeleteDescription: string;
64
68
  itemLabel: string;
69
+ loadingMessage: string;
70
+ errorMessage: string;
65
71
  }
66
72
  > = {
67
73
  pl: {
68
74
  createdAt: 'Wysłano',
69
75
  status: 'Status',
70
- new: 'Nowe',
71
76
  read: 'Przeczytane',
72
- submissions: 'zgłoszeń',
73
- unread: 'nieprzeczytanych',
74
- unreadCount: 'nieprzeczytanych',
77
+ unread: 'Nieprzeczytane',
75
78
  searchPlaceholder: 'Szukaj zgłoszeń…',
76
- all: 'Wszystkie',
77
79
  filterAll: 'Wszystkie',
78
80
  filterUnread: 'Nieprzeczytane',
79
81
  filterRead: 'Przeczytane',
82
+ filterLabel: 'Status',
80
83
  export: 'Eksportuj',
81
84
  exportCsv: 'Eksportuj CSV',
82
85
  exportJson: 'Eksportuj JSON',
@@ -84,27 +87,26 @@
84
87
  noSubmissionsDesc: 'Nie otrzymano jeszcze żadnych zgłoszeń z tego formularza.',
85
88
  noResults: 'Brak wyników',
86
89
  noResultsDesc: 'Spróbuj zmienić kryteria wyszukiwania.',
87
- bulkSelected: (n) => `${n} zaznaczonych`,
90
+ unreadDescription: (n) => `${n} nieprzeczytanych`,
88
91
  bulkMarkRead: 'Oznacz przeczytane',
89
92
  bulkMarkUnread: 'Oznacz nieprzeczytane',
90
93
  bulkExport: 'Eksportuj',
91
- bulkDelete: 'Usuń',
92
- confirmBulkDelete: (n) => `Czy na pewno chcesz usunąć ${n} zgłoszeń?`,
93
- itemLabel: 'zgłoszeń'
94
+ confirmBulkDeleteTitle: (n: number) => `Usunąć ${n} ${pluralPL(n, 'zgłoszenie', 'zgłoszenia', 'zgłoszeń')}?`,
95
+ confirmBulkDeleteDescription: 'Tej akcji nie cofniesz zgłoszenia znikną z bazy.',
96
+ itemLabel: 'zgłoszeń',
97
+ loadingMessage: 'Ładowanie zgłoszeń…',
98
+ errorMessage: 'Nie udało się wczytać zgłoszeń.'
94
99
  },
95
100
  en: {
96
101
  createdAt: 'Sent',
97
102
  status: 'Status',
98
- new: 'New',
99
103
  read: 'Read',
100
- submissions: 'submissions',
101
- unread: 'unread',
102
- unreadCount: 'unread',
104
+ unread: 'Unread',
103
105
  searchPlaceholder: 'Search submissions…',
104
- all: 'All',
105
106
  filterAll: 'All',
106
107
  filterUnread: 'Unread',
107
108
  filterRead: 'Read',
109
+ filterLabel: 'Status',
108
110
  export: 'Export',
109
111
  exportCsv: 'Export CSV',
110
112
  exportJson: 'Export JSON',
@@ -112,13 +114,16 @@
112
114
  noSubmissionsDesc: 'No submissions have been received from this form yet.',
113
115
  noResults: 'No results',
114
116
  noResultsDesc: 'Try adjusting your search criteria.',
115
- bulkSelected: (n) => `${n} selected`,
117
+ unreadDescription: (n) => `${n} unread`,
116
118
  bulkMarkRead: 'Mark read',
117
119
  bulkMarkUnread: 'Mark unread',
118
120
  bulkExport: 'Export',
119
- bulkDelete: 'Delete',
120
- confirmBulkDelete: (n) => `Are you sure you want to delete ${n} submissions?`,
121
- itemLabel: 'submissions'
121
+ confirmBulkDeleteTitle: (n: number) =>
122
+ `Delete ${n} ${n === 1 ? 'submission' : 'submissions'}?`,
123
+ confirmBulkDeleteDescription: 'This cannot be undone — submissions will be removed from the database.',
124
+ itemLabel: 'submissions',
125
+ loadingMessage: 'Loading submissions…',
126
+ errorMessage: 'Failed to load submissions.'
122
127
  }
123
128
  };
124
129
 
@@ -130,9 +135,16 @@
130
135
  type Props = {
131
136
  submissions: FormSubmission[];
132
137
  formConfig: FormConfig;
138
+ data?: FormSubmission[];
139
+ state?: 'loading' | 'error' | 'ok';
133
140
  };
134
141
 
135
- let { submissions, formConfig }: Props = $props();
142
+ let { submissions, formConfig, data: injectedData, state: injectedState }: Props = $props();
143
+
144
+ const effectiveSubmissions = $derived(injectedData ?? submissions);
145
+ const tableViewState = $derived<'idle' | 'loading' | 'error'>(
146
+ injectedState === 'loading' ? 'loading' : injectedState === 'error' ? 'error' : 'idle'
147
+ );
136
148
 
137
149
  let searchQuery = $state('');
138
150
  let readFilter = $state<ReadFilter>('all');
@@ -141,7 +153,6 @@
141
153
  let pageSize = $state(20);
142
154
  let tableInstance = $state<Table<SubmissionRow> | null>(null);
143
155
  let exportDropdownOpen = $state(false);
144
- let filterPopoverOpen = $state(false);
145
156
 
146
157
  const t = $derived(lang[interfaceLanguage.current]);
147
158
  const formLabel = $derived(
@@ -149,8 +160,8 @@
149
160
  );
150
161
 
151
162
  const stats = $derived({
152
- total: submissions.length,
153
- unreadCount: submissions.filter((s) => !s.read).length
163
+ total: effectiveSubmissions.length,
164
+ unreadCount: effectiveSubmissions.filter((s) => !s.read).length
154
165
  });
155
166
 
156
167
  const selectedCount = $derived(
@@ -167,7 +178,7 @@
167
178
  );
168
179
 
169
180
  const filteredData = $derived.by(() => {
170
- let result: SubmissionRow[] = submissions.map((submission) => ({
181
+ let result: SubmissionRow[] = effectiveSubmissions.map((submission) => ({
171
182
  ...submission,
172
183
  ...submission.data,
173
184
  url: `/admin/form-submissions/${submission.id}`
@@ -194,14 +205,29 @@
194
205
  const totalItems = $derived(filteredData.length);
195
206
  const pageCount = $derived(Math.ceil(totalItems / pageSize));
196
207
 
197
- const activeFilterLabel = $derived(
198
- readFilter === 'all' ? t.filterAll : readFilter === 'unread' ? t.filterUnread : t.filterRead
208
+ const dataFilters = $derived([
209
+ {
210
+ slug: 'read',
211
+ label: t.filterLabel,
212
+ options: [
213
+ { value: 'all', label: t.filterAll },
214
+ { value: 'unread', label: t.filterUnread },
215
+ { value: 'read', label: t.filterRead }
216
+ ]
217
+ }
218
+ ]);
219
+
220
+ const activeDataFilters = $derived({
221
+ read: readFilter === 'all' ? null : readFilter
222
+ });
223
+
224
+ const headerDescription = $derived(
225
+ stats.unreadCount > 0 ? t.unreadDescription(stats.unreadCount) : undefined
199
226
  );
200
227
 
201
228
  const columns = $derived.by(() => {
202
229
  const cols: ColumnDef<SubmissionRow>[] = [];
203
230
 
204
- // Checkbox column
205
231
  cols.push({
206
232
  id: 'select',
207
233
  header: ({ table }) =>
@@ -220,22 +246,20 @@
220
246
  enableHiding: false
221
247
  });
222
248
 
223
- // Read dot column
224
249
  cols.push({
225
- id: 'readDot',
226
- header: '',
227
- cell: (info) => {
228
- return renderComponent(SubmissionStatusBadge, {
229
- isRead: info.row.original.read,
230
- variant: 'dot'
231
- });
232
- },
250
+ id: 'status',
251
+ header: t.status,
252
+ cell: (info) =>
253
+ renderComponent(StatusBadge, {
254
+ variant: 'boolean',
255
+ active: info.row.original.read,
256
+ activeLabel: t.read,
257
+ inactiveLabel: t.unread
258
+ }),
233
259
  enableSorting: false,
234
- enableHiding: false,
235
- size: 32
260
+ size: 130
236
261
  });
237
262
 
238
- // Dynamic field columns
239
263
  const firstShowField = formConfig.fields.find((f) => f.showInDataTable);
240
264
  formConfig.fields.forEach((field) => {
241
265
  if (!field.showInDataTable) return;
@@ -271,7 +295,6 @@
271
295
  cols.push(col);
272
296
  });
273
297
 
274
- // Message preview column (find textarea field not in showInDataTable)
275
298
  const messageField = formConfig.fields.find(
276
299
  (f) => f.type === 'textarea' && !f.showInDataTable
277
300
  );
@@ -292,13 +315,12 @@
292
315
  });
293
316
  }
294
317
 
295
- // Date column
296
318
  cols.push({
297
319
  accessorKey: 'createdAt',
298
320
  header: t.createdAt,
299
321
  cell: (info) => {
300
322
  const date = new Date(info.row.original.createdAt);
301
- return formatAbsoluteDateUtil(date, interfaceLanguage.current);
323
+ return formatDateTime(date, interfaceLanguage.current);
302
324
  }
303
325
  });
304
326
 
@@ -318,7 +340,7 @@
318
340
  }
319
341
 
320
342
  async function handleExportJson() {
321
- const blob = new Blob([JSON.stringify(submissions, null, 2)], {
343
+ const blob = new Blob([JSON.stringify(effectiveSubmissions, null, 2)], {
322
344
  type: 'application/json'
323
345
  });
324
346
  const url = URL.createObjectURL(blob);
@@ -346,94 +368,29 @@
346
368
  invalidateAll();
347
369
  }
348
370
 
349
- async function handleBulkDelete() {
371
+ let confirmBulkDeleteOpen = $state(false);
372
+ let bulkDeleting = $state(false);
373
+
374
+ function handleBulkDelete() {
350
375
  if (selectedIds.length === 0) return;
351
- if (!confirm(t.confirmBulkDelete(selectedIds.length))) return;
352
- await remotes.deleteFormSubmissions(selectedIds);
353
- rowSelection = {};
354
- invalidateAll();
376
+ confirmBulkDeleteOpen = true;
355
377
  }
356
378
 
379
+ async function performBulkDelete() {
380
+ bulkDeleting = true;
381
+ try {
382
+ await remotes.deleteFormSubmissions(selectedIds);
383
+ rowSelection = {};
384
+ invalidateAll();
385
+ } finally {
386
+ bulkDeleting = false;
387
+ }
388
+ }
357
389
  </script>
358
390
 
359
391
  <div class="space-y-5">
360
- <!-- Header -->
361
- <div>
362
- <div class="mb-1 flex flex-wrap items-center gap-3">
363
- <h1 class="text-2xl font-bold">{formLabel}</h1>
364
- <span
365
- class="bg-lavender-lighter text-primary inline-flex h-6 items-center rounded-full px-2.5 text-xs font-bold"
366
- aria-label="{stats.total} {t.submissions}"
367
- >
368
- {stats.total} {t.submissions}
369
- </span>
370
- {#if stats.unreadCount > 0}
371
- <span
372
- class="inline-flex h-6 items-center rounded-full bg-amber-50 px-2.5 text-xs font-semibold text-amber-600"
373
- aria-label="{stats.unreadCount} {t.unreadCount}"
374
- >
375
- {stats.unreadCount} {t.unreadCount}
376
- </span>
377
- {/if}
378
- </div>
379
-
380
- <!-- Toolbar -->
381
- <div class="mt-4 flex flex-wrap items-center gap-2.5">
382
- <div class="relative min-w-[240px] flex-1">
383
- <Search
384
- class="text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2"
385
- />
386
- <Input
387
- type="search"
388
- placeholder={t.searchPlaceholder}
389
- class="border-border bg-white pl-9"
390
- value={searchQuery}
391
- oninput={(e) => (searchQuery = e.currentTarget.value)}
392
- aria-label={t.searchPlaceholder}
393
- />
394
- </div>
395
-
396
- <Popover.Root bind:open={filterPopoverOpen}>
397
- <Popover.Trigger>
398
- {#snippet child({ props })}
399
- <Button
400
- {...props}
401
- variant="outline"
402
- size="sm"
403
- class="gap-1.5 {readFilter !== 'all'
404
- ? 'border-primary/30 bg-lavender-lighter text-primary'
405
- : ''}"
406
- >
407
- <FilterIcon class="size-3.5" />
408
- {activeFilterLabel}
409
- </Button>
410
- {/snippet}
411
- </Popover.Trigger>
412
- <Popover.Content class="w-40 p-1" align="start">
413
- {#each ['all', 'unread', 'read'] as filter}
414
- <button
415
- class="hover:bg-accent flex w-full items-center rounded-md px-2.5 py-1.5 text-sm transition-colors {readFilter ===
416
- filter
417
- ? 'bg-accent text-accent-foreground font-medium'
418
- : 'text-foreground'}"
419
- onclick={() => {
420
- readFilter = filter as ReadFilter;
421
- filterPopoverOpen = false;
422
- }}
423
- >
424
- {filter === 'all'
425
- ? t.filterAll
426
- : filter === 'unread'
427
- ? t.filterUnread
428
- : t.filterRead}
429
- </button>
430
- {/each}
431
- </Popover.Content>
432
- </Popover.Root>
433
-
434
- <div class="flex-1"></div>
435
-
436
- <!-- Export dropdown -->
392
+ <PageHeader title={formLabel} count={stats.total} description={headerDescription}>
393
+ {#snippet secondaryActions()}
437
394
  <Popover.Root bind:open={exportDropdownOpen}>
438
395
  <Popover.Trigger>
439
396
  {#snippet child({ props })}
@@ -461,24 +418,30 @@
461
418
  </button>
462
419
  </Popover.Content>
463
420
  </Popover.Root>
464
- </div>
465
- </div>
466
-
467
- <!-- Table -->
468
- {#if submissions.length === 0}
469
- <!-- Empty state: no submissions at all -->
470
- <div class="flex flex-col items-center justify-center rounded-2xl border bg-card px-10 py-20 text-center">
471
- <div
472
- class="bg-surface mb-5 flex size-[72px] items-center justify-center rounded-xl"
473
- >
474
- <ClipboardList class="text-muted-foreground size-8" />
475
- </div>
476
- <h2 class="mb-1.5 text-lg font-bold">{t.noSubmissions}</h2>
477
- <p class="text-muted-foreground max-w-[360px] text-sm leading-relaxed">
478
- {t.noSubmissionsDesc}
479
- </p>
480
- </div>
421
+ {/snippet}
422
+ </PageHeader>
423
+
424
+ {#if tableViewState === 'error'}
425
+ <StateDisplay kind="error" title={t.errorMessage} />
426
+ {:else if tableViewState === 'loading'}
427
+ <StateDisplay kind="loading" title={t.loadingMessage} />
428
+ {:else if effectiveSubmissions.length === 0}
429
+ <StateDisplay kind="empty" title={t.noSubmissions} description={t.noSubmissionsDesc} />
481
430
  {:else}
431
+ <TableToolbar
432
+ {searchQuery}
433
+ searchPlaceholder={t.searchPlaceholder}
434
+ searchLabel={t.searchPlaceholder}
435
+ onSearchChange={(q) => (searchQuery = q)}
436
+ hideStatusFilter
437
+ hideViewToggle
438
+ {dataFilters}
439
+ {activeDataFilters}
440
+ onDataFilterChange={(_slug, value) => {
441
+ readFilter = (value as ReadFilter | null) ?? 'all';
442
+ }}
443
+ />
444
+
482
445
  <div class="overflow-hidden rounded-xl border bg-card shadow-sm">
483
446
  <DataTable
484
447
  data={filteredData}
@@ -493,9 +456,8 @@
493
456
  onRowSelectionChange={(s) => (rowSelection = s)}
494
457
  pagination={{ pageIndex: 0, pageSize }}
495
458
  tableRef={(t) => (tableInstance = t)}
496
- emptyMessage={searchQuery || readFilter !== 'all'
497
- ? t.noResults
498
- : t.noSubmissions}
459
+ emptyTitle={searchQuery || readFilter !== 'all' ? t.noResults : t.noSubmissions}
460
+ emptyDescription={searchQuery || readFilter !== 'all' ? t.noResultsDesc : t.noSubmissionsDesc}
499
461
  />
500
462
 
501
463
  <TablePagination
@@ -514,59 +476,46 @@
514
476
  {/if}
515
477
  </div>
516
478
 
517
- <!-- Bulk actions bar -->
518
- {#if selectedCount > 0}
519
- <div
520
- class="fixed bottom-6 left-1/2 z-50 flex -translate-x-1/2 items-center gap-3 rounded-xl bg-[#2E2558] px-5 py-2.5 text-white shadow-xl"
521
- role="toolbar"
522
- aria-label="Bulk actions"
523
- >
524
- <span class="text-sm font-bold whitespace-nowrap">{t.bulkSelected(selectedCount)}</span>
525
- <div class="h-5 w-px bg-white/20"></div>
479
+ <BulkActionsBar
480
+ {selectedCount}
481
+ onDelete={handleBulkDelete}
482
+ onClear={() => (rowSelection = {})}
483
+ >
484
+ {#snippet actions()}
526
485
  <Button
527
486
  variant="ghost"
528
487
  size="sm"
529
- class="gap-1.5 border border-white/20 text-white hover:bg-white/10 hover:text-white"
488
+ class="border border-white/20 text-white hover:bg-white/10 hover:text-white"
530
489
  onclick={handleBulkMarkRead}
531
490
  >
532
- <Eye class="size-3.5" />
491
+ <Eye class="mr-1.5 size-3.5" />
533
492
  {t.bulkMarkRead}
534
493
  </Button>
535
494
  <Button
536
495
  variant="ghost"
537
496
  size="sm"
538
- class="gap-1.5 border border-white/20 text-white hover:bg-white/10 hover:text-white"
497
+ class="border border-white/20 text-white hover:bg-white/10 hover:text-white"
539
498
  onclick={handleBulkMarkUnread}
540
499
  >
541
- <EyeOff class="size-3.5" />
500
+ <EyeOff class="mr-1.5 size-3.5" />
542
501
  {t.bulkMarkUnread}
543
502
  </Button>
544
503
  <Button
545
504
  variant="ghost"
546
505
  size="sm"
547
- class="gap-1.5 border border-white/20 text-white hover:bg-white/10 hover:text-white"
506
+ class="border border-white/20 text-white hover:bg-white/10 hover:text-white"
548
507
  onclick={handleExportCsv}
549
508
  >
550
- <Download class="size-3.5" />
509
+ <Download class="mr-1.5 size-3.5" />
551
510
  {t.bulkExport}
552
511
  </Button>
553
- <Button
554
- variant="ghost"
555
- size="sm"
556
- class="gap-1.5 border border-red-400/50 text-white hover:bg-red-500/20 hover:text-white"
557
- onclick={handleBulkDelete}
558
- >
559
- <Trash class="size-3.5" />
560
- {t.bulkDelete}
561
- </Button>
562
- <Button
563
- variant="ghost"
564
- size="icon"
565
- class="ml-1 size-7 text-white/60 hover:bg-white/10 hover:text-white"
566
- onclick={() => (rowSelection = {})}
567
- >
568
- <X class="size-3.5" />
569
- </Button>
570
- </div>
571
- {/if}
572
-
512
+ {/snippet}
513
+ </BulkActionsBar>
514
+
515
+ <ConfirmationDialog
516
+ bind:open={confirmBulkDeleteOpen}
517
+ title={t.confirmBulkDeleteTitle(selectedIds.length)}
518
+ description={t.confirmBulkDeleteDescription}
519
+ loading={bulkDeleting}
520
+ onConfirm={performBulkDelete}
521
+ />
@@ -2,6 +2,8 @@ import type { FormConfig, FormSubmission } from '../../../types/forms.js';
2
2
  type Props = {
3
3
  submissions: FormSubmission[];
4
4
  formConfig: FormConfig;
5
+ data?: FormSubmission[];
6
+ state?: 'loading' | 'error' | 'ok';
5
7
  };
6
8
  declare const FormSubmissions: import("svelte").Component<Props, {}, "">;
7
9
  type FormSubmissions = ReturnType<typeof FormSubmissions>;
@@ -12,6 +12,8 @@ export declare const loginLang: Record<string, {
12
12
  form_label: string;
13
13
  login_error: string;
14
14
  login_success: string;
15
+ email_invalid: string;
16
+ password_too_short: string;
15
17
  };
16
18
  forgot: {
17
19
  heading: string;
@@ -37,5 +39,6 @@ export declare const loginLang: Record<string, {
37
39
  passwordHint: string;
38
40
  passwordMinLength: string;
39
41
  passwordRequirements: string;
42
+ generatePassword: string;
40
43
  };
41
44
  }>;
@@ -12,7 +12,9 @@ export const loginLang = {
12
12
  skip_to_content: 'Przejdź do treści',
13
13
  form_label: 'Logowanie',
14
14
  login_error: 'Nieprawidłowy e-mail lub hasło. Spróbuj ponownie.',
15
- login_success: 'Zalogowano pomyślnie'
15
+ login_success: 'Zalogowano pomyślnie',
16
+ email_invalid: 'Podaj poprawny adres e-mail',
17
+ password_too_short: 'Hasło jest za krótkie'
16
18
  },
17
19
  forgot: {
18
20
  heading: 'Przypomnij hasło',
@@ -37,7 +39,8 @@ export const loginLang = {
37
39
  form_label: 'Zmiana hasła',
38
40
  passwordHint: 'Min. 8 znaków, wielka litera, cyfra i znak specjalny',
39
41
  passwordMinLength: 'Hasło musi mieć min. 8 znaków',
40
- passwordRequirements: 'Hasło musi zawierać wielką literę, cyfrę i znak specjalny'
42
+ passwordRequirements: 'Hasło musi zawierać wielką literę, cyfrę i znak specjalny',
43
+ generatePassword: 'Wygeneruj hasło'
41
44
  }
42
45
  },
43
46
  en: {
@@ -53,7 +56,9 @@ export const loginLang = {
53
56
  skip_to_content: 'Skip to content',
54
57
  form_label: 'Login',
55
58
  login_error: 'Invalid email or password. Please try again.',
56
- login_success: 'Logged in successfully'
59
+ login_success: 'Logged in successfully',
60
+ email_invalid: 'Enter a valid email address',
61
+ password_too_short: 'Password is too short'
57
62
  },
58
63
  forgot: {
59
64
  heading: 'Forgot password',
@@ -78,7 +83,8 @@ export const loginLang = {
78
83
  form_label: 'Reset password',
79
84
  passwordHint: 'Min. 8 characters, uppercase, number and special character',
80
85
  passwordMinLength: 'Password must be at least 8 characters',
81
- passwordRequirements: 'Password must contain an uppercase letter, a number and a special character'
86
+ passwordRequirements: 'Password must contain an uppercase letter, a number and a special character',
87
+ generatePassword: 'Generate password'
82
88
  }
83
89
  }
84
90
  };
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { defaults, superForm } from 'sveltekit-superforms';
6
6
  import { zod4, zod4Client } from 'sveltekit-superforms/adapters';
7
- import { loginSchema, forgotPasswordSchema } from './schema.js';
7
+ import { createLoginSchema, createForgotPasswordSchema } from './schema.js';
8
8
  import { toast } from 'svelte-sonner';
9
9
  import { authClient } from '../../auth-client.js';
10
10
  import { loginLang } from './lang.js';
@@ -17,6 +17,13 @@
17
17
  const lang = () => loginLang[interfaceLanguage.current].login;
18
18
  const forgotLang = () => loginLang[interfaceLanguage.current].forgot;
19
19
 
20
+ // superForm is initialized once — capture the current language for validation messages
21
+ const loginSchema = createLoginSchema({
22
+ emailInvalid: lang().email_invalid,
23
+ passwordTooShort: lang().password_too_short
24
+ });
25
+ const forgotPasswordSchema = createForgotPasswordSchema({ emailInvalid: lang().email_invalid });
26
+
20
27
  let mode: 'login' | 'forgot' | 'forgot-sent' = $state('login');
21
28
  let forgotLoading = $state(false);
22
29
  let forgotError = $state('');