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,230 @@
1
+ <script lang="ts">
2
+ import type { Editor as EditorType } from '@tiptap/core';
3
+ import ToolbarButton from './toolbar-button.svelte';
4
+ import * as Tooltip from '../../../components/ui/tooltip/index.js';
5
+ import Separator from '../../../components/ui/separator/separator.svelte';
6
+
7
+ // Icons
8
+ import H_2 from '@tabler/icons-svelte/icons/h-2';
9
+ import H_3 from '@tabler/icons-svelte/icons/h-3';
10
+ import LetterP from '@tabler/icons-svelte/icons/letter-p';
11
+ import Bold from '@tabler/icons-svelte/icons/bold';
12
+ import Italic from '@tabler/icons-svelte/icons/italic';
13
+ import Underline from '@tabler/icons-svelte/icons/underline';
14
+ import Strikethrough from '@tabler/icons-svelte/icons/strikethrough';
15
+ import Highlight from '@tabler/icons-svelte/icons/highlight';
16
+ import AlignLeft from '@tabler/icons-svelte/icons/align-left';
17
+ import AlignCenter from '@tabler/icons-svelte/icons/align-center';
18
+ import AlignRight from '@tabler/icons-svelte/icons/align-right';
19
+ import AlignJustified from '@tabler/icons-svelte/icons/align-justified';
20
+ import List from '@tabler/icons-svelte/icons/list';
21
+ import ListNumbers from '@tabler/icons-svelte/icons/list-numbers';
22
+ import Quote from '@tabler/icons-svelte/icons/quote';
23
+ import LinkIcon from '@tabler/icons-svelte/icons/link';
24
+ import Photo from '@tabler/icons-svelte/icons/photo';
25
+ import VideoIcon from '@tabler/icons-svelte/icons/video';
26
+ import Table from '@tabler/icons-svelte/icons/table';
27
+ import Code from '@tabler/icons-svelte/icons/code';
28
+ import FileCode from '@tabler/icons-svelte/icons/file-code';
29
+ import SourceCode from '@tabler/icons-svelte/icons/source-code';
30
+ import Plus from '@tabler/icons-svelte/icons/plus';
31
+
32
+ type Props = {
33
+ editor: EditorType;
34
+ onLinkDialog: () => void;
35
+ onImageDialog: () => void;
36
+ onVideoDialog: () => void;
37
+ onTableDialog: () => void;
38
+ showCodeView?: boolean;
39
+ isCodeViewActive?: boolean;
40
+ onToggleCodeView?: () => void;
41
+ showInsertBlock?: boolean;
42
+ onInsertBlock?: () => void;
43
+ };
44
+
45
+ let {
46
+ editor: ed,
47
+ onLinkDialog,
48
+ onImageDialog,
49
+ onVideoDialog,
50
+ onTableDialog,
51
+ showCodeView = true,
52
+ isCodeViewActive = false,
53
+ onToggleCodeView,
54
+ showInsertBlock = false,
55
+ onInsertBlock
56
+ }: Props = $props();
57
+ </script>
58
+
59
+ <Tooltip.Provider>
60
+ <div class="flex flex-wrap items-center gap-0.5 border-b p-1 sticky top-0 z-10 bg-background">
61
+ <!-- Headings -->
62
+ <ToolbarButton
63
+ label="Nagłówek 2"
64
+ active={ed.isActive('heading', { level: 2 })}
65
+ onclick={() => ed.chain().focus().toggleHeading({ level: 2 }).run()}
66
+ >
67
+ <H_2 class="h-4 w-4" />
68
+ </ToolbarButton>
69
+ <ToolbarButton
70
+ label="Nagłówek 3"
71
+ active={ed.isActive('heading', { level: 3 })}
72
+ onclick={() => ed.chain().focus().toggleHeading({ level: 3 }).run()}
73
+ >
74
+ <H_3 class="h-4 w-4" />
75
+ </ToolbarButton>
76
+ <ToolbarButton
77
+ label="Paragraf"
78
+ active={ed.isActive('paragraph') && !ed.isActive('heading')}
79
+ onclick={() => ed.chain().focus().setParagraph().run()}
80
+ >
81
+ <LetterP class="h-4 w-4" />
82
+ </ToolbarButton>
83
+
84
+ <Separator orientation="vertical" class="mx-1 h-6" />
85
+
86
+ <!-- Text formatting -->
87
+ <ToolbarButton
88
+ label="Pogrubienie"
89
+ active={ed.isActive('bold')}
90
+ onclick={() => ed.chain().focus().toggleBold().run()}
91
+ >
92
+ <Bold class="h-4 w-4" />
93
+ </ToolbarButton>
94
+ <ToolbarButton
95
+ label="Kursywa"
96
+ active={ed.isActive('italic')}
97
+ onclick={() => ed.chain().focus().toggleItalic().run()}
98
+ >
99
+ <Italic class="h-4 w-4" />
100
+ </ToolbarButton>
101
+ <ToolbarButton
102
+ label="Podkreślenie"
103
+ active={ed.isActive('underline')}
104
+ onclick={() => ed.chain().focus().toggleUnderline().run()}
105
+ >
106
+ <Underline class="h-4 w-4" />
107
+ </ToolbarButton>
108
+ <ToolbarButton
109
+ label="Przekreślenie"
110
+ active={ed.isActive('strike')}
111
+ onclick={() => ed.chain().focus().toggleStrike().run()}
112
+ >
113
+ <Strikethrough class="h-4 w-4" />
114
+ </ToolbarButton>
115
+ <ToolbarButton
116
+ label="Wyróżnienie"
117
+ active={ed.isActive('highlight')}
118
+ onclick={() => ed.chain().focus().toggleHighlight().run()}
119
+ >
120
+ <Highlight class="h-4 w-4" />
121
+ </ToolbarButton>
122
+
123
+ <Separator orientation="vertical" class="mx-1 h-6" />
124
+
125
+ <!-- Alignment -->
126
+ <ToolbarButton
127
+ label="Do lewej"
128
+ active={ed.isActive({ textAlign: 'left' })}
129
+ onclick={() => ed.chain().focus().setTextAlign('left').run()}
130
+ >
131
+ <AlignLeft class="h-4 w-4" />
132
+ </ToolbarButton>
133
+ <ToolbarButton
134
+ label="Wyśrodkuj"
135
+ active={ed.isActive({ textAlign: 'center' })}
136
+ onclick={() => ed.chain().focus().setTextAlign('center').run()}
137
+ >
138
+ <AlignCenter class="h-4 w-4" />
139
+ </ToolbarButton>
140
+ <ToolbarButton
141
+ label="Do prawej"
142
+ active={ed.isActive({ textAlign: 'right' })}
143
+ onclick={() => ed.chain().focus().setTextAlign('right').run()}
144
+ >
145
+ <AlignRight class="h-4 w-4" />
146
+ </ToolbarButton>
147
+ <ToolbarButton
148
+ label="Wyjustuj"
149
+ active={ed.isActive({ textAlign: 'justify' })}
150
+ onclick={() => ed.chain().focus().setTextAlign('justify').run()}
151
+ >
152
+ <AlignJustified class="h-4 w-4" />
153
+ </ToolbarButton>
154
+
155
+ <Separator orientation="vertical" class="mx-1 h-6" />
156
+
157
+ <!-- Lists & Quote -->
158
+ <ToolbarButton
159
+ label="Lista punktowa"
160
+ active={ed.isActive('bulletList')}
161
+ onclick={() => ed.chain().focus().toggleBulletList().run()}
162
+ >
163
+ <List class="h-4 w-4" />
164
+ </ToolbarButton>
165
+ <ToolbarButton
166
+ label="Lista numerowana"
167
+ active={ed.isActive('orderedList')}
168
+ onclick={() => ed.chain().focus().toggleOrderedList().run()}
169
+ >
170
+ <ListNumbers class="h-4 w-4" />
171
+ </ToolbarButton>
172
+ <ToolbarButton
173
+ label="Cytat"
174
+ active={ed.isActive('blockquote')}
175
+ onclick={() => ed.chain().focus().toggleBlockquote().run()}
176
+ >
177
+ <Quote class="h-4 w-4" />
178
+ </ToolbarButton>
179
+
180
+ <Separator orientation="vertical" class="mx-1 h-6" />
181
+
182
+ <!-- Link, Image, Table -->
183
+ <ToolbarButton label="Link" active={ed.isActive('link')} onclick={onLinkDialog}>
184
+ <LinkIcon class="h-4 w-4" />
185
+ </ToolbarButton>
186
+ <ToolbarButton label="Obrazek" active={false} onclick={onImageDialog}>
187
+ <Photo class="h-4 w-4" />
188
+ </ToolbarButton>
189
+ <ToolbarButton label="Wideo" active={false} onclick={onVideoDialog}>
190
+ <VideoIcon class="h-4 w-4" />
191
+ </ToolbarButton>
192
+ <ToolbarButton label="Tabela" active={false} onclick={onTableDialog}>
193
+ <Table class="h-4 w-4" />
194
+ </ToolbarButton>
195
+
196
+ <Separator orientation="vertical" class="mx-1 h-6" />
197
+
198
+ <!-- Code -->
199
+ <ToolbarButton
200
+ label="Kod inline"
201
+ active={ed.isActive('code')}
202
+ onclick={() => ed.chain().focus().toggleCode().run()}
203
+ >
204
+ <Code class="h-4 w-4" />
205
+ </ToolbarButton>
206
+ <ToolbarButton
207
+ label="Blok kodu"
208
+ active={ed.isActive('codeBlock')}
209
+ onclick={() => ed.chain().focus().toggleCodeBlock().run()}
210
+ >
211
+ <FileCode class="h-4 w-4" />
212
+ </ToolbarButton>
213
+
214
+ {#if showInsertBlock && onInsertBlock}
215
+ <Separator orientation="vertical" class="mx-1 h-6" />
216
+ <ToolbarButton label="Wstaw blok" active={false} onclick={onInsertBlock}>
217
+ <Plus class="h-4 w-4" />
218
+ </ToolbarButton>
219
+ {/if}
220
+
221
+ {#if showCodeView && onToggleCodeView}
222
+ <Separator orientation="vertical" class="mx-1 h-6" />
223
+
224
+ <!-- HTML View -->
225
+ <ToolbarButton label="Widok HTML" active={isCodeViewActive} onclick={onToggleCodeView}>
226
+ <SourceCode class="h-4 w-4" />
227
+ </ToolbarButton>
228
+ {/if}
229
+ </div>
230
+ </Tooltip.Provider>
@@ -0,0 +1,16 @@
1
+ import type { Editor as EditorType } from '@tiptap/core';
2
+ type Props = {
3
+ editor: EditorType;
4
+ onLinkDialog: () => void;
5
+ onImageDialog: () => void;
6
+ onVideoDialog: () => void;
7
+ onTableDialog: () => void;
8
+ showCodeView?: boolean;
9
+ isCodeViewActive?: boolean;
10
+ onToggleCodeView?: () => void;
11
+ showInsertBlock?: boolean;
12
+ onInsertBlock?: () => void;
13
+ };
14
+ declare const EditorToolbar: import("svelte").Component<Props, {}, "">;
15
+ type EditorToolbar = ReturnType<typeof EditorToolbar>;
16
+ export default EditorToolbar;
@@ -0,0 +1,2 @@
1
+ import { Extension } from '@tiptap/core';
2
+ export declare const HeadingA11yPlugin: Extension<any, any>;
@@ -0,0 +1,67 @@
1
+ import { Extension } from '@tiptap/core';
2
+ import { Plugin, PluginKey } from '@tiptap/pm/state';
3
+ import { Decoration, DecorationSet } from '@tiptap/pm/view';
4
+ const pluginKey = new PluginKey('headingA11y');
5
+ function findHeadingIssues(doc) {
6
+ const issues = [];
7
+ let seenH2 = false;
8
+ doc.forEach((node, offset) => {
9
+ if (node.type.name === 'heading') {
10
+ const level = node.attrs.level;
11
+ if (level === 2) {
12
+ seenH2 = true;
13
+ }
14
+ else if (level === 3 && !seenH2) {
15
+ issues.push({ pos: offset + node.nodeSize, message: 'Dodaj H2 przed tą podsekcją' });
16
+ }
17
+ else if (level > 3 && !seenH2) {
18
+ issues.push({ pos: offset + node.nodeSize, message: 'Pierwszy nagłówek powinien być H2' });
19
+ }
20
+ }
21
+ });
22
+ return issues;
23
+ }
24
+ function createWarningWidget(message) {
25
+ const el = document.createElement('div');
26
+ el.className = 'heading-a11y-warning';
27
+ el.setAttribute('role', 'status');
28
+ el.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4"/><path d="M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0z"/><path d="M12 16h.01"/></svg><span>${message}</span>`;
29
+ return el;
30
+ }
31
+ function buildDecorations(doc) {
32
+ const issues = findHeadingIssues(doc);
33
+ if (issues.length === 0)
34
+ return DecorationSet.empty;
35
+ const decorations = issues.map((issue) => Decoration.widget(issue.pos, () => createWarningWidget(issue.message), {
36
+ side: -1,
37
+ key: `heading-a11y-${issue.pos}`
38
+ }));
39
+ return DecorationSet.create(doc, decorations);
40
+ }
41
+ export const HeadingA11yPlugin = Extension.create({
42
+ name: 'headingA11y',
43
+ addProseMirrorPlugins() {
44
+ return [
45
+ new Plugin({
46
+ key: pluginKey,
47
+ state: {
48
+ init(_, state) {
49
+ return buildDecorations(state.doc);
50
+ },
51
+ apply(tr, oldDecos, _oldState, newState) {
52
+ // Always rebuild on doc change — mapping empty sets stays empty
53
+ if (tr.docChanged) {
54
+ return buildDecorations(newState.doc);
55
+ }
56
+ return oldDecos;
57
+ }
58
+ },
59
+ props: {
60
+ decorations(state) {
61
+ return pluginKey.getState(state);
62
+ }
63
+ }
64
+ })
65
+ ];
66
+ }
67
+ });
@@ -3,6 +3,7 @@
3
3
  import MediaSelector from '../media/media-selector.svelte';
4
4
  import { getRemotes } from '../../context/remotes.js';
5
5
  import type { Editor } from '@tiptap/core';
6
+ import AlertTriangle from '@tabler/icons-svelte/icons/alert-triangle';
6
7
 
7
8
  type Props = {
8
9
  open: boolean;
@@ -15,6 +16,12 @@
15
16
  const remotes = getRemotes();
16
17
  let selected = $state<string>('');
17
18
 
19
+ // Alt dialog state (separate from media selector dialog)
20
+ let altOpen = $state(false);
21
+ let altText = $state('');
22
+ let fileUrl = $state('');
23
+ let fileId = $state('');
24
+
18
25
  $effect(() => {
19
26
  if (!open) {
20
27
  selected = '';
@@ -27,25 +34,47 @@
27
34
  try {
28
35
  const file = await remotes.getFileById(selected);
29
36
  if (file?.url) {
30
- editor
31
- .chain()
32
- .focus()
33
- .setFigure({
34
- src: file.url,
35
- alt: file.alt || '',
36
- 'data-media-id': file.id
37
- })
38
- .run();
37
+ fileUrl = file.url;
38
+ fileId = file.id;
39
+ altText = file.alt || '';
40
+ // Close media selector, open alt dialog
41
+ open = false;
42
+ onOpenChange?.(false);
43
+ altOpen = true;
39
44
  }
40
45
  } catch (e) {
41
46
  console.error('Failed to get media file:', e);
42
47
  }
48
+ }
49
+
50
+ function insertImage(alt: string) {
51
+ if (!editor || !fileUrl) return;
52
+ editor
53
+ .chain()
54
+ .focus()
55
+ .setFigure({
56
+ src: fileUrl,
57
+ alt,
58
+ 'data-media-id': fileId
59
+ })
60
+ .run();
61
+ altOpen = false;
62
+ }
63
+
64
+ function handleAltKeydown(e: KeyboardEvent) {
65
+ if (e.key === 'Enter') {
66
+ e.preventDefault();
67
+ insertImage(altText.trim());
68
+ }
69
+ }
43
70
 
44
- open = false;
45
- onOpenChange?.(false);
71
+ function handleAltCancel() {
72
+ // Insert without alt
73
+ insertImage('');
46
74
  }
47
75
  </script>
48
76
 
77
+ <!-- Dialog 1: Media selector -->
49
78
  <Dialog.Root bind:open {onOpenChange}>
50
79
  <Dialog.Content class="max-w-5xl! sm:max-w-5xl!">
51
80
  <Dialog.Header>
@@ -54,3 +83,135 @@
54
83
  <MediaSelector bind:selected accept="image/*" onConfirm={handleConfirm} />
55
84
  </Dialog.Content>
56
85
  </Dialog.Root>
86
+
87
+ <!-- Dialog 2: Alt text prompt -->
88
+ <Dialog.Root bind:open={altOpen}>
89
+ <Dialog.Content class="max-w-lg! sm:max-w-lg!">
90
+ <Dialog.Header>
91
+ <Dialog.Title>Opis zdjęcia</Dialog.Title>
92
+ </Dialog.Header>
93
+ <div class="image-alt-prompt">
94
+ {#if !altText.trim()}
95
+ <div class="image-alt-banner">
96
+ <AlertTriangle class="size-4 shrink-0" />
97
+ <span>Dodaj opis zdjęcia, żeby każdy mógł je zrozumieć</span>
98
+ </div>
99
+ {/if}
100
+ <div class="image-alt-preview">
101
+ <img src={fileUrl} alt="" class="image-alt-thumb" />
102
+ </div>
103
+ <label class="image-alt-label" for="image-alt-input">Opis alternatywny (alt text)</label>
104
+ <input
105
+ id="image-alt-input"
106
+ type="text"
107
+ class="image-alt-input"
108
+ bind:value={altText}
109
+ onkeydown={handleAltKeydown}
110
+ placeholder="Np. Zdjęcie zespołu na konferencji..."
111
+ />
112
+ <div class="image-alt-actions">
113
+ <button
114
+ type="button"
115
+ class="image-alt-btn-primary"
116
+ onclick={() => insertImage(altText.trim())}
117
+ >
118
+ Dodaj i wstaw
119
+ </button>
120
+ <button
121
+ type="button"
122
+ class="image-alt-btn-ghost"
123
+ onclick={handleAltCancel}
124
+ >
125
+ Pomiń
126
+ </button>
127
+ </div>
128
+ </div>
129
+ </Dialog.Content>
130
+ </Dialog.Root>
131
+
132
+ <style>
133
+ .image-alt-prompt {
134
+ padding: 8px 0;
135
+ }
136
+ .image-alt-banner {
137
+ display: flex;
138
+ align-items: center;
139
+ gap: 8px;
140
+ padding: 10px 14px;
141
+ border-radius: 8px;
142
+ background: var(--warning-bg);
143
+ color: #7a5520;
144
+ font-size: 13px;
145
+ font-weight: 500;
146
+ margin-bottom: 16px;
147
+ }
148
+ .image-alt-preview {
149
+ display: flex;
150
+ justify-content: center;
151
+ margin-bottom: 16px;
152
+ }
153
+ .image-alt-thumb {
154
+ max-height: 200px;
155
+ max-width: 100%;
156
+ border-radius: 8px;
157
+ object-fit: contain;
158
+ }
159
+ .image-alt-label {
160
+ display: block;
161
+ font-size: 13px;
162
+ font-weight: 600;
163
+ color: var(--foreground);
164
+ margin-bottom: 6px;
165
+ }
166
+ .image-alt-input {
167
+ width: 100%;
168
+ padding: 8px 12px;
169
+ font-family: inherit;
170
+ font-size: 14px;
171
+ border: 1px solid var(--border);
172
+ border-radius: 8px;
173
+ background: var(--background);
174
+ color: var(--foreground);
175
+ outline: none;
176
+ transition: border-color 0.2s;
177
+ }
178
+ .image-alt-input:focus {
179
+ border-color: var(--primary);
180
+ }
181
+ .image-alt-actions {
182
+ display: flex;
183
+ gap: 8px;
184
+ margin-top: 16px;
185
+ justify-content: flex-end;
186
+ }
187
+ .image-alt-btn-primary {
188
+ padding: 8px 20px;
189
+ font-family: inherit;
190
+ font-size: 13px;
191
+ font-weight: 600;
192
+ color: var(--primary-foreground);
193
+ background: var(--primary);
194
+ border: none;
195
+ border-radius: 8px;
196
+ cursor: pointer;
197
+ transition: opacity 0.2s;
198
+ }
199
+ .image-alt-btn-primary:hover {
200
+ opacity: 0.9;
201
+ }
202
+ .image-alt-btn-ghost {
203
+ padding: 8px 16px;
204
+ font-family: inherit;
205
+ font-size: 13px;
206
+ font-weight: 500;
207
+ color: var(--muted-foreground);
208
+ background: transparent;
209
+ border: none;
210
+ border-radius: 8px;
211
+ cursor: pointer;
212
+ transition: background-color 0.2s;
213
+ }
214
+ .image-alt-btn-ghost:hover {
215
+ background: var(--muted);
216
+ }
217
+ </style>
@@ -0,0 +1,19 @@
1
+ import { Node } from '@tiptap/core';
2
+ import type { ObjectField } from '../../../types/fields.js';
3
+ export interface InlineBlockOptions {
4
+ HTMLAttributes: Record<string, string>;
5
+ inlineBlocks: ObjectField[];
6
+ }
7
+ declare module '@tiptap/core' {
8
+ interface Commands<ReturnType> {
9
+ inlineBlock: {
10
+ insertInlineBlock: (options: {
11
+ blockType: string;
12
+ blockData?: Record<string, unknown>;
13
+ }) => ReturnType;
14
+ };
15
+ }
16
+ }
17
+ /** Build default data for an inline block from its field definitions. */
18
+ export declare function buildDefaultData(blockType: string, inlineBlocks: ObjectField[]): Record<string, unknown>;
19
+ export declare const InlineBlockNode: Node<InlineBlockOptions, any>;
@@ -0,0 +1,98 @@
1
+ import { Node, mergeAttributes } from '@tiptap/core';
2
+ import { SvelteNodeViewRenderer } from 'svelte-tiptap';
3
+ import InlineBlockNodeView from './InlineBlockNodeView.svelte';
4
+ /** Build default data for an inline block from its field definitions. */
5
+ export function buildDefaultData(blockType, inlineBlocks) {
6
+ const def = inlineBlocks.find((b) => b.slug === blockType);
7
+ if (!def)
8
+ return {};
9
+ const data = {};
10
+ for (const field of def.fields) {
11
+ data[field.slug] = getFieldDefault(field);
12
+ }
13
+ return data;
14
+ }
15
+ function getFieldDefault(field) {
16
+ if (field.defaultValue !== undefined)
17
+ return field.defaultValue;
18
+ switch (field.type) {
19
+ case 'text':
20
+ return '';
21
+ case 'number':
22
+ return 0;
23
+ case 'boolean':
24
+ return false;
25
+ case 'select':
26
+ case 'radio':
27
+ return field.options[0]?.value ?? '';
28
+ case 'url':
29
+ return { url: '' };
30
+ default:
31
+ return '';
32
+ }
33
+ }
34
+ export const InlineBlockNode = Node.create({
35
+ name: 'inlineBlock',
36
+ group: 'block',
37
+ atom: true,
38
+ draggable: true,
39
+ isolating: true,
40
+ addOptions() {
41
+ return {
42
+ HTMLAttributes: {},
43
+ inlineBlocks: []
44
+ };
45
+ },
46
+ addAttributes() {
47
+ return {
48
+ blockType: { default: '' },
49
+ blockData: { default: '{}' },
50
+ blockId: { default: '' }
51
+ };
52
+ },
53
+ parseHTML() {
54
+ return [
55
+ {
56
+ tag: 'div[data-inline-block]',
57
+ getAttrs: (node) => {
58
+ const el = node;
59
+ return {
60
+ blockType: el.getAttribute('data-block-type') || '',
61
+ blockData: el.getAttribute('data-block-data') || '{}',
62
+ blockId: el.getAttribute('data-block-id') || ''
63
+ };
64
+ }
65
+ }
66
+ ];
67
+ },
68
+ renderHTML({ HTMLAttributes }) {
69
+ return [
70
+ 'div',
71
+ mergeAttributes(this.options.HTMLAttributes, {
72
+ 'data-inline-block': '',
73
+ 'data-block-type': HTMLAttributes.blockType,
74
+ 'data-block-data': HTMLAttributes.blockData,
75
+ 'data-block-id': HTMLAttributes.blockId
76
+ }),
77
+ `[${HTMLAttributes.blockType}]`
78
+ ];
79
+ },
80
+ addCommands() {
81
+ return {
82
+ insertInlineBlock: ({ blockType, blockData }) => ({ commands }) => {
83
+ const data = blockData ?? buildDefaultData(blockType, this.options.inlineBlocks);
84
+ return commands.insertContent({
85
+ type: this.name,
86
+ attrs: {
87
+ blockType,
88
+ blockData: JSON.stringify(data),
89
+ blockId: crypto.randomUUID()
90
+ }
91
+ });
92
+ }
93
+ };
94
+ },
95
+ addNodeView() {
96
+ return SvelteNodeViewRenderer(InlineBlockNodeView);
97
+ }
98
+ });
@@ -96,10 +96,15 @@
96
96
  return;
97
97
  }
98
98
  searchTimeout = setTimeout(async () => {
99
- const results = (await remotes.getEntries({
100
- dataLike: { seo: { slug: url } }
101
- })) as EntryWithSeo[];
102
- suggestions = results.slice(0, 5);
99
+ const [slugResults, titleResults] = await Promise.all([
100
+ remotes.getEntries({ dataLike: { seo: { slug: url } } }),
101
+ remotes.getEntries({ dataLike: { seo: { title: url } } })
102
+ ]) as [EntryWithSeo[], EntryWithSeo[]];
103
+ const combined = [...slugResults, ...titleResults];
104
+ const deduped = combined.filter(
105
+ (entry, index, self) => index === self.findIndex((e) => e.id === entry.id)
106
+ );
107
+ suggestions = deduped.slice(0, 5);
103
108
  }, 300);
104
109
  }
105
110
 
@@ -0,0 +1,17 @@
1
+ import { Extension } from '@tiptap/core';
2
+ import { type SuggestionOptions } from '@tiptap/suggestion';
3
+ import type { ObjectField } from '../../../types/fields.js';
4
+ export interface SlashCommandItem {
5
+ id: string;
6
+ label: string;
7
+ description?: string;
8
+ group: string;
9
+ tier?: 1 | 2;
10
+ icon?: string;
11
+ action: (editor: ReturnType<SuggestionOptions['editor']>['commands']) => void;
12
+ }
13
+ export interface SlashCommandOptions {
14
+ inlineBlocks: ObjectField[];
15
+ suggestion: Partial<SuggestionOptions<SlashCommandItem>>;
16
+ }
17
+ export declare const SlashCommand: Extension<SlashCommandOptions, any>;