includio-cms 0.25.0 → 0.27.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 (411) hide show
  1. package/API.md +97 -4
  2. package/CHANGELOG.md +118 -0
  3. package/DOCS.md +1 -1
  4. package/README.md +2 -0
  5. package/ROADMAP.md +14 -0
  6. package/dist/admin/auth-client.d.ts +42 -42
  7. package/dist/admin/client/account/lang.d.ts +1 -0
  8. package/dist/admin/client/account/lang.js +4 -2
  9. package/dist/admin/client/account/profile-section.svelte +2 -2
  10. package/dist/admin/client/account/security-section.svelte +27 -4
  11. package/dist/admin/client/account/sessions-section.svelte +1 -1
  12. package/dist/admin/client/admin/admin-after-login-layout-content.svelte +1 -1
  13. package/dist/admin/client/admin/admin-layout.svelte +12 -2
  14. package/dist/admin/client/admin/admin-layout.svelte.d.ts +2 -1
  15. package/dist/admin/client/admin/dashboard-page.svelte +34 -10
  16. package/dist/admin/client/collection/bulk-actions-bar.svelte +86 -44
  17. package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +3 -1
  18. package/dist/admin/client/collection/collection-entries.svelte +52 -36
  19. package/dist/admin/client/collection/collection-entries.svelte.d.ts +3 -0
  20. package/dist/admin/client/collection/collection.svelte +28 -14
  21. package/dist/admin/client/collection/collection.svelte.d.ts +3 -0
  22. package/dist/admin/client/collection/data-table.svelte +240 -130
  23. package/dist/admin/client/collection/data-table.svelte.d.ts +9 -0
  24. package/dist/admin/client/collection/date-cell.svelte +4 -4
  25. package/dist/admin/client/collection/row-actions.svelte +2 -1
  26. package/dist/admin/client/collection/sortable-header.svelte +33 -9
  27. package/dist/admin/client/collection/state-display.svelte +102 -0
  28. package/dist/admin/client/collection/state-display.svelte.d.ts +12 -0
  29. package/dist/admin/client/collection/status-badge.svelte +99 -11
  30. package/dist/admin/client/collection/status-badge.svelte.d.ts +15 -1
  31. package/dist/admin/client/collection/table-pagination.svelte +21 -6
  32. package/dist/admin/client/collection/table-toolbar.svelte +105 -80
  33. package/dist/admin/client/collection/table-toolbar.svelte.d.ts +11 -8
  34. package/dist/admin/client/entry/entry-form.svelte +36 -11
  35. package/dist/admin/client/entry/entry-form.svelte.d.ts +1 -0
  36. package/dist/admin/client/entry/entry-header.svelte +22 -15
  37. package/dist/admin/client/entry/entry-header.svelte.d.ts +1 -0
  38. package/dist/admin/client/entry/entry.svelte +269 -165
  39. package/dist/admin/client/entry/header/a11y-header-badge.svelte +47 -0
  40. package/dist/admin/client/entry/header/a11y-header-badge.svelte.d.ts +8 -0
  41. package/dist/admin/client/entry/header/publish-panel.svelte +69 -13
  42. package/dist/admin/client/entry/header/save-indicator.svelte +57 -28
  43. package/dist/admin/client/entry/header/save-indicator.svelte.d.ts +1 -0
  44. package/dist/admin/client/entry/header/status-badge.svelte +60 -15
  45. package/dist/admin/client/entry/header/status-badge.svelte.d.ts +1 -2
  46. package/dist/admin/client/entry/header/version-history-sheet.svelte +1 -1
  47. package/dist/admin/client/entry/hybrid/hybrid-layout.svelte +74 -23
  48. package/dist/admin/client/entry/hybrid/hybrid-preview.svelte +1 -1
  49. package/dist/admin/client/entry/utils.d.ts +14 -0
  50. package/dist/admin/client/entry/utils.js +28 -0
  51. package/dist/admin/client/form/form-submission/form-submission.svelte +2 -2
  52. package/dist/admin/client/form/form-submissions.svelte +143 -194
  53. package/dist/admin/client/form/form-submissions.svelte.d.ts +2 -0
  54. package/dist/admin/client/login/lang.d.ts +3 -0
  55. package/dist/admin/client/login/lang.js +10 -4
  56. package/dist/admin/client/login/login-form.svelte +8 -1
  57. package/dist/admin/client/login/reset-password-page.svelte +24 -3
  58. package/dist/admin/client/login/schema.d.ts +14 -2
  59. package/dist/admin/client/login/schema.js +19 -8
  60. package/dist/admin/client/maintenance/maintenance-page.svelte +16 -17
  61. package/dist/admin/client/media/media-page.svelte +1 -1
  62. package/dist/admin/client/shop/coupon-edit-page.svelte +117 -13
  63. package/dist/admin/client/shop/coupon-form.svelte +282 -138
  64. package/dist/admin/client/shop/coupon-form.svelte.d.ts +1 -9
  65. package/dist/admin/client/shop/coupon-new-page.svelte +40 -10
  66. package/dist/admin/client/shop/coupon-new-page.svelte.d.ts +2 -17
  67. package/dist/admin/client/shop/coupon-schema.d.ts +28 -0
  68. package/dist/admin/client/shop/coupon-schema.js +53 -0
  69. package/dist/admin/client/shop/coupons-list-page.svelte +262 -118
  70. package/dist/admin/client/shop/coupons-list-page.svelte.d.ts +16 -1
  71. package/dist/admin/client/shop/refund-dialog.svelte +37 -1
  72. package/dist/admin/client/shop/refund-dialog.svelte.d.ts +3 -0
  73. package/dist/admin/client/shop/shipping-method-edit-page.svelte +108 -59
  74. package/dist/admin/client/shop/shipping-method-form.svelte +36 -9
  75. package/dist/admin/client/shop/shipping-method-new-page.svelte +44 -13
  76. package/dist/admin/client/shop/shipping-methods-list-page.svelte +101 -59
  77. package/dist/admin/client/shop/shop-order-detail-page.svelte +220 -84
  78. package/dist/admin/client/shop/shop-orders-list-page.svelte +302 -152
  79. package/dist/admin/client/shop/shop-orders-list-page.svelte.d.ts +18 -1
  80. package/dist/admin/client/shop/shop-products-list-page.svelte +355 -118
  81. package/dist/admin/client/shop/shop-products-list-page.svelte.d.ts +19 -1
  82. package/dist/admin/client/users/accept-invite-page.svelte +24 -3
  83. package/dist/admin/client/users/create-user-dialog.svelte +3 -8
  84. package/dist/admin/client/users/lang.d.ts +2 -0
  85. package/dist/admin/client/users/lang.js +4 -0
  86. package/dist/admin/client/users/pending-invitations.svelte +2 -9
  87. package/dist/admin/client/users/user-name-cell.svelte +20 -0
  88. package/dist/admin/client/users/user-name-cell.svelte.d.ts +9 -0
  89. package/dist/admin/client/users/user-role-badge.svelte +16 -0
  90. package/dist/admin/client/users/user-role-badge.svelte.d.ts +7 -0
  91. package/dist/admin/client/users/user-row-actions.svelte +72 -0
  92. package/dist/admin/client/users/user-row-actions.svelte.d.ts +20 -0
  93. package/dist/admin/client/users/user-sessions-sheet.svelte +2 -11
  94. package/dist/admin/client/users/users-page.svelte +283 -497
  95. package/dist/admin/client/users/users-page.svelte.d.ts +12 -1
  96. package/dist/admin/components/dashboard/form-submissions-widget.svelte +59 -74
  97. package/dist/admin/components/dashboard/recent-activity.svelte +17 -5
  98. package/dist/admin/components/dashboard/recent-entries.svelte +19 -7
  99. package/dist/admin/components/dialogs/confirmation-dialog.svelte +105 -0
  100. package/dist/admin/components/dialogs/confirmation-dialog.svelte.d.ts +13 -0
  101. package/dist/admin/components/fields/block-picker-modal.svelte +6 -0
  102. package/dist/admin/components/fields/blocks-field.svelte +46 -1
  103. package/dist/admin/components/fields/boolean-field.svelte +1 -1
  104. package/dist/admin/components/fields/field-renderer.svelte +29 -22
  105. package/dist/admin/components/fields/file-field.svelte +344 -30
  106. package/dist/admin/components/fields/icon-field.svelte +86 -0
  107. package/dist/admin/components/fields/icon-field.svelte.d.ts +8 -0
  108. package/dist/admin/components/fields/icon-picker-dialog.svelte +174 -0
  109. package/dist/admin/components/fields/icon-picker-dialog.svelte.d.ts +11 -0
  110. package/dist/admin/components/fields/media-field.svelte +16 -2
  111. package/dist/admin/components/fields/object-field.svelte +27 -7
  112. package/dist/admin/components/fields/radio-field.svelte +22 -0
  113. package/dist/admin/components/fields/relation-field.svelte +123 -97
  114. package/dist/admin/components/fields/relation-picker-dialog.svelte +2 -2
  115. package/dist/admin/components/fields/seo-field.svelte +60 -30
  116. package/dist/admin/components/fields/shop-field.svelte +219 -24
  117. package/dist/admin/components/fields/simple-array-field.svelte +321 -151
  118. package/dist/admin/components/fields/simple-array-field.svelte.d.ts +3 -0
  119. package/dist/admin/components/fields/slug-field.svelte +146 -21
  120. package/dist/admin/components/fields/text-field-wrapper.svelte +37 -20
  121. package/dist/admin/components/fields/text-field.svelte +7 -2
  122. package/dist/admin/components/fields/url-field-wrapper.svelte +10 -0
  123. package/dist/admin/components/fields/url-field.svelte +36 -23
  124. package/dist/admin/components/forms/form-error-summary.svelte +143 -0
  125. package/dist/admin/components/forms/form-error-summary.svelte.d.ts +27 -0
  126. package/dist/admin/components/layout/app-sidebar.svelte +7 -2
  127. package/dist/admin/components/layout/detail-page-shell.svelte +71 -0
  128. package/dist/admin/components/layout/detail-page-shell.svelte.d.ts +24 -0
  129. package/dist/admin/components/layout/lang.d.ts +5 -0
  130. package/dist/admin/components/layout/lang.js +10 -0
  131. package/dist/admin/components/layout/layout-renderer.svelte +71 -2
  132. package/dist/admin/components/layout/layout-renderer.svelte.d.ts +1 -0
  133. package/dist/admin/components/layout/layout-tabs.svelte +173 -0
  134. package/dist/admin/components/layout/layout-tabs.svelte.d.ts +24 -0
  135. package/dist/admin/components/layout/nav-breadcrumbs.svelte +25 -7
  136. package/dist/admin/components/layout/nav-collections.svelte +23 -36
  137. package/dist/admin/components/layout/nav-forms.svelte +19 -35
  138. package/dist/admin/components/layout/nav-main.svelte +3 -28
  139. package/dist/admin/components/layout/nav-search.svelte +70 -2
  140. package/dist/admin/components/layout/nav-section.svelte +77 -0
  141. package/dist/admin/components/layout/nav-section.svelte.d.ts +22 -0
  142. package/dist/admin/components/layout/nav-shop.svelte +3 -27
  143. package/dist/admin/components/layout/nav-singletons.svelte +16 -28
  144. package/dist/admin/components/layout/page-header.stories.svelte +93 -0
  145. package/dist/admin/components/layout/page-header.stories.svelte.d.ts +27 -0
  146. package/dist/admin/components/layout/page-header.svelte +68 -0
  147. package/dist/admin/components/layout/page-header.svelte.d.ts +17 -0
  148. package/dist/admin/components/layout/site-header.svelte +9 -0
  149. package/dist/admin/components/layout/site-header.svelte.d.ts +2 -17
  150. package/dist/admin/components/media/file/file-name-input.svelte +6 -2
  151. package/dist/admin/components/media/file/file-preview.svelte +130 -17
  152. package/dist/admin/components/media/file-upload.svelte +16 -7
  153. package/dist/admin/components/media/file-upload.svelte.d.ts +1 -0
  154. package/dist/admin/components/media/files-list.svelte +153 -53
  155. package/dist/admin/components/media/files-list.svelte.d.ts +1 -0
  156. package/dist/admin/components/media/media-library.svelte +577 -198
  157. package/dist/admin/components/media/media-library.svelte.d.ts +4 -0
  158. package/dist/admin/components/media/media-selector.svelte +4 -2
  159. package/dist/admin/components/media/media-selector.svelte.d.ts +1 -0
  160. package/dist/admin/components/media/tag-sidebar.svelte +4 -4
  161. package/dist/admin/components/tiptap/FigureNodeView.svelte +10 -0
  162. package/dist/admin/components/tiptap/bubble-menu.svelte +104 -0
  163. package/dist/admin/components/tiptap/bubble-menu.svelte.d.ts +19 -0
  164. package/dist/admin/components/tiptap/content-editor.svelte +28 -24
  165. package/dist/admin/components/tiptap/editor-toolbar.svelte +7 -7
  166. package/dist/admin/components/tiptap/extensions.js +5 -1
  167. package/dist/admin/components/tiptap/image-dialog.svelte +5 -1
  168. package/dist/admin/components/tiptap/link-dialog.svelte +2 -0
  169. package/dist/admin/components/tiptap/tiptap-editor.svelte +18 -20
  170. package/dist/admin/components/tiptap/video-dialog.svelte +1 -1
  171. package/dist/admin/components/variant-form/VariantAttributeRenderer.svelte +109 -0
  172. package/dist/admin/components/variant-form/VariantAttributeRenderer.svelte.d.ts +9 -0
  173. package/dist/admin/helpers/build-icon-set-map.d.ts +8 -0
  174. package/dist/admin/helpers/build-icon-set-map.js +16 -0
  175. package/dist/admin/helpers/index.d.ts +2 -0
  176. package/dist/admin/helpers/index.js +2 -0
  177. package/dist/admin/i18n/errors.d.ts +140 -0
  178. package/dist/admin/i18n/errors.js +151 -0
  179. package/dist/admin/remote/entry.remote.d.ts +59 -4
  180. package/dist/admin/remote/entry.remote.js +239 -62
  181. package/dist/admin/remote/shop.remote.d.ts +87 -48
  182. package/dist/admin/remote/shop.remote.js +70 -8
  183. package/dist/admin/shared/password-generate.d.ts +6 -0
  184. package/dist/admin/shared/password-generate.js +40 -0
  185. package/dist/admin/shared/password-schema.d.ts +6 -0
  186. package/dist/admin/shared/password-schema.js +10 -3
  187. package/dist/admin/state/icon-sets.svelte.d.ts +9 -0
  188. package/dist/admin/state/icon-sets.svelte.js +20 -0
  189. package/dist/admin/styles/admin.css +23 -6
  190. package/dist/admin/styles/tokens.md +244 -0
  191. package/dist/admin/utils/accordionActivation.d.ts +13 -0
  192. package/dist/admin/utils/accordionActivation.js +35 -0
  193. package/dist/admin/utils/entryLabel.d.ts +23 -0
  194. package/dist/admin/utils/entryLabel.js +51 -12
  195. package/dist/admin/utils/field-a11y.d.ts +29 -0
  196. package/dist/admin/utils/field-a11y.js +23 -0
  197. package/dist/admin/utils/fieldPathElement.d.ts +9 -0
  198. package/dist/admin/utils/fieldPathElement.js +18 -0
  199. package/dist/admin/utils/fileDisplay.d.ts +10 -0
  200. package/dist/admin/utils/fileDisplay.js +26 -0
  201. package/dist/admin/utils/flattenFormErrors.d.ts +19 -0
  202. package/dist/admin/utils/flattenFormErrors.js +102 -0
  203. package/dist/admin/utils/formatters.d.ts +12 -0
  204. package/dist/admin/utils/{formatDate.js → formatters.js} +23 -2
  205. package/dist/admin/utils/scrollWithin.d.ts +9 -0
  206. package/dist/admin/utils/scrollWithin.js +32 -0
  207. package/dist/admin/utils/tabActivation.d.ts +12 -0
  208. package/dist/admin/utils/tabActivation.js +24 -0
  209. package/dist/cli/scaffold/admin.js +2 -2
  210. package/dist/cms/runtime/schema.d.ts +1 -0
  211. package/dist/cms/runtime/schema.js +1 -0
  212. package/dist/cms/runtime/types.d.ts +80 -7
  213. package/dist/components/ui/accordion/accordion-content.svelte +17 -3
  214. package/dist/components/ui/accordion/accordion.stories.svelte +21 -1
  215. package/dist/components/ui/alert/alert.stories.svelte +14 -0
  216. package/dist/components/ui/alert-dialog/alert-dialog.stories.svelte +45 -0
  217. package/dist/components/ui/alert-dialog/alert-dialog.stories.svelte.d.ts +27 -0
  218. package/dist/components/ui/avatar/avatar.stories.svelte +27 -0
  219. package/dist/components/ui/badge/badge.stories.svelte +15 -0
  220. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte +47 -0
  221. package/dist/components/ui/breadcrumb/breadcrumb.svelte +1 -1
  222. package/dist/components/ui/button/button.stories.svelte +53 -6
  223. package/dist/components/ui/button/button.svelte +39 -5
  224. package/dist/components/ui/button/button.svelte.d.ts +4 -0
  225. package/dist/components/ui/button-group/button-group.stories.svelte +44 -0
  226. package/dist/components/ui/button-group/button-group.stories.svelte.d.ts +27 -0
  227. package/dist/components/ui/calendar/calendar.stories.svelte +36 -0
  228. package/dist/components/ui/calendar/calendar.stories.svelte.d.ts +27 -0
  229. package/dist/components/ui/card/card.stories.svelte +7 -0
  230. package/dist/components/ui/carousel/carousel.stories.svelte +43 -0
  231. package/dist/components/ui/carousel/carousel.stories.svelte.d.ts +27 -0
  232. package/dist/components/ui/checkbox/checkbox.stories.svelte +67 -0
  233. package/dist/components/ui/checkbox/checkbox.stories.svelte.d.ts +27 -0
  234. package/dist/components/ui/checkbox/checkbox.svelte +1 -1
  235. package/dist/components/ui/command/command.stories.svelte +18 -0
  236. package/dist/components/ui/data-table/data-table.stories.svelte +61 -0
  237. package/dist/components/ui/data-table/data-table.stories.svelte.d.ts +18 -0
  238. package/dist/components/ui/dialog/dialog-content.svelte +5 -0
  239. package/dist/components/ui/dialog/dialog-content.svelte.d.ts +2 -0
  240. package/dist/components/ui/dialog/dialog.stories.svelte +35 -0
  241. package/dist/components/ui/dropdown-menu/dropdown-menu.stories.svelte +74 -0
  242. package/dist/components/ui/dropdown-menu/dropdown-menu.stories.svelte.d.ts +27 -0
  243. package/dist/components/ui/field/field-context.svelte.d.ts +22 -0
  244. package/dist/components/ui/field/field-context.svelte.js +9 -0
  245. package/dist/components/ui/field/field-control.svelte +18 -0
  246. package/dist/components/ui/field/field-control.svelte.d.ts +8 -0
  247. package/dist/components/ui/field/field-description.svelte +12 -0
  248. package/dist/components/ui/field/field-error.svelte +14 -6
  249. package/dist/components/ui/field/field-label.svelte +10 -0
  250. package/dist/components/ui/field/field.stories.svelte +95 -9
  251. package/dist/components/ui/field/field.svelte +57 -0
  252. package/dist/components/ui/field/field.svelte.d.ts +2 -0
  253. package/dist/components/ui/field/index.d.ts +3 -1
  254. package/dist/components/ui/field/index.js +4 -2
  255. package/dist/components/ui/form/form-field-errors.svelte +1 -1
  256. package/dist/components/ui/form/form.stories.svelte +25 -0
  257. package/dist/components/ui/form/form.stories.svelte.d.ts +26 -0
  258. package/dist/components/ui/input/input.stories.svelte +26 -0
  259. package/dist/components/ui/input-group/input-group-input.svelte.d.ts +1 -1
  260. package/dist/components/ui/input-group/input-group.stories.svelte +43 -0
  261. package/dist/components/ui/input-group/input-group.stories.svelte.d.ts +27 -0
  262. package/dist/components/ui/item/item.stories.svelte +61 -0
  263. package/dist/components/ui/item/item.stories.svelte.d.ts +27 -0
  264. package/dist/components/ui/label/label.stories.svelte +7 -0
  265. package/dist/components/ui/live-region/index.d.ts +1 -0
  266. package/dist/components/ui/live-region/index.js +1 -0
  267. package/dist/components/ui/live-region/live-region-demo.svelte +32 -0
  268. package/dist/components/ui/live-region/live-region-demo.svelte.d.ts +7 -0
  269. package/dist/components/ui/live-region/live-region.stories.svelte +23 -0
  270. package/dist/components/ui/live-region/live-region.stories.svelte.d.ts +26 -0
  271. package/dist/components/ui/live-region/live-region.svelte +12 -0
  272. package/dist/components/ui/live-region/live-region.svelte.d.ts +8 -0
  273. package/dist/components/ui/popover/popover.stories.svelte +34 -0
  274. package/dist/components/ui/radio-group/radio-group.stories.svelte +58 -0
  275. package/dist/components/ui/radio-group/radio-group.stories.svelte.d.ts +27 -0
  276. package/dist/components/ui/resizable/resizable.stories.svelte +56 -0
  277. package/dist/components/ui/resizable/resizable.stories.svelte.d.ts +27 -0
  278. package/dist/components/ui/select/select.stories.svelte +49 -0
  279. package/dist/components/ui/separator/separator.stories.svelte +18 -0
  280. package/dist/components/ui/sheet/sheet.stories.svelte +34 -0
  281. package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +1 -1
  282. package/dist/components/ui/sidebar/sidebar-menu-button.svelte +1 -0
  283. package/dist/components/ui/sidebar/sidebar-trigger.svelte +1 -1
  284. package/dist/components/ui/sidebar/sidebar.stories.svelte +72 -0
  285. package/dist/components/ui/sidebar/sidebar.stories.svelte.d.ts +27 -0
  286. package/dist/components/ui/skeleton/skeleton.stories.svelte +39 -0
  287. package/dist/components/ui/skeleton/skeleton.stories.svelte.d.ts +27 -0
  288. package/dist/components/ui/skeleton/skeleton.svelte +6 -0
  289. package/dist/components/ui/sonner/index.d.ts +1 -1
  290. package/dist/components/ui/sonner/index.js +1 -1
  291. package/dist/components/ui/sonner/sonner.stories.svelte +7 -0
  292. package/dist/components/ui/sonner/sonner.svelte +17 -1
  293. package/dist/components/ui/sonner/sonner.svelte.d.ts +6 -0
  294. package/dist/components/ui/spinner/spinner.stories.svelte +30 -0
  295. package/dist/components/ui/spinner/spinner.stories.svelte.d.ts +27 -0
  296. package/dist/components/ui/switch/switch.stories.svelte +56 -0
  297. package/dist/components/ui/switch/switch.stories.svelte.d.ts +27 -0
  298. package/dist/components/ui/table/table-cell.svelte +1 -1
  299. package/dist/components/ui/table/table-head.svelte +1 -1
  300. package/dist/components/ui/table/table.stories.svelte +68 -0
  301. package/dist/components/ui/table/table.stories.svelte.d.ts +27 -0
  302. package/dist/components/ui/table/table.svelte +1 -1
  303. package/dist/components/ui/tabs/tabs.stories.svelte +48 -0
  304. package/dist/components/ui/tabs/tabs.stories.svelte.d.ts +27 -0
  305. package/dist/components/ui/textarea/textarea.stories.svelte +21 -0
  306. package/dist/components/ui/toggle/toggle.stories.svelte +23 -0
  307. package/dist/components/ui/toggle-group/toggle-group.stories.svelte +43 -0
  308. package/dist/components/ui/tooltip/tooltip.stories.svelte +46 -6
  309. package/dist/core/cms.d.ts +11 -2
  310. package/dist/core/cms.js +29 -0
  311. package/dist/core/fields/fieldSchemaToTs.d.ts +7 -0
  312. package/dist/core/fields/fieldSchemaToTs.js +241 -90
  313. package/dist/core/fields/layoutUtils.d.ts +4 -1
  314. package/dist/core/fields/layoutUtils.js +41 -4
  315. package/dist/core/fields/resolveSeo.d.ts +70 -0
  316. package/dist/core/fields/resolveSeo.js +88 -0
  317. package/dist/core/fields/seoFieldDescriptor.d.ts +43 -0
  318. package/dist/core/fields/seoFieldDescriptor.js +74 -0
  319. package/dist/core/fields/slugPath.d.ts +13 -0
  320. package/dist/core/fields/slugPath.js +32 -0
  321. package/dist/core/fields/urlUtils.d.ts +8 -0
  322. package/dist/core/fields/urlUtils.js +27 -0
  323. package/dist/core/index.d.ts +1 -0
  324. package/dist/core/index.js +1 -0
  325. package/dist/core/server/entries/operations/create.js +13 -0
  326. package/dist/core/server/entries/operations/get.d.ts +7 -0
  327. package/dist/core/server/entries/operations/get.js +10 -6
  328. package/dist/core/server/entries/operations/slugUniqueness.d.ts +37 -0
  329. package/dist/core/server/entries/operations/slugUniqueness.js +116 -0
  330. package/dist/core/server/entries/operations/update.d.ts +6 -1
  331. package/dist/core/server/entries/operations/update.js +24 -1
  332. package/dist/core/server/fields/slugResolver.d.ts +3 -13
  333. package/dist/core/server/fields/slugResolver.js +8 -37
  334. package/dist/core/server/generator/fields.d.ts +2 -0
  335. package/dist/core/server/generator/fields.js +44 -18
  336. package/dist/core/server/generator/formFields.js +2 -1
  337. package/dist/core/server/generator/generator.js +6 -5
  338. package/dist/core/server/generator/utils.d.ts +1 -0
  339. package/dist/core/server/generator/utils.js +4 -0
  340. package/dist/db-postgres/schema/shop/order.d.ts +37 -1
  341. package/dist/db-postgres/schema/shop/order.js +3 -1
  342. package/dist/db-postgres/schema/shop/payment.d.ts +20 -0
  343. package/dist/db-postgres/schema/shop/payment.js +4 -1
  344. package/dist/db-postgres/schema/shop/product.d.ts +20 -0
  345. package/dist/db-postgres/schema/shop/product.js +3 -1
  346. package/dist/db-postgres/schema/shop/productVariant.d.ts +12 -2
  347. package/dist/db-postgres/schema/shop/productVariant.js +22 -0
  348. package/dist/shop/cart/types.d.ts +1 -0
  349. package/dist/shop/client/index.d.ts +54 -0
  350. package/dist/shop/client/index.js +5 -1
  351. package/dist/shop/expiry.d.ts +35 -0
  352. package/dist/shop/expiry.js +68 -0
  353. package/dist/shop/http/balance-handler.d.ts +20 -0
  354. package/dist/shop/http/balance-handler.js +91 -0
  355. package/dist/shop/http/cart-handler.js +19 -0
  356. package/dist/shop/http/checkout-handler.js +19 -1
  357. package/dist/shop/http/index.d.ts +2 -0
  358. package/dist/shop/http/index.js +2 -0
  359. package/dist/shop/http/upcoming-handler.d.ts +16 -0
  360. package/dist/shop/http/upcoming-handler.js +65 -0
  361. package/dist/shop/http/webhook-handler.js +46 -9
  362. package/dist/shop/index.d.ts +4 -1
  363. package/dist/shop/index.js +7 -1
  364. package/dist/shop/server/balance-payment.d.ts +40 -0
  365. package/dist/shop/server/balance-payment.js +140 -0
  366. package/dist/shop/server/cart-hydrate.js +2 -0
  367. package/dist/shop/server/init.d.ts +14 -0
  368. package/dist/shop/server/init.js +35 -0
  369. package/dist/shop/server/orders.d.ts +35 -0
  370. package/dist/shop/server/orders.js +155 -2
  371. package/dist/shop/server/payment-policy.d.ts +35 -0
  372. package/dist/shop/server/payment-policy.js +55 -0
  373. package/dist/shop/server/payments.d.ts +29 -0
  374. package/dist/shop/server/payments.js +64 -0
  375. package/dist/shop/server/populate.d.ts +1 -1
  376. package/dist/shop/server/refund.d.ts +17 -12
  377. package/dist/shop/server/refund.js +96 -13
  378. package/dist/shop/server/shop-data.d.ts +6 -1
  379. package/dist/shop/server/shop-data.js +44 -7
  380. package/dist/shop/template.d.ts +13 -0
  381. package/dist/shop/template.js +98 -0
  382. package/dist/shop/types.d.ts +142 -1
  383. package/dist/shop/variant-attributes.d.ts +28 -0
  384. package/dist/shop/variant-attributes.js +69 -0
  385. package/dist/sveltekit/server/handle.js +17 -0
  386. package/dist/sveltekit/server/index.d.ts +1 -0
  387. package/dist/sveltekit/server/index.js +2 -0
  388. package/dist/types/cms.d.ts +4 -3
  389. package/dist/types/cms.schema.d.ts +1 -1
  390. package/dist/types/cms.schema.js +13 -2
  391. package/dist/types/fields.d.ts +56 -2
  392. package/dist/types/index.d.ts +2 -2
  393. package/dist/types/index.js +1 -1
  394. package/dist/types/layout.d.ts +35 -2
  395. package/dist/types/plugins.d.ts +40 -0
  396. package/dist/types/plugins.js +4 -1
  397. package/dist/updates/0.26.0/index.d.ts +2 -0
  398. package/dist/updates/0.26.0/index.js +51 -0
  399. package/dist/updates/0.26.1/index.d.ts +2 -0
  400. package/dist/updates/0.26.1/index.js +19 -0
  401. package/dist/updates/0.27.0/index.d.ts +2 -0
  402. package/dist/updates/0.27.0/index.js +50 -0
  403. package/dist/updates/index.js +7 -1
  404. package/package.json +29 -7
  405. package/dist/admin/client/collection/empty-state.svelte +0 -28
  406. package/dist/admin/client/collection/empty-state.svelte.d.ts +0 -9
  407. package/dist/admin/client/form/submission-status-badge.svelte +0 -41
  408. package/dist/admin/client/form/submission-status-badge.svelte.d.ts +0 -7
  409. package/dist/admin/components/media/file-preview.svelte +0 -51
  410. package/dist/admin/components/media/file-preview.svelte.d.ts +0 -6
  411. package/dist/admin/utils/formatDate.d.ts +0 -5
