includio-cms 0.1.3 → 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 (313) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/ROADMAP.md +23 -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 -256
  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/paraglide/.prettierignore +3 -0
  272. package/dist/paraglide/messages/_index.d.ts +36 -0
  273. package/dist/paraglide/messages/_index.js +72 -0
  274. package/dist/paraglide/messages/en.d.ts +5 -0
  275. package/dist/paraglide/messages/en.js +14 -0
  276. package/dist/paraglide/messages/pl.d.ts +5 -0
  277. package/dist/paraglide/messages/pl.js +14 -0
  278. package/dist/paraglide/messages.d.ts +2 -0
  279. package/dist/paraglide/messages.js +4 -0
  280. package/dist/paraglide/registry.d.ts +21 -0
  281. package/dist/paraglide/registry.js +31 -0
  282. package/dist/paraglide/runtime.d.ts +583 -0
  283. package/dist/paraglide/runtime.js +1402 -0
  284. package/dist/paraglide/server.d.ts +67 -0
  285. package/dist/paraglide/server.js +175 -0
  286. package/dist/server/auth.d.ts +5 -0
  287. package/dist/server/auth.js +12 -1
  288. package/dist/sveltekit/components/structured-content.svelte +204 -0
  289. package/dist/sveltekit/components/structured-content.svelte.d.ts +21 -0
  290. package/dist/sveltekit/config.d.ts +13 -3
  291. package/dist/sveltekit/index.d.ts +3 -0
  292. package/dist/sveltekit/index.js +3 -0
  293. package/dist/sveltekit/server/handle.js +1 -0
  294. package/dist/types/config.d.ts +3 -0
  295. package/dist/types/fields.d.ts +19 -2
  296. package/dist/types/index.d.ts +2 -0
  297. package/dist/types/index.js +2 -0
  298. package/dist/types/layout.d.ts +54 -0
  299. package/dist/types/layout.js +6 -0
  300. package/dist/types/structured-content.d.ts +63 -0
  301. package/dist/types/structured-content.js +1 -0
  302. package/dist/updates/0.1.4/index.d.ts +2 -0
  303. package/dist/updates/0.1.4/index.js +11 -0
  304. package/dist/updates/0.1.5/index.d.ts +2 -0
  305. package/dist/updates/0.1.5/index.js +18 -0
  306. package/dist/updates/0.2.0/index.d.ts +2 -0
  307. package/dist/updates/0.2.0/index.js +11 -0
  308. package/dist/updates/0.2.2/index.d.ts +2 -0
  309. package/dist/updates/0.2.2/index.js +13 -0
  310. package/dist/updates/0.5.0/index.d.ts +2 -0
  311. package/dist/updates/0.5.0/index.js +14 -0
  312. package/dist/updates/index.js +6 -1
  313. package/package.json +17 -10
@@ -1,31 +1,36 @@
1
1
  <script lang="ts">
2
- import Plus from '@tabler/icons-svelte/icons/plus';
3
- import Button from '../../../components/ui/button/button.svelte';
4
2
  import { getRawCollectionEntryLabel } from '../../utils/entryLabel.js';
5
3
  import { getEntryThumbnail } from '../../utils/entryThumbnail.js';
6
4
  import { getRemotes } from '../../../sveltekit/index.js';
7
5
  import type { CollectionConfigWithType } from '../../../types/collections.js';
8
6
  import DataTable from './data-table.svelte';
9
7
  import { getContentLanguage } from '../../state/content-language.svelte.js';
10
- import type { ColumnDef, RowSelectionState, SortingState, Table } from '@tanstack/table-core';
8
+ import type { ColumnDef, RowSelectionState, Table } from '@tanstack/table-core';
11
9
  import { renderComponent } from '../../../components/ui/data-table/render-helpers.js';
12
10
  import EntryLink from './entry-link.svelte';
13
11
  import type { InterfaceLanguage } from '../../../types/languages.js';
14
12
  import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
15
13
  import { getEntryStatus } from '../entry/utils.js';
16
- import * as Tabs from '../../../components/ui/tabs/index.js';
17
14
  import * as AlertDialog from '../../../components/ui/alert-dialog/index.js';
18
15
  import { toast } from 'svelte-sonner';
