@velastack/cms 0.3.1 → 0.5.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/README.md +107 -18
- package/dist/backend/index.d.ts +1 -1
- package/dist/backend/routes/release.js +2 -2
- 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/migrations/0004-release-publisher.d.ts +1 -0
- package/dist/backend/store/migrations/0004-release-publisher.js +15 -0
- package/dist/backend/store/migrations/index.js +3 -1
- package/dist/backend/store/queries.d.ts +9 -3
- package/dist/backend/store/queries.js +105 -11
- 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 +220 -0
- package/dist/components/admin-bar/field-input.svelte.d.ts +29 -0
- package/dist/components/admin-bar/history-panel.svelte +4 -5
- 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/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/reorder-buttons.svelte +52 -0
- package/dist/components/admin-bar/reorder-buttons.svelte.d.ts +10 -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 +250 -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-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-image-editable.svelte +13 -4
- package/dist/components/cms/cms-image.svelte +37 -30
- package/dist/components/cms/cms-image.svelte.d.ts +11 -4
- package/dist/components/cms/cms-link.svelte +26 -19
- package/dist/components/cms/cms-link.svelte.d.ts +2 -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-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-repeater.svelte +15 -18
- package/dist/components/cms/cms-repeater.svelte.d.ts +1 -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-store.svelte.d.ts +14 -0
- package/dist/components/cms/cms-store.svelte.js +39 -2
- package/dist/components/cms/cms-text.svelte +23 -30
- package/dist/components/cms/cms-text.svelte.d.ts +3 -1
- package/dist/components/cms/scope.d.ts +25 -5
- package/dist/components/cms/structured-registry.d.ts +10 -0
- package/dist/components/cms/structured-registry.js +6 -0
- 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/structured.d.ts +108 -0
- package/dist/core/structured.js +184 -0
- package/dist/core/wire.d.ts +42 -2
- package/dist/editor.d.ts +22 -0
- package/dist/editor.js +21 -0
- package/dist/index.d.ts +12 -4
- package/dist/index.js +13 -3
- package/dist/server/load-cms.js +1 -0
- package/package.json +15 -6
- 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
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { page } from '$app/state';
|
|
3
|
-
import ImagesIcon from './icons/images.svelte';
|
|
4
|
-
import { cmsStore, type MediaItem } from '../cms/cms-store.svelte.js';
|
|
5
|
-
import CmsMediaPicker from '../cms/cms-media-picker.svelte';
|
|
6
|
-
import type { CmsPayload, SiteFieldSchema, SiteSchema } from '../cms/scope.js';
|
|
7
|
-
import { clickOutside } from './click-outside.js';
|
|
8
|
-
import PanelFooter from './panel-footer.svelte';
|
|
9
|
-
import PanelHeader from './panel-header.svelte';
|
|
10
|
-
import Panel from './panel.svelte';
|
|
11
|
-
import { Button } from './ui/button/index.js';
|
|
12
|
-
import { Input } from './ui/input/index.js';
|
|
13
|
-
import { Textarea } from './ui/textarea/index.js';
|
|
14
|
-
|
|
15
|
-
type Props = { onClose: () => void; onSave: () => void | Promise<void> };
|
|
16
|
-
let { onClose, onSave }: Props = $props();
|
|
17
|
-
|
|
18
|
-
const cms = $derived(page.data.cms as CmsPayload | undefined);
|
|
19
|
-
const schema = $derived<SiteSchema>(cms?.site?.schema ?? {});
|
|
20
|
-
const endpoint = $derived(cms?.endpoint ?? '/api/cms');
|
|
21
|
-
|
|
22
|
-
// Flat (path → schema) view for save/reset; sections preserved for layout.
|
|
23
|
-
const sections = $derived(Object.entries(schema));
|
|
24
|
-
const allFieldPaths = $derived.by(() => {
|
|
25
|
-
const out: Array<{ path: string; schema: SiteFieldSchema }> = [];
|
|
26
|
-
for (const [sectionKey, section] of sections) {
|
|
27
|
-
for (const [fieldKey, fieldSchema] of Object.entries(section.fields)) {
|
|
28
|
-
out.push({ path: `${sectionKey}.${fieldKey}`, schema: fieldSchema });
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return out;
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
const persistedValue = (path: string): unknown => cmsStore.getSiteValue(path);
|
|
35
|
-
|
|
36
|
-
// Local form state — typing only updates `local`; nothing reaches
|
|
37
|
-
// `cmsStore.siteDraft` until Save fires (matches seo-panel.svelte). That
|
|
38
|
-
// keeps the bar's "X drafts" count from flickering as the user explores.
|
|
39
|
-
let local = $state<Record<string, unknown>>({});
|
|
40
|
-
|
|
41
|
-
$effect(() => {
|
|
42
|
-
const next: Record<string, unknown> = {};
|
|
43
|
-
for (const { path } of allFieldPaths) next[path] = persistedValue(path);
|
|
44
|
-
local = next;
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// Per-field media library popover state — keyed by field path.
|
|
48
|
-
let openLibrary = $state<string | null>(null);
|
|
49
|
-
|
|
50
|
-
const fieldLabelClass = 'vela:text-[12px] vela:text-bar-text-secondary';
|
|
51
|
-
|
|
52
|
-
const stringValue = (v: unknown): string => (typeof v === 'string' ? v : '');
|
|
53
|
-
const numberValue = (v: unknown): number | null =>
|
|
54
|
-
typeof v === 'number' && !Number.isNaN(v) ? v : null;
|
|
55
|
-
|
|
56
|
-
const setNumber = (path: string, raw: string) => {
|
|
57
|
-
if (raw === '') local[path] = undefined;
|
|
58
|
-
else {
|
|
59
|
-
const n = Number(raw);
|
|
60
|
-
local[path] = Number.isFinite(n) ? n : undefined;
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const onLibrarySelect = (path: string, item: MediaItem) => {
|
|
65
|
-
local[path] = item.url;
|
|
66
|
-
openLibrary = null;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const handleSave = async () => {
|
|
70
|
-
for (const { path } of allFieldPaths) {
|
|
71
|
-
const v = local[path];
|
|
72
|
-
if (v !== persistedValue(path)) cmsStore.setSiteValue(path, v);
|
|
73
|
-
}
|
|
74
|
-
await onSave();
|
|
75
|
-
};
|
|
76
|
-
</script>
|
|
77
|
-
|
|
78
|
-
<Panel ariaLabel="Site settings" {onClose}>
|
|
79
|
-
<PanelHeader title="Site settings" {onClose} />
|
|
80
|
-
|
|
81
|
-
<form
|
|
82
|
-
class="vela:overflow-y-auto vela:px-4 vela:pb-4 vela:flex vela:flex-col vela:gap-5"
|
|
83
|
-
onsubmit={(e) => {
|
|
84
|
-
e.preventDefault();
|
|
85
|
-
handleSave();
|
|
86
|
-
}}
|
|
87
|
-
>
|
|
88
|
-
{#if sections.length === 0}
|
|
89
|
-
<p class="vela:text-[13px] vela:text-bar-text-tertiary vela:py-2">
|
|
90
|
-
No site settings have been declared. Pass a <code>site</code> schema to
|
|
91
|
-
<code>createCms()</code> to add fields here.
|
|
92
|
-
</p>
|
|
93
|
-
{:else}
|
|
94
|
-
{#each sections as [sectionKey, section] (sectionKey)}
|
|
95
|
-
<section class="vela:flex vela:flex-col vela:gap-3">
|
|
96
|
-
<h3
|
|
97
|
-
class="vela:text-[10px] vela:font-semibold vela:uppercase vela:tracking-widest vela:text-bar-text-tertiary vela:m-0"
|
|
98
|
-
>
|
|
99
|
-
{section.label}
|
|
100
|
-
</h3>
|
|
101
|
-
|
|
102
|
-
{#each Object.entries(section.fields) as [fieldKey, fieldSchema] (fieldKey)}
|
|
103
|
-
{@const path = `${sectionKey}.${fieldKey}`}
|
|
104
|
-
{#if fieldSchema.type === 'markdown'}
|
|
105
|
-
<label class="vela:flex vela:flex-col vela:gap-1.5">
|
|
106
|
-
<span class={fieldLabelClass}>{fieldSchema.label}</span>
|
|
107
|
-
<Textarea
|
|
108
|
-
value={stringValue(local[path])}
|
|
109
|
-
placeholder={fieldSchema.placeholder ?? ''}
|
|
110
|
-
oninput={(e) => (local[path] = e.currentTarget.value)}
|
|
111
|
-
/>
|
|
112
|
-
</label>
|
|
113
|
-
{:else if fieldSchema.type === 'number'}
|
|
114
|
-
<label class="vela:flex vela:flex-col vela:gap-1.5">
|
|
115
|
-
<span class={fieldLabelClass}>{fieldSchema.label}</span>
|
|
116
|
-
<Input
|
|
117
|
-
type="number"
|
|
118
|
-
value={numberValue(local[path]) ?? ''}
|
|
119
|
-
placeholder={fieldSchema.placeholder ?? ''}
|
|
120
|
-
oninput={(e) => setNumber(path, e.currentTarget.value)}
|
|
121
|
-
/>
|
|
122
|
-
</label>
|
|
123
|
-
{:else if fieldSchema.type === 'datetime'}
|
|
124
|
-
<label class="vela:flex vela:flex-col vela:gap-1.5">
|
|
125
|
-
<span class={fieldLabelClass}>{fieldSchema.label}</span>
|
|
126
|
-
<Input
|
|
127
|
-
type="datetime-local"
|
|
128
|
-
value={stringValue(local[path])}
|
|
129
|
-
oninput={(e) => (local[path] = e.currentTarget.value)}
|
|
130
|
-
/>
|
|
131
|
-
</label>
|
|
132
|
-
{:else if fieldSchema.type === 'color'}
|
|
133
|
-
<label class="vela:flex vela:flex-col vela:gap-1.5">
|
|
134
|
-
<span class={fieldLabelClass}>{fieldSchema.label}</span>
|
|
135
|
-
<div class="vela:flex vela:items-center vela:gap-2">
|
|
136
|
-
<input
|
|
137
|
-
type="color"
|
|
138
|
-
value={stringValue(local[path]) || '#000000'}
|
|
139
|
-
oninput={(e) => (local[path] = e.currentTarget.value)}
|
|
140
|
-
class="vela:h-9 vela:w-12 vela:rounded vela:border vela:border-[var(--cms-bar-divider)] vela:bg-[var(--cms-bar-bg-hover)] vela:cursor-pointer"
|
|
141
|
-
/>
|
|
142
|
-
<Input
|
|
143
|
-
type="text"
|
|
144
|
-
value={stringValue(local[path])}
|
|
145
|
-
placeholder={fieldSchema.placeholder ?? '#1f1f1f'}
|
|
146
|
-
oninput={(e) => (local[path] = e.currentTarget.value)}
|
|
147
|
-
/>
|
|
148
|
-
</div>
|
|
149
|
-
</label>
|
|
150
|
-
{:else if fieldSchema.type === 'url'}
|
|
151
|
-
<label class="vela:flex vela:flex-col vela:gap-1.5">
|
|
152
|
-
<span class={fieldLabelClass}>{fieldSchema.label}</span>
|
|
153
|
-
<Input
|
|
154
|
-
type="url"
|
|
155
|
-
value={stringValue(local[path])}
|
|
156
|
-
placeholder={fieldSchema.placeholder ?? 'https://…'}
|
|
157
|
-
oninput={(e) => (local[path] = e.currentTarget.value)}
|
|
158
|
-
/>
|
|
159
|
-
</label>
|
|
160
|
-
{:else if fieldSchema.type === 'image'}
|
|
161
|
-
<div class="vela:flex vela:flex-col vela:gap-1.5">
|
|
162
|
-
<span class={fieldLabelClass}>{fieldSchema.label}</span>
|
|
163
|
-
<div class="vela:relative vela:flex vela:items-center vela:gap-2">
|
|
164
|
-
<Input
|
|
165
|
-
type="url"
|
|
166
|
-
value={stringValue(local[path])}
|
|
167
|
-
placeholder={fieldSchema.placeholder ?? 'https://…'}
|
|
168
|
-
oninput={(e) => (local[path] = e.currentTarget.value)}
|
|
169
|
-
/>
|
|
170
|
-
<Button
|
|
171
|
-
type="button"
|
|
172
|
-
variant="ghost"
|
|
173
|
-
size="pill-icon"
|
|
174
|
-
aria-label="Choose from media library"
|
|
175
|
-
onclick={() => (openLibrary = openLibrary === path ? null : path)}
|
|
176
|
-
>
|
|
177
|
-
<ImagesIcon class="vela:size-4" />
|
|
178
|
-
</Button>
|
|
179
|
-
{#if openLibrary === path}
|
|
180
|
-
<div
|
|
181
|
-
role="dialog"
|
|
182
|
-
aria-label="Choose from media library"
|
|
183
|
-
class="vela:absolute vela:right-0 vela:top-full vela:mt-1 vela:z-30
|
|
184
|
-
vela:p-2 vela:rounded-md vela:bg-bar-bg
|
|
185
|
-
vela:border vela:border-[var(--cms-bar-divider)]
|
|
186
|
-
vela:shadow-[0_8px_24px_rgba(0,0,0,0.35)]"
|
|
187
|
-
use:clickOutside={() => (openLibrary = null)}
|
|
188
|
-
>
|
|
189
|
-
<CmsMediaPicker {endpoint} onSelect={(item) => onLibrarySelect(path, item)} />
|
|
190
|
-
</div>
|
|
191
|
-
{/if}
|
|
192
|
-
</div>
|
|
193
|
-
{#if stringValue(local[path])}
|
|
194
|
-
<img
|
|
195
|
-
src={stringValue(local[path])}
|
|
196
|
-
alt=""
|
|
197
|
-
class="vela:max-h-24 vela:w-auto vela:rounded vela:border vela:border-[var(--cms-bar-divider)] vela:object-contain vela:bg-[var(--cms-bar-bg-hover)]"
|
|
198
|
-
/>
|
|
199
|
-
{/if}
|
|
200
|
-
</div>
|
|
201
|
-
{:else}
|
|
202
|
-
<label class="vela:flex vela:flex-col vela:gap-1.5">
|
|
203
|
-
<span class={fieldLabelClass}>{fieldSchema.label}</span>
|
|
204
|
-
<Input
|
|
205
|
-
type="text"
|
|
206
|
-
value={stringValue(local[path])}
|
|
207
|
-
placeholder={fieldSchema.placeholder ?? ''}
|
|
208
|
-
oninput={(e) => (local[path] = e.currentTarget.value)}
|
|
209
|
-
/>
|
|
210
|
-
</label>
|
|
211
|
-
{/if}
|
|
212
|
-
{/each}
|
|
213
|
-
</section>
|
|
214
|
-
{/each}
|
|
215
|
-
{/if}
|
|
216
|
-
</form>
|
|
217
|
-
|
|
218
|
-
<PanelFooter>
|
|
219
|
-
<span>Save to keep your changes</span>
|
|
220
|
-
<div class="vela:flex vela:items-center vela:gap-1.5">
|
|
221
|
-
<Button variant="ghost" size="pill" onclick={onClose}>Cancel</Button>
|
|
222
|
-
<Button size="pill" onclick={handleSave}>Save</Button>
|
|
223
|
-
</div>
|
|
224
|
-
</PanelFooter>
|
|
225
|
-
</Panel>
|