@vertebr/react 0.8.1 → 0.9.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.
Files changed (68) hide show
  1. package/dist/components/admin/AddonEditor.d.ts +12 -0
  2. package/dist/components/admin/AddonEditor.d.ts.map +1 -0
  3. package/dist/components/admin/AddonEditor.js +25 -0
  4. package/dist/components/admin/AddonOverview.d.ts +8 -0
  5. package/dist/components/admin/AddonOverview.d.ts.map +1 -0
  6. package/dist/components/admin/AddonOverview.js +125 -0
  7. package/dist/components/admin/AddonPreviewThumb.d.ts +11 -0
  8. package/dist/components/admin/AddonPreviewThumb.d.ts.map +1 -0
  9. package/dist/components/admin/AddonPreviewThumb.js +52 -0
  10. package/dist/components/admin/AdminCommandPalette.d.ts +9 -0
  11. package/dist/components/admin/AdminCommandPalette.d.ts.map +1 -0
  12. package/dist/components/admin/AdminCommandPalette.js +68 -0
  13. package/dist/components/admin/AdminContent.d.ts.map +1 -1
  14. package/dist/components/admin/AdminContent.js +11 -3
  15. package/dist/components/admin/AdminHeader.d.ts +2 -3
  16. package/dist/components/admin/AdminHeader.d.ts.map +1 -1
  17. package/dist/components/admin/AdminHeader.js +10 -3
  18. package/dist/components/admin/AdminPoweredBy.d.ts +5 -0
  19. package/dist/components/admin/AdminPoweredBy.d.ts.map +1 -0
  20. package/dist/components/admin/AdminPoweredBy.js +8 -0
  21. package/dist/components/admin/AdminSidebar.d.ts.map +1 -1
  22. package/dist/components/admin/AdminSidebar.js +9 -7
  23. package/dist/components/admin/AdminSyncPage.d.ts +7 -0
  24. package/dist/components/admin/AdminSyncPage.d.ts.map +1 -0
  25. package/dist/components/admin/AdminSyncPage.js +169 -0
  26. package/dist/components/admin/AdminTopBar.d.ts +6 -2
  27. package/dist/components/admin/AdminTopBar.d.ts.map +1 -1
  28. package/dist/components/admin/AdminTopBar.js +3 -3
  29. package/dist/components/admin/PagePreviewPane.d.ts +3 -1
  30. package/dist/components/admin/PagePreviewPane.d.ts.map +1 -1
  31. package/dist/components/admin/PagePreviewPane.js +2 -2
  32. package/dist/components/admin/VertebrAdmin.d.ts.map +1 -1
  33. package/dist/components/admin/VertebrAdmin.js +76 -13
  34. package/dist/components/admin/addonLabels.d.ts +6 -0
  35. package/dist/components/admin/addonLabels.d.ts.map +1 -0
  36. package/dist/components/admin/addonLabels.js +20 -0
  37. package/dist/components/admin/adminSearch.d.ts +12 -0
  38. package/dist/components/admin/adminSearch.d.ts.map +1 -0
  39. package/dist/components/admin/adminSearch.js +111 -0
  40. package/dist/components/admin/breadcrumbs.d.ts.map +1 -1
  41. package/dist/components/admin/breadcrumbs.js +12 -0
  42. package/dist/components/admin/routes.d.ts.map +1 -1
  43. package/dist/components/admin/routes.js +31 -1
  44. package/dist/components/admin/types.d.ts +7 -0
  45. package/dist/components/admin/types.d.ts.map +1 -1
  46. package/dist/components/env/EnvMultiSelect.d.ts +20 -0
  47. package/dist/components/env/EnvMultiSelect.d.ts.map +1 -0
  48. package/dist/components/env/EnvMultiSelect.js +38 -0
  49. package/dist/components/ui/icons.d.ts +2 -0
  50. package/dist/components/ui/icons.d.ts.map +1 -1
  51. package/dist/components/ui/icons.js +12 -0
  52. package/dist/styles/addon.css +540 -0
  53. package/dist/styles/base.css +1 -0
  54. package/dist/styles/font-library.css +2 -0
  55. package/dist/styles/index.css +2 -0
  56. package/dist/styles/main.css +0 -38
  57. package/dist/styles/modal.css +2 -0
  58. package/dist/styles/motion.css +55 -0
  59. package/dist/styles/nav.css +39 -4
  60. package/dist/styles/select.css +6 -0
  61. package/dist/styles/shell.css +193 -6
  62. package/dist/styles/sidebar.css +63 -3
  63. package/dist/styles/sync.css +540 -0
  64. package/dist/styles/table.css +15 -5
  65. package/dist/themes/dark.css +11 -11
  66. package/dist/themes/index.css +1 -0
  67. package/dist/themes/light.css +19 -19
  68. package/package.json +1 -1
