includio-cms 0.1.4 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/ROADMAP.md +18 -13
  3. package/dist/admin/api/accept-invite.js +1 -5
  4. package/dist/admin/api/invite.js +7 -16
  5. package/dist/admin/client/account/account-page.svelte +20 -50
  6. package/dist/admin/client/account/lang.d.ts +15 -23
  7. package/dist/admin/client/account/lang.js +51 -67
  8. package/dist/admin/client/account/preferences-section.svelte +26 -84
  9. package/dist/admin/client/account/profile-section.svelte +60 -40
  10. package/dist/admin/client/account/schema.d.ts +11 -3
  11. package/dist/admin/client/account/schema.js +25 -16
  12. package/dist/admin/client/account/security-section.svelte +139 -105
  13. package/dist/admin/client/account/sessions-section.svelte +35 -34
  14. package/dist/admin/client/admin/admin-after-login-layout-content.svelte +3 -5
  15. package/dist/admin/client/admin/admin-layout.svelte +3 -2
  16. package/dist/admin/client/admin/admin-preloader.svelte +36 -0
  17. package/dist/admin/client/admin/admin-preloader.svelte.d.ts +18 -0
  18. package/dist/admin/client/admin/dashboard-page.svelte +55 -41
  19. package/dist/admin/client/collection/a11y-score-cell.svelte +45 -0
  20. package/dist/admin/client/collection/a11y-score-cell.svelte.d.ts +6 -0
  21. package/dist/admin/client/collection/bulk-actions-bar.svelte +83 -0
  22. package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +9 -0
  23. package/dist/admin/client/collection/collection-entries.svelte +255 -260
  24. package/dist/admin/client/collection/collection-view.svelte.d.ts +4 -3
  25. package/dist/admin/client/collection/collection-view.svelte.js +9 -5
  26. package/dist/admin/client/collection/collection.svelte +22 -12
  27. package/dist/admin/client/collection/data-table.svelte +50 -39
  28. package/dist/admin/client/collection/data-table.svelte.d.ts +1 -0
  29. package/dist/admin/client/collection/date-cell.svelte +7 -5
  30. package/dist/admin/client/collection/date-cell.svelte.d.ts +1 -1
  31. package/dist/admin/client/collection/empty-state.svelte +28 -0
  32. package/dist/admin/client/collection/empty-state.svelte.d.ts +9 -0
  33. package/dist/admin/client/collection/entry-link.svelte +10 -4
  34. package/dist/admin/client/collection/entry-link.svelte.d.ts +1 -0
  35. package/dist/admin/client/collection/grid-view.svelte +21 -23
  36. package/dist/admin/client/collection/grid-view.svelte.d.ts +1 -2
  37. package/dist/admin/client/collection/row-actions.svelte +60 -0
  38. package/dist/admin/client/collection/row-actions.svelte.d.ts +9 -0
  39. package/dist/admin/client/collection/status-badge.svelte +7 -8
  40. package/dist/admin/client/collection/table-pagination.svelte +122 -79
  41. package/dist/admin/client/collection/table-pagination.svelte.d.ts +1 -0
  42. package/dist/admin/client/collection/table-toolbar.svelte +108 -88
  43. package/dist/admin/client/collection/table-toolbar.svelte.d.ts +8 -9
  44. package/dist/admin/client/entry/entry-form.svelte +109 -1
  45. package/dist/admin/client/entry/entry-header.svelte +96 -37
  46. package/dist/admin/client/entry/entry-header.svelte.d.ts +5 -0
  47. package/dist/admin/client/entry/entry.svelte +171 -60
  48. package/dist/admin/client/entry/header/a11y-validator.d.ts +46 -0
  49. package/dist/admin/client/entry/header/a11y-validator.js +311 -0
  50. package/dist/admin/client/entry/header/publish-panel.svelte +373 -131
  51. package/dist/admin/client/entry/header/publish-panel.svelte.d.ts +4 -0
  52. package/dist/admin/client/entry/header/save-indicator.svelte +33 -23
  53. package/dist/admin/client/entry/header/schedule-popover.svelte +1 -1
  54. package/dist/admin/client/entry/header/status-badge.svelte +25 -118
  55. package/dist/admin/client/entry/header/version-history-sheet.svelte +314 -98
  56. package/dist/admin/client/form/form-submission/form-submission.svelte +271 -83
  57. package/dist/admin/client/form/form-submission/submission-field.svelte +12 -12
  58. package/dist/admin/client/form/form-submissions.svelte +421 -139
  59. package/dist/admin/client/form/submission-link.svelte +8 -2
  60. package/dist/admin/client/form/submission-link.svelte.d.ts +1 -0
  61. package/dist/admin/client/form/submission-status-badge.svelte +18 -4
  62. package/dist/admin/client/form/submission-status-badge.svelte.d.ts +1 -0
  63. package/dist/admin/client/login/lang.d.ts +32 -0
  64. package/dist/admin/client/login/lang.js +66 -2
  65. package/dist/admin/client/login/login-form.svelte +237 -95
  66. package/dist/admin/client/login/login-form.svelte.d.ts +2 -17
  67. package/dist/admin/client/login/login-page.svelte +34 -98
  68. package/dist/admin/client/login/reset-password-page.svelte +235 -0
  69. package/dist/admin/client/login/reset-password-page.svelte.d.ts +4 -0
  70. package/dist/admin/client/login/schema.d.ts +15 -0
  71. package/dist/admin/client/login/schema.js +21 -0
  72. package/dist/admin/client/users/accept-invite-page.svelte +166 -37
  73. package/dist/admin/client/users/create-user-dialog.svelte +15 -7
  74. package/dist/admin/client/users/delete-user-dialog.svelte +81 -16
  75. package/dist/admin/client/users/delete-user-dialog.svelte.d.ts +4 -1
  76. package/dist/admin/client/users/edit-user-dialog.svelte +3 -0
  77. package/dist/admin/client/users/invite-user-dialog.svelte +16 -3
  78. package/dist/admin/client/users/lang.d.ts +27 -0
  79. package/dist/admin/client/users/lang.js +64 -10
  80. package/dist/admin/client/users/pending-invitations.svelte +59 -23
  81. package/dist/admin/client/users/users-page.svelte +471 -72
  82. package/dist/admin/components/accessibility/accessibility-overview.svelte +2 -7
  83. package/dist/admin/components/dashboard/a11y-gauge.svelte +90 -0
  84. package/dist/admin/components/dashboard/a11y-gauge.svelte.d.ts +18 -0
  85. package/dist/admin/components/dashboard/accessibility-hub.svelte +13 -12
  86. package/dist/admin/components/dashboard/form-submissions-widget.svelte +71 -113
  87. package/dist/admin/components/dashboard/index.d.ts +4 -2
  88. package/dist/admin/components/dashboard/index.js +4 -2
  89. package/dist/admin/components/dashboard/recent-activity.svelte +53 -75
  90. package/dist/admin/components/dashboard/recent-entries.svelte +94 -0
  91. package/dist/admin/components/dashboard/recent-entries.svelte.d.ts +18 -0
  92. package/dist/admin/components/dashboard/stat-card.svelte +2 -2
  93. package/dist/admin/components/dashboard/tip-of-the-day.svelte +109 -0
  94. package/dist/admin/components/dashboard/tip-of-the-day.svelte.d.ts +3 -0
  95. package/dist/admin/components/dashboard/welcome-header.svelte +45 -0
  96. package/dist/admin/components/dashboard/welcome-header.svelte.d.ts +3 -0
  97. package/dist/admin/components/fields/{array-field.svelte → blocks-field.svelte} +4 -4
  98. package/dist/admin/components/fields/{array-field.svelte.d.ts → blocks-field.svelte.d.ts} +5 -5
  99. package/dist/admin/components/fields/content-field.svelte +27 -0
  100. package/dist/admin/components/fields/content-field.svelte.d.ts +31 -0
  101. package/dist/admin/components/fields/field-renderer.svelte +9 -7
  102. package/dist/admin/components/fields/image-field.svelte +2 -2
  103. package/dist/admin/components/fields/media-field.svelte +2 -2
  104. package/dist/admin/components/fields/seo-field.svelte +205 -25
  105. package/dist/admin/components/fields/simple-array-field.svelte +289 -0
  106. package/dist/admin/components/fields/simple-array-field.svelte.d.ts +30 -0
  107. package/dist/admin/components/fields/slug-field.svelte +3 -2
  108. package/dist/admin/components/fields/standalone-field-renderer.svelte +148 -0
  109. package/dist/admin/components/fields/standalone-field-renderer.svelte.d.ts +9 -0
  110. package/dist/admin/components/fields/text-field-wrapper.svelte +13 -1
  111. package/dist/admin/components/fields/text-field-wrapper.svelte.d.ts +2 -2
  112. package/dist/admin/components/fields/url-field.svelte +5 -4
  113. package/dist/admin/components/layout/app-sidebar.svelte +27 -24
  114. package/dist/admin/components/layout/lang.d.ts +6 -0
  115. package/dist/admin/components/layout/lang.js +13 -1
  116. package/dist/admin/components/layout/layout-renderer.svelte +352 -0
  117. package/dist/admin/components/layout/layout-renderer.svelte.d.ts +14 -0
  118. package/dist/admin/components/layout/nav-breadcrumbs.svelte +4 -4
  119. package/dist/admin/components/layout/nav-collections.svelte +65 -36
  120. package/dist/admin/components/layout/nav-footer.svelte +31 -0
  121. package/dist/admin/components/layout/nav-footer.svelte.d.ts +18 -0
  122. package/dist/admin/components/layout/nav-forms.svelte +55 -30
  123. package/dist/admin/components/layout/nav-main.svelte +14 -52
  124. package/dist/admin/components/layout/nav-search.svelte +4 -3
  125. package/dist/admin/components/layout/nav-singletons.svelte +59 -17
  126. package/dist/admin/components/layout/nav-singletons.svelte.d.ts +17 -8
  127. package/dist/admin/components/layout/site-header.svelte +74 -13
  128. package/dist/admin/components/media/alt-input.svelte +32 -22
  129. package/dist/admin/components/media/bulk-action-bar.svelte +139 -150
  130. package/dist/admin/components/media/file/file-details.svelte +299 -217
  131. package/dist/admin/components/media/file/file-miniature.svelte +54 -41
  132. package/dist/admin/components/media/file/file-miniature.svelte.d.ts +1 -0
  133. package/dist/admin/components/media/file/file-preview.svelte +1 -1
  134. package/dist/admin/components/media/file-upload.svelte +24 -26
  135. package/dist/admin/components/media/files-list.svelte +112 -40
  136. package/dist/admin/components/media/files-list.svelte.d.ts +2 -0
  137. package/dist/admin/components/media/focal-point-input.svelte +122 -26
  138. package/dist/admin/components/media/media-library.svelte +127 -70
  139. package/dist/admin/components/media/media-search.svelte +6 -6
  140. package/dist/admin/components/media/media-sort.svelte +3 -1
  141. package/dist/admin/components/media/multi-file-summary.svelte +88 -68
  142. package/dist/admin/components/media/tag-combobox.svelte +141 -66
  143. package/dist/admin/components/media/tag-combobox.svelte.d.ts +1 -0
  144. package/dist/admin/components/media/tag-sidebar.svelte +139 -121
  145. package/dist/admin/components/tiptap/FigureNodeView.svelte +144 -15
  146. package/dist/admin/components/tiptap/InlineBlockNodeView.svelte +254 -0
  147. package/dist/admin/components/tiptap/InlineBlockNodeView.svelte.d.ts +4 -0
  148. package/dist/admin/components/tiptap/SlashCommandPopup.svelte +212 -0
  149. package/dist/admin/components/tiptap/SlashCommandPopup.svelte.d.ts +8 -0
  150. package/dist/admin/components/tiptap/content-editor.svelte +280 -0
  151. package/dist/admin/components/tiptap/content-editor.svelte.d.ts +9 -0
  152. package/dist/admin/components/tiptap/editor-toolbar.svelte +230 -0
  153. package/dist/admin/components/tiptap/editor-toolbar.svelte.d.ts +16 -0
  154. package/dist/admin/components/tiptap/heading-a11y-plugin.d.ts +2 -0
  155. package/dist/admin/components/tiptap/heading-a11y-plugin.js +67 -0
  156. package/dist/admin/components/tiptap/image-dialog.svelte +172 -11
  157. package/dist/admin/components/tiptap/inline-block-node.d.ts +19 -0
  158. package/dist/admin/components/tiptap/inline-block-node.js +98 -0
  159. package/dist/admin/components/tiptap/link-dialog.svelte +9 -4
  160. package/dist/admin/components/tiptap/slash-command.d.ts +17 -0
  161. package/dist/admin/components/tiptap/slash-command.js +181 -0
  162. package/dist/admin/components/tiptap/structured-content-utils.d.ts +21 -0
  163. package/dist/admin/components/tiptap/structured-content-utils.js +150 -0
  164. package/dist/admin/components/tiptap/tiptap-editor.svelte +18 -190
  165. package/dist/admin/email/invite-template.d.ts +8 -0
  166. package/dist/admin/email/invite-template.js +99 -0
  167. package/dist/admin/email/reset-password-template.d.ts +7 -0
  168. package/dist/admin/email/reset-password-template.js +96 -0
  169. package/dist/admin/remote/ai.remote.d.ts +1 -0
  170. package/dist/admin/remote/ai.remote.js +4 -1
  171. package/dist/admin/remote/entry.remote.d.ts +8 -0
  172. package/dist/admin/remote/entry.remote.js +53 -4
  173. package/dist/admin/remote/preview.remote.js +2 -1
  174. package/dist/admin/shared/password-schema.d.ts +5 -0
  175. package/dist/admin/shared/password-schema.js +10 -0
  176. package/dist/admin/styles/admin.css +1530 -151
  177. package/dist/admin/utils/formatDate.d.ts +1 -0
  178. package/dist/admin/utils/formatDate.js +8 -0
  179. package/dist/admin/utils/roleLabel.d.ts +2 -0
  180. package/dist/admin/utils/roleLabel.js +13 -0
  181. package/dist/ai-claude/index.d.ts +2 -0
  182. package/dist/ai-claude/index.js +56 -0
  183. package/dist/cms/runtime/api.d.ts +6 -1
  184. package/dist/cms/runtime/api.js +3 -0
  185. package/dist/cms/runtime/schemas.d.ts +9 -1
  186. package/dist/cms/runtime/schemas.js +8 -0
  187. package/dist/cms/runtime/types.d.ts +82 -10
  188. package/dist/cms/runtime/types.js +4 -0
  189. package/dist/components/ui/accordion/accordion.stories.svelte +39 -0
  190. package/dist/components/ui/accordion/accordion.stories.svelte.d.ts +27 -0
  191. package/dist/components/ui/alert/alert.stories.svelte +53 -0
  192. package/dist/components/ui/alert/alert.stories.svelte.d.ts +27 -0
  193. package/dist/components/ui/alert/alert.svelte +5 -0
  194. package/dist/components/ui/alert/alert.svelte.d.ts +9 -0
  195. package/dist/components/ui/avatar/avatar.stories.svelte +16 -0
  196. package/dist/components/ui/avatar/avatar.stories.svelte.d.ts +27 -0
  197. package/dist/components/ui/badge/badge.stories.svelte +33 -0
  198. package/dist/components/ui/badge/badge.stories.svelte.d.ts +27 -0
  199. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte +33 -0
  200. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte.d.ts +27 -0
  201. package/dist/components/ui/button/button.stories.svelte +43 -0
  202. package/dist/components/ui/button/button.stories.svelte.d.ts +27 -0
  203. package/dist/components/ui/button/button.svelte +1 -2
  204. package/dist/components/ui/button/button.svelte.d.ts +0 -3
  205. package/dist/components/ui/button-group/button-group-separator.svelte.d.ts +1 -1
  206. package/dist/components/ui/card/card.stories.svelte +42 -0
  207. package/dist/components/ui/card/card.stories.svelte.d.ts +27 -0
  208. package/dist/components/ui/command/command.stories.svelte +51 -0
  209. package/dist/components/ui/command/command.stories.svelte.d.ts +27 -0
  210. package/dist/components/ui/dialog/dialog.stories.svelte +29 -0
  211. package/dist/components/ui/dialog/dialog.stories.svelte.d.ts +27 -0
  212. package/dist/components/ui/field/field-label.svelte.d.ts +1 -1
  213. package/dist/components/ui/field/field.stories.svelte +21 -0
  214. package/dist/components/ui/field/field.stories.svelte.d.ts +27 -0
  215. package/dist/components/ui/input/input.stories.svelte +40 -0
  216. package/dist/components/ui/input/input.stories.svelte.d.ts +27 -0
  217. package/dist/components/ui/input/input.svelte +2 -4
  218. package/dist/components/ui/item/item-separator.svelte.d.ts +1 -1
  219. package/dist/components/ui/label/label.stories.svelte +20 -0
  220. package/dist/components/ui/label/label.stories.svelte.d.ts +27 -0
  221. package/dist/components/ui/popover/popover.stories.svelte +29 -0
  222. package/dist/components/ui/popover/popover.stories.svelte.d.ts +27 -0
  223. package/dist/components/ui/select/select-group-heading.svelte.d.ts +1 -1
  224. package/dist/components/ui/select/select.stories.svelte +23 -0
  225. package/dist/components/ui/select/select.stories.svelte.d.ts +27 -0
  226. package/dist/components/ui/separator/separator.stories.svelte +24 -0
  227. package/dist/components/ui/separator/separator.stories.svelte.d.ts +27 -0
  228. package/dist/components/ui/sheet/sheet.stories.svelte +29 -0
  229. package/dist/components/ui/sheet/sheet.stories.svelte.d.ts +27 -0
  230. package/dist/components/ui/sidebar/sidebar-group.svelte +3 -3
  231. package/dist/components/ui/sidebar/sidebar-group.svelte.d.ts +2 -2
  232. package/dist/components/ui/sidebar/sidebar-menu-button.svelte +28 -30
  233. package/dist/components/ui/sidebar/sidebar-menu-button.svelte.d.ts +7 -7
  234. package/dist/components/ui/sidebar/sidebar-separator.svelte.d.ts +1 -1
  235. package/dist/components/ui/sidebar/sidebar-trigger.svelte +4 -4
  236. package/dist/components/ui/sonner/sonner.stories.svelte +22 -0
  237. package/dist/components/ui/sonner/sonner.stories.svelte.d.ts +26 -0
  238. package/dist/components/ui/sonner/sonner.svelte +8 -2
  239. package/dist/components/ui/sonner/toast-demo.svelte +29 -0
  240. package/dist/components/ui/sonner/toast-demo.svelte.d.ts +6 -0
  241. package/dist/components/ui/textarea/textarea.stories.svelte +22 -0
  242. package/dist/components/ui/textarea/textarea.stories.svelte.d.ts +27 -0
  243. package/dist/components/ui/textarea/textarea.svelte +0 -2
  244. package/dist/components/ui/toggle/toggle.stories.svelte +22 -0
  245. package/dist/components/ui/toggle/toggle.stories.svelte.d.ts +27 -0
  246. package/dist/components/ui/toggle-group/toggle-group.stories.svelte +17 -0
  247. package/dist/components/ui/toggle-group/toggle-group.stories.svelte.d.ts +27 -0
  248. package/dist/components/ui/tooltip/tooltip.stories.svelte +26 -0
  249. package/dist/components/ui/tooltip/tooltip.stories.svelte.d.ts +27 -0
  250. package/dist/core/fields/fieldSchemaToTs.d.ts +1 -0
  251. package/dist/core/fields/fieldSchemaToTs.js +133 -1
  252. package/dist/core/fields/layoutUtils.d.ts +17 -0
  253. package/dist/core/fields/layoutUtils.js +149 -0
  254. package/dist/core/fields/structuredToHtml.d.ts +9 -0
  255. package/dist/core/fields/structuredToHtml.js +161 -0
  256. package/dist/core/server/entries/operations/create.js +2 -1
  257. package/dist/core/server/entries/operations/get.js +8 -6
  258. package/dist/core/server/entries/operations/update.d.ts +3 -0
  259. package/dist/core/server/entries/operations/update.js +30 -2
  260. package/dist/core/server/fields/queryStructuredContent.d.ts +15 -0
  261. package/dist/core/server/fields/queryStructuredContent.js +65 -0
  262. package/dist/core/server/fields/resolveImageFields.js +51 -2
  263. package/dist/core/server/fields/resolveRelationFields.js +2 -2
  264. package/dist/core/server/fields/resolveRichtextLinks.js +80 -13
  265. package/dist/core/server/fields/resolveUrlFields.js +57 -6
  266. package/dist/core/server/fields/slugResolver.d.ts +10 -0
  267. package/dist/core/server/fields/slugResolver.js +34 -0
  268. package/dist/core/server/generator/fields.js +15 -4
  269. package/dist/core/server/generator/generator.js +3 -2
  270. package/dist/files-local/index.js +126 -64
  271. package/dist/server/auth.d.ts +5 -0
  272. package/dist/server/auth.js +12 -1
  273. package/dist/sveltekit/components/structured-content.svelte +204 -0
  274. package/dist/sveltekit/components/structured-content.svelte.d.ts +21 -0
  275. package/dist/sveltekit/config.d.ts +13 -3
  276. package/dist/sveltekit/index.d.ts +3 -0
  277. package/dist/sveltekit/index.js +3 -0
  278. package/dist/sveltekit/server/handle.js +1 -0
  279. package/dist/types/config.d.ts +3 -0
  280. package/dist/types/fields.d.ts +19 -2
  281. package/dist/types/index.d.ts +2 -0
  282. package/dist/types/index.js +2 -0
  283. package/dist/types/layout.d.ts +54 -0
  284. package/dist/types/layout.js +6 -0
  285. package/dist/types/structured-content.d.ts +63 -0
  286. package/dist/types/structured-content.js +1 -0
  287. package/dist/updates/0.1.5/index.d.ts +2 -0
  288. package/dist/updates/0.1.5/index.js +18 -0
  289. package/dist/updates/0.2.0/index.d.ts +2 -0
  290. package/dist/updates/0.2.0/index.js +11 -0
  291. package/dist/updates/0.2.2/index.d.ts +2 -0
  292. package/dist/updates/0.2.2/index.js +13 -0
  293. package/dist/updates/0.5.0/index.d.ts +2 -0
  294. package/dist/updates/0.5.0/index.js +14 -0
  295. package/dist/updates/index.js +5 -1
  296. package/package.json +16 -9
