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.
- package/API.md +97 -4
- package/CHANGELOG.md +118 -0
- package/DOCS.md +1 -1
- package/README.md +2 -0
- package/ROADMAP.md +14 -0
- package/dist/admin/auth-client.d.ts +42 -42
- package/dist/admin/client/account/lang.d.ts +1 -0
- package/dist/admin/client/account/lang.js +4 -2
- package/dist/admin/client/account/profile-section.svelte +2 -2
- package/dist/admin/client/account/security-section.svelte +27 -4
- package/dist/admin/client/account/sessions-section.svelte +1 -1
- package/dist/admin/client/admin/admin-after-login-layout-content.svelte +1 -1
- package/dist/admin/client/admin/admin-layout.svelte +12 -2
- package/dist/admin/client/admin/admin-layout.svelte.d.ts +2 -1
- package/dist/admin/client/admin/dashboard-page.svelte +34 -10
- package/dist/admin/client/collection/bulk-actions-bar.svelte +86 -44
- package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +3 -1
- package/dist/admin/client/collection/collection-entries.svelte +52 -36
- package/dist/admin/client/collection/collection-entries.svelte.d.ts +3 -0
- package/dist/admin/client/collection/collection.svelte +28 -14
- package/dist/admin/client/collection/collection.svelte.d.ts +3 -0
- package/dist/admin/client/collection/data-table.svelte +240 -130
- package/dist/admin/client/collection/data-table.svelte.d.ts +9 -0
- package/dist/admin/client/collection/date-cell.svelte +4 -4
- package/dist/admin/client/collection/row-actions.svelte +2 -1
- package/dist/admin/client/collection/sortable-header.svelte +33 -9
- package/dist/admin/client/collection/state-display.svelte +102 -0
- package/dist/admin/client/collection/state-display.svelte.d.ts +12 -0
- package/dist/admin/client/collection/status-badge.svelte +99 -11
- package/dist/admin/client/collection/status-badge.svelte.d.ts +15 -1
- package/dist/admin/client/collection/table-pagination.svelte +21 -6
- package/dist/admin/client/collection/table-toolbar.svelte +105 -80
- package/dist/admin/client/collection/table-toolbar.svelte.d.ts +11 -8
- package/dist/admin/client/entry/entry-form.svelte +36 -11
- package/dist/admin/client/entry/entry-form.svelte.d.ts +1 -0
- package/dist/admin/client/entry/entry-header.svelte +22 -15
- package/dist/admin/client/entry/entry-header.svelte.d.ts +1 -0
- package/dist/admin/client/entry/entry.svelte +269 -165
- package/dist/admin/client/entry/header/a11y-header-badge.svelte +47 -0
- package/dist/admin/client/entry/header/a11y-header-badge.svelte.d.ts +8 -0
- package/dist/admin/client/entry/header/publish-panel.svelte +69 -13
- package/dist/admin/client/entry/header/save-indicator.svelte +57 -28
- package/dist/admin/client/entry/header/save-indicator.svelte.d.ts +1 -0
- package/dist/admin/client/entry/header/status-badge.svelte +60 -15
- package/dist/admin/client/entry/header/status-badge.svelte.d.ts +1 -2
- package/dist/admin/client/entry/header/version-history-sheet.svelte +1 -1
- package/dist/admin/client/entry/hybrid/hybrid-layout.svelte +74 -23
- package/dist/admin/client/entry/hybrid/hybrid-preview.svelte +1 -1
- package/dist/admin/client/entry/utils.d.ts +14 -0
- package/dist/admin/client/entry/utils.js +28 -0
- package/dist/admin/client/form/form-submission/form-submission.svelte +2 -2
- package/dist/admin/client/form/form-submissions.svelte +143 -194
- package/dist/admin/client/form/form-submissions.svelte.d.ts +2 -0
- package/dist/admin/client/login/lang.d.ts +3 -0
- package/dist/admin/client/login/lang.js +10 -4
- package/dist/admin/client/login/login-form.svelte +8 -1
- package/dist/admin/client/login/reset-password-page.svelte +24 -3
- package/dist/admin/client/login/schema.d.ts +14 -2
- package/dist/admin/client/login/schema.js +19 -8
- package/dist/admin/client/maintenance/maintenance-page.svelte +16 -17
- package/dist/admin/client/media/media-page.svelte +1 -1
- package/dist/admin/client/shop/coupon-edit-page.svelte +117 -13
- package/dist/admin/client/shop/coupon-form.svelte +282 -138
- package/dist/admin/client/shop/coupon-form.svelte.d.ts +1 -9
- package/dist/admin/client/shop/coupon-new-page.svelte +40 -10
- package/dist/admin/client/shop/coupon-new-page.svelte.d.ts +2 -17
- package/dist/admin/client/shop/coupon-schema.d.ts +28 -0
- package/dist/admin/client/shop/coupon-schema.js +53 -0
- package/dist/admin/client/shop/coupons-list-page.svelte +262 -118
- package/dist/admin/client/shop/coupons-list-page.svelte.d.ts +16 -1
- package/dist/admin/client/shop/refund-dialog.svelte +37 -1
- package/dist/admin/client/shop/refund-dialog.svelte.d.ts +3 -0
- package/dist/admin/client/shop/shipping-method-edit-page.svelte +108 -59
- package/dist/admin/client/shop/shipping-method-form.svelte +36 -9
- package/dist/admin/client/shop/shipping-method-new-page.svelte +44 -13
- package/dist/admin/client/shop/shipping-methods-list-page.svelte +101 -59
- package/dist/admin/client/shop/shop-order-detail-page.svelte +220 -84
- package/dist/admin/client/shop/shop-orders-list-page.svelte +302 -152
- package/dist/admin/client/shop/shop-orders-list-page.svelte.d.ts +18 -1
- package/dist/admin/client/shop/shop-products-list-page.svelte +355 -118
- package/dist/admin/client/shop/shop-products-list-page.svelte.d.ts +19 -1
- package/dist/admin/client/users/accept-invite-page.svelte +24 -3
- package/dist/admin/client/users/create-user-dialog.svelte +3 -8
- package/dist/admin/client/users/lang.d.ts +2 -0
- package/dist/admin/client/users/lang.js +4 -0
- package/dist/admin/client/users/pending-invitations.svelte +2 -9
- package/dist/admin/client/users/user-name-cell.svelte +20 -0
- package/dist/admin/client/users/user-name-cell.svelte.d.ts +9 -0
- package/dist/admin/client/users/user-role-badge.svelte +16 -0
- package/dist/admin/client/users/user-role-badge.svelte.d.ts +7 -0
- package/dist/admin/client/users/user-row-actions.svelte +72 -0
- package/dist/admin/client/users/user-row-actions.svelte.d.ts +20 -0
- package/dist/admin/client/users/user-sessions-sheet.svelte +2 -11
- package/dist/admin/client/users/users-page.svelte +283 -497
- package/dist/admin/client/users/users-page.svelte.d.ts +12 -1
- package/dist/admin/components/dashboard/form-submissions-widget.svelte +59 -74
- package/dist/admin/components/dashboard/recent-activity.svelte +17 -5
- package/dist/admin/components/dashboard/recent-entries.svelte +19 -7
- package/dist/admin/components/dialogs/confirmation-dialog.svelte +105 -0
- package/dist/admin/components/dialogs/confirmation-dialog.svelte.d.ts +13 -0
- package/dist/admin/components/fields/block-picker-modal.svelte +6 -0
- package/dist/admin/components/fields/blocks-field.svelte +46 -1
- package/dist/admin/components/fields/boolean-field.svelte +1 -1
- package/dist/admin/components/fields/field-renderer.svelte +29 -22
- package/dist/admin/components/fields/file-field.svelte +344 -30
- package/dist/admin/components/fields/icon-field.svelte +86 -0
- package/dist/admin/components/fields/icon-field.svelte.d.ts +8 -0
- package/dist/admin/components/fields/icon-picker-dialog.svelte +174 -0
- package/dist/admin/components/fields/icon-picker-dialog.svelte.d.ts +11 -0
- package/dist/admin/components/fields/media-field.svelte +16 -2
- package/dist/admin/components/fields/object-field.svelte +27 -7
- package/dist/admin/components/fields/radio-field.svelte +22 -0
- package/dist/admin/components/fields/relation-field.svelte +123 -97
- package/dist/admin/components/fields/relation-picker-dialog.svelte +2 -2
- package/dist/admin/components/fields/seo-field.svelte +60 -30
- package/dist/admin/components/fields/shop-field.svelte +219 -24
- package/dist/admin/components/fields/simple-array-field.svelte +321 -151
- package/dist/admin/components/fields/simple-array-field.svelte.d.ts +3 -0
- package/dist/admin/components/fields/slug-field.svelte +146 -21
- package/dist/admin/components/fields/text-field-wrapper.svelte +37 -20
- package/dist/admin/components/fields/text-field.svelte +7 -2
- package/dist/admin/components/fields/url-field-wrapper.svelte +10 -0
- package/dist/admin/components/fields/url-field.svelte +36 -23
- package/dist/admin/components/forms/form-error-summary.svelte +143 -0
- package/dist/admin/components/forms/form-error-summary.svelte.d.ts +27 -0
- package/dist/admin/components/layout/app-sidebar.svelte +7 -2
- package/dist/admin/components/layout/detail-page-shell.svelte +71 -0
- package/dist/admin/components/layout/detail-page-shell.svelte.d.ts +24 -0
- package/dist/admin/components/layout/lang.d.ts +5 -0
- package/dist/admin/components/layout/lang.js +10 -0
- package/dist/admin/components/layout/layout-renderer.svelte +71 -2
- package/dist/admin/components/layout/layout-renderer.svelte.d.ts +1 -0
- package/dist/admin/components/layout/layout-tabs.svelte +173 -0
- package/dist/admin/components/layout/layout-tabs.svelte.d.ts +24 -0
- package/dist/admin/components/layout/nav-breadcrumbs.svelte +25 -7
- package/dist/admin/components/layout/nav-collections.svelte +23 -36
- package/dist/admin/components/layout/nav-forms.svelte +19 -35
- package/dist/admin/components/layout/nav-main.svelte +3 -28
- package/dist/admin/components/layout/nav-search.svelte +70 -2
- package/dist/admin/components/layout/nav-section.svelte +77 -0
- package/dist/admin/components/layout/nav-section.svelte.d.ts +22 -0
- package/dist/admin/components/layout/nav-shop.svelte +3 -27
- package/dist/admin/components/layout/nav-singletons.svelte +16 -28
- package/dist/admin/components/layout/page-header.stories.svelte +93 -0
- package/dist/admin/components/layout/page-header.stories.svelte.d.ts +27 -0
- package/dist/admin/components/layout/page-header.svelte +68 -0
- package/dist/admin/components/layout/page-header.svelte.d.ts +17 -0
- package/dist/admin/components/layout/site-header.svelte +9 -0
- package/dist/admin/components/layout/site-header.svelte.d.ts +2 -17
- package/dist/admin/components/media/file/file-name-input.svelte +6 -2
- package/dist/admin/components/media/file/file-preview.svelte +130 -17
- package/dist/admin/components/media/file-upload.svelte +16 -7
- package/dist/admin/components/media/file-upload.svelte.d.ts +1 -0
- package/dist/admin/components/media/files-list.svelte +153 -53
- package/dist/admin/components/media/files-list.svelte.d.ts +1 -0
- package/dist/admin/components/media/media-library.svelte +577 -198
- package/dist/admin/components/media/media-library.svelte.d.ts +4 -0
- package/dist/admin/components/media/media-selector.svelte +4 -2
- package/dist/admin/components/media/media-selector.svelte.d.ts +1 -0
- package/dist/admin/components/media/tag-sidebar.svelte +4 -4
- package/dist/admin/components/tiptap/FigureNodeView.svelte +10 -0
- package/dist/admin/components/tiptap/bubble-menu.svelte +104 -0
- package/dist/admin/components/tiptap/bubble-menu.svelte.d.ts +19 -0
- package/dist/admin/components/tiptap/content-editor.svelte +28 -24
- package/dist/admin/components/tiptap/editor-toolbar.svelte +7 -7
- package/dist/admin/components/tiptap/extensions.js +5 -1
- package/dist/admin/components/tiptap/image-dialog.svelte +5 -1
- package/dist/admin/components/tiptap/link-dialog.svelte +2 -0
- package/dist/admin/components/tiptap/tiptap-editor.svelte +18 -20
- package/dist/admin/components/tiptap/video-dialog.svelte +1 -1
- package/dist/admin/components/variant-form/VariantAttributeRenderer.svelte +109 -0
- package/dist/admin/components/variant-form/VariantAttributeRenderer.svelte.d.ts +9 -0
- package/dist/admin/helpers/build-icon-set-map.d.ts +8 -0
- package/dist/admin/helpers/build-icon-set-map.js +16 -0
- package/dist/admin/helpers/index.d.ts +2 -0
- package/dist/admin/helpers/index.js +2 -0
- package/dist/admin/i18n/errors.d.ts +140 -0
- package/dist/admin/i18n/errors.js +151 -0
- package/dist/admin/remote/entry.remote.d.ts +59 -4
- package/dist/admin/remote/entry.remote.js +239 -62
- package/dist/admin/remote/shop.remote.d.ts +87 -48
- package/dist/admin/remote/shop.remote.js +70 -8
- package/dist/admin/shared/password-generate.d.ts +6 -0
- package/dist/admin/shared/password-generate.js +40 -0
- package/dist/admin/shared/password-schema.d.ts +6 -0
- package/dist/admin/shared/password-schema.js +10 -3
- package/dist/admin/state/icon-sets.svelte.d.ts +9 -0
- package/dist/admin/state/icon-sets.svelte.js +20 -0
- package/dist/admin/styles/admin.css +23 -6
- package/dist/admin/styles/tokens.md +244 -0
- package/dist/admin/utils/accordionActivation.d.ts +13 -0
- package/dist/admin/utils/accordionActivation.js +35 -0
- package/dist/admin/utils/entryLabel.d.ts +23 -0
- package/dist/admin/utils/entryLabel.js +51 -12
- package/dist/admin/utils/field-a11y.d.ts +29 -0
- package/dist/admin/utils/field-a11y.js +23 -0
- package/dist/admin/utils/fieldPathElement.d.ts +9 -0
- package/dist/admin/utils/fieldPathElement.js +18 -0
- package/dist/admin/utils/fileDisplay.d.ts +10 -0
- package/dist/admin/utils/fileDisplay.js +26 -0
- package/dist/admin/utils/flattenFormErrors.d.ts +19 -0
- package/dist/admin/utils/flattenFormErrors.js +102 -0
- package/dist/admin/utils/formatters.d.ts +12 -0
- package/dist/admin/utils/{formatDate.js → formatters.js} +23 -2
- package/dist/admin/utils/scrollWithin.d.ts +9 -0
- package/dist/admin/utils/scrollWithin.js +32 -0
- package/dist/admin/utils/tabActivation.d.ts +12 -0
- package/dist/admin/utils/tabActivation.js +24 -0
- package/dist/cli/scaffold/admin.js +2 -2
- package/dist/cms/runtime/schema.d.ts +1 -0
- package/dist/cms/runtime/schema.js +1 -0
- package/dist/cms/runtime/types.d.ts +80 -7
- package/dist/components/ui/accordion/accordion-content.svelte +17 -3
- package/dist/components/ui/accordion/accordion.stories.svelte +21 -1
- package/dist/components/ui/alert/alert.stories.svelte +14 -0
- package/dist/components/ui/alert-dialog/alert-dialog.stories.svelte +45 -0
- package/dist/components/ui/alert-dialog/alert-dialog.stories.svelte.d.ts +27 -0
- package/dist/components/ui/avatar/avatar.stories.svelte +27 -0
- package/dist/components/ui/badge/badge.stories.svelte +15 -0
- package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte +47 -0
- package/dist/components/ui/breadcrumb/breadcrumb.svelte +1 -1
- package/dist/components/ui/button/button.stories.svelte +53 -6
- package/dist/components/ui/button/button.svelte +39 -5
- package/dist/components/ui/button/button.svelte.d.ts +4 -0
- package/dist/components/ui/button-group/button-group.stories.svelte +44 -0
- package/dist/components/ui/button-group/button-group.stories.svelte.d.ts +27 -0
- package/dist/components/ui/calendar/calendar.stories.svelte +36 -0
- package/dist/components/ui/calendar/calendar.stories.svelte.d.ts +27 -0
- package/dist/components/ui/card/card.stories.svelte +7 -0
- package/dist/components/ui/carousel/carousel.stories.svelte +43 -0
- package/dist/components/ui/carousel/carousel.stories.svelte.d.ts +27 -0
- package/dist/components/ui/checkbox/checkbox.stories.svelte +67 -0
- package/dist/components/ui/checkbox/checkbox.stories.svelte.d.ts +27 -0
- package/dist/components/ui/checkbox/checkbox.svelte +1 -1
- package/dist/components/ui/command/command.stories.svelte +18 -0
- package/dist/components/ui/data-table/data-table.stories.svelte +61 -0
- package/dist/components/ui/data-table/data-table.stories.svelte.d.ts +18 -0
- package/dist/components/ui/dialog/dialog-content.svelte +5 -0
- package/dist/components/ui/dialog/dialog-content.svelte.d.ts +2 -0
- package/dist/components/ui/dialog/dialog.stories.svelte +35 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu.stories.svelte +74 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu.stories.svelte.d.ts +27 -0
- package/dist/components/ui/field/field-context.svelte.d.ts +22 -0
- package/dist/components/ui/field/field-context.svelte.js +9 -0
- package/dist/components/ui/field/field-control.svelte +18 -0
- package/dist/components/ui/field/field-control.svelte.d.ts +8 -0
- package/dist/components/ui/field/field-description.svelte +12 -0
- package/dist/components/ui/field/field-error.svelte +14 -6
- package/dist/components/ui/field/field-label.svelte +10 -0
- package/dist/components/ui/field/field.stories.svelte +95 -9
- package/dist/components/ui/field/field.svelte +57 -0
- package/dist/components/ui/field/field.svelte.d.ts +2 -0
- package/dist/components/ui/field/index.d.ts +3 -1
- package/dist/components/ui/field/index.js +4 -2
- package/dist/components/ui/form/form-field-errors.svelte +1 -1
- package/dist/components/ui/form/form.stories.svelte +25 -0
- package/dist/components/ui/form/form.stories.svelte.d.ts +26 -0
- package/dist/components/ui/input/input.stories.svelte +26 -0
- package/dist/components/ui/input-group/input-group-input.svelte.d.ts +1 -1
- package/dist/components/ui/input-group/input-group.stories.svelte +43 -0
- package/dist/components/ui/input-group/input-group.stories.svelte.d.ts +27 -0
- package/dist/components/ui/item/item.stories.svelte +61 -0
- package/dist/components/ui/item/item.stories.svelte.d.ts +27 -0
- package/dist/components/ui/label/label.stories.svelte +7 -0
- package/dist/components/ui/live-region/index.d.ts +1 -0
- package/dist/components/ui/live-region/index.js +1 -0
- package/dist/components/ui/live-region/live-region-demo.svelte +32 -0
- package/dist/components/ui/live-region/live-region-demo.svelte.d.ts +7 -0
- package/dist/components/ui/live-region/live-region.stories.svelte +23 -0
- package/dist/components/ui/live-region/live-region.stories.svelte.d.ts +26 -0
- package/dist/components/ui/live-region/live-region.svelte +12 -0
- package/dist/components/ui/live-region/live-region.svelte.d.ts +8 -0
- package/dist/components/ui/popover/popover.stories.svelte +34 -0
- package/dist/components/ui/radio-group/radio-group.stories.svelte +58 -0
- package/dist/components/ui/radio-group/radio-group.stories.svelte.d.ts +27 -0
- package/dist/components/ui/resizable/resizable.stories.svelte +56 -0
- package/dist/components/ui/resizable/resizable.stories.svelte.d.ts +27 -0
- package/dist/components/ui/select/select.stories.svelte +49 -0
- package/dist/components/ui/separator/separator.stories.svelte +18 -0
- package/dist/components/ui/sheet/sheet.stories.svelte +34 -0
- package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +1 -1
- package/dist/components/ui/sidebar/sidebar-menu-button.svelte +1 -0
- package/dist/components/ui/sidebar/sidebar-trigger.svelte +1 -1
- package/dist/components/ui/sidebar/sidebar.stories.svelte +72 -0
- package/dist/components/ui/sidebar/sidebar.stories.svelte.d.ts +27 -0
- package/dist/components/ui/skeleton/skeleton.stories.svelte +39 -0
- package/dist/components/ui/skeleton/skeleton.stories.svelte.d.ts +27 -0
- package/dist/components/ui/skeleton/skeleton.svelte +6 -0
- package/dist/components/ui/sonner/index.d.ts +1 -1
- package/dist/components/ui/sonner/index.js +1 -1
- package/dist/components/ui/sonner/sonner.stories.svelte +7 -0
- package/dist/components/ui/sonner/sonner.svelte +17 -1
- package/dist/components/ui/sonner/sonner.svelte.d.ts +6 -0
- package/dist/components/ui/spinner/spinner.stories.svelte +30 -0
- package/dist/components/ui/spinner/spinner.stories.svelte.d.ts +27 -0
- package/dist/components/ui/switch/switch.stories.svelte +56 -0
- package/dist/components/ui/switch/switch.stories.svelte.d.ts +27 -0
- package/dist/components/ui/table/table-cell.svelte +1 -1
- package/dist/components/ui/table/table-head.svelte +1 -1
- package/dist/components/ui/table/table.stories.svelte +68 -0
- package/dist/components/ui/table/table.stories.svelte.d.ts +27 -0
- package/dist/components/ui/table/table.svelte +1 -1
- package/dist/components/ui/tabs/tabs.stories.svelte +48 -0
- package/dist/components/ui/tabs/tabs.stories.svelte.d.ts +27 -0
- package/dist/components/ui/textarea/textarea.stories.svelte +21 -0
- package/dist/components/ui/toggle/toggle.stories.svelte +23 -0
- package/dist/components/ui/toggle-group/toggle-group.stories.svelte +43 -0
- package/dist/components/ui/tooltip/tooltip.stories.svelte +46 -6
- package/dist/core/cms.d.ts +11 -2
- package/dist/core/cms.js +29 -0
- package/dist/core/fields/fieldSchemaToTs.d.ts +7 -0
- package/dist/core/fields/fieldSchemaToTs.js +241 -90
- package/dist/core/fields/layoutUtils.d.ts +4 -1
- package/dist/core/fields/layoutUtils.js +41 -4
- package/dist/core/fields/resolveSeo.d.ts +70 -0
- package/dist/core/fields/resolveSeo.js +88 -0
- package/dist/core/fields/seoFieldDescriptor.d.ts +43 -0
- package/dist/core/fields/seoFieldDescriptor.js +74 -0
- package/dist/core/fields/slugPath.d.ts +13 -0
- package/dist/core/fields/slugPath.js +32 -0
- package/dist/core/fields/urlUtils.d.ts +8 -0
- package/dist/core/fields/urlUtils.js +27 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/core/server/entries/operations/create.js +13 -0
- package/dist/core/server/entries/operations/get.d.ts +7 -0
- package/dist/core/server/entries/operations/get.js +10 -6
- package/dist/core/server/entries/operations/slugUniqueness.d.ts +37 -0
- package/dist/core/server/entries/operations/slugUniqueness.js +116 -0
- package/dist/core/server/entries/operations/update.d.ts +6 -1
- package/dist/core/server/entries/operations/update.js +24 -1
- package/dist/core/server/fields/slugResolver.d.ts +3 -13
- package/dist/core/server/fields/slugResolver.js +8 -37
- package/dist/core/server/generator/fields.d.ts +2 -0
- package/dist/core/server/generator/fields.js +44 -18
- package/dist/core/server/generator/formFields.js +2 -1
- package/dist/core/server/generator/generator.js +6 -5
- package/dist/core/server/generator/utils.d.ts +1 -0
- package/dist/core/server/generator/utils.js +4 -0
- package/dist/db-postgres/schema/shop/order.d.ts +37 -1
- package/dist/db-postgres/schema/shop/order.js +3 -1
- package/dist/db-postgres/schema/shop/payment.d.ts +20 -0
- package/dist/db-postgres/schema/shop/payment.js +4 -1
- package/dist/db-postgres/schema/shop/product.d.ts +20 -0
- package/dist/db-postgres/schema/shop/product.js +3 -1
- package/dist/db-postgres/schema/shop/productVariant.d.ts +12 -2
- package/dist/db-postgres/schema/shop/productVariant.js +22 -0
- package/dist/shop/cart/types.d.ts +1 -0
- package/dist/shop/client/index.d.ts +54 -0
- package/dist/shop/client/index.js +5 -1
- package/dist/shop/expiry.d.ts +35 -0
- package/dist/shop/expiry.js +68 -0
- package/dist/shop/http/balance-handler.d.ts +20 -0
- package/dist/shop/http/balance-handler.js +91 -0
- package/dist/shop/http/cart-handler.js +19 -0
- package/dist/shop/http/checkout-handler.js +19 -1
- package/dist/shop/http/index.d.ts +2 -0
- package/dist/shop/http/index.js +2 -0
- package/dist/shop/http/upcoming-handler.d.ts +16 -0
- package/dist/shop/http/upcoming-handler.js +65 -0
- package/dist/shop/http/webhook-handler.js +46 -9
- package/dist/shop/index.d.ts +4 -1
- package/dist/shop/index.js +7 -1
- package/dist/shop/server/balance-payment.d.ts +40 -0
- package/dist/shop/server/balance-payment.js +140 -0
- package/dist/shop/server/cart-hydrate.js +2 -0
- package/dist/shop/server/init.d.ts +14 -0
- package/dist/shop/server/init.js +35 -0
- package/dist/shop/server/orders.d.ts +35 -0
- package/dist/shop/server/orders.js +155 -2
- package/dist/shop/server/payment-policy.d.ts +35 -0
- package/dist/shop/server/payment-policy.js +55 -0
- package/dist/shop/server/payments.d.ts +29 -0
- package/dist/shop/server/payments.js +64 -0
- package/dist/shop/server/populate.d.ts +1 -1
- package/dist/shop/server/refund.d.ts +17 -12
- package/dist/shop/server/refund.js +96 -13
- package/dist/shop/server/shop-data.d.ts +6 -1
- package/dist/shop/server/shop-data.js +44 -7
- package/dist/shop/template.d.ts +13 -0
- package/dist/shop/template.js +98 -0
- package/dist/shop/types.d.ts +142 -1
- package/dist/shop/variant-attributes.d.ts +28 -0
- package/dist/shop/variant-attributes.js +69 -0
- package/dist/sveltekit/server/handle.js +17 -0
- package/dist/sveltekit/server/index.d.ts +1 -0
- package/dist/sveltekit/server/index.js +2 -0
- package/dist/types/cms.d.ts +4 -3
- package/dist/types/cms.schema.d.ts +1 -1
- package/dist/types/cms.schema.js +13 -2
- package/dist/types/fields.d.ts +56 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js +1 -1
- package/dist/types/layout.d.ts +35 -2
- package/dist/types/plugins.d.ts +40 -0
- package/dist/types/plugins.js +4 -1
- package/dist/updates/0.26.0/index.d.ts +2 -0
- package/dist/updates/0.26.0/index.js +51 -0
- package/dist/updates/0.26.1/index.d.ts +2 -0
- package/dist/updates/0.26.1/index.js +19 -0
- package/dist/updates/0.27.0/index.d.ts +2 -0
- package/dist/updates/0.27.0/index.js +50 -0
- package/dist/updates/index.js +7 -1
- package/package.json +29 -7
- package/dist/admin/client/collection/empty-state.svelte +0 -28
- package/dist/admin/client/collection/empty-state.svelte.d.ts +0 -9
- package/dist/admin/client/form/submission-status-badge.svelte +0 -41
- package/dist/admin/client/form/submission-status-badge.svelte.d.ts +0 -7
- package/dist/admin/components/media/file-preview.svelte +0 -51
- package/dist/admin/components/media/file-preview.svelte.d.ts +0 -6
- 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(
|
|
145
|
+
toast.success(t.saved);
|
|
36
146
|
} catch {
|
|
37
|
-
toast.error(
|
|
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
|
-
{
|
|
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
|
|
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>
|
|
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">
|
|
239
|
+
<Label for="alt-text">{copy.label}</Label>
|
|
125
240
|
<Textarea
|
|
126
241
|
id="alt-text"
|
|
127
242
|
bind:value={altValue}
|
|
128
|
-
placeholder=
|
|
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}>
|
|
250
|
+
<Button variant="outline" onclick={() => altDialogOpen = false}>{t.cancel}</Button>
|
|
138
251
|
<Button onclick={() => saveAlt(file)} disabled={saving}>
|
|
139
|
-
{saving ?
|
|
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">
|
|
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) =>
|
|
31
|
-
uploadError:
|
|
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) =>
|
|
41
|
-
uploadError:
|
|
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
|
|
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)
|
|
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 -->
|
|
@@ -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<
|
|
17
|
-
|
|
18
|
-
|
|
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 {
|
|
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=
|
|
116
|
-
{sel ? 'border-primary ring-2 ring-primary' : 'border-border hover:border-lavender hover:shadow-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
<
|
|
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
|
-
|
|
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="
|
|
137
|
-
{sel ? 'border-primary bg-primary' : 'border-
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
{/
|
|
167
|
-
</
|
|
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
|
-
|
|
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>;
|