@@ -0,0 +1,12 @@
1
+ import type { CatalogAddon, ConfigResponse, VertebrClient } from "@vertebr/client";
2
+ import type { AdminContentProps } from "./AdminContent";
3
+ export type AddonEditorProps = {
4
+ client: VertebrClient;
5
+ addon: CatalogAddon;
6
+ configData: ConfigResponse;
7
+ onConfigSaved: (next: ConfigResponse) => void;
8
+ galleryPicker: AdminContentProps["galleryPicker"];
9
+ fontLibraryPicker: AdminContentProps["fontLibraryPicker"];
10
+ };
11
+ export declare function AddonEditor({ client, addon, configData, onConfigSaved, galleryPicker, fontLibraryPicker, }: AddonEditorProps): import("react").JSX.Element;
12
+ //# sourceMappingURL=AddonEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AddonEditor.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AddonEditor.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAInF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,EAAE,YAAY,CAAC;IACpB,UAAU,EAAE,cAAc,CAAC;IAC3B,aAAa,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAC9C,aAAa,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;IAClD,iBAAiB,EAAE,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;CAC3D,CAAC;AAEF,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,KAAK,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,iBAAiB,GAClB,EAAE,gBAAgB,+BAsFlB"}
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useMemo, useState } from "react";
3
+ import { ConfigForm } from "../config/ConfigForm";
4
+ import { addonCategoryLabel } from "./addonLabels";
5
+ import { PagePreviewPane } from "./PagePreviewPane";
6
+ export function AddonEditor({ client, addon, configData, onConfigSaved, galleryPicker, fontLibraryPicker, }) {
7
+ const [draft, setDraft] = useState(configData.value);
8
+ const onChange = useCallback((value) => {
9
+ setDraft(value);
10
+ }, []);
11
+ const enabled = Boolean(draft?.enabled ?? configData.value.enabled);
12
+ const previewPath = addon.previewPath;
13
+ const showPreview = Boolean(previewPath);
14
+ const previewDraft = useMemo(() => {
15
+ const base = draft ?? configData.value;
16
+ if (!showPreview)
17
+ return base;
18
+ return { ...base, enabled: true };
19
+ }, [configData.value, draft, showPreview]);
20
+ const form = (_jsx(ConfigForm, { schema: configData.schema, value: configData.value, onChange: showPreview ? onChange : undefined, onSave: async (next) => {
21
+ const saved = await client.setConfig(configData.id, next);
22
+ onConfigSaved(saved);
23
+ }, ...galleryPicker, ...fontLibraryPicker }));
24
+ return (_jsxs("div", { className: "vertebr-addon-editor", children: [_jsxs("div", { className: "vertebr-addon-editor-head", "data-category": addon.category ?? "engagement", children: [_jsxs("div", { className: "vertebr-addon-editor-head-start", children: [_jsx("span", { className: "vertebr-addon-category", "data-category": addon.category ?? "engagement", children: addonCategoryLabel(addon.category) }), _jsxs("span", { className: "vertebr-addon-status", "data-enabled": enabled ? "true" : "false", children: [_jsx("span", { className: "vertebr-addon-status-dot", "aria-hidden": "true" }), enabled ? "Enabled on storefront" : "Disabled"] })] }), previewPath ? (_jsxs("div", { className: "vertebr-addon-editor-head-end", children: [_jsx("span", { className: "vertebr-addon-preview-label", children: "Live preview" }), _jsx("code", { className: "vertebr-addon-preview-path", children: previewPath })] })) : null] }), showPreview && previewPath ? (_jsxs("div", { className: "vertebr-page-editor vertebr-addon-page-editor", children: [_jsx("div", { className: "vertebr-page-editor-form", children: form }), _jsx(PagePreviewPane, { previewPath: previewPath, controlId: configData.id, draft: previewDraft, previewKind: "addon" })] })) : (_jsxs("div", { className: "vertebr-addon-editor-form-only", children: [form, _jsxs("div", { className: "vertebr-addon-preview-missing", children: [_jsx("strong", { children: "Live preview unavailable" }), _jsxs("p", { children: ["Register a ", _jsx("code", { children: "previewPath" }), " on this add-on so Vertebr can iframe your storefront while you edit."] })] })] }))] }));
25
+ }
@@ -0,0 +1,8 @@
1
+ import type { CatalogResponse, VertebrClient } from "@vertebr/client";
2
+ export type AddonOverviewProps = {
3
+ client: VertebrClient;
4
+ catalog: CatalogResponse;
5
+ onSelectAddon: (id: string) => void;
6
+ };
7
+ export declare function AddonOverview({ client, catalog, onSelectAddon }: AddonOverviewProps): import("react").JSX.Element;
8
+ //# sourceMappingURL=AddonOverview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AddonOverview.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AddonOverview.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgB,eAAe,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIpF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,eAAe,CAAC;IACzB,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AAyFF,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,kBAAkB,+BAwKnF"}
@@ -0,0 +1,125 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
+ import { AddonPreviewThumb } from "./AddonPreviewThumb";
4
+ import { addonCategoryHint, addonCategoryLabel } from "./addonLabels";
5
+ const CATEGORY_ORDER = ["product", "engagement", "sales"];
6
+ function groupAddons(addons) {
7
+ const buckets = new Map();
8
+ for (const addon of addons) {
9
+ const key = addon.category ?? "other";
10
+ if (!buckets.has(key))
11
+ buckets.set(key, []);
12
+ buckets.get(key).push(addon);
13
+ }
14
+ const groups = [];
15
+ for (const category of CATEGORY_ORDER) {
16
+ const items = buckets.get(category);
17
+ if (!items?.length)
18
+ continue;
19
+ groups.push({
20
+ category,
21
+ label: addonCategoryLabel(category),
22
+ hint: addonCategoryHint(category),
23
+ items,
24
+ });
25
+ buckets.delete(category);
26
+ }
27
+ const other = buckets.get("other");
28
+ if (other?.length) {
29
+ groups.push({
30
+ category: "other",
31
+ label: "Add-ons",
32
+ hint: "Optional storefront features",
33
+ items: other,
34
+ });
35
+ }
36
+ return groups;
37
+ }
38
+ function AddonScrollRow({ children }) {
39
+ const wrapRef = useRef(null);
40
+ const scrollRef = useRef(null);
41
+ useEffect(() => {
42
+ const el = scrollRef.current;
43
+ const wrap = wrapRef.current;
44
+ if (!el || !wrap)
45
+ return;
46
+ const update = () => {
47
+ const canLeft = el.scrollLeft > 4;
48
+ const canRight = el.scrollLeft + el.clientWidth < el.scrollWidth - 4;
49
+ wrap.classList.toggle("can-scroll-left", canLeft);
50
+ wrap.classList.toggle("can-scroll-right", canRight);
51
+ };
52
+ update();
53
+ el.addEventListener("scroll", update, { passive: true });
54
+ const observer = new ResizeObserver(update);
55
+ observer.observe(el);
56
+ return () => {
57
+ el.removeEventListener("scroll", update);
58
+ observer.disconnect();
59
+ };
60
+ }, [children]);
61
+ return (_jsx("div", { ref: wrapRef, className: "vertebr-addon-scroll-wrap", children: _jsx("div", { ref: scrollRef, className: "vertebr-addon-scroll", tabIndex: 0, children: children }) }));
62
+ }
63
+ export function AddonOverview({ client, catalog, onSelectAddon }) {
64
+ const addons = catalog.addons ?? [];
65
+ const [states, setStates] = useState({});
66
+ const [loading, setLoading] = useState(true);
67
+ useEffect(() => {
68
+ let cancelled = false;
69
+ void (async () => {
70
+ setLoading(true);
71
+ const next = {};
72
+ await Promise.all(addons.map(async (addon) => {
73
+ try {
74
+ const config = await client.getConfig(addon.id);
75
+ next[addon.id] = {
76
+ enabled: Boolean(config.value.enabled),
77
+ value: config.value,
78
+ };
79
+ }
80
+ catch {
81
+ next[addon.id] = { enabled: false, value: {} };
82
+ }
83
+ }));
84
+ if (!cancelled) {
85
+ setStates(next);
86
+ setLoading(false);
87
+ }
88
+ })();
89
+ return () => {
90
+ cancelled = true;
91
+ };
92
+ }, [addons, client]);
93
+ const groups = useMemo(() => groupAddons(addons), [addons]);
94
+ const stats = useMemo(() => {
95
+ let enabled = 0;
96
+ const byCategory = {};
97
+ for (const addon of addons) {
98
+ const category = addon.category ?? "other";
99
+ byCategory[category] = (byCategory[category] ?? 0) + 1;
100
+ if (states[addon.id]?.enabled)
101
+ enabled += 1;
102
+ }
103
+ return {
104
+ total: addons.length,
105
+ enabled,
106
+ products: byCategory.product ?? 0,
107
+ engagement: byCategory.engagement ?? 0,
108
+ sales: byCategory.sales ?? 0,
109
+ };
110
+ }, [addons, states]);
111
+ if (!addons.length) {
112
+ return (_jsx("div", { className: "vertebr-addon-overview", children: _jsx("div", { className: "vertebr-empty", children: "No add-ons registered for this host." }) }));
113
+ }
114
+ return (_jsxs("div", { className: "vertebr-addon-overview", children: [_jsxs("header", { className: "vertebr-addon-overview-toolbar", children: [_jsx("div", { className: "vertebr-addon-overview-intro", children: _jsx("p", { children: "Optional storefront features grouped by purpose. Scroll each row to browse, then configure one to edit with a live shop preview." }) }), _jsxs("div", { className: "vertebr-addon-overview-stats", "aria-label": "Add-on summary", children: [_jsxs("div", { className: "vertebr-addon-stat", children: [_jsx("strong", { children: loading ? "—" : stats.enabled }), _jsx("span", { children: "Enabled" })] }), _jsxs("div", { className: "vertebr-addon-stat", children: [_jsx("strong", { children: stats.total }), _jsx("span", { children: "Total" })] }), _jsxs("div", { className: "vertebr-addon-stat", "data-category": "product", children: [_jsx("strong", { children: stats.products }), _jsx("span", { children: "Products" })] }), _jsxs("div", { className: "vertebr-addon-stat", "data-category": "engagement", children: [_jsx("strong", { children: stats.engagement }), _jsx("span", { children: "Engagement" })] }), _jsxs("div", { className: "vertebr-addon-stat", "data-category": "sales", children: [_jsx("strong", { children: stats.sales }), _jsx("span", { children: "Sales" })] })] })] }), groups.map((group) => (_jsxs("section", { className: "vertebr-addon-overview-section", "data-category": group.category, children: [_jsxs("div", { className: "vertebr-addon-section-head", children: [_jsxs("div", { className: "vertebr-addon-section-title", children: [_jsx("h3", { children: group.label }), _jsx("p", { children: group.hint })] }), _jsxs("span", { className: "vertebr-addon-section-count", children: [group.items.length, " add-on", group.items.length === 1 ? "" : "s"] })] }), _jsx(AddonScrollRow, { children: group.items.map((addon) => {
115
+ const state = states[addon.id];
116
+ const previewDraft = state
117
+ ? { ...state.value, enabled: true }
118
+ : { enabled: true };
119
+ return (_jsxs("article", { className: "vertebr-addon-card", "data-category": addon.category ?? "engagement", children: [_jsx(AddonPreviewThumb, { addonId: addon.id, previewPath: addon.previewPath, draft: previewDraft, label: addon.label }), _jsxs("div", { className: "vertebr-addon-card-body", children: [_jsxs("div", { className: "vertebr-addon-card-head", children: [_jsx("h4", { children: addon.label }), _jsx("span", { className: "vertebr-addon-status", "data-enabled": loading
120
+ ? undefined
121
+ : state?.enabled
122
+ ? "true"
123
+ : "false", children: loading ? "…" : state?.enabled ? "On" : "Off" })] }), addon.description ? _jsx("p", { children: addon.description }) : null, _jsxs("div", { className: "vertebr-addon-card-foot", children: [addon.previewPath ? (_jsx("span", { className: "vertebr-addon-route", children: addon.previewPath })) : null, _jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-primary", onClick: () => onSelectAddon(addon.id), children: "Configure" })] })] })] }, addon.id));
124
+ }) })] }, group.category)))] }));
125
+ }
@@ -0,0 +1,11 @@
1
+ export type AddonPreviewThumbProps = {
2
+ addonId: string;
3
+ previewPath?: string;
4
+ draft?: Record<string, unknown> | null;
5
+ label?: string;
6
+ };
7
+ /**
8
+ * Small live host iframe for add-on overview cards.
9
+ */
10
+ export declare function AddonPreviewThumb({ addonId, previewPath, draft, label, }: AddonPreviewThumbProps): import("react").JSX.Element;
11
+ //# sourceMappingURL=AddonPreviewThumb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AddonPreviewThumb.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AddonPreviewThumb.tsx"],"names":[],"mappings":"AAOA,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,WAAW,EACX,KAAK,EACL,KAAK,GACN,EAAE,sBAAsB,+BA6ExB"}
@@ -0,0 +1,52 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
+ import { buildVertebrPreviewUrl, postVertebrPreviewDraft, subscribeVertebrPreviewReady, } from "@vertebr/client";
4
+ /**
5
+ * Small live host iframe for add-on overview cards.
6
+ */
7
+ export function AddonPreviewThumb({ addonId, previewPath, draft, label, }) {
8
+ const iframeRef = useRef(null);
9
+ const draftRef = useRef(draft);
10
+ const [ready, setReady] = useState(false);
11
+ const [error, setError] = useState(false);
12
+ draftRef.current = draft;
13
+ const src = useMemo(() => {
14
+ if (!previewPath)
15
+ return null;
16
+ return buildVertebrPreviewUrl(previewPath, { controlId: addonId });
17
+ }, [addonId, previewPath]);
18
+ const pushDraft = () => {
19
+ const win = iframeRef.current?.contentWindow;
20
+ const value = draftRef.current;
21
+ if (!win || !value)
22
+ return;
23
+ postVertebrPreviewDraft(win, addonId, value);
24
+ };
25
+ useEffect(() => {
26
+ setReady(false);
27
+ setError(false);
28
+ }, [src]);
29
+ useEffect(() => {
30
+ if (!src)
31
+ return;
32
+ return subscribeVertebrPreviewReady((source) => {
33
+ const win = iframeRef.current?.contentWindow;
34
+ if (!win || source !== win)
35
+ return;
36
+ setReady(true);
37
+ pushDraft();
38
+ });
39
+ }, [src]);
40
+ useEffect(() => {
41
+ if (!ready || !draft)
42
+ return;
43
+ pushDraft();
44
+ }, [draft, ready]);
45
+ if (!previewPath) {
46
+ return (_jsx("div", { className: "vertebr-addon-thumb vertebr-addon-thumb-empty", children: _jsx("span", { children: "No preview route" }) }));
47
+ }
48
+ return (_jsxs("div", { className: "vertebr-addon-thumb", "data-ready": ready ? "true" : undefined, "aria-label": label ? `Preview ${label}` : `Preview ${addonId}`, children: [_jsx("div", { className: "vertebr-addon-thumb-scale", children: error ? (_jsx("div", { className: "vertebr-addon-thumb-fallback", children: "Preview unavailable" })) : (_jsx("iframe", { ref: iframeRef, title: label ? `Preview ${label}` : `Preview ${addonId}`, src: src ?? undefined, tabIndex: -1, loading: "lazy", onLoad: () => {
49
+ setReady(true);
50
+ pushDraft();
51
+ }, onError: () => setError(true) })) }), !ready && !error ? (_jsx("div", { className: "vertebr-addon-thumb-loading", children: "Loading preview\u2026" })) : null] }));
52
+ }
@@ -0,0 +1,9 @@
1
+ import type { CatalogResponse } from "@vertebr/client";
2
+ import type { Selection } from "./types";
3
+ export type AdminCommandPaletteProps = {
4
+ catalog: CatalogResponse;
5
+ onClose: () => void;
6
+ onSelect: (selection: Selection) => void;
7
+ };
8
+ export declare function AdminCommandPalette({ catalog, onClose, onSelect, }: AdminCommandPaletteProps): import("react").JSX.Element;
9
+ //# sourceMappingURL=AdminCommandPalette.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdminCommandPalette.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AdminCommandPalette.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAOvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;CAC1C,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,EACP,OAAO,EACP,QAAQ,GACT,EAAE,wBAAwB,+BAqI1B"}
@@ -0,0 +1,68 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
+ import { IconSearch } from "../ui/icons";
4
+ import { adminSearchItems, filterAdminSearchItems, } from "./adminSearch";
5
+ export function AdminCommandPalette({ catalog, onClose, onSelect, }) {
6
+ const inputRef = useRef(null);
7
+ const [query, setQuery] = useState("");
8
+ const [activeIndex, setActiveIndex] = useState(0);
9
+ const items = useMemo(() => adminSearchItems(catalog), [catalog]);
10
+ const results = useMemo(() => filterAdminSearchItems(items, query), [items, query]);
11
+ useEffect(() => {
12
+ inputRef.current?.focus();
13
+ }, []);
14
+ useEffect(() => {
15
+ setActiveIndex(0);
16
+ }, [query]);
17
+ useEffect(() => {
18
+ const onKeyDown = (event) => {
19
+ if (event.key === "Escape") {
20
+ event.preventDefault();
21
+ onClose();
22
+ return;
23
+ }
24
+ if (results.length === 0)
25
+ return;
26
+ if (event.key === "ArrowDown") {
27
+ event.preventDefault();
28
+ setActiveIndex((current) => (current + 1) % results.length);
29
+ }
30
+ else if (event.key === "ArrowUp") {
31
+ event.preventDefault();
32
+ setActiveIndex((current) => (current - 1 + results.length) % results.length);
33
+ }
34
+ else if (event.key === "Enter") {
35
+ event.preventDefault();
36
+ const item = results[activeIndex];
37
+ if (item) {
38
+ onSelect(item.selection);
39
+ onClose();
40
+ }
41
+ }
42
+ };
43
+ window.addEventListener("keydown", onKeyDown);
44
+ return () => window.removeEventListener("keydown", onKeyDown);
45
+ }, [activeIndex, onClose, onSelect, results]);
46
+ const pick = (item) => {
47
+ onSelect(item.selection);
48
+ onClose();
49
+ };
50
+ const grouped = useMemo(() => {
51
+ const map = new Map();
52
+ for (const item of results) {
53
+ const list = map.get(item.group) ?? [];
54
+ list.push(item);
55
+ map.set(item.group, list);
56
+ }
57
+ return map;
58
+ }, [results]);
59
+ let resultIndex = -1;
60
+ return (_jsx("div", { className: "vertebr-command-backdrop", role: "presentation", onMouseDown: (event) => {
61
+ if (event.target === event.currentTarget)
62
+ onClose();
63
+ }, children: _jsxs("div", { className: "vertebr-command", role: "dialog", "aria-modal": "true", "aria-label": "Search admin", children: [_jsxs("div", { className: "vertebr-command-input-wrap", children: [_jsx(IconSearch, {}), _jsx("input", { ref: inputRef, className: "vertebr-command-input", type: "search", placeholder: "Search pages, resources, settings\u2026", value: query, onChange: (event) => setQuery(event.target.value), autoComplete: "off", spellCheck: false }), _jsx("kbd", { children: "esc" })] }), _jsx("div", { className: "vertebr-command-results", role: "listbox", children: results.length === 0 ? (_jsx("div", { className: "vertebr-command-empty", children: "No matches found." })) : ([...grouped.entries()].map(([group, groupItems]) => (_jsxs("div", { className: "vertebr-command-group", children: [_jsx("div", { className: "vertebr-command-group-label", children: group }), groupItems.map((item) => {
64
+ resultIndex += 1;
65
+ const index = resultIndex;
66
+ return (_jsxs("button", { type: "button", className: "vertebr-command-item", role: "option", "aria-selected": index === activeIndex, "data-active": index === activeIndex || undefined, onMouseEnter: () => setActiveIndex(index), onClick: () => pick(item), children: [_jsx("span", { className: "vertebr-command-item-label", children: item.label }), item.hint ? (_jsx("span", { className: "vertebr-command-item-hint", children: item.hint })) : null] }, item.id));
67
+ })] }, group)))) })] }) }));
68
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"AdminContent.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AdminContent.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AdminContent.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AdminContent.tsx"],"names":[],"mappings":"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"}
@@ -6,7 +6,10 @@ import { FontLibraryBoard } from "../fonts/FontLibraryBoard";
6
6
  import { GalleryBoard } from "../gallery/GalleryBoard";
7
7
  import { MetricsBoard } from "../metrics/MetricsBoard";
8
8
  import { ResourcePanel } from "../resources/ResourceTable";
9
+ import { AddonEditor } from "./AddonEditor";
10
+ import { AddonOverview } from "./AddonOverview";
9
11
  import { PagePreviewPane } from "./PagePreviewPane";
12
+ import { AdminSyncPage } from "./AdminSyncPage";
10
13
  function ConfigEditor({ client, configData, isPageSelection, previewPath, onConfigSaved, galleryPicker, fontLibraryPicker, }) {
11
14
  const [draft, setDraft] = useState(configData.value);
12
15
  const showPreview = Boolean(previewPath);
@@ -27,7 +30,7 @@ export function AdminContent({ client, catalog, selection, onSelectionChange, au
27
30
  ? "Loading…"
28
31
  : "Unable to load catalog." }) }) }));
29
32
  }
30
- return (_jsx("div", { className: "vertebr-content", children: _jsxs("section", { className: "vertebr-panel", children: [selection?.kind === "overview" ? (_jsx(MetricsBoard, { label: metricsData?.label ?? catalog.metrics?.label, windowLabel: metricsData?.windowLabel, compareLabel: metricsData?.compareLabel, metrics: metricsData?.metrics ?? [], charts: metricsData?.charts ?? [], range: metricsRange, onRangeChange: onMetricsRangeChange, loading: metricsLoading, onRefresh: () => void onRefreshMetrics() })) : 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 onRefreshGallery(), onUpload: async (files) => {
33
+ return (_jsx("div", { className: "vertebr-content", children: _jsxs("section", { className: "vertebr-panel", children: [selection?.kind === "overview" ? (_jsx(MetricsBoard, { label: metricsData?.label ?? catalog.metrics?.label, windowLabel: metricsData?.windowLabel, compareLabel: metricsData?.compareLabel, metrics: metricsData?.metrics ?? [], charts: metricsData?.charts ?? [], range: metricsRange, onRangeChange: onMetricsRangeChange, loading: metricsLoading, onRefresh: () => void onRefreshMetrics() })) : null, selection?.kind === "sync" ? (_jsx(AdminSyncPage, { client: client, catalog: catalog })) : 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 onRefreshGallery(), onUpload: async (files) => {
31
34
  if (files.length === 1 && files[0]) {
32
35
  await client.uploadGalleryFile(files[0]);
33
36
  }
@@ -135,6 +138,11 @@ export function AdminContent({ client, catalog, selection, onSelectionChange, au
135
138
  const result = await client.uploadResourceFiles(resourceData.id, field, files);
136
139
  return result.files;
137
140
  }
138
- : undefined, ...galleryPicker })) : null, selection?.kind === "config" && configData ? (_jsx(ConfigEditor, { client: client, configData: configData, isPageSelection: isPageSelection, previewPath: catalog.configs.find((item) => item.id === configData.id)
139
- ?.previewPath, onConfigSaved: onConfigSaved, galleryPicker: galleryPicker, fontLibraryPicker: fontLibraryPicker }, configData.id)) : null] }) }));
141
+ : undefined, ...galleryPicker })) : null, selection?.kind === "addons" ? (_jsx(AddonOverview, { client: client, catalog: catalog, onSelectAddon: (id) => onSelectionChange?.({ kind: "addon", id }) })) : null, selection?.kind === "config" && configData ? (_jsx(ConfigEditor, { client: client, configData: configData, isPageSelection: isPageSelection, previewPath: catalog.configs.find((item) => item.id === configData.id)
142
+ ?.previewPath, onConfigSaved: onConfigSaved, galleryPicker: galleryPicker, fontLibraryPicker: fontLibraryPicker }, configData.id)) : null, selection?.kind === "addon" && configData ? ((() => {
143
+ const addon = catalog.addons?.find((item) => item.id === configData.id);
144
+ if (!addon)
145
+ return null;
146
+ return (_jsx(AddonEditor, { client: client, addon: addon, configData: configData, onConfigSaved: onConfigSaved, galleryPicker: galleryPicker, fontLibraryPicker: fontLibraryPicker }, configData.id));
147
+ })()) : null] }) }));
140
148
  }