@@ -3,21 +3,24 @@
3
3
  import { getRemotes } from '../../../context/remotes.js';
4
4
  import { useInterfaceLanguage } from '../../../state/interface-language.svelte.js';
5
5
  import { getLocalizedLabel } from '../../../utils/collectionLabel.js';
6
+ import { formatAbsoluteDate } from '../../../utils/formatDate.js';
6
7
  import type { FormSubmission } from '../../../../types/forms.js';
7
8
  import type { InterfaceLanguage } from '../../../../types/languages.js';
8
9
  import SubmissionField from './submission-field.svelte';
9
10
  import Button from '../../../../components/ui/button/button.svelte';
10
- import Badge from '../../../../components/ui/badge/badge.svelte';
11
+ import * as AlertDialog from '../../../../components/ui/alert-dialog/index.js';
11
12
  import Trash from '@tabler/icons-svelte/icons/trash';
12
13
  import Mail from '@tabler/icons-svelte/icons/mail';
13
14
  import Eye from '@tabler/icons-svelte/icons/eye';
14
15
  import EyeOff from '@tabler/icons-svelte/icons/eye-off';
16
+ import Printer from '@tabler/icons-svelte/icons/printer';
15
17
  import ChevronLeft from '@tabler/icons-svelte/icons/chevron-left';