19
- import ArchivedActions from './archived-actions.svelte';
20
16
  import StatusBadge from './status-badge.svelte';
17
+ import A11yScoreCell from './a11y-score-cell.svelte';
18
+ import RowActions from './row-actions.svelte';
21
19
  import SortableHeader from './sortable-header.svelte';
22
20
  import DateCell from './date-cell.svelte';
23
21
  import SelectionCell from './selection-cell.svelte';
24
22
  import TableToolbar from './table-toolbar.svelte';
25
23
  import TablePagination from './table-pagination.svelte';
26
24
  import GridView from './grid-view.svelte';
25
+ import BulkActionsBar from './bulk-actions-bar.svelte';
26
+ import EmptyState from './empty-state.svelte';
27
27
  import { createCollectionViewState } from './collection-view.svelte.js';
28
- import type { EntryStatus, RawEntry } from '../../../types/entries.js';
28
+ import type { EntryStatus as EntryStatusType, RawEntry } from '../../../types/entries.js';
29
+ import {
30
+ validateA11y,
31
+ a11yLangPl,
32
+ a11yLangEn
33
+ } from '../entry/header/a11y-validator.js';
29
34
 
30
35
  const remotes = getRemotes();
31
36
  const contentLanguage = getContentLanguage();
@@ -35,70 +40,70 @@
35
40
  InterfaceLanguage,
36
41
  {
37
42
  name: string;
38
- createdAt: string;
43
+ status: string;
44
+ a11y: string;
39
45
  updatedAt: string;
40
- active: string;
41
- archived: string;
42
46
  actions: string;
43
- restore: string;
44
- delete: string;
45
- entryRestored: string;
46
- entryDeleted: string;
47
47
  selectAll: string;
48
48
  selectRow: string;
49
49
  entriesArchived: string;
50
+ entryDeleted: string;
50
51
  deleteConfirmTitle: string;
51
52
  deleteConfirmDescription: string;
52
53
  cancel: string;
54
+ delete: string;
55
+ emptyTitle: string;
56
+ emptyDescription: string;
53
57
  }
54
58
  > = {
55
59
  en: {
56
60
  name: 'Name',
57
- createdAt: 'Created At',
58
- updatedAt: 'Updated At',
59
- active: 'Active',
60
- archived: 'Archived',
61
+ status: 'Status',
62
+ a11y: 'Accessibility',
63
+ updatedAt: 'Updated',
61
64
  actions: 'Actions',
62
- restore: 'Restore',
63
- delete: 'Delete',
64
- entryRestored: 'Entry restored',
65
- entryDeleted: 'Entry permanently deleted',
66
65
  selectAll: 'Select all',
67
66
  selectRow: 'Select row',
68
67
  entriesArchived: 'Entries archived',
68
+ entryDeleted: 'Entry permanently deleted',
69
69
  deleteConfirmTitle: 'Delete entry permanently?',
70
- deleteConfirmDescription: 'This action cannot be undone. The entry will be permanently deleted.',
71
- cancel: 'Cancel'
70
+ deleteConfirmDescription:
71
+ 'This action cannot be undone. The entry will be permanently deleted.',
72
+ cancel: 'Cancel',
73
+ delete: 'Delete',
74
+ emptyTitle: 'No entries yet',
75
+ emptyDescription: 'Create your first entry to get started.'
72
76
  },
73
77
  pl: {
74
78
  name: 'Nazwa',
75
- createdAt: 'Utworzono',
79
+ status: 'Status',
80
+ a11y: 'Dostępność',
76
81
  updatedAt: 'Zaktualizowano',
77
- active: 'Aktywne',
78
- archived: 'Zarchiwizowane',
79
82
  actions: 'Akcje',
80
- restore: 'Przywróć',
81
- delete: 'Usuń',
82
- entryRestored: 'Wpis przywrócony',
83
- entryDeleted: 'Wpis trwale usunięty',
84
83
  selectAll: 'Zaznacz wszystkie',
85
84
  selectRow: 'Zaznacz wiersz',
86
85
  entriesArchived: 'Wpisy zarchiwizowane',
86
+ entryDeleted: 'Wpis trwale usunięty',
87
87
  deleteConfirmTitle: 'Usunąć wpis na stałe?',
88
88
  deleteConfirmDescription: 'Ta akcja jest nieodwracalna. Wpis zostanie trwale usunięty.',
89
- cancel: 'Anuluj'
89
+ cancel: 'Anuluj',
90
+ delete: 'Usuń',
91
+ emptyTitle: 'Brak wpisów',
92
+ emptyDescription: 'Stwórz pierwszy wpis, aby rozpocząć.'
90
93
  }
91
94
  };
