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
@@ -1,6 +1,8 @@
1
1
  <script lang="ts">
2
2
  import Button from '../../../../components/ui/button/button.svelte';
3
- import type { MediaFile } from '../../../../types/media.js';
3
+ import type { MediaFile, MediaFileType } from '../../../../types/media.js';
4
+ import type { InterfaceLanguage } from '../../../../types/languages.js';
5
+ import { useInterfaceLanguage } from '../../../state/interface-language.svelte.js';
4
6
  import GripVertical from '@tabler/icons-svelte/icons/grip-vertical';
5
7
  import FileMiniature from './file-miniature.svelte';
6
8
  import X from '@tabler/icons-svelte/icons/x';
@@ -11,6 +13,112 @@
11
13
  import Textarea from '../../../../components/ui/textarea/textarea.svelte';
12
14
  import { toast } from 'svelte-sonner';
13
15
  import Label from '../../../../components/ui/label/label.svelte';
16
+ import { errorMessages } from '../../../i18n/errors.js';
17
+ import { formatFileSize, getFileExtension } from '../../../utils/fileDisplay.js';
18
+
19
+ type AltCopy = {
20
+ title: string;
21
+ label: string;
22
+ placeholder: string;
23
+ help: string;
24
+ editAria: string;
25
+ };
26
+
27
+ const altCopy: Record<InterfaceLanguage, Record<MediaFileType, AltCopy>> = {
28
+ pl: {
29
+ image: {
30
+ title: 'Edytuj tekst alternatywny',
31
+ label: 'Tekst alternatywny',
32
+ placeholder: 'Opisz co przedstawia obraz…',
33
+ help: 'Tekst alternatywny opisuje obraz dla osób niewidomych i wyszukiwarek.',
34
+ editAria: 'Edytuj tekst alternatywny'
35
+ },
36
+ video: {
37
+ title: 'Opis wideo',
38
+ label: 'Opis wideo',
39
+ placeholder: 'Opisz zawartość wideo…',
40
+ help: 'Opis pomaga osobom z niepełnosprawnością wzroku zrozumieć zawartość wideo.',
41
+ editAria: 'Edytuj opis wideo'
42
+ },
43
+ audio: {
44
+ title: 'Opis nagrania',
45
+ label: 'Opis nagrania',
46
+ placeholder: 'Opisz zawartość nagrania…',
47
+ help: 'Opis pomaga osobom z niepełnosprawnością słuchu lub wzroku zrozumieć nagranie.',
48
+ editAria: 'Edytuj opis nagrania'
49
+ },
50
+ pdf: {
51
+ title: 'Opis dokumentu',
52
+ label: 'Opis dokumentu',
53
+ placeholder: 'Krótko o czym jest dokument…',
54
+ help: 'Opis pomaga osobom korzystającym z czytników ekranu zorientować się w zawartości pliku.',
55
+ editAria: 'Edytuj opis dokumentu'
56
+ },
57
+ other: {
58
+ title: 'Opis pliku',
59
+ label: 'Opis pliku',
60
+ placeholder: 'Krótki opis zawartości pliku…',
61
+ help: 'Opis pomaga osobom korzystającym z czytników ekranu zorientować się w zawartości pliku.',
62
+ editAria: 'Edytuj opis pliku'
63
+ }
64
+ },
65
+ en: {
66
+ image: {
67
+ title: 'Edit alt text',
68
+ label: 'Alt text',
69
+ placeholder: 'Describe what the image shows…',
70
+ help: 'Alt text describes the image for screen reader users and search engines.',
71
+ editAria: 'Edit alt text'
72
+ },
73
+ video: {
74
+ title: 'Edit video description',
75
+ label: 'Video description',
76
+ placeholder: 'Describe the video content…',
77
+ help: 'The description helps users with visual impairments understand the video.',
78
+ editAria: 'Edit video description'
79
+ },
80
+ audio: {
81
+ title: 'Edit audio description',
82
+ label: 'Audio description',
83
+ placeholder: 'Describe the audio content…',
84
+ help: 'The description helps users with hearing or visual impairments understand the audio.',
85
+ editAria: 'Edit audio description'
86
+ },
87
+ pdf: {
88
+ title: 'Edit document description',
89
+ label: 'Document description',
90
+ placeholder: 'Briefly describe the document…',
91
+ help: 'The description helps screen reader users understand the file content.',
92
+ editAria: 'Edit document description'
93
+ },
94
+ other: {
95
+ title: 'Edit file description',
96
+ label: 'File description',
97
+ placeholder: 'Briefly describe the file content…',
98
+ help: 'The description helps screen reader users understand the file content.',
99
+ editAria: 'Edit file description'
100
+ }
101
+ }
102
+ };
103
+
104
+ const ui: Record<InterfaceLanguage, { cancel: string; save: string; saving: string; saved: string; saveError: string; fileMissing: string }> = {
105
+ pl: {
106
+ cancel: 'Anuluj',
107
+ save: 'Zapisz',
108
+ saving: 'Zapisuję…',
109
+ saved: 'Opis zapisany',
110
+ saveError: errorMessages.server.saveFailed.pl,
111
+ fileMissing: 'Plik nie istnieje.'
112
+ },
113
+ en: {
114
+ cancel: 'Cancel',
115
+ save: 'Save',
116
+ saving: 'Saving…',
117
+ saved: 'Description saved',
118
+ saveError: errorMessages.server.saveFailed.en,
119
+ fileMissing: 'File does not exist.'
120
+ }
121
+ };
14
122
 
