includio-cms 0.25.0 → 0.26.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 +57 -4
- package/CHANGELOG.md +53 -0
- package/DOCS.md +1 -1
- package/README.md +2 -0
- package/ROADMAP.md +6 -0
- 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/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 +279 -130
- package/dist/admin/client/collection/data-table.svelte.d.ts +11 -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/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 +113 -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 +23 -21
- package/dist/admin/components/fields/file-field.svelte +344 -30
- package/dist/admin/components/fields/media-field.svelte +16 -2
- 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 +9 -4
- 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 +172 -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/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 +37 -32
- package/dist/admin/remote/shop.remote.js +9 -2
- 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/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/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 +3 -3
- 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/fields/fieldSchemaToTs.d.ts +7 -0
- package/dist/core/fields/fieldSchemaToTs.js +234 -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.js +10 -17
- package/dist/core/server/generator/formFields.js +2 -1
- package/dist/core/server/generator/generator.js +4 -4
- package/dist/core/server/generator/utils.d.ts +1 -0
- package/dist/core/server/generator/utils.js +4 -0
- package/dist/paraglide/messages/_index.d.ts +3 -36
- package/dist/paraglide/messages/_index.js +3 -71
- package/dist/paraglide/messages/hello_world.d.ts +5 -0
- package/dist/paraglide/messages/hello_world.js +33 -0
- package/dist/paraglide/messages/login_hello.d.ts +16 -0
- package/dist/paraglide/messages/login_hello.js +34 -0
- package/dist/paraglide/messages/login_please_login.d.ts +16 -0
- package/dist/paraglide/messages/login_please_login.js +34 -0
- package/dist/shop/server/orders.d.ts +1 -0
- package/dist/shop/server/orders.js +14 -0
- package/dist/shop/server/shop-data.d.ts +2 -0
- package/dist/shop/server/shop-data.js +20 -5
- package/dist/sveltekit/server/handle.js +17 -0
- package/dist/types/cms.schema.js +4 -2
- package/dist/types/fields.d.ts +35 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/layout.d.ts +35 -2
- package/dist/updates/0.26.0/index.d.ts +2 -0
- package/dist/updates/0.26.0/index.js +51 -0
- package/dist/updates/index.js +3 -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
- package/dist/paraglide/messages/en.d.ts +0 -5
- package/dist/paraglide/messages/en.js +0 -14
- package/dist/paraglide/messages/pl.d.ts +0 -5
- package/dist/paraglide/messages/pl.js +0 -14
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
* Shared layout for detail/edit pages — wraps PageHeader + body grid + optional
|
|
5
|
+
* sidebar. Used by coupon-edit-page, shipping-method-edit-page, shop-order-detail-page.
|
|
6
|
+
*
|
|
7
|
+
* EntryPage stays custom (hybrid preview + lang switcher + 30+ specific guards).
|
|
8
|
+
*
|
|
9
|
+
* S8.
|
|
10
|
+
*/
|
|
11
|
+
import type { Snippet } from 'svelte';
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<script lang="ts">
|
|
15
|
+
import PageHeader from './page-header.svelte';
|
|
16
|
+
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
17
|
+
import type { InterfaceLanguage } from '../../../types/languages.js';
|
|
18
|
+
import { cn } from '../../../utils.js';
|
|
19
|
+
|
|
20
|
+
type Props = {
|
|
21
|
+
title: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
count?: number;
|
|
24
|
+
breadcrumb?: Snippet;
|
|
25
|
+
primaryActions?: Snippet;
|
|
26
|
+
secondaryActions?: Snippet;
|
|
27
|
+
sidebar?: Snippet;
|
|
28
|
+
children: Snippet;
|
|
29
|
+
class?: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
let {
|
|
33
|
+
title,
|
|
34
|
+
description,
|
|
35
|
+
count,
|
|
36
|
+
breadcrumb,
|
|
37
|
+
primaryActions,
|
|
38
|
+
secondaryActions,
|
|
39
|
+
sidebar,
|
|
40
|
+
children,
|
|
41
|
+
class: className
|
|
42
|
+
}: Props = $props();
|
|
43
|
+
|
|
44
|
+
const interfaceLanguage = useInterfaceLanguage();
|
|
45
|
+
const lang: Record<InterfaceLanguage, { sidebarLabel: string }> = {
|
|
46
|
+
pl: { sidebarLabel: 'Panel boczny' },
|
|
47
|
+
en: { sidebarLabel: 'Sidebar' }
|
|
48
|
+
};
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<div class={cn('flex flex-col', className)}>
|
|
52
|
+
{#if breadcrumb}
|
|
53
|
+
<div class="border-border border-b px-6 py-2">
|
|
54
|
+
{@render breadcrumb()}
|
|
55
|
+
</div>
|
|
56
|
+
{/if}
|
|
57
|
+
|
|
58
|
+
<PageHeader {title} {description} {count} {primaryActions} {secondaryActions} />
|
|
59
|
+
|
|
60
|
+
<div class="flex flex-col gap-6 px-6 pb-8 lg:grid lg:grid-cols-[1fr_320px]">
|
|
61
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
62
|
+
<main id="detail-main" tabindex={-1} class="min-w-0 outline-none">
|
|
63
|
+
{@render children()}
|
|
64
|
+
</main>
|
|
65
|
+
{#if sidebar}
|
|
66
|
+
<aside aria-label={lang[interfaceLanguage.current].sidebarLabel} class="min-w-0">
|
|
67
|
+
{@render sidebar()}
|
|
68
|
+
</aside>
|
|
69
|
+
{/if}
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @internal
|
|
3
|
+
* Shared layout for detail/edit pages — wraps PageHeader + body grid + optional
|
|
4
|
+
* sidebar. Used by coupon-edit-page, shipping-method-edit-page, shop-order-detail-page.
|
|
5
|
+
*
|
|
6
|
+
* EntryPage stays custom (hybrid preview + lang switcher + 30+ specific guards).
|
|
7
|
+
*
|
|
8
|
+
* S8.
|
|
9
|
+
*/
|
|
10
|
+
import type { Snippet } from 'svelte';
|
|
11
|
+
type Props = {
|
|
12
|
+
title: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
count?: number;
|
|
15
|
+
breadcrumb?: Snippet;
|
|
16
|
+
primaryActions?: Snippet;
|
|
17
|
+
secondaryActions?: Snippet;
|
|
18
|
+
sidebar?: Snippet;
|
|
19
|
+
children: Snippet;
|
|
20
|
+
class?: string;
|
|
21
|
+
};
|
|
22
|
+
declare const DetailPageShell: import("svelte").Component<Props, {}, "">;
|
|
23
|
+
type DetailPageShell = ReturnType<typeof DetailPageShell>;
|
|
24
|
+
export default DetailPageShell;
|
|
@@ -37,6 +37,11 @@ export const sidebarLang = {
|
|
|
37
37
|
singletons: 'Singletony',
|
|
38
38
|
forms: 'Formularze',
|
|
39
39
|
navigation: 'Nawigacja'
|
|
40
|
+
},
|
|
41
|
+
nav: {
|
|
42
|
+
primary: 'Główna nawigacja',
|
|
43
|
+
breadcrumb: 'Ścieżka okruszków',
|
|
44
|
+
skipToMain: 'Przejdź do głównej treści'
|
|
40
45
|
}
|
|
41
46
|
},
|
|
42
47
|
en: {
|
|
@@ -77,6 +82,11 @@ export const sidebarLang = {
|
|
|
77
82
|
singletons: 'Singletons',
|
|
78
83
|
forms: 'Forms',
|
|
79
84
|
navigation: 'Navigation'
|
|
85
|
+
},
|
|
86
|
+
nav: {
|
|
87
|
+
primary: 'Main navigation',
|
|
88
|
+
breadcrumb: 'Breadcrumb',
|
|
89
|
+
skipToMain: 'Skip to main content'
|
|
80
90
|
}
|
|
81
91
|
}
|
|
82
92
|
};
|
|
@@ -9,11 +9,14 @@
|
|
|
9
9
|
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
10
10
|
import { getLocalizedLabel } from '../../utils/collectionLabel.js';
|
|
11
11
|
import LayoutRenderer from './layout-renderer.svelte';
|
|
12
|
+
import LayoutTabs, { type TabInfo } from './layout-tabs.svelte';
|
|
12
13
|
import { cn } from '../../../utils.js';
|
|
14
|
+
import slugify from '../../imports/slugify.js';
|
|
13
15
|
import {
|
|
14
16
|
resolveFieldByPath,
|
|
15
17
|
buildFormPath,
|
|
16
|
-
getDistributedObjectSlugs
|
|
18
|
+
getDistributedObjectSlugs,
|
|
19
|
+
collectLeafPathsForNodes
|
|
17
20
|
} from '../../../core/fields/layoutUtils.js';
|
|
18
21
|
|
|
19
22
|
type Props = {
|
|
@@ -22,6 +25,7 @@
|
|
|
22
25
|
form: SuperForm<Record<string, unknown>>;
|
|
23
26
|
focusedPath?: string | null;
|
|
24
27
|
flashingPath?: string | null;
|
|
28
|
+
errorPaths?: Set<string>;
|
|
25
29
|
depth?: number;
|
|
26
30
|
distributedSlugs?: Set<string>;
|
|
27
31
|
};
|
|
@@ -32,6 +36,7 @@
|
|
|
32
36
|
form,
|
|
33
37
|
focusedPath = null,
|
|
34
38
|
flashingPath = null,
|
|
39
|
+
errorPaths = undefined,
|
|
35
40
|
depth = 0,
|
|
36
41
|
distributedSlugs: parentDistributedSlugs
|
|
37
42
|
}: Props = $props();
|
|
@@ -80,6 +85,41 @@
|
|
|
80
85
|
}
|
|
81
86
|
return '';
|
|
82
87
|
}
|
|
88
|
+
|
|
89
|
+
const errorWordByLang: Record<string, string> = {
|
|
90
|
+
pl: 'zawiera błędy',
|
|
91
|
+
en: 'has errors'
|
|
92
|
+
};
|
|
93
|
+
const errorWord = $derived(
|
|
94
|
+
errorWordByLang[interfaceLanguage.current] ?? errorWordByLang.en
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Build per-tab metadata for a tabs node: stable slugified value (unique
|
|
99
|
+
* within the group), localized label and whether any leaf field inside the
|
|
100
|
+
* tab is currently in `errorPaths`.
|
|
101
|
+
*/
|
|
102
|
+
function buildTabs(children: LayoutNode[]): TabInfo[] {
|
|
103
|
+
const seen = new Set<string>();
|
|
104
|
+
return children.map((child, i) => {
|
|
105
|
+
const label = getLabel(child);
|
|
106
|
+
let value = label ? slugify(label, { lower: true, strict: true, trim: true }) : '';
|
|
107
|
+
if (!value || seen.has(value)) value = `tab-${i}`;
|
|
108
|
+
seen.add(value);
|
|
109
|
+
const hasError =
|
|
110
|
+
!!errorPaths &&
|
|
111
|
+
collectLeafPathsForNodes([child], fields).some((p) => errorPaths!.has(p));
|
|
112
|
+
return { value, label, child, hasError };
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function groupId(tabsIndex: number): string {
|
|
117
|
+
return `tg-${depth}-${tabsIndex}`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// URL sync: only the outermost tabs group (depth 0, first tabs node) reads
|
|
121
|
+
// from / writes to the `?tab` query param. Nested tabs keep local state only.
|
|
122
|
+
const firstTabsIndex = $derived(nodes.findIndex((n) => n.type === 'tabs'));
|
|
83
123
|
</script>
|
|
84
124
|
|
|
85
125
|
{#snippet fieldSlot(ref: string, autoGrid?: boolean)}
|
|
@@ -116,6 +156,7 @@
|
|
|
116
156
|
{form}
|
|
117
157
|
{focusedPath}
|
|
118
158
|
{flashingPath}
|
|
159
|
+
{errorPaths}
|
|
119
160
|
depth={depth + 1}
|
|
120
161
|
{distributedSlugs}
|
|
121
162
|
/>
|
|
@@ -186,7 +227,16 @@
|
|
|
186
227
|
<Accordion.Trigger class="layout-accordion-trigger">
|
|
187
228
|
{getLabel(node)}
|
|
188
229
|
</Accordion.Trigger>
|
|
189
|
-
|
|
230
|
+
<!--
|
|
231
|
+
forceMount keeps the panel in the DOM when closed so
|
|
232
|
+
validation/scroll-to-issue can find fields and the
|
|
233
|
+
accordion can be auto-expanded by activateContainingAccordions.
|
|
234
|
+
accordion-content.svelte collapses forceMount content with
|
|
235
|
+
a grid-template-rows transition — animated both ways, and it
|
|
236
|
+
holds the collapsed state (the one-shot keyframe cannot once
|
|
237
|
+
the panel stays permanently mounted).
|
|
238
|
+
-->
|
|
239
|
+
<Accordion.Content forceMount>
|
|
190
240
|
{#if isLayoutLeaf(node)}
|
|
191
241
|
<div class="layout-fields-stack">
|
|
192
242
|
{#each node.fields as ref (ref)}
|
|
@@ -212,6 +262,25 @@
|
|
|
212
262
|
{@render recurse(node.children)}
|
|
213
263
|
{/if}
|
|
214
264
|
</div>
|
|
265
|
+
{:else if node.type === 'tabs'}
|
|
266
|
+
{@const tabsIndex = nodes.indexOf(node)}
|
|
267
|
+
{@const gid = groupId(tabsIndex)}
|
|
268
|
+
{@const tabs = buildTabs(node.children)}
|
|
269
|
+
{@const isTopLevelGroup = depth === 0 && tabsIndex === firstTabsIndex}
|
|
270
|
+
<LayoutTabs {tabs} {gid} syncUrl={isTopLevelGroup} {errorWord}>
|
|
271
|
+
{#snippet panel(child: LayoutNode)}
|
|
272
|
+
{#if isLayoutLeaf(child)}
|
|
273
|
+
<div class="layout-fields-stack">
|
|
274
|
+
{#each child.fields as ref (ref)}
|
|
275
|
+
{@render fieldSlot(ref)}
|
|
276
|
+
{/each}
|
|
277
|
+
</div>
|
|
278
|
+
{/if}
|
|
279
|
+
{#if isLayoutBranch(child)}
|
|
280
|
+
{@render recurse(child.children)}
|
|
281
|
+
{/if}
|
|
282
|
+
{/snippet}
|
|
283
|
+
</LayoutTabs>
|
|
215
284
|
{/if}
|
|
216
285
|
{/each}
|
|
217
286
|
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { LayoutNode } from '../../../types/layout.js';
|
|
3
|
+
|
|
4
|
+
/** Per-tab metadata computed by the renderer for a `tabs` node. */
|
|
5
|
+
export type TabInfo = {
|
|
6
|
+
/** Stable, group-unique slug used as the bits-ui tab value + DOM id. */
|
|
7
|
+
value: string;
|
|
8
|
+
/** Localized trigger text (current interface language). */
|
|
9
|
+
label: string;
|
|
10
|
+
/** The underlying `tab` layout node, rendered via the `panel` snippet. */
|
|
11
|
+
child: LayoutNode;
|
|
12
|
+
/** True when a leaf field inside this tab is currently invalid. */
|
|
13
|
+
hasError: boolean;
|
|
14
|
+
};
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<script lang="ts">
|
|
18
|
+
import type { Snippet } from 'svelte';
|
|
19
|
+
import * as Tabs from '../../../components/ui/tabs/index.js';
|
|
20
|
+
import { Tabs as TabsPrimitive } from 'bits-ui';
|
|
21
|
+
import { cn } from '../../../utils.js';
|
|
22
|
+
import { browser } from '$app/environment';
|
|
23
|
+
import { page } from '$app/state';
|
|
24
|
+
import { replaceState } from '$app/navigation';
|
|
25
|
+
|
|
26
|
+
type Props = {
|
|
27
|
+
tabs: TabInfo[];
|
|
28
|
+
gid: string;
|
|
29
|
+
/** Only the outermost tabs group syncs the active tab to `?tab`. */
|
|
30
|
+
syncUrl: boolean;
|
|
31
|
+
errorWord: string;
|
|
32
|
+
panel: Snippet<[LayoutNode]>;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
let { tabs, gid, syncUrl, errorWord, panel }: Props = $props();
|
|
36
|
+
|
|
37
|
+
function initialValue(): string {
|
|
38
|
+
if (syncUrl && browser) {
|
|
39
|
+
const fromUrl = page.url.searchParams.get('tab');
|
|
40
|
+
if (fromUrl && tabs.some((t) => t.value === fromUrl)) return fromUrl;
|
|
41
|
+
}
|
|
42
|
+
return tabs[0]?.value ?? '';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let active = $state(initialValue());
|
|
46
|
+
|
|
47
|
+
// Write the active tab back to the URL (outermost group only). Guard against
|
|
48
|
+
// the no-op case so we never trigger an infinite replaceState loop.
|
|
49
|
+
$effect(() => {
|
|
50
|
+
if (!syncUrl || !browser) return;
|
|
51
|
+
const current = page.url.searchParams.get('tab');
|
|
52
|
+
if (active && active !== current) {
|
|
53
|
+
const url = new URL(page.url);
|
|
54
|
+
url.searchParams.set('tab', active);
|
|
55
|
+
replaceState(url, page.state);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<Tabs.Root class="gap-0" bind:value={active}>
|
|
61
|
+
<Tabs.List class={cn('layout-tabs-list', syncUrl && 'bleed')}>
|
|
62
|
+
{#each tabs as tb (tb.value)}
|
|
63
|
+
<Tabs.Trigger
|
|
64
|
+
value={tb.value}
|
|
65
|
+
data-tab-value={tb.value}
|
|
66
|
+
data-tabs-group={gid}
|
|
67
|
+
class="layout-tab-trigger"
|
|
68
|
+
>
|
|
69
|
+
{tb.label}
|
|
70
|
+
{#if tb.hasError}
|
|
71
|
+
<span class="layout-tab-error-dot" aria-hidden="true"></span>
|
|
72
|
+
<span class="sr-only"> — {errorWord}</span>
|
|
73
|
+
{/if}
|
|
74
|
+
</Tabs.Trigger>
|
|
75
|
+
{/each}
|
|
76
|
+
</Tabs.List>
|
|
77
|
+
{#each tabs as tb (tb.value)}
|
|
78
|
+
<TabsPrimitive.Content value={tb.value}>
|
|
79
|
+
{#snippet child({ props })}
|
|
80
|
+
{@const panelActive = (props as Record<string, unknown>).hidden !== true}
|
|
81
|
+
<div
|
|
82
|
+
{...props}
|
|
83
|
+
data-slot="tabs-content"
|
|
84
|
+
data-tab-value={tb.value}
|
|
85
|
+
data-tabs-group={gid}
|
|
86
|
+
class={cn(
|
|
87
|
+
'layout-tab-panel',
|
|
88
|
+
panelActive && 'layout-tab-panel-active',
|
|
89
|
+
syncUrl && 'bleed'
|
|
90
|
+
)}
|
|
91
|
+
>
|
|
92
|
+
{@render panel(tb.child)}
|
|
93
|
+
</div>
|
|
94
|
+
{/snippet}
|
|
95
|
+
</TabsPrimitive.Content>
|
|
96
|
+
{/each}
|
|
97
|
+
</Tabs.Root>
|
|
98
|
+
|
|
99
|
+
<style>
|
|
100
|
+
:global(.layout-tabs-list) {
|
|
101
|
+
display: flex;
|
|
102
|
+
width: 100%;
|
|
103
|
+
gap: 4px;
|
|
104
|
+
border-bottom: 1px solid var(--border);
|
|
105
|
+
margin-bottom: 20px;
|
|
106
|
+
height: auto;
|
|
107
|
+
background: transparent;
|
|
108
|
+
padding: 0;
|
|
109
|
+
border-radius: 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
:global(.layout-tabs-list.bleed) {
|
|
113
|
+
box-sizing: border-box;
|
|
114
|
+
width: 100%;
|
|
115
|
+
margin-bottom: 0;
|
|
116
|
+
padding-inline: max(24px, calc((100% - 1100px) / 2));
|
|
117
|
+
border-top: 0;
|
|
118
|
+
border-left: 0;
|
|
119
|
+
border-right: 0;
|
|
120
|
+
box-shadow: none;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@media (max-width: 900px) {
|
|
124
|
+
:global(.layout-tabs-list.bleed) {
|
|
125
|
+
padding-inline: 16px;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
:global(.layout-tab-panel.bleed) {
|
|
130
|
+
box-sizing: border-box;
|
|
131
|
+
max-width: 1100px;
|
|
132
|
+
margin: 0 auto;
|
|
133
|
+
padding: 24px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@media (max-width: 900px) {
|
|
137
|
+
:global(.layout-tab-panel.bleed) {
|
|
138
|
+
padding: 16px;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
:global(.layout-tab-trigger) {
|
|
143
|
+
flex: 1;
|
|
144
|
+
height: auto;
|
|
145
|
+
padding: 10px 14px;
|
|
146
|
+
border: none;
|
|
147
|
+
border-bottom: 2px solid transparent;
|
|
148
|
+
border-radius: 8px 8px 0 0;
|
|
149
|
+
background: transparent;
|
|
150
|
+
color: var(--muted-foreground);
|
|
151
|
+
font-size: 13px;
|
|
152
|
+
font-weight: 600;
|
|
153
|
+
box-shadow: none;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
:global(.layout-tab-trigger[data-state='active']) {
|
|
157
|
+
color: var(--primary);
|
|
158
|
+
border-bottom-color: var(--primary);
|
|
159
|
+
background: transparent;
|
|
160
|
+
box-shadow: none;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
:global(.layout-tab-error-dot) {
|
|
164
|
+
display: inline-block;
|
|
165
|
+
width: 6px;
|
|
166
|
+
height: 6px;
|
|
167
|
+
margin-left: 6px;
|
|
168
|
+
border-radius: 9999px;
|
|
169
|
+
background: var(--error, #c44b4b);
|
|
170
|
+
vertical-align: middle;
|
|
171
|
+
}
|
|
172
|
+
</style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { LayoutNode } from '../../../types/layout.js';
|
|
2
|
+
/** Per-tab metadata computed by the renderer for a `tabs` node. */
|
|
3
|
+
export type TabInfo = {
|
|
4
|
+
/** Stable, group-unique slug used as the bits-ui tab value + DOM id. */
|
|
5
|
+
value: string;
|
|
6
|
+
/** Localized trigger text (current interface language). */
|
|
7
|
+
label: string;
|
|
8
|
+
/** The underlying `tab` layout node, rendered via the `panel` snippet. */
|
|
9
|
+
child: LayoutNode;
|
|
10
|
+
/** True when a leaf field inside this tab is currently invalid. */
|
|
11
|
+
hasError: boolean;
|
|
12
|
+
};
|
|
13
|
+
import type { Snippet } from 'svelte';
|
|
14
|
+
type Props = {
|
|
15
|
+
tabs: TabInfo[];
|
|
16
|
+
gid: string;
|
|
17
|
+
/** Only the outermost tabs group syncs the active tab to `?tab`. */
|
|
18
|
+
syncUrl: boolean;
|
|
19
|
+
errorWord: string;
|
|
20
|
+
panel: Snippet<[LayoutNode]>;
|
|
21
|
+
};
|
|
22
|
+
declare const LayoutTabs: import("svelte").Component<Props, {}, "">;
|
|
23
|
+
type LayoutTabs = ReturnType<typeof LayoutTabs>;
|
|
24
|
+
export default LayoutTabs;
|
|
@@ -1,22 +1,40 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getBreadcrumbs } from '../../state/breadcrumbs.svelte.js';
|
|
3
3
|
import * as Breadcrumb from '../../../components/ui/breadcrumb/index.js';
|
|
4
|
+
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
5
|
+
import { sidebarLang } from './lang.js';
|
|
4
6
|
|
|
5
7
|
const breadcrumbs = getBreadcrumbs();
|
|
8
|
+
const interfaceLanguage = useInterfaceLanguage();
|
|
6
9
|
</script>
|
|
7
10
|
|
|
8
|
-
<Breadcrumb.Root
|
|
9
|
-
|
|
11
|
+
<Breadcrumb.Root
|
|
12
|
+
aria-label={sidebarLang[interfaceLanguage.current].nav.breadcrumb}
|
|
13
|
+
class="min-w-0 flex-1 overflow-hidden"
|
|
14
|
+
>
|
|
15
|
+
<Breadcrumb.List class="flex-nowrap gap-1.5 text-[13px] sm:gap-2">
|
|
10
16
|
{#each breadcrumbs.state as crumb, i}
|
|
11
|
-
|
|
12
|
-
|
|
17
|
+
{@const isLast = i === breadcrumbs.state.length - 1}
|
|
18
|
+
{@const isFirst = i === 0}
|
|
19
|
+
{@const hideOnMobile = breadcrumbs.state.length > 2 && !isLast && !isFirst}
|
|
20
|
+
<Breadcrumb.Item class={hideOnMobile ? 'hidden sm:inline-flex' : ''}>
|
|
21
|
+
{#if crumb.href && !isLast}
|
|
13
22
|
<Breadcrumb.Link class="font-medium" href={crumb.href}>{crumb.label}</Breadcrumb.Link>
|
|
14
23
|
{:else}
|
|
15
|
-
<Breadcrumb.Page class="max-w-
|
|
24
|
+
<Breadcrumb.Page class="max-w-[10rem] truncate font-semibold sm:max-w-60"
|
|
25
|
+
>{crumb.label}</Breadcrumb.Page
|
|
26
|
+
>
|
|
16
27
|
{/if}
|
|
17
28
|
</Breadcrumb.Item>
|
|
18
|
-
{#if
|
|
19
|
-
<Breadcrumb.Separator
|
|
29
|
+
{#if !isLast}
|
|
30
|
+
<Breadcrumb.Separator class={hideOnMobile ? 'hidden sm:inline-flex' : ''}
|
|
31
|
+
>/</Breadcrumb.Separator
|
|
32
|
+
>
|
|
33
|
+
{/if}
|
|
34
|
+
{#if breadcrumbs.state.length > 2 && isFirst}
|
|
35
|
+
<Breadcrumb.Separator class="inline-flex sm:hidden" aria-hidden="true"
|
|
36
|
+
>/…/</Breadcrumb.Separator
|
|
37
|
+
>
|
|
20
38
|
{/if}
|
|
21
39
|
{/each}
|
|
22
40
|
</Breadcrumb.List>
|
|
@@ -2,19 +2,25 @@
|
|
|
2
2
|
import * as Sidebar from '../../../components/ui/sidebar/index.js';
|
|
3
3
|
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
4
4
|
import { getRemotes } from '../../../sveltekit/index.js';
|
|
5
|
+
import { getBreadcrumbs } from '../../state/breadcrumbs.svelte.js';
|
|
5
6
|
import { sidebarLang } from './lang.js';
|
|
6
7
|
import { getLocalizedLabel } from '../../utils/collectionLabel.js';
|
|
7
8
|
import Skeleton from '../../../components/ui/skeleton/skeleton.svelte';
|
|
8
9
|
import { page } from '$app/state';
|
|
9
10
|
import FolderIcon from '@tabler/icons-svelte/icons/folder';
|
|
10
11
|
import { getIcon } from '../icons/icon-map.js';
|
|
12
|
+
import NavSection, { type NavSectionItem } from './nav-section.svelte';
|
|
11
13
|
|
|
12
14
|
const interfaceLanguage = useInterfaceLanguage();
|
|
13
15
|
const remotes = getRemotes();
|
|
16
|
+
const breadcrumbs = getBreadcrumbs();
|
|
14
17
|
|
|
15
18
|
function isActive(url: string) {
|
|
16
19
|
const pathname = page.url.pathname;
|
|
17
|
-
|
|
20
|
+
if (pathname === url || pathname.startsWith(url + '/')) return true;
|
|
21
|
+
// Also highlight a collection while editing one of its entries — the entry
|
|
22
|
+
// page sets a breadcrumb linking back to the collection list.
|
|
23
|
+
return breadcrumbs.state.some((b) => b.href === url);
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
const collectionsQuery = $derived(remotes.getCollections());
|
|
@@ -33,6 +39,15 @@
|
|
|
33
39
|
}
|
|
34
40
|
countsMap = map;
|
|
35
41
|
});
|
|
42
|
+
|
|
43
|
+
const items: NavSectionItem[] = $derived(
|
|
44
|
+
collectionsQuery.current?.map((item) => ({
|
|
45
|
+
title: getLocalizedLabel(item.labels?.plural, interfaceLanguage.current) ?? item.slug,
|
|
46
|
+
url: `/admin/collections/${item.slug}`,
|
|
47
|
+
icon: getIcon(item.sidebarIcon) ?? FolderIcon,
|
|
48
|
+
count: countsMap.get(item.slug)
|
|
49
|
+
})) ?? []
|
|
50
|
+
);
|
|
36
51
|
</script>
|
|
37
52
|
|
|
38
53
|
{#if !collectionsQuery.ready}
|
|
@@ -47,39 +62,11 @@
|
|
|
47
62
|
</div>
|
|
48
63
|
</Sidebar.Menu>
|
|
49
64
|
</Sidebar.Group>
|
|
50
|
-
{:else if
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
{@const name =
|
|
58
|
-
getLocalizedLabel(item.labels?.plural, interfaceLanguage.current) ?? item.slug}
|
|
59
|
-
{@const url = `/admin/collections/${item.slug}`}
|
|
60
|
-
{@const active = isActive(url)}
|
|
61
|
-
<Sidebar.MenuItem>
|
|
62
|
-
<Sidebar.MenuButton isActive={active} tooltipContent={name}>
|
|
63
|
-
{#snippet child({ props })}
|
|
64
|
-
{@const ResolvedIcon = getIcon(item.sidebarIcon) ?? FolderIcon}
|
|
65
|
-
<a {...props} href={url}>
|
|
66
|
-
<ResolvedIcon
|
|
67
|
-
class="size-5! shrink-0 {active ? 'text-primary' : 'text-muted-foreground'}"
|
|
68
|
-
/>
|
|
69
|
-
<span class="flex-1 truncate {active ? 'text-primary' : 'text-muted-foreground'}"
|
|
70
|
-
>{name}</span
|
|
71
|
-
>
|
|
72
|
-
{#if countsMap.get(item.slug)}
|
|
73
|
-
<span
|
|
74
|
-
class="bg-lavender-lighter text-primary inline-flex h-[18px] min-w-[18px] shrink-0 items-center justify-center rounded-full px-[5px] text-[10px] font-bold group-data-[collapsible=icon]:hidden"
|
|
75
|
-
>{countsMap.get(item.slug)}</span
|
|
76
|
-
>
|
|
77
|
-
{/if}
|
|
78
|
-
</a>
|
|
79
|
-
{/snippet}
|
|
80
|
-
</Sidebar.MenuButton>
|
|
81
|
-
</Sidebar.MenuItem>
|
|
82
|
-
{/each}
|
|
83
|
-
</Sidebar.Menu>
|
|
84
|
-
</Sidebar.Group>
|
|
65
|
+
{:else if items.length > 0}
|
|
66
|
+
<NavSection
|
|
67
|
+
{items}
|
|
68
|
+
label={sidebarLang[interfaceLanguage.current].collections.title}
|
|
69
|
+
{isActive}
|
|
70
|
+
withTopBorder
|
|
71
|
+
/>
|
|
85
72
|
{/if}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import ClipboardIcon from '@tabler/icons-svelte/icons/clipboard-list';
|
|
9
9
|
import { getIcon } from '../icons/icon-map.js';
|
|
10
10
|
import { page } from '$app/state';
|
|
11
|
+
import NavSection, { type NavSectionItem } from './nav-section.svelte';
|
|
11
12
|
|
|
12
13
|
const interfaceLanguage = useInterfaceLanguage();
|
|
13
14
|
const remotes = getRemotes();
|
|
@@ -21,13 +22,23 @@
|
|
|
21
22
|
const overviewQuery = $derived(remotes.getSubmissionsOverview());
|
|
22
23
|
|
|
23
24
|
const countsMap = $derived.by(() => {
|
|
25
|
+
// Badge = unread submissions (things needing attention), not total
|
|
24
26
|
const map = new Map<string, number>();
|
|
25
27
|
if (!overviewQuery.ready || !overviewQuery.current) return map;
|
|
26
28
|
for (const item of overviewQuery.current) {
|
|
27
|
-
if (item.
|
|
29
|
+
if (item.unread > 0) map.set(item.slug, item.unread);
|
|
28
30
|
}
|
|
29
31
|
return map;
|
|
30
32
|
});
|
|
33
|
+
|
|
34
|
+
const items: NavSectionItem[] = $derived(
|
|
35
|
+
formsQuery.current?.map((item) => ({
|
|
36
|
+
title: getLocalizedLabel(item.label, interfaceLanguage.current) ?? item.slug,
|
|
37
|
+
url: `/admin/forms/${item.slug}`,
|
|
38
|
+
icon: getIcon(item.sidebarIcon) ?? ClipboardIcon,
|
|
39
|
+
count: countsMap.get(item.slug)
|
|
40
|
+
})) ?? []
|
|
41
|
+
);
|
|
31
42
|
</script>
|
|
32
43
|
|
|
33
44
|
{#if !formsQuery.ready}
|
|
@@ -40,38 +51,11 @@
|
|
|
40
51
|
</div>
|
|
41
52
|
</Sidebar.Menu>
|
|
42
53
|
</Sidebar.Group>
|
|
43
|
-
{:else if
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
{@const name = getLocalizedLabel(item.label, interfaceLanguage.current) ?? item.slug}
|
|
51
|
-
{@const url = `/admin/forms/${item.slug}`}
|
|
52
|
-
{@const active = isActive(url)}
|
|
53
|
-
<Sidebar.MenuItem>
|
|
54
|
-
<Sidebar.MenuButton isActive={active} tooltipContent={name}>
|
|
55
|
-
{#snippet child({ props })}
|
|
56
|
-
{@const ResolvedIcon = getIcon(item.sidebarIcon) ?? ClipboardIcon}
|
|
57
|
-
<a {...props} href={url}>
|
|
58
|
-
<ResolvedIcon
|
|
59
|
-
class="size-5! shrink-0 {active ? 'text-primary' : 'text-muted-foreground'}"
|
|
60
|
-
/>
|
|
61
|
-
<span class="flex-1 {active ? 'text-primary' : 'text-muted-foreground'} truncate"
|
|
62
|
-
>{name}</span
|
|
63
|
-
>
|
|
64
|
-
{#if countsMap.get(item.slug)}
|
|
65
|
-
<span
|
|
66
|
-
class="bg-lavender-lighter text-primary inline-flex h-[18px] min-w-[18px] shrink-0 items-center justify-center rounded-full px-[5px] text-[10px] font-bold group-data-[collapsible=icon]:hidden"
|
|
67
|
-
>{countsMap.get(item.slug)}</span
|
|
68
|
-
>
|
|
69
|
-
{/if}
|
|
70
|
-
</a>
|
|
71
|
-
{/snippet}
|
|
72
|
-
</Sidebar.MenuButton>
|
|
73
|
-
</Sidebar.MenuItem>
|
|
74
|
-
{/each}
|
|
75
|
-
</Sidebar.Menu>
|
|
76
|
-
</Sidebar.Group>
|
|
54
|
+
{:else if items.length > 0}
|
|
55
|
+
<NavSection
|
|
56
|
+
{items}
|
|
57
|
+
label={sidebarLang[interfaceLanguage.current].forms.title}
|
|
58
|
+
{isActive}
|
|
59
|
+
withTopBorder
|
|
60
|
+
/>
|
|
77
61
|
{/if}
|