16
18
  import ChevronRight from '@tabler/icons-svelte/icons/chevron-right';
17
19
  import ArrowLeft from '@tabler/icons-svelte/icons/arrow-left';
18
20
  import Monitor from '@tabler/icons-svelte/icons/device-desktop';
19
21
  import Globe from '@tabler/icons-svelte/icons/world';
20
22
  import Calendar from '@tabler/icons-svelte/icons/calendar';
23
+ import ClipboardList from '@tabler/icons-svelte/icons/clipboard-list';
21
24
 
22
25
  const remotes = getRemotes();
23
26
  const interfaceLanguage = useInterfaceLanguage();
@@ -30,54 +33,76 @@
30
33
  markRead: string;
31
34
  markUnread: string;
32
35
  reply: string;
36
+ print: string;
33
37
  previous: string;
34
38
  next: string;
35
39
  metadata: string;
36
40
  createdAt: string;
37
41
  ip: string;
38
42
  device: string;
43
+ context: string;
39
44
  formData: string;
40
45
  new: string;
41
46
  read: string;
42
- confirmDelete: string;
47
+ confirmDeleteTitle: string;
48
+ confirmDeleteDesc: string;
49
+ cancel: string;
43
50
  noEmail: string;
51
+ of: string;
52
+ printSubmission: string;
53
+ exportPdf: string;
44
54
  }
