includio-cms 0.1.4 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/ROADMAP.md +18 -13
  3. package/dist/admin/api/accept-invite.js +1 -5
  4. package/dist/admin/api/invite.js +7 -16
  5. package/dist/admin/client/account/account-page.svelte +20 -50
  6. package/dist/admin/client/account/lang.d.ts +15 -23
  7. package/dist/admin/client/account/lang.js +51 -67
  8. package/dist/admin/client/account/preferences-section.svelte +26 -84
  9. package/dist/admin/client/account/profile-section.svelte +60 -40
  10. package/dist/admin/client/account/schema.d.ts +11 -3
  11. package/dist/admin/client/account/schema.js +25 -16
  12. package/dist/admin/client/account/security-section.svelte +139 -105
  13. package/dist/admin/client/account/sessions-section.svelte +35 -34
  14. package/dist/admin/client/admin/admin-after-login-layout-content.svelte +3 -5
  15. package/dist/admin/client/admin/admin-layout.svelte +3 -2
  16. package/dist/admin/client/admin/admin-preloader.svelte +36 -0
  17. package/dist/admin/client/admin/admin-preloader.svelte.d.ts +18 -0
  18. package/dist/admin/client/admin/dashboard-page.svelte +55 -41
  19. package/dist/admin/client/collection/a11y-score-cell.svelte +45 -0
  20. package/dist/admin/client/collection/a11y-score-cell.svelte.d.ts +6 -0
  21. package/dist/admin/client/collection/bulk-actions-bar.svelte +83 -0
  22. package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +9 -0
  23. package/dist/admin/client/collection/collection-entries.svelte +255 -260
  24. package/dist/admin/client/collection/collection-view.svelte.d.ts +4 -3
  25. package/dist/admin/client/collection/collection-view.svelte.js +9 -5
  26. package/dist/admin/client/collection/collection.svelte +22 -12
  27. package/dist/admin/client/collection/data-table.svelte +50 -39
  28. package/dist/admin/client/collection/data-table.svelte.d.ts +1 -0
  29. package/dist/admin/client/collection/date-cell.svelte +7 -5
  30. package/dist/admin/client/collection/date-cell.svelte.d.ts +1 -1
  31. package/dist/admin/client/collection/empty-state.svelte +28 -0
  32. package/dist/admin/client/collection/empty-state.svelte.d.ts +9 -0
  33. package/dist/admin/client/collection/entry-link.svelte +10 -4
  34. package/dist/admin/client/collection/entry-link.svelte.d.ts +1 -0
  35. package/dist/admin/client/collection/grid-view.svelte +21 -23
  36. package/dist/admin/client/collection/grid-view.svelte.d.ts +1 -2
  37. package/dist/admin/client/collection/row-actions.svelte +60 -0
  38. package/dist/admin/client/collection/row-actions.svelte.d.ts +9 -0
  39. package/dist/admin/client/collection/status-badge.svelte +7 -8
  40. package/dist/admin/client/collection/table-pagination.svelte +122 -79
  41. package/dist/admin/client/collection/table-pagination.svelte.d.ts +1 -0
  42. package/dist/admin/client/collection/table-toolbar.svelte +108 -88
  43. package/dist/admin/client/collection/table-toolbar.svelte.d.ts +8 -9
  44. package/dist/admin/client/entry/entry-form.svelte +109 -1
  45. package/dist/admin/client/entry/entry-header.svelte +96 -37
  46. package/dist/admin/client/entry/entry-header.svelte.d.ts +5 -0
  47. package/dist/admin/client/entry/entry.svelte +171 -60
  48. package/dist/admin/client/entry/header/a11y-validator.d.ts +46 -0
  49. package/dist/admin/client/entry/header/a11y-validator.js +311 -0
  50. package/dist/admin/client/entry/header/publish-panel.svelte +373 -131
  51. package/dist/admin/client/entry/header/publish-panel.svelte.d.ts +4 -0
  52. package/dist/admin/client/entry/header/save-indicator.svelte +33 -23
  53. package/dist/admin/client/entry/header/schedule-popover.svelte +1 -1
  54. package/dist/admin/client/entry/header/status-badge.svelte +25 -118
  55. package/dist/admin/client/entry/header/version-history-sheet.svelte +314 -98
  56. package/dist/admin/client/form/form-submission/form-submission.svelte +271 -83
  57. package/dist/admin/client/form/form-submission/submission-field.svelte +12 -12
  58. package/dist/admin/client/form/form-submissions.svelte +421 -139
  59. package/dist/admin/client/form/submission-link.svelte +8 -2
  60. package/dist/admin/client/form/submission-link.svelte.d.ts +1 -0
  61. package/dist/admin/client/form/submission-status-badge.svelte +18 -4
  62. package/dist/admin/client/form/submission-status-badge.svelte.d.ts +1 -0
  63. package/dist/admin/client/login/lang.d.ts +32 -0
  64. package/dist/admin/client/login/lang.js +66 -2
  65. package/dist/admin/client/login/login-form.svelte +237 -95
  66. package/dist/admin/client/login/login-form.svelte.d.ts +2 -17
  67. package/dist/admin/client/login/login-page.svelte +34 -98
  68. package/dist/admin/client/login/reset-password-page.svelte +235 -0
  69. package/dist/admin/client/login/reset-password-page.svelte.d.ts +4 -0
  70. package/dist/admin/client/login/schema.d.ts +15 -0
  71. package/dist/admin/client/login/schema.js +21 -0
  72. package/dist/admin/client/users/accept-invite-page.svelte +166 -37
  73. package/dist/admin/client/users/create-user-dialog.svelte +15 -7
  74. package/dist/admin/client/users/delete-user-dialog.svelte +81 -16
  75. package/dist/admin/client/users/delete-user-dialog.svelte.d.ts +4 -1
  76. package/dist/admin/client/users/edit-user-dialog.svelte +3 -0
  77. package/dist/admin/client/users/invite-user-dialog.svelte +16 -3
  78. package/dist/admin/client/users/lang.d.ts +27 -0
  79. package/dist/admin/client/users/lang.js +64 -10
  80. package/dist/admin/client/users/pending-invitations.svelte +59 -23
  81. package/dist/admin/client/users/users-page.svelte +471 -72
  82. package/dist/admin/components/accessibility/accessibility-overview.svelte +2 -7
  83. package/dist/admin/components/dashboard/a11y-gauge.svelte +90 -0
  84. package/dist/admin/components/dashboard/a11y-gauge.svelte.d.ts +18 -0
  85. package/dist/admin/components/dashboard/accessibility-hub.svelte +13 -12
  86. package/dist/admin/components/dashboard/form-submissions-widget.svelte +71 -113
  87. package/dist/admin/components/dashboard/index.d.ts +4 -2
  88. package/dist/admin/components/dashboard/index.js +4 -2
  89. package/dist/admin/components/dashboard/recent-activity.svelte +53 -75
  90. package/dist/admin/components/dashboard/recent-entries.svelte +94 -0
  91. package/dist/admin/components/dashboard/recent-entries.svelte.d.ts +18 -0
  92. package/dist/admin/components/dashboard/stat-card.svelte +2 -2
  93. package/dist/admin/components/dashboard/tip-of-the-day.svelte +109 -0
  94. package/dist/admin/components/dashboard/tip-of-the-day.svelte.d.ts +3 -0
  95. package/dist/admin/components/dashboard/welcome-header.svelte +45 -0
  96. package/dist/admin/components/dashboard/welcome-header.svelte.d.ts +3 -0
  97. package/dist/admin/components/fields/{array-field.svelte → blocks-field.svelte} +4 -4
  98. package/dist/admin/components/fields/{array-field.svelte.d.ts → blocks-field.svelte.d.ts} +5 -5
  99. package/dist/admin/components/fields/content-field.svelte +27 -0
  100. package/dist/admin/components/fields/content-field.svelte.d.ts +31 -0
  101. package/dist/admin/components/fields/field-renderer.svelte +9 -7
  102. package/dist/admin/components/fields/image-field.svelte +2 -2
  103. package/dist/admin/components/fields/media-field.svelte +2 -2
  104. package/dist/admin/components/fields/seo-field.svelte +205 -25
  105. package/dist/admin/components/fields/simple-array-field.svelte +289 -0
  106. package/dist/admin/components/fields/simple-array-field.svelte.d.ts +30 -0
  107. package/dist/admin/components/fields/slug-field.svelte +3 -2
  108. package/dist/admin/components/fields/standalone-field-renderer.svelte +148 -0
  109. package/dist/admin/components/fields/standalone-field-renderer.svelte.d.ts +9 -0
  110. package/dist/admin/components/fields/text-field-wrapper.svelte +13 -1
  111. package/dist/admin/components/fields/text-field-wrapper.svelte.d.ts +2 -2
  112. package/dist/admin/components/fields/url-field.svelte +5 -4
  113. package/dist/admin/components/layout/app-sidebar.svelte +27 -24
  114. package/dist/admin/components/layout/lang.d.ts +6 -0
  115. package/dist/admin/components/layout/lang.js +13 -1
  116. package/dist/admin/components/layout/layout-renderer.svelte +352 -0
  117. package/dist/admin/components/layout/layout-renderer.svelte.d.ts +14 -0
  118. package/dist/admin/components/layout/nav-breadcrumbs.svelte +4 -4
  119. package/dist/admin/components/layout/nav-collections.svelte +65 -36
  120. package/dist/admin/components/layout/nav-footer.svelte +31 -0
  121. package/dist/admin/components/layout/nav-footer.svelte.d.ts +18 -0
  122. package/dist/admin/components/layout/nav-forms.svelte +55 -30
  123. package/dist/admin/components/layout/nav-main.svelte +14 -52
  124. package/dist/admin/components/layout/nav-search.svelte +4 -3
  125. package/dist/admin/components/layout/nav-singletons.svelte +59 -17
  126. package/dist/admin/components/layout/nav-singletons.svelte.d.ts +17 -8
  127. package/dist/admin/components/layout/site-header.svelte +74 -13
  128. package/dist/admin/components/media/alt-input.svelte +32 -22
  129. package/dist/admin/components/media/bulk-action-bar.svelte +139 -150
  130. package/dist/admin/components/media/file/file-details.svelte +299 -217
  131. package/dist/admin/components/media/file/file-miniature.svelte +54 -41
  132. package/dist/admin/components/media/file/file-miniature.svelte.d.ts +1 -0
  133. package/dist/admin/components/media/file/file-preview.svelte +1 -1
  134. package/dist/admin/components/media/file-upload.svelte +24 -26
  135. package/dist/admin/components/media/files-list.svelte +112 -40
  136. package/dist/admin/components/media/files-list.svelte.d.ts +2 -0
  137. package/dist/admin/components/media/focal-point-input.svelte +122 -26
  138. package/dist/admin/components/media/media-library.svelte +127 -70
  139. package/dist/admin/components/media/media-search.svelte +6 -6
  140. package/dist/admin/components/media/media-sort.svelte +3 -1
  141. package/dist/admin/components/media/multi-file-summary.svelte +88 -68
  142. package/dist/admin/components/media/tag-combobox.svelte +141 -66
  143. package/dist/admin/components/media/tag-combobox.svelte.d.ts +1 -0
  144. package/dist/admin/components/media/tag-sidebar.svelte +139 -121
  145. package/dist/admin/components/tiptap/FigureNodeView.svelte +144 -15
  146. package/dist/admin/components/tiptap/InlineBlockNodeView.svelte +254 -0
  147. package/dist/admin/components/tiptap/InlineBlockNodeView.svelte.d.ts +4 -0
  148. package/dist/admin/components/tiptap/SlashCommandPopup.svelte +212 -0
  149. package/dist/admin/components/tiptap/SlashCommandPopup.svelte.d.ts +8 -0
  150. package/dist/admin/components/tiptap/content-editor.svelte +280 -0
  151. package/dist/admin/components/tiptap/content-editor.svelte.d.ts +9 -0
  152. package/dist/admin/components/tiptap/editor-toolbar.svelte +230 -0
  153. package/dist/admin/components/tiptap/editor-toolbar.svelte.d.ts +16 -0
  154. package/dist/admin/components/tiptap/heading-a11y-plugin.d.ts +2 -0
  155. package/dist/admin/components/tiptap/heading-a11y-plugin.js +67 -0
  156. package/dist/admin/components/tiptap/image-dialog.svelte +172 -11
  157. package/dist/admin/components/tiptap/inline-block-node.d.ts +19 -0
  158. package/dist/admin/components/tiptap/inline-block-node.js +98 -0
  159. package/dist/admin/components/tiptap/link-dialog.svelte +9 -4
  160. package/dist/admin/components/tiptap/slash-command.d.ts +17 -0
  161. package/dist/admin/components/tiptap/slash-command.js +181 -0
  162. package/dist/admin/components/tiptap/structured-content-utils.d.ts +21 -0
  163. package/dist/admin/components/tiptap/structured-content-utils.js +150 -0
  164. package/dist/admin/components/tiptap/tiptap-editor.svelte +18 -190
  165. package/dist/admin/email/invite-template.d.ts +8 -0
  166. package/dist/admin/email/invite-template.js +99 -0
  167. package/dist/admin/email/reset-password-template.d.ts +7 -0
  168. package/dist/admin/email/reset-password-template.js +96 -0
  169. package/dist/admin/remote/ai.remote.d.ts +1 -0
  170. package/dist/admin/remote/ai.remote.js +4 -1
  171. package/dist/admin/remote/entry.remote.d.ts +8 -0
  172. package/dist/admin/remote/entry.remote.js +53 -4
  173. package/dist/admin/remote/preview.remote.js +2 -1
  174. package/dist/admin/shared/password-schema.d.ts +5 -0
  175. package/dist/admin/shared/password-schema.js +10 -0
  176. package/dist/admin/styles/admin.css +1530 -151
  177. package/dist/admin/utils/formatDate.d.ts +1 -0
  178. package/dist/admin/utils/formatDate.js +8 -0
  179. package/dist/admin/utils/roleLabel.d.ts +2 -0
  180. package/dist/admin/utils/roleLabel.js +13 -0
  181. package/dist/ai-claude/index.d.ts +2 -0
  182. package/dist/ai-claude/index.js +56 -0
  183. package/dist/cms/runtime/api.d.ts +6 -1
  184. package/dist/cms/runtime/api.js +3 -0
  185. package/dist/cms/runtime/schemas.d.ts +9 -1
  186. package/dist/cms/runtime/schemas.js +8 -0
  187. package/dist/cms/runtime/types.d.ts +82 -10
  188. package/dist/cms/runtime/types.js +4 -0
  189. package/dist/components/ui/accordion/accordion.stories.svelte +39 -0
  190. package/dist/components/ui/accordion/accordion.stories.svelte.d.ts +27 -0
  191. package/dist/components/ui/alert/alert.stories.svelte +53 -0
  192. package/dist/components/ui/alert/alert.stories.svelte.d.ts +27 -0
  193. package/dist/components/ui/alert/alert.svelte +5 -0
  194. package/dist/components/ui/alert/alert.svelte.d.ts +9 -0
  195. package/dist/components/ui/avatar/avatar.stories.svelte +16 -0
  196. package/dist/components/ui/avatar/avatar.stories.svelte.d.ts +27 -0
  197. package/dist/components/ui/badge/badge.stories.svelte +33 -0
  198. package/dist/components/ui/badge/badge.stories.svelte.d.ts +27 -0
  199. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte +33 -0
  200. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte.d.ts +27 -0
  201. package/dist/components/ui/button/button.stories.svelte +43 -0
  202. package/dist/components/ui/button/button.stories.svelte.d.ts +27 -0
  203. package/dist/components/ui/button/button.svelte +1 -2
  204. package/dist/components/ui/button/button.svelte.d.ts +0 -3
  205. package/dist/components/ui/button-group/button-group-separator.svelte.d.ts +1 -1
  206. package/dist/components/ui/card/card.stories.svelte +42 -0
  207. package/dist/components/ui/card/card.stories.svelte.d.ts +27 -0
  208. package/dist/components/ui/command/command.stories.svelte +51 -0
  209. package/dist/components/ui/command/command.stories.svelte.d.ts +27 -0
  210. package/dist/components/ui/dialog/dialog.stories.svelte +29 -0
  211. package/dist/components/ui/dialog/dialog.stories.svelte.d.ts +27 -0
  212. package/dist/components/ui/field/field-label.svelte.d.ts +1 -1
  213. package/dist/components/ui/field/field.stories.svelte +21 -0
  214. package/dist/components/ui/field/field.stories.svelte.d.ts +27 -0
  215. package/dist/components/ui/input/input.stories.svelte +40 -0
  216. package/dist/components/ui/input/input.stories.svelte.d.ts +27 -0
  217. package/dist/components/ui/input/input.svelte +2 -4
  218. package/dist/components/ui/item/item-separator.svelte.d.ts +1 -1
  219. package/dist/components/ui/label/label.stories.svelte +20 -0
  220. package/dist/components/ui/label/label.stories.svelte.d.ts +27 -0
  221. package/dist/components/ui/popover/popover.stories.svelte +29 -0
  222. package/dist/components/ui/popover/popover.stories.svelte.d.ts +27 -0
  223. package/dist/components/ui/select/select-group-heading.svelte.d.ts +1 -1
  224. package/dist/components/ui/select/select.stories.svelte +23 -0
  225. package/dist/components/ui/select/select.stories.svelte.d.ts +27 -0
  226. package/dist/components/ui/separator/separator.stories.svelte +24 -0
  227. package/dist/components/ui/separator/separator.stories.svelte.d.ts +27 -0
  228. package/dist/components/ui/sheet/sheet.stories.svelte +29 -0
  229. package/dist/components/ui/sheet/sheet.stories.svelte.d.ts +27 -0
  230. package/dist/components/ui/sidebar/sidebar-group.svelte +3 -3
  231. package/dist/components/ui/sidebar/sidebar-group.svelte.d.ts +2 -2
  232. package/dist/components/ui/sidebar/sidebar-menu-button.svelte +28 -30
  233. package/dist/components/ui/sidebar/sidebar-menu-button.svelte.d.ts +7 -7
  234. package/dist/components/ui/sidebar/sidebar-separator.svelte.d.ts +1 -1
  235. package/dist/components/ui/sidebar/sidebar-trigger.svelte +4 -4
  236. package/dist/components/ui/sonner/sonner.stories.svelte +22 -0
  237. package/dist/components/ui/sonner/sonner.stories.svelte.d.ts +26 -0
  238. package/dist/components/ui/sonner/sonner.svelte +8 -2
  239. package/dist/components/ui/sonner/toast-demo.svelte +29 -0
  240. package/dist/components/ui/sonner/toast-demo.svelte.d.ts +6 -0
  241. package/dist/components/ui/textarea/textarea.stories.svelte +22 -0
  242. package/dist/components/ui/textarea/textarea.stories.svelte.d.ts +27 -0
  243. package/dist/components/ui/textarea/textarea.svelte +0 -2
  244. package/dist/components/ui/toggle/toggle.stories.svelte +22 -0
  245. package/dist/components/ui/toggle/toggle.stories.svelte.d.ts +27 -0
  246. package/dist/components/ui/toggle-group/toggle-group.stories.svelte +17 -0
  247. package/dist/components/ui/toggle-group/toggle-group.stories.svelte.d.ts +27 -0
  248. package/dist/components/ui/tooltip/tooltip.stories.svelte +26 -0
  249. package/dist/components/ui/tooltip/tooltip.stories.svelte.d.ts +27 -0
  250. package/dist/core/fields/fieldSchemaToTs.d.ts +1 -0
  251. package/dist/core/fields/fieldSchemaToTs.js +133 -1
  252. package/dist/core/fields/layoutUtils.d.ts +17 -0
  253. package/dist/core/fields/layoutUtils.js +149 -0
  254. package/dist/core/fields/structuredToHtml.d.ts +9 -0
  255. package/dist/core/fields/structuredToHtml.js +161 -0
  256. package/dist/core/server/entries/operations/create.js +2 -1
  257. package/dist/core/server/entries/operations/get.js +8 -6
  258. package/dist/core/server/entries/operations/update.d.ts +3 -0
  259. package/dist/core/server/entries/operations/update.js +30 -2
  260. package/dist/core/server/fields/queryStructuredContent.d.ts +15 -0
  261. package/dist/core/server/fields/queryStructuredContent.js +65 -0
  262. package/dist/core/server/fields/resolveImageFields.js +51 -2
  263. package/dist/core/server/fields/resolveRelationFields.js +2 -2
  264. package/dist/core/server/fields/resolveRichtextLinks.js +80 -13
  265. package/dist/core/server/fields/resolveUrlFields.js +57 -6
  266. package/dist/core/server/fields/slugResolver.d.ts +10 -0
  267. package/dist/core/server/fields/slugResolver.js +34 -0
  268. package/dist/core/server/generator/fields.js +15 -4
  269. package/dist/core/server/generator/generator.js +3 -2
  270. package/dist/files-local/index.js +126 -64
  271. package/dist/server/auth.d.ts +5 -0
  272. package/dist/server/auth.js +12 -1
  273. package/dist/sveltekit/components/structured-content.svelte +204 -0
  274. package/dist/sveltekit/components/structured-content.svelte.d.ts +21 -0
  275. package/dist/sveltekit/config.d.ts +13 -3
  276. package/dist/sveltekit/index.d.ts +3 -0
  277. package/dist/sveltekit/index.js +3 -0
  278. package/dist/sveltekit/server/handle.js +1 -0
  279. package/dist/types/config.d.ts +3 -0
  280. package/dist/types/fields.d.ts +19 -2
  281. package/dist/types/index.d.ts +2 -0
  282. package/dist/types/index.js +2 -0
  283. package/dist/types/layout.d.ts +54 -0
  284. package/dist/types/layout.js +6 -0
  285. package/dist/types/structured-content.d.ts +63 -0
  286. package/dist/types/structured-content.js +1 -0
  287. package/dist/updates/0.1.5/index.d.ts +2 -0
  288. package/dist/updates/0.1.5/index.js +18 -0
  289. package/dist/updates/0.2.0/index.d.ts +2 -0
  290. package/dist/updates/0.2.0/index.js +11 -0
  291. package/dist/updates/0.2.2/index.d.ts +2 -0
  292. package/dist/updates/0.2.2/index.js +13 -0
  293. package/dist/updates/0.5.0/index.d.ts +2 -0
  294. package/dist/updates/0.5.0/index.js +14 -0
  295. package/dist/updates/index.js +5 -1
  296. package/package.json +16 -9