15
123
  type Props = {
16
124
  fileId: string;
@@ -20,6 +128,7 @@
20
128
 
21
129
  let { fileId, index, onDelete }: Props = $props();
22
130
 
131
+ const interfaceLanguage = useInterfaceLanguage();
23
132
  const remotes = getRemotes();
24
133
  let lightboxOpen = $state(false);
25
134
  let altDialogOpen = $state(false);
@@ -28,13 +137,14 @@
28
137
 
29
138
  async function saveAlt(file: MediaFile) {
30
139
  saving = true;
140
+ const t = ui[interfaceLanguage.current];
31
141
  try {
32
142
  await remotes.setMediaFileAlt({ fileId: file.id, alt: altValue || null });
33
143
  file.alt = altValue;
34
144
  altDialogOpen = false;
35
- toast.success('Alt text zapisany');
145
+ toast.success(t.saved);
36
146
  } catch {
37
- toast.error('Błąd zapisu');
147
+ toast.error(t.saveError);
38
148
  }
39
149
  saving = false;
40
150
  }
@@ -44,6 +154,9 @@
44
154
 
45
155
  {#if query.ready && query.current}
46
156
  {@const file = query.current}
157
+ {@const copy = altCopy[interfaceLanguage.current][file.type]}
158
+ {@const t = ui[interfaceLanguage.current]}
159
+ {@const ext = getFileExtension(file.url)}
47
160
  <div class="group flex items-center gap-3 rounded-xl border bg-card p-2 shadow-sm transition-all hover:-translate-y-0.5 hover:shadow-md">
48
161
  <!-- Miniaturka z lightbox -->
49
162
  <button
@@ -55,12 +168,16 @@
55
168
  </button>
56
169
 
57
170
  <div class="min-w-0 flex-1">
58
- <div class="flex items-center gap-1">
171
+ <div class="flex items-center gap-1.5">
59
172
  <p class="truncate text-sm font-medium flex-1">{file.name}</p>
173
+ {#if ext}
174
+ <span class="shrink-0 rounded bg-muted px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground">{ext}</span>
175
+ {/if}
60
176
  <Button
61
177
  variant="ghost"
62
178
  size="icon"
63
179
  class="h-6 w-6 shrink-0"
180
+ aria-label={copy.editAria}
64
181
  onclick={() => {
65
182
  altValue = file.alt || '';
66
183
  altDialogOpen = true;
@@ -69,9 +186,7 @@
69
186
  <Pencil class="h-3 w-3" />
70
187
  </Button>
71
188
  </div>
72
- {#if file.size}
73
- <p class="text-xs text-muted-foreground">{(file.size / 1024).toFixed(1)} KB</p>
74
- {/if}
189
+ <p class="text-xs text-muted-foreground">{formatFileSize(file.size)}</p>
75
190
  {#if file.alt}
76
191
  <p class="text-xs text-muted-foreground truncate" title={file.alt}>{file.alt}</p>
77
192
  {/if}
@@ -104,11 +219,11 @@
104
219
  </Dialog.Root>
105
220
  {/if}
106
221
 
107
- <!-- Alt text edit dialog -->
222
+ <!-- Alt / description edit dialog (copy per file type) -->
108
223
  <Dialog.Root bind:open={altDialogOpen}>
109
224
  <Dialog.Content class="max-w-lg">
110
225
  <Dialog.Header>
111
- <Dialog.Title>Edytuj tekst alternatywny</Dialog.Title>
226
+ <Dialog.Title>{copy.title}</Dialog.Title>
112
227
  </Dialog.Header>
113
228
  <div class="space-y-4 py-4">
114
229
  {#if file.type === 'image'}
@@ -121,28 +236,26 @@
121
236
  </div>
122
237
  {/if}
123
238
  <div class="space-y-2">
124
- <Label for="alt-text">Tekst alternatywny</Label>
239
+ <Label for="alt-text">{copy.label}</Label>
125
240
  <Textarea
126
241
  id="alt-text"
127
242
  bind:value={altValue}
128
- placeholder="Opisz zawartość obrazu..."
243
+ placeholder={copy.placeholder}
129
244
  class="min-h-[120px] resize-none"
130
245
  />
131
- <p class="text-xs text-muted-foreground">
132
- Tekst alternatywny opisuje obraz dla osób niewidomych i wyszukiwarek.
133
- </p>
246
+ <p class="text-xs text-muted-foreground">{copy.help}</p>
134
247
  </div>
135
248
  </div>
136
249
  <Dialog.Footer>
137
- <Button variant="outline" onclick={() => altDialogOpen = false}>Anuluj</Button>
250
+ <Button variant="outline" onclick={() => altDialogOpen = false}>{t.cancel}</Button>
138
251
  <Button onclick={() => saveAlt(file)} disabled={saving}>
139
- {saving ? 'Zapisuję...' : 'Zapisz'}
252
+ {saving ? t.saving : t.save}
140
253
  </Button>
141
254
  </Dialog.Footer>
142
255
  </Dialog.Content>
143
256
  </Dialog.Root>
144
257
  {:else if query.ready}
145
- <p class="text-sm text-muted-foreground">Plik nie istnieje.</p>
258
+ <p class="text-sm text-muted-foreground">{ui[interfaceLanguage.current].fileMissing}</p>
146
259
  {/if}
147
260
 
148
261
  <style>
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { getRemotes } from '../../context/remotes.js';
3
3
  import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
4
+ import { errorMessages } from '../../i18n/errors.js';
4
5
  import type { InterfaceLanguage } from '../../../types/languages.js';
5
6
  import { toast } from 'svelte-sonner';
6
7
  import Upload from '@tabler/icons-svelte/icons/upload';
@@ -27,8 +28,8 @@
27
28
  dropHint: 'Przeciągnij pliki tutaj',
28
29
  uploading: 'Wysyłanie...',
29
30
  uploadComplete: 'Ukończono',
30
- fileTooLarge: (maxMB) => `Plik za duży (max ${maxMB} MB)`,
31
- uploadError: 'Błąd przesyłania',
31
+ fileTooLarge: (maxMB) => errorMessages.upload.fileTooLarge(maxMB).pl,
32
+ uploadError: errorMessages.server.uploadFailed.pl,
32
33
  skippedFiles: (count) => `Pominięto ${count} plik(ów) przekraczających limit`
33
34
  },
34
35
  en: {
@@ -37,8 +38,8 @@
37
38
  dropHint: 'Drag files here',
38
39
  uploading: 'Uploading...',
39
40
  uploadComplete: 'Complete',
40
- fileTooLarge: (maxMB) => `File too large (max ${maxMB} MB)`,
41
- uploadError: 'Upload error',
41
+ fileTooLarge: (maxMB) => errorMessages.upload.fileTooLarge(maxMB).en,
42
+ uploadError: errorMessages.server.uploadFailed.en,
42
43
  skippedFiles: (count) => `Skipped ${count} file(s) exceeding the limit`
43
44
  }
44
45
  };
@@ -48,21 +49,27 @@
48
49
  onUpload?: () => void;
49
50
  dropZoneRef?: HTMLElement | null;
50
51
  tagIds?: string[];
52
+ maxSizeMB?: number;
51
53
  };
52
54
 
53
- let { accept, onUpload, dropZoneRef = $bindable(null), tagIds }: Props =
55
+ let { accept, onUpload, dropZoneRef = $bindable(null), tagIds, maxSizeMB }: Props =
54
56
  $props();
55
57
 
56
58
  let inputElement: HTMLInputElement;
57
59
  let isDragging = $state(false);
58
60
  let uploadProgress = $state<{ name: string; progress: number; complete: boolean; error?: string }[]>([]);
59
- let maxUploadSize = $state<number>(50 * 1024 * 1024);
61
+ let serverMaxUploadSize = $state<number>(50 * 1024 * 1024);
62
+ const maxUploadSize = $derived(
63
+ maxSizeMB !== undefined
64
+ ? Math.min(serverMaxUploadSize, maxSizeMB * 1024 * 1024)
65
+ : serverMaxUploadSize
66
+ );
60
67
 
61
68
  $effect(() => {
62
69
  fetch('/admin/api/upload-limit')
63
70
  .then((r) => r.json())
64
71
  .then((data) => {
65
- if (data.maxUploadSize) maxUploadSize = data.maxUploadSize;
72
+ if (data.maxUploadSize) serverMaxUploadSize = data.maxUploadSize;
66
73
  })
67
74
  .catch(() => {});
68
75
  });
@@ -231,6 +238,8 @@
231
238
  {accept}
232
239
  onchange={handleUpload}
233
240
  data-testid="file-input"
241
+ aria-label={lang[interfaceLanguage.current].addFiles}
242
+ tabindex="-1"
234
243
  />
235
244
 
236
245
  <!-- Drag overlay -->
@@ -3,6 +3,7 @@ type Props = {
3
3
  onUpload?: () => void;
4
4
  dropZoneRef?: HTMLElement | null;
5
5
  tagIds?: string[];
6
+ maxSizeMB?: number;
6
7
  };
7
8
  declare const FileUpload: import("svelte").Component<Props, {}, "dropZoneRef">;
8
9
  type FileUpload = ReturnType<typeof FileUpload>;
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { getMediaSort } from '../../state/media-sort.svelte.js';
3
- import type { MediaFile } from '../../../types/media.js';
3
+ import type { MediaFile, MediaFileType } from '../../../types/media.js';
4
4
  import FileMiniature from './file/file-miniature.svelte';
5
5
  import { flip } from 'svelte/animate';
6
6
  import Check from '@tabler/icons-svelte/icons/check';
@@ -11,11 +11,43 @@
11
11
  import File from '@tabler/icons-svelte/icons/file';
12
12
  import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
13
13
  import type { InterfaceLanguage } from '../../../types/languages.js';
14
+ import { formatFileSize, getFileExtension } from '../../utils/fileDisplay.js';
15
+ import { formatRelativeDate } from '../../utils/formatters.js';
14
16
 
15
17
  const interfaceLanguage = useInterfaceLanguage();
16
- const filesLang: Record<InterfaceLanguage, { noFiles: string; uploadOrFilter: string; tags: string }> = {
17
- pl: { noFiles: 'Brak plików', uploadOrFilter: 'Prześlij pliki lub zmień filtry', tags: 'Tagi' },
18
- en: { noFiles: 'No files', uploadOrFilter: 'Upload files or change filters', tags: 'Tags' }
18
+ const filesLang: Record<
19
+ InterfaceLanguage,
20
+ {
21
+ noFiles: string;
22
+ uploadOrFilter: string;
23
+ tags: string;
24
+ typeImage: string;
25
+ typeVideo: string;
26
+ typeAudio: string;
27
+ typePdf: string;
28
+ typeOther: string;
29
+ }
30
+ > = {
31
+ pl: {
32
+ noFiles: 'Brak plików',
33
+ uploadOrFilter: 'Prześlij pliki lub zmień filtry',
34
+ tags: 'Tagi',
35
+ typeImage: 'Obraz',
36
+ typeVideo: 'Wideo',
37
+ typeAudio: 'Audio',
38
+ typePdf: 'PDF',
39
+ typeOther: 'Inne'
40
+ },
41
+ en: {
42
+ noFiles: 'No files',
43
+ uploadOrFilter: 'Upload files or change filters',
44
+ tags: 'Tags',
45
+ typeImage: 'Image',
46
+ typeVideo: 'Video',
47
+ typeAudio: 'Audio',
48
+ typePdf: 'PDF',
49
+ typeOther: 'Other'
50
+ }
19
51
  };
20
52
  const ft = $derived(filesLang[interfaceLanguage.current]);
21
53
 
@@ -25,9 +57,17 @@
25
57
  onSelect: (file: MediaFile, event?: MouseEvent) => void;
26
58
  onRangeSelect?: (fileIds: string[]) => void;
27
59
  selectionMode?: boolean;
60
+ viewMode?: 'grid' | 'list';
28
61
  };
29
62
 
30
- let { files, onSelect, selected, selectionMode = false, onRangeSelect }: Props = $props();
63
+ let {
64
+ files,
65
+ onSelect,
66
+ selected,
67
+ selectionMode = false,
68
+ onRangeSelect,
69
+ viewMode = 'grid'
70
+ }: Props = $props();
31
71
 
32
72
  let lastClickedIndex = $state<number>(-1);
33
73
 
@@ -55,15 +95,6 @@
55
95
  }
56
96
  });
57
97
 
58
- function formatFileSize(bytes: number): string {
59
- if (!bytes) return '';
60
- const units = ['B', 'KB', 'MB', 'GB'];
61
- const k = 1024;
62
- const i = Math.floor(Math.log(bytes) / Math.log(k));
63
- const size = bytes / Math.pow(k, i);
64
- return `${size.toFixed(i > 0 ? 1 : 0)} ${units[i]}`;
65
- }
66
-
67
98
  function getTypeIcon(type: string) {
68
99
  switch (type) {
69
100
  case 'image': return Photo;
@@ -74,6 +105,16 @@
74
105
  }
75
106
  }
76
107
 
108
+ function getTypeLabel(type: MediaFileType): string {
109
+ switch (type) {
110
+ case 'image': return ft.typeImage;
111
+ case 'video': return ft.typeVideo;
112
+ case 'audio': return ft.typeAudio;
113
+ case 'pdf': return ft.typePdf;
114
+ default: return ft.typeOther;
115
+ }
116
+ }
117
+
77
118
  function handleClick(file: MediaFile, event: MouseEvent, index: number) {
78
119
  if (selectionMode && event.shiftKey && lastClickedIndex >= 0 && onRangeSelect) {
79
120
  const start = Math.min(lastClickedIndex, index);
@@ -110,64 +151,123 @@
110
151
  {#each sortedFiles as file, i (file.id)}
111
152
  {@const sel = isSelected(file.id)}
112
153
  {@const TypeIcon = getTypeIcon(file.type)}
154
+ {@const ext = getFileExtension(file.url)}
113
155
  <div
114
156
  animate:flip={{ duration: 300 }}
115
- class="file-card ml-fade-up cursor-pointer overflow-hidden rounded-xl border bg-card transition-all outline-none select-none
116
- {sel ? 'border-primary ring-2 ring-primary' : 'border-border hover:border-lavender hover:shadow-md'}
117
- "
157
+ class={viewMode === 'list'
158
+ ? `ml-fade-up flex cursor-pointer items-center gap-3 rounded-lg border bg-card px-3 py-2 transition-all outline-none select-none ${sel ? 'border-primary ring-2 ring-primary' : 'border-border hover:border-lavender hover:shadow-sm'}`
159
+ : `file-card ml-fade-up cursor-pointer overflow-hidden rounded-xl border bg-card transition-all outline-none select-none ${sel ? 'border-primary ring-2 ring-primary' : 'border-border hover:border-lavender hover:shadow-md'}`}
118
160
  role="option"
119
161
  aria-selected={sel}
120
162
  tabindex="0"
121
163
  onclick={(e) => handleClick(file, e, i)}
122
164
  onkeydown={(e) => handleKeydown(e, file, i)}
123
165
  >
124
- <!-- Thumb area -->
125
- <div class="relative h-[120px] overflow-hidden ml-checkered-bg">
126
- <FileMiniature {file} mode="thumb" />
127
-
128
- <!-- Type badge (frosted glass, top-left) -->
129
- <div class="absolute top-1.5 left-1.5 z-10 inline-flex items-center gap-1 rounded-full bg-white/90 backdrop-blur-sm px-1.5 py-0.5 text-[10px] font-semibold text-muted-foreground shadow-sm">
130
- <TypeIcon class="h-3 w-3" />
131
- <span class="sr-only">{file.type}</span>
166
+ {#if viewMode === 'list'}
167
+ <!-- Thumb 40×40 (relative for ml-file-thumb absolute children) -->
168
+ <div class="relative h-10 w-10 shrink-0 overflow-hidden rounded ml-checkered-bg">
169
+ <FileMiniature {file} mode="thumb" />
132
170
  </div>
133
171
 
134
- <!-- Selection indicator (top-right) -->
172
+ <!-- Name + type/ext -->
173
+ <div class="min-w-0 flex-1">
174
+ <div class="flex items-center gap-1.5">
175
+ <span class="truncate text-sm font-semibold text-foreground">{file.name}</span>
176
+ {#if ext}
177
+ <span class="shrink-0 rounded bg-muted px-1 text-[10px] font-semibold text-muted-foreground">{ext}</span>
178
+ {/if}
179
+ </div>
180
+ <div class="flex items-center gap-1.5 text-[11px] text-text-light">
181
+ <TypeIcon class="h-3 w-3" />
182
+ <span>{getTypeLabel(file.type)}</span>
183
+ {#if file.width && file.height}
184
+ <span aria-hidden="true">·</span>
185
+ <span>{file.width}×{file.height}</span>
186
+ {/if}
187
+ </div>
188
+ </div>
189
+
190
+ <!-- Size -->
191
+ {#if file.size}
192
+ <span class="shrink-0 text-[11px] font-medium text-text-light tabular-nums">{formatFileSize(file.size)}</span>
193
+ {/if}
194
+
195
+ <!-- Date -->
196
+ <span class="shrink-0 text-[11px] text-text-light">{formatRelativeDate(file.createdAt, interfaceLanguage.current)}</span>
197
+
198
+ <!-- Tags -->
199
+ {#if file.tags && file.tags.length > 0}
200
+ <span class="flex shrink-0 items-center gap-0.5" role="list" aria-label={ft.tags}>
201
+ {#each file.tags as tag (tag.id)}
202
+ <span
203
+ class="h-2 w-2 rounded-full"
204
+ style="background-color: {tag.color}"
205
+ role="listitem"
206
+ aria-label={tag.name}
207
+ ></span>
208
+ {/each}
209
+ </span>
210
+ {/if}
211
+
212
+ <!-- Selection indicator -->
135
213
  {#if selectionMode}
136
- <div class="absolute top-1.5 right-1.5 z-10 flex h-[22px] w-[22px] items-center justify-center rounded-md border-2 transition-colors
137
- {sel ? 'border-primary bg-primary' : 'border-white/80 bg-white/50 backdrop-blur-sm'}
214
+ <div class="flex h-[22px] w-[22px] shrink-0 items-center justify-center rounded-md border-2 transition-colors
215
+ {sel ? 'border-primary bg-primary' : 'border-border bg-card'}
138
216
  ">
139
217
  {#if sel}
140
218
  <Check class="h-3.5 w-3.5 text-primary-foreground" />
141
219
  {/if}
142
220
  </div>
143
- {:else}
144
- <div class="ml-file-check {sel ? 'visible' : ''}">
145
- <Check class="h-3 w-3 text-primary-foreground" />
146
- </div>
147
221
  {/if}
148
- </div>
149
-
150
- <!-- File info -->
151
- <div class="px-2.5 py-2">
152
- <div class="truncate text-xs font-semibold leading-snug text-foreground">{file.name}</div>
153
- <div class="flex items-center gap-1">
154
- {#if file.size}
155
- <span class="text-[11px] font-medium text-text-light">{formatFileSize(file.size)}</span>
156
- {/if}
157
- {#if file.tags && file.tags.length > 0}
158
- <span class="flex items-center gap-0.5 ml-auto" role="list" aria-label={ft.tags}>
159
- {#each file.tags as tag (tag.id)}
160
- <span
161
- class="h-2 w-2 rounded-full"
162
- style="background-color: {tag.color}"
163
- role="listitem"
164
- aria-label={tag.name}
165
- ></span>
166
- {/each}
167
- </span>
222
+ {:else}
223
+ <!-- Thumb area -->
224
+ <div class="relative h-[120px] overflow-hidden ml-checkered-bg">
225
+ <FileMiniature {file} mode="thumb" />
226
+
227
+ <!-- Type badge (frosted glass, top-left) -->
228
+ <div class="absolute top-1.5 left-1.5 z-10 inline-flex items-center gap-1 rounded-full bg-white/90 backdrop-blur-sm px-1.5 py-0.5 text-[10px] font-semibold text-muted-foreground shadow-sm">
229
+ <TypeIcon class="h-3 w-3" />
230
+ <span class="sr-only">{file.type}</span>
231
+ </div>
232
+
233
+ <!-- Selection indicator (top-right) -->
234
+ {#if selectionMode}
235
+ <div class="absolute top-1.5 right-1.5 z-10 flex h-[22px] w-[22px] items-center justify-center rounded-md border-2 transition-colors
236
+ {sel ? 'border-primary bg-primary' : 'border-white/80 bg-white/50 backdrop-blur-sm'}
237
+ ">
238
+ {#if sel}
239
+ <Check class="h-3.5 w-3.5 text-primary-foreground" />
240
+ {/if}
241
+ </div>
242
+ {:else}
243
+ <div class="ml-file-check {sel ? 'visible' : ''}">
244
+ <Check class="h-3 w-3 text-primary-foreground" />
245
+ </div>
168
246
  {/if}
169
247
  </div>
170
- </div>
248
+
249
+ <!-- File info -->
250
+ <div class="px-2.5 py-2">
251
+ <div class="truncate text-xs font-semibold leading-snug text-foreground">{file.name}</div>
252
+ <div class="flex items-center gap-1">
253
+ {#if file.size}
254
+ <span class="text-[11px] font-medium text-text-light">{formatFileSize(file.size)}</span>
255
+ {/if}
256
+ {#if file.tags && file.tags.length > 0}
257
+ <span class="flex items-center gap-0.5 ml-auto" role="list" aria-label={ft.tags}>
258
+ {#each file.tags as tag (tag.id)}
259
+ <span
260
+ class="h-2 w-2 rounded-full"
261
+ style="background-color: {tag.color}"
262
+ role="listitem"
263
+ aria-label={tag.name}
264
+ ></span>
265
+ {/each}
266
+ </span>
267
+ {/if}
268
+ </div>
269
+ </div>
270
+ {/if}
171
271
  </div>
172
272
  {/each}
173
273
  {/if}
@@ -5,6 +5,7 @@ type Props = {
5
5
  onSelect: (file: MediaFile, event?: MouseEvent) => void;
6
6
  onRangeSelect?: (fileIds: string[]) => void;
7
7
  selectionMode?: boolean;
8
+ viewMode?: 'grid' | 'list';
8
9
  };
9
10
  declare const FilesList: import("svelte").Component<Props, {}, "">;
10
11
  type FilesList = ReturnType<typeof FilesList>;