45
55
  > = {
46
56
  pl: {
47
- back: 'Powrót',
57
+ back: 'Powrót do listy',
48
58
  delete: 'Usuń',
49
59
  markRead: 'Oznacz jako przeczytane',
50
60
  markUnread: 'Oznacz jako nieprzeczytane',
51
61
  reply: 'Odpowiedz',
62
+ print: 'Drukuj',
52
63
  previous: 'Poprzednie',
53
64
  next: 'Następne',
54
65
  metadata: 'Metadane',
55
66
  createdAt: 'Data utworzenia',
56
67
  ip: 'Adres IP',
57
68
  device: 'Urządzenie',
69
+ context: 'Kontekst',
58
70
  formData: 'Dane formularza',
59
71
  new: 'Nowe',
60
72
  read: 'Przeczytane',
61
- confirmDelete: 'Czy na pewno chcesz usunąć to zgłoszenie?',
62
- noEmail: 'Brak adresu email'
73
+ confirmDeleteTitle: 'Usunąć zgłoszenie?',
74
+ confirmDeleteDesc: 'Tej akcji nie można cofnąć. Zgłoszenie zostanie trwale usunięte.',
75
+ cancel: 'Anuluj',
76
+ noEmail: 'Brak adresu email',
77
+ of: 'z',
78
+ printSubmission: 'Drukuj zgłoszenie',
79
+ exportPdf: 'Eksportuj PDF'
63
80
  },
64
81
  en: {
65
- back: 'Back',
82
+ back: 'Back to list',
66
83
  delete: 'Delete',
67
84
  markRead: 'Mark as read',
68
85
  markUnread: 'Mark as unread',
69
86
  reply: 'Reply',
87
+ print: 'Print',
70
88
  previous: 'Previous',
71
89
  next: 'Next',
72
90
  metadata: 'Metadata',
73
91
  createdAt: 'Created at',
74
92
  ip: 'IP Address',
75
93
  device: 'Device',
94
+ context: 'Context',
76
95
  formData: 'Form data',
77
96
  new: 'New',
78
97
  read: 'Read',
79
- confirmDelete: 'Are you sure you want to delete this submission?',
80
- noEmail: 'No email address'
98
+ confirmDeleteTitle: 'Delete submission?',
99
+ confirmDeleteDesc:
100
+ 'This action cannot be undone. The submission will be permanently deleted.',
101
+ cancel: 'Cancel',
102
+ noEmail: 'No email address',
103
+ of: 'of',
104
+ printSubmission: 'Print submission',
105
+ exportPdf: 'Export PDF'
81
106
  }
82
107
  };
