includio-cms 0.36.8 → 0.37.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 +179 -3
- package/CHANGELOG.md +64 -0
- package/DOCS.md +28 -3
- package/ROADMAP.md +18 -0
- package/dist/admin/client/booking/booking-dashboard.svelte +40 -0
- package/dist/admin/client/booking/booking-dashboard.svelte.d.ts +3 -0
- package/dist/admin/client/booking/customer-panel.svelte +102 -0
- package/dist/admin/client/booking/customer-panel.svelte.d.ts +11 -0
- package/dist/admin/client/booking/customer-view.d.ts +52 -0
- package/dist/admin/client/booking/customer-view.js +134 -0
- package/dist/admin/client/booking/participant-data-panel.svelte +330 -0
- package/dist/admin/client/booking/participant-data-panel.svelte.d.ts +22 -0
- package/dist/admin/client/booking/reservation-detail-page.svelte +637 -0
- package/dist/admin/client/booking/reservation-detail-page.svelte.d.ts +3 -0
- package/dist/admin/client/booking/reservations-page.svelte +221 -0
- package/dist/admin/client/booking/reservations-page.svelte.d.ts +3 -0
- package/dist/admin/client/collection/collection-entries.svelte +21 -2
- package/dist/admin/client/collection/entry-link.svelte +6 -4
- package/dist/admin/client/collection/entry-link.svelte.d.ts +3 -1
- package/dist/admin/client/collection/row-actions.svelte +12 -4
- package/dist/admin/client/collection/row-actions.svelte.d.ts +1 -0
- package/dist/admin/client/collection/status-badge.svelte +39 -3
- package/dist/admin/client/collection/status-badge.svelte.d.ts +5 -3
- package/dist/admin/client/entry/entry.svelte +26 -9
- package/dist/admin/client/entry/hybrid/hybrid-preview.svelte +73 -10
- package/dist/admin/client/entry/hybrid/hybrid-preview.svelte.d.ts +6 -5
- package/dist/admin/client/entry/preview-views-context.svelte.d.ts +22 -0
- package/dist/admin/client/entry/preview-views-context.svelte.js +58 -0
- package/dist/admin/client/entry/preview-views.d.ts +27 -0
- package/dist/admin/client/entry/preview-views.js +33 -0
- package/dist/admin/client/index.d.ts +3 -0
- package/dist/admin/client/index.js +3 -0
- package/dist/admin/client/modules/dashboard-registry.d.ts +7 -0
- package/dist/admin/client/modules/dashboard-registry.js +11 -0
- package/dist/admin/client/modules/module-dashboard-page.svelte +26 -0
- package/dist/admin/client/modules/module-dashboard-page.svelte.d.ts +6 -0
- package/dist/admin/client/modules/stat-card.svelte +22 -0
- package/dist/admin/client/modules/stat-card.svelte.d.ts +10 -0
- package/dist/admin/client/shop/shop-dashboard.svelte +29 -0
- package/dist/admin/client/shop/shop-dashboard.svelte.d.ts +3 -0
- package/dist/admin/components/fields/relation-field.svelte +11 -2
- package/dist/admin/components/icons/icon-map.js +8 -0
- package/dist/admin/components/layout/app-sidebar.svelte +45 -14
- package/dist/admin/components/layout/context-switcher.svelte +90 -0
- package/dist/admin/components/layout/context-switcher.svelte.d.ts +3 -0
- package/dist/admin/components/layout/lang.d.ts +4 -0
- package/dist/admin/components/layout/lang.js +8 -0
- package/dist/admin/components/layout/layout-renderer.svelte +2 -1
- package/dist/admin/components/layout/layout-tabs.svelte +14 -0
- package/dist/admin/components/layout/layout-tabs.svelte.d.ts +2 -0
- package/dist/admin/components/layout/nav-collections.svelte +16 -9
- package/dist/admin/components/layout/nav-collections.svelte.d.ts +5 -1
- package/dist/admin/components/layout/nav-global.svelte +45 -0
- package/dist/admin/components/layout/nav-global.svelte.d.ts +3 -0
- package/dist/admin/components/layout/nav-main.svelte +8 -32
- package/dist/admin/components/layout/nav-main.svelte.d.ts +6 -1
- package/dist/admin/components/layout/nav-module.svelte +57 -0
- package/dist/admin/components/layout/nav-module.svelte.d.ts +7 -0
- package/dist/admin/components/layout/nav-section.svelte +1 -1
- package/dist/admin/components/layout/nav-section.svelte.d.ts +1 -1
- package/dist/admin/components/layout/nav-singletons.svelte +14 -7
- package/dist/admin/components/layout/nav-singletons.svelte.d.ts +5 -1
- package/dist/admin/remote/booking.remote.d.ts +244 -0
- package/dist/admin/remote/booking.remote.js +283 -0
- package/dist/admin/remote/entry.remote.d.ts +3 -0
- package/dist/admin/remote/entry.remote.js +14 -3
- package/dist/admin/remote/index.d.ts +2 -0
- package/dist/admin/remote/index.js +2 -0
- package/dist/admin/remote/modules.remote.d.ts +10 -0
- package/dist/admin/remote/modules.remote.js +14 -0
- package/dist/admin/state/active-context-resolve.d.ts +37 -0
- package/dist/admin/state/active-context-resolve.js +66 -0
- package/dist/admin/state/active-context.svelte.d.ts +8 -0
- package/dist/admin/state/active-context.svelte.js +27 -0
- package/dist/booking/adjustments.d.ts +33 -0
- package/dist/booking/adjustments.js +26 -0
- package/dist/booking/capacity.d.ts +12 -0
- package/dist/booking/capacity.js +10 -0
- package/dist/booking/client/index.d.ts +39 -0
- package/dist/booking/client/index.js +44 -0
- package/dist/booking/client/use-booking.svelte.d.ts +25 -0
- package/dist/booking/client/use-booking.svelte.js +56 -0
- package/dist/booking/config.d.ts +156 -0
- package/dist/booking/config.js +36 -0
- package/dist/booking/draft.d.ts +77 -0
- package/dist/booking/draft.js +67 -0
- package/dist/booking/expiry-logic.d.ts +30 -0
- package/dist/booking/expiry-logic.js +33 -0
- package/dist/booking/index.d.ts +18 -0
- package/dist/booking/index.js +52 -0
- package/dist/booking/ledger.d.ts +46 -0
- package/dist/booking/ledger.js +60 -0
- package/dist/booking/number.d.ts +2 -0
- package/dist/booking/number.js +11 -0
- package/dist/booking/participant-fields/access.d.ts +10 -0
- package/dist/booking/participant-fields/access.js +14 -0
- package/dist/booking/participant-fields/age.d.ts +12 -0
- package/dist/booking/participant-fields/age.js +28 -0
- package/dist/booking/participant-fields/completeness.d.ts +8 -0
- package/dist/booking/participant-fields/completeness.js +13 -0
- package/dist/booking/participant-fields/group.d.ts +6 -0
- package/dist/booking/participant-fields/group.js +15 -0
- package/dist/booking/participant-fields/index.d.ts +6 -0
- package/dist/booking/participant-fields/index.js +6 -0
- package/dist/booking/participant-fields/types.d.ts +50 -0
- package/dist/booking/participant-fields/types.js +5 -0
- package/dist/booking/participant-fields/validate.d.ts +7 -0
- package/dist/booking/participant-fields/validate.js +44 -0
- package/dist/booking/participant-pricing.d.ts +93 -0
- package/dist/booking/participant-pricing.js +91 -0
- package/dist/booking/participants-view.d.ts +32 -0
- package/dist/booking/participants-view.js +22 -0
- package/dist/booking/payment-context.d.ts +19 -0
- package/dist/booking/payment-context.js +29 -0
- package/dist/booking/pricing-inputs.d.ts +28 -0
- package/dist/booking/pricing-inputs.js +35 -0
- package/dist/booking/pricing.d.ts +86 -0
- package/dist/booking/pricing.js +125 -0
- package/dist/booking/recompute.d.ts +22 -0
- package/dist/booking/recompute.js +31 -0
- package/dist/booking/reminders-schedule.d.ts +11 -0
- package/dist/booking/reminders-schedule.js +28 -0
- package/dist/booking/server/adjustments.d.ts +27 -0
- package/dist/booking/server/adjustments.js +136 -0
- package/dist/booking/server/bookings.d.ts +45 -0
- package/dist/booking/server/bookings.js +288 -0
- package/dist/booking/server/catalog.d.ts +9 -0
- package/dist/booking/server/catalog.js +20 -0
- package/dist/booking/server/db.d.ts +7 -0
- package/dist/booking/server/db.js +18 -0
- package/dist/booking/server/email.d.ts +23 -0
- package/dist/booking/server/email.js +59 -0
- package/dist/booking/server/emailTemplateRegistry.d.ts +29 -0
- package/dist/booking/server/emailTemplateRegistry.js +125 -0
- package/dist/booking/server/http/create-handler.d.ts +5 -0
- package/dist/booking/server/http/create-handler.js +68 -0
- package/dist/booking/server/http/index.d.ts +4 -0
- package/dist/booking/server/http/index.js +4 -0
- package/dist/booking/server/http/maintenance-handler.d.ts +9 -0
- package/dist/booking/server/http/maintenance-handler.js +36 -0
- package/dist/booking/server/http/portal-handler.d.ts +13 -0
- package/dist/booking/server/http/portal-handler.js +99 -0
- package/dist/booking/server/http/webhook-handler.d.ts +9 -0
- package/dist/booking/server/http/webhook-handler.js +39 -0
- package/dist/booking/server/index.d.ts +12 -0
- package/dist/booking/server/index.js +14 -0
- package/dist/booking/server/maintenance.d.ts +28 -0
- package/dist/booking/server/maintenance.js +134 -0
- package/dist/booking/server/participants.d.ts +26 -0
- package/dist/booking/server/participants.js +92 -0
- package/dist/booking/server/payments.d.ts +34 -0
- package/dist/booking/server/payments.js +207 -0
- package/dist/booking/server/portal-session.d.ts +16 -0
- package/dist/booking/server/portal-session.js +42 -0
- package/dist/booking/server/portal.d.ts +207 -0
- package/dist/booking/server/portal.js +234 -0
- package/dist/booking/server/refunds.d.ts +7 -0
- package/dist/booking/server/refunds.js +58 -0
- package/dist/booking/server/reminders.d.ts +9 -0
- package/dist/booking/server/reminders.js +24 -0
- package/dist/booking/server/validation.d.ts +17 -0
- package/dist/booking/server/validation.js +55 -0
- package/dist/booking/state-machine.d.ts +41 -0
- package/dist/booking/state-machine.js +73 -0
- package/dist/booking/templates/_partials/footer.en.html +4 -0
- package/dist/booking/templates/_partials/footer.pl.html +4 -0
- package/dist/booking/templates/_partials/header.en.html +4 -0
- package/dist/booking/templates/_partials/header.pl.html +4 -0
- package/dist/booking/templates/balance-due.en.html +10 -0
- package/dist/booking/templates/balance-due.pl.html +10 -0
- package/dist/booking/templates/balance-overdue-cancelled.en.html +5 -0
- package/dist/booking/templates/balance-overdue-cancelled.pl.html +5 -0
- package/dist/booking/templates/booking-received.en.html +9 -0
- package/dist/booking/templates/booking-received.pl.html +9 -0
- package/dist/booking/templates/deposit-paid.en.html +6 -0
- package/dist/booking/templates/deposit-paid.pl.html +6 -0
- package/dist/booking/templates/payment-link.en.html +5 -0
- package/dist/booking/templates/payment-link.pl.html +5 -0
- package/dist/booking/templates/payment-received.en.html +10 -0
- package/dist/booking/templates/payment-received.pl.html +10 -0
- package/dist/booking/totals.d.ts +38 -0
- package/dist/booking/totals.js +61 -0
- package/dist/booking/webhook-logic.d.ts +28 -0
- package/dist/booking/webhook-logic.js +50 -0
- package/dist/cli/create-user.d.ts +7 -1
- package/dist/cli/create-user.js +23 -15
- package/dist/cli/index.js +55 -7
- package/dist/cli/scaffold/admin.d.ts +6 -0
- package/dist/cli/scaffold/admin.js +5 -3
- package/dist/cli/scaffold/booking.d.ts +12 -0
- package/dist/cli/scaffold/booking.js +103 -0
- package/dist/core/cms.d.ts +24 -9
- package/dist/core/cms.js +72 -34
- package/dist/core/config/validatePreviews.d.ts +12 -0
- package/dist/core/config/validatePreviews.js +90 -0
- package/dist/core/fields/dotPath.d.ts +4 -0
- package/dist/core/fields/dotPath.js +18 -0
- package/dist/core/fields/slugPath.d.ts +9 -1
- package/dist/core/fields/slugPath.js +16 -2
- package/dist/core/fields/slugify.d.ts +3 -0
- package/dist/core/fields/slugify.js +4 -0
- package/dist/core/server/entries/operations/duplicate.d.ts +10 -0
- package/dist/core/server/entries/operations/duplicate.js +73 -0
- package/dist/core/server/entries/operations/slugNormalize.d.ts +8 -0
- package/dist/core/server/entries/operations/slugNormalize.js +20 -0
- package/dist/core/server/entries/operations/slugUniqueness.d.ts +17 -0
- package/dist/core/server/entries/operations/slugUniqueness.js +39 -0
- package/dist/core/server/fields/resolveRelationFields.d.ts +11 -2
- package/dist/core/server/fields/resolveRelationFields.js +12 -3
- package/dist/core/server/generator/generator.js +7 -2
- package/dist/db-postgres/schema/booking/bookingAdjustments.d.ts +186 -0
- package/dist/db-postgres/schema/booking/bookingAdjustments.js +22 -0
- package/dist/db-postgres/schema/booking/bookingItemPersons.d.ts +117 -0
- package/dist/db-postgres/schema/booking/bookingItemPersons.js +22 -0
- package/dist/db-postgres/schema/booking/bookingItems.d.ts +181 -0
- package/dist/db-postgres/schema/booking/bookingItems.js +22 -0
- package/dist/db-postgres/schema/booking/bookingPayments.d.ts +204 -0
- package/dist/db-postgres/schema/booking/bookingPayments.js +25 -0
- package/dist/db-postgres/schema/booking/bookingPersons.d.ts +99 -0
- package/dist/db-postgres/schema/booking/bookingPersons.js +17 -0
- package/dist/db-postgres/schema/booking/bookingReminders.d.ts +131 -0
- package/dist/db-postgres/schema/booking/bookingReminders.js +18 -0
- package/dist/db-postgres/schema/booking/bookings.d.ts +307 -0
- package/dist/db-postgres/schema/booking/bookings.js +40 -0
- package/dist/db-postgres/schema/booking/index.d.ts +7 -0
- package/dist/db-postgres/schema/booking/index.js +7 -0
- package/dist/db-postgres/schema/index.d.ts +1 -0
- package/dist/db-postgres/schema/index.js +1 -0
- package/dist/db-postgres/schema-booking.d.ts +1 -0
- package/dist/db-postgres/schema-booking.js +1 -0
- package/dist/server/security/rate-limit-handler.d.ts +19 -0
- package/dist/server/security/rate-limit-handler.js +34 -0
- package/dist/shop/adapters/payu/client.js +3 -1
- package/dist/shop/adapters/payu/index.js +37 -17
- package/dist/shop/adapters/payu/payload.d.ts +6 -0
- package/dist/shop/adapters/payu/payload.js +1 -1
- package/dist/shop/adapters/stripe/index.js +36 -21
- package/dist/shop/index.d.ts +11 -2
- package/dist/shop/index.js +43 -1
- package/dist/shop/rate-limit.d.ts +1 -9
- package/dist/shop/rate-limit.js +3 -28
- package/dist/shop/types.d.ts +19 -0
- package/dist/sveltekit/config.d.ts +4 -0
- package/dist/sveltekit/config.js +6 -0
- package/dist/types/cms.d.ts +15 -1
- package/dist/types/cms.schema.d.ts +96 -2
- package/dist/types/cms.schema.js +84 -1
- package/dist/types/config.d.ts +33 -0
- package/dist/types/layout.d.ts +6 -0
- package/dist/types/modules.d.ts +133 -0
- package/dist/types/modules.js +27 -0
- package/dist/updates/0.36.9/index.d.ts +2 -0
- package/dist/updates/0.36.9/index.js +12 -0
- package/dist/updates/0.37.0/index.d.ts +2 -0
- package/dist/updates/0.37.0/index.js +52 -0
- package/dist/updates/index.js +5 -1
- package/package.json +19 -1
- package/dist/admin/components/layout/nav-shop.svelte +0 -33
- package/dist/admin/components/layout/nav-shop.svelte.d.ts +0 -3
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as DropdownMenu from '../../../components/ui/dropdown-menu/index.js';
|
|
3
|
+
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
4
|
+
import { getLocalizedLabel } from '../../utils/collectionLabel.js';
|
|
5
|
+
import { getIcon } from '../icons/icon-map.js';
|
|
6
|
+
import { getRemotes } from '../../../sveltekit/index.js';
|
|
7
|
+
import {
|
|
8
|
+
getActiveContext,
|
|
9
|
+
setActiveContext,
|
|
10
|
+
CONTENT_CONTEXT
|
|
11
|
+
} from '../../state/active-context.svelte.js';
|
|
12
|
+
import { sidebarLang } from './lang.js';
|
|
13
|
+
import { goto } from '$app/navigation';
|
|
14
|
+
import ChevronDownIcon from '@tabler/icons-svelte/icons/chevron-down';
|
|
15
|
+
import FileTextIcon from '@tabler/icons-svelte/icons/file-text';
|
|
16
|
+
import CheckIcon from '@tabler/icons-svelte/icons/check';
|
|
17
|
+
import type { Localized } from '../../../types/languages.js';
|
|
18
|
+
|
|
19
|
+
const interfaceLanguage = useInterfaceLanguage();
|
|
20
|
+
const remotes = getRemotes();
|
|
21
|
+
|
|
22
|
+
const modulesQuery = $derived(remotes.getModules());
|
|
23
|
+
const modules = $derived(modulesQuery.current ?? []);
|
|
24
|
+
const moduleIds = $derived(modules.map((m) => m.id));
|
|
25
|
+
const active = $derived(getActiveContext(moduleIds));
|
|
26
|
+
const lang = $derived(sidebarLang[interfaceLanguage.current].contexts);
|
|
27
|
+
|
|
28
|
+
function labelFor(id: string): string {
|
|
29
|
+
if (id === CONTENT_CONTEXT) return lang.content;
|
|
30
|
+
const m = modules.find((x) => x.id === id);
|
|
31
|
+
if (!m) return id;
|
|
32
|
+
return (
|
|
33
|
+
getLocalizedLabel(
|
|
34
|
+
(m.context.contextLabel ?? m.label) as Localized,
|
|
35
|
+
interfaceLanguage.current
|
|
36
|
+
) || m.id
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function iconFor(id: string) {
|
|
41
|
+
if (id === CONTENT_CONTEXT) return FileTextIcon;
|
|
42
|
+
const m = modules.find((x) => x.id === id);
|
|
43
|
+
return (m && getIcon(m.icon)) || FileTextIcon;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function choose(id: string) {
|
|
47
|
+
setActiveContext(id);
|
|
48
|
+
if (id === CONTENT_CONTEXT) {
|
|
49
|
+
goto('/admin');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const m = modules.find((x) => x.id === id);
|
|
53
|
+
goto(m?.context.landingUrl ?? '/admin');
|
|
54
|
+
}
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
{#if modulesQuery.ready && modules.length >= 1}
|
|
58
|
+
{@const ActiveIcon = iconFor(active)}
|
|
59
|
+
<DropdownMenu.Root>
|
|
60
|
+
<DropdownMenu.Trigger
|
|
61
|
+
aria-label={lang.switch}
|
|
62
|
+
class="border-input hover:bg-lavender-lighter hover:border-lavender focus-visible:ring-ring ml-auto inline-flex cursor-pointer items-center gap-1.5 rounded-md border bg-transparent px-2 py-1 text-[13px] font-medium outline-none focus-visible:ring-2 focus-visible:ring-offset-1 group-data-[collapsible=icon]:ml-0 group-data-[collapsible=icon]:px-1.5"
|
|
63
|
+
>
|
|
64
|
+
<ActiveIcon class="text-primary size-4 shrink-0" />
|
|
65
|
+
<span class="text-primary group-data-[collapsible=icon]:hidden">{labelFor(active)}</span>
|
|
66
|
+
<ChevronDownIcon class="size-3.5 shrink-0 opacity-60 group-data-[collapsible=icon]:hidden" />
|
|
67
|
+
</DropdownMenu.Trigger>
|
|
68
|
+
<DropdownMenu.Content align="start" class="w-52">
|
|
69
|
+
{@const ContentIcon = iconFor(CONTENT_CONTEXT)}
|
|
70
|
+
<DropdownMenu.Item onSelect={() => choose(CONTENT_CONTEXT)}>
|
|
71
|
+
<ContentIcon class="mr-2 size-4" />
|
|
72
|
+
<span class="flex-1">{labelFor(CONTENT_CONTEXT)}</span>
|
|
73
|
+
{#if active === CONTENT_CONTEXT}
|
|
74
|
+
<CheckIcon class="text-primary size-4" />
|
|
75
|
+
{/if}
|
|
76
|
+
</DropdownMenu.Item>
|
|
77
|
+
<DropdownMenu.Separator />
|
|
78
|
+
{#each modules as m (m.id)}
|
|
79
|
+
{@const MIcon = iconFor(m.id)}
|
|
80
|
+
<DropdownMenu.Item onSelect={() => choose(m.id)}>
|
|
81
|
+
<MIcon class="mr-2 size-4" />
|
|
82
|
+
<span class="flex-1">{labelFor(m.id)}</span>
|
|
83
|
+
{#if active === m.id}
|
|
84
|
+
<CheckIcon class="text-primary size-4" />
|
|
85
|
+
{/if}
|
|
86
|
+
</DropdownMenu.Item>
|
|
87
|
+
{/each}
|
|
88
|
+
</DropdownMenu.Content>
|
|
89
|
+
</DropdownMenu.Root>
|
|
90
|
+
{/if}
|
|
@@ -42,6 +42,10 @@ export const sidebarLang = {
|
|
|
42
42
|
primary: 'Główna nawigacja',
|
|
43
43
|
breadcrumb: 'Ścieżka okruszków',
|
|
44
44
|
skipToMain: 'Przejdź do głównej treści'
|
|
45
|
+
},
|
|
46
|
+
contexts: {
|
|
47
|
+
switch: 'Przełącz widok',
|
|
48
|
+
content: 'Treści'
|
|
45
49
|
}
|
|
46
50
|
},
|
|
47
51
|
en: {
|
|
@@ -87,6 +91,10 @@ export const sidebarLang = {
|
|
|
87
91
|
primary: 'Main navigation',
|
|
88
92
|
breadcrumb: 'Breadcrumb',
|
|
89
93
|
skipToMain: 'Skip to main content'
|
|
94
|
+
},
|
|
95
|
+
contexts: {
|
|
96
|
+
switch: 'Switch view',
|
|
97
|
+
content: 'Content'
|
|
90
98
|
}
|
|
91
99
|
}
|
|
92
100
|
};
|
|
@@ -109,7 +109,8 @@
|
|
|
109
109
|
const hasError =
|
|
110
110
|
!!errorPaths &&
|
|
111
111
|
collectLeafPathsForNodes([child], fields).some((p) => errorPaths!.has(p));
|
|
112
|
-
|
|
112
|
+
const preview = child.type === 'tab' ? child.preview : undefined;
|
|
113
|
+
return { value, label, child, hasError, preview };
|
|
113
114
|
});
|
|
114
115
|
}
|
|
115
116
|
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
child: LayoutNode;
|
|
12
12
|
/** True when a leaf field inside this tab is currently invalid. */
|
|
13
13
|
hasError: boolean;
|
|
14
|
+
/** Preview view this tab binds to (`TabNode.preview`), if any. */
|
|
15
|
+
preview?: string;
|
|
14
16
|
};
|
|
15
17
|
</script>
|
|
16
18
|
|
|
@@ -22,6 +24,7 @@
|
|
|
22
24
|
import { browser } from '$app/environment';
|
|
23
25
|
import { page } from '$app/state';
|
|
24
26
|
import { replaceState } from '$app/navigation';
|
|
27
|
+
import { getPreviewViewsContext } from '../../client/entry/preview-views-context.svelte.js';
|
|
25
28
|
|
|
26
29
|
type Props = {
|
|
27
30
|
tabs: TabInfo[];
|
|
@@ -44,6 +47,17 @@
|
|
|
44
47
|
|
|
45
48
|
let active = $state(initialValue());
|
|
46
49
|
|
|
50
|
+
const previewViews = getPreviewViewsContext();
|
|
51
|
+
|
|
52
|
+
// Tell the preview which view the active tab wants. Only the URL-synced
|
|
53
|
+
// (outermost) group drives it, so two tab groups never fight over the preview.
|
|
54
|
+
// Runs on mount too, so a `?tab=` deep-link lands on the right view.
|
|
55
|
+
$effect(() => {
|
|
56
|
+
if (!syncUrl || !previewViews) return;
|
|
57
|
+
const tab = tabs.find((t) => t.value === active);
|
|
58
|
+
if (tab) previewViews.onTabActivate(tab.value, tab.preview);
|
|
59
|
+
});
|
|
60
|
+
|
|
47
61
|
// Write the active tab back to the URL (outermost group only). Guard against
|
|
48
62
|
// the no-op case so we never trigger an infinite replaceState loop.
|
|
49
63
|
$effect(() => {
|
|
@@ -9,6 +9,8 @@ export type TabInfo = {
|
|
|
9
9
|
child: LayoutNode;
|
|
10
10
|
/** True when a leaf field inside this tab is currently invalid. */
|
|
11
11
|
hasError: boolean;
|
|
12
|
+
/** Preview view this tab binds to (`TabNode.preview`), if any. */
|
|
13
|
+
preview?: string;
|
|
12
14
|
};
|
|
13
15
|
import type { Snippet } from 'svelte';
|
|
14
16
|
type Props = {
|
|
@@ -11,16 +11,19 @@
|
|
|
11
11
|
import { getIcon } from '../icons/icon-map.js';
|
|
12
12
|
import NavSection, { type NavSectionItem } from './nav-section.svelte';
|
|
13
13
|
|
|
14
|
+
let { filterSlugs, ctx }: { filterSlugs?: string[]; ctx?: string } = $props();
|
|
15
|
+
|
|
14
16
|
const interfaceLanguage = useInterfaceLanguage();
|
|
15
17
|
const remotes = getRemotes();
|
|
16
18
|
const breadcrumbs = getBreadcrumbs();
|
|
17
19
|
|
|
18
20
|
function isActive(url: string) {
|
|
21
|
+
const base = url.split('?')[0];
|
|
19
22
|
const pathname = page.url.pathname;
|
|
20
|
-
if (pathname ===
|
|
23
|
+
if (pathname === base || pathname.startsWith(base + '/')) return true;
|
|
21
24
|
// Also highlight a collection while editing one of its entries — the entry
|
|
22
25
|
// page sets a breadcrumb linking back to the collection list.
|
|
23
|
-
return breadcrumbs.state.some((b) => b.href ===
|
|
26
|
+
return breadcrumbs.state.some((b) => b.href === base);
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
const collectionsQuery = $derived(remotes.getCollections());
|
|
@@ -41,16 +44,20 @@
|
|
|
41
44
|
});
|
|
42
45
|
|
|
43
46
|
const items: NavSectionItem[] = $derived(
|
|
44
|
-
collectionsQuery.current
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
(collectionsQuery.current ?? [])
|
|
48
|
+
.filter((item) => !filterSlugs || filterSlugs.includes(item.slug))
|
|
49
|
+
.map((item) => ({
|
|
50
|
+
title: getLocalizedLabel(item.labels?.plural, interfaceLanguage.current) ?? item.slug,
|
|
51
|
+
url: `/admin/collections/${item.slug}${ctx ? `?ctx=${ctx}` : ''}`,
|
|
52
|
+
icon: getIcon(item.sidebarIcon) ?? FolderIcon,
|
|
53
|
+
count: countsMap.get(item.slug)
|
|
54
|
+
}))
|
|
50
55
|
);
|
|
51
56
|
</script>
|
|
52
57
|
|
|
53
|
-
{#if
|
|
58
|
+
{#if filterSlugs && filterSlugs.length === 0}
|
|
59
|
+
<!-- no surfaced collections in this context -->
|
|
60
|
+
{:else if !collectionsQuery.ready}
|
|
54
61
|
<Sidebar.Group class="border-sidebar-border mt-1 border-t px-0 pt-2 pb-1">
|
|
55
62
|
<Sidebar.GroupLabel
|
|
56
63
|
>{sidebarLang[interfaceLanguage.current].collections.title}</Sidebar.GroupLabel
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
filterSlugs?: string[];
|
|
3
|
+
ctx?: string;
|
|
4
|
+
};
|
|
5
|
+
declare const NavCollections: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
2
6
|
type NavCollections = ReturnType<typeof NavCollections>;
|
|
3
7
|
export default NavCollections;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { sidebarLang } from './lang.js';
|
|
3
|
+
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
4
|
+
import CameraIcon from '@tabler/icons-svelte/icons/camera';
|
|
5
|
+
import UsersIcon from '@tabler/icons-svelte/icons/users';
|
|
6
|
+
import SettingsIcon from '@tabler/icons-svelte/icons/settings';
|
|
7
|
+
import { page } from '$app/state';
|
|
8
|
+
import { authClient } from '../../auth-client.js';
|
|
9
|
+
import NavSection, { type NavSectionItem } from './nav-section.svelte';
|
|
10
|
+
|
|
11
|
+
const interfaceLanguage = useInterfaceLanguage();
|
|
12
|
+
let session = authClient.useSession();
|
|
13
|
+
|
|
14
|
+
const isAdmin = $derived($session.data?.user?.role === 'admin');
|
|
15
|
+
|
|
16
|
+
const items: NavSectionItem[] = $derived([
|
|
17
|
+
{
|
|
18
|
+
title: sidebarLang[interfaceLanguage.current].main.media,
|
|
19
|
+
url: '/admin/media',
|
|
20
|
+
icon: CameraIcon
|
|
21
|
+
},
|
|
22
|
+
...(isAdmin
|
|
23
|
+
? [
|
|
24
|
+
{
|
|
25
|
+
title: sidebarLang[interfaceLanguage.current].main.users,
|
|
26
|
+
url: '/admin/users',
|
|
27
|
+
icon: UsersIcon
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
title: sidebarLang[interfaceLanguage.current].main.maintenance,
|
|
31
|
+
url: '/admin/maintenance',
|
|
32
|
+
icon: SettingsIcon
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
: [])
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
function isActive(url: string) {
|
|
39
|
+
return page.url.pathname.startsWith(url);
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<div class="mt-auto">
|
|
44
|
+
<NavSection {items} {isActive} withTopBorder />
|
|
45
|
+
</div>
|
|
@@ -1,49 +1,25 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { sidebarLang } from './lang.js';
|
|
3
3
|
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
4
|
-
import CameraIcon from '@tabler/icons-svelte/icons/camera';
|
|
5
4
|
import LayoutDashboardIcon from '@tabler/icons-svelte/icons/layout-dashboard';
|
|
6
|
-
import UsersIcon from '@tabler/icons-svelte/icons/users';
|
|
7
|
-
import SettingsIcon from '@tabler/icons-svelte/icons/settings';
|
|
8
5
|
import { page } from '$app/state';
|
|
9
|
-
import {
|
|
6
|
+
import type { Icon } from '@tabler/icons-svelte';
|
|
10
7
|
import NavSection, { type NavSectionItem } from './nav-section.svelte';
|
|
11
8
|
|
|
12
|
-
|
|
13
|
-
let session = authClient.useSession();
|
|
9
|
+
let { url = '/admin', icon = LayoutDashboardIcon }: { url?: string; icon?: Icon } = $props();
|
|
14
10
|
|
|
15
|
-
const
|
|
11
|
+
const interfaceLanguage = useInterfaceLanguage();
|
|
16
12
|
|
|
17
13
|
const items: NavSectionItem[] = $derived([
|
|
18
14
|
{
|
|
19
15
|
title: sidebarLang[interfaceLanguage.current].main.dashboard,
|
|
20
|
-
url
|
|
21
|
-
icon
|
|
22
|
-
}
|
|
23
|
-
{
|
|
24
|
-
title: sidebarLang[interfaceLanguage.current].main.media,
|
|
25
|
-
url: '/admin/media',
|
|
26
|
-
icon: CameraIcon
|
|
27
|
-
},
|
|
28
|
-
...(isAdmin
|
|
29
|
-
? [
|
|
30
|
-
{
|
|
31
|
-
title: sidebarLang[interfaceLanguage.current].main.users,
|
|
32
|
-
url: '/admin/users',
|
|
33
|
-
icon: UsersIcon
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
title: sidebarLang[interfaceLanguage.current].main.maintenance,
|
|
37
|
-
url: '/admin/maintenance',
|
|
38
|
-
icon: SettingsIcon
|
|
39
|
-
}
|
|
40
|
-
]
|
|
41
|
-
: [])
|
|
16
|
+
url,
|
|
17
|
+
icon
|
|
18
|
+
}
|
|
42
19
|
]);
|
|
43
20
|
|
|
44
|
-
function isActive(
|
|
45
|
-
|
|
46
|
-
return page.url.pathname.startsWith(url);
|
|
21
|
+
function isActive(u: string) {
|
|
22
|
+
return page.url.pathname === u.split('?')[0];
|
|
47
23
|
}
|
|
48
24
|
</script>
|
|
49
25
|
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Icon } from '@tabler/icons-svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
url?: string;
|
|
4
|
+
icon?: Icon;
|
|
5
|
+
};
|
|
6
|
+
declare const NavMain: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
2
7
|
type NavMain = ReturnType<typeof NavMain>;
|
|
3
8
|
export default NavMain;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
3
|
+
import { getLocalizedLabel } from '../../utils/collectionLabel.js';
|
|
4
|
+
import { getIcon } from '../icons/icon-map.js';
|
|
5
|
+
import { getRemotes } from '../../../sveltekit/index.js';
|
|
6
|
+
import { page } from '$app/state';
|
|
7
|
+
import BoxIcon from '@tabler/icons-svelte/icons/box';
|
|
8
|
+
import NavSection, { type NavSectionItem } from './nav-section.svelte';
|
|
9
|
+
import type { CMSModuleDescriptor } from '../../../types/modules.js';
|
|
10
|
+
import type { Localized } from '../../../types/languages.js';
|
|
11
|
+
|
|
12
|
+
let { module }: { module: CMSModuleDescriptor } = $props();
|
|
13
|
+
|
|
14
|
+
const interfaceLanguage = useInterfaceLanguage();
|
|
15
|
+
const remotes = getRemotes();
|
|
16
|
+
|
|
17
|
+
function isActive(url: string) {
|
|
18
|
+
const pathname = page.url.pathname;
|
|
19
|
+
const base = url.split('?')[0];
|
|
20
|
+
return pathname === base || pathname.startsWith(base + '/');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Optional reactive badges for sections declaring a `countSource` remote
|
|
24
|
+
// query (mirrors nav-collections' entry-count pattern). Dormant otherwise.
|
|
25
|
+
let countsMap: Map<string, number> = $state(new Map());
|
|
26
|
+
$effect(() => {
|
|
27
|
+
const map = new Map<string, number>();
|
|
28
|
+
for (const section of module.context.sections) {
|
|
29
|
+
if (!section.countSource) continue;
|
|
30
|
+
const fn = (remotes as Record<string, unknown>)[section.countSource];
|
|
31
|
+
if (typeof fn !== 'function') continue;
|
|
32
|
+
const q = (fn as () => { ready: boolean; current: unknown })();
|
|
33
|
+
if (q.ready && typeof q.current === 'number') map.set(section.key, q.current);
|
|
34
|
+
}
|
|
35
|
+
countsMap = map;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const label = $derived(
|
|
39
|
+
getLocalizedLabel(module.label as Localized, interfaceLanguage.current) || module.id
|
|
40
|
+
);
|
|
41
|
+
const items: NavSectionItem[] = $derived(
|
|
42
|
+
module.context.sections.map((s) => ({
|
|
43
|
+
title: getLocalizedLabel(s.title as Localized, interfaceLanguage.current) || s.url,
|
|
44
|
+
url: s.url,
|
|
45
|
+
icon: getIcon(s.icon) ?? BoxIcon,
|
|
46
|
+
count: countsMap.get(s.key)
|
|
47
|
+
}))
|
|
48
|
+
);
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<NavSection
|
|
52
|
+
{items}
|
|
53
|
+
{label}
|
|
54
|
+
labelIcon={getIcon(module.icon) ?? BoxIcon}
|
|
55
|
+
{isActive}
|
|
56
|
+
withTopBorder
|
|
57
|
+
/>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CMSModuleDescriptor } from '../../../types/modules.js';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
module: CMSModuleDescriptor;
|
|
4
|
+
};
|
|
5
|
+
declare const NavModule: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
6
|
+
type NavModule = ReturnType<typeof NavModule>;
|
|
7
|
+
export default NavModule;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
/**
|
|
3
3
|
* @internal
|
|
4
|
-
* Internal helper — DRY for sidebar nav-* sections (NavMain, NavCollections, NavSingletons, NavForms,
|
|
4
|
+
* Internal helper — DRY for sidebar nav-* sections (NavMain, NavCollections, NavSingletons, NavForms, NavModule).
|
|
5
5
|
* Not exported publicly. Sesja 4 (UI Normalization → 0.26.0).
|
|
6
6
|
*/
|
|
7
7
|
import type { Icon } from '@tabler/icons-svelte';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @internal
|
|
3
|
-
* Internal helper — DRY for sidebar nav-* sections (NavMain, NavCollections, NavSingletons, NavForms,
|
|
3
|
+
* Internal helper — DRY for sidebar nav-* sections (NavMain, NavCollections, NavSingletons, NavForms, NavModule).
|
|
4
4
|
* Not exported publicly. Sesja 4 (UI Normalization → 0.26.0).
|
|
5
5
|
*/
|
|
6
6
|
import type { Icon } from '@tabler/icons-svelte';
|
|
@@ -10,26 +10,33 @@
|
|
|
10
10
|
import { getIcon } from '../icons/icon-map.js';
|
|
11
11
|
import NavSection, { type NavSectionItem } from './nav-section.svelte';
|
|
12
12
|
|
|
13
|
+
let { filterSlugs, ctx }: { filterSlugs?: string[]; ctx?: string } = $props();
|
|
14
|
+
|
|
13
15
|
const interfaceLanguage = useInterfaceLanguage();
|
|
14
16
|
const remotes = getRemotes();
|
|
15
17
|
|
|
16
18
|
function isActive(url: string) {
|
|
19
|
+
const base = url.split('?')[0];
|
|
17
20
|
const pathname = page.url.pathname;
|
|
18
|
-
return pathname ===
|
|
21
|
+
return pathname === base || pathname.startsWith(base + '/');
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
const query = $derived(remotes.getSingles());
|
|
22
25
|
|
|
23
26
|
const items: NavSectionItem[] = $derived(
|
|
24
|
-
query.current
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
(query.current ?? [])
|
|
28
|
+
.filter((item) => !filterSlugs || filterSlugs.includes(item.slug))
|
|
29
|
+
.map((item) => ({
|
|
30
|
+
title: getLocalizedLabel(item.label, interfaceLanguage.current) ?? item.slug,
|
|
31
|
+
url: `/admin/entries/${item.slug}${ctx ? `?ctx=${ctx}` : ''}`,
|
|
32
|
+
icon: getIcon(item.sidebarIcon) ?? SettingsIcon
|
|
33
|
+
}))
|
|
29
34
|
);
|
|
30
35
|
</script>
|
|
31
36
|
|
|
32
|
-
{#if
|
|
37
|
+
{#if filterSlugs && filterSlugs.length === 0}
|
|
38
|
+
<!-- no surfaced singletons in this context -->
|
|
39
|
+
{:else if !query.ready}
|
|
33
40
|
<Sidebar.Group class="border-sidebar-border mt-1 border-t px-0 pt-2 pb-1">
|
|
34
41
|
<Sidebar.GroupLabel
|
|
35
42
|
>{sidebarLang[interfaceLanguage.current].singletons.title}</Sidebar.GroupLabel
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
filterSlugs?: string[];
|
|
3
|
+
ctx?: string;
|
|
4
|
+
};
|
|
5
|
+
declare const NavSingletons: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
2
6
|
type NavSingletons = ReturnType<typeof NavSingletons>;
|
|
3
7
|
export default NavSingletons;
|