92
95
 
93
96
  interface CollectionDataTableRow {
94
97
  id: string;
95
98
  name: string;
96
- status: EntryStatus;
99
+ slug?: string;
100
+ status: EntryStatusType;
97
101
  createdAt: Date;
98
102
  updatedAt: Date;
99
103
  url: string;
100
104
  thumbnail: string | null;
101
105
  searchText: string;
106
+ a11yWarnings: number;
102
107
  }
103
108
 
104
109
  type Props = {
@@ -117,44 +122,45 @@
117
122
  let deleteDialogOpen = $state(false);
118
123
  let pendingDeleteId = $state<string | null>(null);
119
124
 
125
+ // Find seo field for slug extraction
126
+ const seoField = $derived(collection.fields.find((f) => f.type === 'seo'));
127
+
120
128
  // Determine if we need fetch-all fallback (search active or sorting by name)
121
129
  const isSortingByName = $derived(
122
130
  viewState.sorting.length > 0 && viewState.sorting[0].id === 'name'
123
131
  );
124
132
  const useServerPagination = $derived(!searchQuery && !isSortingByName);
125
133
 
134
+ // Is the current filter for archived entries?
135
+ const isArchivedFilter = $derived(viewState.statusFilter === 'archived');
136
+
126
137
  // Build orderBy from sorting state for server-side mode
127
138
  const serverOrderBy = $derived.by(() => {
128
139
  if (!viewState.sorting.length) return undefined;
129
140
  const { id, desc } = viewState.sorting[0];
130
141
  if (id === 'createdAt' || id === 'updatedAt') {
131
- return { column: id as 'createdAt' | 'updatedAt', direction: (desc ? 'desc' : 'asc') as 'asc' | 'desc' };
142
+ return {
143
+ column: id as 'createdAt' | 'updatedAt',
144
+ direction: (desc ? 'desc' : 'asc') as 'asc' | 'desc'
145
+ };
132
146
  }
133
147
  return undefined;
134
148
  });
135
149
 
136
150
  // Server-side query params
137
- const activeQueryParams = $derived(
151
+ const queryParams = $derived(
138
152
  useServerPagination
139
153
  ? {
140
154
  slug: collection.slug,
155
+ ...(isArchivedFilter ? { onlyArchived: true as const } : {}),
141
156
  limit: viewState.pageSize,
142
157
  offset: viewState.pageIndex * viewState.pageSize,
143
158
  orderBy: serverOrderBy
144
159
  }
145
- : { slug: collection.slug }
146
- );
147
-
148
- const archivedQueryParams = $derived(
149
- useServerPagination
150
- ? {
160
+ : {
151
161
  slug: collection.slug,
152
- onlyArchived: true as const,
153
- limit: viewState.pageSize,
154
- offset: viewState.pageIndex * viewState.pageSize,
155
- orderBy: serverOrderBy
162
+ ...(isArchivedFilter ? { onlyArchived: true as const } : {})
156
163
  }
157
- : { slug: collection.slug, onlyArchived: true as const }
158
164
  );
159
165
 
160
166
  const columns: ColumnDef<CollectionDataTableRow>[] = $derived([
@@ -174,7 +180,8 @@
174
180
  ariaLabel: lang[interfaceLanguage.current].selectRow
175
181
  }),
176
182
  enableSorting: false,
177
- enableHiding: false
183
+ enableHiding: false,
184
+ size: 40
178
185
  },
179
186
  {
180
187
  accessorKey: 'name',
@@ -187,32 +194,30 @@
187
194
  cell: (info) => {
188
195
  return renderComponent(EntryLink, {
189
196
  name: info.row.original.name,
190
- url: info.row.original.url
197
+ url: info.row.original.url,
198
+ slug: info.row.original.slug?.[interfaceLanguage.current]
191
199
  });
192
200
  }
193
201
  },
194
202
  {
195
203
  accessorKey: 'status',
196
- header: 'Status',
204
+ header: lang[interfaceLanguage.current].status,
197
205
  cell: (info) =>
198
206
  renderComponent(StatusBadge, {
199
207
  status: info.row.original.status
200
208
  }),
201
- enableSorting: false
209
+ enableSorting: false,
210
+ size: 130
202
211
  },
203
212
  {
204
- accessorKey: 'createdAt',
205
- header: ({ column }) =>
206
- renderComponent(SortableHeader<CollectionDataTableRow>, {
207
- column,
208
- label: lang[interfaceLanguage.current].createdAt,
209
- sorting: viewState.sorting
210
- }),
213
+ id: 'a11y',
214
+ header: lang[interfaceLanguage.current].a11y,
211
215
  cell: (info) =>
212
- renderComponent(DateCell, {
213
- date: info.row.original.createdAt,
214
- format: viewState.dateFormat
215
- })
216
+ renderComponent(A11yScoreCell, {
217
+ warningCount: info.row.original.a11yWarnings
218
+ }),
219
+ enableSorting: false,
220
+ size: 130
216
221
  },
217
222
  {
218
223
  accessorKey: 'updatedAt',
@@ -225,61 +230,32 @@
225
230
  cell: (info) =>
226
231
  renderComponent(DateCell, {
227
232
  date: info.row.original.updatedAt,
228
- format: viewState.dateFormat
229
- })
230
- }
231
- ]);
232
-
233
- interface ArchivedDataTableRow extends CollectionDataTableRow {
234
- onRestore: () => void;
235
- onDelete: () => void;
236
- }
237
-
238
- const archivedColumns: ColumnDef<ArchivedDataTableRow>[] = $derived([
239
- {
240
- accessorKey: 'name',
241
- header: lang[interfaceLanguage.current].name
242
- },
243
- {
244
- accessorKey: 'createdAt',
245
- header: lang[interfaceLanguage.current].createdAt,
246
- cell: (info) =>
247
- renderComponent(DateCell, {
248
- date: info.row.original.createdAt,
249
- format: viewState.dateFormat
250
- })
251
- },
252
- {
253
- accessorKey: 'updatedAt',
254
- header: lang[interfaceLanguage.current].updatedAt,
255
- cell: (info) =>
256
- renderComponent(DateCell, {
257
- date: info.row.original.updatedAt,
258
- format: viewState.dateFormat
259
- })
233
+ format: 'short'
234
+ }),
235
+ size: 140
260
236
  },