83
108
 
@@ -87,25 +112,44 @@
87
112
 
88
113
  let { submission }: Props = $props();
89
114
 
115
+ const t = $derived(lang[interfaceLanguage.current]);
116
+
90
117
  let form = await remotes.getForm(submission.formSlug);
91
118
  let allSubmissions = await remotes.getFormSubmissions(submission.formSlug);
92
119
 
93
120
  let isRead = $state(submission.read);
121
+ let deleteDialogOpen = $state(false);
122
+
123
+ const formLabel = $derived(
124
+ getLocalizedLabel(form.label, interfaceLanguage.current) || form.slug
125
+ );
94
126
 
95
127
  const currentIndex = $derived(allSubmissions.findIndex((s) => s.id === submission.id));
96
- const previousSubmission = $derived(currentIndex > 0 ? allSubmissions[currentIndex - 1] : null);
128
+ const previousSubmission = $derived(
129
+ currentIndex > 0 ? allSubmissions[currentIndex - 1] : null
130
+ );
97
131
  const nextSubmission = $derived(
98
132
  currentIndex < allSubmissions.length - 1 ? allSubmissions[currentIndex + 1] : null
99
133
  );
100
134
 
101
135
  const emailField = $derived(form.fields.find((f) => f.type === 'email'));
102
- const emailValue = $derived(emailField ? (submission.data[emailField.slug] as string) : null);
136
+ const emailValue = $derived(
137
+ emailField ? (submission.data[emailField.slug] as string) : null
138
+ );
103
139
 
