@revealui/core 0.13.1 → 0.14.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/README.md +3 -2
- package/dist/client/admin/components/AdminDashboard.d.ts +8 -1
- package/dist/client/admin/components/AdminDashboard.d.ts.map +1 -1
- package/dist/client/admin/components/AdminDashboard.js +11 -10
- package/dist/client/admin/components/CollectionList.d.ts.map +1 -1
- package/dist/client/admin/components/CollectionList.js +4 -6
- package/dist/client/admin/components/DocumentForm.d.ts.map +1 -1
- package/dist/client/admin/components/DocumentForm.js +26 -26
- package/dist/client/admin/components/GlobalForm.d.ts.map +1 -1
- package/dist/client/admin/components/GlobalForm.js +10 -9
- package/dist/client/admin/page.d.ts.map +1 -1
- package/dist/client/admin/page.js +2 -1
- package/dist/client/richtext/components/ImageNodeComponent.d.ts.map +1 -1
- package/dist/client/richtext/components/ImageNodeComponent.js +3 -22
- package/dist/client/richtext/components/ImageUploadButton.d.ts.map +1 -1
- package/dist/client/richtext/components/ImageUploadButton.js +2 -4
- package/dist/client/richtext/plugins/FloatingToolbarPlugin.d.ts.map +1 -1
- package/dist/client/richtext/plugins/FloatingToolbarPlugin.js +3 -2
- package/dist/client/richtext/plugins/ToolbarPlugin.d.ts.map +1 -1
- package/dist/client/richtext/plugins/ToolbarPlugin.js +3 -2
- package/dist/client/ui/index.d.ts.map +1 -1
- package/dist/client/ui/index.js +10 -6
- package/dist/cogs-breaker.d.ts +27 -0
- package/dist/cogs-breaker.d.ts.map +1 -0
- package/dist/cogs-breaker.js +29 -0
- package/dist/error-handling/error-boundary.d.ts.map +1 -1
- package/dist/error-handling/error-boundary.js +2 -9
- package/dist/error-handling/fallback-components.d.ts.map +1 -1
- package/dist/error-handling/fallback-components.js +9 -86
- package/dist/instance/logger.d.ts +2 -1
- package/dist/instance/logger.d.ts.map +1 -1
- package/dist/license/mint-client.d.ts +15 -4
- package/dist/license/mint-client.d.ts.map +1 -1
- package/dist/license/mint-client.js +38 -9
- package/dist/license.d.ts +39 -14
- package/dist/license.d.ts.map +1 -1
- package/dist/license.js +111 -34
- package/dist/margin-governor.d.ts +82 -0
- package/dist/margin-governor.d.ts.map +1 -0
- package/dist/margin-governor.js +143 -0
- package/dist/revforge-license-boot.d.ts +0 -10
- package/dist/revforge-license-boot.d.ts.map +1 -1
- package/dist/revforge-license-boot.js +41 -20
- package/dist/types/runtime.d.ts +3 -6
- package/dist/types/runtime.d.ts.map +1 -1
- package/dist/utils/block-conversion.d.ts.map +1 -1
- package/dist/utils/block-conversion.js +2 -1
- package/package.json +64 -3
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ Part of the [RevealUI monorepo](https://github.com/RevealUIStudio/revealui) -
|
|
|
24
24
|
- **Security** - CORS, CSP, HSTS, RBAC/ABAC policy engine, encryption (AES-256-GCM), audit logging
|
|
25
25
|
- **GDPR Compliance** - Consent management, data export, deletion, anonymization, breach reporting
|
|
26
26
|
- **Observability** - Structured logging, process health monitoring, alert system, graceful shutdown
|
|
27
|
-
- **Plugins** - Extensible plugin system (form builder, nested docs, redirects)
|
|
27
|
+
- **Plugins** - Extensible plugin system (form builder, nested docs, redirects). Guide: [docs/PLUGINS.md](../../docs/PLUGINS.md)
|
|
28
28
|
- **Feature Gating** - Tier-based licensing (free, pro, max, enterprise) with JWT license keys
|
|
29
29
|
- **Database** - PostgreSQL adapters (NeonDB + PGlite for testing), connection pooling, SSL/TLS
|
|
30
30
|
- **Storage** - Pluggable storage interface (Cloudflare R2 sole non-mock backend; mock adapter for tests)
|
|
@@ -41,11 +41,12 @@ pnpm add @revealui/core
|
|
|
41
41
|
|
|
42
42
|
```typescript
|
|
43
43
|
import { buildConfig } from '@revealui/core/config'
|
|
44
|
+
import { formBuilderPlugin, nestedDocsPlugin } from '@revealui/core/plugins'
|
|
44
45
|
|
|
45
46
|
const config = buildConfig({
|
|
46
47
|
collections: [Posts, Categories, Users],
|
|
47
48
|
globals: [Settings, Navigation],
|
|
48
|
-
plugins: [
|
|
49
|
+
plugins: [formBuilderPlugin(), nestedDocsPlugin()],
|
|
49
50
|
})
|
|
50
51
|
```
|
|
51
52
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
1
2
|
import type { RevealConfig } from '../../../types/index.js';
|
|
2
3
|
interface AdminDashboardProps {
|
|
3
4
|
config: RevealConfig;
|
|
@@ -7,7 +8,13 @@ interface AdminDashboardProps {
|
|
|
7
8
|
* files cannot read those env vars at runtime (build-time inlining).
|
|
8
9
|
*/
|
|
9
10
|
siteName?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Optional lead content above the Overview stats (GAP-300 onboarding
|
|
13
|
+
* checklist/nudge). Only shown on the home Overview view, not collection
|
|
14
|
+
* or document editors.
|
|
15
|
+
*/
|
|
16
|
+
overviewLead?: ReactNode;
|
|
10
17
|
}
|
|
11
|
-
export declare function AdminDashboard({ config, siteName }: AdminDashboardProps): import("react").JSX.Element;
|
|
18
|
+
export declare function AdminDashboard({ config, siteName, overviewLead, }: AdminDashboardProps): import("react").JSX.Element;
|
|
12
19
|
export {};
|
|
13
20
|
//# sourceMappingURL=AdminDashboard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminDashboard.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/components/AdminDashboard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AdminDashboard.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/components/AdminDashboard.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAEV,YAAY,EAGb,MAAM,yBAAyB,CAAC;AAUjC,UAAU,mBAAmB;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,CAAC;CAC1B;AAqhBD,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,QAAqB,EACrB,YAAY,GACb,EAAE,mBAAmB,+BAqVrB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { logger } from '@revealui/core/utils/logger';
|
|
4
|
+
import { Button, IconPrimitiveContent, IconSettings } from '@revealui/presentation';
|
|
4
5
|
import { useCallback, useEffect, useReducer, useState } from 'react';
|
|
5
6
|
import { APIError, APIErrorType, apiClient, postSignOut } from '../utils/index.js';
|
|
6
7
|
import { CollectionList } from './CollectionList.js';
|
|
@@ -53,7 +54,7 @@ function reducer(state, action) {
|
|
|
53
54
|
// Shared sub-components
|
|
54
55
|
// =============================================================================
|
|
55
56
|
function AdminHeader({ title, onBack }) {
|
|
56
|
-
return (_jsx("header", { className: "bg-card shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsxs("div", { className: "flex justify-between items-center py-4", children: [_jsxs("div", { className: "flex items-center space-x-4", children: [_jsx(
|
|
57
|
+
return (_jsx("header", { className: "bg-card shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsxs("div", { className: "flex justify-between items-center py-4", children: [_jsxs("div", { className: "flex items-center space-x-4", children: [_jsx(Button, { type: "button", variant: "neutral", appearance: "ghost", size: "sm", onClick: onBack, children: "\u2190 Back to Dashboard" }), _jsx("h1", { className: "text-2xl font-bold text-foreground capitalize", children: title })] }), _jsx(SignOutButton, {})] }) }) }));
|
|
57
58
|
}
|
|
58
59
|
function StatusBanners({ error, successMessage, }) {
|
|
59
60
|
return (_jsxs(_Fragment, { children: [error && (_jsxs("div", { className: "mb-4 bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded", children: [_jsx("p", { className: "font-medium", children: "Error" }), _jsx("p", { className: "text-sm", children: error })] })), successMessage && (_jsxs("div", { className: "mb-4 bg-success/10 border border-success/30 text-success px-4 py-3 rounded", children: [_jsx("p", { className: "font-medium", children: "Success" }), _jsx("p", { className: "text-sm", children: successMessage })] }))] }));
|
|
@@ -73,7 +74,7 @@ function SignOutButton() {
|
|
|
73
74
|
}
|
|
74
75
|
window.location.href = '/login';
|
|
75
76
|
}, []);
|
|
76
|
-
return (_jsx(
|
|
77
|
+
return (_jsx(Button, { type: "button", variant: "neutral", appearance: "ghost", size: "sm", onClick: () => void handleSignOut(), disabled: loading, children: loading ? 'Signing out...' : 'Sign Out' }));
|
|
77
78
|
}
|
|
78
79
|
const TAXONOMY_GROUPS = ['Operate', 'Build', 'Configure'];
|
|
79
80
|
function isTaxonomyGroup(value) {
|
|
@@ -123,8 +124,8 @@ const COLLECTION_LINK_OVERRIDES = {
|
|
|
123
124
|
};
|
|
124
125
|
// Static icons: hoisted so the same element is reused across renders instead
|
|
125
126
|
// of re-created (they take no props and never change).
|
|
126
|
-
const collectionsIcon =
|
|
127
|
-
const globalsIcon =
|
|
127
|
+
const collectionsIcon = _jsx(IconPrimitiveContent, { size: "sm", className: "text-muted-foreground" });
|
|
128
|
+
const globalsIcon = _jsx(IconSettings, { size: "sm", className: "text-muted-foreground" });
|
|
128
129
|
/**
|
|
129
130
|
* Small local equivalents of `@revealui/presentation`'s `Badge` / `Stat` /
|
|
130
131
|
* `StatusDot`, built from the same `--rvui-*` token bridge classes (`bg-muted`,
|
|
@@ -160,11 +161,11 @@ function CollectionGroupCard({ group, collections, onCollectionClick, }) {
|
|
|
160
161
|
const slug = String(collection.slug);
|
|
161
162
|
const overrideHref = COLLECTION_LINK_OVERRIDES[slug];
|
|
162
163
|
const rowClassName = 'flex w-full items-center px-5 py-2.5 text-left text-sm font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground cursor-pointer';
|
|
163
|
-
return (_jsx("li", { children: overrideHref ? (_jsx("a", { href: overrideHref, className: rowClassName, children: slug })) : (_jsx(
|
|
164
|
+
return (_jsx("li", { children: overrideHref ? (_jsx("a", { href: overrideHref, className: rowClassName, children: slug })) : (_jsx(Button, { type: "button", variant: "neutral", appearance: "ghost", size: "clear", onClick: () => onCollectionClick(collection), className: rowClassName, children: slug })) }, slug));
|
|
164
165
|
}) })] }));
|
|
165
166
|
}
|
|
166
167
|
function GlobalsCard({ globals, onGlobalClick, }) {
|
|
167
|
-
return (_jsxs("section", { "aria-labelledby": "dashboard-globals", className: "overflow-hidden rounded-lg bg-card shadow", children: [_jsxs("div", { className: "flex items-center justify-between border-b px-5 py-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [globalsIcon, _jsx("h3", { id: "dashboard-globals", className: "text-sm font-semibold text-foreground", children: "Globals" })] }), _jsx(CountBadge, { count: globals.length })] }), globals.length > 0 ? (_jsx("ul", { className: "divide-y divide-border", children: globals.map((global) => (_jsx("li", { children: _jsx(
|
|
168
|
+
return (_jsxs("section", { "aria-labelledby": "dashboard-globals", className: "overflow-hidden rounded-lg bg-card shadow", children: [_jsxs("div", { className: "flex items-center justify-between border-b px-5 py-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [globalsIcon, _jsx("h3", { id: "dashboard-globals", className: "text-sm font-semibold text-foreground", children: "Globals" })] }), _jsx(CountBadge, { count: globals.length })] }), globals.length > 0 ? (_jsx("ul", { className: "divide-y divide-border", children: globals.map((global) => (_jsx("li", { children: _jsx(Button, { type: "button", variant: "neutral", appearance: "ghost", size: "clear", onClick: () => onGlobalClick(global), className: "flex w-full items-center px-5 py-2.5 text-left text-sm font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground cursor-pointer", children: global.label || String(global.slug) }) }, String(global.slug)))) })) : (_jsx("p", { className: "px-5 py-4 text-sm text-muted-foreground", children: "No globals configured" }))] }));
|
|
168
169
|
}
|
|
169
170
|
/** System status card: a status-dot-led card, never a bare prose sentence. */
|
|
170
171
|
function SystemStatusCard({ degraded }) {
|
|
@@ -174,9 +175,9 @@ function SystemStatusCard({ degraded }) {
|
|
|
174
175
|
: 'The admin console is responding normally.';
|
|
175
176
|
return (_jsxs("section", { "aria-labelledby": "dashboard-system-status", className: "overflow-hidden rounded-lg bg-card shadow", children: [_jsxs("div", { className: "flex items-center justify-between border-b px-5 py-3", children: [_jsx("h3", { id: "dashboard-system-status", className: "text-sm font-semibold text-foreground", children: "System status" }), _jsxs("span", { className: "inline-flex items-center gap-2 text-sm font-medium text-foreground", children: [_jsx(StatusIndicator, { degraded: degraded, label: `System status: ${word}`, pulse: !degraded }), word] })] }), _jsx("p", { className: "px-5 py-4 text-sm text-muted-foreground", children: description })] }));
|
|
176
177
|
}
|
|
177
|
-
function DashboardHome({ siteName, collections, globals, degraded, onCollectionClick, onGlobalClick, }) {
|
|
178
|
+
function DashboardHome({ siteName, collections, globals, degraded, onCollectionClick, onGlobalClick, overviewLead, }) {
|
|
178
179
|
const grouped = groupCollectionsByTaxonomy(collections);
|
|
179
|
-
return (_jsxs("div", { className: "min-h-screen bg-background", children: [_jsx("header", { className: "bg-card shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsxs("div", { className: "flex justify-between items-center py-4", children: [_jsx("div", { className: "flex items-center", children: _jsx("h1", { className: "text-2xl font-bold text-foreground", children: `${siteName} Admin` }) }), _jsxs("div", { className: "flex shrink-0 items-center gap-3", children: [_jsxs("span", { className: "shrink-0 text-sm tabular-nums text-muted-foreground", title: "Application version", children: ["v", process.env.NEXT_PUBLIC_APP_VERSION ?? process.env.APP_VERSION ?? '0.0.0'] }), _jsx(SignOutButton, {})] })] }) }) }), _jsxs("main", { className: "max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8", children: [_jsxs("div", { className: "mb-6", children: [_jsx("h2", { className: "text-2xl font-bold tracking-tight text-foreground", children: "Overview" }), _jsxs("p", { className: "mt-1 text-sm text-muted-foreground", children: ["Collections, globals, and system status for ", siteName, "."] })] }), _jsxs("div", { className: "mb-8 grid grid-cols-1 gap-4 sm:grid-cols-3", children: [_jsx(StatTile, { label: "Collections", value: collections.length, icon: collectionsIcon }), _jsx(StatTile, { label: "Globals", value: globals.length, icon: globalsIcon }), _jsx(StatTile, { label: "Status", value: degraded ? 'Degraded' : 'Healthy', icon: _jsx(StatusIndicator, { degraded: degraded, label: degraded ? 'Degraded' : 'Healthy' }) })] }), _jsxs("div", { className: "grid grid-cols-1 gap-6 lg:grid-cols-3", children: [_jsx("div", { className: "lg:col-span-2 flex flex-col gap-6", children: collections.length > 0 ? (TAXONOMY_GROUPS.map((group) => (_jsx(CollectionGroupCard, { group: group, collections: grouped[group], onCollectionClick: onCollectionClick }, group)))) : (_jsx("div", { className: "rounded-lg bg-card p-5 shadow", children: _jsx("p", { className: "text-sm text-muted-foreground", children: "No collections configured" }) })) }), _jsxs("div", { className: "flex flex-col gap-6", children: [_jsx(GlobalsCard, { globals: globals, onGlobalClick: onGlobalClick }), _jsx(SystemStatusCard, { degraded: degraded })] })] })] })] }));
|
|
180
|
+
return (_jsxs("div", { className: "min-h-screen bg-background", children: [_jsx("header", { className: "bg-card shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsxs("div", { className: "flex justify-between items-center py-4", children: [_jsx("div", { className: "flex items-center", children: _jsx("h1", { className: "text-2xl font-bold text-foreground", children: `${siteName} Admin` }) }), _jsxs("div", { className: "flex shrink-0 items-center gap-3", children: [_jsxs("span", { className: "shrink-0 text-sm tabular-nums text-muted-foreground", title: "Application version", children: ["v", process.env.NEXT_PUBLIC_APP_VERSION ?? process.env.APP_VERSION ?? '0.0.0'] }), _jsx(SignOutButton, {})] })] }) }) }), _jsxs("main", { className: "max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8", children: [_jsxs("div", { className: "mb-6", children: [_jsx("h2", { className: "text-2xl font-bold tracking-tight text-foreground", children: "Overview" }), _jsxs("p", { className: "mt-1 text-sm text-muted-foreground", children: ["Collections, globals, and system status for ", siteName, "."] })] }), overviewLead ? _jsx("div", { className: "mb-6", children: overviewLead }) : null, _jsxs("div", { className: "mb-8 grid grid-cols-1 gap-4 sm:grid-cols-3", children: [_jsx(StatTile, { label: "Collections", value: collections.length, icon: collectionsIcon }), _jsx(StatTile, { label: "Globals", value: globals.length, icon: globalsIcon }), _jsx(StatTile, { label: "Status", value: degraded ? 'Degraded' : 'Healthy', icon: _jsx(StatusIndicator, { degraded: degraded, label: degraded ? 'Degraded' : 'Healthy' }) })] }), _jsxs("div", { className: "grid grid-cols-1 gap-6 lg:grid-cols-3", children: [_jsx("div", { className: "lg:col-span-2 flex flex-col gap-6", children: collections.length > 0 ? (TAXONOMY_GROUPS.map((group) => (_jsx(CollectionGroupCard, { group: group, collections: grouped[group], onCollectionClick: onCollectionClick }, group)))) : (_jsx("div", { className: "rounded-lg bg-card p-5 shadow", children: _jsx("p", { className: "text-sm text-muted-foreground", children: "No collections configured" }) })) }), _jsxs("div", { className: "flex flex-col gap-6", children: [_jsx(GlobalsCard, { globals: globals, onGlobalClick: onGlobalClick }), _jsx(SystemStatusCard, { degraded: degraded })] })] })] })] }));
|
|
180
181
|
}
|
|
181
182
|
// =============================================================================
|
|
182
183
|
// Error handling helpers
|
|
@@ -193,7 +194,7 @@ function logApiError(err, context) {
|
|
|
193
194
|
// =============================================================================
|
|
194
195
|
// Main component
|
|
195
196
|
// =============================================================================
|
|
196
|
-
export function AdminDashboard({ config, siteName = 'RevealUI' }) {
|
|
197
|
+
export function AdminDashboard({ config, siteName = 'RevealUI', overviewLead, }) {
|
|
197
198
|
const [state, dispatch] = useReducer(reducer, initialState);
|
|
198
199
|
const collections = config.collections || [];
|
|
199
200
|
const globals = config.globals || [];
|
|
@@ -441,5 +442,5 @@ export function AdminDashboard({ config, siteName = 'RevealUI' }) {
|
|
|
441
442
|
return (_jsxs("div", { className: "min-h-screen bg-background", children: [_jsx(AdminHeader, { title: state.view.global.label || String(state.view.global.slug), onBack: goToDashboard }), _jsx("main", { className: "max-w-7xl mx-auto py-6 sm:px-6 lg:px-8", children: _jsxs("div", { className: "max-w-3xl", children: [_jsx(StatusBanners, { error: state.error, successMessage: state.successMessage }), state.globalLoading && _jsx(LoadingSpinner, {}), !state.globalLoading && state.globalDocument && (_jsx(GlobalForm, { global: state.view.global, document: state.globalDocument, onSave: (data) => void handleSaveGlobal(data), onCancel: goToDashboard, isLoading: state.saving }))] }) })] }));
|
|
442
443
|
}
|
|
443
444
|
// ── Dashboard home ────────────────────────────────────────────────────
|
|
444
|
-
return (_jsx(DashboardHome, { siteName: siteName, collections: collections, globals: globals, degraded: Boolean(state.error), onCollectionClick: (c) => void handleCollectionClick(c), onGlobalClick: (g) => void handleGlobalClick(g) }));
|
|
445
|
+
return (_jsx(DashboardHome, { siteName: siteName, collections: collections, globals: globals, degraded: Boolean(state.error), onCollectionClick: (c) => void handleCollectionClick(c), onGlobalClick: (g) => void handleGlobalClick(g), overviewLead: overviewLead }));
|
|
445
446
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollectionList.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/components/CollectionList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CollectionList.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/components/CollectionList.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EACV,sBAAsB,EACtB,cAAc,EAEf,MAAM,yBAAyB,CAAC;AAoCjC,UAAU,mBAAmB;IAC3B,UAAU,EAAE,sBAAsB,CAAC;IACnC,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAC;IACxC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACzC;AAED,wBAAgB,cAAc,CAAC,EAC7B,UAAU,EACV,SAAS,EACT,SAAS,EACT,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,aAAa,GACd,EAAE,mBAAmB,qBAkRrB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Button, Checkbox, IconPlus } from '@revealui/presentation';
|
|
3
4
|
import { useState } from 'react';
|
|
4
5
|
function getFieldLabel(field) {
|
|
5
6
|
const { label } = field;
|
|
@@ -83,13 +84,10 @@ export function CollectionList({ collection, documents, totalDocs, page, totalPa
|
|
|
83
84
|
})
|
|
84
85
|
.slice(0, 5); // Show first 5 visible fields
|
|
85
86
|
const colCount = displayFields.length + 1 + (hasBulk ? 1 : 0);
|
|
86
|
-
return (_jsxs("div", { className: "bg-card shadow overflow-hidden sm:rounded-md", children: [_jsxs("div", { className: "px-4 py-5 sm:px-6 flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-lg leading-6 font-medium text-foreground capitalize", children: collection.slug }), _jsxs("p", { className: "mt-1 max-w-2xl text-sm text-muted-foreground", children: [totalDocs, " ", totalDocs === 1 ? 'document' : 'documents'] })] }), _jsxs(
|
|
87
|
-
if (el)
|
|
88
|
-
el.indeterminate = someSelected;
|
|
89
|
-
}, onChange: toggleAll, className: "h-4 w-4 rounded border-input text-primary focus:ring-ring", "aria-label": "Select all" }) })), displayFields.map((field) => (_jsx("th", { scope: "col", className: "px-6 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider", children: getFieldLabel(field) }, field.name))), _jsx("th", { scope: "col", className: "relative px-6 py-3", children: _jsx("span", { className: "sr-only", children: "Actions" }) })] }) }), _jsx("tbody", { className: "bg-card divide-y divide-border", children: documents.length === 0 ? (_jsx("tr", { children: _jsxs("td", { colSpan: colCount, className: "px-6 py-4 text-center text-sm text-muted-foreground", children: ["No documents found.", ' ', _jsx("button", { type: "button", onClick: onCreate, className: "text-primary hover:text-primary/80", children: "Create the first one" }), "."] }) })) : (documents.map((doc) => {
|
|
87
|
+
return (_jsxs("div", { className: "bg-card shadow overflow-hidden sm:rounded-md", children: [_jsxs("div", { className: "px-4 py-5 sm:px-6 flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-lg leading-6 font-medium text-foreground capitalize", children: collection.slug }), _jsxs("p", { className: "mt-1 max-w-2xl text-sm text-muted-foreground", children: [totalDocs, " ", totalDocs === 1 ? 'document' : 'documents'] })] }), _jsxs(Button, { type: "button", variant: "brand", appearance: "solid", onClick: onCreate, children: [_jsx(IconPlus, { size: "sm", label: "Create New", className: "-ml-1 mr-2" }), "Create New"] })] }), hasBulk && selectedIds.size > 0 && (_jsxs("div", { className: "bg-primary/10 border-y border-primary/20 px-4 py-2 flex items-center gap-3", children: [_jsxs("span", { className: "text-sm font-medium text-primary", children: [selectedIds.size, " selected"] }), onBulkDelete && (_jsx(Button, { type: "button", variant: "danger", appearance: "solid", size: "sm", onClick: () => void handleBulkAction('delete'), disabled: bulkLoading, children: "Delete" })), onBulkPublish && (_jsx(Button, { type: "button", variant: "success", appearance: "solid", size: "sm", onClick: () => void handleBulkAction('publish'), disabled: bulkLoading, children: "Publish" })), _jsx(Button, { type: "button", variant: "neutral", appearance: "ghost", size: "sm", onClick: () => setSelectedIds(new Set()), className: "ml-auto", children: "Clear selection" })] })), _jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "min-w-full divide-y divide-border", children: [_jsx("thead", { className: "bg-muted", children: _jsxs("tr", { children: [hasBulk && (_jsx("th", { scope: "col", className: "w-10 px-3 py-3", children: _jsx(Checkbox, { checked: allSelected, indeterminate: someSelected, onChange: () => toggleAll(), "aria-label": "Select all" }) })), displayFields.map((field) => (_jsx("th", { scope: "col", className: "px-6 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider", children: getFieldLabel(field) }, field.name))), _jsx("th", { scope: "col", className: "relative px-6 py-3", children: _jsx("span", { className: "sr-only", children: "Actions" }) })] }) }), _jsx("tbody", { className: "bg-card divide-y divide-border", children: documents.length === 0 ? (_jsx("tr", { children: _jsxs("td", { colSpan: colCount, className: "px-6 py-4 text-center text-sm text-muted-foreground", children: ["No documents found.", ' ', _jsx(Button, { type: "button", variant: "brand", appearance: "link", size: "clear", onClick: onCreate, className: "inline p-0 h-auto", children: "Create the first one" }), "."] }) })) : (documents.map((doc) => {
|
|
90
88
|
const docId = String(doc.id);
|
|
91
|
-
return (_jsxs("tr", { className: `hover:bg-muted ${selectedIds.has(docId) ? 'bg-primary/10' : ''}`, children: [hasBulk && (_jsx("td", { className: "w-10 px-3 py-4", children: _jsx(
|
|
92
|
-
})) })] }) }), totalPages > 1 && (_jsxs("div", { className: "bg-card px-4 py-3 flex items-center justify-between border-t border-border sm:px-6", children: [_jsxs("div", { className: "flex-1 flex justify-between sm:hidden", children: [_jsx(
|
|
89
|
+
return (_jsxs("tr", { className: `hover:bg-muted ${selectedIds.has(docId) ? 'bg-primary/10' : ''}`, children: [hasBulk && (_jsx("td", { className: "w-10 px-3 py-4", children: _jsx(Checkbox, { checked: selectedIds.has(docId), onChange: () => toggleOne(docId), "aria-label": `Select ${docId}` }) })), displayFields.map((field) => (_jsx("td", { className: "px-6 py-4 whitespace-nowrap text-sm text-foreground", children: renderFieldValue(field.name ? doc[field.name] : undefined, field) }, field.name))), _jsxs("td", { className: "px-6 py-4 whitespace-nowrap text-right text-sm font-medium space-x-2", children: [_jsx(Button, { type: "button", variant: "brand", appearance: "link", size: "sm", onClick: () => onEdit(doc), disabled: deleting !== null, children: "Edit" }), _jsx(Button, { type: "button", variant: "danger", appearance: "link", size: "sm", onClick: () => onDelete(doc), disabled: deleting !== null, children: deleting === docId ? 'Deleting...' : 'Delete' })] })] }, docId));
|
|
90
|
+
})) })] }) }), totalPages > 1 && (_jsxs("div", { className: "bg-card px-4 py-3 flex items-center justify-between border-t border-border sm:px-6", children: [_jsxs("div", { className: "flex-1 flex justify-between sm:hidden", children: [_jsx(Button, { type: "button", variant: "neutral", appearance: "outline", onClick: () => onPageChange(page - 1), disabled: page <= 1, children: "Previous" }), _jsx(Button, { type: "button", variant: "neutral", appearance: "outline", onClick: () => onPageChange(page + 1), disabled: page >= totalPages, className: "ml-3", children: "Next" })] }), _jsxs("div", { className: "hidden sm:flex-1 sm:flex sm:items-center sm:justify-between", children: [_jsx("div", { children: _jsxs("p", { className: "text-sm text-foreground", children: ["Showing page ", _jsx("span", { className: "font-medium", children: page }), " of", ' ', _jsx("span", { className: "font-medium", children: totalPages })] }) }), _jsx("div", { children: _jsxs("nav", { className: "relative z-0 inline-flex rounded-md shadow-sm -space-x-px", children: [_jsx(Button, { type: "button", variant: "neutral", appearance: "outline", size: "sm", onClick: () => onPageChange(page - 1), disabled: page <= 1, className: "rounded-r-none", children: "Previous" }), _jsx(Button, { type: "button", variant: "neutral", appearance: "outline", size: "sm", onClick: () => onPageChange(page + 1), disabled: page >= totalPages, className: "rounded-l-none", children: "Next" })] }) })] })] }))] }));
|
|
93
91
|
}
|
|
94
92
|
function renderFieldValue(value, field) {
|
|
95
93
|
if (value === null || value === undefined) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocumentForm.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/components/DocumentForm.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DocumentForm.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/components/DocumentForm.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EACV,sBAAsB,EACtB,cAAc,EAEf,MAAM,yBAAyB,CAAC;AAiEjC,UAAU,iBAAiB;IACzB,UAAU,EAAE,sBAAsB,CAAC;IACnC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAChD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,YAAY,CAAC,EAC3B,UAAU,EACV,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,SAAiB,GAClB,EAAE,iBAAiB,qBAsEnB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Button, Checkbox, FieldLabel, Input, Radio, RadioField, RadioGroup, Select, Textarea, } from '@revealui/presentation';
|
|
3
4
|
import { lazy, Suspense, useCallback, useState } from 'react';
|
|
4
5
|
// Lazy-loaded so Lexical (~1.2MB) is only bundled for edit pages with richText
|
|
5
6
|
// fields - list/dashboard pages skip the entire Lexical chunk.
|
|
@@ -70,11 +71,11 @@ export function DocumentForm({ collection, document, onSave, onCancel, isLoading
|
|
|
70
71
|
const handleFieldChange = (fieldName, value) => {
|
|
71
72
|
setFormData((prev) => ({ ...prev, [fieldName]: value }));
|
|
72
73
|
};
|
|
73
|
-
return (_jsx("div", { className: "bg-card shadow overflow-hidden sm:rounded-lg", children: _jsxs("div", { className: "px-4 py-5 sm:p-6", children: [_jsxs("h3", { className: "text-lg leading-6 font-medium text-foreground mb-4", children: [document ? 'Edit' : 'Create', " ", collection.slug.slice(0, -1)] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-6", children: [collection.upload && !document ? (_jsxs("div", { children: [_jsxs("label", { htmlFor: "__file", className: "block text-sm font-medium text-foreground", children: ["File", _jsx("span", { className: "text-red-500 ml-1", children: "*" })] }), _jsx("div", { className: "mt-1", children: _jsx(
|
|
74
|
+
return (_jsx("div", { className: "bg-card shadow overflow-hidden sm:rounded-lg", children: _jsxs("div", { className: "px-4 py-5 sm:p-6", children: [_jsxs("h3", { className: "text-lg leading-6 font-medium text-foreground mb-4", children: [document ? 'Edit' : 'Create', " ", collection.slug.slice(0, -1)] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-6", children: [collection.upload && !document ? (_jsxs("div", { children: [_jsxs("label", { htmlFor: "__file", className: "block text-sm font-medium text-foreground", children: ["File", _jsx("span", { className: "text-red-500 ml-1", children: "*" })] }), _jsx("div", { className: "mt-1", children: _jsx(Input, { type: "file", id: "__file", required: true, onChange: (e) => {
|
|
74
75
|
const file = e.target.files?.[0];
|
|
75
76
|
if (file)
|
|
76
77
|
handleFieldChange('file', file);
|
|
77
|
-
}, className: "block w-full text-sm text-muted-foreground file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-medium file:bg-primary/10 file:text-primary hover:file:bg-primary/20" }) })] })) : null, visibleFields.map((field) => (_jsxs("div", { children: [_jsxs("label", { htmlFor: field.name, className: "block text-sm font-medium text-foreground", children: [getFieldLabel(field), field.required && _jsx("span", { className: "text-red-500 ml-1", children: "*" })] }), _jsx("div", { className: "mt-1", children: _jsx(FieldInput, { field: field, value: field.name ? formData[field.name] : undefined, onChange: (value) => field.name && handleFieldChange(field.name, value) }) })] }, field.name || 'layout'))), _jsxs("div", { className: "flex justify-end space-x-3 pt-6", children: [_jsx(
|
|
78
|
+
}, className: "block w-full text-sm text-muted-foreground file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-medium file:bg-primary/10 file:text-primary hover:file:bg-primary/20" }) })] })) : null, visibleFields.map((field) => (_jsxs("div", { children: [_jsxs("label", { htmlFor: field.name, className: "block text-sm font-medium text-foreground", children: [getFieldLabel(field), field.required && _jsx("span", { className: "text-red-500 ml-1", children: "*" })] }), _jsx("div", { className: "mt-1", children: _jsx(FieldInput, { field: field, value: field.name ? formData[field.name] : undefined, onChange: (value) => field.name && handleFieldChange(field.name, value) }) })] }, field.name || 'layout'))), _jsxs("div", { className: "flex justify-end space-x-3 pt-6", children: [_jsx(Button, { type: "button", variant: "neutral", appearance: "outline", onClick: onCancel, children: "Cancel" }), _jsx(Button, { type: "submit", variant: "brand", appearance: "solid", disabled: isLoading, children: isLoading ? 'Saving...' : 'Save' })] })] })] }) }));
|
|
78
79
|
}
|
|
79
80
|
// ---------------------------------------------------------------------------
|
|
80
81
|
// Array field: repeatable list of sub-fields
|
|
@@ -88,7 +89,7 @@ function ArrayFieldRenderer({ field, value, onChange, }) {
|
|
|
88
89
|
const updated = rows.map((row, i) => (i === idx ? { ...row, [key]: val } : row));
|
|
89
90
|
onChange(updated);
|
|
90
91
|
};
|
|
91
|
-
return (_jsxs("div", { className: "space-y-3", children: [rows.map((row, idx) => (_jsxs("div", { className: "border border-border rounded-md p-3 space-y-2 relative", children: [_jsx(
|
|
92
|
+
return (_jsxs("div", { className: "space-y-3", children: [rows.map((row, idx) => (_jsxs("div", { className: "border border-border rounded-md p-3 space-y-2 relative", children: [_jsx(Button, { type: "button", variant: "danger", appearance: "ghost", size: "sm", onClick: () => removeRow(idx), className: "absolute top-2 right-2", children: "Remove" }), subFields.map((sf) => (_jsxs("div", { children: [_jsx("label", { htmlFor: `${field.name}-${idx}-${sf.name}`, className: "block text-xs font-medium text-muted-foreground", children: getFieldLabel(sf) }), _jsx(FieldInput, { field: sf, value: row[sf.name ?? ''], onChange: (v) => updateRow(idx, sf.name ?? '', v) })] }, sf.name)))] }, `${field.name}-row-${idx.toString()}`))), _jsx(Button, { type: "button", variant: "brand", appearance: "ghost", size: "sm", onClick: addRow, children: "+ Add item" })] }));
|
|
92
93
|
}
|
|
93
94
|
// ---------------------------------------------------------------------------
|
|
94
95
|
// Group field: named group of sub-fields (single object, not repeatable)
|
|
@@ -118,8 +119,8 @@ function BlocksFieldRenderer({ field, value, onChange, }) {
|
|
|
118
119
|
};
|
|
119
120
|
return (_jsxs("div", { className: "space-y-3", children: [blocks.map((block, idx) => {
|
|
120
121
|
const blockDef = blockTypes.find((bt) => bt.slug === block.blockType);
|
|
121
|
-
return (_jsxs("div", { className: "border border-border rounded-md p-3 space-y-2 relative", children: [_jsxs("div", { className: "flex items-center justify-between mb-1", children: [_jsx("span", { className: "text-xs font-semibold text-muted-foreground uppercase", children: String(block.blockType) }), _jsx(
|
|
122
|
-
}), blockTypes.length > 0 && (_jsx("div", { className: "flex gap-2 flex-wrap", children: blockTypes.map((bt) => (_jsxs(
|
|
122
|
+
return (_jsxs("div", { className: "border border-border rounded-md p-3 space-y-2 relative", children: [_jsxs("div", { className: "flex items-center justify-between mb-1", children: [_jsx("span", { className: "text-xs font-semibold text-muted-foreground uppercase", children: String(block.blockType) }), _jsx(Button, { type: "button", variant: "danger", appearance: "ghost", size: "sm", onClick: () => removeBlock(idx), children: "Remove" })] }), (blockDef?.fields ?? []).map((sf) => (_jsxs("div", { children: [_jsx("label", { htmlFor: `${field.name}-${idx}-${sf.name}`, className: "block text-xs font-medium text-muted-foreground", children: getFieldLabel(sf) }), _jsx(FieldInput, { field: sf, value: block[sf.name ?? ''], onChange: (v) => updateBlock(idx, sf.name ?? '', v) })] }, sf.name)))] }, `${field.name}-block-${idx.toString()}`));
|
|
123
|
+
}), blockTypes.length > 0 && (_jsx("div", { className: "flex gap-2 flex-wrap", children: blockTypes.map((bt) => (_jsxs(Button, { type: "button", variant: "brand", appearance: "ghost", size: "sm", onClick: () => addBlock(bt.slug), children: ["+ ", bt.slug] }, bt.slug))) }))] }));
|
|
123
124
|
}
|
|
124
125
|
// ---------------------------------------------------------------------------
|
|
125
126
|
// Collapsible field: expandable section of sub-fields
|
|
@@ -131,7 +132,7 @@ function CollapsibleFieldRenderer({ field, value, onChange, }) {
|
|
|
131
132
|
const handleChange = (key, val) => {
|
|
132
133
|
onChange({ ...data, [key]: val });
|
|
133
134
|
};
|
|
134
|
-
return (_jsxs("div", { className: "border border-border rounded-md", children: [_jsxs(
|
|
135
|
+
return (_jsxs("div", { className: "border border-border rounded-md", children: [_jsxs(Button, { type: "button", variant: "neutral", appearance: "ghost", size: "clear", onClick: () => setOpen(!open), className: "w-full text-left px-3 py-2 text-sm font-medium text-foreground hover:bg-muted flex items-center justify-between", children: [getFieldLabel(field), _jsx("span", { className: "text-muted-foreground", children: open ? '\u25B2' : '\u25BC' })] }), open && (_jsx("div", { className: "px-3 pb-3 space-y-3", children: subFields.map((sf) => (_jsxs("div", { children: [_jsx("label", { htmlFor: `${field.name}-${sf.name}`, className: "block text-xs font-medium text-muted-foreground", children: getFieldLabel(sf) }), _jsx(FieldInput, { field: sf, value: data[sf.name ?? ''], onChange: (v) => handleChange(sf.name ?? '', v) })] }, sf.name))) }))] }));
|
|
135
136
|
}
|
|
136
137
|
// ---------------------------------------------------------------------------
|
|
137
138
|
// JSON field: raw JSON editor with syntax-highlighted textarea
|
|
@@ -151,7 +152,7 @@ function JsonFieldRenderer({ field, value, onChange, }) {
|
|
|
151
152
|
onChange(raw);
|
|
152
153
|
}
|
|
153
154
|
}, [onChange]);
|
|
154
|
-
return (_jsxs("div", { children: [_jsx(
|
|
155
|
+
return (_jsxs("div", { children: [_jsx(Textarea, { id: field.name, value: formatted, onChange: handleChange, rows: 8, className: "mt-1 font-mono text-xs", spellCheck: false }), error && _jsx("p", { className: "mt-1 text-xs text-red-500", children: error })] }));
|
|
155
156
|
}
|
|
156
157
|
// ---------------------------------------------------------------------------
|
|
157
158
|
// Point field: latitude/longitude pair
|
|
@@ -159,31 +160,30 @@ function JsonFieldRenderer({ field, value, onChange, }) {
|
|
|
159
160
|
function PointFieldRenderer({ field, value, onChange, }) {
|
|
160
161
|
const point = (typeof value === 'object' && value !== null ? value : { lat: 0, lng: 0 });
|
|
161
162
|
const baseClasses = 'mt-1 block w-full border-input rounded-md shadow-sm focus:ring-ring focus:border-primary sm:text-sm';
|
|
162
|
-
return (_jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { children: [_jsx("label", { htmlFor: `${field.name}-lat`, className: "block text-xs font-medium text-muted-foreground", children: "Latitude" }), _jsx(
|
|
163
|
+
return (_jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { children: [_jsx("label", { htmlFor: `${field.name}-lat`, className: "block text-xs font-medium text-muted-foreground", children: "Latitude" }), _jsx(Input, { type: "number", id: `${field.name}-lat`, value: point.lat, onChange: (e) => onChange({ ...point, lat: Number(e.target.value) }), className: baseClasses, step: "any", min: -90, max: 90 })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: `${field.name}-lng`, className: "block text-xs font-medium text-muted-foreground", children: "Longitude" }), _jsx(Input, { type: "number", id: `${field.name}-lng`, value: point.lng, onChange: (e) => onChange({ ...point, lng: Number(e.target.value) }), className: baseClasses, step: "any", min: -180, max: 180 })] })] }));
|
|
163
164
|
}
|
|
164
165
|
// ---------------------------------------------------------------------------
|
|
165
166
|
// Main FieldInput - renders the appropriate control for each field type
|
|
166
167
|
// ---------------------------------------------------------------------------
|
|
167
168
|
function FieldInput({ field, value, onChange }) {
|
|
168
|
-
const baseClasses = 'mt-1
|
|
169
|
+
const baseClasses = 'mt-1';
|
|
169
170
|
switch (field.type) {
|
|
170
171
|
case 'text':
|
|
171
|
-
return (_jsx(
|
|
172
|
+
return (_jsx(Input, { type: "text", id: field.name, value: formatTextValue(value), onChange: (e) => onChange(e.target.value), className: baseClasses, required: field.required }));
|
|
172
173
|
case 'email':
|
|
173
|
-
return (_jsx(
|
|
174
|
+
return (_jsx(Input, { type: "email", id: field.name, value: formatTextValue(value), onChange: (e) => onChange(e.target.value), className: baseClasses, required: field.required, placeholder: field.admin?.placeholder }));
|
|
174
175
|
case 'password':
|
|
175
|
-
return (_jsx(
|
|
176
|
+
return (_jsx(Input, { type: "password", id: field.name, value: formatTextValue(value), onChange: (e) => onChange(e.target.value), className: baseClasses, required: field.required, autoComplete: "new-password" }));
|
|
176
177
|
case 'code':
|
|
177
|
-
return (_jsx(
|
|
178
|
+
return (_jsx(Textarea, { id: field.name, value: formatTextValue(value), onChange: (e) => onChange(e.target.value), rows: 8, className: `${baseClasses} font-mono text-xs`, required: field.required, spellCheck: false }));
|
|
178
179
|
case 'textarea':
|
|
179
|
-
return (_jsx(
|
|
180
|
+
return (_jsx(Textarea, { id: field.name, value: formatTextValue(value), onChange: (e) => onChange(e.target.value), rows: 4, className: baseClasses, required: field.required }));
|
|
180
181
|
case 'number':
|
|
181
|
-
return (_jsx(
|
|
182
|
+
return (_jsx(Input, { type: "number", id: field.name, value: typeof value === 'number' ? value : value ? Number(value) : '', onChange: (e) => onChange(Number(e.target.value) || undefined), className: baseClasses, required: field.required, min: field.min, max: field.max }));
|
|
182
183
|
case 'checkbox':
|
|
183
|
-
return (_jsx(
|
|
184
|
+
return (_jsx(Checkbox, { checked: Boolean(value), onChange: (checked) => onChange(checked), name: field.name }));
|
|
184
185
|
case 'select': {
|
|
185
186
|
const isMulti = field.hasMany === true;
|
|
186
|
-
const selectClasses = `${baseClasses} text-foreground bg-card`;
|
|
187
187
|
const optionNodes = field.options?.map((option) => {
|
|
188
188
|
const optValue = typeof option === 'string' ? option : option.value;
|
|
189
189
|
const optLabel = typeof option === 'string' ? option : option.label;
|
|
@@ -191,29 +191,29 @@ function FieldInput({ field, value, onChange }) {
|
|
|
191
191
|
});
|
|
192
192
|
if (isMulti) {
|
|
193
193
|
const selected = Array.isArray(value) ? value : value ? [String(value)] : [];
|
|
194
|
-
return (_jsx(
|
|
194
|
+
return (_jsx(Select, { id: field.name, multiple: true, value: selected, onChange: (e) => {
|
|
195
195
|
const vals = Array.from(e.target.selectedOptions).map((o) => o.value);
|
|
196
196
|
onChange(vals);
|
|
197
|
-
}, className: `${
|
|
197
|
+
}, className: `${baseClasses} h-32`, required: field.required, children: optionNodes }));
|
|
198
198
|
}
|
|
199
|
-
return (_jsxs(
|
|
199
|
+
return (_jsxs(Select, { id: field.name, value: formatTextValue(value), onChange: (e) => onChange(e.target.value), className: baseClasses, required: field.required, children: [_jsx("option", { value: "", children: "Select an option" }), optionNodes] }));
|
|
200
200
|
}
|
|
201
201
|
case 'radio':
|
|
202
|
-
return (_jsx(
|
|
202
|
+
return (_jsx(RadioGroup, { name: field.name, value: formatTextValue(value), onChange: (next) => onChange(next), className: "mt-1", children: field.options?.map((option) => {
|
|
203
203
|
const optValue = typeof option === 'string' ? option : option.value;
|
|
204
204
|
const optLabel = typeof option === 'string' ? option : option.label;
|
|
205
|
-
return (_jsxs(
|
|
205
|
+
return (_jsxs(RadioField, { children: [_jsx(Radio, { value: optValue }), _jsx(FieldLabel, { children: optLabel })] }, optValue));
|
|
206
206
|
}) }));
|
|
207
207
|
case 'relationship':
|
|
208
|
-
return (_jsxs("div", { children: [_jsx(
|
|
208
|
+
return (_jsxs("div", { children: [_jsx(Input, { type: "text", id: field.name, value: formatTextValue(value), onChange: (e) => onChange(e.target.value), className: baseClasses, required: field.required, placeholder: `Enter ${field.relationTo ?? 'related'} ID` }), _jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: ["Related to: ", field.relationTo ?? 'unknown'] })] }));
|
|
209
209
|
case 'upload':
|
|
210
|
-
return (_jsxs("div", { children: [_jsx(
|
|
210
|
+
return (_jsxs("div", { children: [_jsx(Input, { type: "file", id: field.name, onChange: (e) => {
|
|
211
211
|
const file = e.target.files?.[0];
|
|
212
212
|
if (file)
|
|
213
213
|
onChange(file);
|
|
214
214
|
}, className: "block w-full text-sm text-muted-foreground file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-medium file:bg-primary/10 file:text-primary hover:file:bg-primary/20" }), typeof value === 'string' && value !== '' && (_jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: ["Current: ", value] }))] }));
|
|
215
215
|
case 'date':
|
|
216
|
-
return (_jsx(
|
|
216
|
+
return (_jsx(Input, { type: "datetime-local", id: field.name, value: formatDateInputValue(value), onChange: (e) => onChange(e.target.value ? new Date(e.target.value) : null), className: baseClasses, required: field.required }));
|
|
217
217
|
case 'richText': {
|
|
218
218
|
const editorConfig = field.editor;
|
|
219
219
|
return (_jsx(Suspense, { fallback: _jsx("div", { className: "border border-input rounded-md h-40 flex items-center justify-center text-sm text-muted-foreground", children: "Loading editor\u2026" }), children: _jsx(RichTextEditor, { namespace: String(field.name), editorConfig: editorConfig, initialValue: value, onSerializedChange: (json) => onChange(json), className: "border border-input rounded-md" }) }));
|
|
@@ -233,6 +233,6 @@ function FieldInput({ field, value, onChange }) {
|
|
|
233
233
|
case 'ui':
|
|
234
234
|
return (_jsxs("div", { className: "border border-dashed border-input rounded-md p-3 text-sm text-muted-foreground text-center", children: ["Custom UI field: ", field.name] }));
|
|
235
235
|
default:
|
|
236
|
-
return (_jsx(
|
|
236
|
+
return (_jsx(Input, { type: "text", id: field.name, value: formatTextValue(value), onChange: (e) => onChange(e.target.value), className: baseClasses, required: field.required }));
|
|
237
237
|
}
|
|
238
238
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalForm.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/components/GlobalForm.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GlobalForm.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/components/GlobalForm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAiB,MAAM,yBAAyB,CAAC;AAsCjG,UAAU,eAAe;IACvB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAChD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,SAAiB,GAClB,EAAE,eAAe,qBAoDjB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Button, Checkbox, Input, Select, Textarea } from '@revealui/presentation';
|
|
3
4
|
import { useState } from 'react';
|
|
4
5
|
function getFieldLabel(field) {
|
|
5
6
|
const { label } = field;
|
|
@@ -47,28 +48,28 @@ export function GlobalForm({ global, document, onSave, onCancel, isLoading = fal
|
|
|
47
48
|
const handleFieldChange = (fieldName, value) => {
|
|
48
49
|
setFormData((prev) => ({ ...prev, [fieldName]: value }));
|
|
49
50
|
};
|
|
50
|
-
return (_jsx("div", { className: "bg-card shadow overflow-hidden sm:rounded-lg", children: _jsxs("div", { className: "px-4 py-5 sm:p-6", children: [_jsxs("h3", { className: "text-lg leading-6 font-medium text-foreground mb-4", children: ["Edit ", global.label || global.slug] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-6", children: [visibleFields.map((field) => (_jsxs("div", { children: [_jsxs("label", { htmlFor: field.name, className: "block text-sm font-medium text-foreground", children: [getFieldLabel(field), field.required && _jsx("span", { className: "text-red-500 ml-1", children: "*" })] }), _jsx("div", { className: "mt-1", children: _jsx(FieldInput, { field: field, value: field.name ? formData[field.name] : undefined, onChange: (value) => field.name && handleFieldChange(field.name, value) }) })] }, field.name || 'layout'))), _jsxs("div", { className: "flex justify-end space-x-3 pt-6", children: [_jsx(
|
|
51
|
+
return (_jsx("div", { className: "bg-card shadow overflow-hidden sm:rounded-lg", children: _jsxs("div", { className: "px-4 py-5 sm:p-6", children: [_jsxs("h3", { className: "text-lg leading-6 font-medium text-foreground mb-4", children: ["Edit ", global.label || global.slug] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-6", children: [visibleFields.map((field) => (_jsxs("div", { children: [_jsxs("label", { htmlFor: field.name, className: "block text-sm font-medium text-foreground", children: [getFieldLabel(field), field.required && _jsx("span", { className: "text-red-500 ml-1", children: "*" })] }), _jsx("div", { className: "mt-1", children: _jsx(FieldInput, { field: field, value: field.name ? formData[field.name] : undefined, onChange: (value) => field.name && handleFieldChange(field.name, value) }) })] }, field.name || 'layout'))), _jsxs("div", { className: "flex justify-end space-x-3 pt-6", children: [_jsx(Button, { type: "button", variant: "neutral", appearance: "outline", onClick: onCancel, children: "Cancel" }), _jsx(Button, { type: "submit", variant: "brand", appearance: "solid", disabled: isLoading, children: isLoading ? 'Saving...' : 'Save' })] })] })] }) }));
|
|
51
52
|
}
|
|
52
53
|
function FieldInput({ field, value, onChange }) {
|
|
53
|
-
const baseClasses = 'mt-1
|
|
54
|
+
const baseClasses = 'mt-1';
|
|
54
55
|
switch (field.type) {
|
|
55
56
|
case 'text':
|
|
56
|
-
return (_jsx(
|
|
57
|
+
return (_jsx(Input, { type: "text", id: field.name, value: formatTextValue(value), onChange: (e) => onChange(e.target.value), className: baseClasses, required: field.required }));
|
|
57
58
|
case 'textarea':
|
|
58
|
-
return (_jsx(
|
|
59
|
+
return (_jsx(Textarea, { id: field.name, value: formatTextValue(value), onChange: (e) => onChange(e.target.value), rows: 4, className: baseClasses, required: field.required }));
|
|
59
60
|
case 'number':
|
|
60
|
-
return (_jsx(
|
|
61
|
+
return (_jsx(Input, { type: "number", id: field.name, value: typeof value === 'number' ? value : value ? Number(value) : '', onChange: (e) => onChange(Number(e.target.value) || undefined), className: baseClasses, required: field.required, min: field.min, max: field.max }));
|
|
61
62
|
case 'checkbox':
|
|
62
|
-
return (_jsx(
|
|
63
|
+
return (_jsx(Checkbox, { checked: Boolean(value), onChange: (checked) => onChange(checked), name: field.name }));
|
|
63
64
|
case 'select':
|
|
64
|
-
return (_jsxs(
|
|
65
|
+
return (_jsxs(Select, { id: field.name, value: formatTextValue(value), onChange: (e) => onChange(e.target.value), className: baseClasses, required: field.required, children: [_jsx("option", { value: "", children: "Select an option" }), field.options?.map((option) => {
|
|
65
66
|
const value = typeof option === 'string' ? option : option.value;
|
|
66
67
|
const label = typeof option === 'string' ? option : option.label;
|
|
67
68
|
return (_jsx("option", { value: value, children: label }, value));
|
|
68
69
|
})] }));
|
|
69
70
|
case 'date':
|
|
70
|
-
return (_jsx(
|
|
71
|
+
return (_jsx(Input, { type: "datetime-local", id: field.name, value: formatDateInputValue(value), onChange: (e) => onChange(e.target.value ? new Date(e.target.value) : null), className: baseClasses, required: field.required }));
|
|
71
72
|
default:
|
|
72
|
-
return (_jsx(
|
|
73
|
+
return (_jsx(Input, { type: "text", id: field.name, value: formatTextValue(value), onChange: (e) => onChange(e.target.value), className: baseClasses, required: field.required }));
|
|
73
74
|
}
|
|
74
75
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../src/client/admin/page.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../src/client/admin/page.tsx"],"names":[],"mappings":"AAGA,UAAU,QAAQ;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE;QACN,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;QACxB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;QACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,MAAM,EAAE,OAAO,CAAC;QAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACzC,YAAY,EAAE,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE;QACN,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;QACxB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;QACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,MAAM,EAAE,OAAO,CAAC;QAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACzC,YAAY,EAAE,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,wBAAgB,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,aAAa,+BAsJjD;AAED,wBAAgB,YAAY,gCAO3B;AAED,wBAAgB,oBAAoB,IAAI,QAAQ,CAS/C"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { IconCheck, IconPrimitiveContent, IconSettings } from '@revealui/presentation';
|
|
2
3
|
export function RootPage({ config }) {
|
|
3
4
|
const collections = (config.collections || []);
|
|
4
5
|
const globals = (config.globals || []);
|
|
@@ -6,7 +7,7 @@ export function RootPage({ config }) {
|
|
|
6
7
|
// REVEALUI_TENANT_NAME. `||` not `??`: Compose `${VAR:-}` interpolation
|
|
7
8
|
// delivers unset vars as empty strings.
|
|
8
9
|
const siteName = process.env.REVEALUI_BRAND_NAME || process.env.REVEALUI_TENANT_NAME || 'RevealUI';
|
|
9
|
-
return (_jsxs("div", { className: "min-h-screen bg-background", children: [_jsx("header", { className: "bg-card shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsxs("div", { className: "flex justify-between items-center py-4", children: [_jsx("div", { className: "flex items-center", children: _jsx("h1", { className: "text-2xl font-bold text-foreground", children: `${siteName} Admin` }) }), _jsx("div", { className: "flex shrink-0 items-center gap-3", children: _jsxs("span", { className: "shrink-0 text-sm tabular-nums text-muted-foreground", title: "Application version", children: ["v", process.env.NEXT_PUBLIC_APP_VERSION ?? process.env.APP_VERSION ?? '0.0.0'] }) })] }) }) }), _jsx("main", { className: "max-w-7xl mx-auto py-6 sm:px-6 lg:px-8", children: _jsx("div", { className: "px-4 py-6 sm:px-0", children: _jsxs("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: [_jsxs("div", { className: "bg-card overflow-hidden shadow rounded-lg", children: [_jsx("div", { className: "p-5", children: _jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "flex-shrink-0", children:
|
|
10
|
+
return (_jsxs("div", { className: "min-h-screen bg-background", children: [_jsx("header", { className: "bg-card shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsxs("div", { className: "flex justify-between items-center py-4", children: [_jsx("div", { className: "flex items-center", children: _jsx("h1", { className: "text-2xl font-bold text-foreground", children: `${siteName} Admin` }) }), _jsx("div", { className: "flex shrink-0 items-center gap-3", children: _jsxs("span", { className: "shrink-0 text-sm tabular-nums text-muted-foreground", title: "Application version", children: ["v", process.env.NEXT_PUBLIC_APP_VERSION ?? process.env.APP_VERSION ?? '0.0.0'] }) })] }) }) }), _jsx("main", { className: "max-w-7xl mx-auto py-6 sm:px-6 lg:px-8", children: _jsx("div", { className: "px-4 py-6 sm:px-0", children: _jsxs("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: [_jsxs("div", { className: "bg-card overflow-hidden shadow rounded-lg", children: [_jsx("div", { className: "p-5", children: _jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "flex-shrink-0", children: _jsx(IconPrimitiveContent, { size: "lg", className: "h-8 w-8 text-muted-foreground", label: "Collections" }) }), _jsx("div", { className: "ml-5 w-0 flex-1", children: _jsxs("dl", { children: [_jsx("dt", { className: "text-sm font-medium text-muted-foreground truncate", children: "Collections" }), _jsx("dd", { className: "text-lg font-medium text-foreground", children: collections.length })] }) })] }) }), _jsx("div", { className: "bg-muted px-5 py-3", children: _jsx("div", { className: "text-sm", children: collections.length > 0 ? (_jsx("ul", { className: "space-y-1", children: collections.map((collection) => (_jsxs("li", { className: "text-muted-foreground", children: [_jsx("span", { className: "font-medium", children: collection.slug }), _jsxs("span", { className: "ml-2 text-xs text-muted-foreground", children: ["(", collection.fields?.length || 0, " fields)"] })] }, collection.slug))) })) : (_jsx("p", { className: "text-muted-foreground", children: "No collections configured" })) }) })] }), _jsxs("div", { className: "bg-card overflow-hidden shadow rounded-lg", children: [_jsx("div", { className: "p-5", children: _jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "flex-shrink-0", children: _jsx(IconSettings, { size: "lg", className: "h-8 w-8 text-muted-foreground", label: "Globals" }) }), _jsx("div", { className: "ml-5 w-0 flex-1", children: _jsxs("dl", { children: [_jsx("dt", { className: "text-sm font-medium text-muted-foreground truncate", children: "Globals" }), _jsx("dd", { className: "text-lg font-medium text-foreground", children: globals.length })] }) })] }) }), _jsx("div", { className: "bg-muted px-5 py-3", children: _jsx("div", { className: "text-sm", children: globals.length > 0 ? (_jsx("ul", { className: "space-y-1", children: globals.map((global) => (_jsxs("li", { className: "text-muted-foreground", children: [_jsx("span", { className: "font-medium", children: global.slug }), _jsxs("span", { className: "ml-2 text-xs text-muted-foreground", children: ["(", global.fields?.length || 0, " fields)"] })] }, global.slug))) })) : (_jsx("p", { className: "text-muted-foreground", children: "No globals configured" })) }) })] }), _jsxs("div", { className: "bg-card overflow-hidden shadow rounded-lg", children: [_jsx("div", { className: "p-5", children: _jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "flex-shrink-0", children: _jsx("div", { className: "h-8 w-8 bg-success/15 rounded-full flex items-center justify-center", children: _jsx(IconCheck, { size: "sm", className: "h-5 w-5 text-success", label: "System operational" }) }) }), _jsx("div", { className: "ml-5 w-0 flex-1", children: _jsxs("dl", { children: [_jsx("dt", { className: "text-sm font-medium text-muted-foreground truncate", children: "System Status" }), _jsx("dd", { className: "text-lg font-medium text-foreground", children: "Operational" })] }) })] }) }), _jsx("div", { className: "bg-muted px-5 py-3", children: _jsxs("div", { className: "text-sm text-muted-foreground", children: [siteName, " admin is running successfully with ", collections.length, " collections and", ' ', globals.length, " globals configured."] }) })] })] }) }) })] }));
|
|
10
11
|
}
|
|
11
12
|
export function NotFoundPage() {
|
|
12
13
|
return (_jsxs("div", { children: [_jsx("h1", { children: "404 - Page Not Found" }), _jsx("p", { children: "The requested admin page could not be found." })] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageNodeComponent.d.ts","sourceRoot":"","sources":["../../../../src/client/richtext/components/ImageNodeComponent.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ImageNodeComponent.d.ts","sourceRoot":"","sources":["../../../../src/client/richtext/components/ImageNodeComponent.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CA0I9C,CAAC"}
|
|
@@ -6,6 +6,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
* React component for rendering and editing images in the editor.
|
|
7
7
|
*/
|
|
8
8
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
9
|
+
import { Button, Input } from '@revealui/presentation';
|
|
9
10
|
import { $getNodeByKey } from 'lexical';
|
|
10
11
|
import { useCallback, useState } from 'react';
|
|
11
12
|
import { OPEN_IMAGE_UPLOAD_COMMAND } from '../nodes/ImageNode.js';
|
|
@@ -61,21 +62,7 @@ export const ImageNodeComponent = (props) => {
|
|
|
61
62
|
opacity: showControls ? 1 : 0,
|
|
62
63
|
transition: 'opacity 0.2s',
|
|
63
64
|
pointerEvents: showControls ? 'auto' : 'none',
|
|
64
|
-
}, children: [_jsx("button", { type: "button", onClick:
|
|
65
|
-
padding: '4px 8px',
|
|
66
|
-
background: 'white',
|
|
67
|
-
border: `1px solid var(--rvui-border, #e2e8f0)`,
|
|
68
|
-
borderRadius: '4px',
|
|
69
|
-
cursor: 'pointer',
|
|
70
|
-
fontSize: '12px',
|
|
71
|
-
}, title: "Edit Image", "aria-label": "Edit Image", children: "\u270E" }), _jsx("button", { type: "button", onClick: removeImage, className: "editor-image-btn", style: {
|
|
72
|
-
padding: '4px 8px',
|
|
73
|
-
background: 'white',
|
|
74
|
-
border: `1px solid var(--rvui-border, #e2e8f0)`,
|
|
75
|
-
borderRadius: '4px',
|
|
76
|
-
cursor: 'pointer',
|
|
77
|
-
fontSize: '12px',
|
|
78
|
-
}, title: "Remove Image", "aria-label": "Remove Image", children: "\u00D7" })] })] }), isEditing ? (_jsx("input", { type: "text", value: editAlt, onChange: (e) => setEditAlt(e.target.value), onBlur: updateAlt, onKeyDown: (e) => {
|
|
65
|
+
}, children: [_jsx(Button, { type: "button", variant: "neutral", appearance: "outline", size: "sm", onClick: handleEdit, className: "editor-image-btn", title: "Edit Image", "aria-label": "Edit Image", children: "\u270E" }), _jsx(Button, { type: "button", variant: "neutral", appearance: "outline", size: "sm", onClick: removeImage, className: "editor-image-btn", title: "Remove Image", "aria-label": "Remove Image", children: "\u00D7" })] })] }), isEditing ? (_jsx(Input, { type: "text", value: editAlt, onChange: (e) => setEditAlt(e.target.value), onBlur: updateAlt, onKeyDown: (e) => {
|
|
79
66
|
if (e.key === 'Enter') {
|
|
80
67
|
updateAlt();
|
|
81
68
|
}
|
|
@@ -83,13 +70,7 @@ export const ImageNodeComponent = (props) => {
|
|
|
83
70
|
setEditAlt(data.alt || '');
|
|
84
71
|
setIsEditing(false);
|
|
85
72
|
}
|
|
86
|
-
}, placeholder: "Image alt text", style: {
|
|
87
|
-
width: '100%',
|
|
88
|
-
marginTop: '8px',
|
|
89
|
-
padding: '4px 8px',
|
|
90
|
-
border: `1px solid var(--rvui-border, #e2e8f0)`,
|
|
91
|
-
borderRadius: '4px',
|
|
92
|
-
} })) : (data.caption && (_jsx("figcaption", { style: {
|
|
73
|
+
}, placeholder: "Image alt text", className: "mt-2 w-full" })) : (data.caption && (_jsx("figcaption", { style: {
|
|
93
74
|
marginTop: '8px',
|
|
94
75
|
fontSize: '14px',
|
|
95
76
|
color: 'var(--rvui-text-2, #64748b)',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageUploadButton.d.ts","sourceRoot":"","sources":["../../../../src/client/richtext/components/ImageUploadButton.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ImageUploadButton.d.ts","sourceRoot":"","sources":["../../../../src/client/richtext/components/ImageUploadButton.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAQ/B,UAAU,sBAAsB;IAC9B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,0DAA0D;IAC1D,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAqBD,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAkJ9D,CAAC"}
|