261
237
  {
262
238
  id: 'actions',
263
- header: lang[interfaceLanguage.current].actions,
264
- cell: (info) => {
265
- return renderComponent(ArchivedActions, {
266
- restoreLabel: lang[interfaceLanguage.current].restore,
267
- deleteLabel: lang[interfaceLanguage.current].delete,
268
- onRestore: info.row.original.onRestore,
269
- onDelete: info.row.original.onDelete
270
- });
271
- }
239
+ header: '',
240
+ cell: (info) =>
241
+ renderComponent(RowActions, {
242
+ entryUrl: info.row.original.url,
243
+ entryName: info.row.original.name,
244
+ onArchive: () => handleArchiveSingle(info.row.original.id),
245
+ onDelete: () => handleDelete(info.row.original.id)
246
+ }),
247
+ enableSorting: false,
248
+ size: 50
272
249
  }
273
250
  ]);
274
251
 
275
252
  function refreshQueries() {
276
- remotes.getRawEntries(activeQueryParams).refresh();
277
- remotes.getRawEntries(archivedQueryParams).refresh();
253
+ remotes.getRawEntries(queryParams).refresh();
278
254
  }
279
255
 
280
- async function handleRestore(id: string) {
281
- await remotes.unarchiveEntryCommand(id);
282
- toast.success(lang[interfaceLanguage.current].entryRestored);
256
+ async function handleArchiveSingle(id: string) {
257
+ await remotes.archiveEntryCommand(id);
258
+ toast.success(lang[interfaceLanguage.current].entriesArchived);
283
259
  refreshQueries();
284
260
  }
285
261
 
@@ -321,24 +297,52 @@
321
297
  return values;
322
298
  }
