@xiwebdesign/xicms-core 7.1.0 → 7.3.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/dist/XiCMSProvider.d.ts +2 -8
- package/dist/XiCMSProvider.js +1 -8
- package/dist/XiCMSProvider.js.map +1 -1
- package/dist/admin/AdminApp.js +7 -12
- package/dist/admin/AdminApp.js.map +1 -1
- package/dist/admin/NewsEditor.d.ts +8 -1
- package/dist/admin/NewsEditor.js +19 -18
- package/dist/admin/NewsEditor.js.map +1 -1
- package/dist/admin/SuperadminPanel.js +6 -7
- package/dist/admin/SuperadminPanel.js.map +1 -1
- package/dist/admin/customBlocks/CustomBlocksPanel.js +3 -4
- package/dist/admin/customBlocks/CustomBlocksPanel.js.map +1 -1
- package/dist/admin/lib/pagesClient.js +3 -4
- package/dist/admin/lib/pagesClient.js.map +1 -1
- package/dist/admin/lib/symbolsClient.js +3 -4
- package/dist/admin/lib/symbolsClient.js.map +1 -1
- package/dist/admin/pages/PagesPanel.js +5 -2
- package/dist/admin/pages/PagesPanel.js.map +1 -1
- package/dist/admin/settings/MailSettings.js +2 -3
- package/dist/admin/settings/MailSettings.js.map +1 -1
- package/dist/admin/settings/MailTemplates.js +2 -3
- package/dist/admin/settings/MailTemplates.js.map +1 -1
- package/dist/admin/settings/SettingsPanel.js +250 -225
- package/dist/admin/settings/SettingsPanel.js.map +1 -1
- package/dist/admin/settings/SnapshotsCard.js +3 -4
- package/dist/admin/settings/SnapshotsCard.js.map +1 -1
- package/dist/admin/shop/lib.js +2 -3
- package/dist/admin/shop/lib.js.map +1 -1
- package/dist/admin/visual/VisualEditor.js +239 -103
- package/dist/admin/visual/VisualEditor.js.map +1 -1
- package/dist/admin.css +1 -1
- package/dist/blocks/builtins/Agenda.js +6 -6
- package/dist/blocks/builtins/Agenda.js.map +1 -1
- package/dist/blocks/builtins/Banner.js +1 -1
- package/dist/blocks/builtins/Banner.js.map +1 -1
- package/dist/blocks/builtins/Breadcrumbs.js +5 -2
- package/dist/blocks/builtins/Breadcrumbs.js.map +1 -1
- package/dist/blocks/builtins/Cards.js +2 -2
- package/dist/blocks/builtins/Cards.js.map +1 -1
- package/dist/blocks/builtins/Contact.js +3 -3
- package/dist/blocks/builtins/Contact.js.map +1 -1
- package/dist/blocks/builtins/Cta.js +3 -3
- package/dist/blocks/builtins/Cta.js.map +1 -1
- package/dist/blocks/builtins/Downloads.js +5 -5
- package/dist/blocks/builtins/Downloads.js.map +1 -1
- package/dist/blocks/builtins/Elements.js +8 -5
- package/dist/blocks/builtins/Elements.js.map +1 -1
- package/dist/blocks/builtins/Hero.js +1 -1
- package/dist/blocks/builtins/Hero.js.map +1 -1
- package/dist/blocks/builtins/Jobs.js +4 -1
- package/dist/blocks/builtins/Jobs.js.map +1 -1
- package/dist/blocks/builtins/MapBlock.js +11 -11
- package/dist/blocks/builtins/MapBlock.js.map +1 -1
- package/dist/blocks/builtins/Newsletter.js +3 -2
- package/dist/blocks/builtins/Newsletter.js.map +1 -1
- package/dist/blocks/builtins/OpeningHours.js +2 -2
- package/dist/blocks/builtins/OpeningHours.js.map +1 -1
- package/dist/blocks/builtins/PdfBlock.js +2 -2
- package/dist/blocks/builtins/PdfBlock.js.map +1 -1
- package/dist/blocks/builtins/Portfolio.js +4 -4
- package/dist/blocks/builtins/Portfolio.js.map +1 -1
- package/dist/blocks/builtins/Pricing.js +3 -3
- package/dist/blocks/builtins/Pricing.js.map +1 -1
- package/dist/blocks/builtins/Sections.js +7 -7
- package/dist/blocks/builtins/Sections.js.map +1 -1
- package/dist/blocks/builtins/Team.js +3 -3
- package/dist/blocks/builtins/Team.js.map +1 -1
- package/dist/blocks/builtins/Widgets.js +28 -28
- package/dist/blocks/builtins/Widgets.js.map +1 -1
- package/dist/blocks/builtins/lib/submitForm.js +3 -4
- package/dist/blocks/builtins/lib/submitForm.js.map +1 -1
- package/dist/blocks/ui/index.d.ts +8 -1
- package/dist/blocks/ui/index.js +3 -2
- package/dist/blocks/ui/index.js.map +1 -1
- package/dist/components/EditBar.d.ts +9 -1
- package/dist/components/EditBar.js +6 -5
- package/dist/components/EditBar.js.map +1 -1
- package/dist/components/PageView.js +3 -5
- package/dist/components/PageView.js.map +1 -1
- package/dist/firebase/admin.js +4 -0
- package/dist/firebase/admin.js.map +1 -1
- package/dist/firebase/client.js +23 -5
- package/dist/firebase/client.js.map +1 -1
- package/dist/firebase/emulators.d.ts +9 -0
- package/dist/firebase/emulators.js +24 -0
- package/dist/firebase/emulators.js.map +1 -0
- package/dist/firebase/functionsClient.d.ts +18 -0
- package/dist/firebase/functionsClient.js +17 -0
- package/dist/firebase/functionsClient.js.map +1 -0
- package/dist/lock/DemoLock.js +19 -2
- package/dist/lock/DemoLock.js.map +1 -1
- package/dist/modules/shop/cartStore.js +2 -1
- package/dist/modules/shop/cartStore.js.map +1 -1
- package/dist/modules/shop/lib.js +9 -10
- package/dist/modules/shop/lib.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/pages.d.ts +11 -0
- package/dist/server/pages.js +47 -0
- package/dist/server/pages.js.map +1 -1
- package/dist/server/version.d.ts +7 -0
- package/dist/server/version.js +2 -1
- package/dist/server/version.js.map +1 -1
- package/dist/styles.css +130 -29
- package/dist/theme/color.d.ts +17 -0
- package/dist/theme/color.js +12 -0
- package/dist/theme/color.js.map +1 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useRef, useState } from "react";
|
|
4
4
|
import { doc, onSnapshot } from "firebase/firestore";
|
|
5
|
-
import {
|
|
5
|
+
import { callable } from "../../firebase/functionsClient.js";
|
|
6
6
|
import { getDb, getFirebaseApp } from "../../firebase/client.js";
|
|
7
|
-
import { functionsRegion } from "../../firebase/region.js";
|
|
8
7
|
import { SiteSettingsSchema } from "../../schema/settings.js";
|
|
9
8
|
import { useModules } from "../../modules/context.js";
|
|
10
9
|
import { builtinThemePresets } from "../../theme/presets.js";
|
|
@@ -31,10 +30,7 @@ function SettingsPanel({ siteId }) {
|
|
|
31
30
|
if (!app) return false;
|
|
32
31
|
setExporting(true);
|
|
33
32
|
try {
|
|
34
|
-
const fn =
|
|
35
|
-
getFunctions(app, functionsRegion()),
|
|
36
|
-
"exportSite"
|
|
37
|
-
);
|
|
33
|
+
const fn = callable(app, "exportSite");
|
|
38
34
|
const res = await fn({ siteId });
|
|
39
35
|
const blob = new Blob([JSON.stringify(res.data, null, 2)], { type: "application/json" });
|
|
40
36
|
const url = URL.createObjectURL(blob);
|
|
@@ -88,7 +84,7 @@ function SettingsPanel({ siteId }) {
|
|
|
88
84
|
}
|
|
89
85
|
const app = getFirebaseApp();
|
|
90
86
|
if (!app) throw new Error("Firebase niet geconfigureerd.");
|
|
91
|
-
const fn =
|
|
87
|
+
const fn = callable(app, "restoreSite");
|
|
92
88
|
await fn({ siteId, backup });
|
|
93
89
|
toast({ title: "Back-up teruggezet", description: "Herlaad de pagina om alles bij te werken.", tone: "success" });
|
|
94
90
|
} catch (e) {
|
|
@@ -97,6 +93,7 @@ function SettingsPanel({ siteId }) {
|
|
|
97
93
|
setRestoring(false);
|
|
98
94
|
}
|
|
99
95
|
}
|
|
96
|
+
const [sectie, setSectie] = useState("algemeen");
|
|
100
97
|
useEffect(() => {
|
|
101
98
|
const db = getDb();
|
|
102
99
|
if (!db) {
|
|
@@ -119,7 +116,7 @@ function SettingsPanel({ siteId }) {
|
|
|
119
116
|
try {
|
|
120
117
|
const app = getFirebaseApp();
|
|
121
118
|
if (!app) throw new Error("Firebase is niet geconfigureerd.");
|
|
122
|
-
const fn =
|
|
119
|
+
const fn = callable(app, "saveSiteSettings");
|
|
123
120
|
const res = await fn({ siteId, settings: parsed.data });
|
|
124
121
|
toast({ title: "Opgeslagen", description: res.data?.message ?? "Wijzigingen zijn live.", tone: "success" });
|
|
125
122
|
} catch (e) {
|
|
@@ -137,235 +134,263 @@ function SettingsPanel({ siteId }) {
|
|
|
137
134
|
return { enabled: raw?.enabled ?? defaultEnabled, config: raw?.config ?? {} };
|
|
138
135
|
};
|
|
139
136
|
const setModule = (id, next) => setS({ ...s, modules: { ...s.modules, [id]: next } });
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
137
|
+
const SECTIES = [
|
|
138
|
+
{ sleutel: "algemeen", label: "Algemeen" },
|
|
139
|
+
{ sleutel: "huisstijl", label: "Huisstijl" },
|
|
140
|
+
{ sleutel: "seo", label: "SEO" },
|
|
141
|
+
{ sleutel: "footer", label: "Footer" },
|
|
142
|
+
{ sleutel: "modules", label: "Modules" },
|
|
143
|
+
{ sleutel: "mail", label: "E-mail" },
|
|
144
|
+
{ sleutel: "backup", label: "Back-up" }
|
|
145
|
+
];
|
|
146
|
+
return (
|
|
147
|
+
/* Een formulier leest niet op 1300px breed; een invoerveld hoort niet breder te zijn dan de
|
|
148
|
+
tekst die erin komt. Vandaar een leesbreedte in plaats van het hele werkblad vullen. */
|
|
149
|
+
/* @__PURE__ */ jsxs("div", { className: "grid max-w-4xl gap-4", children: [
|
|
150
|
+
/* @__PURE__ */ jsx("nav", { "aria-label": "Onderdelen van de instellingen", className: "flex flex-wrap gap-1", children: SECTIES.map((x) => /* @__PURE__ */ jsx(
|
|
151
|
+
"button",
|
|
152
|
+
{
|
|
153
|
+
type: "button",
|
|
154
|
+
"aria-current": sectie === x.sleutel ? "page" : void 0,
|
|
155
|
+
onClick: () => setSectie(x.sleutel),
|
|
156
|
+
className: "rounded-lg px-3 py-1.5 text-sm font-medium text-slate-600 hover:bg-slate-200 hover:text-slate-900 focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:outline-none aria-[current=page]:bg-slate-200 aria-[current=page]:text-slate-900",
|
|
157
|
+
children: x.label
|
|
158
|
+
},
|
|
159
|
+
x.sleutel
|
|
160
|
+
)) }),
|
|
161
|
+
sectie === "algemeen" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Card, { children: [
|
|
162
|
+
/* @__PURE__ */ jsx("h3", { className: "mb-3 text-base font-semibold", children: "Algemeen" }),
|
|
164
163
|
/* @__PURE__ */ jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [
|
|
165
|
-
/* @__PURE__ */ jsx(Field, { label: "
|
|
166
|
-
/* @__PURE__ */ jsx(Field, { label: "
|
|
167
|
-
/* @__PURE__ */ jsx(Field, { label: "
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
children: /* @__PURE__ */ jsx(
|
|
176
|
-
Select,
|
|
177
|
-
{
|
|
178
|
-
value: donkerModus,
|
|
179
|
-
onValueChange: (v) => setS({ ...s, theme: { ...theme, dark: { ...theme.dark ?? {}, mode: v } } }),
|
|
180
|
-
options: [
|
|
181
|
-
{ value: "light", label: "Altijd licht" },
|
|
182
|
-
{ value: "dark", label: "Altijd donker" },
|
|
183
|
-
{ value: "auto", label: "Automatisch \u2014 volg de bezoeker" }
|
|
184
|
-
]
|
|
185
|
-
}
|
|
186
|
-
)
|
|
187
|
-
}
|
|
188
|
-
),
|
|
189
|
-
donkerModus !== "light" && /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-3", children: [
|
|
190
|
-
/* @__PURE__ */ jsx(Field, { label: "Donkere achtergrond", children: /* @__PURE__ */ jsx(
|
|
191
|
-
Input,
|
|
192
|
-
{
|
|
193
|
-
value: theme.dark?.background ?? "",
|
|
194
|
-
onChange: (e) => setS({ ...s, theme: { ...theme, dark: { ...theme.dark ?? {}, background: e.target.value } } }),
|
|
195
|
-
placeholder: "#0f172a"
|
|
196
|
-
}
|
|
197
|
-
) }),
|
|
198
|
-
/* @__PURE__ */ jsx(Field, { label: "Donkere tekstkleur", children: /* @__PURE__ */ jsx(
|
|
199
|
-
Input,
|
|
164
|
+
/* @__PURE__ */ jsx(Field, { label: "Sitenaam", children: /* @__PURE__ */ jsx(Input, { value: s.name ?? "", onChange: (e) => setS({ ...s, name: e.target.value }) }) }),
|
|
165
|
+
/* @__PURE__ */ jsx(Field, { label: "Domein", children: /* @__PURE__ */ jsx(Input, { value: s.domain ?? "", onChange: (e) => setS({ ...s, domain: e.target.value }) }) }),
|
|
166
|
+
/* @__PURE__ */ jsx(Field, { label: "Contact-e-mail", children: /* @__PURE__ */ jsx(Input, { value: s.contactEmail ?? "", onChange: (e) => setS({ ...s, contactEmail: e.target.value }) }) })
|
|
167
|
+
] })
|
|
168
|
+
] }) }),
|
|
169
|
+
sectie === "huisstijl" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Card, { children: [
|
|
170
|
+
/* @__PURE__ */ jsx("h3", { className: "mb-3 text-base font-semibold", children: "Huisstijl" }),
|
|
171
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-3", children: [
|
|
172
|
+
/* @__PURE__ */ jsx(Field, { label: "Thema-preset", hint: "Vult kleuren, lettertype en afronding in \xE9\xE9n keer in.", children: /* @__PURE__ */ jsx(
|
|
173
|
+
Select,
|
|
200
174
|
{
|
|
201
|
-
value:
|
|
202
|
-
|
|
203
|
-
|
|
175
|
+
value: "",
|
|
176
|
+
placeholder: "Kies een preset\u2026",
|
|
177
|
+
onValueChange: (id) => {
|
|
178
|
+
const preset = builtinThemePresets.find((p) => p.id === id);
|
|
179
|
+
if (preset) setS({ ...s, theme: { ...theme, ...preset.theme } });
|
|
180
|
+
},
|
|
181
|
+
options: builtinThemePresets.map((p) => ({ value: p.id, label: p.label }))
|
|
204
182
|
}
|
|
205
183
|
) }),
|
|
206
|
-
/* @__PURE__ */
|
|
207
|
-
Input,
|
|
208
|
-
{
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
) })
|
|
214
|
-
] }),
|
|
215
|
-
/* @__PURE__ */ jsx(Field, { label: "Logo-URL (e-mail & factuur)", hint: "Absolute https-URL naar een PNG/JPG. Verschijnt in de mail-header en op de factuur-PDF.", children: /* @__PURE__ */ jsx(Input, { value: theme.logo ?? "", onChange: (e) => setS({ ...s, theme: { ...theme, logo: e.target.value } }), placeholder: "https://\u2026/logo.png" }) })
|
|
216
|
-
] })
|
|
217
|
-
] }),
|
|
218
|
-
/* @__PURE__ */ jsxs(Card, { children: [
|
|
219
|
-
/* @__PURE__ */ jsx("h3", { className: "mb-3 text-base font-semibold", children: "SEO (standaard)" }),
|
|
220
|
-
/* @__PURE__ */ jsxs("div", { className: "grid gap-3", children: [
|
|
221
|
-
/* @__PURE__ */ jsx(Field, { label: "Standaard-omschrijving", children: /* @__PURE__ */ jsx(Input, { value: s.seoDefaults?.description ?? "", onChange: (e) => setS({ ...s, seoDefaults: { ...s.seoDefaults, description: e.target.value } }) }) }),
|
|
222
|
-
/* @__PURE__ */ jsx(Field, { label: "OG-afbeelding (URL)", children: /* @__PURE__ */ jsx(Input, { value: s.seoDefaults?.ogImage ?? "", onChange: (e) => setS({ ...s, seoDefaults: { ...s.seoDefaults, ogImage: e.target.value } }) }) })
|
|
223
|
-
] })
|
|
224
|
-
] }),
|
|
225
|
-
/* @__PURE__ */ jsxs(Card, { children: [
|
|
226
|
-
/* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "Footer" }),
|
|
227
|
-
/* @__PURE__ */ jsx("p", { className: "mb-3 text-xs text-slate-500", children: "Kolommen met links, social-links en copyright. Wijzigingen zijn direct live." }),
|
|
228
|
-
/* @__PURE__ */ jsxs("div", { className: "grid gap-4", children: [
|
|
229
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
230
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Kolommen" }),
|
|
231
|
-
/* @__PURE__ */ jsx(
|
|
232
|
-
ArrayEditor,
|
|
233
|
-
{
|
|
234
|
-
items: footer.columns ?? [],
|
|
235
|
-
onChange: (columns) => setS({ ...s, footer: { ...footer, columns } }),
|
|
236
|
-
newItem: () => ({ heading: "", links: [] }),
|
|
237
|
-
addLabel: "+ Kolom",
|
|
238
|
-
emptyLabel: "Nog geen kolommen.",
|
|
239
|
-
renderRow: (col, update) => /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
|
|
240
|
-
/* @__PURE__ */ jsx(Field, { label: "Kop", children: /* @__PURE__ */ jsx(Input, { value: col.heading ?? "", onChange: (e) => update({ heading: e.target.value }) }) }),
|
|
241
|
-
/* @__PURE__ */ jsx(
|
|
242
|
-
ArrayEditor,
|
|
243
|
-
{
|
|
244
|
-
items: col.links ?? [],
|
|
245
|
-
onChange: (links) => update({ links }),
|
|
246
|
-
newItem: () => ({ label: "", href: "" }),
|
|
247
|
-
addLabel: "+ Link",
|
|
248
|
-
renderRow: (link, updL) => /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
249
|
-
/* @__PURE__ */ jsx(Input, { value: link.label, placeholder: "Label", onChange: (e) => updL({ label: e.target.value }) }),
|
|
250
|
-
/* @__PURE__ */ jsx(Input, { value: link.href, placeholder: "/pad of https://\u2026", onChange: (e) => updL({ href: e.target.value }) })
|
|
251
|
-
] })
|
|
252
|
-
}
|
|
253
|
-
)
|
|
254
|
-
] })
|
|
255
|
-
}
|
|
256
|
-
)
|
|
257
|
-
] }),
|
|
258
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
259
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Social-links" }),
|
|
184
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [
|
|
185
|
+
/* @__PURE__ */ jsx(Field, { label: "Primaire kleur", children: /* @__PURE__ */ jsx(Input, { value: theme.primary, onChange: (e) => setS({ ...s, theme: { ...theme, primary: e.target.value } }) }) }),
|
|
186
|
+
/* @__PURE__ */ jsx(Field, { label: "Accentkleur", children: /* @__PURE__ */ jsx(Input, { value: theme.accent ?? "", onChange: (e) => setS({ ...s, theme: { ...theme, accent: e.target.value } }) }) }),
|
|
187
|
+
/* @__PURE__ */ jsx(Field, { label: "Achtergrondkleur", children: /* @__PURE__ */ jsx(Input, { value: theme.background ?? "", onChange: (e) => setS({ ...s, theme: { ...theme, background: e.target.value } }), placeholder: "#ffffff" }) }),
|
|
188
|
+
/* @__PURE__ */ jsx(Field, { label: "Tekstkleur", children: /* @__PURE__ */ jsx(Input, { value: theme.foreground ?? "", onChange: (e) => setS({ ...s, theme: { ...theme, foreground: e.target.value } }), placeholder: "#0f172a" }) })
|
|
189
|
+
] }),
|
|
260
190
|
/* @__PURE__ */ jsx(
|
|
261
|
-
|
|
191
|
+
Field,
|
|
262
192
|
{
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
193
|
+
label: "Donkere modus",
|
|
194
|
+
hint: donkerModus === "auto" ? "Volgt de voorkeur van de bezoeker: wie zijn telefoon of computer op donker heeft staan, ziet de site donker." : donkerModus === "dark" ? "De site is voor iedereen donker, ongeacht de voorkeur van de bezoeker." : "De site is voor iedereen licht.",
|
|
195
|
+
children: /* @__PURE__ */ jsx(
|
|
196
|
+
Select,
|
|
197
|
+
{
|
|
198
|
+
value: donkerModus,
|
|
199
|
+
onValueChange: (v) => setS({ ...s, theme: { ...theme, dark: { ...theme.dark ?? {}, mode: v } } }),
|
|
200
|
+
options: [
|
|
201
|
+
{ value: "light", label: "Altijd licht" },
|
|
202
|
+
{ value: "dark", label: "Altijd donker" },
|
|
203
|
+
{ value: "auto", label: "Automatisch \u2014 volg de bezoeker" }
|
|
204
|
+
]
|
|
205
|
+
}
|
|
206
|
+
)
|
|
271
207
|
}
|
|
272
|
-
)
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
208
|
+
),
|
|
209
|
+
donkerModus !== "light" && /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-3", children: [
|
|
210
|
+
/* @__PURE__ */ jsx(Field, { label: "Donkere achtergrond", children: /* @__PURE__ */ jsx(
|
|
211
|
+
Input,
|
|
212
|
+
{
|
|
213
|
+
value: theme.dark?.background ?? "",
|
|
214
|
+
onChange: (e) => setS({ ...s, theme: { ...theme, dark: { ...theme.dark ?? {}, background: e.target.value } } }),
|
|
215
|
+
placeholder: "#0f172a"
|
|
216
|
+
}
|
|
217
|
+
) }),
|
|
218
|
+
/* @__PURE__ */ jsx(Field, { label: "Donkere tekstkleur", children: /* @__PURE__ */ jsx(
|
|
219
|
+
Input,
|
|
220
|
+
{
|
|
221
|
+
value: theme.dark?.foreground ?? "",
|
|
222
|
+
onChange: (e) => setS({ ...s, theme: { ...theme, dark: { ...theme.dark ?? {}, foreground: e.target.value } } }),
|
|
223
|
+
placeholder: "#e2e8f0"
|
|
224
|
+
}
|
|
225
|
+
) }),
|
|
226
|
+
/* @__PURE__ */ jsx(Field, { label: "Donkere merkkleur", hint: "Laat leeg om dezelfde te gebruiken.", children: /* @__PURE__ */ jsx(
|
|
227
|
+
Input,
|
|
228
|
+
{
|
|
229
|
+
value: theme.dark?.primary ?? "",
|
|
230
|
+
onChange: (e) => setS({ ...s, theme: { ...theme, dark: { ...theme.dark ?? {}, primary: e.target.value } } }),
|
|
231
|
+
placeholder: theme.primary
|
|
232
|
+
}
|
|
233
|
+
) })
|
|
234
|
+
] }),
|
|
235
|
+
/* @__PURE__ */ jsx(Field, { label: "Logo-URL (e-mail & factuur)", hint: "Absolute https-URL naar een PNG/JPG. Verschijnt in de mail-header en op de factuur-PDF.", children: /* @__PURE__ */ jsx(Input, { value: theme.logo ?? "", onChange: (e) => setS({ ...s, theme: { ...theme, logo: e.target.value } }), placeholder: "https://\u2026/logo.png" }) })
|
|
236
|
+
] })
|
|
237
|
+
] }) }),
|
|
238
|
+
sectie === "seo" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Card, { children: [
|
|
239
|
+
/* @__PURE__ */ jsx("h3", { className: "mb-3 text-base font-semibold", children: "SEO (standaard)" }),
|
|
240
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-3", children: [
|
|
241
|
+
/* @__PURE__ */ jsx(Field, { label: "Standaard-omschrijving", children: /* @__PURE__ */ jsx(Input, { value: s.seoDefaults?.description ?? "", onChange: (e) => setS({ ...s, seoDefaults: { ...s.seoDefaults, description: e.target.value } }) }) }),
|
|
242
|
+
/* @__PURE__ */ jsx(Field, { label: "OG-afbeelding (URL)", children: /* @__PURE__ */ jsx(Input, { value: s.seoDefaults?.ogImage ?? "", onChange: (e) => setS({ ...s, seoDefaults: { ...s.seoDefaults, ogImage: e.target.value } }) }) })
|
|
243
|
+
] })
|
|
244
|
+
] }) }),
|
|
245
|
+
sectie === "footer" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Card, { children: [
|
|
246
|
+
/* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "Footer" }),
|
|
247
|
+
/* @__PURE__ */ jsx("p", { className: "mb-3 text-xs text-slate-500", children: "Kolommen met links, social-links en copyright. Wijzigingen zijn direct live." }),
|
|
248
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-4", children: [
|
|
249
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
250
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Kolommen" }),
|
|
251
|
+
/* @__PURE__ */ jsx(
|
|
252
|
+
ArrayEditor,
|
|
253
|
+
{
|
|
254
|
+
items: footer.columns ?? [],
|
|
255
|
+
onChange: (columns) => setS({ ...s, footer: { ...footer, columns } }),
|
|
256
|
+
newItem: () => ({ heading: "", links: [] }),
|
|
257
|
+
addLabel: "+ Kolom",
|
|
258
|
+
emptyLabel: "Nog geen kolommen.",
|
|
259
|
+
renderRow: (col, update) => /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
|
|
260
|
+
/* @__PURE__ */ jsx(Field, { label: "Kop", children: /* @__PURE__ */ jsx(Input, { value: col.heading ?? "", onChange: (e) => update({ heading: e.target.value }) }) }),
|
|
261
|
+
/* @__PURE__ */ jsx(
|
|
262
|
+
ArrayEditor,
|
|
263
|
+
{
|
|
264
|
+
items: col.links ?? [],
|
|
265
|
+
onChange: (links) => update({ links }),
|
|
266
|
+
newItem: () => ({ label: "", href: "" }),
|
|
267
|
+
addLabel: "+ Link",
|
|
268
|
+
renderRow: (link, updL) => /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
269
|
+
/* @__PURE__ */ jsx(Input, { value: link.label, placeholder: "Label", onChange: (e) => updL({ label: e.target.value }) }),
|
|
270
|
+
/* @__PURE__ */ jsx(Input, { value: link.href, placeholder: "/pad of https://\u2026", onChange: (e) => updL({ href: e.target.value }) })
|
|
271
|
+
] })
|
|
272
|
+
}
|
|
273
|
+
)
|
|
274
|
+
] })
|
|
275
|
+
}
|
|
276
|
+
)
|
|
277
|
+
] }),
|
|
278
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
279
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Social-links" }),
|
|
280
|
+
/* @__PURE__ */ jsx(
|
|
281
|
+
ArrayEditor,
|
|
282
|
+
{
|
|
283
|
+
items: footer.social ?? [],
|
|
284
|
+
onChange: (social) => setS({ ...s, footer: { ...footer, social } }),
|
|
285
|
+
newItem: () => ({ platform: "", href: "" }),
|
|
286
|
+
addLabel: "+ Social-link",
|
|
287
|
+
renderRow: (link, update) => /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
288
|
+
/* @__PURE__ */ jsx(Input, { value: link.platform, placeholder: "bv. Instagram", onChange: (e) => update({ platform: e.target.value }) }),
|
|
289
|
+
/* @__PURE__ */ jsx(Input, { value: link.href, placeholder: "https://\u2026", onChange: (e) => update({ href: e.target.value }) })
|
|
290
|
+
] })
|
|
291
|
+
}
|
|
292
|
+
)
|
|
293
|
+
] }),
|
|
294
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [
|
|
295
|
+
/* @__PURE__ */ jsx(Field, { label: "Copyright (leeg = automatisch)", children: /* @__PURE__ */ jsx(Input, { value: footer.copyright ?? "", onChange: (e) => setS({ ...s, footer: { ...footer, copyright: e.target.value } }) }) }),
|
|
296
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 self-end text-sm", children: [
|
|
297
|
+
/* @__PURE__ */ jsx(Switch, { checked: footer.showAdminLink !== false, onCheckedChange: (v) => setS({ ...s, footer: { ...footer, showAdminLink: v } }) }),
|
|
298
|
+
"\u201CBeheer\u201D-link tonen"
|
|
299
|
+
] })
|
|
279
300
|
] })
|
|
280
301
|
] })
|
|
281
|
-
] })
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
302
|
+
] }) }),
|
|
303
|
+
sectie === "modules" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Card, { children: [
|
|
304
|
+
/* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "Modules" }),
|
|
305
|
+
/* @__PURE__ */ jsx("p", { className: "mb-3 text-xs text-slate-500", children: "Zet functies aan/uit en stel ze in. Uitgezette modules verbergen hun blokken en beheer-paneel." }),
|
|
306
|
+
/* @__PURE__ */ jsx("div", { className: "grid gap-3", children: defs.filter((d) => !d.core).map((d) => {
|
|
307
|
+
const st = moduleState(d.id, d.defaultEnabled ?? true);
|
|
308
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-slate-200 p-3", children: [
|
|
309
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center justify-between gap-2", children: [
|
|
310
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
311
|
+
/* @__PURE__ */ jsx("strong", { className: "text-sm", children: d.label }),
|
|
312
|
+
d.description && /* @__PURE__ */ jsx("span", { className: "block text-xs text-slate-500", children: d.description })
|
|
313
|
+
] }),
|
|
314
|
+
/* @__PURE__ */ jsx(Switch, { checked: st.enabled, onCheckedChange: (v) => setModule(d.id, { enabled: v, config: st.config }) })
|
|
293
315
|
] }),
|
|
294
|
-
/* @__PURE__ */ jsx(
|
|
316
|
+
st.enabled && d.settingsSchema && /* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsx(
|
|
317
|
+
ModuleSettingsForm,
|
|
318
|
+
{
|
|
319
|
+
schema: d.settingsSchema,
|
|
320
|
+
value: st.config,
|
|
321
|
+
onChange: (config) => setModule(d.id, { enabled: st.enabled, config })
|
|
322
|
+
}
|
|
323
|
+
) })
|
|
324
|
+
] }, d.id);
|
|
325
|
+
}) })
|
|
326
|
+
] }) }),
|
|
327
|
+
sectie === "mail" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
328
|
+
/* @__PURE__ */ jsx(MailSettings, { siteId }),
|
|
329
|
+
/* @__PURE__ */ jsxs(Card, { children: [
|
|
330
|
+
/* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "E-mailteksten" }),
|
|
331
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm text-slate-600", children: [
|
|
332
|
+
"De teksten van automatische e-mails bewerk je bij het onderdeel zelf: formulier-mails onder",
|
|
333
|
+
" ",
|
|
334
|
+
/* @__PURE__ */ jsx("strong", { children: "Formulieren" }),
|
|
335
|
+
", webwinkel-mails onder ",
|
|
336
|
+
/* @__PURE__ */ jsx("strong", { children: "Webwinkel \u2192 E-mails" }),
|
|
337
|
+
". Provider en opmaak (logo, huisstijlkleur) gelden site-breed en stel je hier in."
|
|
338
|
+
] })
|
|
339
|
+
] }),
|
|
340
|
+
/* @__PURE__ */ jsxs(Card, { children: [
|
|
341
|
+
/* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "Formulier-afzender" }),
|
|
342
|
+
/* @__PURE__ */ jsxs("p", { className: "mb-3 text-xs text-slate-500", children: [
|
|
343
|
+
"De afzender-identiteit die formulier-notificaties gebruiken. Kies de XiCMS-afzender (werkt direct) of het eigen domein van de klant (vereist domeinverificatie). De provider waarmee daadwerkelijk verstuurd wordt, stel je hierboven bij ",
|
|
344
|
+
/* @__PURE__ */ jsx("strong", { children: "E-mail" }),
|
|
345
|
+
" in."
|
|
295
346
|
] }),
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
/* @__PURE__ */ jsx("strong", { children: "Formulieren" }),
|
|
314
|
-
", webwinkel-mails onder ",
|
|
315
|
-
/* @__PURE__ */ jsx("strong", { children: "Webwinkel \u2192 E-mails" }),
|
|
316
|
-
". Provider en opmaak (logo, huisstijlkleur) gelden site-breed en stel je hier in."
|
|
317
|
-
] })
|
|
318
|
-
] }),
|
|
319
|
-
/* @__PURE__ */ jsxs(Card, { children: [
|
|
320
|
-
/* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "Formulier-afzender" }),
|
|
321
|
-
/* @__PURE__ */ jsxs("p", { className: "mb-3 text-xs text-slate-500", children: [
|
|
322
|
-
"De afzender-identiteit die formulier-notificaties gebruiken. Kies de XiCMS-afzender (werkt direct) of het eigen domein van de klant (vereist domeinverificatie). De provider waarmee daadwerkelijk verstuurd wordt, stel je hierboven bij ",
|
|
323
|
-
/* @__PURE__ */ jsx("strong", { children: "E-mail" }),
|
|
324
|
-
" in."
|
|
347
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [
|
|
348
|
+
/* @__PURE__ */ jsx(Field, { label: "Afzender-modus", children: /* @__PURE__ */ jsx(
|
|
349
|
+
Select,
|
|
350
|
+
{
|
|
351
|
+
value: forms.mode,
|
|
352
|
+
onValueChange: (v) => setS({ ...s, forms: { ...forms, mode: v } }),
|
|
353
|
+
options: [
|
|
354
|
+
{ value: "xicms", label: "XiCMS-domein (aanbevolen)" },
|
|
355
|
+
{ value: "client", label: "Eigen domein van de klant" }
|
|
356
|
+
]
|
|
357
|
+
}
|
|
358
|
+
) }),
|
|
359
|
+
/* @__PURE__ */ jsx(Field, { label: "Van (from) e-mail", hint: "Moet een geverifieerd domein zijn.", children: /* @__PURE__ */ jsx(Input, { value: forms.fromEmail ?? "", onChange: (e) => setS({ ...s, forms: { ...forms, fromEmail: e.target.value } }) }) }),
|
|
360
|
+
/* @__PURE__ */ jsx(Field, { label: "Van (naam)", children: /* @__PURE__ */ jsx(Input, { value: forms.fromName ?? "", onChange: (e) => setS({ ...s, forms: { ...forms, fromName: e.target.value } }) }) }),
|
|
361
|
+
/* @__PURE__ */ jsx(Field, { label: "Notificaties naar", hint: "Meestal het mailadres van de klant.", children: /* @__PURE__ */ jsx(Input, { value: forms.notifyTo ?? "", onChange: (e) => setS({ ...s, forms: { ...forms, notifyTo: e.target.value } }) }) })
|
|
362
|
+
] })
|
|
363
|
+
] })
|
|
325
364
|
] }),
|
|
326
|
-
/* @__PURE__ */ jsxs(
|
|
327
|
-
/* @__PURE__ */
|
|
328
|
-
|
|
329
|
-
{
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
{
|
|
352
|
-
ref: restoreInput,
|
|
353
|
-
type: "file",
|
|
354
|
-
accept: "application/json,.json",
|
|
355
|
-
hidden: true,
|
|
356
|
-
onChange: (e) => {
|
|
357
|
-
const f = e.target.files?.[0];
|
|
358
|
-
if (f) void restoreFromFile(f);
|
|
359
|
-
e.target.value = "";
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
)
|
|
365
|
+
sectie === "backup" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
366
|
+
/* @__PURE__ */ jsxs(Card, { children: [
|
|
367
|
+
/* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "Back-up & herstel" }),
|
|
368
|
+
/* @__PURE__ */ jsx("p", { className: "mb-3 text-xs text-slate-500", children: "Sla alle content van deze site (pagina's, nieuws, formulieren, instellingen en je foto-galerij) op in \xE9\xE9n bestand. Bewaar dat veilig; je kunt het later weer terugzetten. De foto-bestanden zelf blijven in de cloud staan \u2014 de back-up bevat de teksten, instellingen en verwijzingen." }),
|
|
369
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
370
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => void downloadBackup(), disabled: exporting || restoring, children: exporting ? "Bezig\u2026" : "Back-up downloaden" }),
|
|
371
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => restoreInput.current?.click(), disabled: restoring || exporting, children: restoring ? "Terugzetten\u2026" : "Back-up terugzetten\u2026" }),
|
|
372
|
+
/* @__PURE__ */ jsx(
|
|
373
|
+
"input",
|
|
374
|
+
{
|
|
375
|
+
ref: restoreInput,
|
|
376
|
+
type: "file",
|
|
377
|
+
accept: "application/json,.json",
|
|
378
|
+
hidden: true,
|
|
379
|
+
onChange: (e) => {
|
|
380
|
+
const f = e.target.files?.[0];
|
|
381
|
+
if (f) void restoreFromFile(f);
|
|
382
|
+
e.target.value = "";
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
)
|
|
386
|
+
] }),
|
|
387
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-slate-400", children: "Terugzetten vervangt de huidige content door de back-up. We maken automatisch eerst een back-up van de huidige stand, zodat je nooit iets kwijtraakt." })
|
|
388
|
+
] }),
|
|
389
|
+
/* @__PURE__ */ jsx(SnapshotsCard, { siteId })
|
|
363
390
|
] }),
|
|
364
|
-
/* @__PURE__ */ jsx("
|
|
365
|
-
] })
|
|
366
|
-
|
|
367
|
-
/* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(Button, { onClick: save, children: "Instellingen opslaan" }) })
|
|
368
|
-
] });
|
|
391
|
+
/* @__PURE__ */ jsx("div", { className: "sticky bottom-0 -mx-4 flex justify-end border-t px-4 py-3", style: { borderColor: "var(--color-border)", background: "var(--admin-canvas)" }, children: /* @__PURE__ */ jsx(Button, { onClick: save, children: "Instellingen opslaan" }) })
|
|
392
|
+
] })
|
|
393
|
+
);
|
|
369
394
|
}
|
|
370
395
|
export {
|
|
371
396
|
SettingsPanel
|