@@ -332,7 +332,12 @@
332
332
  {/if}
333
333
 
334
334
  <Dialog.Root bind:open={dialogOpen}>
335
- <Dialog.Content class="h-[85vh] w-full max-w-6xl! sm:max-w-6xl! overflow-hidden p-0 flex flex-col">
335
+ <Dialog.Content
336
+ fullscreenMobile
337
+ class="flex h-[85vh] w-full max-w-6xl! flex-col overflow-hidden p-0 sm:max-w-6xl!"
338
+ >
339
+ <Dialog.Title class="sr-only">{lang[interfaceLanguage.current].selectMedia}</Dialog.Title>
340
+ <Dialog.Description class="sr-only">{lang[interfaceLanguage.current].selectMedia}</Dialog.Description>
336
341
  <MediaSelector
337
342
  bind:selected={value}
338
343
  multiple={field.multiple}
@@ -345,7 +350,16 @@
345
350
 
346
351
  <!-- Lightbox for images -->
347
352
  <Dialog.Root bind:open={lightboxOpen}>
348
- <Dialog.Content class="max-w-[90vw] max-h-[90vh] p-2 bg-black/95 border-none">
353
+ <Dialog.Content
354
+ fullscreenMobile
355
+ class="max-h-[90vh] max-w-[90vw]! border-none bg-black/95 p-2"
356
+ >
357
+ <Dialog.Title class="sr-only">
358
+ {lightboxFile?.alt || lightboxFile?.name || ''}
359
+ </Dialog.Title>
360
+ <Dialog.Description class="sr-only">
361
+ {lightboxFile?.alt || lightboxFile?.name || ''}
362
+ </Dialog.Description>
349
363
  {#if lightboxFile}
350
364
  <div class="checkered-lightbox flex items-center justify-center">
351
365
  <img
@@ -9,7 +9,6 @@
9
9
  import type { ObjectField, ObjectFieldData } from '../../../types/fields.js';
10
10
  import { evaluateCondition } from '../../utils/fieldCondition.js';
11
11
  import { onMount } from 'svelte';
12
- import * as Item from '../../../components/ui/item/index.js';
13
12
  import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
14
13
  import { getLocalizedLabel } from '../../utils/collectionLabel.js';
15
14
  import { cn } from '../../../utils.js';
@@ -90,12 +89,33 @@
90
89
  {@render content()}
91
90
  </div>
92
91
  {:else}
93
- <!-- Top-level: with border -->
94
- <Item.Root variant="outline">
95
- <Item.Content>
96
- <Item.Title class="mb-4 text-lg">{getLocalizedLabel(field.label, interfaceLanguage.current)}</Item.Title>
92
+ <!-- Top-level: full-width card -->
93
+ <div class="object-card">
94
+ <div class="object-card-header">{getLocalizedLabel(field.label, interfaceLanguage.current)}</div>
95
+ <div class="object-card-body">
97
96
  {@render content()}
98
- </Item.Content>
99
- </Item.Root>
97
+ </div>
98
+ </div>
100
99
  {/if}
101
100
  {/if}
101
+
102
+ <style>
103
+ .object-card {
104
+ background: var(--card);
105
+ border: 1px solid var(--border);
106
+ border-radius: 12px;
107
+ box-shadow: 0 1px 2px rgba(43, 37, 88, 0.04);
108
+ overflow: hidden;
109
+ }
110
+
111
+ .object-card-header {
112
+ font-size: 13px;
113
+ font-weight: 700;
114
+ color: var(--foreground);
115
+ padding: 12px 16px 0;
116
+ }
117
+
118
+ .object-card-body {
119
+ padding: 10px 16px 16px;
120
+ }
121
+ </style>
@@ -15,11 +15,18 @@
15
15
 
16
16
  const interfaceLanguage = useInterfaceLanguage();
17
17
 
18
+ const clearLabel: Record<string, string> = {
19
+ pl: 'Wyczyść wybór',
20
+ en: 'Clear selection'
21
+ };
22
+
18
23
  onMount(() => {
19
24
  if (value === undefined) {
20
25
  value = field.defaultValue ?? '';
21
26
  }
22
27
  });
28
+
29
+ const canClear = $derived(!field.required && typeof value === 'string' && value !== '');
23
30
  </script>
24
31
 
25
32
  {#if value !== undefined}
@@ -35,4 +42,19 @@
35
42
  </div>
36
43
  {/each}
37
44
  </RadioGroup.Root>
45
+
46
+ {#if canClear}
47
+ <!--
48
+ Native radios have no native "uncheck" gesture. For optional fields,
49
+ expose an explicit Clear link so the editor can return to the
50
+ "no value" state without picking a sentinel option.
51
+ -->
52
+ <button
53
+ type="button"
54
+ class="text-muted-foreground hover:text-foreground mt-1 self-start text-xs underline-offset-2 hover:underline"
55
+ onclick={() => (value = '')}
56
+ >
57
+ {clearLabel[interfaceLanguage.current] ?? clearLabel.en}
58
+ </button>
59
+ {/if}
38
60
  {/if}
@@ -16,6 +16,7 @@
16
16
  import Spinner from '../../../components/ui/spinner/spinner.svelte';
17
17
  import type { InterfaceLanguage } from '../../../types/languages.js';
18
18
  import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
19
+ import { getContentLanguage } from '../../state/content-language.svelte.js';
19
20
  import { getLocalizedLabel } from '../../utils/collectionLabel.js';
20
21
  import { droppable, draggable } from '@thisux/sveltednd';
21
22
  import { arrayMove } from '../../utils/arrayMove.js';
@@ -23,6 +24,7 @@
23
24
  import { flip } from 'svelte/animate';
24
25
  import { fade } from 'svelte/transition';
25
26
  import RelationPickerDialog from './relation-picker-dialog.svelte';
27
+ import { LiveRegion } from '../../../components/ui/live-region/index.js';
26
28
 
27
29
  const lang: Record<
28
30
  InterfaceLanguage,
@@ -79,6 +81,7 @@
79
81
 
80
82
  const remotes = getRemotes();
81
83
  const interfaceLanguage = useInterfaceLanguage();
84
+ const contentLanguage = getContentLanguage();
82
85
 
83
86
  type Props = {
84
87
  field: RelationField;
@@ -90,6 +93,13 @@
90
93
  const multiple = $derived(field.multiple === true);
91
94
  const t = $derived(lang[interfaceLanguage.current]);
92
95
 
96
+ // Collection singular labels come from config Pascal/Title-cased (it is the
97
+ // noun's nominative — "Projekt", "Post"). Inside a sentence it should be
98
+ // lowercase ("Wybierz projekt"). Cheap rule: first char to lowercase.
99
+ function inSentence(label: string): string {
100
+ return label ? label.charAt(0).toLowerCase() + label.slice(1) : label;
101
+ }
102
+
93
103
  // Ensure value is array when multiple
94
104
  onMount(() => {
95
105
  if (multiple && !Array.isArray(value)) {
@@ -140,7 +150,8 @@
140
150
 
141
151
  const results = await remotes.getEntryLabels({
142
152
  slug: field.collection,
143
- ids: missing
153
+ ids: missing,
154
+ language: contentLanguage.current
144
155
  });
145
156
  const newCache = new Map(labelCache);
146
157
  for (const r of results) {
@@ -181,7 +192,8 @@
181
192
  slug: field.collection,
182
193
  search: search || undefined,
183
194
  status: 'published',
184
- limit: 100
195
+ limit: 100,
196
+ language: contentLanguage.current
185
197
  });
186
198
  pickerOptions = results.map((r) => ({ id: r.id, label: r.label }));
187
199
  if (results.length > 0) {
@@ -200,7 +212,8 @@
200
212
  const results = await remotes.getEntryLabels({
201
213
  slug: field.collection,
202
214
  status: 'published',
203
- limit: 100
215
+ limit: 100,
216
+ language: contentLanguage.current
204
217
  });
205
218
  pickerOptions = results.map((r) => ({ id: r.id, label: r.label }));
206
219
  totalCount = results.length > 0 ? results[0].total : 0;
@@ -366,7 +379,7 @@
366
379
  aria-haspopup="dialog"
367
380
  >
368
381
  <Plus class="h-4 w-4" />
369
- {t.add} {singularLabel}
382
+ {t.select} {inSentence(singularLabel)}
370
383
  </button>
371
384
 
372
385
  <RelationPickerDialog
@@ -393,10 +406,12 @@
393
406
  aria-expanded={popoverOpen}
394
407
  >
395
408
  <Plus class="h-4 w-4" />
396
- {t.add} {singularLabel}
409
+ {t.select} {inSentence(singularLabel)}
397
410
  </Popover.Trigger>
398
411
 
399
- <Popover.Content class="min-w-[280px] p-0">
412
+ <Popover.Content
413
+ class="w-[var(--bits-popover-anchor-width)] min-w-[280px] max-w-[calc(100vw-1rem)] p-0"
414
+ >
400
415
  <Command.Root>
401
416
  <Command.Input
402
417
  autofocus
@@ -434,107 +449,118 @@
434
449
  </Popover.Root>
435
450
  {/if}
436
451
 
437
- <!-- Live region for screen readers -->
438
- <div class="sr-only" aria-live="polite" role="status">
439
- {liveMessage || `${getArrayValue().length} ${t.selected}`}
440
- </div>
452
+ <LiveRegion message={liveMessage || `${getArrayValue().length} ${t.selected}`} />
441
453
  {:else}
442
- <!-- Single-select mode -->
443
- {#if value}
444
- <!-- Show selected chip -->
445
- <div class="flex items-center gap-2 rounded-md border bg-background px-3 py-2 text-sm">
446
- <span class="flex-1 truncate">{singleLabel}</span>
454
+ <!-- Single-select mode: the combobox trigger shows the selected label
455
+ (or a placeholder), with an inline X to clear. Standard shadcn/bits-ui
456
+ combobox UX replaces the previous chip + separate trigger pair. -->
457
+ {@const placeholder = `${t.select} ${inSentence(singularLabel)}`}
458
+ {@const triggerLabel = singleLabel || placeholder}
459
+
460
+ <div class="relative">
461
+ {#if useDialog}
447
462
  <button
448
463
  type="button"
449
- class="shrink-0 text-muted-foreground hover:text-destructive"
450
- onclick={clearValue}
451
- aria-label={t.clear}
452
- >
453
- <X class="h-3.5 w-3.5" />
454
- </button>
455
- </div>
456
- {/if}
457
-
458
- {#if useDialog}
459
- <button
460
- type="button"
461
- class={cn(
462
- buttonVariants({ variant: 'outline' }),
463
- 'w-full justify-between',
464
- !value && 'text-muted-foreground',
465
- value && 'mt-1.5'
466
- )}
467
- onclick={openPicker}
468
- role="combobox"
469
- aria-expanded={pickerOpen}
470
- aria-haspopup="dialog"
471
- {...props}
472
- >
473
- {`${t.select} ${singularLabel}`}
474
- <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg>
475
- </button>
476
-
477
- <RelationPickerDialog
478
- bind:open={pickerOpen}
479
- title="{t.dialogTitle} {singularLabel}"
480
- searchPlaceholder="{t.search} {collectionLabel}..."
481
- noResults={t.noResults}
482
- closeLabel={t.closeDialog}
483
- {multiple}
484
- selected={value ? [value as string] : []}
485
- options={pickerOptions}
486
- loading={pickerLoading}
487
- bind:searchValue
488
- onSearchChange={handleSearchChange}
489
- onSelect={toggleItem}
490
- onClose={closePicker}
491
- />
492
- {:else}
493
- <Popover.Root bind:open={popoverOpen}>
494
- <Popover.Trigger
495
- id={triggerId}
496
464
  class={cn(
497
465
  buttonVariants({ variant: 'outline' }),
498
466
  'w-full justify-between',
499
467
  !value && 'text-muted-foreground',
500
- value && 'mt-1.5'
468
+ value && 'pr-16'
501
469
  )}
470
+ onclick={openPicker}
502
471
  role="combobox"
503
- aria-expanded={popoverOpen}
472
+ aria-expanded={pickerOpen}
473
+ aria-haspopup="dialog"
504
474
  {...props}
505
475
  >
506
- {`${t.select} ${singularLabel}`}
507
- <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg>
508
- </Popover.Trigger>
476
+ <span class="truncate text-left">{triggerLabel}</span>
477
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0 opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg>
478
+ </button>
509
479
 
510
- <Popover.Content class="min-w-[280px] p-0">
511
- <Command.Root>
512
- <Command.Input
513
- autofocus
514
- placeholder="{t.search} {collectionLabel}..."
515
- class="h-9"
516
- />
517
- <Command.List>
518
- <Command.Empty>{t.noResults}</Command.Empty>
519
- <Command.Group>
520
- {#each pickerOptions as option (option.id)}
521
- <Command.Item
522
- value={option.label}
523
- onSelect={() => {
524
- value = option.id;
525
- closePopoverAndFocus();
526
- }}
527
- >
528
- {option.label}
529
- <Check
530
- class={cn('ml-auto', option.id !== value && 'text-transparent')}
531
- />
532
- </Command.Item>
533
- {/each}
534
- </Command.Group>
535
- </Command.List>
536
- </Command.Root>
537
- </Popover.Content>
538
- </Popover.Root>
539
- {/if}
480
+ <RelationPickerDialog
481
+ bind:open={pickerOpen}
482
+ title="{t.dialogTitle} {inSentence(singularLabel)}"
483
+ searchPlaceholder="{t.search} {collectionLabel}..."
484
+ noResults={t.noResults}
485
+ closeLabel={t.closeDialog}
486
+ {multiple}
487
+ selected={value ? [value as string] : []}
488
+ options={pickerOptions}
489
+ loading={pickerLoading}
490
+ bind:searchValue
491
+ onSearchChange={handleSearchChange}
492
+ onSelect={toggleItem}
493
+ onClose={closePicker}
494
+ />
495
+ {:else}
496
+ <Popover.Root bind:open={popoverOpen}>
497
+ <Popover.Trigger
498
+ id={triggerId}
499
+ class={cn(
500
+ buttonVariants({ variant: 'outline' }),
501
+ 'w-full justify-between',
502
+ !value && 'text-muted-foreground',
503
+ value && 'pr-16'
504
+ )}
505
+ role="combobox"
506
+ aria-expanded={popoverOpen}
507
+ {...props}
508
+ >
509
+ <span class="truncate text-left">{triggerLabel}</span>
510
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0 opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg>
511
+ </Popover.Trigger>
512
+
513
+ <Popover.Content
514
+ class="w-[var(--bits-popover-anchor-width)] min-w-[280px] max-w-[calc(100vw-1rem)] p-0"
515
+ >
516
+ <Command.Root>
517
+ <Command.Input
518
+ autofocus
519
+ placeholder="{t.search} {collectionLabel}..."
520
+ class="h-9"
521
+ />
522
+ <Command.List>
523
+ <Command.Empty>{t.noResults}</Command.Empty>
524
+ <Command.Group>
525
+ {#each pickerOptions as option (option.id)}
526
+ <Command.Item
527
+ value={option.label}
528
+ onSelect={() => {
529
+ value = option.id;
530
+ closePopoverAndFocus();
531
+ }}
532
+ >
533
+ {option.label}
534
+ <Check
535
+ class={cn('ml-auto', option.id !== value && 'text-transparent')}
536
+ />
537
+ </Command.Item>
538
+ {/each}
539
+ </Command.Group>
540
+ </Command.List>
541
+ </Command.Root>
542
+ </Popover.Content>
543
+ </Popover.Root>
544
+ {/if}
545
+
546
+ {#if value}
547
+ <!--
548
+ Absolute-positioned clear button next to the chevron. Sits inside
549
+ the trigger's right padding (`pr-16` above) so it doesn't overlap
550
+ the label, and stops propagation to avoid opening the picker.
551
+ -->
552
+ <button
553
+ type="button"
554
+ class="text-muted-foreground hover:text-destructive absolute top-1/2 right-9 -translate-y-1/2 rounded-sm p-0.5"
555
+ onclick={(e) => {
556
+ e.preventDefault();
557
+ e.stopPropagation();
558
+ clearValue();
559
+ }}
560
+ aria-label={t.clear}
561
+ >
562
+ <X class="h-3.5 w-3.5" />
563
+ </button>
564
+ {/if}
565
+ </div>
540
566
  {/if}
@@ -67,9 +67,9 @@
67
67
  onValueChange={(v) => onSearchChange(v)}
68
68
  class="h-10"
69
69
  />
70
- <Command.List class="max-h-[50vh] flex-1 overflow-y-auto">
70
+ <Command.List class="max-h-[50vh] flex-1 overflow-y-auto" aria-busy={loading}>
71
71
  {#if loading}
72
- <div class="flex items-center justify-center py-6">
72
+ <div class="flex items-center justify-center py-6" role="status" aria-label="Ładowanie wyników">
73
73
  <Spinner class="size-5" />
74
74
  </div>
75
75
  {:else if options.length === 0}
@@ -103,14 +103,6 @@
103
103
  required: false
104
104
  };
105
105
 
106
- const titleField: TextField = {
107
- type: 'text',
108
- slug: 'title',
109
- label: labels.title.label,
110
- description: labels.title.description,
111
- required: true
112
- };
113
-
114
106
  const descriptionField: TextField = {
115
107
  type: 'text',
116
108
  slug: 'description',
@@ -149,7 +141,6 @@
149
141
 
150
142
  const fields: Field[] = [
151
143
  canonicalUrlField,
152
- titleField,
153
144
  descriptionField,
154
145
  keyWordsField,
155
146
  ogImageField,
@@ -179,9 +170,11 @@
179
170
  return 'text-destructive';
180
171
  }
181
172
 
182
- // Slug field proxy for direct input binding
173
+ // Slug + title field proxies for direct input binding
183
174
  const slugPath = joinPath(String(path), 'slug');
175
+ const titlePath = joinPath(String(path), 'title');
184
176
  const { value: slugValue } = formFieldProxy(form, slugPath as FormPathLeaves<Record<string, unknown>>);
177
+ const { value: titleValue } = formFieldProxy(form, titlePath as FormPathLeaves<Record<string, unknown>>);
185
178
 
186
179
  // Auto-gen: track last auto-generated value
187
180
  let lastAutoSlug = '';
@@ -229,24 +222,46 @@
229
222
  $formData = $formData;
230
223
  }
231
224
 
232
- // titleSource auto-fill seo.title (flat)
225
+ // Auto title toggle (analogiczne do autoSlug)
226
+ let autoTitle = $state((() => {
227
+ if (!field.titleSource) return false;
228
+ if (wasPublished) return false;
229
+ const sourceRaw = ($formData as Record<string, unknown>)[field.titleSource];
230
+ if (!sourceRaw || typeof sourceRaw !== 'string') return true;
231
+ const current = getAtPath($formData as Record<string, unknown>, titlePath) as string | undefined;
232
+ if (current != null && current !== '' && current !== sourceRaw) return false;
233
+ return true;
234
+ })());
235
+
236
+ // titleSource → auto-fill seo.title (flat) — tylko gdy autoTitle włączony
233
237
  $effect(() => {
234
- if (!field.titleSource) return;
238
+ if (!field.titleSource || !autoTitle) return;
235
239
  const sourceRaw = ($formData as Record<string, unknown>)[field.titleSource];
236
240
  if (!sourceRaw || typeof sourceRaw !== 'string') return;
237
241
 
238
242
  untrack(() => {
239
- const titlePath = joinPath(String(path), 'title');
240
243
  const current = getAtPath($formData as Record<string, unknown>, titlePath) as string | undefined;
241
- if (!current || current === lastAutoTitle) {
242
- if (sourceRaw !== current) {
243
- setAtPath($formData as Record<string, unknown>, titlePath, sourceRaw);
244
- $formData = $formData;
245
- }
246
- lastAutoTitle = sourceRaw;
244
+ if (sourceRaw !== current) {
245
+ setAtPath($formData as Record<string, unknown>, titlePath, sourceRaw);
246
+ $formData = $formData;
247
247
  }
248
+ lastAutoTitle = sourceRaw;
248
249
  });
249
250
  });
251
+
252
+ function onAutoTitleToggle(checked: boolean) {
253
+ if (!checked || !field.titleSource) return;
254
+ const sourceRaw = ($formData as Record<string, unknown>)[field.titleSource];
255
+ if (!sourceRaw || typeof sourceRaw !== 'string') return;
256
+ setAtPath($formData as Record<string, unknown>, titlePath, sourceRaw);
257
+ lastAutoTitle = sourceRaw;
258
+ $formData = $formData;
259
+ }
260
+
261
+ // User edycja inputa tytułu → wyłącz auto (analogiczne do slug-field cichy flip)
262
+ function onTitleInput() {
263
+ if (autoTitle) autoTitle = false;
264
+ }
250
265
  </script>
251
266
 
252
267
  <div class="space-y-4">
@@ -267,6 +282,31 @@
267
282
  </div>
268
283
  <Form.Description>{getLocalizedLabel(labels.slug.description, interfaceLanguage.current)}</Form.Description>
269
284
  </Form.Field>
285
+
286
+ <!-- Title field with auto/manual toggle (analogiczne do slug) -->
287
+ <Form.Field {form} name={titlePath} class="space-y-1">
288
+ <div class="flex items-center justify-between">
289
+ <Form.Label>{getLocalizedLabel(labels.title.label, interfaceLanguage.current)}</Form.Label>
290
+ {#if field.titleSource}
291
+ <div class="flex items-center gap-2">
292
+ <span class="text-sm font-medium text-muted-foreground">Auto</span>
293
+ <Switch bind:checked={autoTitle} onCheckedChange={onAutoTitleToggle} />
294
+ </div>
295
+ {/if}
296
+ </div>
297
+ <Input bind:value={$titleValue} readonly={autoTitle} oninput={onTitleInput} />
298
+ <Form.Description>{getLocalizedLabel(labels.title.description, interfaceLanguage.current)}</Form.Description>
299
+ <p class="mt-1 text-xs {charHintClass(titleLength, 50, 60)}" aria-live="polite">
300
+ {titleLength}/60
301
+ {#if titleLength > 0 && titleLength < 50}
302
+ — {getLocalizedLabel({ en: 'a bit short', pl: 'trochę za krótko' }, interfaceLanguage.current)}
303
+ {:else if titleLength > 60}
304
+ — {getLocalizedLabel({ en: 'too long', pl: 'za długo' }, interfaceLanguage.current)}
305
+ {/if}
306
+ </p>
307
+ <Form.FieldErrors />
308
+ </Form.Field>
309
+
270
310
  {#each fields as f}
271
311
  <div>
272
312
  <FieldRenderer
@@ -274,18 +314,8 @@
274
314
  {form}
275
315
  path={joinPath(path, f.slug)}
276
316
  />
277
- {#if f.slug === 'title'}
278
- <p class="mt-1 text-xs {charHintClass(titleLength, 50, 60)}">
279
- {titleLength}/60
280
- {#if titleLength > 0 && titleLength < 50}
281
- — {getLocalizedLabel({ en: 'a bit short', pl: 'trochę za krótko' }, interfaceLanguage.current)}
282
- {:else if titleLength > 60}
283
- — {getLocalizedLabel({ en: 'too long', pl: 'za długo' }, interfaceLanguage.current)}
284
- {/if}
285
- </p>
286
- {/if}
287
317
  {#if f.slug === 'description'}
288
- <p class="mt-1 text-xs {charHintClass(descLength, 120, 160)}">
318
+ <p class="mt-1 text-xs {charHintClass(descLength, 120, 160)}" aria-live="polite">
289
319
  {descLength}/160
290
320
  {#if descLength > 0 && descLength < 120}
291
321
  — {getLocalizedLabel({ en: 'a bit short', pl: 'trochę za krótko' }, interfaceLanguage.current)}