@@ -1,16 +1,15 @@
1
- import type { AdminEnvironment } from "@vertebr/client";
2
1
  import type { Breadcrumb } from "./breadcrumbs";
3
2
  import type { Selection } from "./types";
4
3
  export type AdminHeaderProps = {
5
4
  activeLabel: string;
6
- activeEnv?: AdminEnvironment;
7
5
  catalogLoaded: boolean;
8
6
  authRequired: boolean;
9
7
  selection: Selection;
10
8
  isPageSelection: boolean;
11
9
  hasPagePreview?: boolean;
10
+ selectionDescription?: string;
12
11
  error: string | null;
13
12
  breadcrumbs: Breadcrumb[];
14
13
  };
15
- export declare function AdminHeader({ activeLabel, activeEnv, catalogLoaded, authRequired, selection, isPageSelection, hasPagePreview, error, breadcrumbs, }: AdminHeaderProps): import("react").JSX.Element;
14
+ export declare function AdminHeader({ activeLabel, catalogLoaded, authRequired, selection, isPageSelection, hasPagePreview, selectionDescription, error, breadcrumbs, }: AdminHeaderProps): import("react").JSX.Element;
16
15
  //# sourceMappingURL=AdminHeader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AdminHeader.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AdminHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,SAAS,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B,CAAC;AAiDF,wBAAgB,WAAW,CAAC,EAC1B,WAAW,EACX,SAAS,EACT,aAAa,EACb,YAAY,EACZ,SAAS,EACT,eAAe,EACf,cAAc,EACd,KAAK,EACL,WAAW,GACZ,EAAE,gBAAgB,+BA6ClB"}
