includio-cms 0.1.4 → 0.5.1

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