@actuate-media/cms-admin 0.10.0 → 0.11.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/AdminRoot.d.ts.map +1 -1
- package/dist/AdminRoot.js +8 -5
- package/dist/AdminRoot.js.map +1 -1
- package/dist/__tests__/layout/primitives.test.d.ts +2 -0
- package/dist/__tests__/layout/primitives.test.d.ts.map +1 -0
- package/dist/__tests__/layout/primitives.test.js +34 -0
- package/dist/__tests__/layout/primitives.test.js.map +1 -0
- package/dist/__tests__/lib/cv.test.d.ts +2 -0
- package/dist/__tests__/lib/cv.test.d.ts.map +1 -0
- package/dist/__tests__/lib/cv.test.js +66 -0
- package/dist/__tests__/lib/cv.test.js.map +1 -0
- package/dist/actuate-admin.css +1 -1
- package/dist/assets/actuate-logo.d.ts +36 -0
- package/dist/assets/actuate-logo.d.ts.map +1 -0
- package/dist/assets/actuate-logo.js +15 -0
- package/dist/assets/actuate-logo.js.map +1 -0
- package/dist/components/Breadcrumbs.js +2 -2
- package/dist/components/CommandPalette.js +10 -10
- package/dist/components/ContentOverviewChart.js +3 -3
- package/dist/components/ErrorBoundary.js +1 -1
- package/dist/components/FocalPointPicker.js +2 -2
- package/dist/components/FolderTree.js +20 -20
- package/dist/components/LivePreview.js +3 -3
- package/dist/components/LocaleSwitcher.js +1 -1
- package/dist/components/MediaPickerModal.js +4 -4
- package/dist/components/PresenceIndicator.js +1 -1
- package/dist/components/SEOConfigPanel.d.ts +2 -0
- package/dist/components/SEOConfigPanel.d.ts.map +1 -0
- package/dist/components/SEOConfigPanel.js +174 -0
- package/dist/components/SEOConfigPanel.js.map +1 -0
- package/dist/components/SEOPanel.js +9 -9
- package/dist/components/SEOPerformance.js +2 -2
- package/dist/components/SchedulePublishDialog.js +1 -1
- package/dist/components/SharePreviewLinkDialog.js +1 -1
- package/dist/components/TipTapEditor.js +5 -5
- package/dist/components/VersionHistory.js +2 -2
- package/dist/components/ui/Badge.d.ts +33 -3
- package/dist/components/ui/Badge.d.ts.map +1 -1
- package/dist/components/ui/Badge.js +42 -8
- package/dist/components/ui/Badge.js.map +1 -1
- package/dist/components/ui/Button.d.ts +19 -8
- package/dist/components/ui/Button.d.ts.map +1 -1
- package/dist/components/ui/Button.js +35 -14
- package/dist/components/ui/Button.js.map +1 -1
- package/dist/components/ui/Card.d.ts +26 -0
- package/dist/components/ui/Card.d.ts.map +1 -0
- package/dist/components/ui/Card.js +45 -0
- package/dist/components/ui/Card.js.map +1 -0
- package/dist/components/ui/DataTable.js +1 -1
- package/dist/components/ui/Input.d.ts +15 -0
- package/dist/components/ui/Input.d.ts.map +1 -0
- package/dist/components/ui/Input.js +23 -0
- package/dist/components/ui/Input.js.map +1 -0
- package/dist/components/ui/SearchInput.js +1 -1
- package/dist/components/ui/Select.d.ts +16 -0
- package/dist/components/ui/Select.d.ts.map +1 -0
- package/dist/components/ui/Select.js +25 -0
- package/dist/components/ui/Select.js.map +1 -0
- package/dist/components/ui/Toast.js +1 -1
- package/dist/components/ui/index.d.ts +10 -4
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +5 -2
- package/dist/components/ui/index.js.map +1 -1
- package/dist/fields/BlockBuilderField.js +3 -3
- package/dist/fields/DateField.js +1 -1
- package/dist/fields/RelationshipField.js +3 -3
- package/dist/fields/TextField.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/layout/Header.js +1 -1
- package/dist/layout/Layout.d.ts +14 -0
- package/dist/layout/Layout.d.ts.map +1 -1
- package/dist/layout/Layout.js +17 -11
- package/dist/layout/Layout.js.map +1 -1
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/Sidebar.js +21 -11
- package/dist/layout/Sidebar.js.map +1 -1
- package/dist/layout/primitives/AdminShell.d.ts +43 -0
- package/dist/layout/primitives/AdminShell.d.ts.map +1 -0
- package/dist/layout/primitives/AdminShell.js +51 -0
- package/dist/layout/primitives/AdminShell.js.map +1 -0
- package/dist/layout/primitives/Box.d.ts +19 -0
- package/dist/layout/primitives/Box.d.ts.map +1 -0
- package/dist/layout/primitives/Box.js +12 -0
- package/dist/layout/primitives/Box.js.map +1 -0
- package/dist/layout/primitives/Cluster.d.ts +27 -0
- package/dist/layout/primitives/Cluster.d.ts.map +1 -0
- package/dist/layout/primitives/Cluster.js +37 -0
- package/dist/layout/primitives/Cluster.js.map +1 -0
- package/dist/layout/primitives/Grid.d.ts +45 -0
- package/dist/layout/primitives/Grid.d.ts.map +1 -0
- package/dist/layout/primitives/Grid.js +59 -0
- package/dist/layout/primitives/Grid.js.map +1 -0
- package/dist/layout/primitives/PageContainer.d.ts +36 -0
- package/dist/layout/primitives/PageContainer.d.ts.map +1 -0
- package/dist/layout/primitives/PageContainer.js +41 -0
- package/dist/layout/primitives/PageContainer.js.map +1 -0
- package/dist/layout/primitives/Split.d.ts +34 -0
- package/dist/layout/primitives/Split.d.ts.map +1 -0
- package/dist/layout/primitives/Split.js +27 -0
- package/dist/layout/primitives/Split.js.map +1 -0
- package/dist/layout/primitives/Stack.d.ts +23 -0
- package/dist/layout/primitives/Stack.d.ts.map +1 -0
- package/dist/layout/primitives/Stack.js +34 -0
- package/dist/layout/primitives/Stack.js.map +1 -0
- package/dist/layout/primitives/index.d.ts +30 -0
- package/dist/layout/primitives/index.d.ts.map +1 -0
- package/dist/layout/primitives/index.js +22 -0
- package/dist/layout/primitives/index.js.map +1 -0
- package/dist/layout/primitives/tokens.d.ts +48 -0
- package/dist/layout/primitives/tokens.d.ts.map +1 -0
- package/dist/layout/primitives/tokens.js +54 -0
- package/dist/layout/primitives/tokens.js.map +1 -0
- package/dist/lib/cv.d.ts +53 -0
- package/dist/lib/cv.d.ts.map +1 -0
- package/dist/lib/cv.js +39 -0
- package/dist/lib/cv.js.map +1 -0
- package/dist/views/ApiKeys.js +7 -7
- package/dist/views/CollectionList.js +8 -8
- package/dist/views/Dashboard.d.ts.map +1 -1
- package/dist/views/Dashboard.js +333 -78
- package/dist/views/Dashboard.js.map +1 -1
- package/dist/views/DocumentEdit.js +3 -3
- package/dist/views/ForgotPassword.js +2 -2
- package/dist/views/FormEditor.js +5 -5
- package/dist/views/FormSubmissions.js +6 -6
- package/dist/views/Forms.js +2 -2
- package/dist/views/Login.d.ts +16 -1
- package/dist/views/Login.d.ts.map +1 -1
- package/dist/views/Login.js +17 -7
- package/dist/views/Login.js.map +1 -1
- package/dist/views/MediaBrowser.js +16 -16
- package/dist/views/PageEditor.js +2 -2
- package/dist/views/Pages.js +10 -10
- package/dist/views/PostEditor.js +2 -2
- package/dist/views/Posts.js +4 -4
- package/dist/views/Redirects.js +4 -4
- package/dist/views/ResetPassword.js +2 -2
- package/dist/views/SEO.js +6 -6
- package/dist/views/ScriptTagEditor.js +4 -4
- package/dist/views/ScriptTags.js +2 -2
- package/dist/views/Settings.d.ts.map +1 -1
- package/dist/views/Settings.js +9 -8
- package/dist/views/Settings.js.map +1 -1
- package/dist/views/SetupWizard.js +2 -2
- package/dist/views/Users.js +4 -4
- package/dist/views/page-builder/AIBlockAssist.js +1 -1
- package/dist/views/page-builder/AIGenerateDialog.js +10 -10
- package/dist/views/page-builder/BlockEditor.js +10 -10
- package/dist/views/page-builder/BlockPicker.js +4 -4
- package/dist/views/page-builder/BottomBar.js +1 -1
- package/dist/views/page-builder/BuilderToolbar.js +2 -2
- package/dist/views/page-builder/ContextPanel.js +2 -2
- package/dist/views/page-builder/DesignScore.js +9 -9
- package/dist/views/page-builder/NodeSettings.js +8 -8
- package/dist/views/page-builder/PageBuilder.js +3 -3
- package/dist/views/page-builder/PageSettings.js +1 -1
- package/dist/views/page-builder/PageTemplates.js +2 -2
- package/dist/views/page-builder/SEOPanel.js +13 -13
- package/dist/views/page-builder/SavedSections.js +5 -5
- package/dist/views/page-builder/TemplatePicker.js +2 -2
- package/dist/views/page-builder/block-renderers/CTAPreview.js +5 -5
- package/dist/views/page-builder/block-renderers/CardsPreview.js +1 -1
- package/dist/views/page-builder/block-renderers/CodePreview.js +1 -1
- package/dist/views/page-builder/block-renderers/FAQPreview.js +3 -3
- package/dist/views/page-builder/block-renderers/FallbackPreview.js +1 -1
- package/dist/views/page-builder/block-renderers/FormPreview.js +3 -3
- package/dist/views/page-builder/block-renderers/GalleryPreview.js +5 -5
- package/dist/views/page-builder/block-renderers/HeroPreview.js +3 -3
- package/dist/views/page-builder/block-renderers/ImagePreview.js +3 -3
- package/dist/views/page-builder/block-renderers/TextPreview.js +3 -3
- package/dist/views/page-builder/block-renderers/VideoPreview.js +4 -4
- package/dist/views/page-builder/canvas/BlockRenderer.js +1 -1
- package/dist/views/page-builder/canvas/BuilderCanvas.js +3 -3
- package/dist/views/page-builder/canvas/ColumnRenderer.js +2 -2
- package/dist/views/page-builder/canvas/ContainerRenderer.js +2 -2
- package/dist/views/page-builder/canvas/RowRenderer.js +2 -2
- package/dist/views/page-builder/canvas/SectionRenderer.js +2 -2
- package/package.json +6 -2
- package/src/AdminRoot.tsx +21 -11
- package/src/__tests__/layout/primitives.test.ts +37 -0
- package/src/__tests__/lib/cv.test.ts +74 -0
- package/src/assets/actuate-logo.tsx +72 -0
- package/src/components/Breadcrumbs.tsx +6 -6
- package/src/components/CommandPalette.tsx +34 -34
- package/src/components/ContentOverviewChart.tsx +3 -3
- package/src/components/ErrorBoundary.tsx +3 -3
- package/src/components/FocalPointPicker.tsx +4 -4
- package/src/components/FolderTree.tsx +38 -38
- package/src/components/LivePreview.tsx +16 -16
- package/src/components/LocaleSwitcher.tsx +7 -7
- package/src/components/MediaPickerModal.tsx +21 -21
- package/src/components/PresenceIndicator.tsx +2 -2
- package/src/components/SEOConfigPanel.tsx +582 -0
- package/src/components/SEOPanel.tsx +46 -46
- package/src/components/SEOPerformance.tsx +21 -21
- package/src/components/SchedulePublishDialog.tsx +4 -4
- package/src/components/SharePreviewLinkDialog.tsx +1 -1
- package/src/components/TipTapEditor.tsx +33 -33
- package/src/components/VersionHistory.tsx +16 -16
- package/src/components/ui/Badge.tsx +66 -14
- package/src/components/ui/Button.tsx +70 -33
- package/src/components/ui/Card.tsx +101 -0
- package/src/components/ui/DataTable.tsx +1 -1
- package/src/components/ui/Input.tsx +35 -0
- package/src/components/ui/SearchInput.tsx +4 -4
- package/src/components/ui/Select.tsx +56 -0
- package/src/components/ui/Toast.tsx +1 -1
- package/src/components/ui/index.ts +18 -4
- package/src/fields/BlockBuilderField.tsx +3 -3
- package/src/fields/DateField.tsx +1 -1
- package/src/fields/RelationshipField.tsx +10 -10
- package/src/fields/TextField.tsx +1 -1
- package/src/index.ts +28 -0
- package/src/layout/Header.tsx +28 -28
- package/src/layout/Layout.tsx +39 -46
- package/src/layout/Sidebar.tsx +37 -64
- package/src/layout/primitives/AdminShell.tsx +118 -0
- package/src/layout/primitives/Box.tsx +30 -0
- package/src/layout/primitives/Cluster.tsx +74 -0
- package/src/layout/primitives/Grid.tsx +120 -0
- package/src/layout/primitives/PageContainer.tsx +96 -0
- package/src/layout/primitives/Split.tsx +73 -0
- package/src/layout/primitives/Stack.tsx +67 -0
- package/src/layout/primitives/index.ts +36 -0
- package/src/layout/primitives/tokens.ts +76 -0
- package/src/lib/cv.ts +96 -0
- package/src/styles/build-input.css +1 -1
- package/src/views/ApiKeys.tsx +57 -57
- package/src/views/CollectionList.tsx +30 -30
- package/src/views/Dashboard.tsx +737 -186
- package/src/views/DocumentEdit.tsx +9 -9
- package/src/views/ForgotPassword.tsx +18 -18
- package/src/views/FormEditor.tsx +75 -75
- package/src/views/FormSubmissions.tsx +76 -76
- package/src/views/Forms.tsx +27 -27
- package/src/views/Login.tsx +65 -25
- package/src/views/MediaBrowser.tsx +127 -127
- package/src/views/PageEditor.tsx +25 -25
- package/src/views/Pages.tsx +59 -59
- package/src/views/PostEditor.tsx +37 -37
- package/src/views/Posts.tsx +48 -48
- package/src/views/Redirects.tsx +21 -21
- package/src/views/ResetPassword.tsx +28 -28
- package/src/views/SEO.tsx +144 -144
- package/src/views/ScriptTagEditor.tsx +24 -24
- package/src/views/ScriptTags.tsx +10 -10
- package/src/views/Settings.tsx +88 -80
- package/src/views/SetupWizard.tsx +28 -28
- package/src/views/Users.tsx +20 -20
- package/src/views/page-builder/AIBlockAssist.tsx +1 -1
- package/src/views/page-builder/AIGenerateDialog.tsx +63 -63
- package/src/views/page-builder/BlockEditor.tsx +26 -26
- package/src/views/page-builder/BlockPicker.tsx +22 -22
- package/src/views/page-builder/BottomBar.tsx +8 -8
- package/src/views/page-builder/BuilderToolbar.tsx +17 -17
- package/src/views/page-builder/ContextPanel.tsx +3 -3
- package/src/views/page-builder/DesignScore.tsx +21 -21
- package/src/views/page-builder/NodeSettings.tsx +27 -27
- package/src/views/page-builder/PageBuilder.tsx +11 -11
- package/src/views/page-builder/PageSettings.tsx +4 -4
- package/src/views/page-builder/PageTemplates.tsx +18 -18
- package/src/views/page-builder/SEOPanel.tsx +53 -53
- package/src/views/page-builder/SavedSections.tsx +37 -37
- package/src/views/page-builder/TemplatePicker.tsx +17 -17
- package/src/views/page-builder/block-renderers/CTAPreview.tsx +13 -13
- package/src/views/page-builder/block-renderers/CardsPreview.tsx +5 -5
- package/src/views/page-builder/block-renderers/CodePreview.tsx +6 -6
- package/src/views/page-builder/block-renderers/FAQPreview.tsx +13 -13
- package/src/views/page-builder/block-renderers/FallbackPreview.tsx +3 -3
- package/src/views/page-builder/block-renderers/FormPreview.tsx +20 -20
- package/src/views/page-builder/block-renderers/GalleryPreview.tsx +8 -8
- package/src/views/page-builder/block-renderers/HeroPreview.tsx +16 -16
- package/src/views/page-builder/block-renderers/ImagePreview.tsx +4 -4
- package/src/views/page-builder/block-renderers/TextPreview.tsx +14 -14
- package/src/views/page-builder/block-renderers/VideoPreview.tsx +12 -12
- package/src/views/page-builder/canvas/BlockRenderer.tsx +4 -4
- package/src/views/page-builder/canvas/BuilderCanvas.tsx +6 -6
- package/src/views/page-builder/canvas/ColumnRenderer.tsx +3 -3
- package/src/views/page-builder/canvas/ContainerRenderer.tsx +2 -2
- package/src/views/page-builder/canvas/RowRenderer.tsx +2 -2
- package/src/views/page-builder/canvas/SectionRenderer.tsx +2 -2
|
@@ -210,23 +210,23 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
210
210
|
return (
|
|
211
211
|
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
|
212
212
|
<div className="absolute inset-0 bg-black/50" onClick={handleClose} />
|
|
213
|
-
<div className="
|
|
213
|
+
<div className="bg-card border-border relative flex max-h-[85vh] w-full max-w-2xl flex-col overflow-hidden rounded-xl border shadow-2xl">
|
|
214
214
|
{/* Header */}
|
|
215
|
-
<div className="flex items-center justify-between px-6 py-4
|
|
215
|
+
<div className="border-border flex items-center justify-between border-b px-6 py-4">
|
|
216
216
|
<div className="flex items-center gap-2.5">
|
|
217
|
-
<div className="
|
|
217
|
+
<div className="bg-primary/10 rounded-lg p-1.5">
|
|
218
218
|
<Sparkles size={18} className="text-primary" />
|
|
219
219
|
</div>
|
|
220
220
|
<div>
|
|
221
|
-
<h2 className="text-base font-medium
|
|
222
|
-
<p className="text-
|
|
221
|
+
<h2 className="text-foreground text-base font-medium">AI Page Generator</h2>
|
|
222
|
+
<p className="text-muted-foreground text-xs">
|
|
223
223
|
Describe your page and let AI build it
|
|
224
224
|
</p>
|
|
225
225
|
</div>
|
|
226
226
|
</div>
|
|
227
227
|
<button
|
|
228
228
|
onClick={handleClose}
|
|
229
|
-
className="
|
|
229
|
+
className="hover:bg-muted rounded-md p-1.5 transition-colors"
|
|
230
230
|
aria-label="Close"
|
|
231
231
|
>
|
|
232
232
|
<X size={16} className="text-muted-foreground" />
|
|
@@ -238,15 +238,15 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
238
238
|
{phase === 'prompt' && (
|
|
239
239
|
<div className="space-y-5">
|
|
240
240
|
{error && (
|
|
241
|
-
<div className="flex items-start gap-2.5
|
|
242
|
-
<AlertTriangle size={16} className="text-destructive
|
|
243
|
-
<p className="text-
|
|
241
|
+
<div className="bg-destructive/5 border-destructive/20 flex items-start gap-2.5 rounded-lg border p-3">
|
|
242
|
+
<AlertTriangle size={16} className="text-destructive mt-0.5 shrink-0" />
|
|
243
|
+
<p className="text-destructive text-sm">{error}</p>
|
|
244
244
|
</div>
|
|
245
245
|
)}
|
|
246
246
|
|
|
247
247
|
{/* Prompt */}
|
|
248
248
|
<div>
|
|
249
|
-
<label className="block text-sm font-medium
|
|
249
|
+
<label className="text-foreground mb-1.5 block text-sm font-medium">
|
|
250
250
|
Describe your page
|
|
251
251
|
</label>
|
|
252
252
|
<textarea
|
|
@@ -254,20 +254,20 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
254
254
|
onChange={(e) => setPrompt(e.target.value)}
|
|
255
255
|
placeholder="e.g. A landing page for a plumbing company with a hero section, service cards, testimonials, and a contact form"
|
|
256
256
|
rows={4}
|
|
257
|
-
className="
|
|
257
|
+
className="bg-background border-border focus:ring-primary/40 text-foreground placeholder:text-muted-foreground w-full resize-none rounded-lg border px-3 py-2.5 text-sm focus:ring-2 focus:outline-none"
|
|
258
258
|
autoFocus
|
|
259
259
|
/>
|
|
260
260
|
</div>
|
|
261
261
|
|
|
262
262
|
{/* Tone */}
|
|
263
263
|
<div>
|
|
264
|
-
<label className="block text-sm font-medium
|
|
264
|
+
<label className="text-foreground mb-1.5 block text-sm font-medium">Tone</label>
|
|
265
265
|
<div className="flex flex-wrap gap-2">
|
|
266
266
|
{TONES.map((t) => (
|
|
267
267
|
<button
|
|
268
268
|
key={t.value}
|
|
269
269
|
onClick={() => setTone(t.value)}
|
|
270
|
-
className={`px-3 py-1.5 text-xs
|
|
270
|
+
className={`rounded-full border px-3 py-1.5 text-xs transition-colors ${
|
|
271
271
|
tone === t.value
|
|
272
272
|
? 'border-primary bg-primary/10 text-primary'
|
|
273
273
|
: 'border-border bg-background text-muted-foreground hover:border-primary/40'
|
|
@@ -281,18 +281,18 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
281
281
|
|
|
282
282
|
{/* Steps */}
|
|
283
283
|
<div>
|
|
284
|
-
<label className="block text-sm font-medium
|
|
284
|
+
<label className="text-foreground mb-1.5 block text-sm font-medium">
|
|
285
285
|
Generation steps
|
|
286
286
|
</label>
|
|
287
287
|
<div className="space-y-1.5">
|
|
288
288
|
{ALL_STEPS.map((step) => (
|
|
289
289
|
<label
|
|
290
290
|
key={step.key}
|
|
291
|
-
className={`flex items-center gap-3 p-2.5
|
|
291
|
+
className={`flex cursor-pointer items-center gap-3 rounded-lg border p-2.5 transition-colors ${
|
|
292
292
|
enabledSteps.has(step.key)
|
|
293
293
|
? 'border-primary/30 bg-primary/5'
|
|
294
294
|
: 'border-border bg-background'
|
|
295
|
-
} ${step.key === 'structure' ? '
|
|
295
|
+
} ${step.key === 'structure' ? 'cursor-not-allowed opacity-70' : 'hover:border-primary/20'}`}
|
|
296
296
|
>
|
|
297
297
|
<input
|
|
298
298
|
type="checkbox"
|
|
@@ -302,19 +302,19 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
302
302
|
className="sr-only"
|
|
303
303
|
/>
|
|
304
304
|
<div
|
|
305
|
-
className={`
|
|
305
|
+
className={`flex h-5 w-5 shrink-0 items-center justify-center rounded ${
|
|
306
306
|
enabledSteps.has(step.key)
|
|
307
307
|
? 'bg-primary text-white'
|
|
308
|
-
: 'bg-muted border border
|
|
308
|
+
: 'bg-muted border-border border'
|
|
309
309
|
}`}
|
|
310
310
|
>
|
|
311
311
|
{enabledSteps.has(step.key) && <Check size={12} />}
|
|
312
312
|
</div>
|
|
313
|
-
<div className="flex
|
|
313
|
+
<div className="flex min-w-0 flex-1 items-center gap-2">
|
|
314
314
|
<span className="text-muted-foreground">{step.icon}</span>
|
|
315
315
|
<div>
|
|
316
|
-
<span className="text-
|
|
317
|
-
<span className="text-
|
|
316
|
+
<span className="text-foreground text-sm">{step.label}</span>
|
|
317
|
+
<span className="text-muted-foreground ml-2 text-xs">
|
|
318
318
|
{step.description}
|
|
319
319
|
</span>
|
|
320
320
|
</div>
|
|
@@ -328,55 +328,55 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
328
328
|
<div>
|
|
329
329
|
<button
|
|
330
330
|
onClick={() => setShowContext(!showContext)}
|
|
331
|
-
className="flex items-center gap-1.5 text-sm
|
|
331
|
+
className="text-muted-foreground hover:text-foreground flex items-center gap-1.5 text-sm transition-colors"
|
|
332
332
|
>
|
|
333
333
|
{showContext ? <ChevronUp size={14} /> : <ChevronDown size={14} />}
|
|
334
334
|
Business context (optional)
|
|
335
335
|
</button>
|
|
336
336
|
{showContext && (
|
|
337
|
-
<div className="mt-3 space-y-3
|
|
337
|
+
<div className="bg-muted/50 border-border mt-3 space-y-3 rounded-lg border p-4">
|
|
338
338
|
<div className="grid grid-cols-2 gap-3">
|
|
339
339
|
<div>
|
|
340
|
-
<label className="
|
|
340
|
+
<label className="text-muted-foreground mb-1 block text-xs">
|
|
341
341
|
Business name
|
|
342
342
|
</label>
|
|
343
343
|
<input
|
|
344
344
|
type="text"
|
|
345
345
|
value={businessName}
|
|
346
346
|
onChange={(e) => setBusiness(e.target.value)}
|
|
347
|
-
className="w-full px-2.5 py-1.5 text-sm
|
|
347
|
+
className="bg-background border-border focus:ring-primary/40 text-foreground w-full rounded-md border px-2.5 py-1.5 text-sm focus:ring-2 focus:outline-none"
|
|
348
348
|
/>
|
|
349
349
|
</div>
|
|
350
350
|
<div>
|
|
351
|
-
<label className="
|
|
351
|
+
<label className="text-muted-foreground mb-1 block text-xs">Industry</label>
|
|
352
352
|
<input
|
|
353
353
|
type="text"
|
|
354
354
|
value={industry}
|
|
355
355
|
onChange={(e) => setIndustry(e.target.value)}
|
|
356
|
-
className="w-full px-2.5 py-1.5 text-sm
|
|
356
|
+
className="bg-background border-border focus:ring-primary/40 text-foreground w-full rounded-md border px-2.5 py-1.5 text-sm focus:ring-2 focus:outline-none"
|
|
357
357
|
/>
|
|
358
358
|
</div>
|
|
359
359
|
<div>
|
|
360
|
-
<label className="
|
|
360
|
+
<label className="text-muted-foreground mb-1 block text-xs">Phone</label>
|
|
361
361
|
<input
|
|
362
362
|
type="text"
|
|
363
363
|
value={phone}
|
|
364
364
|
onChange={(e) => setPhone(e.target.value)}
|
|
365
|
-
className="w-full px-2.5 py-1.5 text-sm
|
|
365
|
+
className="bg-background border-border focus:ring-primary/40 text-foreground w-full rounded-md border px-2.5 py-1.5 text-sm focus:ring-2 focus:outline-none"
|
|
366
366
|
/>
|
|
367
367
|
</div>
|
|
368
368
|
<div>
|
|
369
|
-
<label className="
|
|
369
|
+
<label className="text-muted-foreground mb-1 block text-xs">Address</label>
|
|
370
370
|
<input
|
|
371
371
|
type="text"
|
|
372
372
|
value={address}
|
|
373
373
|
onChange={(e) => setAddress(e.target.value)}
|
|
374
|
-
className="w-full px-2.5 py-1.5 text-sm
|
|
374
|
+
className="bg-background border-border focus:ring-primary/40 text-foreground w-full rounded-md border px-2.5 py-1.5 text-sm focus:ring-2 focus:outline-none"
|
|
375
375
|
/>
|
|
376
376
|
</div>
|
|
377
377
|
</div>
|
|
378
378
|
<div>
|
|
379
|
-
<label className="
|
|
379
|
+
<label className="text-muted-foreground mb-1 block text-xs">
|
|
380
380
|
Services (comma-separated)
|
|
381
381
|
</label>
|
|
382
382
|
<input
|
|
@@ -384,7 +384,7 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
384
384
|
value={services}
|
|
385
385
|
onChange={(e) => setServices(e.target.value)}
|
|
386
386
|
placeholder="e.g. Web design, SEO, Content marketing"
|
|
387
|
-
className="w-full px-2.5 py-1.5 text-sm
|
|
387
|
+
className="bg-background border-border focus:ring-primary/40 text-foreground placeholder:text-muted-foreground w-full rounded-md border px-2.5 py-1.5 text-sm focus:ring-2 focus:outline-none"
|
|
388
388
|
/>
|
|
389
389
|
</div>
|
|
390
390
|
</div>
|
|
@@ -394,13 +394,13 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
394
394
|
)}
|
|
395
395
|
|
|
396
396
|
{phase === 'generating' && (
|
|
397
|
-
<div className="
|
|
397
|
+
<div className="space-y-6 py-8">
|
|
398
398
|
<div className="text-center">
|
|
399
|
-
<Loader2 size={32} className="
|
|
400
|
-
<p className="text-sm font-medium
|
|
399
|
+
<Loader2 size={32} className="text-primary mx-auto mb-3 animate-spin" />
|
|
400
|
+
<p className="text-foreground text-sm font-medium">
|
|
401
401
|
{stepMessage || 'Generating...'}
|
|
402
402
|
</p>
|
|
403
|
-
<p className="text-
|
|
403
|
+
<p className="text-muted-foreground mt-1 text-xs">This may take 15-30 seconds</p>
|
|
404
404
|
</div>
|
|
405
405
|
|
|
406
406
|
<div className="space-y-2">
|
|
@@ -411,7 +411,7 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
411
411
|
return (
|
|
412
412
|
<div
|
|
413
413
|
key={step.key}
|
|
414
|
-
className={`flex items-center gap-3
|
|
414
|
+
className={`flex items-center gap-3 rounded-lg border p-3 transition-colors ${
|
|
415
415
|
isComplete
|
|
416
416
|
? 'border-primary/30 bg-primary/5'
|
|
417
417
|
: isCurrent
|
|
@@ -419,15 +419,15 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
419
419
|
: 'border-border bg-muted/30'
|
|
420
420
|
}`}
|
|
421
421
|
>
|
|
422
|
-
<div className="
|
|
422
|
+
<div className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full">
|
|
423
423
|
{isComplete ? (
|
|
424
|
-
<div className="
|
|
424
|
+
<div className="bg-primary flex h-6 w-6 items-center justify-center rounded-full">
|
|
425
425
|
<Check size={12} className="text-white" />
|
|
426
426
|
</div>
|
|
427
427
|
) : isCurrent ? (
|
|
428
|
-
<Loader2 size={16} className="animate-spin
|
|
428
|
+
<Loader2 size={16} className="text-primary animate-spin" />
|
|
429
429
|
) : (
|
|
430
|
-
<div className="
|
|
430
|
+
<div className="bg-muted border-border h-6 w-6 rounded-full border" />
|
|
431
431
|
)}
|
|
432
432
|
</div>
|
|
433
433
|
<div className="flex items-center gap-2">
|
|
@@ -448,13 +448,13 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
448
448
|
{phase === 'review' && result && (
|
|
449
449
|
<div className="space-y-5">
|
|
450
450
|
{/* Summary */}
|
|
451
|
-
<div className="flex items-center gap-3
|
|
452
|
-
<div className="
|
|
451
|
+
<div className="bg-primary/5 border-primary/20 flex items-center gap-3 rounded-lg border p-4">
|
|
452
|
+
<div className="bg-primary/10 flex h-10 w-10 shrink-0 items-center justify-center rounded-full">
|
|
453
453
|
<Sparkles size={18} className="text-primary" />
|
|
454
454
|
</div>
|
|
455
455
|
<div>
|
|
456
|
-
<p className="text-sm font-medium
|
|
457
|
-
<p className="text-
|
|
456
|
+
<p className="text-foreground text-sm font-medium">Page generated successfully</p>
|
|
457
|
+
<p className="text-muted-foreground mt-0.5 text-xs">
|
|
458
458
|
{result.totalTokensUsed.toLocaleString()} tokens
|
|
459
459
|
{' \u00B7 '}
|
|
460
460
|
{(result.totalDurationMs / 1000).toFixed(1)}s{' \u00B7 '}
|
|
@@ -465,7 +465,7 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
465
465
|
|
|
466
466
|
{/* Step details */}
|
|
467
467
|
<div className="space-y-2">
|
|
468
|
-
<h3 className="text-sm font-medium
|
|
468
|
+
<h3 className="text-foreground text-sm font-medium">Generation steps</h3>
|
|
469
469
|
{result.steps.map((step) => {
|
|
470
470
|
const info = ALL_STEPS.find((s) => s.key === step.step)
|
|
471
471
|
const isExpanded = expandedStep === step.step
|
|
@@ -473,18 +473,18 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
473
473
|
return (
|
|
474
474
|
<div
|
|
475
475
|
key={step.step}
|
|
476
|
-
className="
|
|
476
|
+
className="border-border overflow-hidden rounded-lg border"
|
|
477
477
|
>
|
|
478
478
|
<button
|
|
479
479
|
onClick={() => setExpandedStep(isExpanded ? null : step.step)}
|
|
480
|
-
className="w-full
|
|
480
|
+
className="hover:bg-muted/50 flex w-full items-center gap-3 p-3 text-left transition-colors"
|
|
481
481
|
>
|
|
482
|
-
<div className="
|
|
482
|
+
<div className="bg-primary flex h-6 w-6 shrink-0 items-center justify-center rounded-full">
|
|
483
483
|
<Check size={12} className="text-white" />
|
|
484
484
|
</div>
|
|
485
485
|
<span className="text-muted-foreground">{info?.icon}</span>
|
|
486
|
-
<span className="text-
|
|
487
|
-
<span className="text-
|
|
486
|
+
<span className="text-foreground flex-1 text-sm">{info?.label}</span>
|
|
487
|
+
<span className="text-muted-foreground text-xs">
|
|
488
488
|
{(step.metadata.durationMs / 1000).toFixed(1)}s
|
|
489
489
|
</span>
|
|
490
490
|
{isExpanded ? (
|
|
@@ -494,19 +494,19 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
494
494
|
)}
|
|
495
495
|
</button>
|
|
496
496
|
{isExpanded && (
|
|
497
|
-
<div className="
|
|
497
|
+
<div className="border-border border-t px-3 pt-2 pb-3">
|
|
498
498
|
<ul className="space-y-1">
|
|
499
499
|
{step.metadata.changes.map((change, i) => (
|
|
500
500
|
<li
|
|
501
501
|
key={i}
|
|
502
|
-
className="flex items-start gap-2 text-xs
|
|
502
|
+
className="text-muted-foreground flex items-start gap-2 text-xs"
|
|
503
503
|
>
|
|
504
|
-
<ArrowRight size={10} className="
|
|
504
|
+
<ArrowRight size={10} className="mt-0.5 shrink-0" />
|
|
505
505
|
{change}
|
|
506
506
|
</li>
|
|
507
507
|
))}
|
|
508
508
|
</ul>
|
|
509
|
-
<p className="text-
|
|
509
|
+
<p className="text-muted-foreground mt-2 text-xs">
|
|
510
510
|
Tokens: {step.metadata.tokensUsed.toLocaleString()}
|
|
511
511
|
</p>
|
|
512
512
|
</div>
|
|
@@ -516,7 +516,7 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
516
516
|
})}
|
|
517
517
|
</div>
|
|
518
518
|
|
|
519
|
-
<p className="text-
|
|
519
|
+
<p className="text-muted-foreground text-xs">
|
|
520
520
|
Review the generated page in the canvas after accepting. You can always undo to
|
|
521
521
|
revert.
|
|
522
522
|
</p>
|
|
@@ -525,19 +525,19 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
525
525
|
</div>
|
|
526
526
|
|
|
527
527
|
{/* Footer */}
|
|
528
|
-
<div className="
|
|
528
|
+
<div className="border-border flex items-center justify-end gap-3 border-t px-6 py-4">
|
|
529
529
|
{phase === 'prompt' && (
|
|
530
530
|
<>
|
|
531
531
|
<button
|
|
532
532
|
onClick={handleClose}
|
|
533
|
-
className="px-4 py-2 text-sm
|
|
533
|
+
className="text-muted-foreground hover:text-foreground px-4 py-2 text-sm transition-colors"
|
|
534
534
|
>
|
|
535
535
|
Cancel
|
|
536
536
|
</button>
|
|
537
537
|
<button
|
|
538
538
|
onClick={handleGenerate}
|
|
539
539
|
disabled={!prompt.trim()}
|
|
540
|
-
className="flex items-center gap-2 px-4 py-2 text-sm font-medium text-white
|
|
540
|
+
className="bg-primary hover:bg-primary/90 flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium text-white transition-colors disabled:cursor-not-allowed disabled:opacity-50"
|
|
541
541
|
>
|
|
542
542
|
<Sparkles size={14} />
|
|
543
543
|
Generate Page
|
|
@@ -548,7 +548,7 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
548
548
|
{phase === 'generating' && (
|
|
549
549
|
<button
|
|
550
550
|
onClick={handleClose}
|
|
551
|
-
className="px-4 py-2 text-sm
|
|
551
|
+
className="text-muted-foreground hover:text-foreground px-4 py-2 text-sm transition-colors"
|
|
552
552
|
>
|
|
553
553
|
Cancel
|
|
554
554
|
</button>
|
|
@@ -561,13 +561,13 @@ export function AIGenerateDialog({ open, onClose, onAccept }: AIGenerateDialogPr
|
|
|
561
561
|
setPhase('prompt')
|
|
562
562
|
setResult(null)
|
|
563
563
|
}}
|
|
564
|
-
className="px-4 py-2 text-sm
|
|
564
|
+
className="text-muted-foreground hover:text-foreground px-4 py-2 text-sm transition-colors"
|
|
565
565
|
>
|
|
566
566
|
Regenerate
|
|
567
567
|
</button>
|
|
568
568
|
<button
|
|
569
569
|
onClick={handleAccept}
|
|
570
|
-
className="flex items-center gap-2 px-4 py-2 text-sm font-medium text-white
|
|
570
|
+
className="bg-primary hover:bg-primary/90 flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium text-white transition-colors"
|
|
571
571
|
>
|
|
572
572
|
<Check size={14} />
|
|
573
573
|
Accept & Apply
|
|
@@ -64,7 +64,7 @@ export function BlockEditor({
|
|
|
64
64
|
if (!blockDef) {
|
|
65
65
|
return (
|
|
66
66
|
<div className="p-4">
|
|
67
|
-
<p className="text-
|
|
67
|
+
<p className="text-muted-foreground text-sm">
|
|
68
68
|
Unknown block type: <code className="text-xs">{node.settings.blockType}</code>
|
|
69
69
|
</p>
|
|
70
70
|
</div>
|
|
@@ -72,21 +72,21 @@ export function BlockEditor({
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
return (
|
|
75
|
-
<div className="flex flex-col
|
|
76
|
-
<div className="
|
|
75
|
+
<div className="flex h-full flex-col">
|
|
76
|
+
<div className="border-border border-b p-4">
|
|
77
77
|
<div className="flex items-center gap-2">
|
|
78
78
|
<Star size={16} className="text-muted-foreground" />
|
|
79
|
-
<span className="text-
|
|
79
|
+
<span className="text-foreground flex-1 text-sm font-medium">{blockDef.label}</span>
|
|
80
80
|
<AIBlockAssist block={node} onUpdateData={(data) => onUpdateBlock(node.id, data)} />
|
|
81
81
|
</div>
|
|
82
82
|
{blockDef.description && (
|
|
83
|
-
<p className="text-
|
|
83
|
+
<p className="text-muted-foreground mt-1 text-xs">{blockDef.description}</p>
|
|
84
84
|
)}
|
|
85
85
|
</div>
|
|
86
86
|
|
|
87
87
|
{blockDef.variants.length > 1 && (
|
|
88
|
-
<div className="
|
|
89
|
-
<p className="text-xs font-medium
|
|
88
|
+
<div className="border-border border-b p-4">
|
|
89
|
+
<p className="text-muted-foreground mb-2 text-xs font-medium tracking-wider uppercase">
|
|
90
90
|
Variant
|
|
91
91
|
</p>
|
|
92
92
|
<div className="grid grid-cols-2 gap-1.5">
|
|
@@ -95,7 +95,7 @@ export function BlockEditor({
|
|
|
95
95
|
key={variant.name}
|
|
96
96
|
type="button"
|
|
97
97
|
onClick={() => handleVariantChange(variant.name)}
|
|
98
|
-
className={`px-2 py-1.5 text-xs
|
|
98
|
+
className={`rounded-md border px-2 py-1.5 text-xs transition-colors ${
|
|
99
99
|
node.settings.variant === variant.name
|
|
100
100
|
? 'bg-primary text-primary-foreground border-primary'
|
|
101
101
|
: 'bg-background border-input text-foreground hover:bg-accent'
|
|
@@ -108,8 +108,8 @@ export function BlockEditor({
|
|
|
108
108
|
</div>
|
|
109
109
|
)}
|
|
110
110
|
|
|
111
|
-
<div className="space-y-4 p-4
|
|
112
|
-
<p className="text-xs font-medium
|
|
111
|
+
<div className="flex-1 space-y-4 p-4">
|
|
112
|
+
<p className="text-muted-foreground mb-2 text-xs font-medium tracking-wider uppercase">
|
|
113
113
|
Fields
|
|
114
114
|
</p>
|
|
115
115
|
{Object.entries(blockDef.fields).map(([fieldName, fieldDef]) => (
|
|
@@ -123,11 +123,11 @@ export function BlockEditor({
|
|
|
123
123
|
))}
|
|
124
124
|
</div>
|
|
125
125
|
|
|
126
|
-
<div className="
|
|
126
|
+
<div className="border-border space-y-2 border-t p-4">
|
|
127
127
|
<button
|
|
128
128
|
type="button"
|
|
129
129
|
onClick={() => onDuplicateNode(node.id)}
|
|
130
|
-
className="w-full
|
|
130
|
+
className="bg-background border-input hover:bg-accent flex w-full items-center justify-center gap-2 rounded-md border px-3 py-2 text-sm font-medium transition-colors"
|
|
131
131
|
>
|
|
132
132
|
<Copy size={14} />
|
|
133
133
|
Duplicate
|
|
@@ -136,10 +136,10 @@ export function BlockEditor({
|
|
|
136
136
|
type="button"
|
|
137
137
|
onClick={handleDelete}
|
|
138
138
|
onBlur={() => setConfirmDelete(false)}
|
|
139
|
-
className={`w-full
|
|
139
|
+
className={`flex w-full items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors ${
|
|
140
140
|
confirmDelete
|
|
141
141
|
? 'bg-destructive text-destructive-foreground'
|
|
142
|
-
: 'bg-background border
|
|
142
|
+
: 'bg-background border-destructive text-destructive hover:bg-destructive/10 border'
|
|
143
143
|
}`}
|
|
144
144
|
>
|
|
145
145
|
<Trash2 size={14} />
|
|
@@ -179,7 +179,7 @@ function FieldRenderer({ name, definition, value, onChange }: FieldRendererProps
|
|
|
179
179
|
return (
|
|
180
180
|
<div>
|
|
181
181
|
<label className={LABEL_CLASS}>{label}</label>
|
|
182
|
-
<div className="
|
|
182
|
+
<div className="border-input bg-background overflow-hidden rounded-md border">
|
|
183
183
|
<TipTapEditor
|
|
184
184
|
content={(value as string) ?? ''}
|
|
185
185
|
onChange={(html) => onChange(html)}
|
|
@@ -222,14 +222,14 @@ function FieldRenderer({ name, definition, value, onChange }: FieldRendererProps
|
|
|
222
222
|
case 'boolean':
|
|
223
223
|
return (
|
|
224
224
|
<div className="flex items-center justify-between">
|
|
225
|
-
<label className="text-sm font-medium
|
|
225
|
+
<label className="text-foreground text-sm font-medium">{label}</label>
|
|
226
226
|
<SwitchPrimitive.Root
|
|
227
227
|
checked={!!value}
|
|
228
228
|
onCheckedChange={(checked) => onChange(checked)}
|
|
229
|
-
className="
|
|
229
|
+
className="bg-input data-[state=checked]:bg-primary relative h-5 w-9 rounded-full transition-colors"
|
|
230
230
|
aria-label={label}
|
|
231
231
|
>
|
|
232
|
-
<SwitchPrimitive.Thumb className="block h-3.5 w-3.5 rounded-full
|
|
232
|
+
<SwitchPrimitive.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-[18px]" />
|
|
233
233
|
</SwitchPrimitive.Root>
|
|
234
234
|
</div>
|
|
235
235
|
)
|
|
@@ -332,7 +332,7 @@ function FieldRenderer({ name, definition, value, onChange }: FieldRendererProps
|
|
|
332
332
|
type="color"
|
|
333
333
|
value={(value as string) ?? '#000000'}
|
|
334
334
|
onChange={(e) => onChange(e.target.value)}
|
|
335
|
-
className="h-9 w-9 rounded-md border
|
|
335
|
+
className="border-input h-9 w-9 cursor-pointer rounded-md border"
|
|
336
336
|
/>
|
|
337
337
|
<input
|
|
338
338
|
type="text"
|
|
@@ -394,15 +394,15 @@ function MediaFieldRenderer({ label, value, onChange }: SimpleFieldProps) {
|
|
|
394
394
|
<button
|
|
395
395
|
type="button"
|
|
396
396
|
onClick={() => setOpen(true)}
|
|
397
|
-
className="
|
|
397
|
+
className="bg-accent text-foreground border-input hover:bg-accent/80 rounded-md border px-3 py-2 text-xs font-medium transition-colors"
|
|
398
398
|
>
|
|
399
399
|
Browse
|
|
400
400
|
</button>
|
|
401
401
|
</div>
|
|
402
402
|
{url && /\.(png|jpe?g|gif|webp|avif|svg)(\?|$)/i.test(url) && (
|
|
403
|
-
<div className="
|
|
403
|
+
<div className="border-border bg-muted mt-2 overflow-hidden rounded-md border">
|
|
404
404
|
{/* Plain img is fine here; admin only and we don't have next/image in scope. */}
|
|
405
|
-
<img src={url} alt="" className="
|
|
405
|
+
<img src={url} alt="" className="bg-checkered h-32 w-full object-contain" />
|
|
406
406
|
</div>
|
|
407
407
|
)}
|
|
408
408
|
<MediaPickerModal
|
|
@@ -460,10 +460,10 @@ function JsonFieldRenderer({ label, value, onChange }: SimpleFieldProps) {
|
|
|
460
460
|
onChange={(e) => handleChange(e.target.value)}
|
|
461
461
|
rows={6}
|
|
462
462
|
spellCheck={false}
|
|
463
|
-
className={`${INPUT_CLASS} font-mono text-xs
|
|
463
|
+
className={`${INPUT_CLASS} resize-y font-mono text-xs`}
|
|
464
464
|
/>
|
|
465
465
|
{error && (
|
|
466
|
-
<p className="mt-1 text-xs
|
|
466
|
+
<p className="text-destructive mt-1 text-xs" role="alert">
|
|
467
467
|
{error}
|
|
468
468
|
</p>
|
|
469
469
|
)}
|
|
@@ -510,7 +510,7 @@ function ArrayFieldRenderer({ label, value, onChange }: SimpleFieldProps) {
|
|
|
510
510
|
type="button"
|
|
511
511
|
onClick={() => removeItem(idx)}
|
|
512
512
|
aria-label={`Remove item ${idx + 1}`}
|
|
513
|
-
className="
|
|
513
|
+
className="text-destructive border-input hover:bg-destructive/10 rounded-md border px-2 py-2 text-xs transition-colors"
|
|
514
514
|
>
|
|
515
515
|
<Trash2 size={14} />
|
|
516
516
|
</button>
|
|
@@ -519,7 +519,7 @@ function ArrayFieldRenderer({ label, value, onChange }: SimpleFieldProps) {
|
|
|
519
519
|
<button
|
|
520
520
|
type="button"
|
|
521
521
|
onClick={addItem}
|
|
522
|
-
className="
|
|
522
|
+
className="bg-accent text-foreground border-input hover:bg-accent/80 w-full rounded-md border px-3 py-2 text-xs font-medium transition-colors"
|
|
523
523
|
>
|
|
524
524
|
+ Add item
|
|
525
525
|
</button>
|