104
- const createdAtFormatted = $derived(new Date(submission.createdAt).toLocaleString('pl'));
140
+ // Get the first field value for the title
141
+ const titleValue = $derived(
142
+ form.fields.length > 0 ? String(submission.data[form.fields[0].slug] || '-') : '-'
143
+ );
144
+
145
+ const createdAtFormatted = $derived(
146
+ formatAbsoluteDate(new Date(submission.createdAt), interfaceLanguage.current)
147
+ );
105
148
 
106
149
  function parseUserAgent(ua?: string | null): string {
107
150
  if (!ua) return '-';
108
- const browser = ua.match(/(Chrome|Firefox|Safari|Edge|Opera)[/\s](\d+)/)?.[1] || 'Unknown';
151
+ const browser =
152
+ ua.match(/(Chrome|Firefox|Safari|Edge|Opera)[/\s](\d+)/)?.[1] || 'Unknown';
109
153
  const os = ua.includes('Windows')
110
154
  ? 'Windows'
111
155
  : ua.includes('Mac')
@@ -121,7 +165,6 @@
121
165
  }
122
166
 
123
167
  async function handleDelete() {
124
- if (!confirm(lang[interfaceLanguage.current].confirmDelete)) return;
125
168
  await remotes.deleteFormSubmission(submission.id);
126
169
  goto(`/admin/forms/${submission.formSlug}`);
127
170
  }
@@ -136,108 +179,253 @@
136
179
  window.location.href = `mailto:${emailValue}`;
137
180
  }
138
181
  }
182
+
183
+ function handlePrint() {
184
+ window.print();
185
+ }
139
186
  </script>
140
187
 
141
188
  <div class="space-y-6">
142
- <div class="flex flex-wrap items-center justify-between gap-4">
189
+ <!-- Back + navigation row -->
190
+ <div class="flex flex-wrap items-center justify-between gap-3">
143
191
  <a
144
192
  href="/admin/forms/{submission.formSlug}"
145
- class="text-muted-foreground hover:text-foreground flex items-center gap-1 text-sm"
193
+ class="text-muted-foreground hover:text-primary flex items-center gap-1.5 text-sm font-medium transition-colors"
146
194
  >
147
195
  <ArrowLeft class="size-4" />
148
- {lang[interfaceLanguage.current].back}
196
+ {t.back}
149
197
  </a>
150
198
 
