@actuate-media/cms-admin 0.21.1 → 0.22.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/__tests__/layout/sidebar-forms-badge.render.test.d.ts +2 -0
- package/dist/__tests__/layout/sidebar-forms-badge.render.test.d.ts.map +1 -0
- package/dist/__tests__/layout/sidebar-forms-badge.render.test.js +30 -0
- package/dist/__tests__/layout/sidebar-forms-badge.render.test.js.map +1 -0
- package/dist/__tests__/layout/sidebar-submenu.render.test.js +8 -2
- package/dist/__tests__/layout/sidebar-submenu.render.test.js.map +1 -1
- package/dist/__tests__/views/forms-list.render.test.d.ts +2 -0
- package/dist/__tests__/views/forms-list.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/forms-list.render.test.js +122 -0
- package/dist/__tests__/views/forms-list.render.test.js.map +1 -0
- package/dist/actuate-admin.css +1 -1
- package/dist/components/forms/Drawer.d.ts +13 -0
- package/dist/components/forms/Drawer.d.ts.map +1 -0
- package/dist/components/forms/Drawer.js +13 -0
- package/dist/components/forms/Drawer.js.map +1 -0
- package/dist/components/forms/EmbedPanel.d.ts +7 -0
- package/dist/components/forms/EmbedPanel.d.ts.map +1 -0
- package/dist/components/forms/EmbedPanel.js +91 -0
- package/dist/components/forms/EmbedPanel.js.map +1 -0
- package/dist/components/forms/FieldsPanel.d.ts +8 -0
- package/dist/components/forms/FieldsPanel.d.ts.map +1 -0
- package/dist/components/forms/FieldsPanel.js +123 -0
- package/dist/components/forms/FieldsPanel.js.map +1 -0
- package/dist/components/forms/FormSchemaDrawer.d.ts +9 -0
- package/dist/components/forms/FormSchemaDrawer.d.ts.map +1 -0
- package/dist/components/forms/FormSchemaDrawer.js +96 -0
- package/dist/components/forms/FormSchemaDrawer.js.map +1 -0
- package/dist/components/forms/NotificationsPanel.d.ts +6 -0
- package/dist/components/forms/NotificationsPanel.d.ts.map +1 -0
- package/dist/components/forms/NotificationsPanel.js +80 -0
- package/dist/components/forms/NotificationsPanel.js.map +1 -0
- package/dist/components/forms/primitives.d.ts +42 -0
- package/dist/components/forms/primitives.d.ts.map +1 -0
- package/dist/components/forms/primitives.js +96 -0
- package/dist/components/forms/primitives.js.map +1 -0
- package/dist/layout/Sidebar.d.ts +5 -0
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/Sidebar.js +43 -3
- package/dist/layout/Sidebar.js.map +1 -1
- package/dist/lib/forms-events.d.ts +17 -0
- package/dist/lib/forms-events.d.ts.map +1 -0
- package/dist/lib/forms-events.js +20 -0
- package/dist/lib/forms-events.js.map +1 -0
- package/dist/lib/forms-service.d.ts +80 -0
- package/dist/lib/forms-service.d.ts.map +1 -0
- package/dist/lib/forms-service.js +144 -0
- package/dist/lib/forms-service.js.map +1 -0
- package/dist/views/Forms.d.ts.map +1 -1
- package/dist/views/Forms.js +119 -17
- package/dist/views/Forms.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/layout/sidebar-forms-badge.render.test.tsx +50 -0
- package/src/__tests__/layout/sidebar-submenu.render.test.tsx +9 -2
- package/src/__tests__/views/forms-list.render.test.tsx +141 -0
- package/src/components/forms/Drawer.tsx +70 -0
- package/src/components/forms/EmbedPanel.tsx +173 -0
- package/src/components/forms/FieldsPanel.tsx +385 -0
- package/src/components/forms/FormSchemaDrawer.tsx +185 -0
- package/src/components/forms/NotificationsPanel.tsx +240 -0
- package/src/components/forms/primitives.tsx +200 -0
- package/src/layout/Sidebar.tsx +72 -6
- package/src/lib/forms-events.ts +32 -0
- package/src/lib/forms-service.ts +244 -0
- package/src/views/Forms.tsx +343 -106
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmbedPanel.js","sourceRoot":"","sources":["../../../src/components/forms/EmbedPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FormField } from '../../lib/forms-service.js';
|
|
2
|
+
export declare function FieldsPanel({ fields, onChange, hasSubmissions, }: {
|
|
3
|
+
fields: FormField[];
|
|
4
|
+
onChange: (next: FormField[]) => void;
|
|
5
|
+
/** When the form already has submissions, key renames/deletes are riskier. */
|
|
6
|
+
hasSubmissions: boolean;
|
|
7
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=FieldsPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FieldsPanel.d.ts","sourceRoot":"","sources":["../../../src/components/forms/FieldsPanel.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,4BAA4B,CAAA;AAqC1E,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,EACR,cAAc,GACf,EAAE;IACD,MAAM,EAAE,SAAS,EAAE,CAAA;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,IAAI,CAAA;IACrC,8EAA8E;IAC9E,cAAc,EAAE,OAAO,CAAA;CACxB,2CAiFA"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* Fields tab of the Form Schema drawer. Renders the form's field list with
|
|
5
|
+
* drag-to-reorder (dnd-kit, keyboard-accessible) plus an inline editor for the
|
|
6
|
+
* selected field. The parent owns the `fields` array and persistence; this
|
|
7
|
+
* panel is a controlled editor that calls `onChange` with the next array.
|
|
8
|
+
*/
|
|
9
|
+
import { DndContext, KeyboardSensor, PointerSensor, closestCenter, useSensor, useSensors, } from '@dnd-kit/core';
|
|
10
|
+
import { SortableContext, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy, } from '@dnd-kit/sortable';
|
|
11
|
+
import { CSS } from '@dnd-kit/utilities';
|
|
12
|
+
import { ChevronDown, GripVertical, Plus, Trash2 } from 'lucide-react';
|
|
13
|
+
import * as Switch from '@radix-ui/react-switch';
|
|
14
|
+
import { useId, useState } from 'react';
|
|
15
|
+
import { FieldTypeBadge, FormsEmptyState } from './primitives.js';
|
|
16
|
+
const FIELD_TYPES = [
|
|
17
|
+
{ value: 'text', label: 'Text' },
|
|
18
|
+
{ value: 'email', label: 'Email' },
|
|
19
|
+
{ value: 'phone', label: 'Phone' },
|
|
20
|
+
{ value: 'textarea', label: 'Textarea' },
|
|
21
|
+
{ value: 'select', label: 'Select' },
|
|
22
|
+
{ value: 'multiselect', label: 'Multi-select' },
|
|
23
|
+
{ value: 'radio', label: 'Radio' },
|
|
24
|
+
{ value: 'checkbox', label: 'Checkbox' },
|
|
25
|
+
{ value: 'date', label: 'Date' },
|
|
26
|
+
{ value: 'number', label: 'Number' },
|
|
27
|
+
{ value: 'url', label: 'URL' },
|
|
28
|
+
{ value: 'consent', label: 'Consent' },
|
|
29
|
+
{ value: 'file', label: 'File upload' },
|
|
30
|
+
{ value: 'hidden', label: 'Hidden' },
|
|
31
|
+
{ value: 'richtext', label: 'Content block' },
|
|
32
|
+
{ value: 'divider', label: 'Divider / heading' },
|
|
33
|
+
];
|
|
34
|
+
const OPTION_TYPES = ['select', 'multiselect', 'radio'];
|
|
35
|
+
function slugifyKey(label) {
|
|
36
|
+
return label
|
|
37
|
+
.toLowerCase()
|
|
38
|
+
.trim()
|
|
39
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
40
|
+
.replace(/^_+|_+$/g, '');
|
|
41
|
+
}
|
|
42
|
+
function makeId() {
|
|
43
|
+
if (typeof crypto !== 'undefined' && 'randomUUID' in crypto)
|
|
44
|
+
return crypto.randomUUID();
|
|
45
|
+
return `f_${Math.random().toString(36).slice(2)}`;
|
|
46
|
+
}
|
|
47
|
+
export function FieldsPanel({ fields, onChange, hasSubmissions, }) {
|
|
48
|
+
const [editingId, setEditingId] = useState(null);
|
|
49
|
+
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 4 } }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
|
|
50
|
+
function handleDragEnd(event) {
|
|
51
|
+
const { active, over } = event;
|
|
52
|
+
if (!over || active.id === over.id)
|
|
53
|
+
return;
|
|
54
|
+
const ids = fields.map((f) => f.id);
|
|
55
|
+
const from = ids.indexOf(String(active.id));
|
|
56
|
+
const to = ids.indexOf(String(over.id));
|
|
57
|
+
if (from === -1 || to === -1)
|
|
58
|
+
return;
|
|
59
|
+
const next = fields.slice();
|
|
60
|
+
const [moved] = next.splice(from, 1);
|
|
61
|
+
next.splice(to, 0, moved);
|
|
62
|
+
onChange(next.map((f, i) => ({ ...f, sortOrder: i })));
|
|
63
|
+
}
|
|
64
|
+
function updateField(id, patch) {
|
|
65
|
+
onChange(fields.map((f) => (f.id === id ? { ...f, ...patch } : f)));
|
|
66
|
+
}
|
|
67
|
+
function deleteField(id) {
|
|
68
|
+
onChange(fields.filter((f) => f.id !== id));
|
|
69
|
+
if (editingId === id)
|
|
70
|
+
setEditingId(null);
|
|
71
|
+
}
|
|
72
|
+
function addField() {
|
|
73
|
+
const id = makeId();
|
|
74
|
+
const next = {
|
|
75
|
+
id,
|
|
76
|
+
label: 'New Field',
|
|
77
|
+
key: `field_${fields.length + 1}`,
|
|
78
|
+
type: 'text',
|
|
79
|
+
required: false,
|
|
80
|
+
sortOrder: fields.length,
|
|
81
|
+
};
|
|
82
|
+
onChange([...fields, next]);
|
|
83
|
+
setEditingId(id);
|
|
84
|
+
}
|
|
85
|
+
return (_jsxs("div", { className: "space-y-3", children: [fields.length === 0 ? (_jsx(FormsEmptyState, { title: "No fields yet", description: "Add your first field to start building this form." })) : (_jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: fields.map((f) => f.id), strategy: verticalListSortingStrategy, children: _jsx("ul", { className: "space-y-2", children: fields.map((field) => (_jsx(SortableFieldRow, { field: field, editing: editingId === field.id, hasSubmissions: hasSubmissions, onToggleEdit: () => setEditingId((cur) => (cur === field.id ? null : field.id)), onUpdate: (patch) => updateField(field.id, patch), onDelete: () => deleteField(field.id) }, field.id))) }) }) })), _jsxs("button", { type: "button", onClick: addField, className: "border-border text-foreground hover:bg-accent flex w-full items-center justify-center gap-2 rounded-lg border border-dashed px-3 py-2.5 text-sm font-medium transition-colors", children: [_jsx(Plus, { className: "h-4 w-4", "aria-hidden": true }), "Add Field"] })] }));
|
|
86
|
+
}
|
|
87
|
+
function SortableFieldRow({ field, editing, hasSubmissions, onToggleEdit, onUpdate, onDelete, }) {
|
|
88
|
+
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
|
|
89
|
+
id: field.id,
|
|
90
|
+
});
|
|
91
|
+
const style = {
|
|
92
|
+
transform: CSS.Transform.toString(transform),
|
|
93
|
+
transition,
|
|
94
|
+
zIndex: isDragging ? 10 : undefined,
|
|
95
|
+
};
|
|
96
|
+
const needsOptions = OPTION_TYPES.includes(field.type);
|
|
97
|
+
return (_jsx("li", { ref: setNodeRef, style: style, children: _jsxs("div", { className: `border-border bg-card rounded-lg border ${isDragging ? 'shadow-md' : ''} ${editing ? 'ring-primary/30 ring-1' : ''}`, children: [_jsxs("div", { className: "flex items-center gap-2 px-2.5 py-2", children: [_jsx("button", { type: "button", className: "text-muted-foreground hover:text-foreground focus-visible:ring-ring shrink-0 cursor-grab touch-none rounded focus-visible:ring-2 focus-visible:outline-none", "aria-label": `Drag to reorder ${field.label}`, ...attributes, ...listeners, children: _jsx(GripVertical, { className: "h-4 w-4", "aria-hidden": true }) }), _jsx("button", { type: "button", onClick: onToggleEdit, className: "flex min-w-0 flex-1 items-center gap-2 text-left", "aria-expanded": editing, children: _jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: "text-foreground block truncate text-sm font-medium", children: field.label || '(untitled)' }), _jsx("span", { className: "text-muted-foreground block truncate font-mono text-xs", children: field.key })] }) }), _jsx(FieldTypeBadge, { type: field.type }), field.required && (_jsx("span", { className: "bg-muted text-muted-foreground rounded px-1.5 py-0.5 text-[10px] font-medium uppercase", children: "Required" })), _jsx("button", { type: "button", onClick: onToggleEdit, className: "text-muted-foreground hover:text-foreground focus-visible:ring-ring shrink-0 rounded p-1 focus-visible:ring-2 focus-visible:outline-none", "aria-label": `${editing ? 'Collapse' : 'Edit'} ${field.label}`, children: _jsx(ChevronDown, { className: `h-4 w-4 transition-transform ${editing ? '' : '-rotate-90'}`, "aria-hidden": true }) }), _jsx("button", { type: "button", onClick: onDelete, className: "text-muted-foreground hover:text-destructive focus-visible:ring-ring shrink-0 rounded p-1 focus-visible:ring-2 focus-visible:outline-none", "aria-label": `Delete ${field.label}`, children: _jsx(Trash2, { className: "h-4 w-4", "aria-hidden": true }) })] }), editing && (_jsx(FieldEditor, { field: field, hasSubmissions: hasSubmissions, needsOptions: needsOptions, onUpdate: onUpdate }))] }) }));
|
|
98
|
+
}
|
|
99
|
+
function FieldEditor({ field, hasSubmissions, needsOptions, onUpdate, }) {
|
|
100
|
+
const reqId = useId();
|
|
101
|
+
const optionsText = (field.options ?? []).map((o) => o.label).join('\n');
|
|
102
|
+
return (_jsxs("div", { className: "border-border space-y-3 border-t px-3 py-3", children: [_jsxs("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2", children: [_jsx(Labeled, { label: "Label", children: _jsx("input", { type: "text", value: field.label, onChange: (e) => {
|
|
103
|
+
const label = e.target.value;
|
|
104
|
+
// Auto-derive the key from the label until the form has data and
|
|
105
|
+
// until the user has clearly customised the key.
|
|
106
|
+
const autoKey = slugifyKey(field.label);
|
|
107
|
+
const patch = { label };
|
|
108
|
+
if (!hasSubmissions && (field.key === autoKey || !field.key)) {
|
|
109
|
+
patch.key = slugifyKey(label);
|
|
110
|
+
}
|
|
111
|
+
onUpdate(patch);
|
|
112
|
+
}, className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none" }) }), _jsx(Labeled, { label: "Key", hint: hasSubmissions ? 'Renaming affects existing entries & exports' : undefined, children: _jsx("input", { type: "text", value: field.key, onChange: (e) => onUpdate({ key: slugifyKey(e.target.value) }), className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 font-mono text-sm focus-visible:ring-2 focus-visible:outline-none" }) }), _jsx(Labeled, { label: "Type", children: _jsx("select", { value: field.type, onChange: (e) => onUpdate({ type: e.target.value }), className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none", children: FIELD_TYPES.map((t) => (_jsx("option", { value: t.value, children: t.label }, t.value))) }) }), _jsx(Labeled, { label: "Placeholder", children: _jsx("input", { type: "text", value: field.placeholder ?? '', onChange: (e) => onUpdate({ placeholder: e.target.value }), className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none" }) })] }), _jsx(Labeled, { label: "Help text", children: _jsx("input", { type: "text", value: field.helpText ?? '', onChange: (e) => onUpdate({ helpText: e.target.value }), className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none" }) }), needsOptions && (_jsx(Labeled, { label: "Options", hint: "One per line", children: _jsx("textarea", { rows: 3, value: optionsText, onChange: (e) => onUpdate({
|
|
113
|
+
options: e.target.value
|
|
114
|
+
.split('\n')
|
|
115
|
+
.map((line) => line.trim())
|
|
116
|
+
.filter(Boolean)
|
|
117
|
+
.map((label) => ({ label, value: slugifyKey(label) })),
|
|
118
|
+
}), className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none" }) })), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { htmlFor: reqId, className: "text-foreground text-sm font-medium", children: "Required" }), _jsx(Switch.Root, { id: reqId, checked: field.required, onCheckedChange: (v) => onUpdate({ required: v }), className: "bg-input-background data-[state=checked]:bg-primary focus-visible:ring-ring relative h-[18px] w-8 shrink-0 rounded-full transition-colors focus-visible:ring-2 focus-visible:outline-none", children: _jsx(Switch.Thumb, { className: "bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[14px]" }) })] })] }));
|
|
119
|
+
}
|
|
120
|
+
function Labeled({ label, hint, children, }) {
|
|
121
|
+
return (_jsxs("label", { className: "block", children: [_jsx("span", { className: "text-muted-foreground mb-1 block text-xs font-medium", children: label }), children, hint && _jsx("span", { className: "text-warning mt-1 block text-xs", children: hint })] }));
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=FieldsPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FieldsPanel.js","sourceRoot":"","sources":["../../../src/components/forms/FieldsPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FormListItem } from '../../lib/forms-service.js';
|
|
2
|
+
export declare function FormSchemaDrawer({ form, open, onOpenChange, onSaved, }: {
|
|
3
|
+
form: FormListItem | null;
|
|
4
|
+
open: boolean;
|
|
5
|
+
onOpenChange: (open: boolean) => void;
|
|
6
|
+
/** Called after a schema/settings change so the list can refetch. */
|
|
7
|
+
onSaved?: () => void;
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
9
|
+
//# sourceMappingURL=FormSchemaDrawer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormSchemaDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/forms/FormSchemaDrawer.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAe9D,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,IAAI,EACJ,YAAY,EACZ,OAAO,GACR,EAAE;IACD,IAAI,EAAE,YAAY,GAAG,IAAI,CAAA;IACzB,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB,kDA+IA"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* Form Schema drawer — the right-side panel opened from the Forms list "Schema"
|
|
5
|
+
* action. Three tabs: Fields (versioned schema editor), Embed (public snippets
|
|
6
|
+
* + domain restrictions), Notifications (per-form notification settings).
|
|
7
|
+
*
|
|
8
|
+
* Saving the Fields tab creates a new schema version server-side; existing
|
|
9
|
+
* submissions keep referencing the version they were captured against, so
|
|
10
|
+
* historical entries never break when the schema changes.
|
|
11
|
+
*/
|
|
12
|
+
import * as Tabs from '@radix-ui/react-tabs';
|
|
13
|
+
import { useEffect, useState } from 'react';
|
|
14
|
+
import { toast } from 'sonner';
|
|
15
|
+
import { fetchFormSchema, saveFormSchema } from '../../lib/forms-service.js';
|
|
16
|
+
import { emitFormsChanged } from '../../lib/forms-events.js';
|
|
17
|
+
import { ConfirmDialog } from '../ui/ConfirmDialog.js';
|
|
18
|
+
import { Drawer } from './Drawer.js';
|
|
19
|
+
import { FieldsPanel } from './FieldsPanel.js';
|
|
20
|
+
import { EmbedPanel } from './EmbedPanel.js';
|
|
21
|
+
import { NotificationsPanel } from './NotificationsPanel.js';
|
|
22
|
+
import { FormsErrorState, FormsLoading, btnPrimary, btnSecondary } from './primitives.js';
|
|
23
|
+
const TABS = [
|
|
24
|
+
{ id: 'fields', label: 'Fields' },
|
|
25
|
+
{ id: 'embed', label: 'Embed' },
|
|
26
|
+
{ id: 'notifications', label: 'Notifications' },
|
|
27
|
+
];
|
|
28
|
+
export function FormSchemaDrawer({ form, open, onOpenChange, onSaved, }) {
|
|
29
|
+
const [tab, setTab] = useState('fields');
|
|
30
|
+
const [fields, setFields] = useState([]);
|
|
31
|
+
const [loading, setLoading] = useState(false);
|
|
32
|
+
const [error, setError] = useState(null);
|
|
33
|
+
const [dirty, setDirty] = useState(false);
|
|
34
|
+
const [saving, setSaving] = useState(false);
|
|
35
|
+
const [confirmDiscard, setConfirmDiscard] = useState(false);
|
|
36
|
+
const formId = form?.id ?? null;
|
|
37
|
+
const hasSubmissions = (form?.totalEntries ?? 0) > 0;
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!open || !formId)
|
|
40
|
+
return;
|
|
41
|
+
setTab('fields');
|
|
42
|
+
setDirty(false);
|
|
43
|
+
setLoading(true);
|
|
44
|
+
setError(null);
|
|
45
|
+
let active = true;
|
|
46
|
+
fetchFormSchema(formId)
|
|
47
|
+
.then((schema) => {
|
|
48
|
+
if (active)
|
|
49
|
+
setFields(schema.fields);
|
|
50
|
+
})
|
|
51
|
+
.catch((e) => {
|
|
52
|
+
if (active)
|
|
53
|
+
setError(e instanceof Error ? e.message : 'Failed to load schema');
|
|
54
|
+
})
|
|
55
|
+
.finally(() => {
|
|
56
|
+
if (active)
|
|
57
|
+
setLoading(false);
|
|
58
|
+
});
|
|
59
|
+
return () => {
|
|
60
|
+
active = false;
|
|
61
|
+
};
|
|
62
|
+
}, [open, formId]);
|
|
63
|
+
function handleFieldsChange(next) {
|
|
64
|
+
setFields(next);
|
|
65
|
+
setDirty(true);
|
|
66
|
+
}
|
|
67
|
+
async function handleSave() {
|
|
68
|
+
if (!formId)
|
|
69
|
+
return;
|
|
70
|
+
setSaving(true);
|
|
71
|
+
const res = await saveFormSchema(formId, fields.map((f, i) => ({ ...f, sortOrder: i })));
|
|
72
|
+
setSaving(false);
|
|
73
|
+
if (res.error) {
|
|
74
|
+
toast.error(res.error);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
setDirty(false);
|
|
78
|
+
toast.success('Schema saved.');
|
|
79
|
+
emitFormsChanged();
|
|
80
|
+
onSaved?.();
|
|
81
|
+
}
|
|
82
|
+
function requestClose(next) {
|
|
83
|
+
if (!next && dirty) {
|
|
84
|
+
setConfirmDiscard(true);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
onOpenChange(next);
|
|
88
|
+
}
|
|
89
|
+
if (!form)
|
|
90
|
+
return null;
|
|
91
|
+
return (_jsxs(_Fragment, { children: [_jsx(Drawer, { open: open, onOpenChange: requestClose, title: form.name, description: `/${form.slug}`, width: "max-w-2xl", footer: tab === 'fields' ? (_jsxs(_Fragment, { children: [_jsx("button", { className: btnSecondary, onClick: () => requestClose(false), children: "Close" }), _jsx("button", { className: btnPrimary, onClick: handleSave, disabled: saving || loading, children: saving ? 'Saving…' : 'Save Schema' })] })) : undefined, children: _jsxs(Tabs.Root, { value: tab, onValueChange: setTab, children: [_jsx(Tabs.List, { className: "border-border mb-4 flex gap-1 border-b", "aria-label": "Form schema sections", children: TABS.map((t) => (_jsx(Tabs.Trigger, { value: t.id, className: "text-muted-foreground hover:text-foreground data-[state=active]:text-foreground data-[state=active]:border-primary focus-visible:ring-ring -mb-px border-b-2 border-transparent px-3 py-2 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none", children: t.label }, t.id))) }), _jsx(Tabs.Content, { value: "fields", tabIndex: -1, children: loading ? (_jsx(FormsLoading, { label: "Loading schema\u2026" })) : error ? (_jsx(FormsErrorState, { message: error, onRetry: () => formId && setTab('fields') })) : (_jsx(FieldsPanel, { fields: fields, onChange: handleFieldsChange, hasSubmissions: hasSubmissions })) }), _jsx(Tabs.Content, { value: "embed", tabIndex: -1, children: formId && _jsx(EmbedPanel, { formId: formId, slug: form.slug, status: form.status }) }), _jsx(Tabs.Content, { value: "notifications", tabIndex: -1, children: formId && _jsx(NotificationsPanel, { formId: formId, onChanged: onSaved }) })] }) }), _jsx(ConfirmDialog, { open: confirmDiscard, onClose: () => setConfirmDiscard(false), onConfirm: () => {
|
|
92
|
+
setDirty(false);
|
|
93
|
+
onOpenChange(false);
|
|
94
|
+
}, title: "Discard unsaved changes?", description: "You have unsaved schema changes. Closing now will discard them.", confirmLabel: "Discard", cancelLabel: "Keep editing", destructive: true })] }));
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=FormSchemaDrawer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormSchemaDrawer.js","sourceRoot":"","sources":["../../../src/components/forms/FormSchemaDrawer.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function NotificationsPanel({ formId, onChanged, }: {
|
|
2
|
+
formId: string;
|
|
3
|
+
/** Called after a successful save so the list can refresh the notify state. */
|
|
4
|
+
onChanged?: () => void;
|
|
5
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
6
|
+
//# sourceMappingURL=NotificationsPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationsPanel.d.ts","sourceRoot":"","sources":["../../../src/components/forms/NotificationsPanel.tsx"],"names":[],"mappings":"AAsBA,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,EAAE,MAAM,CAAA;IACd,+EAA+E;IAC/E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB,kDAmKA"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* Notifications tab of the Form Schema drawer. Persists per-form notification
|
|
5
|
+
* settings (recipients, reply-to, subject/message templates, field inclusion,
|
|
6
|
+
* autoresponder). Actual email/webhook delivery + the "send test" action are
|
|
7
|
+
* wired in a later phase (PR 6); this panel owns the configuration only.
|
|
8
|
+
*/
|
|
9
|
+
import { useEffect, useState } from 'react';
|
|
10
|
+
import * as Switch from '@radix-ui/react-switch';
|
|
11
|
+
import { toast } from 'sonner';
|
|
12
|
+
import { fetchNotificationSettings, updateNotificationSettings, } from '../../lib/forms-service.js';
|
|
13
|
+
import { emitFormsChanged } from '../../lib/forms-events.js';
|
|
14
|
+
import { FormsErrorState, FormsLoading, btnPrimary } from './primitives.js';
|
|
15
|
+
const inputCls = 'border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none';
|
|
16
|
+
export function NotificationsPanel({ formId, onChanged, }) {
|
|
17
|
+
const [settings, setSettings] = useState(null);
|
|
18
|
+
const [loading, setLoading] = useState(true);
|
|
19
|
+
const [error, setError] = useState(null);
|
|
20
|
+
const [saving, setSaving] = useState(false);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
let active = true;
|
|
23
|
+
setLoading(true);
|
|
24
|
+
setError(null);
|
|
25
|
+
fetchNotificationSettings(formId)
|
|
26
|
+
.then((s) => {
|
|
27
|
+
if (active)
|
|
28
|
+
setSettings(s);
|
|
29
|
+
})
|
|
30
|
+
.catch((e) => {
|
|
31
|
+
if (active)
|
|
32
|
+
setError(e instanceof Error ? e.message : 'Failed to load notification settings');
|
|
33
|
+
})
|
|
34
|
+
.finally(() => {
|
|
35
|
+
if (active)
|
|
36
|
+
setLoading(false);
|
|
37
|
+
});
|
|
38
|
+
return () => {
|
|
39
|
+
active = false;
|
|
40
|
+
};
|
|
41
|
+
}, [formId]);
|
|
42
|
+
function patch(p) {
|
|
43
|
+
setSettings((cur) => (cur ? { ...cur, ...p } : cur));
|
|
44
|
+
}
|
|
45
|
+
async function save() {
|
|
46
|
+
if (!settings)
|
|
47
|
+
return;
|
|
48
|
+
setSaving(true);
|
|
49
|
+
const res = await updateNotificationSettings(formId, settings);
|
|
50
|
+
setSaving(false);
|
|
51
|
+
if (res.error) {
|
|
52
|
+
toast.error(res.error);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (res.data)
|
|
56
|
+
setSettings(res.data);
|
|
57
|
+
toast.success('Notification settings saved.');
|
|
58
|
+
emitFormsChanged();
|
|
59
|
+
onChanged?.();
|
|
60
|
+
}
|
|
61
|
+
if (loading)
|
|
62
|
+
return _jsx(FormsLoading, { label: "Loading notification settings\u2026" });
|
|
63
|
+
if (error)
|
|
64
|
+
return _jsx(FormsErrorState, { message: error });
|
|
65
|
+
if (!settings)
|
|
66
|
+
return null;
|
|
67
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsx(ToggleRow, { label: "Enable notifications", help: "Email the recipients below when a new entry arrives.", checked: settings.enabled, onChange: (v) => patch({ enabled: v }) }), _jsxs("fieldset", { disabled: !settings.enabled, className: "space-y-4 transition-opacity disabled:opacity-50", children: [_jsx(Field, { label: "Recipients", hint: "Comma-separated email addresses", children: _jsx("input", { type: "text", value: settings.recipients.join(', '), onChange: (e) => patch({
|
|
68
|
+
recipients: e.target.value
|
|
69
|
+
.split(',')
|
|
70
|
+
.map((s) => s.trim())
|
|
71
|
+
.filter(Boolean),
|
|
72
|
+
}), placeholder: "team@example.com", className: inputCls }) }), _jsx(Field, { label: "Reply-to field key", hint: "Field whose value is used as the reply-to address", children: _jsx("input", { type: "text", value: settings.replyToFieldKey ?? '', onChange: (e) => patch({ replyToFieldKey: e.target.value || null }), placeholder: "email", className: inputCls }) }), _jsx(Field, { label: "Subject template", children: _jsx("input", { type: "text", value: settings.subjectTemplate ?? '', onChange: (e) => patch({ subjectTemplate: e.target.value }), placeholder: "New submission from {{name}}", className: inputCls }) }), _jsx(Field, { label: "Message template", children: _jsx("textarea", { rows: 3, value: settings.messageTemplate ?? '', onChange: (e) => patch({ messageTemplate: e.target.value }), className: inputCls }) }), _jsx(ToggleRow, { label: "Include all fields", help: "Append every submitted field to the notification body.", checked: settings.includeFields ?? true, onChange: (v) => patch({ includeFields: v }) }), _jsx(ToggleRow, { label: "Exclude sensitive fields", help: "Omit fields marked as sensitive/PII from the email.", checked: settings.excludeSensitiveFields ?? false, onChange: (v) => patch({ excludeSensitiveFields: v }) }), _jsxs("div", { className: "border-border border-t pt-4", children: [_jsx(ToggleRow, { label: "Auto-response email", help: "Send a confirmation email back to the submitter.", checked: settings.autoresponderEnabled ?? false, onChange: (v) => patch({ autoresponderEnabled: v }) }), settings.autoresponderEnabled && (_jsxs("div", { className: "mt-3 space-y-3", children: [_jsx(Field, { label: "Auto-response subject", children: _jsx("input", { type: "text", value: settings.autoresponderSubject ?? '', onChange: (e) => patch({ autoresponderSubject: e.target.value }), className: inputCls }) }), _jsx(Field, { label: "Auto-response body", children: _jsx("textarea", { rows: 3, value: settings.autoresponderBody ?? '', onChange: (e) => patch({ autoresponderBody: e.target.value }), className: inputCls }) })] }))] })] }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Email & webhook delivery (including the test action) is wired in an upcoming release. Settings saved here apply automatically once delivery is enabled." }), _jsx("div", { className: "flex justify-end", children: _jsx("button", { className: btnPrimary, onClick: save, disabled: saving, children: saving ? 'Saving…' : 'Save notifications' }) })] }));
|
|
73
|
+
}
|
|
74
|
+
function ToggleRow({ label, help, checked, onChange, }) {
|
|
75
|
+
return (_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: "text-foreground block text-sm font-medium", children: label }), _jsx("span", { className: "text-muted-foreground block text-sm", children: help })] }), _jsx(Switch.Root, { checked: checked, onCheckedChange: onChange, "aria-label": label, className: "bg-input-background data-[state=checked]:bg-primary focus-visible:ring-ring relative h-[18px] w-8 shrink-0 rounded-full transition-colors focus-visible:ring-2 focus-visible:outline-none", children: _jsx(Switch.Thumb, { className: "bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[14px]" }) })] }));
|
|
76
|
+
}
|
|
77
|
+
function Field({ label, hint, children, }) {
|
|
78
|
+
return (_jsxs("label", { className: "block", children: [_jsx("span", { className: "text-foreground mb-1 block text-sm font-medium", children: label }), children, hint && _jsx("span", { className: "text-muted-foreground mt-1 block text-xs", children: hint })] }));
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=NotificationsPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationsPanel.js","sourceRoot":"","sources":["../../../src/components/forms/NotificationsPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Forms UI primitives — token-only, accessible building blocks used
|
|
3
|
+
* across the Forms list, schema drawer, and (later) the entries views. No raw
|
|
4
|
+
* palette colours: field-type and status hues map onto the theme's semantic
|
|
5
|
+
* tokens (success / warning / info / destructive / primary / muted) so they
|
|
6
|
+
* track light/dark mode and brand overrides automatically.
|
|
7
|
+
*/
|
|
8
|
+
import type { ReactNode } from 'react';
|
|
9
|
+
import type { FormFieldType, FormStatus } from '../../lib/forms-service.js';
|
|
10
|
+
export declare function FieldTypeBadge({ type }: {
|
|
11
|
+
type: FormFieldType;
|
|
12
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function FormStatusBadge({ status }: {
|
|
14
|
+
status: FormStatus;
|
|
15
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
/** Small red count badge for unread submissions. Hidden when count is 0. */
|
|
17
|
+
export declare function UnreadBadge({ count, className }: {
|
|
18
|
+
count: number;
|
|
19
|
+
className?: string;
|
|
20
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
21
|
+
export declare function SummaryChip({ value, label, tone, }: {
|
|
22
|
+
value: ReactNode;
|
|
23
|
+
label: string;
|
|
24
|
+
tone?: 'neutral' | 'success' | 'warning' | 'destructive';
|
|
25
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
export declare function FormsLoading({ label }: {
|
|
27
|
+
label?: string;
|
|
28
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
export declare function FormsEmptyState({ icon, title, description, action, }: {
|
|
30
|
+
icon?: ReactNode;
|
|
31
|
+
title: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
action?: ReactNode;
|
|
34
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
export declare function FormsErrorState({ message, onRetry }: {
|
|
36
|
+
message: string;
|
|
37
|
+
onRetry?: () => void;
|
|
38
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
export declare const btnPrimary = "inline-flex items-center justify-center gap-2 rounded-md bg-primary px-4 py-2 text-base font-medium text-primary-foreground transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-60";
|
|
40
|
+
export declare const btnSecondary = "inline-flex items-center justify-center gap-2 rounded-md border border-border bg-card px-4 py-2 text-base font-medium text-foreground transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-60";
|
|
41
|
+
export declare const btnGhostIcon = "inline-flex items-center justify-center rounded-md p-2 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
|
|
42
|
+
//# sourceMappingURL=primitives.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../../src/components/forms/primitives.tsx"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAiD3E,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,2CAQ/D;AAcD,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,2CAUjE;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,SAAc,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,kDAU3F;AAID,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,KAAK,EACL,IAAgB,GACjB,EAAE;IACD,KAAK,EAAE,SAAS,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;CACzD,2CAeA;AAID,wBAAgB,YAAY,CAAC,EAAE,KAAkB,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,2CAOtE;AAED,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,KAAK,EACL,WAAW,EACX,MAAM,GACP,EAAE;IACD,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB,2CAaA;AAED,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,2CAkB9F;AAID,eAAO,MAAM,UAAU,kQAC0O,CAAA;AAEjQ,eAAO,MAAM,YAAY,wQAC8O,CAAA;AAEvQ,eAAO,MAAM,YAAY,iNACuL,CAAA"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { AlertTriangle, Loader2 } from 'lucide-react';
|
|
4
|
+
// ─── Field-type badges ─────────────────────────────────────────────────────
|
|
5
|
+
/** Map a field type onto a semantic colour pair (background + text). */
|
|
6
|
+
function fieldTypeTone(type) {
|
|
7
|
+
switch (type) {
|
|
8
|
+
case 'email':
|
|
9
|
+
case 'url':
|
|
10
|
+
case 'date':
|
|
11
|
+
case 'number':
|
|
12
|
+
return 'bg-info/10 text-info';
|
|
13
|
+
case 'phone':
|
|
14
|
+
case 'textarea':
|
|
15
|
+
return 'bg-primary/10 text-primary';
|
|
16
|
+
case 'select':
|
|
17
|
+
case 'multiselect':
|
|
18
|
+
case 'radio':
|
|
19
|
+
return 'bg-warning/10 text-warning';
|
|
20
|
+
case 'checkbox':
|
|
21
|
+
case 'consent':
|
|
22
|
+
return 'bg-success/10 text-success';
|
|
23
|
+
case 'file':
|
|
24
|
+
return 'bg-destructive/10 text-destructive';
|
|
25
|
+
default:
|
|
26
|
+
return 'bg-muted text-muted-foreground';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const FIELD_TYPE_LABELS = {
|
|
30
|
+
text: 'TEXT',
|
|
31
|
+
email: 'EMAIL',
|
|
32
|
+
phone: 'PHONE',
|
|
33
|
+
textarea: 'TEXTAREA',
|
|
34
|
+
select: 'SELECT',
|
|
35
|
+
multiselect: 'MULTI',
|
|
36
|
+
radio: 'RADIO',
|
|
37
|
+
checkbox: 'CHECKBOX',
|
|
38
|
+
date: 'DATE',
|
|
39
|
+
number: 'NUMBER',
|
|
40
|
+
url: 'URL',
|
|
41
|
+
hidden: 'HIDDEN',
|
|
42
|
+
file: 'FILE',
|
|
43
|
+
consent: 'CONSENT',
|
|
44
|
+
richtext: 'CONTENT',
|
|
45
|
+
divider: 'DIVIDER',
|
|
46
|
+
honeypot: 'HONEYPOT',
|
|
47
|
+
};
|
|
48
|
+
export function FieldTypeBadge({ type }) {
|
|
49
|
+
return (_jsx("span", { className: `inline-flex items-center rounded-md px-1.5 py-0.5 text-[10px] font-medium tracking-wide uppercase ${fieldTypeTone(type)}`, children: FIELD_TYPE_LABELS[type] ?? type }));
|
|
50
|
+
}
|
|
51
|
+
// ─── Status badges ─────────────────────────────────────────────────────────
|
|
52
|
+
const STATUS_META = {
|
|
53
|
+
active: { label: 'Active', cls: 'bg-success/10 text-success', dot: 'bg-success' },
|
|
54
|
+
draft: { label: 'Draft', cls: 'bg-warning/10 text-warning', dot: 'bg-warning' },
|
|
55
|
+
archived: {
|
|
56
|
+
label: 'Archived',
|
|
57
|
+
cls: 'bg-muted text-muted-foreground',
|
|
58
|
+
dot: 'bg-muted-foreground',
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
export function FormStatusBadge({ status }) {
|
|
62
|
+
const meta = STATUS_META[status] ?? STATUS_META.draft;
|
|
63
|
+
return (_jsxs("span", { className: `inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium ${meta.cls}`, children: [_jsx("span", { className: `h-1.5 w-1.5 rounded-full ${meta.dot}`, "aria-hidden": true }), meta.label] }));
|
|
64
|
+
}
|
|
65
|
+
/** Small red count badge for unread submissions. Hidden when count is 0. */
|
|
66
|
+
export function UnreadBadge({ count, className = '' }) {
|
|
67
|
+
if (count <= 0)
|
|
68
|
+
return null;
|
|
69
|
+
return (_jsx("span", { className: `bg-destructive text-destructive-foreground inline-flex min-w-5 items-center justify-center rounded-full px-1.5 py-0.5 text-xs font-medium tabular-nums ${className}`, "aria-label": `${count} unread`, children: count > 99 ? '99+' : count }));
|
|
70
|
+
}
|
|
71
|
+
// ─── Summary chips ───────────────────────────────────────────────────────
|
|
72
|
+
export function SummaryChip({ value, label, tone = 'neutral', }) {
|
|
73
|
+
const valueCls = tone === 'success'
|
|
74
|
+
? 'text-success'
|
|
75
|
+
: tone === 'warning'
|
|
76
|
+
? 'text-warning'
|
|
77
|
+
: tone === 'destructive'
|
|
78
|
+
? 'text-destructive'
|
|
79
|
+
: 'text-foreground';
|
|
80
|
+
return (_jsxs("div", { className: "border-border bg-card flex items-baseline gap-1.5 rounded-lg border px-3 py-2", children: [_jsx("span", { className: `text-base font-medium tabular-nums ${valueCls}`, children: value }), _jsx("span", { className: "text-muted-foreground text-sm", children: label })] }));
|
|
81
|
+
}
|
|
82
|
+
// ─── States ──────────────────────────────────────────────────────────────
|
|
83
|
+
export function FormsLoading({ label = 'Loading…' }) {
|
|
84
|
+
return (_jsxs("div", { className: "flex h-64 items-center justify-center", role: "status", "aria-live": "polite", children: [_jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin", "aria-hidden": true }), _jsx("span", { className: "sr-only", children: label })] }));
|
|
85
|
+
}
|
|
86
|
+
export function FormsEmptyState({ icon, title, description, action, }) {
|
|
87
|
+
return (_jsxs("div", { className: "border-border flex flex-col items-center justify-center rounded-lg border border-dashed px-6 py-12 text-center", children: [icon && (_jsx("div", { className: "text-muted-foreground mb-3", "aria-hidden": true, children: icon })), _jsx("h3", { className: "text-foreground text-base font-medium", children: title }), description && _jsx("p", { className: "text-muted-foreground mt-1 max-w-md text-sm", children: description }), action && _jsx("div", { className: "mt-4", children: action })] }));
|
|
88
|
+
}
|
|
89
|
+
export function FormsErrorState({ message, onRetry }) {
|
|
90
|
+
return (_jsxs("div", { className: "border-destructive/30 bg-destructive/5 flex items-center gap-3 rounded-lg border p-3", role: "alert", children: [_jsx(AlertTriangle, { className: "text-destructive h-5 w-5 shrink-0", "aria-hidden": true }), _jsx("span", { className: "text-destructive flex-1 text-sm", children: message }), onRetry && (_jsx("button", { onClick: onRetry, className: "border-border text-foreground hover:bg-accent rounded-md border px-3 py-1 text-sm transition-colors", children: "Retry" }))] }));
|
|
91
|
+
}
|
|
92
|
+
// ─── Button helpers (token-only) ─────────────────────────────────────────
|
|
93
|
+
export const btnPrimary = 'inline-flex items-center justify-center gap-2 rounded-md bg-primary px-4 py-2 text-base font-medium text-primary-foreground transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-60';
|
|
94
|
+
export const btnSecondary = 'inline-flex items-center justify-center gap-2 rounded-md border border-border bg-card px-4 py-2 text-base font-medium text-foreground transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-60';
|
|
95
|
+
export const btnGhostIcon = 'inline-flex items-center justify-center rounded-md p-2 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring';
|
|
96
|
+
//# sourceMappingURL=primitives.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primitives.js","sourceRoot":"","sources":["../../../src/components/forms/primitives.tsx"],"names":[],"mappings":"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"}
|
package/dist/layout/Sidebar.d.ts
CHANGED
|
@@ -19,6 +19,11 @@ export interface NavItem {
|
|
|
19
19
|
group?: string;
|
|
20
20
|
/** Indented children rendered immediately after this item. */
|
|
21
21
|
children?: NavItem[];
|
|
22
|
+
/**
|
|
23
|
+
* Optional unread/notification count. Rendered as a red pill (expanded)
|
|
24
|
+
* or a dot (collapsed). Falsy / zero values render nothing.
|
|
25
|
+
*/
|
|
26
|
+
badge?: number;
|
|
22
27
|
}
|
|
23
28
|
/**
|
|
24
29
|
* Build the sidebar nav tree from the CMS config. If no collections are
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../src/layout/Sidebar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../src/layout/Sidebar.tsx"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAmI9C,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAA;IAClB,gBAAgB,EAAE,MAAM,IAAI,CAAA;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,MAAM,CAAC,EAAE,GAAG,CAAA;CACb;AAED,wBAAgB,OAAO,CAAC,EACtB,SAAS,EACT,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,MAAM,GACP,EAAE,YAAY,2CAgDd;AAkYD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,UAAU,CAAA;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;IACpB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,EAAE,CA0GpD"}
|