@@ -0,0 +1,90 @@
1
+ <script lang="ts">
2
+ import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
3
+ import Skeleton from '../../../components/ui/skeleton/skeleton.svelte';
4
+ import { getRemotes } from '../../../sveltekit/index.js';
5
+ import type { InterfaceLanguage } from '../../../types/languages.js';
6
+
7
+ const interfaceLanguage = useInterfaceLanguage();
8
+ const remotes = getRemotes();
9
+
10
+ const CIRCUMFERENCE = 2 * Math.PI * 54; // 339.292
11
+
12
+ const lang: Record<InterfaceLanguage, {
13
+ title: string;
14
+ overallScore: string;
15
+ imageDescriptions: string;
16
+ allGood: string;
17
+ hint: (n: number) => string;
18
+ }> = {
19
+ pl: {
20
+ title: 'Dostępność treści',
21
+ overallScore: 'wynik ogólny',
22
+ imageDescriptions: 'Opisy obrazów',
23
+ allGood: 'Wszystkie obrazy mają opisy — świetna robota!',
24
+ hint: (n) => `${n} ${n === 1 ? 'obraz wymaga' : 'obrazów wymaga'} dodania opisu. Przejdź do biblioteki mediów, żeby je uzupełnić.`
25
+ },
26
+ en: {
27
+ title: 'Content accessibility',
28
+ overallScore: 'overall score',
29
+ imageDescriptions: 'Image descriptions',
30
+ allGood: 'All images have descriptions — great job!',
31
+ hint: (n) => `${n} image${n === 1 ? ' needs' : 's need'} a description. Go to the media library to add them.`
32
+ }
33
+ };
34
+ </script>
35
+
36
+ <section class="dash-card dash-card--a11y" aria-labelledby="a11y-heading">
37
+ <div class="dash-card-header">
38
+ <h2 class="dash-card-title" id="a11y-heading">{lang[interfaceLanguage.current].title}</h2>
39
+ </div>
40
+
41
+ {#await remotes.getAltOverview()}
42
+ <div class="a11y-card-body">
43
+ <div class="gauge-wrap">
44
+ <Skeleton class="rounded-full" style="width:140px;height:140px" />
45
+ </div>
46
+ <Skeleton class="h-4 w-32 mb-2" />
47
+ <Skeleton class="h-12 w-full" />
48
+ </div>
49
+ {:then overview}
50
+ {@const compliancePercent = overview.totalFiles > 0 ? Math.round((overview.filesWithAlt / overview.totalFiles) * 100) : 100}
51
+ {@const fillLength = (compliancePercent / 100) * CIRCUMFERENCE}
52
+ {@const hasIssues = overview.filesWithoutAlt > 0}
53
+
54
+ <div class="a11y-card-body">
55
+ <div class="gauge-wrap">
56
+ <svg class="gauge-svg" viewBox="0 0 140 140" role="img" aria-label="{interfaceLanguage.current === 'pl' ? 'Ocena dostępności' : 'Accessibility score'}: {compliancePercent}%">
57
+ <circle class="gauge-bg" cx="70" cy="70" r="54" />
58
+ <circle class="gauge-fill" cx="70" cy="70" r="54"
59
+ style="stroke-dasharray: {fillLength} {CIRCUMFERENCE}"
60
+ stroke-dashoffset="0" />
61
+ <text class="gauge-text-group" x="70" y="64">
62
+ <tspan class="gauge-value">{compliancePercent}%</tspan>
63
+ </text>
64
+ <text class="gauge-text-group" x="70" y="84">
65
+ <tspan class="gauge-label">{lang[interfaceLanguage.current].overallScore}</tspan>
66
+ </text>
67
+ </svg>
68
+ </div>
69
+
70
+ <ul class="a11y-breakdown" aria-label={interfaceLanguage.current === 'pl' ? 'Szczegóły dostępności' : 'Accessibility details'}>
71
+ <li class="a11y-breakdown-item">
72
+ <span class="a11y-breakdown-icon {hasIssues ? 'a11y-breakdown-icon--warn' : 'a11y-breakdown-icon--ok'}" aria-hidden="true">
73
+ {hasIssues ? '⚠' : '✓'}
74
+ </span>
75
+ <span class="a11y-breakdown-label">
76
+ {lang[interfaceLanguage.current].imageDescriptions}
77
+ </span>
78
+ </li>
79
+ </ul>
80
+
81
+ <div class="a11y-hint" role="status">
82
+ {#if hasIssues}
83
+ {lang[interfaceLanguage.current].hint(overview.filesWithoutAlt)}
84
+ {:else}
85
+ {lang[interfaceLanguage.current].allGood}
86
+ {/if}
87
+ </div>
88
+ </div>
89
+ {/await}
90
+ </section>
@@ -0,0 +1,18 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const A11yGauge: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type A11yGauge = InstanceType<typeof A11yGauge>;
18
+ export default A11yGauge;
@@ -6,6 +6,7 @@
6
6
  import { getRemotes } from '../../../sveltekit/index.js';
7
7
  import type { InterfaceLanguage } from '../../../types/languages.js';
8
8
  import StatCard from './stat-card.svelte';
9
+ import * as Alert from '../../../components/ui/alert/index.js';
9
10
  import AccessibilityIcon from '@tabler/icons-svelte/icons/accessible';
10
11
  import PhotoIcon from '@tabler/icons-svelte/icons/photo';
11
12
  import AlertTriangleIcon from '@tabler/icons-svelte/icons/alert-triangle';
@@ -53,7 +54,7 @@
53
54
  };
54
55
  </script>
55
56
 
56
- <Card.Root class="rounded-2xl border-slate-200/50 bg-white shadow-sm dark:border-slate-800 dark:bg-slate-900">
57
+ <Card.Root class="rounded-2xl border bg-card shadow-sm">
57
58
  <Card.Header class="pb-2">
58
59
  <div class="flex items-center gap-2">
59
60
  <div class="rounded-lg bg-primary/10 p-2">
@@ -103,7 +104,7 @@
103
104
  value={overview.totalFiles}
104
105
  >
105
106
  {#snippet icon()}
106
- <PhotoIcon class="size-5 text-slate-600 dark:text-slate-400" />
107
+ <PhotoIcon class="size-5 text-muted-foreground" />
107
108
  {/snippet}
108
109
  </StatCard>
109
110
 
@@ -121,24 +122,24 @@
121
122
  </div>
122
123
 
123
124
  {#if hasIssues}
124
- <div class="flex items-center justify-between rounded-lg border border-amber-200 bg-amber-50 p-3 dark:border-amber-900/50 dark:bg-amber-950/30">
125
+ <Alert.Root variant="warning" class="flex items-center justify-between">
125
126
  <div class="flex items-center gap-2">
126
- <AlertTriangleIcon class="size-5 text-amber-600 dark:text-amber-400" />
127
- <span class="text-sm text-amber-800 dark:text-amber-200">
127
+ <AlertTriangleIcon class="size-5" />
128
+ <Alert.Description class="text-inherit">
128
129
  {overview.filesWithoutAlt} {lang[interfaceLanguage.current].issuesFound}
129
- </span>
130
+ </Alert.Description>
130
131
  </div>
131
132
  <Button href="/admin/media" variant="outline" size="sm">
132
133
  {lang[interfaceLanguage.current].fixIssues}
133
134
  </Button>
134
- </div>
135
+ </Alert.Root>
135
136
  {:else}
136
- <div class="flex items-center gap-2 rounded-lg border border-emerald-200 bg-emerald-50 p-3 dark:border-emerald-900/50 dark:bg-emerald-950/30">
137
- <CircleCheckIcon class="size-5 text-emerald-600 dark:text-emerald-400" />
138
- <span class="text-sm text-emerald-800 dark:text-emerald-200">
137
+ <Alert.Root variant="success">
138
+ <CircleCheckIcon class="size-5" />
139
+ <Alert.Description class="text-inherit">
139
140
  {lang[interfaceLanguage.current].allGood}
140
- </span>
141
- </div>
141
+ </Alert.Description>
142
+ </Alert.Root>
142
143
  {/if}
143
144
  </div>
144
145
  {/await}
@@ -1,47 +1,28 @@
1
1
  <script lang="ts">
2
2
  import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
3
3
  import { formatRelativeDate as formatRelativeDateUtil } from '../../utils/formatDate.js';
4
- import * as Card from '../../../components/ui/card/index.js';
5
- import { Badge } from '../../../components/ui/badge/index.js';
6
- import { Button } from '../../../components/ui/button/index.js';
7
4
  import Skeleton from '../../../components/ui/skeleton/skeleton.svelte';
8
5
  import { getRemotes } from '../../../sveltekit/index.js';
9
6
  import { getLocalizedLabel } from '../../utils/collectionLabel.js';
10
7
  import type { InterfaceLanguage, Localized } from '../../../types/languages.js';
11
- import InboxIcon from '@tabler/icons-svelte/icons/inbox';
12
- import MailIcon from '@tabler/icons-svelte/icons/mail';
13
- import MailOpenedIcon from '@tabler/icons-svelte/icons/mail-opened';
14
- import ChevronRightIcon from '@tabler/icons-svelte/icons/chevron-right';
15
8
 
16
9
  const interfaceLanguage = useInterfaceLanguage();
17
10
  const remotes = getRemotes();
18
11
 
19
- const lang: Record<
20
- InterfaceLanguage,
21
- {
22
- title: string;
23
- description: string;
24
- viewAll: string;
25
- noSubmissions: string;
26
- new: string;
27
- total: string;
28
- }
29
- > = {
12
+ const lang: Record<InterfaceLanguage, {
13
+ title: string;
14
+ viewAll: string;
15
+ noSubmissions: string;
16
+ }> = {
30
17
  pl: {
31
- title: 'Zgłoszenia formularzy',
32
- description: 'Ostatnie zgłoszenia',
33
- viewAll: 'Zobacz wszystkie',
34
- noSubmissions: 'Brak zgłoszeń',
35
- new: 'nowe',
36
- total: 'wszystkich'
18
+ title: 'Zgłoszenia',
19
+ viewAll: 'Wszystkie ',
20
+ noSubmissions: 'Brak zgłoszeń'
37
21
  },
38
22
  en: {
39
- title: 'Form Submissions',
40
- description: 'Recent submissions',
41
- viewAll: 'View all',
42
- noSubmissions: 'No submissions',
43
- new: 'new',
44
- total: 'total'
23
+ title: 'Submissions',
24
+ viewAll: 'View all →',
25
+ noSubmissions: 'No submissions'
45
26
  }
46
27
  };
47
28
 
@@ -50,93 +31,70 @@
50
31
  }
51
32
  </script>
52
33
 
53
- <Card.Root class="rounded-2xl border-slate-200/50 bg-white shadow-sm dark:border-slate-800 dark:bg-slate-900">
54
- <Card.Header class="pb-2">
55
- <div class="flex items-center gap-2">
56
- <div class="rounded-lg bg-blue-500/10 p-2">
57
- <InboxIcon class="size-5 text-blue-600 dark:text-blue-400" />
58
- </div>
59
- <div>
60
- <Card.Title>{lang[interfaceLanguage.current].title}</Card.Title>
61
- <Card.Description>{lang[interfaceLanguage.current].description}</Card.Description>
62
- </div>
34
+ <section class="dash-card dash-card--forms" aria-labelledby="forms-heading">
35
+ <div class="dash-card-header">
36
+ <h2 class="dash-card-title" id="forms-heading">{lang[interfaceLanguage.current].title}</h2>
37
+ <a href="/admin/forms" class="dash-card-link">{lang[interfaceLanguage.current].viewAll}</a>
38
+ </div>
39
+
40
+ {#await remotes.getSubmissionsOverview()}
41
+ <div class="forms-card-body">
42
+ {#each Array(2) as _}
43
+ <div class="form-group">
44
+ <Skeleton class="h-4 w-24 mb-2" />
45
+ <Skeleton class="h-8 w-full" />
46
+ <Skeleton class="h-8 w-full mt-1" />
47
+ </div>
48
+ {/each}
63
49
  </div>
64
- </Card.Header>
65
- <Card.Content>
66
- {#await remotes.getSubmissionsOverview()}
67
- <div class="space-y-3">
68
- {#each Array(3) as _}
69
- <div class="flex items-center gap-3">
70
- <Skeleton class="size-8 rounded-lg" />
71
- <div class="flex-1 space-y-1">
72
- <Skeleton class="h-4 w-32" />
73
- <Skeleton class="h-3 w-20" />
50
+ {:then overview}
51
+ {#if overview.length === 0}
52
+ <p class="text-center text-sm py-6" style="color:var(--text-light)">
53
+ {lang[interfaceLanguage.current].noSubmissions}
54
+ </p>
55
+ {:else}
56
+ <div class="forms-card-body">
57
+ {#each overview as form}
58
+ <div class="form-group">
59
+ <div class="form-group-header">
60
+ <span class="form-group-name">
61
+ {getLocalizedLabel(form.label as Localized, interfaceLanguage.current)}
62
+ </span>
63
+ <span
64
+ class="form-group-badge {form.unread > 0 ? 'form-group-badge--unread' : ''}"
65
+ aria-label="{form.unread} {interfaceLanguage.current === 'pl' ? 'nieprzeczytanych' : 'unread'}"
66
+ >
67
+ {form.unread}
68
+ </span>
74
69
  </div>
75
- </div>
76
- {/each}
77
- </div>
78
- {:then overview}
79
- {@const totalUnread = overview.reduce((sum, f) => sum + f.unread, 0)}
80
70
 
81
- {#if overview.length === 0}
82
- <p class="text-muted-foreground py-4 text-center text-sm">
83
- {lang[interfaceLanguage.current].noSubmissions}
84
- </p>
85
- {:else}
86
- <div class="space-y-4">
87
- {#each overview as form}
88
- <div class="space-y-2">
89
- <div class="flex items-center justify-between">
90
- <div class="flex items-center gap-2">
91
- <span class="font-medium">
92
- {getLocalizedLabel(form.label as Localized, interfaceLanguage.current)}
93
- </span>
94
- {#if form.unread > 0}
95
- <Badge variant="default" class="h-5 px-1.5 text-xs">
96
- {form.unread}
97
- </Badge>
98
- {/if}
99
- </div>
100
- <Button href="/admin/forms/{form.slug}" variant="ghost" size="sm" class="h-7 px-2">
101
- {lang[interfaceLanguage.current].viewAll}
102
- <ChevronRightIcon class="ml-1 size-4" />
103
- </Button>
104
- </div>
105
-
106
- {#if form.recent.length > 0}
107
- <div class="space-y-1">
108
- {#each form.recent.slice(0, 3) as submission}
109
- <a
110
- href="/admin/form-submissions/{submission.id}"
111
- class="flex items-center gap-2 rounded-lg px-2 py-1.5 transition-colors hover:bg-slate-100 dark:hover:bg-slate-800"
112
- >
113
- {#if submission.read}
114
- <MailOpenedIcon class="size-4 text-slate-400" />
115
- {:else}
116
- <MailIcon class="size-4 text-blue-600 dark:text-blue-400" />
117
- {/if}
118
- <span
119
- class="flex-1 truncate text-sm {submission.read
120
- ? 'text-slate-600 dark:text-slate-400'
121
- : 'font-medium'}"
122
- >
71
+ {#if form.recent.length > 0}
72
+ <ul class="form-submissions-list" aria-label="{getLocalizedLabel(form.label as Localized, interfaceLanguage.current)}">
73
+ {#each form.recent.slice(0, 3) as submission}
74
+ <li>
75
+ <a href="/admin/form-submissions/{submission.id}" class="form-submission-item">
76
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" style="flex-shrink:0; color: {submission.read ? 'var(--text-light)' : 'var(--primary)'}">
77
+ <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
78
+ <polyline points="22,6 12,13 2,6"/>
79
+ </svg>
80
+ <span style="flex:1; min-width:0; font-size:13px; font-weight:{submission.read ? '500' : '700'}; color:{submission.read ? 'var(--muted-foreground)' : 'var(--foreground)'}; overflow:hidden; text-overflow:ellipsis; white-space:nowrap">
123
81
  {submission.preview || '—'}
124
82
  </span>
125
- <span class="text-muted-foreground text-xs">
83
+ <time style="font-size:11px; color:var(--text-light); white-space:nowrap; flex-shrink:0">
126
84
  {formatRelativeDate(new Date(submission.createdAt))}
127
- </span>
85
+ </time>
128
86
  </a>
129
- {/each}
130
- </div>
131
- {:else}
132
- <p class="text-muted-foreground px-2 text-sm">
133
- {lang[interfaceLanguage.current].noSubmissions}
134
- </p>
135
- {/if}
136
- </div>
137
- {/each}
138
- </div>
139
- {/if}
140
- {/await}
141
- </Card.Content>
142
- </Card.Root>
87
+ </li>
88
+ {/each}
89
+ </ul>
90
+ {:else}
91
+ <p style="font-size:13px; color:var(--text-light); padding:4px 10px">
92
+ {lang[interfaceLanguage.current].noSubmissions}
93
+ </p>
94
+ {/if}
95
+ </div>
96
+ {/each}
97
+ </div>
98
+ {/if}
99
+ {/await}
100
+ </section>
@@ -1,4 +1,6 @@
1
- export { default as AccessibilityHub } from './accessibility-hub.svelte';
1
+ export { default as A11yGauge } from './a11y-gauge.svelte';
2
2
  export { default as FormSubmissionsWidget } from './form-submissions-widget.svelte';
3
3
  export { default as RecentActivity } from './recent-activity.svelte';
4
- export { default as StatCard } from './stat-card.svelte';
4
+ export { default as RecentEntries } from './recent-entries.svelte';
5
+ export { default as TipOfTheDay } from './tip-of-the-day.svelte';
6
+ export { default as WelcomeHeader } from './welcome-header.svelte';
@@ -1,4 +1,6 @@
1
- export { default as AccessibilityHub } from './accessibility-hub.svelte';
1
+ export { default as A11yGauge } from './a11y-gauge.svelte';
2
2
  export { default as FormSubmissionsWidget } from './form-submissions-widget.svelte';
3
3
  export { default as RecentActivity } from './recent-activity.svelte';
4
- export { default as StatCard } from './stat-card.svelte';
4
+ export { default as RecentEntries } from './recent-entries.svelte';
5
+ export { default as TipOfTheDay } from './tip-of-the-day.svelte';
6
+ export { default as WelcomeHeader } from './welcome-header.svelte';
@@ -1,34 +1,25 @@
1
1
  <script lang="ts">
2
2
  import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
3
3
  import { formatRelativeDate as formatRelativeDateUtil } from '../../utils/formatDate.js';
4
- import * as Card from '../../../components/ui/card/index.js';
5
4
  import Skeleton from '../../../components/ui/skeleton/skeleton.svelte';
6
5
  import { getRemotes } from '../../../sveltekit/index.js';
7
6
  import type { InterfaceLanguage } from '../../../types/languages.js';
8
- import HistoryIcon from '@tabler/icons-svelte/icons/history';
9
- import EditIcon from '@tabler/icons-svelte/icons/edit';
10
7
 
11
8
  const interfaceLanguage = useInterfaceLanguage();
12
9
  const remotes = getRemotes();
13
10
 
14
- const lang: Record<
15
- InterfaceLanguage,
16
- {
17
- title: string;
18
- description: string;
19
- noActivity: string;
20
- edited: string;
21
- }
22
- > = {
11
+ const lang: Record<InterfaceLanguage, {
12
+ title: string;
13
+ noActivity: string;
14
+ edited: string;
15
+ }> = {
23
16
  pl: {
24
- title: 'Ostatnia aktywność',
25
- description: 'Najnowsze zmiany',
17
+ title: 'Aktywność',
26
18
  noActivity: 'Brak aktywności',
27
19
  edited: 'Edytowano'
28
20
  },
29
21
  en: {
30
- title: 'Recent Activity',
31
- description: 'Latest changes',
22
+ title: 'Activity',
32
23
  noActivity: 'No activity',
33
24
  edited: 'Edited'
34
25
  }
@@ -39,64 +30,51 @@
39
30
  }
40
31
  </script>
41
32
 
42
- <Card.Root class="rounded-2xl border-slate-200/50 bg-white shadow-sm dark:border-slate-800 dark:bg-slate-900">
43
- <Card.Header class="pb-2">
44
- <div class="flex items-center gap-2">
45
- <div class="rounded-lg bg-violet-500/10 p-2">
46
- <HistoryIcon class="size-5 text-violet-600 dark:text-violet-400" />
47
- </div>
48
- <div>
49
- <Card.Title>{lang[interfaceLanguage.current].title}</Card.Title>
50
- <Card.Description>{lang[interfaceLanguage.current].description}</Card.Description>
51
- </div>
52
- </div>
53
- </Card.Header>
54
- <Card.Content>
55
- {#await remotes.getRecentActivity(10)}
56
- <div class="space-y-3">
57
- {#each Array(5) as _}
58
- <div class="flex items-center gap-3">
59
- <Skeleton class="size-8 rounded-full" />
60
- <div class="flex-1 space-y-1">
61
- <Skeleton class="h-4 w-40" />
62
- <Skeleton class="h-3 w-24" />
63
- </div>
64
- </div>
65
- {/each}
66
- </div>
67
- {:then activity}
68
- {#if activity.length === 0}
69
- <p class="text-muted-foreground py-4 text-center text-sm">
70
- {lang[interfaceLanguage.current].noActivity}
71
- </p>
72
- {:else}
73
- <div class="relative">
74
- <div class="absolute bottom-0 left-4 top-0 w-px bg-slate-200 dark:bg-slate-700"></div>
33
+ <section class="dash-card dash-card--activity" aria-labelledby="activity-heading">
34
+ <div class="dash-card-header">
35
+ <h2 class="dash-card-title" id="activity-heading">{lang[interfaceLanguage.current].title}</h2>
36
+ </div>
75
37
 
76
- <div class="space-y-4">
77
- {#each activity as item}
78
- <a
79
- href="/admin/entries/{item.entryId}"
80
- class="group relative flex items-start gap-3 rounded-lg py-1 pl-1 transition-colors hover:bg-slate-50 dark:hover:bg-slate-800/50"
81
- >
82
- <div class="relative z-10 rounded-full border-2 border-white bg-slate-100 p-1.5 dark:border-slate-900 dark:bg-slate-800">
83
- <EditIcon class="size-3 text-slate-600 dark:text-slate-400" />
84
- </div>
85
- <div class="flex-1 min-w-0">
86
- <p class="truncate text-sm font-medium group-hover:text-primary">
87
- {item.label || item.slug}
88
- </p>
89
- <p class="text-muted-foreground text-xs">
90
- {lang[interfaceLanguage.current].edited} · {formatRelativeDate(
91
- new Date(item.updatedAt)
92
- )}
93
- </p>
94
- </div>
95
- </a>
96
- {/each}
38
+ {#await remotes.getRecentActivity(10)}
39
+ <ul class="activity-list">
40
+ {#each Array(4) as _}
41
+ <li class="activity-item">
42
+ <div class="activity-dot-col">
43
+ <Skeleton class="rounded-full" style="width:10px;height:10px" />
97
44
  </div>
98
- </div>
99
- {/if}
100
- {/await}
101
- </Card.Content>
102
- </Card.Root>
45
+ <div class="activity-body">
46
+ <Skeleton class="h-4 w-40" />
47
+ <Skeleton class="h-3 w-24 mt-1" />
48
+ </div>
49
+ </li>
50
+ {/each}
51
+ </ul>
52
+ {:then activity}
53
+ {#if activity.length === 0}
54
+ <p class="text-center text-sm py-6" style="color:var(--text-light)">
55
+ {lang[interfaceLanguage.current].noActivity}
56
+ </p>
57
+ {:else}
58
+ <ul class="activity-list" aria-label={lang[interfaceLanguage.current].title}>
59
+ {#each activity as item, i}
60
+ <li class="activity-item">
61
+ <div class="activity-dot-col">
62
+ <div class="activity-dot activity-dot--edit" aria-hidden="true"></div>
63
+ {#if i < activity.length - 1}
64
+ <div class="activity-line" aria-hidden="true"></div>
65
+ {/if}
66
+ </div>
67
+ <a href="/admin/entries/{item.entryId}" class="activity-body" style="text-decoration:none">
68
+ <p class="activity-text">
69
+ {lang[interfaceLanguage.current].edited} „{item.label || item.slug}"
70
+ </p>
71
+ <p class="activity-meta">
72
+ {formatRelativeDate(new Date(item.updatedAt))}
73
+ </p>
74
+ </a>
75
+ </li>
76
+ {/each}
77
+ </ul>
78
+ {/if}
79
+ {/await}
80
+ </section>
@@ -0,0 +1,94 @@
1
+ <script lang="ts">
2
+ import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
3
+ import { formatRelativeDate as formatRelativeDateUtil } from '../../utils/formatDate.js';
4
+ import { getLocalizedLabel } from '../../utils/collectionLabel.js';
5
+ import Skeleton from '../../../components/ui/skeleton/skeleton.svelte';
6
+ import { getRemotes } from '../../../sveltekit/index.js';
7
+ import type { InterfaceLanguage, Localized } from '../../../types/languages.js';
8
+
9
+ const interfaceLanguage = useInterfaceLanguage();
10
+ const remotes = getRemotes();
11
+
12
+ const lang: Record<InterfaceLanguage, {
13
+ title: string;
14
+ viewAll: string;
15
+ noEntries: string;
16
+ published: string;
17
+ draft: string;
18
+ scheduled: string;
19
+ }> = {
20
+ pl: {
21
+ title: 'Ostatnie wpisy',
22
+ viewAll: 'Wszystkie →',
23
+ noEntries: 'Brak wpisów',
24
+ published: 'Opubl.',
25
+ draft: 'Szkic',
26
+ scheduled: 'Zaplan.'
27
+ },
28
+ en: {
29
+ title: 'Recent entries',
30
+ viewAll: 'View all →',
31
+ noEntries: 'No entries',
32
+ published: 'Published',
33
+ draft: 'Draft',
34
+ scheduled: 'Scheduled'
35
+ }
36
+ };
37
+
38
+ function formatRelativeDate(date: Date): string {
39
+ return formatRelativeDateUtil(date, interfaceLanguage.current);
40
+ }
41
+
42
+ const statusIcon: Record<string, string> = {
43
+ published: '●',
44
+ draft: '○',
45
+ scheduled: '◐'
46
+ };
47
+ </script>
48
+
49
+ <section class="dash-card dash-card--entries" aria-labelledby="entries-heading">
50
+ <div class="dash-card-header">
51
+ <h2 class="dash-card-title" id="entries-heading">{lang[interfaceLanguage.current].title}</h2>
52
+ <a href="/admin/entries" class="dash-card-link">{lang[interfaceLanguage.current].viewAll}</a>
53
+ </div>
54
+
55
+ {#await remotes.getRecentEntries(6)}
56
+ <ul class="entries-list">
57
+ {#each Array(4) as _}
58
+ <li class="entry-item">
59
+ <div class="entry-item-link" style="pointer-events:none">
60
+ <div class="entry-item-main">
61
+ <Skeleton class="h-4 w-36" />
62
+ <Skeleton class="h-3 w-20 mt-1" />
63
+ </div>
64
+ </div>
65
+ </li>
66
+ {/each}
67
+ </ul>
68
+ {:then entries}
69
+ {#if entries.length === 0}
70
+ <p class="text-center text-sm py-6" style="color:var(--text-light)">
71
+ {lang[interfaceLanguage.current].noEntries}
72
+ </p>
73
+ {:else}
74
+ <ul class="entries-list" aria-label={lang[interfaceLanguage.current].title}>
75
+ {#each entries as entry}
76
+ <li class="entry-item">
77
+ <a href="/admin/entries/{entry.entryId}" class="entry-item-link">
78
+ <div class="entry-item-main">
79
+ <span class="entry-item-title">{entry.label || entry.slug}</span>
80
+ <span class="entry-item-meta">
81
+ {getLocalizedLabel(entry.collectionLabel as Localized, interfaceLanguage.current)} · {formatRelativeDate(new Date(entry.updatedAt))}
82
+ </span>
83
+ </div>
84
+ <span class="dash-status-badge dash-status-{entry.status}">
85
+ <span aria-hidden="true">{statusIcon[entry.status] ?? ''}</span>
86
+ {lang[interfaceLanguage.current][entry.status as keyof typeof lang['pl']] ?? entry.status}
87
+ </span>
88
+ </a>
89
+ </li>
90
+ {/each}
91
+ </ul>
92
+ {/if}
93
+ {/await}
94
+ </section>