1
+ {"version":3,"file":"AdminHeader.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AdminHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,SAAS,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B,CAAC;AAyDF,wBAAgB,WAAW,CAAC,EAC1B,WAAW,EACX,aAAa,EACb,YAAY,EACZ,SAAS,EACT,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,KAAK,EACL,WAAW,GACZ,EAAE,gBAAgB,+BAoClB"}
@@ -1,11 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- function subtitle({ catalogLoaded, authRequired, selection, isPageSelection, hasPagePreview, }) {
2
+ function subtitle({ catalogLoaded, authRequired, selection, isPageSelection, hasPagePreview, selectionDescription, }) {
3
3
  if (!catalogLoaded && authRequired) {
4
4
  return "Provide an access token to load this environment.";
5
5
  }
6
+ if (selectionDescription) {
7
+ return selectionDescription;
8
+ }
6
9
  if (selection?.kind === "overview") {
7
10
  return "Commerce, growth, and catalog for the selected environment.";
8
11
  }
12
+ if (selection?.kind === "sync") {
13
+ return "Copy selected content between environments.";
14
+ }
9
15
  if (selection?.kind === "gallery") {
10
16
  return "Browse and upload shared media assets.";
11
17
  }
@@ -32,12 +38,13 @@ function subtitle({ catalogLoaded, authRequired, selection, isPageSelection, has
32
38
  }
33
39
  return "Select a panel.";
34
40
  }
35
- export function AdminHeader({ activeLabel, activeEnv, catalogLoaded, authRequired, selection, isPageSelection, hasPagePreview, error, breadcrumbs, }) {
36
- return (_jsxs("header", { className: "vertebr-header", children: [_jsxs("div", { children: [breadcrumbs.length > 1 ? (_jsx("ol", { className: "vertebr-breadcrumbs", children: breadcrumbs.map((crumb, index) => (_jsx("li", { children: index === breadcrumbs.length - 1 ? (_jsx("strong", { children: crumb.label })) : (crumb.label) }, `${crumb.label}-${index}`))) })) : null, _jsxs("div", { className: "vertebr-heading-row", children: [_jsx("h1", { children: activeLabel }), activeEnv ? (_jsx("span", { className: "vertebr-env-badge", "data-tone": activeEnv.tone ?? "neutral", children: activeEnv.label })) : null] }), _jsx("p", { children: subtitle({
41
+ export function AdminHeader({ activeLabel, catalogLoaded, authRequired, selection, isPageSelection, hasPagePreview, selectionDescription, error, breadcrumbs, }) {
42
+ return (_jsxs("header", { className: "vertebr-header", children: [_jsxs("div", { children: [breadcrumbs.length > 1 ? (_jsx("ol", { className: "vertebr-breadcrumbs", children: breadcrumbs.map((crumb, index) => (_jsx("li", { children: index === breadcrumbs.length - 1 ? (_jsx("strong", { children: crumb.label })) : (crumb.label) }, `${crumb.label}-${index}`))) })) : null, _jsx("h1", { children: activeLabel }), _jsx("p", { children: subtitle({
37
43
  catalogLoaded,
38
44
  authRequired,
39
45
  selection,
40
46
  isPageSelection,
41
47
  hasPagePreview,
48
+ selectionDescription,
42
49
  }) })] }), error ? (_jsx("span", { className: "vertebr-status", "data-tone": "danger", children: error })) : null] }));
43
50
  }
@@ -0,0 +1,5 @@
1
+ export type AdminPoweredByProps = {
2
+ collapsed?: boolean;
3
+ };
4
+ export declare function AdminPoweredBy({ collapsed }: AdminPoweredByProps): import("react").JSX.Element;
5
+ //# sourceMappingURL=AdminPoweredBy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdminPoweredBy.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AdminPoweredBy.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,EAAE,mBAAmB,+BAwBhE"}
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ const VERTEBR_URL = "https://github.com/yaboijams/vertebr";
3
+ export function AdminPoweredBy({ collapsed }) {
4
+ if (collapsed) {
5
+ return (_jsx("div", { className: "vertebr-powered-by", "data-collapsed": "true", children: _jsx("a", { href: VERTEBR_URL, target: "_blank", rel: "noopener noreferrer", title: "Powered by Vertebr", "aria-label": "Powered by Vertebr", children: "V" }) }));
6
+ }
7
+ return (_jsx("div", { className: "vertebr-powered-by", children: _jsxs("a", { href: VERTEBR_URL, target: "_blank", rel: "noopener noreferrer", children: ["Powered by ", _jsx("strong", { children: "Vertebr" })] }) }));
8
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"AdminSidebar.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AdminSidebar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgB,eAAe,EAAE,MAAM,SAAS,CAAC;AAG7D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAwFF,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,iBAAiB,+BAuBvE"}
1
+ {"version":3,"file":"AdminSidebar.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AdminSidebar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAgB,eAAe,EAAE,MAAM,SAAS,CAAC;AAG7D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AA6FF,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,iBAAiB,+BAwBvE"}
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from "react";
3
+ import { AdminPoweredBy } from "./AdminPoweredBy";
3
4
  import { iconForNavKey } from "../ui/icons";
4
5
  function SidebarNavItem({ item, collapsed, }) {
5
6
  const hasChildren = Boolean(item.children?.length);
@@ -11,17 +12,18 @@ function SidebarNavItem({ item, collapsed, }) {
11
12
  if (sectionActive)
12
13
  setOpen(true);
13
14
  }, [sectionActive]);
14
- if (!hasChildren) {
15
- return (_jsxs("button", { type: "button", "data-active": item.active, title: collapsed ? item.label : undefined, onClick: item.onSelect, children: [_jsx(Icon, { className: "vertebr-nav-icon" }), _jsx("span", { className: "vertebr-nav-label-text", children: item.label })] }));
15
+ if (!hasChildren || collapsed) {
16
+ const active = hasChildren ? sectionActive : item.active;
17
+ return (_jsxs("button", { type: "button", "data-active": active || undefined, title: collapsed ? item.label : undefined, onClick: item.onSelect, children: [_jsx(Icon, { className: "vertebr-nav-icon" }), _jsx("span", { className: "vertebr-nav-label-text", children: item.label })] }));
16
18
  }
17
19
  return (_jsxs("div", { className: "vertebr-nav-item", "data-has-children": "true", "data-open": open || undefined, children: [_jsxs("div", { className: "vertebr-nav-parent", children: [_jsxs("button", { type: "button", className: "vertebr-nav-parent-label", "data-active": sectionActive && !childActive, "data-section": sectionActive || undefined, title: collapsed ? item.label : undefined, onClick: () => {
18
20
  setOpen(true);
19
21
  item.onSelect();
20
- }, children: [_jsx(Icon, { className: "vertebr-nav-icon" }), _jsx("span", { className: "vertebr-nav-label-text", children: item.label })] }), !collapsed ? (_jsx("button", { type: "button", className: "vertebr-nav-parent-toggle", "aria-label": open ? `Collapse ${item.label}` : `Expand ${item.label}`, "aria-expanded": open, onClick: () => setOpen((prev) => !prev), children: _jsx("span", { "aria-hidden": "true", children: open ? "▾" : "▸" }) })) : null] }), open && !collapsed ? (_jsx("div", { className: "vertebr-nav-sub", role: "group", children: item.children.map((child) => (_jsx("button", { type: "button", className: "vertebr-nav-subitem", "data-active": child.active, onClick: () => {
21
- setOpen(true);
22
- child.onSelect();
23
- }, children: child.label }, child.key))) })) : null] }));
22
+ }, children: [_jsx(Icon, { className: "vertebr-nav-icon" }), _jsx("span", { className: "vertebr-nav-label-text", children: item.label })] }), !collapsed ? (_jsx("button", { type: "button", className: "vertebr-nav-parent-toggle", "aria-label": open ? `Collapse ${item.label}` : `Expand ${item.label}`, "aria-expanded": open, onClick: () => setOpen((prev) => !prev), children: _jsx("span", { className: "vertebr-nav-chevron", "aria-hidden": "true", children: "\u25B8" }) })) : null] }), _jsx("div", { className: "vertebr-nav-sub-wrap", "data-open": open ? "true" : undefined, children: _jsx("div", { className: "vertebr-nav-sub-inner", children: _jsx("div", { className: "vertebr-nav-sub", role: "group", children: item.children.map((child) => (_jsx("button", { type: "button", className: "vertebr-nav-subitem", "data-active": child.active, onClick: () => {
23
+ setOpen(true);
24
+ child.onSelect();
25
+ }, children: child.label }, child.key))) }) }) })] }));
24
26
  }
25
27
  export function AdminSidebar({ navGroups, collapsed }) {
26
- return (_jsx("aside", { className: "vertebr-sidebar", "data-collapsed": collapsed || undefined, children: _jsx("div", { className: "vertebr-sidebar-top", children: _jsx("nav", { className: "vertebr-nav", children: navGroups.map((group) => (_jsxs("div", { className: "vertebr-nav-group", children: [!collapsed ? (_jsx("div", { className: "vertebr-nav-label", children: group.label })) : null, group.items.map((item) => (_jsx(SidebarNavItem, { item: item, collapsed: collapsed }, item.key)))] }, group.label))) }) }) }));
28
+ return (_jsxs("aside", { className: "vertebr-sidebar", "data-collapsed": collapsed || undefined, children: [_jsx("div", { className: "vertebr-sidebar-top", children: _jsx("nav", { className: "vertebr-nav", children: navGroups.map((group) => (_jsxs("div", { className: "vertebr-nav-group", children: [_jsx("div", { className: "vertebr-nav-label", children: group.label }), group.items.map((item) => (_jsx(SidebarNavItem, { item: item, collapsed: collapsed }, item.key)))] }, group.label))) }) }), _jsx("div", { className: "vertebr-sidebar-bottom", children: _jsx(AdminPoweredBy, { collapsed: collapsed }) })] }));
27
29
  }
@@ -0,0 +1,7 @@
1
+ import type { CatalogResponse, VertebrClient } from "@vertebr/client";
2
+ export type AdminSyncPageProps = {
3
+ client: VertebrClient;
4
+ catalog: CatalogResponse;
5
+ };
6
+ export declare function AdminSyncPage({ client, catalog }: AdminSyncPageProps): import("react").JSX.Element;
7
+ //# sourceMappingURL=AdminSyncPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdminSyncPage.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AdminSyncPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,eAAe,EAGf,aAAa,EACd,MAAM,iBAAiB,CAAC;AAOzB,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,eAAe,CAAC;CAC1B,CAAC;AAiDF,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,kBAAkB,+BA2VpE"}