includio-cms 0.1.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/ROADMAP.md +23 -13
  3. package/dist/admin/api/accept-invite.js +1 -5
  4. package/dist/admin/api/invite.js +7 -16
  5. package/dist/admin/client/account/account-page.svelte +20 -50
  6. package/dist/admin/client/account/lang.d.ts +15 -23
  7. package/dist/admin/client/account/lang.js +51 -67
  8. package/dist/admin/client/account/preferences-section.svelte +26 -84
  9. package/dist/admin/client/account/profile-section.svelte +60 -40
  10. package/dist/admin/client/account/schema.d.ts +11 -3
  11. package/dist/admin/client/account/schema.js +25 -16
  12. package/dist/admin/client/account/security-section.svelte +139 -105
  13. package/dist/admin/client/account/sessions-section.svelte +35 -34
  14. package/dist/admin/client/admin/admin-after-login-layout-content.svelte +3 -5
  15. package/dist/admin/client/admin/admin-layout.svelte +3 -2
  16. package/dist/admin/client/admin/admin-preloader.svelte +36 -0
  17. package/dist/admin/client/admin/admin-preloader.svelte.d.ts +18 -0
  18. package/dist/admin/client/admin/dashboard-page.svelte +55 -41
  19. package/dist/admin/client/collection/a11y-score-cell.svelte +45 -0
  20. package/dist/admin/client/collection/a11y-score-cell.svelte.d.ts +6 -0
  21. package/dist/admin/client/collection/bulk-actions-bar.svelte +83 -0
  22. package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +9 -0
  23. package/dist/admin/client/collection/collection-entries.svelte +255 -256
  24. package/dist/admin/client/collection/collection-view.svelte.d.ts +4 -3
  25. package/dist/admin/client/collection/collection-view.svelte.js +9 -5
  26. package/dist/admin/client/collection/collection.svelte +22 -12
  27. package/dist/admin/client/collection/data-table.svelte +50 -39
  28. package/dist/admin/client/collection/data-table.svelte.d.ts +1 -0
  29. package/dist/admin/client/collection/date-cell.svelte +7 -5
  30. package/dist/admin/client/collection/date-cell.svelte.d.ts +1 -1
  31. package/dist/admin/client/collection/empty-state.svelte +28 -0
  32. package/dist/admin/client/collection/empty-state.svelte.d.ts +9 -0
  33. package/dist/admin/client/collection/entry-link.svelte +10 -4
  34. package/dist/admin/client/collection/entry-link.svelte.d.ts +1 -0
  35. package/dist/admin/client/collection/grid-view.svelte +21 -23
  36. package/dist/admin/client/collection/grid-view.svelte.d.ts +1 -2
  37. package/dist/admin/client/collection/row-actions.svelte +60 -0
  38. package/dist/admin/client/collection/row-actions.svelte.d.ts +9 -0
  39. package/dist/admin/client/collection/status-badge.svelte +7 -8
  40. package/dist/admin/client/collection/table-pagination.svelte +122 -79
  41. package/dist/admin/client/collection/table-pagination.svelte.d.ts +1 -0
  42. package/dist/admin/client/collection/table-toolbar.svelte +108 -88
  43. package/dist/admin/client/collection/table-toolbar.svelte.d.ts +8 -9
  44. package/dist/admin/client/entry/entry-form.svelte +109 -1
  45. package/dist/admin/client/entry/entry-header.svelte +96 -37
  46. package/dist/admin/client/entry/entry-header.svelte.d.ts +5 -0
  47. package/dist/admin/client/entry/entry.svelte +171 -60
  48. package/dist/admin/client/entry/header/a11y-validator.d.ts +46 -0
  49. package/dist/admin/client/entry/header/a11y-validator.js +311 -0
  50. package/dist/admin/client/entry/header/publish-panel.svelte +373 -131
  51. package/dist/admin/client/entry/header/publish-panel.svelte.d.ts +4 -0
  52. package/dist/admin/client/entry/header/save-indicator.svelte +33 -23
  53. package/dist/admin/client/entry/header/schedule-popover.svelte +1 -1
  54. package/dist/admin/client/entry/header/status-badge.svelte +25 -118
  55. package/dist/admin/client/entry/header/version-history-sheet.svelte +314 -98
  56. package/dist/admin/client/form/form-submission/form-submission.svelte +271 -83
  57. package/dist/admin/client/form/form-submission/submission-field.svelte +12 -12
  58. package/dist/admin/client/form/form-submissions.svelte +421 -139
  59. package/dist/admin/client/form/submission-link.svelte +8 -2
  60. package/dist/admin/client/form/submission-link.svelte.d.ts +1 -0
  61. package/dist/admin/client/form/submission-status-badge.svelte +18 -4
  62. package/dist/admin/client/form/submission-status-badge.svelte.d.ts +1 -0
  63. package/dist/admin/client/login/lang.d.ts +32 -0
  64. package/dist/admin/client/login/lang.js +66 -2
  65. package/dist/admin/client/login/login-form.svelte +237 -95
  66. package/dist/admin/client/login/login-form.svelte.d.ts +2 -17
  67. package/dist/admin/client/login/login-page.svelte +34 -98
  68. package/dist/admin/client/login/reset-password-page.svelte +235 -0
  69. package/dist/admin/client/login/reset-password-page.svelte.d.ts +4 -0
  70. package/dist/admin/client/login/schema.d.ts +15 -0
  71. package/dist/admin/client/login/schema.js +21 -0
  72. package/dist/admin/client/users/accept-invite-page.svelte +166 -37
  73. package/dist/admin/client/users/create-user-dialog.svelte +15 -7
  74. package/dist/admin/client/users/delete-user-dialog.svelte +81 -16
  75. package/dist/admin/client/users/delete-user-dialog.svelte.d.ts +4 -1
  76. package/dist/admin/client/users/edit-user-dialog.svelte +3 -0
  77. package/dist/admin/client/users/invite-user-dialog.svelte +16 -3
  78. package/dist/admin/client/users/lang.d.ts +27 -0
  79. package/dist/admin/client/users/lang.js +64 -10
  80. package/dist/admin/client/users/pending-invitations.svelte +59 -23
  81. package/dist/admin/client/users/users-page.svelte +471 -72
  82. package/dist/admin/components/accessibility/accessibility-overview.svelte +2 -7
  83. package/dist/admin/components/dashboard/a11y-gauge.svelte +90 -0
  84. package/dist/admin/components/dashboard/a11y-gauge.svelte.d.ts +18 -0
  85. package/dist/admin/components/dashboard/accessibility-hub.svelte +13 -12
  86. package/dist/admin/components/dashboard/form-submissions-widget.svelte +71 -113
  87. package/dist/admin/components/dashboard/index.d.ts +4 -2
  88. package/dist/admin/components/dashboard/index.js +4 -2
  89. package/dist/admin/components/dashboard/recent-activity.svelte +53 -75
  90. package/dist/admin/components/dashboard/recent-entries.svelte +94 -0
  91. package/dist/admin/components/dashboard/recent-entries.svelte.d.ts +18 -0
  92. package/dist/admin/components/dashboard/stat-card.svelte +2 -2
  93. package/dist/admin/components/dashboard/tip-of-the-day.svelte +109 -0
  94. package/dist/admin/components/dashboard/tip-of-the-day.svelte.d.ts +3 -0
  95. package/dist/admin/components/dashboard/welcome-header.svelte +45 -0
  96. package/dist/admin/components/dashboard/welcome-header.svelte.d.ts +3 -0
  97. package/dist/admin/components/fields/{array-field.svelte → blocks-field.svelte} +4 -4
  98. package/dist/admin/components/fields/{array-field.svelte.d.ts → blocks-field.svelte.d.ts} +5 -5
  99. package/dist/admin/components/fields/content-field.svelte +27 -0
  100. package/dist/admin/components/fields/content-field.svelte.d.ts +31 -0
  101. package/dist/admin/components/fields/field-renderer.svelte +9 -7
  102. package/dist/admin/components/fields/image-field.svelte +2 -2
  103. package/dist/admin/components/fields/media-field.svelte +2 -2
  104. package/dist/admin/components/fields/seo-field.svelte +205 -25
  105. package/dist/admin/components/fields/simple-array-field.svelte +289 -0
  106. package/dist/admin/components/fields/simple-array-field.svelte.d.ts +30 -0
  107. package/dist/admin/components/fields/slug-field.svelte +3 -2
  108. package/dist/admin/components/fields/standalone-field-renderer.svelte +148 -0
  109. package/dist/admin/components/fields/standalone-field-renderer.svelte.d.ts +9 -0
  110. package/dist/admin/components/fields/text-field-wrapper.svelte +13 -1
  111. package/dist/admin/components/fields/text-field-wrapper.svelte.d.ts +2 -2
  112. package/dist/admin/components/fields/url-field.svelte +5 -4
  113. package/dist/admin/components/layout/app-sidebar.svelte +27 -24
  114. package/dist/admin/components/layout/lang.d.ts +6 -0
  115. package/dist/admin/components/layout/lang.js +13 -1
  116. package/dist/admin/components/layout/layout-renderer.svelte +352 -0
  117. package/dist/admin/components/layout/layout-renderer.svelte.d.ts +14 -0
  118. package/dist/admin/components/layout/nav-breadcrumbs.svelte +4 -4
  119. package/dist/admin/components/layout/nav-collections.svelte +65 -36
  120. package/dist/admin/components/layout/nav-footer.svelte +31 -0
  121. package/dist/admin/components/layout/nav-footer.svelte.d.ts +18 -0
  122. package/dist/admin/components/layout/nav-forms.svelte +55 -30
  123. package/dist/admin/components/layout/nav-main.svelte +14 -52
  124. package/dist/admin/components/layout/nav-search.svelte +4 -3
  125. package/dist/admin/components/layout/nav-singletons.svelte +59 -17
  126. package/dist/admin/components/layout/nav-singletons.svelte.d.ts +17 -8
  127. package/dist/admin/components/layout/site-header.svelte +74 -13
  128. package/dist/admin/components/media/alt-input.svelte +32 -22
  129. package/dist/admin/components/media/bulk-action-bar.svelte +139 -150
  130. package/dist/admin/components/media/file/file-details.svelte +299 -217
  131. package/dist/admin/components/media/file/file-miniature.svelte +54 -41
  132. package/dist/admin/components/media/file/file-miniature.svelte.d.ts +1 -0
  133. package/dist/admin/components/media/file/file-preview.svelte +1 -1
  134. package/dist/admin/components/media/file-upload.svelte +24 -26
  135. package/dist/admin/components/media/files-list.svelte +112 -40
  136. package/dist/admin/components/media/files-list.svelte.d.ts +2 -0
  137. package/dist/admin/components/media/focal-point-input.svelte +122 -26
  138. package/dist/admin/components/media/media-library.svelte +127 -70
  139. package/dist/admin/components/media/media-search.svelte +6 -6
  140. package/dist/admin/components/media/media-sort.svelte +3 -1
  141. package/dist/admin/components/media/multi-file-summary.svelte +88 -68
  142. package/dist/admin/components/media/tag-combobox.svelte +141 -66
  143. package/dist/admin/components/media/tag-combobox.svelte.d.ts +1 -0
  144. package/dist/admin/components/media/tag-sidebar.svelte +139 -121
  145. package/dist/admin/components/tiptap/FigureNodeView.svelte +144 -15
  146. package/dist/admin/components/tiptap/InlineBlockNodeView.svelte +254 -0
  147. package/dist/admin/components/tiptap/InlineBlockNodeView.svelte.d.ts +4 -0
  148. package/dist/admin/components/tiptap/SlashCommandPopup.svelte +212 -0
  149. package/dist/admin/components/tiptap/SlashCommandPopup.svelte.d.ts +8 -0
  150. package/dist/admin/components/tiptap/content-editor.svelte +280 -0
  151. package/dist/admin/components/tiptap/content-editor.svelte.d.ts +9 -0
  152. package/dist/admin/components/tiptap/editor-toolbar.svelte +230 -0
  153. package/dist/admin/components/tiptap/editor-toolbar.svelte.d.ts +16 -0
  154. package/dist/admin/components/tiptap/heading-a11y-plugin.d.ts +2 -0
  155. package/dist/admin/components/tiptap/heading-a11y-plugin.js +67 -0
  156. package/dist/admin/components/tiptap/image-dialog.svelte +172 -11
  157. package/dist/admin/components/tiptap/inline-block-node.d.ts +19 -0
  158. package/dist/admin/components/tiptap/inline-block-node.js +98 -0
  159. package/dist/admin/components/tiptap/link-dialog.svelte +9 -4
  160. package/dist/admin/components/tiptap/slash-command.d.ts +17 -0
  161. package/dist/admin/components/tiptap/slash-command.js +181 -0
  162. package/dist/admin/components/tiptap/structured-content-utils.d.ts +21 -0
  163. package/dist/admin/components/tiptap/structured-content-utils.js +150 -0
  164. package/dist/admin/components/tiptap/tiptap-editor.svelte +18 -190
  165. package/dist/admin/email/invite-template.d.ts +8 -0
  166. package/dist/admin/email/invite-template.js +99 -0
  167. package/dist/admin/email/reset-password-template.d.ts +7 -0
  168. package/dist/admin/email/reset-password-template.js +96 -0
  169. package/dist/admin/remote/ai.remote.d.ts +1 -0
  170. package/dist/admin/remote/ai.remote.js +4 -1
  171. package/dist/admin/remote/entry.remote.d.ts +8 -0
  172. package/dist/admin/remote/entry.remote.js +53 -4
  173. package/dist/admin/remote/preview.remote.js +2 -1
  174. package/dist/admin/shared/password-schema.d.ts +5 -0
  175. package/dist/admin/shared/password-schema.js +10 -0
  176. package/dist/admin/styles/admin.css +1530 -151
  177. package/dist/admin/utils/formatDate.d.ts +1 -0
  178. package/dist/admin/utils/formatDate.js +8 -0
  179. package/dist/admin/utils/roleLabel.d.ts +2 -0
  180. package/dist/admin/utils/roleLabel.js +13 -0
  181. package/dist/ai-claude/index.d.ts +2 -0
  182. package/dist/ai-claude/index.js +56 -0
  183. package/dist/cms/runtime/api.d.ts +6 -1
  184. package/dist/cms/runtime/api.js +3 -0
  185. package/dist/cms/runtime/schemas.d.ts +9 -1
  186. package/dist/cms/runtime/schemas.js +8 -0
  187. package/dist/cms/runtime/types.d.ts +82 -10
  188. package/dist/cms/runtime/types.js +4 -0
  189. package/dist/components/ui/accordion/accordion.stories.svelte +39 -0
  190. package/dist/components/ui/accordion/accordion.stories.svelte.d.ts +27 -0
  191. package/dist/components/ui/alert/alert.stories.svelte +53 -0
  192. package/dist/components/ui/alert/alert.stories.svelte.d.ts +27 -0
  193. package/dist/components/ui/alert/alert.svelte +5 -0
  194. package/dist/components/ui/alert/alert.svelte.d.ts +9 -0
  195. package/dist/components/ui/avatar/avatar.stories.svelte +16 -0
  196. package/dist/components/ui/avatar/avatar.stories.svelte.d.ts +27 -0
  197. package/dist/components/ui/badge/badge.stories.svelte +33 -0
  198. package/dist/components/ui/badge/badge.stories.svelte.d.ts +27 -0
  199. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte +33 -0
  200. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte.d.ts +27 -0
  201. package/dist/components/ui/button/button.stories.svelte +43 -0
  202. package/dist/components/ui/button/button.stories.svelte.d.ts +27 -0
  203. package/dist/components/ui/button/button.svelte +1 -2
  204. package/dist/components/ui/button/button.svelte.d.ts +0 -3
  205. package/dist/components/ui/button-group/button-group-separator.svelte.d.ts +1 -1
  206. package/dist/components/ui/card/card.stories.svelte +42 -0
  207. package/dist/components/ui/card/card.stories.svelte.d.ts +27 -0
  208. package/dist/components/ui/command/command.stories.svelte +51 -0
  209. package/dist/components/ui/command/command.stories.svelte.d.ts +27 -0
  210. package/dist/components/ui/dialog/dialog.stories.svelte +29 -0
  211. package/dist/components/ui/dialog/dialog.stories.svelte.d.ts +27 -0
  212. package/dist/components/ui/field/field-label.svelte.d.ts +1 -1
  213. package/dist/components/ui/field/field.stories.svelte +21 -0
  214. package/dist/components/ui/field/field.stories.svelte.d.ts +27 -0
  215. package/dist/components/ui/input/input.stories.svelte +40 -0
  216. package/dist/components/ui/input/input.stories.svelte.d.ts +27 -0
  217. package/dist/components/ui/input/input.svelte +2 -4
  218. package/dist/components/ui/item/item-separator.svelte.d.ts +1 -1
  219. package/dist/components/ui/label/label.stories.svelte +20 -0
  220. package/dist/components/ui/label/label.stories.svelte.d.ts +27 -0
  221. package/dist/components/ui/popover/popover.stories.svelte +29 -0
  222. package/dist/components/ui/popover/popover.stories.svelte.d.ts +27 -0
  223. package/dist/components/ui/select/select-group-heading.svelte.d.ts +1 -1
  224. package/dist/components/ui/select/select.stories.svelte +23 -0
  225. package/dist/components/ui/select/select.stories.svelte.d.ts +27 -0
  226. package/dist/components/ui/separator/separator.stories.svelte +24 -0
  227. package/dist/components/ui/separator/separator.stories.svelte.d.ts +27 -0
  228. package/dist/components/ui/sheet/sheet.stories.svelte +29 -0
  229. package/dist/components/ui/sheet/sheet.stories.svelte.d.ts +27 -0
  230. package/dist/components/ui/sidebar/sidebar-group.svelte +3 -3
  231. package/dist/components/ui/sidebar/sidebar-group.svelte.d.ts +2 -2
  232. package/dist/components/ui/sidebar/sidebar-menu-button.svelte +28 -30
  233. package/dist/components/ui/sidebar/sidebar-menu-button.svelte.d.ts +7 -7
  234. package/dist/components/ui/sidebar/sidebar-separator.svelte.d.ts +1 -1
  235. package/dist/components/ui/sidebar/sidebar-trigger.svelte +4 -4
  236. package/dist/components/ui/sonner/sonner.stories.svelte +22 -0
  237. package/dist/components/ui/sonner/sonner.stories.svelte.d.ts +26 -0
  238. package/dist/components/ui/sonner/sonner.svelte +8 -2
  239. package/dist/components/ui/sonner/toast-demo.svelte +29 -0
  240. package/dist/components/ui/sonner/toast-demo.svelte.d.ts +6 -0
  241. package/dist/components/ui/textarea/textarea.stories.svelte +22 -0
  242. package/dist/components/ui/textarea/textarea.stories.svelte.d.ts +27 -0
  243. package/dist/components/ui/textarea/textarea.svelte +0 -2
  244. package/dist/components/ui/toggle/toggle.stories.svelte +22 -0
  245. package/dist/components/ui/toggle/toggle.stories.svelte.d.ts +27 -0
  246. package/dist/components/ui/toggle-group/toggle-group.stories.svelte +17 -0
  247. package/dist/components/ui/toggle-group/toggle-group.stories.svelte.d.ts +27 -0
  248. package/dist/components/ui/tooltip/tooltip.stories.svelte +26 -0
  249. package/dist/components/ui/tooltip/tooltip.stories.svelte.d.ts +27 -0
  250. package/dist/core/fields/fieldSchemaToTs.d.ts +1 -0
  251. package/dist/core/fields/fieldSchemaToTs.js +133 -1
  252. package/dist/core/fields/layoutUtils.d.ts +17 -0
  253. package/dist/core/fields/layoutUtils.js +149 -0
  254. package/dist/core/fields/structuredToHtml.d.ts +9 -0
  255. package/dist/core/fields/structuredToHtml.js +161 -0
  256. package/dist/core/server/entries/operations/create.js +2 -1
  257. package/dist/core/server/entries/operations/get.js +8 -6
  258. package/dist/core/server/entries/operations/update.d.ts +3 -0
  259. package/dist/core/server/entries/operations/update.js +30 -2
  260. package/dist/core/server/fields/queryStructuredContent.d.ts +15 -0
  261. package/dist/core/server/fields/queryStructuredContent.js +65 -0
  262. package/dist/core/server/fields/resolveImageFields.js +51 -2
  263. package/dist/core/server/fields/resolveRelationFields.js +2 -2
  264. package/dist/core/server/fields/resolveRichtextLinks.js +80 -13
  265. package/dist/core/server/fields/resolveUrlFields.js +57 -6
  266. package/dist/core/server/fields/slugResolver.d.ts +10 -0
  267. package/dist/core/server/fields/slugResolver.js +34 -0
  268. package/dist/core/server/generator/fields.js +15 -4
  269. package/dist/core/server/generator/generator.js +3 -2
  270. package/dist/files-local/index.js +126 -64
  271. package/dist/paraglide/.prettierignore +3 -0
  272. package/dist/paraglide/messages/_index.d.ts +36 -0
  273. package/dist/paraglide/messages/_index.js +72 -0
  274. package/dist/paraglide/messages/en.d.ts +5 -0
  275. package/dist/paraglide/messages/en.js +14 -0
  276. package/dist/paraglide/messages/pl.d.ts +5 -0
  277. package/dist/paraglide/messages/pl.js +14 -0
  278. package/dist/paraglide/messages.d.ts +2 -0
  279. package/dist/paraglide/messages.js +4 -0
  280. package/dist/paraglide/registry.d.ts +21 -0
  281. package/dist/paraglide/registry.js +31 -0
  282. package/dist/paraglide/runtime.d.ts +583 -0
  283. package/dist/paraglide/runtime.js +1402 -0
  284. package/dist/paraglide/server.d.ts +67 -0
  285. package/dist/paraglide/server.js +175 -0
  286. package/dist/server/auth.d.ts +5 -0
  287. package/dist/server/auth.js +12 -1
  288. package/dist/sveltekit/components/structured-content.svelte +204 -0
  289. package/dist/sveltekit/components/structured-content.svelte.d.ts +21 -0
  290. package/dist/sveltekit/config.d.ts +13 -3
  291. package/dist/sveltekit/index.d.ts +3 -0
  292. package/dist/sveltekit/index.js +3 -0
  293. package/dist/sveltekit/server/handle.js +1 -0
  294. package/dist/types/config.d.ts +3 -0
  295. package/dist/types/fields.d.ts +19 -2
  296. package/dist/types/index.d.ts +2 -0
  297. package/dist/types/index.js +2 -0
  298. package/dist/types/layout.d.ts +54 -0
  299. package/dist/types/layout.js +6 -0
  300. package/dist/types/structured-content.d.ts +63 -0
  301. package/dist/types/structured-content.js +1 -0
  302. package/dist/updates/0.1.4/index.d.ts +2 -0
  303. package/dist/updates/0.1.4/index.js +11 -0
  304. package/dist/updates/0.1.5/index.d.ts +2 -0
  305. package/dist/updates/0.1.5/index.js +18 -0
  306. package/dist/updates/0.2.0/index.d.ts +2 -0
  307. package/dist/updates/0.2.0/index.js +11 -0
  308. package/dist/updates/0.2.2/index.d.ts +2 -0
  309. package/dist/updates/0.2.2/index.js +13 -0
  310. package/dist/updates/0.5.0/index.d.ts +2 -0
  311. package/dist/updates/0.5.0/index.js +14 -0
  312. package/dist/updates/index.js +6 -1
  313. package/package.json +17 -10