323
299
 
300
+ function extractSlug(entry: RawEntry): string | undefined {
301
+ if (!seoField) return undefined;
302
+ const data = entry.draftVersion?.data || entry.publishedVersion?.data;
303
+ if (!data) return undefined;
304
+ const seoData = data[seoField.slug];
305
+ if (seoData && typeof seoData === 'object' && 'slug' in seoData) {
306
+ return (seoData as { slug?: string }).slug || undefined;
307
+ }
308
+ return undefined;
309
+ }
310
+
311
+ function countA11yWarnings(entry: RawEntry): number {
312
+ const data = entry.draftVersion?.data || entry.publishedVersion?.data;
313
+ if (!data) return 0;
314
+ const a11yLang = interfaceLanguage.current === 'pl' ? a11yLangPl : a11yLangEn;
315
+ const issues = validateA11y(data as Record<string, unknown>, collection.fields, a11yLang);
316
+ return issues.filter((i) => i.type === 'warning').length;
317
+ }
318
+
324
319
  function mapEntryToRow(entry: RawEntry): CollectionDataTableRow {
325
320
  const data = entry.draftVersion?.data || entry.publishedVersion?.data || {};
326
321
  return {
327
322
  id: entry.id,
328
323
  name: getRawCollectionEntryLabel(entry, collection, contentLanguage.current),
324
+ slug: extractSlug(entry),
329
325
  url: `/admin/entries/${entry.id}`,
330
326
  status: getEntryStatus(entry),
331
327
  createdAt: new Date(entry.createdAt),
332
328
  updatedAt: new Date(entry.updatedAt),
333
329
  thumbnail: getEntryThumbnail(data as Record<string, unknown>, collection),
334
- searchText: getSearchText(entry)
330
+ searchText: getSearchText(entry),
331
+ a11yWarnings: countA11yWarnings(entry)
335
332
  };
336
333
  }
337
334
 
338
- const selectedIndices = $derived(Object.keys(rowSelection).filter((k) => rowSelection[k]).map(Number));
335
+ const selectedIndices = $derived(
336
+ Object.keys(rowSelection)
337
+ .filter((k) => rowSelection[k])
338
+ .map(Number)
339
+ );
339
340
  const selectedCount = $derived(selectedIndices.length);
340
341
 
