@velastack/cms 0.4.0 → 0.5.1
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/README.md +140 -28
- package/dist/backend/index.d.ts +1 -1
- package/dist/backend/routes/seed.d.ts +6 -0
- package/dist/backend/routes/seed.js +96 -0
- package/dist/backend/routes/table.js +3 -0
- package/dist/backend/store/queries.d.ts +6 -1
- package/dist/backend/store/queries.js +89 -0
- package/dist/cms.js +13 -16
- package/dist/components/admin-bar/admin-bar-internal.svelte +4 -4
- package/dist/components/admin-bar/admin-bar.css +1 -1
- package/dist/components/admin-bar/field-input.svelte +239 -0
- package/dist/components/admin-bar/field-input.svelte.d.ts +30 -0
- package/dist/components/admin-bar/fields-form.svelte +218 -0
- package/dist/components/admin-bar/fields-form.svelte.d.ts +16 -0
- package/dist/components/admin-bar/icons/pencil.svelte +19 -0
- package/dist/components/admin-bar/icons/pencil.svelte.d.ts +3 -0
- package/dist/components/admin-bar/keyboard-shortcuts-dialog.svelte +1 -1
- package/dist/components/admin-bar/link-input.svelte +102 -0
- package/dist/components/admin-bar/link-input.svelte.d.ts +9 -0
- package/dist/components/admin-bar/list-field.svelte +93 -0
- package/dist/components/admin-bar/list-field.svelte.d.ts +20 -0
- package/dist/components/admin-bar/locales-panel.svelte +42 -1
- package/dist/components/admin-bar/page-config.d.ts +8 -1
- package/dist/components/admin-bar/page-config.js +15 -2
- package/dist/components/admin-bar/page-options.d.ts +24 -0
- package/dist/components/admin-bar/page-options.js +53 -0
- package/dist/components/admin-bar/reorder-buttons.svelte +52 -0
- package/dist/components/admin-bar/reorder-buttons.svelte.d.ts +10 -0
- package/dist/components/admin-bar/rich-text-input.svelte +92 -0
- package/dist/components/admin-bar/rich-text-input.svelte.d.ts +9 -0
- package/dist/components/admin-bar/seo-panel.svelte +144 -189
- package/dist/components/admin-bar/site-options-panel.svelte +115 -0
- package/dist/components/admin-bar/site-options-panel.svelte.d.ts +7 -0
- package/dist/components/admin-bar/structured-editor-popover.svelte +259 -0
- package/dist/components/admin-bar/structured-editor-popover.svelte.d.ts +48 -0
- package/dist/components/admin-bar/ui/checkbox/checkbox.svelte +36 -0
- package/dist/components/admin-bar/ui/checkbox/checkbox.svelte.d.ts +5 -0
- package/dist/components/admin-bar/ui/checkbox/index.d.ts +2 -0
- package/dist/components/admin-bar/ui/checkbox/index.js +2 -0
- package/dist/components/admin-bar/ui/popover/index.d.ts +5 -0
- package/dist/components/admin-bar/ui/popover/index.js +7 -0
- package/dist/components/admin-bar/ui/popover/popover-close.svelte +7 -0
- package/dist/components/admin-bar/ui/popover/popover-close.svelte.d.ts +4 -0
- package/dist/components/admin-bar/ui/popover/popover-content.svelte +35 -0
- package/dist/components/admin-bar/ui/popover/popover-content.svelte.d.ts +10 -0
- package/dist/components/admin-bar/ui/popover/popover-trigger.svelte +7 -0
- package/dist/components/admin-bar/ui/popover/popover-trigger.svelte.d.ts +4 -0
- package/dist/components/admin-bar/ui/popover/popover.svelte +7 -0
- package/dist/components/admin-bar/ui/popover/popover.svelte.d.ts +3 -0
- package/dist/components/admin-bar/ui/sheet/index.d.ts +10 -0
- package/dist/components/admin-bar/ui/sheet/index.js +12 -0
- package/dist/components/admin-bar/ui/sheet/sheet-close.svelte +7 -0
- package/dist/components/admin-bar/ui/sheet/sheet-close.svelte.d.ts +4 -0
- package/dist/components/admin-bar/ui/sheet/sheet-content.svelte +64 -0
- package/dist/components/admin-bar/ui/sheet/sheet-content.svelte.d.ts +17 -0
- package/dist/components/admin-bar/ui/sheet/sheet-description.svelte +17 -0
- package/dist/components/admin-bar/ui/sheet/sheet-description.svelte.d.ts +4 -0
- package/dist/components/admin-bar/ui/sheet/sheet-footer.svelte +23 -0
- package/dist/components/admin-bar/ui/sheet/sheet-footer.svelte.d.ts +5 -0
- package/dist/components/admin-bar/ui/sheet/sheet-header.svelte +20 -0
- package/dist/components/admin-bar/ui/sheet/sheet-header.svelte.d.ts +5 -0
- package/dist/components/admin-bar/ui/sheet/sheet-overlay.svelte +20 -0
- package/dist/components/admin-bar/ui/sheet/sheet-overlay.svelte.d.ts +4 -0
- package/dist/components/admin-bar/ui/sheet/sheet-title.svelte +17 -0
- package/dist/components/admin-bar/ui/sheet/sheet-title.svelte.d.ts +4 -0
- package/dist/components/admin-bar/ui/sheet/sheet-trigger.svelte +7 -0
- package/dist/components/admin-bar/ui/sheet/sheet-trigger.svelte.d.ts +4 -0
- package/dist/components/admin-bar/ui/sheet/sheet.svelte +7 -0
- package/dist/components/admin-bar/ui/sheet/sheet.svelte.d.ts +3 -0
- package/dist/components/admin-bar/ui/switch/index.d.ts +2 -0
- package/dist/components/admin-bar/ui/switch/index.js +2 -0
- package/dist/components/admin-bar/ui/switch/switch.svelte +27 -0
- package/dist/components/admin-bar/ui/switch/switch.svelte.d.ts +5 -0
- package/dist/components/admin-bar/ui/tabs/index.d.ts +5 -0
- package/dist/components/admin-bar/ui/tabs/index.js +7 -0
- package/dist/components/admin-bar/ui/tabs/tabs-content.svelte +17 -0
- package/dist/components/admin-bar/ui/tabs/tabs-content.svelte.d.ts +4 -0
- package/dist/components/admin-bar/ui/tabs/tabs-list.svelte +16 -0
- package/dist/components/admin-bar/ui/tabs/tabs-list.svelte.d.ts +4 -0
- package/dist/components/admin-bar/ui/tabs/tabs-trigger.svelte +20 -0
- package/dist/components/admin-bar/ui/tabs/tabs-trigger.svelte.d.ts +4 -0
- package/dist/components/admin-bar/ui/tabs/tabs.svelte +19 -0
- package/dist/components/admin-bar/ui/tabs/tabs.svelte.d.ts +4 -0
- package/dist/components/cms/cms-boolean.svelte +9 -18
- package/dist/components/cms/cms-boolean.svelte.d.ts +1 -0
- package/dist/components/cms/cms-collection.svelte +46 -0
- package/dist/components/cms/cms-collection.svelte.d.ts +25 -0
- package/dist/components/cms/cms-contact.svelte +26 -0
- package/dist/components/cms/cms-contact.svelte.d.ts +14 -0
- package/dist/components/cms/cms-date-time-editable.svelte +3 -3
- package/dist/components/cms/cms-date-time.svelte +17 -17
- package/dist/components/cms/cms-date-time.svelte.d.ts +2 -1
- package/dist/components/cms/cms-faq.svelte +22 -0
- package/dist/components/cms/cms-faq.svelte.d.ts +15 -0
- package/dist/components/cms/cms-gallery.svelte +31 -0
- package/dist/components/cms/cms-gallery.svelte.d.ts +16 -0
- package/dist/components/cms/cms-hours-editable.svelte +160 -0
- package/dist/components/cms/cms-hours-editable.svelte.d.ts +17 -0
- package/dist/components/cms/cms-hours.svelte +42 -0
- package/dist/components/cms/cms-hours.svelte.d.ts +19 -0
- package/dist/components/cms/cms-image-editable.svelte +13 -4
- package/dist/components/cms/cms-image.svelte +19 -34
- package/dist/components/cms/cms-image.svelte.d.ts +7 -8
- package/dist/components/cms/cms-link-editable.svelte +4 -60
- package/dist/components/cms/cms-link.svelte +15 -28
- package/dist/components/cms/cms-link.svelte.d.ts +4 -9
- package/dist/components/cms/cms-logos.svelte +29 -0
- package/dist/components/cms/cms-logos.svelte.d.ts +16 -0
- package/dist/components/cms/cms-markdown.svelte +15 -16
- package/dist/components/cms/cms-markdown.svelte.d.ts +1 -0
- package/dist/components/cms/cms-nav.svelte +22 -0
- package/dist/components/cms/cms-nav.svelte.d.ts +15 -0
- package/dist/components/cms/cms-number-editable.svelte +4 -2
- package/dist/components/cms/cms-number.svelte +18 -17
- package/dist/components/cms/cms-number.svelte.d.ts +2 -1
- package/dist/components/cms/cms-pricing.svelte +36 -0
- package/dist/components/cms/cms-pricing.svelte.d.ts +14 -0
- package/dist/components/cms/cms-rich-text.svelte +17 -22
- package/dist/components/cms/cms-rich-text.svelte.d.ts +1 -0
- package/dist/components/cms/cms-schedule.svelte +35 -0
- package/dist/components/cms/cms-schedule.svelte.d.ts +16 -0
- package/dist/components/cms/cms-social-links.svelte +35 -0
- package/dist/components/cms/cms-social-links.svelte.d.ts +15 -0
- package/dist/components/cms/cms-stats.svelte +31 -0
- package/dist/components/cms/cms-stats.svelte.d.ts +16 -0
- package/dist/components/cms/cms-steps.svelte +31 -0
- package/dist/components/cms/cms-steps.svelte.d.ts +16 -0
- package/dist/components/cms/cms-store.svelte.d.ts +14 -0
- package/dist/components/cms/cms-store.svelte.js +39 -2
- package/dist/components/cms/cms-structured-editable.svelte +29 -0
- package/dist/components/cms/{cms-repeater-editable.svelte.d.ts → cms-structured-editable.svelte.d.ts} +12 -8
- package/dist/components/cms/cms-structured.svelte +50 -0
- package/dist/components/cms/cms-structured.svelte.d.ts +49 -0
- package/dist/components/cms/cms-team.svelte +22 -0
- package/dist/components/cms/cms-team.svelte.d.ts +15 -0
- package/dist/components/cms/cms-testimonials.svelte +36 -0
- package/dist/components/cms/cms-testimonials.svelte.d.ts +15 -0
- package/dist/components/cms/cms-text.svelte +23 -30
- package/dist/components/cms/cms-text.svelte.d.ts +3 -1
- package/dist/components/cms/cms-timeline.svelte +35 -0
- package/dist/components/cms/cms-timeline.svelte.d.ts +16 -0
- package/dist/components/cms/index.d.ts +15 -1
- package/dist/components/cms/index.js +15 -1
- package/dist/components/cms/scope.d.ts +25 -5
- package/dist/components/cms/use-cms-field.svelte.d.ts +54 -0
- package/dist/components/cms/use-cms-field.svelte.js +83 -0
- package/dist/core/metadata.d.ts +44 -0
- package/dist/core/metadata.js +59 -0
- package/dist/core/shapes/collection.d.ts +60 -0
- package/dist/core/shapes/collection.js +194 -0
- package/dist/core/shapes/contact.d.ts +70 -0
- package/dist/core/shapes/contact.js +214 -0
- package/dist/core/shapes/faq.d.ts +12 -0
- package/dist/core/shapes/faq.js +48 -0
- package/dist/core/shapes/form.d.ts +46 -0
- package/dist/core/shapes/form.js +7 -0
- package/dist/core/shapes/hours.d.ts +91 -0
- package/dist/core/shapes/hours.js +325 -0
- package/dist/core/shapes/image.d.ts +15 -0
- package/dist/core/shapes/image.js +27 -0
- package/dist/core/shapes/index.d.ts +31 -0
- package/dist/core/shapes/index.js +13 -0
- package/dist/core/shapes/link.d.ts +15 -0
- package/dist/core/shapes/link.js +42 -0
- package/dist/core/shapes/nav.d.ts +21 -0
- package/dist/core/shapes/nav.js +71 -0
- package/dist/core/shapes/presets.d.ts +65 -0
- package/dist/core/shapes/presets.js +152 -0
- package/dist/core/shapes/pricing.d.ts +40 -0
- package/dist/core/shapes/pricing.js +115 -0
- package/dist/core/shapes/social-links.d.ts +19 -0
- package/dist/core/shapes/social-links.js +83 -0
- package/dist/core/shapes/team.d.ts +22 -0
- package/dist/core/shapes/team.js +70 -0
- package/dist/core/shapes/testimonials.d.ts +24 -0
- package/dist/core/shapes/testimonials.js +86 -0
- package/dist/core/structured-registry.d.ts +10 -0
- package/dist/core/structured-registry.js +6 -0
- package/dist/core/structured.d.ts +131 -0
- package/dist/core/structured.js +235 -0
- package/dist/core/wire.d.ts +31 -1
- package/dist/editor.d.ts +26 -0
- package/dist/editor.js +25 -0
- package/dist/index.d.ts +26 -4
- package/dist/index.js +31 -2
- package/dist/server/load-cms.js +1 -0
- package/package.json +12 -3
- package/plugin/README.md +22 -2
- package/plugin/dist/build.d.ts +74 -0
- package/plugin/dist/build.js +210 -0
- package/plugin/dist/build.js.map +1 -0
- package/plugin/dist/index.d.ts +10 -1
- package/plugin/dist/index.js +63 -4
- package/plugin/dist/index.js.map +1 -1
- package/plugin/dist/manifest.d.ts +31 -0
- package/plugin/dist/manifest.js +146 -41
- package/plugin/dist/manifest.js.map +1 -1
- package/plugin/dist/parse-svelte.d.ts +15 -0
- package/plugin/dist/parse-svelte.js +26 -16
- package/plugin/dist/parse-svelte.js.map +1 -1
- package/dist/components/admin-bar/site-settings-panel.svelte +0 -225
- package/dist/components/admin-bar/site-settings-panel.svelte.d.ts +0 -7
- package/dist/components/cms/cms-repeater-editable.svelte +0 -137
- package/dist/components/cms/cms-repeater.svelte +0 -55
- package/dist/components/cms/cms-repeater.svelte.d.ts +0 -30
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
export type CmsDateTimeProps = {
|
|
7
7
|
name: string;
|
|
8
|
+
scope?: string;
|
|
8
9
|
/**
|
|
9
10
|
* `'datetime'` (default) → `<input type="datetime-local">`, stores
|
|
10
11
|
* `YYYY-MM-DDTHH:MM`. `'date'` → `<input type="date">`, stores
|
|
@@ -13,44 +14,43 @@
|
|
|
13
14
|
*/
|
|
14
15
|
mode?: CmsDateTimeMode;
|
|
15
16
|
fallback?: string;
|
|
16
|
-
/** Per-item override used by
|
|
17
|
+
/** Per-item override used by structured components. */
|
|
17
18
|
value?: unknown;
|
|
18
19
|
children?: Snippet<[string]>;
|
|
19
20
|
};
|
|
20
21
|
</script>
|
|
21
22
|
|
|
22
23
|
<script lang="ts">
|
|
23
|
-
import {
|
|
24
|
-
import { cmsStore, type CmsScopeRef } from './cms-store.svelte.js';
|
|
24
|
+
import { useCmsField } from './use-cms-field.svelte.js';
|
|
25
25
|
|
|
26
|
-
let { name, mode = 'datetime', fallback, value, children }: CmsDateTimeProps = $props();
|
|
26
|
+
let { name, scope, mode = 'datetime', fallback, value, children }: CmsDateTimeProps = $props();
|
|
27
27
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
const field = useCmsField(
|
|
29
|
+
() => ({ name, scope, value }),
|
|
30
|
+
(raw): string | undefined => {
|
|
31
|
+
if (raw === undefined) return fallback;
|
|
32
|
+
return typeof raw === 'string' ? raw : '';
|
|
33
|
+
}
|
|
31
34
|
);
|
|
32
35
|
|
|
33
|
-
const
|
|
34
|
-
if (value !== undefined) return value;
|
|
35
|
-
return ref ? cmsStore.getValue(ref, name) : undefined;
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
const current = $derived(typeof resolved === 'string' ? resolved : fallback);
|
|
39
|
-
const editable = $derived(cmsStore.isEditing && value === undefined && !!ref);
|
|
36
|
+
const current = $derived(field.current);
|
|
40
37
|
</script>
|
|
41
38
|
|
|
42
|
-
{#if editable && ref}
|
|
39
|
+
{#if field.editable && field.ref}
|
|
43
40
|
{#await import('./cms-date-time-editable.svelte') then { default: Editable }}
|
|
44
|
-
<Editable scope={ref} {name} {mode} initial={current} />
|
|
41
|
+
<Editable scope={field.ref} {name} {mode} initial={current} />
|
|
45
42
|
{/await}
|
|
46
43
|
{:else if current && children}
|
|
47
44
|
{@render children(current)}
|
|
48
45
|
{:else if current}
|
|
49
46
|
{current}
|
|
47
|
+
{:else if field.raw === null}
|
|
48
|
+
<!-- cleared by the editor -->
|
|
50
49
|
{:else if children}
|
|
51
50
|
{@render children('')}
|
|
52
51
|
{:else}
|
|
53
|
-
<span class="cms-missing" data-cms-name={name} data-cms-scope={
|
|
52
|
+
<span class="cms-missing" data-cms-name={name} data-cms-scope={field.ref?.scopeId ?? '?'}
|
|
53
|
+
>{name}</span
|
|
54
54
|
>
|
|
55
55
|
{/if}
|
|
56
56
|
|
|
@@ -2,6 +2,7 @@ import type { Snippet } from 'svelte';
|
|
|
2
2
|
export type CmsDateTimeMode = 'datetime' | 'date' | 'time';
|
|
3
3
|
export type CmsDateTimeProps = {
|
|
4
4
|
name: string;
|
|
5
|
+
scope?: string;
|
|
5
6
|
/**
|
|
6
7
|
* `'datetime'` (default) → `<input type="datetime-local">`, stores
|
|
7
8
|
* `YYYY-MM-DDTHH:MM`. `'date'` → `<input type="date">`, stores
|
|
@@ -10,7 +11,7 @@ export type CmsDateTimeProps = {
|
|
|
10
11
|
*/
|
|
11
12
|
mode?: CmsDateTimeMode;
|
|
12
13
|
fallback?: string;
|
|
13
|
-
/** Per-item override used by
|
|
14
|
+
/** Per-item override used by structured components. */
|
|
14
15
|
value?: unknown;
|
|
15
16
|
children?: Snippet<[string]>;
|
|
16
17
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
/** `CmsFaq`: questions and rich answers. */
|
|
3
|
+
export * from '../../core/shapes/faq.js';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<script lang="ts">
|
|
7
|
+
import type { Snippet } from 'svelte';
|
|
8
|
+
import Structured from './cms-structured.svelte';
|
|
9
|
+
import { cmsFaq, faqView, type CmsFaqValue, type FaqItem } from '../../core/shapes/faq.js';
|
|
10
|
+
|
|
11
|
+
type Props = {
|
|
12
|
+
name: string;
|
|
13
|
+
scope?: string;
|
|
14
|
+
/** The full value, or a bare item list. */
|
|
15
|
+
fallback?: Partial<CmsFaqValue> | Array<Partial<CmsFaqValue['items'][number]>>;
|
|
16
|
+
value?: unknown;
|
|
17
|
+
children: Snippet<[FaqItem[]]>;
|
|
18
|
+
};
|
|
19
|
+
let { name, scope, fallback, value, children }: Props = $props();
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<Structured schema={cmsFaq} {name} {scope} {fallback} {value} view={faqView} {children} />
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** `CmsFaq`: questions and rich answers. */
|
|
2
|
+
export * from '../../core/shapes/faq.js';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
import { type CmsFaqValue, type FaqItem } from '../../core/shapes/faq.js';
|
|
5
|
+
type Props = {
|
|
6
|
+
name: string;
|
|
7
|
+
scope?: string;
|
|
8
|
+
/** The full value, or a bare item list. */
|
|
9
|
+
fallback?: Partial<CmsFaqValue> | Array<Partial<CmsFaqValue['items'][number]>>;
|
|
10
|
+
value?: unknown;
|
|
11
|
+
children: Snippet<[FaqItem[]]>;
|
|
12
|
+
};
|
|
13
|
+
declare const CmsFaq: import("svelte").Component<Props, {}, "">;
|
|
14
|
+
type CmsFaq = ReturnType<typeof CmsFaq>;
|
|
15
|
+
export default CmsFaq;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
/** `CmsGallery` preset: image and caption. */
|
|
3
|
+
export type { CmsGalleryValue, GalleryItem } from '../../core/shapes/presets.js';
|
|
4
|
+
export { cmsGallery } from '../../core/shapes/presets.js';
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
import type { Snippet } from 'svelte';
|
|
9
|
+
import Structured from './cms-structured.svelte';
|
|
10
|
+
import { cmsGallery, type CmsGalleryValue, type GalleryItem } from '../../core/shapes/presets.js';
|
|
11
|
+
|
|
12
|
+
type Props = {
|
|
13
|
+
name: string;
|
|
14
|
+
scope?: string;
|
|
15
|
+
/** The full value, or a bare item list. */
|
|
16
|
+
fallback?: Partial<CmsGalleryValue> | Partial<GalleryItem>[];
|
|
17
|
+
value?: unknown;
|
|
18
|
+
children: Snippet<[GalleryItem[]]>;
|
|
19
|
+
};
|
|
20
|
+
let { name, scope, fallback, value, children }: Props = $props();
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<Structured
|
|
24
|
+
schema={cmsGallery}
|
|
25
|
+
{name}
|
|
26
|
+
{scope}
|
|
27
|
+
{fallback}
|
|
28
|
+
{value}
|
|
29
|
+
view={(v: CmsGalleryValue) => v.items.filter((i) => i.image !== null)}
|
|
30
|
+
{children}
|
|
31
|
+
/>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** `CmsGallery` preset: image and caption. */
|
|
2
|
+
export type { CmsGalleryValue, GalleryItem } from '../../core/shapes/presets.js';
|
|
3
|
+
export { cmsGallery } from '../../core/shapes/presets.js';
|
|
4
|
+
import type { Snippet } from 'svelte';
|
|
5
|
+
import { type CmsGalleryValue, type GalleryItem } from '../../core/shapes/presets.js';
|
|
6
|
+
type Props = {
|
|
7
|
+
name: string;
|
|
8
|
+
scope?: string;
|
|
9
|
+
/** The full value, or a bare item list. */
|
|
10
|
+
fallback?: Partial<CmsGalleryValue> | Partial<GalleryItem>[];
|
|
11
|
+
value?: unknown;
|
|
12
|
+
children: Snippet<[GalleryItem[]]>;
|
|
13
|
+
};
|
|
14
|
+
declare const CmsGallery: import("svelte").Component<Props, {}, "">;
|
|
15
|
+
type CmsGallery = ReturnType<typeof CmsGallery>;
|
|
16
|
+
export default CmsGallery;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* The bespoke editor for `CmsHours`: a week grid (closed toggle, one or
|
|
4
|
+
* two ranges per day, copy Monday across) above the shape's other fields
|
|
5
|
+
* (note, exceptions, labels) rendered through the generic form.
|
|
6
|
+
*/
|
|
7
|
+
import type { Snippet } from 'svelte';
|
|
8
|
+
import type { Tree } from '../../core/path.js';
|
|
9
|
+
import type { FormShape } from '../../core/shapes/form.js';
|
|
10
|
+
import {
|
|
11
|
+
DAY_KEYS,
|
|
12
|
+
dayNames,
|
|
13
|
+
type CmsHoursValue,
|
|
14
|
+
type DayKey,
|
|
15
|
+
type HoursRange
|
|
16
|
+
} from '../../core/shapes/hours.js';
|
|
17
|
+
import type { CmsField } from './use-cms-field.svelte.js';
|
|
18
|
+
import { cmsStore } from './cms-store.svelte.js';
|
|
19
|
+
import StructuredEditorPopover from '../admin-bar/structured-editor-popover.svelte';
|
|
20
|
+
import FieldsForm from '../admin-bar/fields-form.svelte';
|
|
21
|
+
import { Button } from '../admin-bar/ui/button/index.js';
|
|
22
|
+
import { Input } from '../admin-bar/ui/input/index.js';
|
|
23
|
+
import { Switch } from '../admin-bar/ui/switch/index.js';
|
|
24
|
+
|
|
25
|
+
type Props = {
|
|
26
|
+
field: CmsField<CmsHoursValue>;
|
|
27
|
+
schema: FormShape<CmsHoursValue>;
|
|
28
|
+
preview: Snippet;
|
|
29
|
+
};
|
|
30
|
+
let { field, schema, preview }: Props = $props();
|
|
31
|
+
|
|
32
|
+
const names = $derived(dayNames(cmsStore.activeLocale || 'en', 'long'));
|
|
33
|
+
const DEFAULT_RANGE: HoursRange = { open: '09:00', close: '17:00' };
|
|
34
|
+
|
|
35
|
+
const setDay = (
|
|
36
|
+
draft: CmsHoursValue,
|
|
37
|
+
key: DayKey,
|
|
38
|
+
patch: Partial<CmsHoursValue['days'][DayKey]>
|
|
39
|
+
) => ({
|
|
40
|
+
...draft,
|
|
41
|
+
days: { ...draft.days, [key]: { ...draft.days[key], ...patch } }
|
|
42
|
+
});
|
|
43
|
+
const setRange = (
|
|
44
|
+
draft: CmsHoursValue,
|
|
45
|
+
key: DayKey,
|
|
46
|
+
index: number,
|
|
47
|
+
patch: Partial<HoursRange>
|
|
48
|
+
): CmsHoursValue =>
|
|
49
|
+
setDay(draft, key, {
|
|
50
|
+
ranges: draft.days[key].ranges.map((r, i) => (i === index ? { ...r, ...patch } : r))
|
|
51
|
+
});
|
|
52
|
+
const toggleClosed = (draft: CmsHoursValue, key: DayKey, closed: boolean): CmsHoursValue =>
|
|
53
|
+
setDay(draft, key, {
|
|
54
|
+
closed,
|
|
55
|
+
ranges:
|
|
56
|
+
!closed && draft.days[key].ranges.length === 0 ? [DEFAULT_RANGE] : draft.days[key].ranges
|
|
57
|
+
});
|
|
58
|
+
const copyMonday = (draft: CmsHoursValue, keys: readonly DayKey[]): CmsHoursValue => {
|
|
59
|
+
const mon = draft.days.mon;
|
|
60
|
+
const days = { ...draft.days };
|
|
61
|
+
for (const k of keys)
|
|
62
|
+
days[k] = { closed: mon.closed, ranges: mon.ranges.map((r) => ({ ...r })) };
|
|
63
|
+
return { ...draft, days };
|
|
64
|
+
};
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<StructuredEditorPopover {field} {schema} label={schema.label} {preview}>
|
|
68
|
+
{#snippet editor(draft: CmsHoursValue, update: (next: CmsHoursValue) => void)}
|
|
69
|
+
<div class="vela:flex vela:flex-col vela:gap-2">
|
|
70
|
+
{#each DAY_KEYS as key (key)}
|
|
71
|
+
{@const day = draft.days[key]}
|
|
72
|
+
<div class="vela:flex vela:items-start vela:gap-2">
|
|
73
|
+
<label
|
|
74
|
+
class="vela:flex vela:w-24 vela:shrink-0 vela:items-center vela:gap-2 vela:pt-2 vela:text-[13px] vela:text-bar-text"
|
|
75
|
+
>
|
|
76
|
+
<Switch
|
|
77
|
+
checked={!day.closed}
|
|
78
|
+
onCheckedChange={(open) => update(toggleClosed(draft, key, !open))}
|
|
79
|
+
aria-label={`${names[key]} open`}
|
|
80
|
+
/>
|
|
81
|
+
<span class="vela:truncate">{names[key]}</span>
|
|
82
|
+
</label>
|
|
83
|
+
<div class="vela:flex vela:flex-1 vela:flex-col vela:gap-1">
|
|
84
|
+
{#if day.closed}
|
|
85
|
+
<span class="vela:pt-2 vela:text-[12px] vela:text-bar-text-tertiary"
|
|
86
|
+
>{draft.labels.closed}</span
|
|
87
|
+
>
|
|
88
|
+
{:else}
|
|
89
|
+
{#each day.ranges as range, i (i)}
|
|
90
|
+
<div class="vela:flex vela:items-center vela:gap-1">
|
|
91
|
+
<Input
|
|
92
|
+
type="time"
|
|
93
|
+
value={range.open}
|
|
94
|
+
aria-label={`${names[key]} opens`}
|
|
95
|
+
oninput={(e) =>
|
|
96
|
+
update(setRange(draft, key, i, { open: e.currentTarget.value }))}
|
|
97
|
+
/>
|
|
98
|
+
<span class="vela:text-bar-text-tertiary">–</span>
|
|
99
|
+
<Input
|
|
100
|
+
type="time"
|
|
101
|
+
value={range.close}
|
|
102
|
+
aria-label={`${names[key]} closes`}
|
|
103
|
+
oninput={(e) =>
|
|
104
|
+
update(setRange(draft, key, i, { close: e.currentTarget.value }))}
|
|
105
|
+
/>
|
|
106
|
+
{#if day.ranges.length > 1}
|
|
107
|
+
<Button
|
|
108
|
+
size="icon"
|
|
109
|
+
variant="ghost"
|
|
110
|
+
class="vela:h-6 vela:w-6 vela:shrink-0"
|
|
111
|
+
aria-label="Remove shift"
|
|
112
|
+
onclick={() =>
|
|
113
|
+
update(
|
|
114
|
+
setDay(draft, key, { ranges: day.ranges.filter((_, j) => j !== i) })
|
|
115
|
+
)}
|
|
116
|
+
>
|
|
117
|
+
×
|
|
118
|
+
</Button>
|
|
119
|
+
{:else}
|
|
120
|
+
<Button
|
|
121
|
+
size="xs"
|
|
122
|
+
variant="ghost"
|
|
123
|
+
class="vela:shrink-0"
|
|
124
|
+
aria-label="Add a second shift"
|
|
125
|
+
onclick={() =>
|
|
126
|
+
update(
|
|
127
|
+
setDay(draft, key, {
|
|
128
|
+
ranges: [...day.ranges, { open: '18:00', close: '22:00' }]
|
|
129
|
+
})
|
|
130
|
+
)}
|
|
131
|
+
>
|
|
132
|
+
+ Split
|
|
133
|
+
</Button>
|
|
134
|
+
{/if}
|
|
135
|
+
</div>
|
|
136
|
+
{/each}
|
|
137
|
+
{/if}
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
{/each}
|
|
141
|
+
<div class="vela:flex vela:gap-1.5">
|
|
142
|
+
<Button
|
|
143
|
+
variant="outline"
|
|
144
|
+
size="pill"
|
|
145
|
+
onclick={() => update(copyMonday(draft, ['tue', 'wed', 'thu', 'fri']))}
|
|
146
|
+
>
|
|
147
|
+
Copy Monday to weekdays
|
|
148
|
+
</Button>
|
|
149
|
+
<Button variant="outline" size="pill" onclick={() => update(copyMonday(draft, DAY_KEYS))}>
|
|
150
|
+
Copy to all
|
|
151
|
+
</Button>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
<FieldsForm
|
|
155
|
+
fields={schema.fields}
|
|
156
|
+
value={draft as unknown as Tree}
|
|
157
|
+
onChange={(next) => update(next as unknown as CmsHoursValue)}
|
|
158
|
+
/>
|
|
159
|
+
{/snippet}
|
|
160
|
+
</StructuredEditorPopover>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bespoke editor for `CmsHours`: a week grid (closed toggle, one or
|
|
3
|
+
* two ranges per day, copy Monday across) above the shape's other fields
|
|
4
|
+
* (note, exceptions, labels) rendered through the generic form.
|
|
5
|
+
*/
|
|
6
|
+
import type { Snippet } from 'svelte';
|
|
7
|
+
import type { FormShape } from '../../core/shapes/form.js';
|
|
8
|
+
import { type CmsHoursValue } from '../../core/shapes/hours.js';
|
|
9
|
+
import type { CmsField } from './use-cms-field.svelte.js';
|
|
10
|
+
type Props = {
|
|
11
|
+
field: CmsField<CmsHoursValue>;
|
|
12
|
+
schema: FormShape<CmsHoursValue>;
|
|
13
|
+
preview: Snippet;
|
|
14
|
+
};
|
|
15
|
+
declare const CmsHoursEditable: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
type CmsHoursEditable = ReturnType<typeof CmsHoursEditable>;
|
|
17
|
+
export default CmsHoursEditable;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
/**
|
|
3
|
+
* `CmsHours`: opening hours, edited in a week grid and rendered from the
|
|
4
|
+
* derived view (`rows`, `today`, `isOpenNow`) in the visitor's locale.
|
|
5
|
+
* `isOpenNow` is computed when the page renders; a prerendered page
|
|
6
|
+
* shows the state at build time.
|
|
7
|
+
*/
|
|
8
|
+
export * from '../../core/shapes/hours.js';
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<script lang="ts">
|
|
12
|
+
import type { Snippet } from 'svelte';
|
|
13
|
+
import Structured from './cms-structured.svelte';
|
|
14
|
+
import { cmsStore } from './cms-store.svelte.js';
|
|
15
|
+
import {
|
|
16
|
+
cmsHours,
|
|
17
|
+
hoursView,
|
|
18
|
+
type CmsHoursValue,
|
|
19
|
+
type HoursView
|
|
20
|
+
} from '../../core/shapes/hours.js';
|
|
21
|
+
|
|
22
|
+
type Props = {
|
|
23
|
+
name: string;
|
|
24
|
+
scope?: string;
|
|
25
|
+
fallback?: Partial<CmsHoursValue>;
|
|
26
|
+
value?: unknown;
|
|
27
|
+
children: Snippet<[HoursView]>;
|
|
28
|
+
};
|
|
29
|
+
let { name, scope, fallback, value, children }: Props = $props();
|
|
30
|
+
const locale = $derived(cmsStore.activeLocale || 'en');
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<Structured
|
|
34
|
+
schema={cmsHours}
|
|
35
|
+
{name}
|
|
36
|
+
{scope}
|
|
37
|
+
{fallback}
|
|
38
|
+
{value}
|
|
39
|
+
view={(v: CmsHoursValue) => hoursView(v, locale)}
|
|
40
|
+
editable={() => import('./cms-hours-editable.svelte')}
|
|
41
|
+
{children}
|
|
42
|
+
/>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `CmsHours`: opening hours, edited in a week grid and rendered from the
|
|
3
|
+
* derived view (`rows`, `today`, `isOpenNow`) in the visitor's locale.
|
|
4
|
+
* `isOpenNow` is computed when the page renders; a prerendered page
|
|
5
|
+
* shows the state at build time.
|
|
6
|
+
*/
|
|
7
|
+
export * from '../../core/shapes/hours.js';
|
|
8
|
+
import type { Snippet } from 'svelte';
|
|
9
|
+
import { type CmsHoursValue, type HoursView } from '../../core/shapes/hours.js';
|
|
10
|
+
type Props = {
|
|
11
|
+
name: string;
|
|
12
|
+
scope?: string;
|
|
13
|
+
fallback?: Partial<CmsHoursValue>;
|
|
14
|
+
value?: unknown;
|
|
15
|
+
children: Snippet<[HoursView]>;
|
|
16
|
+
};
|
|
17
|
+
declare const CmsHours: import("svelte").Component<Props, {}, "">;
|
|
18
|
+
type CmsHours = ReturnType<typeof CmsHours>;
|
|
19
|
+
export default CmsHours;
|
|
@@ -29,13 +29,17 @@
|
|
|
29
29
|
// Read leaves through `getValue` so live drafts reflect immediately. Fall
|
|
30
30
|
// back to the snapshot the display passed in when nothing's been written.
|
|
31
31
|
const currentUrl = $derived.by(() => {
|
|
32
|
-
const
|
|
32
|
+
const stored = cmsStore.getValue(scope, name);
|
|
33
|
+
const v = pathGet(stored, 'url');
|
|
33
34
|
if (typeof v === 'string') return v;
|
|
35
|
+
if (v === null || stored === null) return '';
|
|
34
36
|
return initial.url ?? '';
|
|
35
37
|
});
|
|
36
38
|
const currentAlt = $derived.by(() => {
|
|
37
|
-
const
|
|
39
|
+
const stored = cmsStore.getValue(scope, name);
|
|
40
|
+
const v = pathGet(stored, 'alt');
|
|
38
41
|
if (typeof v === 'string') return v;
|
|
42
|
+
if (v === null || stored === null) return '';
|
|
39
43
|
return initial.alt ?? '';
|
|
40
44
|
});
|
|
41
45
|
|
|
@@ -55,8 +59,13 @@
|
|
|
55
59
|
let uploading = $state(false);
|
|
56
60
|
let error: string | null = $state(null);
|
|
57
61
|
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
// Whole-object writes (see `core/structured.ts`): a cleared image is
|
|
63
|
+
// `{ url: null }`, which merges over the published tree as "cleared"
|
|
64
|
+
// instead of falling back to the template's demo image.
|
|
65
|
+
const writeUrl = (v: string) =>
|
|
66
|
+
cmsStore.setValue(scope, name, { url: v || null, alt: currentAlt || null });
|
|
67
|
+
const writeAlt = (v: string) =>
|
|
68
|
+
cmsStore.setValue(scope, name, { url: currentUrl || null, alt: v || null });
|
|
60
69
|
|
|
61
70
|
const upload = async (file: File) => {
|
|
62
71
|
if (!file.type.startsWith('image/')) {
|
|
@@ -1,62 +1,47 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
alt?: string;
|
|
5
|
-
width?: number;
|
|
6
|
-
height?: number;
|
|
7
|
-
};
|
|
2
|
+
export { normalizeImage } from '../../core/shapes/image.js';
|
|
3
|
+
export type { CmsImageValue } from '../../core/shapes/image.js';
|
|
8
4
|
</script>
|
|
9
5
|
|
|
10
6
|
<script lang="ts">
|
|
11
7
|
import type { Snippet } from 'svelte';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
8
|
+
import { useCmsField } from './use-cms-field.svelte.js';
|
|
9
|
+
import { normalizeImage, type CmsImageValue } from '../../core/shapes/image.js';
|
|
14
10
|
|
|
15
11
|
type Props = {
|
|
16
12
|
name: string;
|
|
17
|
-
|
|
13
|
+
scope?: string;
|
|
14
|
+
/** Fallback alt text used when the stored value has no `alt`. */
|
|
18
15
|
alt?: string;
|
|
19
|
-
|
|
16
|
+
/** A URL, or a full `{ url, alt }` value. */
|
|
17
|
+
fallback?: string | CmsImageValue;
|
|
20
18
|
value?: unknown;
|
|
21
19
|
children?: Snippet;
|
|
22
20
|
};
|
|
23
21
|
|
|
24
|
-
let { name, alt = '', fallback, value, children }: Props = $props();
|
|
22
|
+
let { name, scope, alt = '', fallback, value, children }: Props = $props();
|
|
25
23
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
const field = useCmsField(
|
|
25
|
+
() => ({ name, scope, value }),
|
|
26
|
+
(raw): CmsImageValue => (raw === undefined ? normalizeImage(fallback) : normalizeImage(raw))
|
|
29
27
|
);
|
|
30
28
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
return ref ? cmsStore.getValue(ref, name) : undefined;
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// `<CmsImage>` owns a `{ url, alt, width?, height? }` branch. Accept a bare
|
|
37
|
-
// string as the URL leaf for legacy/value-prop callers.
|
|
38
|
-
const branch = $derived.by((): CmsImageValue | null => {
|
|
39
|
-
if (resolved == null) return null;
|
|
40
|
-
if (typeof resolved === 'string') return { url: resolved };
|
|
41
|
-
if (typeof resolved === 'object' && !Array.isArray(resolved)) return resolved as CmsImageValue;
|
|
42
|
-
return null;
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const src = $derived(branch?.url ?? fallback ?? '');
|
|
46
|
-
const altText = $derived(branch?.alt ?? alt ?? '');
|
|
47
|
-
const editable = $derived(cmsStore.isEditing && value === undefined && !!ref);
|
|
29
|
+
const src = $derived(field.current.url ?? '');
|
|
30
|
+
const altText = $derived(field.current.alt ?? alt);
|
|
48
31
|
</script>
|
|
49
32
|
|
|
50
|
-
{#if editable && ref}
|
|
33
|
+
{#if field.editable && field.ref}
|
|
51
34
|
{#await import('./cms-image-editable.svelte') then { default: Editable }}
|
|
52
|
-
<Editable scope={ref} {name} initial={
|
|
35
|
+
<Editable scope={field.ref} {name} initial={field.current} fallbackAlt={alt} />
|
|
53
36
|
{/await}
|
|
54
37
|
{:else if src}
|
|
55
38
|
<img class="cms-image" {src} alt={altText} />
|
|
39
|
+
{:else if field.raw === null}
|
|
40
|
+
<!-- cleared by the editor -->
|
|
56
41
|
{:else if children}
|
|
57
42
|
{@render children()}
|
|
58
43
|
{:else}
|
|
59
|
-
<span class="cms-missing" data-cms-name={name} data-cms-scope={
|
|
44
|
+
<span class="cms-missing" data-cms-name={name} data-cms-scope={field.ref?.scopeId ?? '?'}>
|
|
60
45
|
{name}
|
|
61
46
|
</span>
|
|
62
47
|
{/if}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
alt?: string;
|
|
4
|
-
width?: number;
|
|
5
|
-
height?: number;
|
|
6
|
-
};
|
|
1
|
+
export { normalizeImage } from '../../core/shapes/image.js';
|
|
2
|
+
export type { CmsImageValue } from '../../core/shapes/image.js';
|
|
7
3
|
import type { Snippet } from 'svelte';
|
|
4
|
+
import { type CmsImageValue } from '../../core/shapes/image.js';
|
|
8
5
|
type Props = {
|
|
9
6
|
name: string;
|
|
10
|
-
|
|
7
|
+
scope?: string;
|
|
8
|
+
/** Fallback alt text used when the stored value has no `alt`. */
|
|
11
9
|
alt?: string;
|
|
12
|
-
|
|
10
|
+
/** A URL, or a full `{ url, alt }` value. */
|
|
11
|
+
fallback?: string | CmsImageValue;
|
|
13
12
|
value?: unknown;
|
|
14
13
|
children?: Snippet;
|
|
15
14
|
};
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { page } from '$app/state';
|
|
5
5
|
import { cmsStore, type CmsScopeRef } from './cms-store.svelte.js';
|
|
6
6
|
import { resolveRouteUrl } from '../admin-bar/resolve-route.js';
|
|
7
|
+
import { fetchPageOptions, pageOptionValue, type PageOption } from '../admin-bar/page-options.js';
|
|
7
8
|
import type { CmsLinkValue, CmsLinkRenderProps } from './cms-link.svelte';
|
|
8
9
|
import { Button } from '../admin-bar/ui/button/index.js';
|
|
9
10
|
import { Input } from '../admin-bar/ui/input/index.js';
|
|
@@ -16,19 +17,6 @@
|
|
|
16
17
|
import XIcon from '../admin-bar/icons/x.svelte';
|
|
17
18
|
import Trash from '../admin-bar/icons/trash-2.svelte';
|
|
18
19
|
|
|
19
|
-
type PageEntry = {
|
|
20
|
-
params: Record<string, string>;
|
|
21
|
-
isDraft: boolean;
|
|
22
|
-
isDeletePending: boolean;
|
|
23
|
-
redirectTo?: string;
|
|
24
|
-
gone?: boolean;
|
|
25
|
-
};
|
|
26
|
-
type PageRoute = {
|
|
27
|
-
routeId: string;
|
|
28
|
-
ownedParams: string[];
|
|
29
|
-
entries: PageEntry[];
|
|
30
|
-
};
|
|
31
|
-
|
|
32
20
|
type Props = {
|
|
33
21
|
scope: CmsScopeRef;
|
|
34
22
|
name: string;
|
|
@@ -65,7 +53,7 @@
|
|
|
65
53
|
let urlInput = $state('');
|
|
66
54
|
let urlInputEl: HTMLInputElement | null = $state(null);
|
|
67
55
|
|
|
68
|
-
let
|
|
56
|
+
let pageOptions: PageOption[] = $state([]);
|
|
69
57
|
let pagesLoaded = $state(false);
|
|
70
58
|
let selectedValue = $state('');
|
|
71
59
|
let pageSelectOpen = $state(false);
|
|
@@ -128,61 +116,17 @@
|
|
|
128
116
|
else if (e.key === 'Escape') cancelMode(e);
|
|
129
117
|
};
|
|
130
118
|
|
|
131
|
-
const optionValueFor = (routeId: string, params: Record<string, string>) =>
|
|
132
|
-
`${routeId}::${JSON.stringify(params)}`;
|
|
133
|
-
|
|
134
119
|
const enterPageMode = async (e: Event) => {
|
|
135
120
|
e.preventDefault();
|
|
136
121
|
e.stopPropagation();
|
|
137
|
-
selectedValue = current.routeId ?
|
|
122
|
+
selectedValue = current.routeId ? pageOptionValue(current.routeId, current.params ?? {}) : '';
|
|
138
123
|
mode = 'page';
|
|
139
124
|
if (!pagesLoaded) {
|
|
140
|
-
|
|
141
|
-
const res = await fetch(`${endpoint}/pages`, { credentials: 'include' });
|
|
142
|
-
if (res.ok) {
|
|
143
|
-
const data = (await res.json()) as { routes: PageRoute[] };
|
|
144
|
-
pages = data.routes;
|
|
145
|
-
}
|
|
146
|
-
} catch {
|
|
147
|
-
/* ignore — picker shows "No pages found" */
|
|
148
|
-
}
|
|
125
|
+
pageOptions = await fetchPageOptions(endpoint);
|
|
149
126
|
pagesLoaded = true;
|
|
150
127
|
}
|
|
151
128
|
};
|
|
152
129
|
|
|
153
|
-
const pageOptions = $derived.by(() => {
|
|
154
|
-
const opts: {
|
|
155
|
-
value: string;
|
|
156
|
-
label: string;
|
|
157
|
-
routeId: string;
|
|
158
|
-
params: Record<string, string>;
|
|
159
|
-
}[] = [];
|
|
160
|
-
for (const r of pages) {
|
|
161
|
-
const entries =
|
|
162
|
-
r.entries.length > 0
|
|
163
|
-
? r.entries
|
|
164
|
-
: [{ params: {} as Record<string, string>, isDraft: false, isDeletePending: false }];
|
|
165
|
-
for (const ent of entries) {
|
|
166
|
-
// Tombstones (redirected / gone) aren't real link targets.
|
|
167
|
-
if (ent.redirectTo || ent.gone) continue;
|
|
168
|
-
let url: string;
|
|
169
|
-
try {
|
|
170
|
-
url = resolveRouteUrl(r.routeId, ent.params);
|
|
171
|
-
} catch {
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
opts.push({
|
|
175
|
-
value: optionValueFor(r.routeId, ent.params),
|
|
176
|
-
label: url,
|
|
177
|
-
routeId: r.routeId,
|
|
178
|
-
params: ent.params
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
opts.sort((a, b) => a.label.localeCompare(b.label));
|
|
183
|
-
return opts;
|
|
184
|
-
});
|
|
185
|
-
|
|
186
130
|
const applyPageValue = (value: string) => {
|
|
187
131
|
const opt = pageOptions.find((o) => o.value === value);
|
|
188
132
|
if (!opt) return;
|