@@ -0,0 +1,212 @@
1
+ <script lang="ts">
2
+ import type { SlashCommandItem } from './slash-command.js';
3
+ import { onMount } from 'svelte';
4
+
5
+ type Props = {
6
+ items: SlashCommandItem[];
7
+ command: (item: SlashCommandItem) => void;
8
+ };
9
+
10
+ let { items, command }: Props = $props();
11
+
12
+ let selectedIndex = $state(0);
13
+ let listEl = $state<HTMLDivElement | null>(null);
14
+ let showTier2 = $state(false);
15
+
16
+ // When user is searching (items filtered), show all tiers
17
+ const isFiltered = $derived(items.length > 0 && items.some((i) => i.tier === 2) && items.some((i) => i.tier === 1)
18
+ ? false
19
+ : true
20
+ );
21
+
22
+ const visibleItems = $derived.by(() => {
23
+ if (isFiltered || showTier2) return items;
24
+ return items.filter((i) => !i.tier || i.tier === 1);
25
+ });
26
+
27
+ const hasTier2Hidden = $derived(!isFiltered && !showTier2 && items.some((i) => i.tier === 2));
28
+
29
+ // Group items by group name
30
+ const grouped = $derived(() => {
31
+ const groups = new Map<string, SlashCommandItem[]>();
32
+ for (const item of visibleItems) {
33
+ const existing = groups.get(item.group) ?? [];
34
+ existing.push(item);
35
+ groups.set(item.group, existing);
36
+ }
37
+ return groups;
38
+ });
39
+
40
+ function selectItem(index: number) {
41
+ const item = visibleItems[index];
42
+ if (item) command(item);
43
+ }
44
+
45
+ function handleKeydown(e: CustomEvent<{ key: string }>) {
46
+ const { key } = e.detail;
47
+ if (key === 'ArrowDown') {
48
+ e.preventDefault();
49
+ selectedIndex = (selectedIndex + 1) % visibleItems.length;
50
+ scrollToSelected();
51
+ } else if (key === 'ArrowUp') {
52
+ e.preventDefault();
53
+ selectedIndex = (selectedIndex - 1 + visibleItems.length) % visibleItems.length;
54
+ scrollToSelected();
55
+ } else if (key === 'Enter') {
56
+ e.preventDefault();
57
+ selectItem(selectedIndex);
58
+ }
59
+ }
60
+
61
+ function scrollToSelected() {
62
+ const el = listEl?.querySelector(`[data-index="${selectedIndex}"]`);
63
+ el?.scrollIntoView({ block: 'nearest' });
64
+ }
65
+
66
+ onMount(() => {
67
+ const el = listEl;
68
+ if (!el) return;
69
+
70
+ const handler = (e: Event) => handleKeydown(e as CustomEvent<{ key: string }>);
71
+ el.addEventListener('slash-keydown', handler);
72
+ return () => el.removeEventListener('slash-keydown', handler);
73
+ });
74
+
75
+ // Reset selection when items change
76
+ $effect(() => {
77
+ items; // dependency
78
+ selectedIndex = 0;
79
+ });
80
+ </script>
81
+
82
+ <div class="slash-popup" bind:this={listEl} data-slash-popup role="listbox" aria-label="Polecenia">
83
+ {#if items.length === 0}
84
+ <div class="slash-empty">Brak wyników</div>
85
+ {:else}
86
+ {@const groups = grouped()}
87
+ {#each [...groups.entries()] as [group, groupItems]}
88
+ <div class="slash-group-label" role="presentation">{group}</div>
89
+ {#each groupItems as item}
90
+ {@const idx = visibleItems.indexOf(item)}
91
+ <button
92
+ type="button"
93
+ class="slash-item"
94
+ class:selected={idx === selectedIndex}
95
+ data-index={idx}
96
+ role="option"
97
+ aria-selected={idx === selectedIndex}
98
+ onclick={() => selectItem(idx)}
99
+ onmouseenter={() => (selectedIndex = idx)}
100
+ >
101
+ <div class="slash-item-content">
102
+ <span class="slash-item-label">{item.label}</span>
103
+ {#if item.description}
104
+ <span class="slash-item-desc">{item.description}</span>
105
+ {/if}
106
+ </div>
107
+ </button>
108
+ {/each}
109
+ {/each}
110
+
111
+ {#if hasTier2Hidden}
112
+ <button
113
+ type="button"
114
+ class="slash-more-btn"
115
+ onclick={() => (showTier2 = true)}
116
+ >
117
+ Więcej...
118
+ </button>
119
+ {/if}
120
+ {/if}
121
+ </div>
122
+
123
+ <style>
124
+ .slash-popup {
125
+ background: var(--popover);
126
+ color: var(--popover-foreground);
127
+ border: 1px solid var(--border);
128
+ border-radius: 8px;
129
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
130
+ overflow-y: auto;
131
+ max-height: 320px;
132
+ min-width: 220px;
133
+ padding: 0.25rem;
134
+ }
135
+
136
+ .slash-group-label {
137
+ padding: 0.375rem 0.5rem 0.25rem;
138
+ font-size: 0.6875rem;
139
+ font-weight: 600;
140
+ text-transform: uppercase;
141
+ letter-spacing: 0.05em;
142
+ color: var(--muted-foreground);
143
+ }
144
+
145
+ .slash-item {
146
+ display: flex;
147
+ align-items: center;
148
+ width: 100%;
149
+ padding: 0.375rem 0.5rem;
150
+ border: none;
151
+ background: transparent;
152
+ border-radius: 6px;
153
+ cursor: pointer;
154
+ font-size: 0.8125rem;
155
+ color: var(--foreground);
156
+ text-align: left;
157
+ min-height: 36px;
158
+ transition: background-color 0.1s;
159
+ }
160
+
161
+ .slash-item:hover,
162
+ .slash-item.selected {
163
+ background: var(--accent);
164
+ }
165
+
166
+ .slash-item:focus-visible {
167
+ outline: 2px solid var(--ring);
168
+ outline-offset: -2px;
169
+ }
170
+
171
+ .slash-item-content {
172
+ display: flex;
173
+ flex-direction: column;
174
+ gap: 1px;
175
+ }
176
+
177
+ .slash-item-label {
178
+ font-weight: 500;
179
+ }
180
+
181
+ .slash-item-desc {
182
+ font-size: 0.6875rem;
183
+ color: var(--muted-foreground);
184
+ line-height: 1.3;
185
+ }
186
+
187
+ .slash-more-btn {
188
+ display: block;
189
+ width: 100%;
190
+ padding: 0.375rem 0.5rem;
191
+ border: none;
192
+ background: transparent;
193
+ border-radius: 6px;
194
+ cursor: pointer;
195
+ font-size: 0.75rem;
196
+ font-weight: 500;
197
+ color: var(--primary);
198
+ text-align: left;
199
+ transition: background-color 0.1s;
200
+ }
201
+
202
+ .slash-more-btn:hover {
203
+ background: var(--accent);
204
+ }
205
+
206
+ .slash-empty {
207
+ padding: 1rem;
208
+ text-align: center;
209
+ color: var(--muted-foreground);
210
+ font-size: 0.8125rem;
211
+ }
212
+ </style>
@@ -0,0 +1,8 @@
1
+ import type { SlashCommandItem } from './slash-command.js';
2
+ type Props = {
3
+ items: SlashCommandItem[];
4
+ command: (item: SlashCommandItem) => void;
5
+ };
6
+ declare const SlashCommandPopup: import("svelte").Component<Props, {}, "">;
7
+ type SlashCommandPopup = ReturnType<typeof SlashCommandPopup>;
8
+ export default SlashCommandPopup;
@@ -0,0 +1,280 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import { Editor, type Editor as EditorType } from '@tiptap/core';
4
+ import BubbleMenu from '@tiptap/extension-bubble-menu';
5
+ import { extensions } from './extensions.js';
6
+ import ToolbarButton from './toolbar-button.svelte';
7
+ import EditorToolbar from './editor-toolbar.svelte';
8
+ import LinkDialog from './link-dialog.svelte';
9
+ import ImageDialog from './image-dialog.svelte';
10
+ import VideoDialog from './video-dialog.svelte';
11
+ import TableDialog from './table-dialog.svelte';
12
+ import * as Tooltip from '../../../components/ui/tooltip/index.js';
13
+ import Separator from '../../../components/ui/separator/separator.svelte';
14
+ import type { StructuredContentDoc } from '../../../types/structured-content.js';
15
+ import type { ObjectField } from '../../../types/fields.js';
16
+ import { tiptapDocToStructured, structuredToTiptapDoc } from './structured-content-utils.js';
17
+ import { InlineBlockNode } from './inline-block-node.js';
18
+ import { SlashCommand } from './slash-command.js';
19
+ import { HeadingA11yPlugin } from './heading-a11y-plugin.js';
20
+
21
+ // Icons (bubble menu only)
22
+ import Bold from '@tabler/icons-svelte/icons/bold';
23
+ import Italic from '@tabler/icons-svelte/icons/italic';
24
+ import Underline from '@tabler/icons-svelte/icons/underline';
25
+ import Strikethrough from '@tabler/icons-svelte/icons/strikethrough';
26
+ import Highlight from '@tabler/icons-svelte/icons/highlight';
27
+ import LinkIcon from '@tabler/icons-svelte/icons/link';
28
+ import RowInsertBottom from '@tabler/icons-svelte/icons/row-insert-bottom';
29
+ import RowInsertTop from '@tabler/icons-svelte/icons/row-insert-top';
30
+ import ColumnInsertLeft from '@tabler/icons-svelte/icons/column-insert-left';
31
+ import ColumnInsertRight from '@tabler/icons-svelte/icons/column-insert-right';
32
+ import RowRemove from '@tabler/icons-svelte/icons/row-remove';
33
+ import ColumnRemove from '@tabler/icons-svelte/icons/column-remove';
34
+ import TableOff from '@tabler/icons-svelte/icons/table-off';
35
+ import Unlink from '@tabler/icons-svelte/icons/unlink';
36
+ import Pencil from '@tabler/icons-svelte/icons/pencil';
37
+ import ExternalLink from '@tabler/icons-svelte/icons/external-link';
38
+
39
+ type Props = {
40
+ value?: StructuredContentDoc;
41
+ inlineBlocks?: ObjectField[];
42
+ };
43
+
44
+ let { value = $bindable(undefined), inlineBlocks = [] }: Props = $props();
45
+
46
+ const hasInlineBlocks = $derived(inlineBlocks.length > 0);
47
+
48
+ let element = $state<HTMLDivElement | null>(null);
49
+ let editorState = $state<{ editor: EditorType | null }>({ editor: null });
50
+ let bubbleMenu = $state<HTMLDivElement | null>(null);
51
+
52
+ // Dialog states
53
+ let linkDialogOpen = $state(false);
54
+ let imageDialogOpen = $state(false);
55
+ let videoDialogOpen = $state(false);
56
+ let tableDialogOpen = $state(false);
57
+
58
+ // Track last structured JSON to avoid circular updates.
59
+ // Always compare in structured format (blockData as object) to stay consistent.
60
+ let lastStructuredJson = $state('');
61
+
62
+ onMount(() => {
63
+ const initialContent = value ? structuredToTiptapDoc(value) : '';
64
+
65
+ const extraExtensions = hasInlineBlocks
66
+ ? [
67
+ InlineBlockNode.configure({ inlineBlocks }),
68
+ SlashCommand.configure({ inlineBlocks })
69
+ ]
70
+ : [];
71
+
72
+ const editor = new Editor({
73
+ element: element!,
74
+ extensions: [
75
+ ...extensions,
76
+ ...extraExtensions,
77
+ HeadingA11yPlugin,
78
+ BubbleMenu.configure({
79
+ element: bubbleMenu!
80
+ })
81
+ ],
82
+ content: initialContent,
83
+ onTransaction: ({ editor }) => {
84
+ const json = editor.getJSON();
85
+ try {
86
+ const structured = tiptapDocToStructured(json);
87
+ const structuredStr = JSON.stringify(structured);
88
+ if (structuredStr !== lastStructuredJson) {
89
+ lastStructuredJson = structuredStr;
90
+ value = structured;
91
+ }
92
+ } catch {
93
+ // Invalid doc shape during editing — skip update
94
+ }
95
+ editorState = { editor };
96
+ }
97
+ });
98
+
99
+ editorState = { editor };
100
+
101
+ return () => {
102
+ editor.destroy();
103
+ };
104
+ });
105
+
106
+ // Sync incoming value changes (e.g. from form reset)
107
+ $effect(() => {
108
+ if (!editorState.editor || !value) return;
109
+ const incomingJson = JSON.stringify(value);
110
+ if (incomingJson !== lastStructuredJson) {
111
+ lastStructuredJson = incomingJson;
112
+ editorState.editor.commands.setContent(structuredToTiptapDoc(value));
113
+ }
114
+ });
115
+
116
+ const ed = $derived(editorState.editor);
117
+ </script>
118
+
119
+ <Tooltip.Provider>
120
+ <div class="border-input bg-background rounded-lg border">
121
+ <!-- Toolbar — no code view for content editor -->
122
+ {#if ed}
123
+ <EditorToolbar
124
+ editor={ed}
125
+ onLinkDialog={() => (linkDialogOpen = true)}
126
+ onImageDialog={() => (imageDialogOpen = true)}
127
+ onVideoDialog={() => (videoDialogOpen = true)}
128
+ onTableDialog={() => (tableDialogOpen = true)}
129
+ showCodeView={false}
130
+ showInsertBlock={hasInlineBlocks}
131
+ onInsertBlock={() => {
132
+ // Insert "/" at cursor to trigger slash command
133
+ ed?.chain().focus().insertContent('/').run();
134
+ }}
135
+ />
136
+ {/if}
137
+
138
+ <!-- Bubble Menu -->
139
+ <div bind:this={bubbleMenu} class="bubble-menu">
140
+ {#if ed}
141
+ <div class="bg-popover text-popover-foreground flex items-center gap-0.5 rounded-lg border p-1 shadow-md">
142
+ {#if ed.isActive('link')}
143
+ {#if ed.getAttributes('link').target === '_blank'}
144
+ <span class="text-muted-foreground flex items-center px-1" title="Otwiera w nowej karcie">
145
+ <ExternalLink class="h-4 w-4" />
146
+ </span>
147
+ {/if}
148
+ <ToolbarButton label="Edytuj link" active={false} onclick={() => (linkDialogOpen = true)}>
149
+ <Pencil class="h-4 w-4" />
150
+ </ToolbarButton>
151
+ <ToolbarButton
152
+ label="Usuń link"
153
+ active={false}
154
+ onclick={() => ed.chain().focus().unsetLink().run()}
155
+ >
156
+ <Unlink class="h-4 w-4" />
157
+ </ToolbarButton>
158
+ {:else if ed.isActive('table')}
159
+ <ToolbarButton
160
+ label="Wiersz powyżej"
161
+ active={false}
162
+ onclick={() => ed.chain().focus().addRowBefore().run()}
163
+ >
164
+ <RowInsertTop class="h-4 w-4" />
165
+ </ToolbarButton>
166
+ <ToolbarButton
167
+ label="Wiersz poniżej"
168
+ active={false}
169
+ onclick={() => ed.chain().focus().addRowAfter().run()}
170
+ >
171
+ <RowInsertBottom class="h-4 w-4" />
172
+ </ToolbarButton>
173
+ <ToolbarButton
174
+ label="Kolumna z lewej"
175
+ active={false}
176
+ onclick={() => ed.chain().focus().addColumnBefore().run()}
177
+ >
178
+ <ColumnInsertLeft class="h-4 w-4" />
179
+ </ToolbarButton>
180
+ <ToolbarButton
181
+ label="Kolumna z prawej"
182
+ active={false}
183
+ onclick={() => ed.chain().focus().addColumnAfter().run()}
184
+ >
185
+ <ColumnInsertRight class="h-4 w-4" />
186
+ </ToolbarButton>
187
+ <Separator orientation="vertical" class="mx-1 h-6" />
188
+ <ToolbarButton
189
+ label="Usuń wiersz"
190
+ active={false}
191
+ onclick={() => ed.chain().focus().deleteRow().run()}
192
+ >
193
+ <RowRemove class="h-4 w-4" />
194
+ </ToolbarButton>
195
+ <ToolbarButton
196
+ label="Usuń kolumnę"
197
+ active={false}
198
+ onclick={() => ed.chain().focus().deleteColumn().run()}
199
+ >
200
+ <ColumnRemove class="h-4 w-4" />
201
+ </ToolbarButton>
202
+ <ToolbarButton
203
+ label="Usuń tabelę"
204
+ active={false}
205
+ onclick={() => ed.chain().focus().deleteTable().run()}
206
+ >
207
+ <TableOff class="h-4 w-4" />
208
+ </ToolbarButton>
209
+ {:else}
210
+ <ToolbarButton
211
+ label="Pogrubienie"
212
+ active={ed.isActive('bold')}
213
+ onclick={() => ed.chain().focus().toggleBold().run()}
214
+ >
215
+ <Bold class="h-4 w-4" />
216
+ </ToolbarButton>
217
+ <ToolbarButton
218
+ label="Kursywa"
219
+ active={ed.isActive('italic')}
220
+ onclick={() => ed.chain().focus().toggleItalic().run()}
221
+ >
222
+ <Italic class="h-4 w-4" />
223
+ </ToolbarButton>
224
+ <ToolbarButton
225
+ label="Podkreślenie"
226
+ active={ed.isActive('underline')}
227
+ onclick={() => ed.chain().focus().toggleUnderline().run()}
228
+ >
229
+ <Underline class="h-4 w-4" />
230
+ </ToolbarButton>
231
+ <ToolbarButton
232
+ label="Przekreślenie"
233
+ active={ed.isActive('strike')}
234
+ onclick={() => ed.chain().focus().toggleStrike().run()}
235
+ >
236
+ <Strikethrough class="h-4 w-4" />
237
+ </ToolbarButton>
238
+ <ToolbarButton
239
+ label="Wyróżnienie"
240
+ active={ed.isActive('highlight')}
241
+ onclick={() => ed.chain().focus().toggleHighlight().run()}
242
+ >
243
+ <Highlight class="h-4 w-4" />
244
+ </ToolbarButton>
245
+ <Separator orientation="vertical" class="mx-1 h-6" />
246
+ <ToolbarButton
247
+ label="Link"
248
+ active={ed.isActive('link')}
249
+ onclick={() => (linkDialogOpen = true)}
250
+ >
251
+ <LinkIcon class="h-4 w-4" />
252
+ </ToolbarButton>
253
+ {/if}
254
+ </div>
255
+ {/if}
256
+ </div>
257
+
258
+ <!-- Editor content -->
259
+ <div
260
+ bind:this={element}
261
+ class="prose prose-sm dark:prose-invert max-w-none p-4 focus:outline-none [&_.ProseMirror]:min-h-[200px] [&_.ProseMirror]:outline-none [&_.ProseMirror]:scroll-padding-top-12"
262
+ ></div>
263
+ </div>
264
+ </Tooltip.Provider>
265
+
266
+ <!-- Dialogs -->
267
+ <LinkDialog bind:open={linkDialogOpen} editor={ed} />
268
+ <ImageDialog bind:open={imageDialogOpen} editor={ed} />
269
+ <VideoDialog bind:open={videoDialogOpen} editor={ed} />
270
+ <TableDialog bind:open={tableDialogOpen} editor={ed} />
271
+
272
+ <style>
273
+ .bubble-menu {
274
+ visibility: hidden;
275
+ opacity: 0;
276
+ transition:
277
+ visibility 0.1s ease,
278
+ opacity 0.1s ease;
279
+ }
280
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { StructuredContentDoc } from '../../../types/structured-content.js';
2
+ import type { ObjectField } from '../../../types/fields.js';
3
+ type Props = {
4
+ value?: StructuredContentDoc;
5
+ inlineBlocks?: ObjectField[];
6
+ };
7
+ declare const ContentEditor: import("svelte").Component<Props, {}, "value">;
8
+ type ContentEditor = ReturnType<typeof ContentEditor>;
9
+ export default ContentEditor;