@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,11 +1,28 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { flexRender, getCoreRowModel, useReactTable, } from "@tanstack/react-table";
|
|
4
4
|
import { ConfigForm } from "../config/ConfigForm";
|
|
5
5
|
import { BulkImageUploadModal } from "./BulkImageUploadModal";
|
|
6
6
|
import { ColumnVisibilityMenu } from "./ColumnVisibilityMenu";
|
|
7
7
|
import { ResourceCell } from "./ResourceCell";
|
|
8
|
+
import { ResourceCreateModal } from "./ResourceCreateModal";
|
|
9
|
+
import { actionInputSchema, ResourceActionModal, } from "./ResourceActionModal";
|
|
10
|
+
import { ResourceMailModal } from "./ResourceMailModal";
|
|
8
11
|
import { ResourceViewModal } from "./ResourceViewModal";
|
|
12
|
+
function actionHasInput(meta) {
|
|
13
|
+
return Boolean(meta?.input && Object.keys(meta.input).length > 0);
|
|
14
|
+
}
|
|
15
|
+
function actionIsMail(meta) {
|
|
16
|
+
return Boolean(meta?.mail);
|
|
17
|
+
}
|
|
18
|
+
function toggleId(current, id) {
|
|
19
|
+
const next = new Set(current);
|
|
20
|
+
if (next.has(id))
|
|
21
|
+
next.delete(id);
|
|
22
|
+
else
|
|
23
|
+
next.add(id);
|
|
24
|
+
return next;
|
|
25
|
+
}
|
|
9
26
|
function resolveRowId(row, keys) {
|
|
10
27
|
for (const key of keys) {
|
|
11
28
|
const value = row[key];
|
|
@@ -31,32 +48,69 @@ function rowTitle(row, keys) {
|
|
|
31
48
|
}
|
|
32
49
|
return "Record";
|
|
33
50
|
}
|
|
34
|
-
function
|
|
51
|
+
function writeVisibility(storageKey, value) {
|
|
35
52
|
if (!storageKey || typeof localStorage === "undefined")
|
|
36
|
-
return
|
|
53
|
+
return;
|
|
37
54
|
try {
|
|
38
|
-
|
|
39
|
-
if (!raw)
|
|
40
|
-
return {};
|
|
41
|
-
const parsed = JSON.parse(raw);
|
|
42
|
-
if (!parsed || typeof parsed !== "object")
|
|
43
|
-
return {};
|
|
44
|
-
return parsed;
|
|
55
|
+
localStorage.setItem(`vertebr:columns:v2:${storageKey}`, JSON.stringify(value));
|
|
45
56
|
}
|
|
46
57
|
catch {
|
|
47
|
-
|
|
58
|
+
/* ignore quota / private mode */
|
|
48
59
|
}
|
|
49
60
|
}
|
|
50
|
-
function
|
|
61
|
+
function isDefaultHiddenColumn(key, field, schema) {
|
|
62
|
+
if (/^show[A-Z]/.test(key))
|
|
63
|
+
return true;
|
|
64
|
+
if (field?.type === "richtext")
|
|
65
|
+
return true;
|
|
66
|
+
if (key === "updatedAt" || key === "createdAt")
|
|
67
|
+
return true;
|
|
68
|
+
if ((key === "imageSrc" || key === "imageAlt") && "images" in schema) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
if (key === "slug" && "name" in schema)
|
|
72
|
+
return true;
|
|
73
|
+
if (field?.type === "string" && /^(details|description)$/i.test(key)) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
function defaultVisibility(schema) {
|
|
79
|
+
const next = {};
|
|
80
|
+
for (const [key, field] of Object.entries(schema)) {
|
|
81
|
+
if (isDefaultHiddenColumn(key, field, schema))
|
|
82
|
+
next[key] = false;
|
|
83
|
+
}
|
|
84
|
+
return next;
|
|
85
|
+
}
|
|
86
|
+
function readVisibility(storageKey, schema) {
|
|
87
|
+
const defaults = defaultVisibility(schema);
|
|
51
88
|
if (!storageKey || typeof localStorage === "undefined")
|
|
52
|
-
return;
|
|
89
|
+
return defaults;
|
|
53
90
|
try {
|
|
54
|
-
localStorage.
|
|
91
|
+
const raw = localStorage.getItem(`vertebr:columns:v2:${storageKey}`);
|
|
92
|
+
if (!raw)
|
|
93
|
+
return defaults;
|
|
94
|
+
const parsed = JSON.parse(raw);
|
|
95
|
+
if (!parsed || typeof parsed !== "object")
|
|
96
|
+
return defaults;
|
|
97
|
+
return { ...defaults, ...parsed };
|
|
55
98
|
}
|
|
56
99
|
catch {
|
|
57
|
-
|
|
100
|
+
return defaults;
|
|
58
101
|
}
|
|
59
102
|
}
|
|
103
|
+
function addRecordLabel(resourceLabel) {
|
|
104
|
+
const name = resourceLabel?.trim();
|
|
105
|
+
if (!name)
|
|
106
|
+
return "Add record";
|
|
107
|
+
const singular = /ies$/i.test(name)
|
|
108
|
+
? name.replace(/ies$/i, "y")
|
|
109
|
+
: /s$/i.test(name)
|
|
110
|
+
? name.slice(0, -1)
|
|
111
|
+
: name;
|
|
112
|
+
return `Add ${singular.toLowerCase()}`;
|
|
113
|
+
}
|
|
60
114
|
function titleFromFilename(name) {
|
|
61
115
|
return name
|
|
62
116
|
.replace(/\.[^.]+$/, "")
|
|
@@ -64,26 +118,106 @@ function titleFromFilename(name) {
|
|
|
64
118
|
.replace(/\s+/g, " ")
|
|
65
119
|
.trim();
|
|
66
120
|
}
|
|
67
|
-
export function ResourcePanel({ schema, items, permissions, actions = {}, uploads, rowIdKeys = ["id", "slug", "uid", "email"], storageKey, onUpdate, onCreate, onDelete, onAction, onUpload, galleryUpload, onListGallery, onUploadGallery, }) {
|
|
121
|
+
export function ResourcePanel({ schema, items, permissions, actions = {}, label, uploads, rowIdKeys = ["id", "slug", "uid", "email"], storageKey, onUpdate, onCreate, onDelete, onAction, onActionDone, onPreviewMail, collectionActions = {}, onCollectionAction, onUpload, galleryUpload, onListGallery, onUploadGallery, }) {
|
|
68
122
|
const [editing, setEditing] = useState(null);
|
|
123
|
+
const [creating, setCreating] = useState(false);
|
|
69
124
|
const [viewing, setViewing] = useState(null);
|
|
70
125
|
const [bulkOpen, setBulkOpen] = useState(false);
|
|
71
126
|
const [busyAction, setBusyAction] = useState(null);
|
|
127
|
+
const [selected, setSelected] = useState(new Set());
|
|
128
|
+
const [pendingAction, setPendingAction] = useState(null);
|
|
129
|
+
const [pendingCollectionAction, setPendingCollectionAction] = useState(null);
|
|
72
130
|
const tableWrapRef = useRef(null);
|
|
73
131
|
const [tableOverflow, setTableOverflow] = useState({
|
|
74
132
|
overflow: false,
|
|
75
133
|
canLeft: false,
|
|
76
134
|
canRight: false,
|
|
77
135
|
});
|
|
78
|
-
const [columnVisibility, setColumnVisibility] = useState(() => readVisibility(storageKey));
|
|
136
|
+
const [columnVisibility, setColumnVisibility] = useState(() => readVisibility(storageKey, schema));
|
|
79
137
|
const canUpdate = Boolean(permissions?.update && onUpdate);
|
|
80
138
|
const canCreate = Boolean(permissions?.create && onCreate);
|
|
81
139
|
const canDelete = Boolean(permissions?.delete && onDelete);
|
|
140
|
+
const createLabel = addRecordLabel(label);
|
|
82
141
|
const canUpload = Boolean(uploads && onUpload && Object.keys(uploads).length);
|
|
83
142
|
const actionEntries = Object.entries(actions);
|
|
143
|
+
const collectionActionEntries = Object.entries(collectionActions);
|
|
84
144
|
const fieldKeys = Object.keys(schema);
|
|
145
|
+
const selectable = Boolean(onAction && actionEntries.length > 0);
|
|
85
146
|
useEffect(() => {
|
|
86
|
-
|
|
147
|
+
const valid = new Set(items
|
|
148
|
+
.map((row) => resolveRowId(row, rowIdKeys))
|
|
149
|
+
.filter((id) => Boolean(id)));
|
|
150
|
+
setSelected((current) => {
|
|
151
|
+
const next = new Set([...current].filter((id) => valid.has(id)));
|
|
152
|
+
return next.size === current.size ? current : next;
|
|
153
|
+
});
|
|
154
|
+
}, [items, rowIdKeys]);
|
|
155
|
+
const runActions = useCallback(async (actionId, rowIds, input) => {
|
|
156
|
+
if (!onAction || rowIds.length === 0)
|
|
157
|
+
return;
|
|
158
|
+
setBusyAction(actionId);
|
|
159
|
+
const errors = [];
|
|
160
|
+
try {
|
|
161
|
+
for (const rowId of rowIds) {
|
|
162
|
+
try {
|
|
163
|
+
await onAction(rowId, actionId, input);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
errors.push(`${rowId}: ${error instanceof Error ? error.message : "Failed"}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
await onActionDone?.();
|
|
170
|
+
setSelected(new Set());
|
|
171
|
+
if (errors.length > 0) {
|
|
172
|
+
window.alert(`Finished with ${errors.length} error(s).\n\n${errors.slice(0, 8).join("\n")}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
setBusyAction(null);
|
|
177
|
+
}
|
|
178
|
+
}, [onAction, onActionDone]);
|
|
179
|
+
const queueAction = useCallback((actionId, rowIds) => {
|
|
180
|
+
const meta = actions[actionId];
|
|
181
|
+
if (!meta || rowIds.length === 0 || !onAction)
|
|
182
|
+
return;
|
|
183
|
+
if (actionIsMail(meta) || actionHasInput(meta)) {
|
|
184
|
+
setPendingAction({ actionId, rowIds });
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const who = rowIds.length === 1 ? "this person" : `${rowIds.length} people`;
|
|
188
|
+
if (!window.confirm(`${meta.label} for ${who}?`))
|
|
189
|
+
return;
|
|
190
|
+
void runActions(actionId, rowIds);
|
|
191
|
+
}, [actions, onAction, runActions]);
|
|
192
|
+
const runCollectionAction = useCallback(async (actionId, input) => {
|
|
193
|
+
if (!onCollectionAction)
|
|
194
|
+
return;
|
|
195
|
+
setBusyAction(actionId);
|
|
196
|
+
try {
|
|
197
|
+
await onCollectionAction(actionId, input);
|
|
198
|
+
await onActionDone?.();
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
window.alert(error instanceof Error ? error.message : "Action failed");
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
setBusyAction(null);
|
|
205
|
+
}
|
|
206
|
+
}, [onCollectionAction, onActionDone]);
|
|
207
|
+
const queueCollectionAction = useCallback((actionId) => {
|
|
208
|
+
const meta = collectionActions[actionId];
|
|
209
|
+
if (!meta || !onCollectionAction)
|
|
210
|
+
return;
|
|
211
|
+
if (actionHasInput(meta)) {
|
|
212
|
+
setPendingCollectionAction(actionId);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (!window.confirm(`${meta.label}?`))
|
|
216
|
+
return;
|
|
217
|
+
void runCollectionAction(actionId);
|
|
218
|
+
}, [collectionActions, onCollectionAction, runCollectionAction]);
|
|
219
|
+
useEffect(() => {
|
|
220
|
+
setColumnVisibility(readVisibility(storageKey, schema));
|
|
87
221
|
}, [storageKey]);
|
|
88
222
|
useEffect(() => {
|
|
89
223
|
writeVisibility(storageKey, columnVisibility);
|
|
@@ -110,6 +244,9 @@ export function ResourcePanel({ schema, items, permissions, actions = {}, upload
|
|
|
110
244
|
el.addEventListener("scroll", onScroll, { passive: true });
|
|
111
245
|
const observer = new ResizeObserver(updateTableOverflow);
|
|
112
246
|
observer.observe(el);
|
|
247
|
+
const table = el.querySelector("table");
|
|
248
|
+
if (table)
|
|
249
|
+
observer.observe(table);
|
|
113
250
|
return () => {
|
|
114
251
|
el.removeEventListener("scroll", onScroll);
|
|
115
252
|
observer.disconnect();
|
|
@@ -130,7 +267,33 @@ export function ResourcePanel({ schema, items, permissions, actions = {}, upload
|
|
|
130
267
|
label: schema[key]?.label ?? humanizeKey(key),
|
|
131
268
|
})), [fieldKeys, schema]);
|
|
132
269
|
const columns = useMemo(() => {
|
|
133
|
-
const defs =
|
|
270
|
+
const defs = [];
|
|
271
|
+
if (selectable) {
|
|
272
|
+
const visibleIds = items
|
|
273
|
+
.map((row) => resolveRowId(row, rowIdKeys))
|
|
274
|
+
.filter((id) => Boolean(id));
|
|
275
|
+
const allSelected = visibleIds.length > 0 && visibleIds.every((id) => selected.has(id));
|
|
276
|
+
defs.push({
|
|
277
|
+
id: "_select",
|
|
278
|
+
enableHiding: false,
|
|
279
|
+
header: () => (_jsx("input", { type: "checkbox", className: "vertebr-row-check", checked: allSelected, "aria-label": "Select all", onChange: () => {
|
|
280
|
+
setSelected((current) => {
|
|
281
|
+
if (visibleIds.every((id) => current.has(id))) {
|
|
282
|
+
return new Set();
|
|
283
|
+
}
|
|
284
|
+
return new Set(visibleIds);
|
|
285
|
+
});
|
|
286
|
+
} })),
|
|
287
|
+
cell: ({ row }) => {
|
|
288
|
+
const rowId = resolveRowId(row.original, rowIdKeys);
|
|
289
|
+
if (!rowId)
|
|
290
|
+
return null;
|
|
291
|
+
return (_jsx("input", { type: "checkbox", className: "vertebr-row-check", checked: selected.has(rowId), "aria-label": "Select row", onClick: (event) => event.stopPropagation(), onChange: () => setSelected((current) => toggleId(current, rowId)) }));
|
|
292
|
+
},
|
|
293
|
+
size: 44,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
defs.push(...(fieldKeys.length === 0
|
|
134
297
|
? [
|
|
135
298
|
{
|
|
136
299
|
id: "raw",
|
|
@@ -147,10 +310,10 @@ export function ResourcePanel({ schema, items, permissions, actions = {}, upload
|
|
|
147
310
|
accessorKey: key,
|
|
148
311
|
header: field?.label ?? humanizeKey(key),
|
|
149
312
|
meta: { fieldKey: key, field },
|
|
150
|
-
cell: ({ getValue }) => (_jsx(ResourceCell, { fieldKey: key, field: field, value: getValue() })),
|
|
313
|
+
cell: ({ getValue, }) => (_jsx(ResourceCell, { fieldKey: key, field: field, value: getValue() })),
|
|
151
314
|
size: isImage ? 220 : undefined,
|
|
152
315
|
};
|
|
153
|
-
});
|
|
316
|
+
})));
|
|
154
317
|
defs.push({
|
|
155
318
|
id: "_actions",
|
|
156
319
|
header: () => _jsx("span", { className: "vertebr-sr-only", children: "Actions" }),
|
|
@@ -158,12 +321,7 @@ export function ResourcePanel({ schema, items, permissions, actions = {}, upload
|
|
|
158
321
|
cell: ({ row }) => {
|
|
159
322
|
const rowId = resolveRowId(row.original, rowIdKeys);
|
|
160
323
|
return (_jsxs("div", { className: "vertebr-row-actions", onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: [_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", onClick: () => setViewing(row.original), children: "View" }), canUpdate ? (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", onClick: () => setEditing(row.original), children: "Edit" })) : null, rowId
|
|
161
|
-
? actionEntries.map(([actionId, meta]) => (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", disabled: busyAction
|
|
162
|
-
if (!onAction)
|
|
163
|
-
return;
|
|
164
|
-
setBusyAction(`${rowId}:${actionId}`);
|
|
165
|
-
void onAction(rowId, actionId).finally(() => setBusyAction(null));
|
|
166
|
-
}, children: meta.label }, actionId)))
|
|
324
|
+
? actionEntries.map(([actionId, meta]) => (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", disabled: busyAction != null, onClick: () => queueAction(actionId, [rowId]), children: meta.label }, actionId)))
|
|
167
325
|
: null, canDelete && rowId ? (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-danger-quiet", onClick: () => {
|
|
168
326
|
if (window.confirm("Delete this row? This cannot be undone.")) {
|
|
169
327
|
void onDelete?.(rowId);
|
|
@@ -175,11 +333,14 @@ export function ResourcePanel({ schema, items, permissions, actions = {}, upload
|
|
|
175
333
|
}, [
|
|
176
334
|
schema,
|
|
177
335
|
fieldKeys,
|
|
336
|
+
items,
|
|
337
|
+
selected,
|
|
338
|
+
selectable,
|
|
178
339
|
canUpdate,
|
|
179
340
|
canDelete,
|
|
180
341
|
actionEntries,
|
|
181
342
|
busyAction,
|
|
182
|
-
|
|
343
|
+
queueAction,
|
|
183
344
|
onDelete,
|
|
184
345
|
rowIdKeys,
|
|
185
346
|
]);
|
|
@@ -191,6 +352,23 @@ export function ResourcePanel({ schema, items, permissions, actions = {}, upload
|
|
|
191
352
|
getCoreRowModel: getCoreRowModel(),
|
|
192
353
|
});
|
|
193
354
|
const editingId = editing ? resolveRowId(editing, rowIdKeys) : null;
|
|
355
|
+
const createSchema = Object.fromEntries(Object.entries(schema)
|
|
356
|
+
.filter(([, field]) => !field.readOnly || field.required)
|
|
357
|
+
.map(([key, field]) => [
|
|
358
|
+
key,
|
|
359
|
+
field.readOnly ? { ...field, readOnly: false } : field,
|
|
360
|
+
]));
|
|
361
|
+
const createDefaults = Object.fromEntries(Object.entries(createSchema).map(([key, field]) => [
|
|
362
|
+
key,
|
|
363
|
+
field.default ??
|
|
364
|
+
(field.type === "boolean"
|
|
365
|
+
? false
|
|
366
|
+
: field.type === "number"
|
|
367
|
+
? undefined
|
|
368
|
+
: field.type === "file[]"
|
|
369
|
+
? []
|
|
370
|
+
: ""),
|
|
371
|
+
]));
|
|
194
372
|
if (editing && editingId && onUpdate) {
|
|
195
373
|
const editableSchema = Object.fromEntries(Object.entries(schema).filter(([, field]) => !field.readOnly));
|
|
196
374
|
const title = rowTitle(editing, rowIdKeys);
|
|
@@ -199,7 +377,7 @@ export function ResourcePanel({ schema, items, permissions, actions = {}, upload
|
|
|
199
377
|
setEditing(null);
|
|
200
378
|
} })] }));
|
|
201
379
|
}
|
|
202
|
-
const toolbar = (_jsxs("div", { className: "vertebr-table-toolbar", children: [_jsxs("div", { className: "vertebr-table-toolbar-start", children: [columnOptions.length > 0 ? (_jsx(ColumnVisibilityMenu, { columns: columnOptions, visibility: columnVisibility, onChange: setColumnVisibility })) : null, canUpload ? (_jsxs("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon", onClick: () => setBulkOpen(true), children: [_jsx(ImageUploadIcon, {}), "Bulk upload"] })) : null] }), tableOverflow.overflow ? (_jsxs("div", { className: "vertebr-table-scroll-controls", role: "group", "aria-label": "Scroll columns", children: [_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon vertebr-table-scroll-btn", disabled: !tableOverflow.canLeft, onClick: () => scrollTable("left"), "aria-label": "Scroll columns left", children: _jsx(ChevronLeftIcon, {}) }), _jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon vertebr-table-scroll-btn", disabled: !tableOverflow.canRight, onClick: () => scrollTable("right"), "aria-label": "Scroll columns right", children: _jsx(ChevronRightIcon, {}) })] })) : null] }));
|
|
380
|
+
const toolbar = (_jsxs("div", { className: "vertebr-table-toolbar", children: [_jsxs("div", { className: "vertebr-table-toolbar-start", children: [columnOptions.length > 0 ? (_jsx(ColumnVisibilityMenu, { columns: columnOptions, visibility: columnVisibility, onChange: setColumnVisibility })) : null, canUpload ? (_jsxs("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon", onClick: () => setBulkOpen(true), children: [_jsx(ImageUploadIcon, {}), "Bulk upload"] })) : null, collectionActionEntries.map(([actionId, meta]) => (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", disabled: busyAction != null, onClick: () => queueCollectionAction(actionId), children: meta.label }, actionId))), selectable && selected.size > 0 ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "vertebr-count", children: [selected.size, " selected"] }), actionEntries.map(([actionId, meta]) => (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", disabled: busyAction != null, onClick: () => queueAction(actionId, [...selected]), children: meta.label }, actionId))), _jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", onClick: () => setSelected(new Set()), children: "Clear" })] })) : null] }), tableOverflow.overflow ? (_jsxs("div", { className: "vertebr-table-scroll-controls", role: "group", "aria-label": "Scroll columns", children: [_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon vertebr-table-scroll-btn", disabled: !tableOverflow.canLeft, onClick: () => scrollTable("left"), "aria-label": "Scroll columns left", children: _jsx(ChevronLeftIcon, {}) }), _jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon vertebr-table-scroll-btn", disabled: !tableOverflow.canRight, onClick: () => scrollTable("right"), "aria-label": "Scroll columns right", children: _jsx(ChevronRightIcon, {}) })] })) : null] }));
|
|
203
381
|
const bulkModal = bulkOpen && uploads && onUpload ? (_jsx(BulkImageUploadModal, { uploads: uploads, canCreate: canCreate, fieldLabels: Object.fromEntries(Object.keys(uploads).map((key) => [
|
|
204
382
|
key,
|
|
205
383
|
schema[key]?.label ?? humanizeKey(key),
|
|
@@ -215,29 +393,57 @@ export function ResourcePanel({ schema, items, permissions, actions = {}, upload
|
|
|
215
393
|
}
|
|
216
394
|
}
|
|
217
395
|
: undefined })) : null;
|
|
396
|
+
const createModal = creating && onCreate ? (_jsx(ResourceCreateModal, { title: createLabel, schema: createSchema, value: createDefaults, uploads: uploads, onUpload: onUpload, galleryUpload: galleryUpload, onListGallery: onListGallery, onUploadGallery: onUploadGallery, onClose: () => setCreating(false), onCreate: onCreate })) : null;
|
|
397
|
+
const pendingActionModal = pendingAction ? (actionIsMail(actions[pendingAction.actionId]) && onPreviewMail ? (_jsx(ResourceMailModal, { title: actions[pendingAction.actionId]?.label ?? "Send email", count: pendingAction.rowIds.length, schema: actionInputSchema(actions[pendingAction.actionId]?.input ?? {}), submitLabel: busyAction
|
|
398
|
+
? "Sending…"
|
|
399
|
+
: pendingAction.rowIds.length === 1
|
|
400
|
+
? "Send"
|
|
401
|
+
: `Send to ${pendingAction.rowIds.length}`, onClose: () => setPendingAction(null), onPreview: (value) => onPreviewMail(pendingAction.rowIds[0], pendingAction.actionId, value), onSubmit: (value) => runActions(pendingAction.actionId, pendingAction.rowIds, value) })) : actions[pendingAction.actionId]?.input ? (_jsx(ResourceActionModal, { title: actions[pendingAction.actionId]?.label ?? "Run action", count: pendingAction.rowIds.length, schema: actionInputSchema(actions[pendingAction.actionId].input), submitLabel: busyAction
|
|
402
|
+
? "Sending…"
|
|
403
|
+
: pendingAction.rowIds.length === 1
|
|
404
|
+
? actions[pendingAction.actionId]?.label ?? "Send"
|
|
405
|
+
: `Send to ${pendingAction.rowIds.length}`, onClose: () => setPendingAction(null), onSubmit: (value) => runActions(pendingAction.actionId, pendingAction.rowIds, value) })) : null) : null;
|
|
406
|
+
const pendingCollectionModal = pendingCollectionAction &&
|
|
407
|
+
collectionActions[pendingCollectionAction]?.input ? (_jsx(ResourceActionModal, { title: collectionActions[pendingCollectionAction]?.label ?? "Run action", eyebrow: "This resource", schema: actionInputSchema(collectionActions[pendingCollectionAction].input), submitLabel: busyAction ? "Working…" : "Run", onClose: () => setPendingCollectionAction(null), onSubmit: (value) => runCollectionAction(pendingCollectionAction, value) })) : null;
|
|
408
|
+
const recordsHead = (_jsxs("div", { className: "vertebr-panel-head", children: [_jsx("h2", { children: "Records" }), _jsxs("div", { className: "vertebr-panel-head-actions", children: [canCreate ? (_jsxs("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon", onClick: () => setCreating(true), children: [_jsx(PlusIcon, {}), createLabel] })) : null, _jsx("span", { className: "vertebr-count", children: items.length })] })] }));
|
|
218
409
|
if (items.length === 0) {
|
|
219
|
-
return (_jsxs("div", { className: "vertebr-resource-body", children: [
|
|
410
|
+
return (_jsxs("div", { className: "vertebr-resource-body", children: [recordsHead, canUpload ||
|
|
411
|
+
columnOptions.length > 0 ||
|
|
412
|
+
collectionActionEntries.length > 0
|
|
413
|
+
? toolbar
|
|
414
|
+
: null, _jsx("div", { className: "vertebr-empty", children: "No rows yet." }), bulkModal, createModal, pendingActionModal, pendingCollectionModal] }));
|
|
220
415
|
}
|
|
221
|
-
return (_jsxs("div", { className: "vertebr-resource-body", children: [
|
|
416
|
+
return (_jsxs("div", { className: "vertebr-resource-body", children: [recordsHead, toolbar, _jsx("div", { className: "vertebr-table-wrap", ref: tableWrapRef, "data-overflow": tableOverflow.overflow ? "true" : undefined, "data-overflow-left": tableOverflow.canLeft ? "true" : undefined, "data-overflow-right": tableOverflow.canRight ? "true" : undefined, children: _jsxs("table", { className: "vertebr-table", children: [_jsx("thead", { children: table.getHeaderGroups().map((headerGroup) => (_jsx("tr", { children: headerGroup.headers.map((header) => (_jsx("th", { className: header.column.id === "_actions"
|
|
222
417
|
? "vertebr-col-actions"
|
|
223
|
-
:
|
|
418
|
+
: header.column.id === "_select"
|
|
419
|
+
? "vertebr-col-select"
|
|
420
|
+
: undefined, children: header.isPlaceholder
|
|
224
421
|
? null
|
|
225
|
-
: flexRender(header.column.columnDef.header, header.getContext()) }, header.id))) }, headerGroup.id))) }), _jsx("tbody", { children: table.getRowModel().rows.map((row) => (_jsx("tr", { className: "vertebr-table-row-clickable",
|
|
422
|
+
: flexRender(header.column.columnDef.header, header.getContext()) }, header.id))) }, headerGroup.id))) }), _jsx("tbody", { children: table.getRowModel().rows.map((row) => (_jsx("tr", { className: "vertebr-table-row-clickable", "data-selected": selectable &&
|
|
423
|
+
resolveRowId(row.original, rowIdKeys) &&
|
|
424
|
+
selected.has(resolveRowId(row.original, rowIdKeys))
|
|
425
|
+
? "true"
|
|
426
|
+
: undefined, tabIndex: 0, onClick: () => setViewing(row.original), onKeyDown: (event) => {
|
|
226
427
|
if (event.key === "Enter" || event.key === " ") {
|
|
227
428
|
event.preventDefault();
|
|
228
429
|
setViewing(row.original);
|
|
229
430
|
}
|
|
230
431
|
}, children: row.getVisibleCells().map((cell) => (_jsx("td", { className: cell.column.id === "_actions"
|
|
231
432
|
? "vertebr-col-actions"
|
|
232
|
-
:
|
|
433
|
+
: cell.column.id === "_select"
|
|
434
|
+
? "vertebr-col-select"
|
|
435
|
+
: undefined, children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id))) }, row.id))) })] }) }), viewing ? (_jsx(ResourceViewModal, { schema: schema, row: viewing, title: rowTitle(viewing, rowIdKeys), canEdit: canUpdate, onClose: () => setViewing(null), onEdit: () => {
|
|
233
436
|
setEditing(viewing);
|
|
234
437
|
setViewing(null);
|
|
235
|
-
} })) : null, bulkModal] }));
|
|
438
|
+
} })) : null, pendingActionModal, pendingCollectionModal, bulkModal, createModal] }));
|
|
236
439
|
}
|
|
237
440
|
/** @deprecated Prefer ResourcePanel */
|
|
238
441
|
export function ResourceTable(props) {
|
|
239
442
|
return _jsx(ResourcePanel, { ...props });
|
|
240
443
|
}
|
|
444
|
+
function PlusIcon() {
|
|
445
|
+
return (_jsxs("svg", { className: "vertebr-btn-glyph", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M12 5v14" }), _jsx("path", { d: "M5 12h14" })] }));
|
|
446
|
+
}
|
|
241
447
|
function ChevronLeftIcon() {
|
|
242
448
|
return (_jsx("svg", { className: "vertebr-btn-glyph", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "m15 18-6-6 6-6" }) }));
|
|
243
449
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,12 @@ export { VertebrAdmin } from "./components/admin/VertebrAdmin";
|
|
|
2
2
|
export type { VertebrAdminProps } from "./components/admin/VertebrAdmin";
|
|
3
3
|
export { MetricsBoard } from "./components/metrics/MetricsBoard";
|
|
4
4
|
export { GalleryBoard } from "./components/gallery/GalleryBoard";
|
|
5
|
+
export { EmailsBoard } from "./components/emails/EmailsBoard";
|
|
6
|
+
export type { EmailsBoardProps } from "./components/emails/EmailsBoard";
|
|
7
|
+
export type { EmailRecipientOption } from "./components/emails/EmailRecipientSelect";
|
|
8
|
+
export type { MultiCheckOption } from "./components/emails/MultiCheckSelect";
|
|
9
|
+
export type { EmailsLibraryPanelProps } from "./components/emails/EmailsLibraryPanel";
|
|
10
|
+
export type { EmailsActivityPanelProps } from "./components/emails/EmailsActivityPanel";
|
|
5
11
|
export { ResourcePanel, ResourceTable } from "./components/resources/ResourceTable";
|
|
6
12
|
export { ThemeToggle } from "./components/theme/ThemeToggle";
|
|
7
13
|
export type { ThemeToggleProps } from "./components/theme/ThemeToggle";
|
|
@@ -17,5 +23,9 @@ export type { VertebrControlsProviderProps } from "./hooks/useVertebrControls";
|
|
|
17
23
|
export { createVertebrClient, VERTEBR_ENV_HEADER, renderMarkdown, } from "@vertebr/client";
|
|
18
24
|
export { VertebrMarkdown } from "@vertebr/client/react";
|
|
19
25
|
export type { VertebrMarkdownProps } from "@vertebr/client/react";
|
|
20
|
-
export
|
|
26
|
+
export { createVertebrCatalog, catalogHref, catalogMatch, } from "@vertebr/client";
|
|
27
|
+
export type { VertebrCatalog, VertebrCatalogOptions, PublicResourceResponse, } from "@vertebr/client";
|
|
28
|
+
export { VertebrCatalogProvider, useVertebrCatalog, useVertebrCatalogItem, } from "@vertebr/client/react";
|
|
29
|
+
export type { VertebrCatalogProviderProps, VertebrCatalogState, } from "@vertebr/client/react";
|
|
30
|
+
export type { VertebrClient, VertebrClientOptions, VertebrMetricsOptions, VertebrReadOptions, AdminEnvironment, BootstrapResponse, CatalogResponse, CatalogResource, CatalogConfig, CatalogConfigSection, EnvironmentAuthPublic, FieldSchema, FieldType, GalleryItem, GalleryMeta, GalleryResponse, MailPreviewResponse, MailLibraryTemplate, MailHistoryEntry, MailProductOption, MailDiscountOption, EmailsBoardResponse, MetricCard, MetricChart, MetricsResponse, ResourceListResponse, ResourceActionMeta, ResourceUploadMeta, ResourceUploadResponse, ResourceBulkUploadResponse, ConfigResponse, VertebrControlsMap, } from "@vertebr/client";
|
|
21
31
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAC7D,YAAY,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAG/E,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAClE,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACrB,WAAW,EACX,SAAS,EACT,WAAW,EACX,WAAW,EACX,eAAe,EACf,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC1B,cAAc,EACd,kBAAkB,GACnB,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,YAAY,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AACrF,YAAY,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,YAAY,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AACtF,YAAY,EAAE,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AACxF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAC7D,YAAY,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAG/E,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,cAAc,EACd,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACrB,WAAW,EACX,SAAS,EACT,WAAW,EACX,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC1B,cAAc,EACd,kBAAkB,GACnB,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { VertebrAdmin } from "./components/admin/VertebrAdmin";
|
|
2
2
|
export { MetricsBoard } from "./components/metrics/MetricsBoard";
|
|
3
3
|
export { GalleryBoard } from "./components/gallery/GalleryBoard";
|
|
4
|
+
export { EmailsBoard } from "./components/emails/EmailsBoard";
|
|
4
5
|
export { ResourcePanel, ResourceTable } from "./components/resources/ResourceTable";
|
|
5
6
|
export { ThemeToggle } from "./components/theme/ThemeToggle";
|
|
6
7
|
export { ConfigForm } from "./components/config/ConfigForm";
|
|
@@ -12,3 +13,5 @@ export { VertebrControlsProvider, useVertebrConfig, useVertebrControls, } from "
|
|
|
12
13
|
// Re-export the framework-agnostic client for convenience.
|
|
13
14
|
export { createVertebrClient, VERTEBR_ENV_HEADER, renderMarkdown, } from "@vertebr/client";
|
|
14
15
|
export { VertebrMarkdown } from "@vertebr/client/react";
|
|
16
|
+
export { createVertebrCatalog, catalogHref, catalogMatch, } from "@vertebr/client";
|
|
17
|
+
export { VertebrCatalogProvider, useVertebrCatalog, useVertebrCatalogItem, } from "@vertebr/client/react";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const METRICS_RANGES: readonly [{
|
|
2
|
+
readonly id: "7d";
|
|
3
|
+
readonly label: "Last 7 days";
|
|
4
|
+
}, {
|
|
5
|
+
readonly id: "14d";
|
|
6
|
+
readonly label: "Last 14 days";
|
|
7
|
+
}, {
|
|
8
|
+
readonly id: "30d";
|
|
9
|
+
readonly label: "Last 30 days";
|
|
10
|
+
}, {
|
|
11
|
+
readonly id: "this_month";
|
|
12
|
+
readonly label: "This month";
|
|
13
|
+
}, {
|
|
14
|
+
readonly id: "last_month";
|
|
15
|
+
readonly label: "Last month";
|
|
16
|
+
}];
|
|
17
|
+
export type MetricsRangeId = (typeof METRICS_RANGES)[number]["id"];
|
|
18
|
+
export declare const DEFAULT_METRICS_RANGE: MetricsRangeId;
|
|
19
|
+
export declare function parseMetricsRangeId(raw: string | null | undefined): MetricsRangeId;
|
|
20
|
+
//# sourceMappingURL=metricsRanges.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metricsRanges.d.ts","sourceRoot":"","sources":["../../src/lib/metricsRanges.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;EAMjB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;AAEnE,eAAO,MAAM,qBAAqB,EAAE,cAAsB,CAAC;AAI3D,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC7B,cAAc,CAGhB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const METRICS_RANGES = [
|
|
2
|
+
{ id: "7d", label: "Last 7 days" },
|
|
3
|
+
{ id: "14d", label: "Last 14 days" },
|
|
4
|
+
{ id: "30d", label: "Last 30 days" },
|
|
5
|
+
{ id: "this_month", label: "This month" },
|
|
6
|
+
{ id: "last_month", label: "Last month" },
|
|
7
|
+
];
|
|
8
|
+
export const DEFAULT_METRICS_RANGE = "14d";
|
|
9
|
+
const RANGE_IDS = new Set(METRICS_RANGES.map((item) => item.id));
|
|
10
|
+
export function parseMetricsRangeId(raw) {
|
|
11
|
+
if (raw && RANGE_IDS.has(raw))
|
|
12
|
+
return raw;
|
|
13
|
+
return DEFAULT_METRICS_RANGE;
|
|
14
|
+
}
|
package/dist/styles/cells.css
CHANGED
|
@@ -137,6 +137,11 @@
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
.vertebr-chip {
|
|
140
|
+
display: inline-block;
|
|
141
|
+
max-width: 12rem;
|
|
142
|
+
overflow: hidden;
|
|
143
|
+
text-overflow: ellipsis;
|
|
144
|
+
white-space: nowrap;
|
|
140
145
|
border: 1px solid var(--vb-border);
|
|
141
146
|
border-radius: 999px;
|
|
142
147
|
padding: 0.1rem 0.45rem;
|
|
@@ -145,6 +150,43 @@
|
|
|
145
150
|
background: var(--vb-surface-tint);
|
|
146
151
|
}
|
|
147
152
|
|
|
153
|
+
.vertebr-cell-thumbs {
|
|
154
|
+
display: flex;
|
|
155
|
+
align-items: center;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.vertebr-cell-thumbs img {
|
|
159
|
+
width: 36px;
|
|
160
|
+
height: 36px;
|
|
161
|
+
object-fit: cover;
|
|
162
|
+
border-radius: var(--vb-radius-sm);
|
|
163
|
+
border: 1px solid var(--vb-border);
|
|
164
|
+
background: var(--vb-bg-muted);
|
|
165
|
+
flex: none;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.vertebr-cell-thumbs img + img {
|
|
169
|
+
margin-left: -0.55rem;
|
|
170
|
+
box-shadow: -2px 0 0 var(--vb-bg-elevated);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.vertebr-cell-thumbs-more {
|
|
174
|
+
margin-left: 0.4rem;
|
|
175
|
+
font-size: 0.72rem;
|
|
176
|
+
font-weight: 600;
|
|
177
|
+
color: var(--vb-text-muted);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.vertebr-cell-thumbs-detail {
|
|
181
|
+
flex-wrap: wrap;
|
|
182
|
+
gap: 0.75rem;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.vertebr-cell-thumbs-detail img + img {
|
|
186
|
+
margin-left: 0;
|
|
187
|
+
box-shadow: none;
|
|
188
|
+
}
|
|
189
|
+
|
|
148
190
|
.vertebr-empty {
|
|
149
191
|
flex: 1 1 auto;
|
|
150
192
|
display: grid;
|