341
- function sortItems<T extends CollectionDataTableRow>(items: T[], sorting: SortingState): T[] {
342
+ function sortItems<T extends CollectionDataTableRow>(
343
+ items: T[],
344
+ sorting: typeof viewState.sorting
345
+ ): T[] {
342
346
  if (!sorting.length) return items;
343
347
  const { id, desc } = sorting[0];
344
348
  return [...items].sort((a, b) => {
@@ -354,6 +358,19 @@
354
358
  });
355
359
  }
356
360
 
361
+ function filterByStatus(items: CollectionDataTableRow[]): CollectionDataTableRow[] {
362
+ const filter = viewState.statusFilter;
363
+ // null = all non-archived, 'all' = everything, 'archived' handled by server
364
+ if (filter === null) {
365
+ return items.filter((item) => item.status !== 'archived');
366
+ }
367
+ if (filter === 'all' || filter === 'archived') {
368
+ return items;
369
+ }
370
+ // Specific status: published, draft, scheduled
371
+ return items.filter((item) => item.status === filter);
372
+ }
373
+
357
374
  async function handleBulkArchive(items: CollectionDataTableRow[]) {
358
375
  const idsToArchive = selectedIndices.map((idx) => items[idx]?.id).filter(Boolean);
359
376
  for (const id of idsToArchive) {
@@ -364,64 +381,82 @@
364
381
  refreshQueries();
365
382
  }
366
383
 
384
+ async function handleBulkDelete(items: CollectionDataTableRow[]) {
385
+ const idsToDelete = selectedIndices.map((idx) => items[idx]?.id).filter(Boolean);
386
+ for (const id of idsToDelete) {
387
+ await remotes.deleteEntryCommand(id);
388
+ }
389
+ toast.success(lang[interfaceLanguage.current].entryDeleted);
390
+ rowSelection = {};
391
+ refreshQueries();
392
+ }
367
393
  </script>
368
394
 
369
- <Tabs.Root
370
- value={viewState.activeTab}
371
- onValueChange={(v) => {
372
- if (v === 'active' || v === 'archived') viewState.activeTab = v;
373
- }}
374
- class="w-full"
375
- >
376
- <div class="flex items-center justify-between border-b border-slate-200/50 px-4 py-3 dark:border-white/10">
377
- <Tabs.List class="h-auto gap-1 bg-transparent p-0">
378
- <Tabs.Trigger value="active" class="rounded-lg px-3 py-1.5 text-sm font-medium data-[state=active]:bg-slate-100 data-[state=active]:text-slate-900 dark:data-[state=active]:bg-slate-800 dark:data-[state=active]:text-white">{lang[interfaceLanguage.current].active}</Tabs.Trigger>
379
- <Tabs.Trigger value="archived" class="rounded-lg px-3 py-1.5 text-sm font-medium data-[state=active]:bg-slate-100 data-[state=active]:text-slate-900 dark:data-[state=active]:bg-slate-800 dark:data-[state=active]:text-white">{lang[interfaceLanguage.current].archived}</Tabs.Trigger>
380
- </Tabs.List>
381
- <Button type="button" onclick={onCreateEntry} variant="gradient" size="sm">
382
- <Plus class="size-4" /> {addLabel}
383
- </Button>
384
- </div>
385
-
386
- <Tabs.Content value="active" class="mt-0">
387
- {#await remotes.getRawEntries(activeQueryParams) then result}
388
- {@const allRows = result.entries.map(mapEntryToRow)}
389
- {@const items = useServerPagination
390
- ? allRows
391
- : (() => {
392
- let filtered = searchQuery
393
- ? allRows.filter((item) => item.searchText.includes(searchQuery.toLowerCase()))
394
- : allRows;
395
- return sortItems(filtered, viewState.sorting);
396
- })()}
397
- {@const totalItems = useServerPagination ? result.total : items.length}
398
- {@const pageCount = Math.ceil(totalItems / viewState.pageSize)}
399
-
400
- <TableToolbar
401
- {searchQuery}
402
- onSearchChange={(q) => {
403
- searchQuery = q;
404
- viewState.pageIndex = 0;
405
- }}
406
- viewMode={viewState.viewMode}
407
- onViewModeChange={(m) => (viewState.viewMode = m)}
408
- dateFormat={viewState.dateFormat}
409
- onDateFormatChange={(f) => (viewState.dateFormat = f)}
410
- {selectedCount}
411
- onBulkArchive={() => handleBulkArchive(items)}
395
+ {#key JSON.stringify(queryParams)}
396
+ {#await remotes.getRawEntries(queryParams) then result}
397
+ {@const allRows = result.entries.map(mapEntryToRow)}
398
+ {@const filteredRows = (() => {
399
+ let rows = allRows;
400
+ // Client-side status filter (non-archived statuses)
401
+ if (!isArchivedFilter) {
402
+ rows = filterByStatus(rows);
403
+ }
404
+ // Client-side search
405
+ if (searchQuery) {
406
+ rows = rows.filter((item) => item.searchText.includes(searchQuery.toLowerCase()));
407
+ }
408
+ // Client-side sort (if sorting by name)
409
+ if (!useServerPagination) {
410
+ rows = sortItems(rows, viewState.sorting);
411
+ }
412
+ return rows;
413
+ })()}
414
+ {@const totalItems =
415
+ useServerPagination && !viewState.statusFilter && viewState.statusFilter !== 'archived'
416
+ ? result.total
417
+ : filteredRows.length}
418
+ {@const pageCount = Math.ceil(totalItems / viewState.pageSize)}
419
+ {@const displayItems =
420
+ useServerPagination && !viewState.statusFilter
421
+ ? filteredRows
422
+ : filteredRows.slice(
423
+ viewState.pageIndex * viewState.pageSize,
424
+ (viewState.pageIndex + 1) * viewState.pageSize
425
+ )}
426
+
427
+ <TableToolbar
428
+ {searchQuery}
429
+ onSearchChange={(q) => {
430
+ searchQuery = q;
431
+ viewState.pageIndex = 0;
432
+ }}
433
+ statusFilter={viewState.statusFilter}
434
+ onStatusFilterChange={(f) => (viewState.statusFilter = f)}
435
+ viewMode={viewState.viewMode}
436
+ onViewModeChange={(m) => (viewState.viewMode = m)}
437
+ {onCreateEntry}
438
+ createLabel={addLabel}
439
+ />
440
+
441
+ {#if totalItems === 0 && !searchQuery}
442
+ <EmptyState
443
+ title={lang[interfaceLanguage.current].emptyTitle}
444
+ description={lang[interfaceLanguage.current].emptyDescription}
445
+ ctaLabel={addLabel}
446
+ onCta={onCreateEntry}
412
447
  />
413
-
414
- {#if viewState.viewMode === 'list'}
415
- {#if useServerPagination}
448
+ {:else if viewState.viewMode === 'list'}
449
+ <div class="bg-card overflow-hidden rounded-xl border shadow-sm">
450
+ {#if useServerPagination && !viewState.statusFilter}
416
451
  <DataTable
417
- data={items}
452
+ data={displayItems}
418
453
  {columns}
419
454
  enableSorting
420
455
  enableFiltering
421
456
  enableSelection
422
457
  enablePagination
423
458
  manualPagination={true}
424
- pageCount={pageCount}
459
+ {pageCount}
425
460
  rowCount={totalItems}
426
461
  sorting={viewState.sorting}
427
462
  onSortingChange={(s) => (viewState.sorting = s)}
@@ -435,7 +470,7 @@
435
470
  />
436
471
  {:else}
437
472
  <DataTable
438
- data={items}
473
+ data={displayItems}
439
474
  {columns}
440
475
  enableSorting
441
476
  enableFiltering
@@ -452,113 +487,77 @@
452
487
  tableRef={(t) => (tableInstance = t)}
453
488
  />
454
489
  {/if}
490
+ </div>
491
+
492
+ <TablePagination
493
+ pageIndex={viewState.pageIndex}
494
+ pageSize={viewState.pageSize}
495
+ {pageCount}
496
+ {totalItems}
497
+ onPageChange={(p) => (viewState.pageIndex = p)}
498
+ onPageSizeChange={(s) => {
499
+ viewState.pageSize = s;
500
+ }}
501
+ />
502
+ {:else}
503
+ {@const gridItems = displayItems.map((item) => ({
504
+ id: item.id,
505
+ name: item.name,
506
+ slug: item.slug,
507
+ status: item.status,
508
+ url: item.url,
509
+ thumbnail: item.thumbnail,
510
+ updatedAt: item.updatedAt
511
+ }))}
455
512
 
456
- <TablePagination
457
- pageIndex={viewState.pageIndex}
458
- pageSize={viewState.pageSize}
459
- {pageCount}
460
- {totalItems}
461
- onPageChange={(p) => (viewState.pageIndex = p)}
462
- onPageSizeChange={(s) => {
463
- viewState.pageSize = s;
464
- }}
465
- />
466
- {:else}
467
- {@const displayItems = useServerPagination
468
- ? items
469
- : items.slice(
470
- viewState.pageIndex * viewState.pageSize,
471
- (viewState.pageIndex + 1) * viewState.pageSize
472
- )}
473
- <GridView
474
- items={displayItems.map((item) => ({
475
- id: item.id,
476
- name: item.name,
477
- status: item.status,
478
- url: item.url,
479
- thumbnail: item.thumbnail,
480
- updatedAt: item.updatedAt
481
- }))}
482
- dateFormat={viewState.dateFormat}
483
- enableSelection
484
- selectedIds={new Set(selectedIndices.map((idx) => items[idx]?.id).filter(Boolean))}
485
- onSelectionChange={(ids) => {
486
- const newSelection: RowSelectionState = {};
487
- for (const id of ids) {
488
- const idx = items.findIndex((i) => i.id === id);
489
- if (idx !== -1) {
490
- newSelection[idx] = true;
491
- }
513
+ <GridView
514
+ items={gridItems}
515
+ enableSelection
516
+ selectedIds={new Set(selectedIndices.map((idx) => displayItems[idx]?.id).filter(Boolean))}
517
+ onSelectionChange={(ids) => {
518
+ const newSelection: RowSelectionState = {};
519
+ for (const id of ids) {
520
+ const idx = displayItems.findIndex((i) => i.id === id);
521
+ if (idx !== -1) {
522
+ newSelection[idx] = true;
492
523
  }
493
- rowSelection = newSelection;
494
- }}
495
- />
496
-
497
- <TablePagination
498
- pageIndex={viewState.pageIndex}
499
- pageSize={viewState.pageSize}
500
- {pageCount}
501
- {totalItems}
502
- onPageChange={(p) => (viewState.pageIndex = p)}
503
- onPageSizeChange={(s) => {
504
- viewState.pageSize = s;
505
- }}
506
- />
507
- {/if}
508
- {/await}
509
- </Tabs.Content>
510
-
511
- <Tabs.Content value="archived" class="mt-0">
512
- {#await remotes.getRawEntries(archivedQueryParams) then result}
513
- {@const items = result.entries.map((entry) => ({
514
- ...mapEntryToRow(entry),
515
- onRestore: () => handleRestore(entry.id),
516
- onDelete: () => handleDelete(entry.id)
517
- }))}
518
- {@const totalItems = result.total}
519
- {@const pageCount = Math.ceil(totalItems / viewState.pageSize)}
524
+ }
525
+ rowSelection = newSelection;
526
+ }}
527
+ />
520
528
 
521
- {#if useServerPagination}
522
- <div class="p-4">
523
- <DataTable
524
- data={items}
525
- columns={archivedColumns}
526
- manualPagination={true}
527
- pageCount={pageCount}
528
- rowCount={totalItems}
529
- enablePagination
530
- pagination={{ pageIndex: viewState.pageIndex, pageSize: viewState.pageSize }}
531
- onPaginationChange={(p) => {
532
- viewState.pageIndex = p.pageIndex;
533
- }}
534
- />
535
- </div>
536
- <TablePagination
537
- pageIndex={viewState.pageIndex}
538
- pageSize={viewState.pageSize}
539
- {pageCount}
540
- {totalItems}
541
- onPageChange={(p) => (viewState.pageIndex = p)}
542
- onPageSizeChange={(s) => {
543
- viewState.pageSize = s;
544
- }}
545
- />
546
- {:else}
547
- <div class="p-4">
548
- <DataTable data={items} columns={archivedColumns} />
549
- </div>
550
- {/if}
551
- {/await}
552
- </Tabs.Content>
553
- </Tabs.Root>
529
+ <TablePagination
530
+ pageIndex={viewState.pageIndex}
531
+ pageSize={viewState.pageSize}
532
+ {pageCount}
533
+ {totalItems}
534
+ onPageChange={(p) => (viewState.pageIndex = p)}
535
+ onPageSizeChange={(s) => {
536
+ viewState.pageSize = s;
537
+ }}
538
+ />
539
+ {/if}
540
+
541
+ <BulkActionsBar
542
+ {selectedCount}
543
+ onArchive={() => handleBulkArchive(displayItems)}
544
+ onDelete={() => handleBulkDelete(displayItems)}
545
+ onClear={() => (rowSelection = {})}
546
+ />
547
+ {/await}
548
+ {/key}
554
549
 
555
550
  <AlertDialog.Root bind:open={deleteDialogOpen}>
556
551
  <AlertDialog.Content>
557
552
  <AlertDialog.Title>{lang[interfaceLanguage.current].deleteConfirmTitle}</AlertDialog.Title>
558
- <AlertDialog.Description>{lang[interfaceLanguage.current].deleteConfirmDescription}</AlertDialog.Description>
553
+ <AlertDialog.Description
554
+ >{lang[interfaceLanguage.current].deleteConfirmDescription}</AlertDialog.Description
555
+ >
559
556
  <AlertDialog.Footer>
560
557
  <AlertDialog.Cancel>{lang[interfaceLanguage.current].cancel}</AlertDialog.Cancel>
561
- <AlertDialog.Action onclick={confirmDelete}>{lang[interfaceLanguage.current].delete}</AlertDialog.Action>
558
+ <AlertDialog.Action onclick={confirmDelete}
559
+ >{lang[interfaceLanguage.current].delete}</AlertDialog.Action
560
+ >
562
561
  </AlertDialog.Footer>
563
562
  </AlertDialog.Content>
564
563
  </AlertDialog.Root>