151
- <div class="flex items-center gap-2">
199
+ <nav class="flex items-center gap-2" aria-label={t.previous}>
152
200
  {#if previousSubmission}
153
- <Button variant="outline" size="sm" href="/admin/form-submissions/{previousSubmission.id}">
154
- <ChevronLeft class="mr-1 size-4" />
155
- {lang[interfaceLanguage.current].previous}
201
+ <Button
202
+ variant="outline"
203
+ size="icon"
204
+ class="size-8"
205
+ href="/admin/form-submissions/{previousSubmission.id}"
206
+ title={t.previous}
207
+ >
208
+ <ChevronLeft class="size-4" />
209
+ </Button>
210
+ {:else}
211
+ <Button variant="outline" size="icon" class="size-8" disabled>
212
+ <ChevronLeft class="size-4" />
156
213
  </Button>
157
214
  {/if}
215
+ <span class="text-muted-foreground px-1 text-sm font-medium">
216
+ {currentIndex + 1} {t.of} {allSubmissions.length}
217
+ </span>
158
218
  {#if nextSubmission}
159
- <Button variant="outline" size="sm" href="/admin/form-submissions/{nextSubmission.id}">
160
- {lang[interfaceLanguage.current].next}
161
- <ChevronRight class="ml-1 size-4" />
219
+ <Button
220
+ variant="outline"
221
+ size="icon"
222
+ class="size-8"
223
+ href="/admin/form-submissions/{nextSubmission.id}"
224
+ title={t.next}
225
+ >
226
+ <ChevronRight class="size-4" />
227
+ </Button>
228
+ {:else}
229
+ <Button variant="outline" size="icon" class="size-8" disabled>
230
+ <ChevronRight class="size-4" />
162
231
  </Button>
163
232
  {/if}
164
- </div>
233
+ </nav>
165
234
  </div>
166
235
 
167
- <div class="flex flex-wrap items-center justify-between gap-4 rounded-lg border bg-white p-4 dark:bg-slate-900">
168
- <div class="flex items-center gap-4">
169
- <span class="text-muted-foreground text-sm">{createdAtFormatted}</span>
170
- <Badge variant={isRead ? 'secondary' : 'default'}>
171
- {isRead ? lang[interfaceLanguage.current].read : lang[interfaceLanguage.current].new}
172
- </Badge>
236
+ <!-- Title + status -->
237
+ <div>
238
+ <div class="mb-1 flex flex-wrap items-center gap-3">
239
+ <h1 class="text-2xl font-bold">{titleValue}</h1>
240
+ {#if isRead}
241
+ <span
242
+ class="bg-lavender-lighter text-primary inline-flex h-6 items-center rounded-full px-2.5 text-xs font-semibold"
243
+ >
244
+ {t.read}
245
+ </span>
246
+ {:else}
247
+ <span
248
+ class="bg-primary inline-flex h-6 items-center rounded-full px-2.5 text-xs font-semibold text-white"
249
+ >
250
+ {t.new}
251
+ </span>
252
+ {/if}
173
253
  </div>
254
+ <p class="text-muted-foreground text-sm font-medium">{formLabel}</p>
255
+ </div>
174
256
 
175
- <div class="flex items-center gap-2">
176
- <Button variant="outline" size="sm" onclick={toggleRead}>
177
- {#if isRead}
178
- <EyeOff class="mr-2 size-4" />
179
- {lang[interfaceLanguage.current].markUnread}
180
- {:else}
181
- <Eye class="mr-2 size-4" />
182
- {lang[interfaceLanguage.current].markRead}
183
- {/if}
184
- </Button>
185
-
186
- {#if emailValue}
187
- <Button variant="outline" size="sm" onclick={handleReply}>
188
- <Mail class="mr-2 size-4" />
189
- {lang[interfaceLanguage.current].reply}
190
- </Button>
257
+ <!-- Actions bar -->
258
+ <div class="flex flex-wrap items-center gap-2">
259
+ <Button variant="outline" size="sm" class="gap-1.5" onclick={toggleRead}>
260
+ {#if isRead}
261
+ <EyeOff class="size-4" />
262
+ {t.markUnread}
263
+ {:else}
264
+ <Eye class="size-4" />
265
+ {t.markRead}
191
266
  {/if}
267
+ </Button>
192
268
 
193
- <Button variant="destructive" size="sm" onclick={handleDelete}>
194
- <Trash class="mr-2 size-4" />
195
- {lang[interfaceLanguage.current].delete}
269
+ {#if emailValue}
270
+ <Button variant="outline" size="sm" class="gap-1.5" onclick={handleReply}>
271
+ <Mail class="size-4" />
272
+ {t.reply}
196
273
  </Button>
197
- </div>
274
+ {/if}
275
+
276
+ <Button variant="outline" size="sm" class="gap-1.5" onclick={handlePrint}>
277
+ <Printer class="size-4" />
278
+ {t.print}
279
+ </Button>
280
+
281
+ <div class="flex-1"></div>
282
+
283
+ <AlertDialog.Root bind:open={deleteDialogOpen}>
284
+ <AlertDialog.Trigger>
285
+ {#snippet child({ props })}
286
+ <Button
287
+ {...props}
288
+ variant="outline"
289
+ size="sm"
290
+ class="gap-1.5 text-destructive hover:bg-destructive/10"
291
+ >
292
+ <Trash class="size-4" />
293
+ {t.delete}
294
+ </Button>
295
+ {/snippet}
296
+ </AlertDialog.Trigger>
297
+ <AlertDialog.Content>
298
+ <div class="flex flex-col gap-2">
299
+ <AlertDialog.Title>{t.confirmDeleteTitle}</AlertDialog.Title>
300
+ <AlertDialog.Description>
301
+ {t.confirmDeleteDesc}
302
+ </AlertDialog.Description>
303
+ </div>
304
+ <AlertDialog.Footer>
305
+ <AlertDialog.Cancel>{t.cancel}</AlertDialog.Cancel>
306
+ <AlertDialog.Action
307
+ class="bg-destructive text-destructive-foreground hover:bg-destructive/90"
308
+ onclick={handleDelete}
309
+ >
310
+ <Trash class="mr-1.5 size-4" />
311
+ {t.delete}
312
+ </AlertDialog.Action>
313
+ </AlertDialog.Footer>
314
+ </AlertDialog.Content>
315
+ </AlertDialog.Root>
198
316
  </div>
199
317
 
200
- <div class="grid gap-6 lg:grid-cols-3">
201
- <div class="space-y-4 lg:col-span-2">
202
- <h2 class="text-lg font-semibold">{lang[interfaceLanguage.current].formData}</h2>
203
- <div class="grid gap-4 sm:grid-cols-2">
318
+ <!-- Two-column layout -->
319
+ <div class="grid items-start gap-7 lg:grid-cols-[2fr_1fr]">
320
+ <!-- Left: Form data -->
321
+ <section aria-labelledby="form-data-heading">
322
+ <h2 class="mb-4 text-lg font-semibold" id="form-data-heading">{t.formData}</h2>
323
+ <div class="grid gap-3 sm:grid-cols-2">
204
324
  {#each form.fields as field}
205
- <SubmissionField
206
- label={getLocalizedLabel(field.label, interfaceLanguage.current) || field.slug}
207
- value={submission.data[field.slug]}
208
- fieldType={field.type}
209
- />
325
+ {@const isFullWidth = field.type === 'textarea' || field.type === 'checkbox'}
326
+ <div class={isFullWidth ? 'sm:col-span-2' : ''}>
327
+ <SubmissionField
328
+ label={getLocalizedLabel(field.label, interfaceLanguage.current) ||
329
+ field.slug}
330
+ value={submission.data[field.slug]}
331
+ fieldType={field.type}
332
+ />
333
+ </div>
210
334
  {/each}
211
335
  </div>
212
- </div>
336
+ </section>
213
337
 
214
- <div class="space-y-4">
215
- <h2 class="text-lg font-semibold">{lang[interfaceLanguage.current].metadata}</h2>
216
- <div class="space-y-3 rounded-lg border bg-slate-50 p-4 dark:bg-slate-800/50">
217
- <div class="flex items-center gap-3">
218
- <Calendar class="size-4 text-slate-400" />
219
- <div>
220
- <p class="text-muted-foreground text-xs">{lang[interfaceLanguage.current].createdAt}</p>
221
- <p class="text-sm font-medium">{createdAtFormatted}</p>
222
- </div>
338
+ <!-- Right: Metadata -->
339
+ <aside class="lg:sticky lg:top-7" aria-labelledby="metadata-heading">
340
+ <div class="overflow-hidden rounded-xl border shadow-sm">
341
+ <div class="border-b px-5 py-4">
342
+ <h2 class="text-sm font-bold" id="metadata-heading">{t.metadata}</h2>
223
343
  </div>
224
-
225
- <div class="flex items-center gap-3">
226
- <Globe class="size-4 text-slate-400" />
227
- <div>
228
- <p class="text-muted-foreground text-xs">{lang[interfaceLanguage.current].ip}</p>
229
- <p class="text-sm font-medium">{submission.ip || '-'}</p>
344
+ <div class="divide-y">
345
+ <div class="flex items-center gap-3 px-5 py-3">
346
+ <div
347
+ class="bg-surface flex size-8 shrink-0 items-center justify-center rounded-md"
348
+ >
349
+ <ClipboardList class="text-muted-foreground size-4" />
350
+ </div>
351
+ <div>
352
+ <div
353
+ class="text-muted-foreground text-[11px] font-semibold uppercase tracking-wide"
354
+ >
355
+ {t.context}
356
+ </div>
357
+ <div class="mt-0.5 text-sm font-medium">{formLabel}</div>
358
+ </div>
230
359
  </div>
231
- </div>
232
-
233
- <div class="flex items-center gap-3">
234
- <Monitor class="size-4 text-slate-400" />
235
- <div>
236
- <p class="text-muted-foreground text-xs">{lang[interfaceLanguage.current].device}</p>
237
- <p class="text-sm font-medium">{parseUserAgent(submission.userAgent)}</p>
360
+ <div class="flex items-center gap-3 px-5 py-3">
361
+ <div
362
+ class="bg-surface flex size-8 shrink-0 items-center justify-center rounded-md"
363
+ >
364
+ <Calendar class="text-muted-foreground size-4" />
365
+ </div>
366
+ <div>
367
+ <div
368
+ class="text-muted-foreground text-[11px] font-semibold uppercase tracking-wide"
369
+ >
370
+ {t.createdAt}
371
+ </div>
372
+ <div class="mt-0.5 text-sm font-medium">
373
+ <time datetime={new Date(submission.createdAt).toISOString()}>
374
+ {createdAtFormatted}
375
+ </time>
376
+ </div>
377
+ </div>
378
+ </div>
379
+ <div class="flex items-center gap-3 px-5 py-3">
380
+ <div
381
+ class="bg-surface flex size-8 shrink-0 items-center justify-center rounded-md"
382
+ >
383
+ <Globe class="text-muted-foreground size-4" />
384
+ </div>
385
+ <div>
386
+ <div
387
+ class="text-muted-foreground text-[11px] font-semibold uppercase tracking-wide"
388
+ >
389
+ {t.ip}
390
+ </div>
391
+ <div class="mt-0.5 text-sm font-medium">{submission.ip || '-'}</div>
392
+ </div>
238
393
  </div>
394
+ <div class="flex items-center gap-3 px-5 py-3">
395
+ <div
396
+ class="bg-surface flex size-8 shrink-0 items-center justify-center rounded-md"
397
+ >
398
+ <Monitor class="text-muted-foreground size-4" />
399
+ </div>
400
+ <div>
401
+ <div
402
+ class="text-muted-foreground text-[11px] font-semibold uppercase tracking-wide"
403
+ >
404
+ {t.device}
405
+ </div>
406
+ <div class="mt-0.5 text-sm font-medium">
407
+ {parseUserAgent(submission.userAgent)}
408
+ </div>
409
+ </div>
410
+ </div>
411
+ </div>
412
+ <div class="flex flex-col gap-2 border-t p-4">
413
+ <Button variant="outline" size="sm" class="w-full gap-1.5" onclick={handlePrint}>
414
+ <Printer class="size-3.5" />
415
+ {t.printSubmission}
416
+ </Button>
239
417
  </div>
240
418
  </div>
241
- </div>
419
+ </aside>
242
420
  </div>
243
421
  </div>
422
+
423
+ <style>
424
+ @media print {
425
+ :global(.sidebar),
426
+ :global(.site-header),
427
+ :global([data-slot='sheet-content']) {
428
+ display: none !important;
429
+ }
430
+ }
431
+ </style>
@@ -48,26 +48,26 @@
48
48
  }
49
49
  </script>
50
50
 
51
- <div class="rounded-lg border bg-white p-4 dark:bg-slate-900">
51
+ <div class="rounded-lg border bg-card p-4">
52
52
  <div class="mb-2 flex items-center gap-2">
53
53
  {#if iconType === 'check'}
54
- <CheckCircle class="size-4 text-slate-400" />
54
+ <CheckCircle class="size-4 text-muted-foreground" />
55
55
  {:else if iconType === 'x'}
56
- <CircleX class="size-4 text-slate-400" />
56
+ <CircleX class="size-4 text-muted-foreground" />
57
57
  {:else if iconType === 'mail'}
58
- <Mail class="size-4 text-slate-400" />
58
+ <Mail class="size-4 text-muted-foreground" />
59
59
  {:else if iconType === 'phone'}
60
- <Phone class="size-4 text-slate-400" />
60
+ <Phone class="size-4 text-muted-foreground" />
61
61
  {:else if iconType === 'message'}
62
- <MessageSquare class="size-4 text-slate-400" />
62
+ <MessageSquare class="size-4 text-muted-foreground" />
63
63
  {:else if iconType === 'hash'}
64
- <Hash class="size-4 text-slate-400" />
64
+ <Hash class="size-4 text-muted-foreground" />
65
65
  {:else if iconType === 'calendar'}
66
- <Calendar class="size-4 text-slate-400" />
66
+ <Calendar class="size-4 text-muted-foreground" />
67
67
  {:else}
68
- <FileText class="size-4 text-slate-400" />
68
+ <FileText class="size-4 text-muted-foreground" />
69
69
  {/if}
70
- <span class="text-sm font-medium text-slate-500 dark:text-slate-400">{label}</span>
70
+ <span class="text-sm font-medium text-muted-foreground">{label}</span>
71
71
  </div>
72
72
 
73
73
  <div class="flex items-start justify-between gap-2">
@@ -82,9 +82,9 @@
82
82
  {/if}
83
83
  </div>
84
84
  {:else if isEmail}
85
- <a href="mailto:{value}" class="text-blue-600 hover:underline break-all">{displayValue()}</a>
85
+ <a href="mailto:{value}" class="text-primary hover:underline break-all">{displayValue()}</a>
86
86
  {:else if isPhone}
87
- <a href="tel:{value}" class="text-blue-600 hover:underline">{displayValue()}</a>
87
+ <a href="tel:{value}" class="text-primary hover:underline">{displayValue()}</a>
88
88
  {:else if fieldType === 'textarea'}
89
89
  <p class="whitespace-pre-wrap break-words">{displayValue()}</p>
90
90
  {:else}