@vertebr/react 0.3.0 → 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/dist/components/admin/AdminContent.d.ts +36 -0
- package/dist/components/admin/AdminContent.d.ts.map +1 -0
- package/dist/components/admin/AdminContent.js +107 -0
- package/dist/components/admin/AdminHeader.d.ts +13 -0
- package/dist/components/admin/AdminHeader.d.ts.map +1 -0
- package/dist/components/admin/AdminHeader.js +32 -0
- package/dist/components/admin/AdminSidebar.d.ts +25 -0
- package/dist/components/admin/AdminSidebar.d.ts.map +1 -0
- package/dist/components/admin/AdminSidebar.js +31 -0
- package/dist/components/admin/VertebrAdmin.d.ts +3 -18
- package/dist/components/admin/VertebrAdmin.d.ts.map +1 -1
- package/dist/components/admin/VertebrAdmin.js +130 -120
- package/dist/components/admin/sidebar.d.ts +3 -0
- package/dist/components/admin/sidebar.d.ts.map +1 -0
- package/dist/components/admin/sidebar.js +13 -0
- package/dist/components/admin/storage.d.ts +4 -0
- package/dist/components/admin/storage.d.ts.map +1 -0
- package/dist/components/admin/storage.js +24 -0
- package/dist/components/admin/types.d.ts +53 -0
- package/dist/components/admin/types.d.ts.map +1 -0
- package/dist/components/admin/types.js +1 -0
- package/dist/components/config/EnumInput.d.ts +10 -0
- package/dist/components/config/EnumInput.d.ts.map +1 -0
- package/dist/components/config/EnumInput.js +19 -0
- package/dist/components/config/EnumListInput.d.ts +10 -0
- package/dist/components/config/EnumListInput.d.ts.map +1 -0
- package/dist/components/config/EnumListInput.js +46 -0
- package/dist/components/config/VisibilityEye.d.ts +8 -0
- package/dist/components/config/VisibilityEye.d.ts.map +1 -0
- package/dist/components/config/VisibilityEye.js +18 -0
- package/dist/components/config/form/ConfigField.d.ts +2 -1
- package/dist/components/config/form/ConfigField.d.ts.map +1 -1
- package/dist/components/config/form/ConfigField.js +9 -4
- package/dist/components/config/form/ConfigForm.d.ts +1 -1
- package/dist/components/config/form/ConfigForm.d.ts.map +1 -1
- package/dist/components/config/form/ConfigForm.js +18 -9
- package/dist/components/config/form/ConfigFormActions.d.ts +2 -1
- package/dist/components/config/form/ConfigFormActions.d.ts.map +1 -1
- package/dist/components/config/form/ConfigFormActions.js +2 -2
- package/dist/components/config/form/RecordConfigForm.d.ts +3 -1
- package/dist/components/config/form/RecordConfigForm.d.ts.map +1 -1
- package/dist/components/config/form/RecordConfigForm.js +16 -8
- package/dist/components/config/form/SettingsConfigForm.d.ts +3 -1
- package/dist/components/config/form/SettingsConfigForm.d.ts.map +1 -1
- package/dist/components/config/form/SettingsConfigForm.js +2 -2
- package/dist/components/config/form/helpers/fields.d.ts +7 -0
- package/dist/components/config/form/helpers/fields.d.ts.map +1 -0
- package/dist/components/config/form/helpers/fields.js +31 -0
- package/dist/components/config/form/helpers/groups.d.ts +4 -0
- package/dist/components/config/form/helpers/groups.d.ts.map +1 -0
- package/dist/components/config/form/helpers/groups.js +107 -0
- package/dist/components/config/form/helpers/images.d.ts +4 -0
- package/dist/components/config/form/helpers/images.d.ts.map +1 -0
- package/dist/components/config/form/helpers/images.js +27 -0
- package/dist/components/config/form/helpers/index.d.ts +7 -0
- package/dist/components/config/form/helpers/index.d.ts.map +1 -0
- package/dist/components/config/form/helpers/index.js +6 -0
- package/dist/components/config/form/helpers/labels.d.ts +5 -0
- package/dist/components/config/form/helpers/labels.d.ts.map +1 -0
- package/dist/components/config/form/helpers/labels.js +28 -0
- package/dist/components/config/form/helpers/schema.d.ts +8 -0
- package/dist/components/config/form/helpers/schema.d.ts.map +1 -0
- package/dist/components/config/form/helpers/schema.js +30 -0
- package/dist/components/config/form/helpers/visibility.d.ts +13 -0
- package/dist/components/config/form/helpers/visibility.d.ts.map +1 -0
- package/dist/components/config/form/helpers/visibility.js +86 -0
- package/dist/components/config/form/types.d.ts +6 -0
- package/dist/components/config/form/types.d.ts.map +1 -1
- package/dist/components/emails/EmailRecipientSelect.d.ts +16 -0
- package/dist/components/emails/EmailRecipientSelect.d.ts.map +1 -0
- package/dist/components/emails/EmailRecipientSelect.js +10 -0
- package/dist/components/emails/EmailsActivityPanel.d.ts +11 -0
- package/dist/components/emails/EmailsActivityPanel.d.ts.map +1 -0
- package/dist/components/emails/EmailsActivityPanel.js +139 -0
- package/dist/components/emails/EmailsBoard.d.ts +47 -0
- package/dist/components/emails/EmailsBoard.d.ts.map +1 -0
- package/dist/components/emails/EmailsBoard.js +594 -0
- package/dist/components/emails/EmailsLibraryPanel.d.ts +25 -0
- package/dist/components/emails/EmailsLibraryPanel.d.ts.map +1 -0
- package/dist/components/emails/EmailsLibraryPanel.js +379 -0
- package/dist/components/emails/EmailsNavSelect.d.ts +18 -0
- package/dist/components/emails/EmailsNavSelect.d.ts.map +1 -0
- package/dist/components/emails/EmailsNavSelect.js +37 -0
- package/dist/components/emails/MultiCheckSelect.d.ts +18 -0
- package/dist/components/emails/MultiCheckSelect.d.ts.map +1 -0
- package/dist/components/emails/MultiCheckSelect.js +74 -0
- package/dist/components/metrics/MetricsBoard.d.ts +8 -2
- package/dist/components/metrics/MetricsBoard.d.ts.map +1 -1
- package/dist/components/metrics/MetricsBoard.js +55 -2
- package/dist/components/metrics/charts.d.ts +14 -0
- package/dist/components/metrics/charts.d.ts.map +1 -0
- package/dist/components/metrics/charts.js +212 -0
- package/dist/components/resources/ResourceActionModal.d.ts +14 -0
- package/dist/components/resources/ResourceActionModal.d.ts.map +1 -0
- package/dist/components/resources/ResourceActionModal.js +64 -0
- package/dist/components/resources/ResourceCell.d.ts.map +1 -1
- package/dist/components/resources/ResourceCell.js +25 -9
- package/dist/components/resources/ResourceCreateModal.d.ts +18 -0
- package/dist/components/resources/ResourceCreateModal.d.ts.map +1 -0
- package/dist/components/resources/ResourceCreateModal.js +22 -0
- package/dist/components/resources/ResourceMailModal.d.ts +12 -0
- package/dist/components/resources/ResourceMailModal.d.ts.map +1 -0
- package/dist/components/resources/ResourceMailModal.js +196 -0
- package/dist/components/resources/ResourceTable.d.ts +9 -3
- package/dist/components/resources/ResourceTable.d.ts.map +1 -1
- package/dist/components/resources/ResourceTable.js +241 -35
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/lib/metricsRanges.d.ts +20 -0
- package/dist/lib/metricsRanges.d.ts.map +1 -0
- package/dist/lib/metricsRanges.js +14 -0
- package/dist/styles/cells.css +42 -0
- package/dist/styles/emails.css +632 -0
- package/dist/styles/form.css +145 -0
- package/dist/styles/index.css +3 -0
- package/dist/styles/mail.css +240 -0
- package/dist/styles/metrics.css +633 -0
- package/dist/styles/modal.css +18 -0
- package/dist/styles/nav.css +103 -1
- package/dist/styles/panel.css +8 -68
- package/dist/styles/table.css +26 -3
- package/package.json +2 -2
- package/dist/components/config/form/helpers.d.ts +0 -16
- package/dist/components/config/form/helpers.d.ts.map +0 -1
- package/dist/components/config/form/helpers.js +0 -186
|
@@ -1,38 +1,14 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
3
|
import { createVertebrClient, } from "@vertebr/client";
|
|
4
|
-
import { ConfigForm } from "../config/ConfigForm";
|
|
5
|
-
import { EnvSelect } from "../env/EnvSelect";
|
|
6
|
-
import { GalleryBoard } from "../gallery/GalleryBoard";
|
|
7
|
-
import { MetricsBoard } from "../metrics/MetricsBoard";
|
|
8
|
-
import { ResourcePanel } from "../resources/ResourceTable";
|
|
9
|
-
import { ThemeToggle } from "../theme/ThemeToggle";
|
|
10
4
|
import { useVertebrTheme } from "../../hooks/useVertebrTheme";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
function writeStored(key, value) {
|
|
20
|
-
try {
|
|
21
|
-
localStorage.setItem(key, value);
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
// ignore
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function clearStored(key) {
|
|
28
|
-
try {
|
|
29
|
-
localStorage.removeItem(key);
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
// ignore
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane", envStorageKey = "vertebr:env", tokenStorageKey = "vertebr:token", themeStorageKey = "vertebr:theme", getAccessToken, authUserLabel, onSignOut, }) {
|
|
5
|
+
import { parseMetricsRangeId, } from "../../lib/metricsRanges";
|
|
6
|
+
import { AdminContent } from "./AdminContent";
|
|
7
|
+
import { AdminHeader } from "./AdminHeader";
|
|
8
|
+
import { AdminSidebar } from "./AdminSidebar";
|
|
9
|
+
import { sidebarGroups } from "./sidebar";
|
|
10
|
+
import { clearStored, readStored, writeStored } from "./storage";
|
|
11
|
+
export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane", envStorageKey = "vertebr:env", tokenStorageKey = "vertebr:token", themeStorageKey = "vertebr:theme", metricsRangeStorageKey = "vertebr:metrics-range", getAccessToken, authUserLabel, onSignOut, }) {
|
|
36
12
|
const { theme, setTheme } = useVertebrTheme(themeStorageKey);
|
|
37
13
|
const [environment, setEnvironment] = useState(() => readStored(envStorageKey) ?? "");
|
|
38
14
|
const [token, setToken] = useState(() => readStored(tokenStorageKey) ?? "");
|
|
@@ -50,8 +26,11 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
50
26
|
const [configData, setConfigData] = useState(null);
|
|
51
27
|
const [metricsData, setMetricsData] = useState(null);
|
|
52
28
|
const [metricsLoading, setMetricsLoading] = useState(false);
|
|
29
|
+
const [metricsRange, setMetricsRange] = useState(() => parseMetricsRangeId(readStored(metricsRangeStorageKey)));
|
|
53
30
|
const [galleryData, setGalleryData] = useState(null);
|
|
54
31
|
const [galleryLoading, setGalleryLoading] = useState(false);
|
|
32
|
+
const [emailsData, setEmailsData] = useState(null);
|
|
33
|
+
const [emailsLoading, setEmailsLoading] = useState(false);
|
|
55
34
|
const [error, setError] = useState(null);
|
|
56
35
|
const [loading, setLoading] = useState(true);
|
|
57
36
|
useEffect(() => {
|
|
@@ -97,6 +76,8 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
97
76
|
return current;
|
|
98
77
|
if (current?.kind === "gallery" && next.gallery)
|
|
99
78
|
return current;
|
|
79
|
+
if (current?.kind === "emails" && next.emails)
|
|
80
|
+
return current;
|
|
100
81
|
if (current?.kind === "resource") {
|
|
101
82
|
if (next.resources.some((r) => r.id === current.id))
|
|
102
83
|
return current;
|
|
@@ -112,6 +93,8 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
112
93
|
return { kind: "resource", id: firstResource.id };
|
|
113
94
|
if (next.gallery)
|
|
114
95
|
return { kind: "gallery" };
|
|
96
|
+
if (next.emails)
|
|
97
|
+
return { kind: "emails", tab: "compose" };
|
|
115
98
|
const firstConfig = next.configs[0];
|
|
116
99
|
if (firstConfig)
|
|
117
100
|
return { kind: "config", id: firstConfig.id };
|
|
@@ -142,12 +125,13 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
142
125
|
setError(null);
|
|
143
126
|
if (selection.kind === "overview") {
|
|
144
127
|
setMetricsLoading(true);
|
|
145
|
-
const data = await client.getMetrics();
|
|
128
|
+
const data = await client.getMetrics({ range: metricsRange });
|
|
146
129
|
if (!cancelled) {
|
|
147
130
|
setMetricsData(data);
|
|
148
131
|
setResourceData(null);
|
|
149
132
|
setConfigData(null);
|
|
150
133
|
setGalleryData(null);
|
|
134
|
+
setEmailsData(null);
|
|
151
135
|
}
|
|
152
136
|
}
|
|
153
137
|
else if (selection.kind === "gallery") {
|
|
@@ -158,6 +142,18 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
158
142
|
setResourceData(null);
|
|
159
143
|
setConfigData(null);
|
|
160
144
|
setMetricsData(null);
|
|
145
|
+
setEmailsData(null);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (selection.kind === "emails") {
|
|
149
|
+
setEmailsLoading(true);
|
|
150
|
+
const data = await client.getEmails();
|
|
151
|
+
if (!cancelled) {
|
|
152
|
+
setEmailsData(data);
|
|
153
|
+
setResourceData(null);
|
|
154
|
+
setConfigData(null);
|
|
155
|
+
setMetricsData(null);
|
|
156
|
+
setGalleryData(null);
|
|
161
157
|
}
|
|
162
158
|
}
|
|
163
159
|
else if (selection.kind === "resource") {
|
|
@@ -167,6 +163,7 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
167
163
|
setConfigData(null);
|
|
168
164
|
setMetricsData(null);
|
|
169
165
|
setGalleryData(null);
|
|
166
|
+
setEmailsData(null);
|
|
170
167
|
}
|
|
171
168
|
}
|
|
172
169
|
else {
|
|
@@ -176,6 +173,7 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
176
173
|
setResourceData(null);
|
|
177
174
|
setMetricsData(null);
|
|
178
175
|
setGalleryData(null);
|
|
176
|
+
setEmailsData(null);
|
|
179
177
|
}
|
|
180
178
|
}
|
|
181
179
|
}
|
|
@@ -188,13 +186,14 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
188
186
|
if (!cancelled) {
|
|
189
187
|
setMetricsLoading(false);
|
|
190
188
|
setGalleryLoading(false);
|
|
189
|
+
setEmailsLoading(false);
|
|
191
190
|
}
|
|
192
191
|
}
|
|
193
192
|
})();
|
|
194
193
|
return () => {
|
|
195
194
|
cancelled = true;
|
|
196
195
|
};
|
|
197
|
-
}, [client, selection, catalog, environment]);
|
|
196
|
+
}, [client, selection, catalog, environment, metricsRange]);
|
|
198
197
|
const refreshResource = useCallback(async () => {
|
|
199
198
|
if (selection?.kind !== "resource")
|
|
200
199
|
return;
|
|
@@ -204,13 +203,17 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
204
203
|
const refreshMetrics = useCallback(async () => {
|
|
205
204
|
setMetricsLoading(true);
|
|
206
205
|
try {
|
|
207
|
-
const data = await client.getMetrics();
|
|
206
|
+
const data = await client.getMetrics({ range: metricsRange, fresh: true });
|
|
208
207
|
setMetricsData(data);
|
|
209
208
|
}
|
|
210
209
|
finally {
|
|
211
210
|
setMetricsLoading(false);
|
|
212
211
|
}
|
|
213
|
-
}, [client]);
|
|
212
|
+
}, [client, metricsRange]);
|
|
213
|
+
const changeMetricsRange = useCallback((next) => {
|
|
214
|
+
setMetricsRange(next);
|
|
215
|
+
writeStored(metricsRangeStorageKey, next);
|
|
216
|
+
}, [metricsRangeStorageKey]);
|
|
214
217
|
const refreshGallery = useCallback(async () => {
|
|
215
218
|
setGalleryLoading(true);
|
|
216
219
|
try {
|
|
@@ -221,6 +224,16 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
221
224
|
setGalleryLoading(false);
|
|
222
225
|
}
|
|
223
226
|
}, [client]);
|
|
227
|
+
const refreshEmails = useCallback(async () => {
|
|
228
|
+
setEmailsLoading(true);
|
|
229
|
+
try {
|
|
230
|
+
const data = await client.getEmails({ fresh: true });
|
|
231
|
+
setEmailsData(data);
|
|
232
|
+
}
|
|
233
|
+
finally {
|
|
234
|
+
setEmailsLoading(false);
|
|
235
|
+
}
|
|
236
|
+
}, [client]);
|
|
224
237
|
const listGallery = useCallback(async () => {
|
|
225
238
|
const data = await client.getGallery();
|
|
226
239
|
return data.items;
|
|
@@ -278,6 +291,79 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
278
291
|
setTokenDraft("");
|
|
279
292
|
clearStored(tokenStorageKey);
|
|
280
293
|
};
|
|
294
|
+
const navGroups = useMemo(() => {
|
|
295
|
+
if (!catalog)
|
|
296
|
+
return [];
|
|
297
|
+
const entries = [];
|
|
298
|
+
if (catalog.metrics) {
|
|
299
|
+
entries.push({
|
|
300
|
+
key: "overview",
|
|
301
|
+
group: catalog.metrics.group ?? "Analytics",
|
|
302
|
+
label: catalog.metrics.label,
|
|
303
|
+
active: selection?.kind === "overview",
|
|
304
|
+
onSelect: () => setSelection({ kind: "overview" }),
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
for (const resource of catalog.resources) {
|
|
308
|
+
entries.push({
|
|
309
|
+
key: `resource:${resource.id}`,
|
|
310
|
+
group: resource.group ?? "Resources",
|
|
311
|
+
label: resource.label,
|
|
312
|
+
active: selection?.kind === "resource" && selection.id === resource.id,
|
|
313
|
+
onSelect: () => setSelection({ kind: "resource", id: resource.id }),
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
if (catalog.gallery) {
|
|
317
|
+
entries.push({
|
|
318
|
+
key: "gallery",
|
|
319
|
+
group: catalog.gallery.group ?? "Resources",
|
|
320
|
+
label: catalog.gallery.label,
|
|
321
|
+
active: selection?.kind === "gallery",
|
|
322
|
+
onSelect: () => setSelection({ kind: "gallery" }),
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
if (catalog.emails) {
|
|
326
|
+
const emailsTab = selection?.kind === "emails" ? (selection.tab ?? "compose") : null;
|
|
327
|
+
entries.push({
|
|
328
|
+
key: "emails",
|
|
329
|
+
group: catalog.emails.group ?? "Growth",
|
|
330
|
+
label: catalog.emails.label,
|
|
331
|
+
active: selection?.kind === "emails",
|
|
332
|
+
onSelect: () => setSelection({ kind: "emails", tab: "compose" }),
|
|
333
|
+
children: [
|
|
334
|
+
{
|
|
335
|
+
key: "emails:compose",
|
|
336
|
+
label: "Compose",
|
|
337
|
+
active: emailsTab === "compose",
|
|
338
|
+
onSelect: () => setSelection({ kind: "emails", tab: "compose" }),
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
key: "emails:templates",
|
|
342
|
+
label: "Templates",
|
|
343
|
+
active: emailsTab === "templates",
|
|
344
|
+
onSelect: () => setSelection({ kind: "emails", tab: "templates" }),
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
key: "emails:activity",
|
|
348
|
+
label: "Activity",
|
|
349
|
+
active: emailsTab === "activity",
|
|
350
|
+
onSelect: () => setSelection({ kind: "emails", tab: "activity" }),
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
for (const config of catalog.configs) {
|
|
356
|
+
const fallback = config.section === "page" ? "Pages" : "Config";
|
|
357
|
+
entries.push({
|
|
358
|
+
key: `config:${config.id}`,
|
|
359
|
+
group: config.group ?? fallback,
|
|
360
|
+
label: config.label,
|
|
361
|
+
active: selection?.kind === "config" && selection.id === config.id,
|
|
362
|
+
onSelect: () => setSelection({ kind: "config", id: config.id }),
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
return sidebarGroups(entries);
|
|
366
|
+
}, [catalog, selection]);
|
|
281
367
|
if (!bootstrap && loading) {
|
|
282
368
|
return _jsx("div", { className: "vertebr-loading", children: "Loading Vertebr\u2026" });
|
|
283
369
|
}
|
|
@@ -288,88 +374,12 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
288
374
|
? (catalog?.metrics?.label ?? "Overview")
|
|
289
375
|
: selection?.kind === "gallery"
|
|
290
376
|
? (catalog?.gallery?.label ?? "Gallery")
|
|
291
|
-
: selection?.kind === "
|
|
292
|
-
? catalog?.
|
|
293
|
-
: selection?.kind === "
|
|
294
|
-
? catalog?.
|
|
295
|
-
:
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
catalog.configs.some((c) => (c.section ?? "config") !== "page") ? (_jsxs("div", { className: "vertebr-nav-group", children: [_jsx("div", { className: "vertebr-nav-label", children: "Config" }), catalog.configs
|
|
300
|
-
.filter((c) => (c.section ?? "config") !== "page")
|
|
301
|
-
.map((config) => (_jsx("button", { type: "button", "data-active": selection?.kind === "config" &&
|
|
302
|
-
selection.id === config.id, onClick: () => setSelection({ kind: "config", id: config.id }), children: config.label }, config.id)))] })) : null, catalog &&
|
|
303
|
-
catalog.configs.some((c) => c.section === "page") ? (_jsxs("div", { className: "vertebr-nav-group", children: [_jsx("div", { className: "vertebr-nav-label", children: "Pages" }), catalog.configs
|
|
304
|
-
.filter((c) => c.section === "page")
|
|
305
|
-
.map((config) => (_jsx("button", { type: "button", "data-active": selection?.kind === "config" &&
|
|
306
|
-
selection.id === config.id, onClick: () => setSelection({ kind: "config", id: config.id }), children: config.label }, config.id)))] })) : null] })] }), _jsxs("div", { className: "vertebr-sidebar-bottom", children: [getAccessToken && authUserLabel ? (_jsxs("div", { className: "vertebr-auth", children: [_jsx("div", { className: "vertebr-nav-label", children: "Signed in" }), _jsx("p", { className: "vertebr-auth-hint", children: authUserLabel }), onSignOut ? (_jsx("button", { type: "button", className: "vertebr-btn", onClick: () => void onSignOut(), children: "Sign out" })) : null] })) : null, !getAccessToken && (authRequired || token) ? (_jsxs("div", { className: "vertebr-auth", children: [_jsx("div", { className: "vertebr-nav-label", children: "Access" }), _jsx("p", { className: "vertebr-auth-hint", children: authRequired
|
|
307
|
-
? `This environment requires auth${activeEnv?.auth?.claimKey
|
|
308
|
-
? ` (${activeEnv.auth.claimKey})`
|
|
309
|
-
: ""}.`
|
|
310
|
-
: "Optional access token for protected environments." }), _jsx("input", { className: "vertebr-auth-input", type: "password", placeholder: "Bearer token", value: tokenDraft, onChange: (event) => setTokenDraft(event.target.value), autoComplete: "off" }), _jsxs("div", { className: "vertebr-auth-actions", children: [_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-primary", onClick: saveToken, children: "Use token" }), token ? (_jsx("button", { type: "button", className: "vertebr-btn", onClick: clearToken, children: "Clear" })) : null] })] })) : null, _jsx(ThemeToggle, { theme: theme, onChange: setTheme })] })] }), _jsxs("main", { className: "vertebr-main", children: [_jsxs("header", { className: "vertebr-header", children: [_jsxs("div", { children: [_jsxs("div", { className: "vertebr-heading-row", children: [_jsx("h1", { children: activeLabel ?? (catalog ? "Dashboard" : "Sign in") }), activeEnv ? (_jsx("span", { className: "vertebr-env-badge", "data-tone": activeEnv.tone ?? "neutral", children: activeEnv.label })) : null] }), _jsx("p", { children: !catalog && authRequired
|
|
311
|
-
? "Provide an access token to load this environment."
|
|
312
|
-
: selection?.kind === "overview"
|
|
313
|
-
? "Live metrics for the selected environment."
|
|
314
|
-
: selection?.kind === "gallery"
|
|
315
|
-
? "Browse and upload shared media assets."
|
|
316
|
-
: selection?.kind === "resource"
|
|
317
|
-
? "Manage records scoped to the selected environment."
|
|
318
|
-
: selection?.kind === "config"
|
|
319
|
-
? isPageSelection
|
|
320
|
-
? "Edit content for this page."
|
|
321
|
-
: "Owner-managed config for this environment."
|
|
322
|
-
: "Select a panel." })] }), error ? (_jsx("span", { className: "vertebr-status", "data-tone": "danger", children: error })) : null] }), _jsx("div", { className: "vertebr-content", children: catalog ? (_jsxs("section", { className: "vertebr-panel", children: [selection?.kind === "overview" ? (_jsx(MetricsBoard, { label: metricsData?.label ?? catalog.metrics?.label, metrics: metricsData?.metrics ?? [], loading: metricsLoading, onRefresh: () => void refreshMetrics() })) : null, selection?.kind === "gallery" && galleryData ? (_jsx(GalleryBoard, { label: galleryData.label, items: galleryData.items, accept: galleryData.accept, maxBytes: galleryData.maxBytes, canDelete: galleryData.canDelete, loading: galleryLoading, onRefresh: () => void refreshGallery(), onUpload: async (files) => {
|
|
323
|
-
if (files.length === 1 && files[0]) {
|
|
324
|
-
await client.uploadGalleryFile(files[0]);
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
await client.uploadGalleryFiles(files);
|
|
328
|
-
}
|
|
329
|
-
await refreshGallery();
|
|
330
|
-
}, onDelete: galleryData.canDelete
|
|
331
|
-
? async (id) => {
|
|
332
|
-
await client.deleteGalleryItem(id);
|
|
333
|
-
await refreshGallery();
|
|
334
|
-
}
|
|
335
|
-
: undefined })) : null, selection?.kind === "resource" && resourceData ? (_jsx(ResourcePanel, { schema: resourceData.schema, items: resourceData.items, permissions: resourceData.permissions, actions: resourceData.actions, uploads: resourceData.uploads, storageKey: resourceData.id, onUpdate: resourceData.permissions.update
|
|
336
|
-
? async (rowId, value) => {
|
|
337
|
-
await client.updateResource(resourceData.id, rowId, value);
|
|
338
|
-
await refreshResource();
|
|
339
|
-
}
|
|
340
|
-
: undefined, onCreate: resourceData.permissions.create
|
|
341
|
-
? async (value) => {
|
|
342
|
-
await client.createResource(resourceData.id, value);
|
|
343
|
-
await refreshResource();
|
|
344
|
-
}
|
|
345
|
-
: undefined, onDelete: resourceData.permissions.delete
|
|
346
|
-
? async (rowId) => {
|
|
347
|
-
await client.deleteResource(resourceData.id, rowId);
|
|
348
|
-
await refreshResource();
|
|
349
|
-
}
|
|
350
|
-
: undefined, onAction: async (rowId, actionId) => {
|
|
351
|
-
await client.runResourceAction(resourceData.id, rowId, actionId);
|
|
352
|
-
await refreshResource();
|
|
353
|
-
}, onUpload: resourceData.uploads
|
|
354
|
-
? async (field, files) => {
|
|
355
|
-
if (files.length === 1 && files[0]) {
|
|
356
|
-
const result = await client.uploadResourceFile(resourceData.id, field, files[0]);
|
|
357
|
-
return [
|
|
358
|
-
{ url: result.url, name: result.name },
|
|
359
|
-
];
|
|
360
|
-
}
|
|
361
|
-
const result = await client.uploadResourceFiles(resourceData.id, field, files);
|
|
362
|
-
return result.files;
|
|
363
|
-
}
|
|
364
|
-
: undefined, ...galleryPicker })) : null, selection?.kind === "config" && configData ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "vertebr-panel-head", children: [_jsx("h2", { children: isPageSelection ? "Page content" : "Settings" }), _jsxs("span", { className: "vertebr-count", children: [Object.keys(configData.schema).length, " fields"] })] }), _jsx(ConfigForm, { schema: configData.schema, value: configData.value, onSave: async (next) => {
|
|
365
|
-
const saved = await client.setConfig(configData.id, next);
|
|
366
|
-
setConfigData({
|
|
367
|
-
...configData,
|
|
368
|
-
value: saved.value,
|
|
369
|
-
});
|
|
370
|
-
}, ...galleryPicker })] })) : null] })) : (_jsx("section", { className: "vertebr-panel", children: _jsx("div", { className: "vertebr-empty", children: authRequired
|
|
371
|
-
? "Authenticated access required for this environment."
|
|
372
|
-
: loading
|
|
373
|
-
? "Loading…"
|
|
374
|
-
: "Unable to load catalog." }) })) })] })] }));
|
|
377
|
+
: selection?.kind === "emails"
|
|
378
|
+
? (catalog?.emails?.label ?? "Emails")
|
|
379
|
+
: selection?.kind === "resource"
|
|
380
|
+
? catalog?.resources.find((r) => r.id === selection.id)?.label
|
|
381
|
+
: selection?.kind === "config"
|
|
382
|
+
? catalog?.configs.find((c) => c.id === selection.id)?.label
|
|
383
|
+
: null;
|
|
384
|
+
return (_jsxs("div", { className: "vertebr-root", "data-env": environment, children: [_jsx(AdminSidebar, { brand: bootstrap?.brand ?? catalog?.brand ?? "Vertebr", title: title, envList: envList, environment: environment, onEnvironmentChange: switchEnvironment, navGroups: navGroups, getAccessToken: getAccessToken, authUserLabel: authUserLabel, onSignOut: onSignOut, authRequired: authRequired, activeEnv: activeEnv, token: token, tokenDraft: tokenDraft, onTokenDraftChange: setTokenDraft, onSaveToken: saveToken, onClearToken: clearToken, theme: theme, onThemeChange: setTheme }), _jsxs("main", { className: "vertebr-main", children: [_jsx(AdminHeader, { activeLabel: activeLabel ?? (catalog ? "Dashboard" : "Sign in"), activeEnv: activeEnv, catalogLoaded: Boolean(catalog), authRequired: authRequired, selection: selection, isPageSelection: isPageSelection, error: error }), _jsx(AdminContent, { client: client, catalog: catalog, selection: selection, authRequired: authRequired, loading: loading, isPageSelection: isPageSelection, metricsData: metricsData, metricsLoading: metricsLoading, metricsRange: metricsRange, onMetricsRangeChange: changeMetricsRange, onRefreshMetrics: refreshMetrics, galleryData: galleryData, galleryLoading: galleryLoading, onRefreshGallery: refreshGallery, emailsData: emailsData, emailsLoading: emailsLoading, onRefreshEmails: refreshEmails, resourceData: resourceData, onRefreshResource: refreshResource, configData: configData, onConfigSaved: setConfigData, galleryPicker: galleryPicker })] })] }));
|
|
375
385
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/admin/sidebar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE7D,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,eAAe,EAAE,CAYxE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function sidebarGroups(entries) {
|
|
2
|
+
const order = [];
|
|
3
|
+
const map = new Map();
|
|
4
|
+
for (const entry of entries) {
|
|
5
|
+
const group = entry.group.trim() || "Resources";
|
|
6
|
+
if (!map.has(group)) {
|
|
7
|
+
map.set(group, []);
|
|
8
|
+
order.push(group);
|
|
9
|
+
}
|
|
10
|
+
map.get(group).push(entry);
|
|
11
|
+
}
|
|
12
|
+
return order.map((label) => ({ label, items: map.get(label) }));
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/components/admin/storage.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMrD;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAM5D;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAM7C"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function readStored(key) {
|
|
2
|
+
try {
|
|
3
|
+
return localStorage.getItem(key);
|
|
4
|
+
}
|
|
5
|
+
catch {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function writeStored(key, value) {
|
|
10
|
+
try {
|
|
11
|
+
localStorage.setItem(key, value);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
// ignore
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function clearStored(key) {
|
|
18
|
+
try {
|
|
19
|
+
localStorage.removeItem(key);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// ignore
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type VertebrAdminProps = {
|
|
2
|
+
/** Base URL for Vertebr API, e.g. `/admin/api` */
|
|
3
|
+
apiBase?: string;
|
|
4
|
+
title?: string;
|
|
5
|
+
/** localStorage key for remembering the selected environment */
|
|
6
|
+
envStorageKey?: string;
|
|
7
|
+
/** localStorage key for the access token */
|
|
8
|
+
tokenStorageKey?: string;
|
|
9
|
+
/** localStorage key for light/dark theme preference */
|
|
10
|
+
themeStorageKey?: string;
|
|
11
|
+
/** localStorage key for the overview metrics range */
|
|
12
|
+
metricsRangeStorageKey?: string;
|
|
13
|
+
/** Optional host-provided token getter (Firebase ID token, etc.) */
|
|
14
|
+
getAccessToken?: () => string | null | undefined | Promise<string | null | undefined>;
|
|
15
|
+
/** Signed-in identity shown in the dashboard. */
|
|
16
|
+
authUserLabel?: string;
|
|
17
|
+
/** Host-provided sign-out action. */
|
|
18
|
+
onSignOut?: () => void | Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
export type EmailsTab = "compose" | "templates" | "activity";
|
|
21
|
+
export type Selection = {
|
|
22
|
+
kind: "overview";
|
|
23
|
+
} | {
|
|
24
|
+
kind: "resource";
|
|
25
|
+
id: string;
|
|
26
|
+
} | {
|
|
27
|
+
kind: "gallery";
|
|
28
|
+
} | {
|
|
29
|
+
kind: "emails";
|
|
30
|
+
tab?: EmailsTab;
|
|
31
|
+
} | {
|
|
32
|
+
kind: "config";
|
|
33
|
+
id: string;
|
|
34
|
+
} | null;
|
|
35
|
+
export type SidebarEntry = {
|
|
36
|
+
key: string;
|
|
37
|
+
group: string;
|
|
38
|
+
label: string;
|
|
39
|
+
active: boolean;
|
|
40
|
+
onSelect: () => void;
|
|
41
|
+
/** Nested items shown under this entry (e.g. Emails sections). */
|
|
42
|
+
children?: Array<{
|
|
43
|
+
key: string;
|
|
44
|
+
label: string;
|
|
45
|
+
active: boolean;
|
|
46
|
+
onSelect: () => void;
|
|
47
|
+
}>;
|
|
48
|
+
};
|
|
49
|
+
export type SidebarNavGroup = {
|
|
50
|
+
label: string;
|
|
51
|
+
items: SidebarEntry[];
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/admin/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,oEAAoE;IACpE,cAAc,CAAC,EAAE,MACb,MAAM,GACN,IAAI,GACJ,SAAS,GACT,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACvC,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAE7D,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,CAAC,EAAE,SAAS,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9B,IAAI,CAAC;AAET,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,OAAO,CAAC;QAChB,QAAQ,EAAE,MAAM,IAAI,CAAC;KACtB,CAAC,CAAC;CACJ,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FieldSchema } from "@vertebr/client";
|
|
2
|
+
export type EnumInputProps = {
|
|
3
|
+
id: string;
|
|
4
|
+
value: unknown;
|
|
5
|
+
field: FieldSchema;
|
|
6
|
+
readOnly?: boolean;
|
|
7
|
+
onChange: (value: string) => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function EnumInput({ id, value, field, readOnly, onChange, }: EnumInputProps): import("react").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=EnumInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnumInput.d.ts","sourceRoot":"","sources":["../../../src/components/config/EnumInput.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AAEF,wBAAgB,SAAS,CAAC,EACxB,EAAE,EACF,KAAK,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,GACT,EAAE,cAAc,+BAmDhB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as Select from "@radix-ui/react-select";
|
|
3
|
+
import { optionLabel } from "./form/helpers/labels";
|
|
4
|
+
export function EnumInput({ id, value, field, readOnly, onChange, }) {
|
|
5
|
+
const options = field.options?.filter(Boolean) ?? [];
|
|
6
|
+
const current = typeof value === "string" && options.includes(value)
|
|
7
|
+
? value
|
|
8
|
+
: (options[0] ?? "");
|
|
9
|
+
if (options.length === 0) {
|
|
10
|
+
return (_jsx("input", { id: id, type: "text", readOnly: readOnly, value: current, disabled: true }));
|
|
11
|
+
}
|
|
12
|
+
return (_jsxs(Select.Root, { value: current, onValueChange: onChange, disabled: readOnly, children: [_jsxs(Select.Trigger, { id: id, className: "vertebr-select-trigger", children: [_jsx("span", { className: "vertebr-select-value", children: _jsx(Select.Value, { children: optionLabel(current, field) }) }), _jsx(Select.Icon, { className: "vertebr-select-icon", children: _jsx(ChevronIcon, {}) })] }), _jsx(Select.Portal, { children: _jsx(Select.Content, { className: "vertebr-select-content", position: "popper", sideOffset: 6, children: _jsx(Select.Viewport, { className: "vertebr-select-viewport", children: options.map((option) => (_jsxs(Select.Item, { value: option, className: "vertebr-select-item", children: [_jsx(Select.ItemText, { children: optionLabel(option, field) }), _jsx(Select.ItemIndicator, { className: "vertebr-select-check", children: _jsx(CheckIcon, {}) })] }, option))) }) }) })] }));
|
|
13
|
+
}
|
|
14
|
+
function ChevronIcon() {
|
|
15
|
+
return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", "aria-hidden": "true", children: _jsx("path", { d: "M2.5 4.5 6 8l3.5-3.5", fill: "none", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
16
|
+
}
|
|
17
|
+
function CheckIcon() {
|
|
18
|
+
return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", "aria-hidden": "true", children: _jsx("path", { d: "M2.5 6.2 5 8.7 9.5 3.5", fill: "none", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
19
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FieldSchema } from "@vertebr/client";
|
|
2
|
+
export type EnumListInputProps = {
|
|
3
|
+
id: string;
|
|
4
|
+
value: unknown;
|
|
5
|
+
field: FieldSchema;
|
|
6
|
+
readOnly?: boolean;
|
|
7
|
+
onChange: (value: string[]) => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function EnumListInput({ id, value, field, readOnly, onChange, }: EnumListInputProps): import("react").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=EnumListInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnumListInput.d.ts","sourceRoot":"","sources":["../../../src/components/config/EnumListInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACrC,CAAC;AAiBF,wBAAgB,aAAa,CAAC,EAC5B,EAAE,EACF,KAAK,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,GACT,EAAE,kBAAkB,+BAiEpB"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { optionLabel } from "./form/helpers/labels";
|
|
3
|
+
function asStringList(value) {
|
|
4
|
+
if (!Array.isArray(value))
|
|
5
|
+
return [];
|
|
6
|
+
return value.map((item) => String(item).trim()).filter(Boolean);
|
|
7
|
+
}
|
|
8
|
+
function orderedRows(options, selected) {
|
|
9
|
+
const known = new Set(options);
|
|
10
|
+
const picked = selected.filter((id) => known.has(id));
|
|
11
|
+
const rest = options.filter((id) => !picked.includes(id));
|
|
12
|
+
return [
|
|
13
|
+
...picked.map((id) => ({ id, on: true })),
|
|
14
|
+
...rest.map((id) => ({ id, on: false })),
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
export function EnumListInput({ id, value, field, readOnly, onChange, }) {
|
|
18
|
+
const options = field.options?.filter(Boolean) ?? [];
|
|
19
|
+
const selected = asStringList(value);
|
|
20
|
+
const rows = orderedRows(options, selected);
|
|
21
|
+
const commit = (nextRows) => {
|
|
22
|
+
onChange(nextRows.filter((row) => row.on).map((row) => row.id));
|
|
23
|
+
};
|
|
24
|
+
return (_jsx("ul", { id: id, className: "vertebr-enum-list", children: rows.map((row, index) => (_jsxs("li", { className: "vertebr-enum-list-row", "data-on": row.on, children: [_jsxs("label", { className: "vertebr-enum-list-label", children: [_jsx("input", { type: "checkbox", checked: row.on, disabled: readOnly, onChange: (event) => {
|
|
25
|
+
const next = rows.map((item) => item.id === row.id
|
|
26
|
+
? { ...item, on: event.target.checked }
|
|
27
|
+
: item);
|
|
28
|
+
commit(next);
|
|
29
|
+
} }), _jsx("span", { children: optionLabel(row.id, field) })] }), _jsxs("div", { className: "vertebr-enum-list-move", children: [_jsx("button", { type: "button", "aria-label": `Move ${optionLabel(row.id, field)} up`, disabled: readOnly || index === 0, onClick: () => {
|
|
30
|
+
if (index === 0)
|
|
31
|
+
return;
|
|
32
|
+
const next = [...rows];
|
|
33
|
+
const current = next[index];
|
|
34
|
+
next[index] = next[index - 1];
|
|
35
|
+
next[index - 1] = current;
|
|
36
|
+
commit(next);
|
|
37
|
+
}, children: "\u2191" }), _jsx("button", { type: "button", "aria-label": `Move ${optionLabel(row.id, field)} down`, disabled: readOnly || index === rows.length - 1, onClick: () => {
|
|
38
|
+
if (index >= rows.length - 1)
|
|
39
|
+
return;
|
|
40
|
+
const next = [...rows];
|
|
41
|
+
const current = next[index];
|
|
42
|
+
next[index] = next[index + 1];
|
|
43
|
+
next[index + 1] = current;
|
|
44
|
+
commit(next);
|
|
45
|
+
}, children: "\u2193" })] })] }, row.id))) }));
|
|
46
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { UseFormReturn } from "react-hook-form";
|
|
2
|
+
export type VisibilityEyeButtonProps = {
|
|
3
|
+
name: string;
|
|
4
|
+
label: string;
|
|
5
|
+
form: UseFormReturn<Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
export declare function VisibilityEyeButton({ name, label, form, }: VisibilityEyeButtonProps): import("react").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=VisibilityEye.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VisibilityEye.d.ts","sourceRoot":"","sources":["../../../src/components/config/VisibilityEye.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC9C,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,KAAK,EACL,IAAI,GACL,EAAE,wBAAwB,+BA0B1B"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
export function VisibilityEyeButton({ name, label, form, }) {
|
|
4
|
+
const visible = form.watch(name) !== false;
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
form.register(name);
|
|
7
|
+
}, [form, name]);
|
|
8
|
+
return (_jsx("button", { type: "button", className: "vertebr-visibility-btn", "aria-pressed": visible, "aria-label": visible ? `Hide ${label} on storefront` : `Show ${label} on storefront`, title: visible ? "Visible on storefront" : "Hidden on storefront", onClick: () => form.setValue(name, !visible, {
|
|
9
|
+
shouldDirty: true,
|
|
10
|
+
shouldTouch: true,
|
|
11
|
+
}), children: visible ? _jsx(EyeIcon, {}) : _jsx(EyeOffIcon, {}) }));
|
|
12
|
+
}
|
|
13
|
+
function EyeIcon() {
|
|
14
|
+
return (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0" }), _jsx("circle", { cx: "12", cy: "12", r: "3" })] }));
|
|
15
|
+
}
|
|
16
|
+
function EyeOffIcon() {
|
|
17
|
+
return (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49" }), _jsx("path", { d: "M14.084 14.158a3 3 0 0 1-4.242-4.242" }), _jsx("path", { d: "M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143" }), _jsx("path", { d: "m2 2 20 20" })] }));
|
|
18
|
+
}
|
|
@@ -16,6 +16,7 @@ export type ConfigFieldProps = GalleryHandlers & {
|
|
|
16
16
|
}>>;
|
|
17
17
|
hideImagePreview?: boolean;
|
|
18
18
|
hideUpload?: boolean;
|
|
19
|
+
visibilityGroup?: string;
|
|
19
20
|
};
|
|
20
|
-
export declare function ConfigField({ fieldKey, field, groupLabel, variant, schema, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, hideImagePreview, hideUpload, }: ConfigFieldProps): import("react").JSX.Element;
|
|
21
|
+
export declare function ConfigField({ fieldKey, field, groupLabel, variant, schema, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, hideImagePreview, hideUpload, visibilityGroup, }: ConfigFieldProps): import("react").JSX.Element;
|
|
21
22
|
//# sourceMappingURL=ConfigField.d.ts.map
|