@kyro-cms/admin 0.8.0 → 0.9.1
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/index.cjs +11960 -11006
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +67 -65
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +563 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.js +12183 -11238
- package/dist/index.js.map +1 -1
- package/package.json +15 -11
- package/src/components/ActionBar.tsx +27 -14
- package/src/components/Admin.tsx +1 -1
- package/src/components/ApiKeysManager.tsx +5 -5
- package/src/components/AutoForm.tsx +585 -369
- package/src/components/BrandingHub.tsx +7 -4
- package/src/components/CreateView.tsx +2 -0
- package/src/components/DetailView.tsx +71 -56
- package/src/components/DeveloperCenter.tsx +8 -6
- package/src/components/FieldRenderer.tsx +94 -19
- package/src/components/ListView.tsx +33 -20
- package/src/components/MediaGallery.tsx +219 -194
- package/src/components/PluginsManager.tsx +197 -70
- package/src/components/RestPlayground.tsx +7 -7
- package/src/components/SessionsManager.tsx +1 -1
- package/src/components/SettingsPage.tsx +22 -0
- package/src/components/Sidebar.astro +13 -41
- package/src/components/UserManagement.tsx +153 -15
- package/src/components/UserMenu.tsx +30 -4
- package/src/components/VersionHistoryPanel.tsx +112 -119
- package/src/components/WebhookManager.tsx +6 -4
- package/src/components/blocks/ArrayBlock.tsx +6 -23
- package/src/components/blocks/BlockEditModal.tsx +82 -309
- package/src/components/blocks/CardBlock.tsx +35 -0
- package/src/components/blocks/ChildBlocksTree.tsx +57 -31
- package/src/components/blocks/GenericBlock.tsx +44 -0
- package/src/components/blocks/HeadingSubheadingBlock.tsx +32 -0
- package/src/components/blocks/HeroBlock.tsx +5 -14
- package/src/components/blocks/RichTextBlock.tsx +5 -5
- package/src/components/blocks/index.ts +5 -3
- package/src/components/fields/AccordionField.tsx +2 -2
- package/src/components/fields/ArrayField.tsx +1 -1
- package/src/components/fields/ArrayLayout.tsx +120 -29
- package/src/components/fields/BlocksField.tsx +430 -50
- package/src/components/fields/CardField.tsx +73 -0
- package/src/components/fields/CheckboxField.tsx +7 -3
- package/src/components/fields/DateField.tsx +4 -1
- package/src/components/fields/GroupLayout.tsx +2 -2
- package/src/components/fields/HeadingSubheadingField.tsx +43 -0
- package/src/components/fields/ListField.tsx +2 -2
- package/src/components/fields/NumberField.tsx +4 -1
- package/src/components/fields/RelationshipField.tsx +153 -87
- package/src/components/fields/RichTextField.tsx +781 -0
- package/src/components/fields/SecretField.tsx +102 -0
- package/src/components/fields/SelectField.tsx +19 -6
- package/src/components/fields/TabsLayout.tsx +19 -9
- package/src/components/fields/TextField.tsx +4 -1
- package/src/components/fields/UploadField.tsx +122 -56
- package/src/components/fields/extensions/blockComponents.tsx +103 -174
- package/src/components/fields/extensions/blocksStore.ts +8 -1
- package/src/components/fields/index.ts +4 -2
- package/src/components/ui/PageHeader.tsx +5 -5
- package/src/components/ui/SlidePanel.tsx +8 -3
- package/src/components/ui/icons.tsx +109 -109
- package/src/components/users/UserDetail.tsx +79 -16
- package/src/hooks/useAutoFormState.ts +125 -62
- package/src/integration.ts +148 -46
- package/src/kyro-cms.d.ts +7 -2
- package/src/layouts/AuthLayout.astro +14 -2
- package/src/lib/autoform-store.ts +85 -52
- package/src/lib/change-source.ts +9 -0
- package/src/lib/config.ts +104 -8
- package/src/lib/globals.ts +44 -9
- package/src/lib/normalize-upload-fields.ts +41 -0
- package/src/lib/paths.ts +2 -2
- package/src/lib/resolve-field-value.ts +110 -0
- package/src/lib/shim/use-sync-external-store-with-selector.js +30 -0
- package/src/lib/shim/use-sync-external-store.js +1 -0
- package/src/lib/stores/index.ts +1 -0
- package/src/lib/useResourceManager.ts +4 -4
- package/src/lib/vite-shim-plugin.ts +100 -0
- package/src/pages/[collection]/[id].astro +1 -1
- package/src/pages/preview/[collection]/[id].astro +4 -4
- package/src/pages/settings/[slug].astro +2 -2
- package/src/styles/main.css +60 -54
- package/README.md +0 -46
- package/dist/EditorClient-Q23UXR37.cjs +0 -468
- package/dist/EditorClient-Q23UXR37.cjs.map +0 -1
- package/dist/EditorClient-T5PASFNR.js +0 -466
- package/dist/EditorClient-T5PASFNR.js.map +0 -1
- package/dist/chunk-3BGDYKTD.cjs +0 -348
- package/dist/chunk-3BGDYKTD.cjs.map +0 -1
- package/dist/chunk-EEFXLQVT.js +0 -3
- package/dist/chunk-EEFXLQVT.js.map +0 -1
- package/src/components/blocks/ButtonBlock.tsx +0 -64
- package/src/components/blocks/ColumnsBlock.tsx +0 -55
- package/src/components/blocks/DividerBlock.tsx +0 -43
- package/src/components/blocks/LinkBlock.tsx +0 -65
- package/src/components/blocks/VStackBlock.tsx +0 -29
- package/src/components/fields/EditorClient.tsx +0 -535
- package/src/components/fields/PortableTextField.tsx +0 -155
- package/src/components/fields/PortableTextRenderer.tsx +0 -68
|
@@ -1,247 +1,176 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { ColumnsBlock } from "../../blocks/ColumnsBlock";
|
|
3
2
|
import { HeadingBlock } from "../../blocks/HeadingBlock";
|
|
4
3
|
import { ParagraphBlock } from "../../blocks/ParagraphBlock";
|
|
5
|
-
import { DividerBlock } from "../../blocks/DividerBlock";
|
|
6
4
|
import { ImageBlock } from "../../blocks/ImageBlock";
|
|
7
5
|
import { VideoBlock } from "../../blocks/VideoBlock";
|
|
8
6
|
import { ListBlock } from "../../blocks/ListBlock";
|
|
9
7
|
import { CodeBlock } from "../../blocks/CodeBlock";
|
|
10
|
-
import { LinkBlock } from "../../blocks/LinkBlock";
|
|
11
8
|
import { FileBlock } from "../../blocks/FileBlock";
|
|
12
|
-
import { VStackBlock } from "../../blocks/VStackBlock";
|
|
13
|
-
import { ButtonBlock } from "../../blocks/ButtonBlock";
|
|
14
9
|
import { AccordionBlock } from "../../blocks/AccordionBlock";
|
|
15
10
|
import { RichTextBlock } from "../../blocks/RichTextBlock";
|
|
16
11
|
|
|
17
12
|
import { HeroBlock } from "../../blocks/HeroBlock";
|
|
13
|
+
import { HeadingSubheadingBlock } from "../../blocks/HeadingSubheadingBlock";
|
|
14
|
+
import { CardBlock } from "../../blocks/CardBlock";
|
|
18
15
|
import { ArrayBlock } from "../../blocks/ArrayBlock";
|
|
19
16
|
import { RelationshipBlock } from "../../blocks/RelationshipBlock";
|
|
20
17
|
|
|
21
18
|
import {
|
|
22
|
-
|
|
19
|
+
Box,
|
|
23
20
|
Heading1,
|
|
24
21
|
AlignLeft,
|
|
25
|
-
Minus,
|
|
26
22
|
Image,
|
|
27
23
|
Video,
|
|
28
24
|
List,
|
|
29
25
|
Code,
|
|
30
|
-
Link,
|
|
31
26
|
File,
|
|
32
|
-
ArrowDown,
|
|
33
|
-
MousePointerClick,
|
|
34
27
|
ChevronDown,
|
|
35
28
|
Star,
|
|
36
29
|
ListOrdered,
|
|
37
30
|
Link2,
|
|
31
|
+
Columns3,
|
|
32
|
+
Sparkles,
|
|
33
|
+
Users,
|
|
34
|
+
HelpCircle,
|
|
35
|
+
Activity,
|
|
36
|
+
Tag,
|
|
37
|
+
Database,
|
|
38
|
+
Mail,
|
|
39
|
+
Blocks,
|
|
40
|
+
Clock,
|
|
38
41
|
} from "../../ui/icons";
|
|
39
42
|
|
|
40
43
|
// Block component registry
|
|
41
44
|
export const BLOCK_COMPONENTS: Record<string, React.ComponentType<{ block: Record<string, unknown>; index: number }>> = {
|
|
42
|
-
columns: ColumnsBlock,
|
|
43
45
|
heading: HeadingBlock,
|
|
44
46
|
paragraph: ParagraphBlock,
|
|
45
|
-
divider: DividerBlock,
|
|
46
47
|
image: ImageBlock,
|
|
47
48
|
video: VideoBlock,
|
|
48
49
|
list: ListBlock,
|
|
49
50
|
code: CodeBlock,
|
|
50
|
-
link: LinkBlock,
|
|
51
51
|
file: FileBlock,
|
|
52
|
-
vstack: VStackBlock,
|
|
53
|
-
button: ButtonBlock,
|
|
54
52
|
accordion: AccordionBlock,
|
|
55
53
|
richtext: RichTextBlock,
|
|
56
54
|
|
|
57
55
|
hero: HeroBlock,
|
|
56
|
+
"heading-subheading": HeadingSubheadingBlock,
|
|
57
|
+
card: CardBlock,
|
|
58
58
|
array: ArrayBlock,
|
|
59
59
|
relationship: RelationshipBlock,
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
+
// Block Theme mapping for consistent coloring across UI
|
|
63
|
+
export const blockTheme: Record<string, { text: string; border: string; borderLeft: string }> = {
|
|
64
|
+
"feature-split": { text: "text-indigo-500", border: "border-indigo-500", borderLeft: "border-l-indigo-500" },
|
|
65
|
+
"feature-grid": { text: "text-blue-500", border: "border-blue-500", borderLeft: "border-l-blue-500" },
|
|
66
|
+
"cta-banner": { text: "text-amber-500", border: "border-amber-500", borderLeft: "border-l-amber-500" },
|
|
67
|
+
testimonials: { text: "text-emerald-500", border: "border-emerald-500", borderLeft: "border-l-emerald-500" },
|
|
68
|
+
faq: { text: "text-orange-500", border: "border-orange-500", borderLeft: "border-l-orange-500" },
|
|
69
|
+
stats: { text: "text-rose-500", border: "border-rose-500", borderLeft: "border-l-rose-500" },
|
|
70
|
+
"logo-cloud": { text: "text-cyan-500", border: "border-cyan-500", borderLeft: "border-l-cyan-500" },
|
|
71
|
+
pricing: { text: "text-green-500", border: "border-green-500", borderLeft: "border-l-green-500" },
|
|
72
|
+
team: { text: "text-violet-500", border: "border-violet-500", borderLeft: "border-l-violet-500" },
|
|
73
|
+
"recent-feed": { text: "text-sky-500", border: "border-sky-500", borderLeft: "border-l-sky-500" },
|
|
74
|
+
"process-steps": { text: "text-fuchsia-500", border: "border-fuchsia-500", borderLeft: "border-l-fuchsia-500" },
|
|
75
|
+
"form-embed": { text: "text-pink-500", border: "border-pink-500", borderLeft: "border-l-pink-500" },
|
|
76
|
+
"video-showcase": { text: "text-red-500", border: "border-red-500", borderLeft: "border-l-red-500" },
|
|
77
|
+
hero: { text: "text-yellow-500", border: "border-yellow-500", borderLeft: "border-l-yellow-500" },
|
|
78
|
+
card: { text: "text-teal-500", border: "border-teal-500", borderLeft: "border-l-teal-500" },
|
|
79
|
+
default: { text: "text-zinc-400", border: "border-zinc-400", borderLeft: "border-l-zinc-400" },
|
|
80
|
+
};
|
|
81
|
+
|
|
62
82
|
// Icon mapping for drawer (actual Lucide components)
|
|
63
83
|
export const blockIcons: Record<string, React.ReactNode> = {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
84
|
+
heading: <Heading1 className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
85
|
+
paragraph: <AlignLeft className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
86
|
+
image: <Image className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
87
|
+
video: <Video className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
88
|
+
list: <List className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
89
|
+
code: <Code className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
90
|
+
file: <File className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
91
|
+
accordion: <ChevronDown className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
92
|
+
richtext: <AlignLeft className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
93
|
+
|
|
94
|
+
hero: <Star className={`w-4 h-4 ${blockTheme.hero.text}`} />,
|
|
95
|
+
"heading-subheading": <Heading1 className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
96
|
+
card: <Box className={`w-4 h-4 ${blockTheme.card.text}`} />,
|
|
97
|
+
array: <ListOrdered className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
98
|
+
relationship: <Link2 className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
78
99
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
100
|
+
// New Block Icons
|
|
101
|
+
"feature-split": <Columns3 className={`w-4 h-4 ${blockTheme["feature-split"].text}`} />,
|
|
102
|
+
"feature-grid": <Blocks className={`w-4 h-4 ${blockTheme["feature-grid"].text}`} />,
|
|
103
|
+
"cta-banner": <Sparkles className={`w-4 h-4 ${blockTheme["cta-banner"].text}`} />,
|
|
104
|
+
testimonials: <Users className={`w-4 h-4 ${blockTheme.testimonials.text}`} />,
|
|
105
|
+
faq: <HelpCircle className={`w-4 h-4 ${blockTheme.faq.text}`} />,
|
|
106
|
+
stats: <Activity className={`w-4 h-4 ${blockTheme.stats.text}`} />,
|
|
107
|
+
"logo-cloud": <Image className={`w-4 h-4 ${blockTheme["logo-cloud"].text}`} />,
|
|
108
|
+
pricing: <Tag className={`w-4 h-4 ${blockTheme.pricing.text}`} />,
|
|
109
|
+
team: <Users className={`w-4 h-4 ${blockTheme.team.text}`} />,
|
|
110
|
+
"recent-feed": <Database className={`w-4 h-4 ${blockTheme["recent-feed"].text}`} />,
|
|
111
|
+
"process-steps": <Clock className={`w-4 h-4 ${blockTheme["process-steps"].text}`} />,
|
|
112
|
+
"form-embed": <Mail className={`w-4 h-4 ${blockTheme["form-embed"].text}`} />,
|
|
113
|
+
"video-showcase": <Video className={`w-4 h-4 ${blockTheme["video-showcase"].text}`} />,
|
|
82
114
|
};
|
|
83
115
|
|
|
84
|
-
//
|
|
116
|
+
// Internal utility to check if block has a specific custom react component
|
|
85
117
|
export function getBlockComponent(type: string) {
|
|
86
|
-
return BLOCK_COMPONENTS[type];
|
|
118
|
+
return BLOCK_COMPONENTS[type] || null;
|
|
87
119
|
}
|
|
88
120
|
|
|
89
|
-
//
|
|
90
|
-
export function
|
|
91
|
-
return
|
|
121
|
+
// Determines if block is a native layout requiring generic rendering
|
|
122
|
+
export function isGenericSemanticBlock(type: string) {
|
|
123
|
+
return [
|
|
124
|
+
"feature-split", "feature-grid", "cta-banner",
|
|
125
|
+
"testimonials", "faq", "stats", "logo-cloud",
|
|
126
|
+
"pricing", "team", "recent-feed", "process-steps", "form-embed", "video-showcase"
|
|
127
|
+
].includes(type);
|
|
92
128
|
}
|
|
93
129
|
|
|
94
130
|
// Get human-readable label for block type
|
|
95
131
|
export function getBlockLabel(type: string): string {
|
|
96
132
|
const labelMap: Record<string, string> = {
|
|
133
|
+
// Primitives
|
|
97
134
|
paragraph: "Paragraph",
|
|
98
135
|
heading: "Heading",
|
|
99
136
|
image: "Image",
|
|
100
137
|
video: "Video",
|
|
101
|
-
link: "Link",
|
|
102
|
-
button: "Button",
|
|
103
138
|
list: "List",
|
|
104
139
|
code: "Code",
|
|
105
140
|
file: "File",
|
|
106
|
-
divider: "Divider",
|
|
107
141
|
accordion: "Accordion",
|
|
108
142
|
array: "Repeater",
|
|
109
|
-
hero: "Hero",
|
|
110
|
-
vstack: "VStack",
|
|
111
|
-
columns: "Columns",
|
|
112
143
|
relationship: "Relationship",
|
|
113
144
|
richtext: "Rich Text",
|
|
145
|
+
|
|
146
|
+
// Core Semantic Blocks
|
|
147
|
+
hero: "Hero Section",
|
|
148
|
+
"heading-subheading": "Heading + Subheading",
|
|
149
|
+
card: "Card Block",
|
|
150
|
+
"feature-split": "Feature Split",
|
|
151
|
+
"feature-grid": "Feature Grid",
|
|
152
|
+
"cta-banner": "CTA Banner",
|
|
153
|
+
testimonials: "Testimonials Stack",
|
|
154
|
+
faq: "FAQ Section",
|
|
155
|
+
stats: "Stats & Metrics",
|
|
156
|
+
"logo-cloud": "Logo Cloud",
|
|
157
|
+
|
|
158
|
+
// Brand New Blocks
|
|
159
|
+
pricing: "Pricing Grid / Plan",
|
|
160
|
+
team: "Team Profiles Showcase",
|
|
161
|
+
"recent-feed": "Dynamic Content Feed",
|
|
162
|
+
"process-steps": "Process Timeline / Steps",
|
|
163
|
+
"form-embed": "Lead Intake Form",
|
|
164
|
+
"video-showcase": "Cinematic Video Showcase",
|
|
165
|
+
|
|
166
|
+
// Inline Content Elements
|
|
167
|
+
"heading-element": "Heading",
|
|
168
|
+
"text-element": "Text",
|
|
169
|
+
"image-element": "Image",
|
|
170
|
+
"richtext-element": "Rich Text",
|
|
171
|
+
"button-element": "Button",
|
|
172
|
+
"video-element": "Video",
|
|
173
|
+
"list-element": "List",
|
|
114
174
|
};
|
|
115
175
|
return labelMap[type] || type;
|
|
116
176
|
}
|
|
117
|
-
|
|
118
|
-
// Block categories for the drawer
|
|
119
|
-
export const blockCategories = [
|
|
120
|
-
{
|
|
121
|
-
title: "Layout",
|
|
122
|
-
blocks: [
|
|
123
|
-
{
|
|
124
|
-
type: "columns",
|
|
125
|
-
label: "Columns",
|
|
126
|
-
icon: "columns",
|
|
127
|
-
description: "1-6 columns side-by-side",
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
type: "vstack",
|
|
131
|
-
label: "VStack",
|
|
132
|
-
icon: "vstack",
|
|
133
|
-
description: "Stack blocks vertically",
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
type: "hero",
|
|
137
|
-
label: "Hero",
|
|
138
|
-
icon: "hero",
|
|
139
|
-
description: "Hero with content + video",
|
|
140
|
-
},
|
|
141
|
-
],
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
title: "Text",
|
|
145
|
-
blocks: [
|
|
146
|
-
{
|
|
147
|
-
type: "heading",
|
|
148
|
-
label: "Heading",
|
|
149
|
-
icon: "heading",
|
|
150
|
-
description: "Heading text",
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
type: "paragraph",
|
|
154
|
-
label: "Paragraph",
|
|
155
|
-
icon: "paragraph",
|
|
156
|
-
description: "Plain text content",
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
type: "richtext",
|
|
160
|
-
label: "Rich Text",
|
|
161
|
-
icon: "richtext",
|
|
162
|
-
description: "Formatted text with links & styles",
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
type: "list",
|
|
166
|
-
label: "List",
|
|
167
|
-
icon: "list",
|
|
168
|
-
description: "Ordered/unordered list",
|
|
169
|
-
},
|
|
170
|
-
{ type: "link", label: "Link", icon: "link", description: "Hyperlink" },
|
|
171
|
-
],
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
title: "Media",
|
|
175
|
-
blocks: [
|
|
176
|
-
{
|
|
177
|
-
type: "image",
|
|
178
|
-
label: "Image",
|
|
179
|
-
icon: "image",
|
|
180
|
-
description: "Single image",
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
type: "video",
|
|
184
|
-
label: "Video",
|
|
185
|
-
icon: "video",
|
|
186
|
-
description: "Embed video",
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
type: "file",
|
|
190
|
-
label: "File",
|
|
191
|
-
icon: "file",
|
|
192
|
-
description: "File download link",
|
|
193
|
-
},
|
|
194
|
-
],
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
title: "Interactive",
|
|
198
|
-
blocks: [
|
|
199
|
-
{
|
|
200
|
-
type: "button",
|
|
201
|
-
label: "Button",
|
|
202
|
-
icon: "button",
|
|
203
|
-
description: "CTA button",
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
type: "accordion",
|
|
207
|
-
label: "Accordion",
|
|
208
|
-
icon: "accordion",
|
|
209
|
-
description: "Collapsible sections",
|
|
210
|
-
},
|
|
211
|
-
],
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
title: "Data",
|
|
215
|
-
blocks: [
|
|
216
|
-
{
|
|
217
|
-
type: "array",
|
|
218
|
-
label: "Repeater",
|
|
219
|
-
icon: "array",
|
|
220
|
-
description: "Add multiple child blocks",
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
type: "code",
|
|
224
|
-
label: "Code",
|
|
225
|
-
icon: "code",
|
|
226
|
-
description: "Code snippet",
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
type: "relationship",
|
|
230
|
-
label: "Relationship",
|
|
231
|
-
icon: "relationship",
|
|
232
|
-
description: "Link to other collection",
|
|
233
|
-
},
|
|
234
|
-
],
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
title: "Basic",
|
|
238
|
-
blocks: [
|
|
239
|
-
{
|
|
240
|
-
type: "divider",
|
|
241
|
-
label: "Divider",
|
|
242
|
-
icon: "divider",
|
|
243
|
-
description: "Horizontal separator",
|
|
244
|
-
},
|
|
245
|
-
],
|
|
246
|
-
},
|
|
247
|
-
];
|
|
@@ -12,15 +12,19 @@ export interface BlocksStore {
|
|
|
12
12
|
moveBlock: (id: string, direction: "up" | "down") => void;
|
|
13
13
|
onBlocksChange: (() => void) | null;
|
|
14
14
|
setOnBlocksChange: (cb: () => void) => void;
|
|
15
|
+
allowedBlocks: any[];
|
|
16
|
+
dynamicCategories: { title: string; blocks: any[] }[];
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
export type BlocksStoreApi = StoreApi<BlocksStore>;
|
|
18
20
|
|
|
19
21
|
export const BlocksContext = createContext<BlocksStoreApi | null>(null);
|
|
20
22
|
|
|
21
|
-
export function createBlocksStore(): BlocksStoreApi {
|
|
23
|
+
export function createBlocksStore(allowedBlocks: any[] = [], dynamicCategories: any[] = []): BlocksStoreApi {
|
|
22
24
|
return createStore<BlocksStore>((set, get) => ({
|
|
23
25
|
blocks: [],
|
|
26
|
+
allowedBlocks,
|
|
27
|
+
dynamicCategories,
|
|
24
28
|
setBlocks: (blocks) => {
|
|
25
29
|
const ensuredBlocks = ensureIds(blocks || []);
|
|
26
30
|
set({ blocks: ensuredBlocks });
|
|
@@ -152,6 +156,9 @@ export function createNewBlock(type: string): BlockData {
|
|
|
152
156
|
function getDefaultData(type: string): Record<string, unknown> {
|
|
153
157
|
const defaults: Record<string, unknown> = {
|
|
154
158
|
heading: { level: 1, text: "" },
|
|
159
|
+
"heading-subheading": { heading: "", subheading: "" },
|
|
160
|
+
hero: { isMultiScreen: false },
|
|
161
|
+
card: { title: "", description: "", icon: "", link: "", linkText: "", isMultiCard: false },
|
|
155
162
|
paragraph: { text: "" },
|
|
156
163
|
divider: {},
|
|
157
164
|
callout: { text: "", variant: "info" },
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { default as
|
|
2
|
-
export { PortableTextRenderer } from "./PortableTextRenderer";
|
|
1
|
+
export { default as RichTextField } from "./RichTextField";
|
|
3
2
|
export { CodeField } from "./CodeField";
|
|
4
3
|
export { JSONField } from "./JSONField";
|
|
5
4
|
export { MarkdownField } from "./MarkdownField";
|
|
5
|
+
export { default as SecretField } from "./SecretField";
|
|
6
6
|
export { default as TextField } from "./TextField";
|
|
7
7
|
export { default as NumberField } from "./NumberField";
|
|
8
8
|
export { default as CheckboxField } from "./CheckboxField";
|
|
@@ -22,3 +22,5 @@ export { ArrayField } from "./ArrayField";
|
|
|
22
22
|
export { ChildrenField } from "./ChildrenField";
|
|
23
23
|
export { ColumnsField } from "./ColumnsField";
|
|
24
24
|
export { RelationshipBlockField } from "./RelationshipBlockField";
|
|
25
|
+
export { HeadingSubheadingField } from "./HeadingSubheadingField";
|
|
26
|
+
export { CardField } from "./CardField";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { type ReactNode } from "react";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ComponentType, SVGAttributes } from "react";
|
|
3
3
|
|
|
4
4
|
interface Breadcrumb {
|
|
5
5
|
label: string;
|
|
@@ -10,7 +10,7 @@ interface Breadcrumb {
|
|
|
10
10
|
interface Action {
|
|
11
11
|
label: string;
|
|
12
12
|
onClick: () => void;
|
|
13
|
-
icon?:
|
|
13
|
+
icon?: ComponentType<SVGAttributes<SVGSVGElement>>;
|
|
14
14
|
variant?: "primary" | "outline" | "ghost";
|
|
15
15
|
className?: string;
|
|
16
16
|
}
|
|
@@ -18,7 +18,7 @@ interface Action {
|
|
|
18
18
|
interface PageHeaderProps {
|
|
19
19
|
title?: string;
|
|
20
20
|
description?: string;
|
|
21
|
-
icon?:
|
|
21
|
+
icon?: ComponentType<SVGAttributes<SVGSVGElement>>;
|
|
22
22
|
breadcrumbs?: Breadcrumb[];
|
|
23
23
|
metadata?: ReactNode[];
|
|
24
24
|
back?: { label?: string; href?: string; onClick?: () => void };
|
|
@@ -129,7 +129,7 @@ export function PageHeader({
|
|
|
129
129
|
? "border border-[var(--kyro-border)] text-[var(--kyro-text-secondary)] hover:bg-[var(--kyro-surface-accent)]"
|
|
130
130
|
: act.variant === "ghost"
|
|
131
131
|
? "text-[var(--kyro-text-secondary)] hover:bg-[var(--kyro-surface-accent)] shadow-none"
|
|
132
|
-
: "
|
|
132
|
+
: "kyro-btn-primary hover:opacity-90"
|
|
133
133
|
} ${act.className || ""}`}
|
|
134
134
|
>
|
|
135
135
|
{act.icon && <act.icon className="w-4 h-4" />}
|
|
@@ -145,7 +145,7 @@ export function PageHeader({
|
|
|
145
145
|
<button
|
|
146
146
|
type="button"
|
|
147
147
|
onClick={action.onClick}
|
|
148
|
-
className={`flex items-center gap-2 px-6 py-2.5 rounded-xl font-bold text-sm
|
|
148
|
+
className={`kyro-btn kyro-btn-primary flex items-center gap-2 px-6 py-2.5 rounded-xl font-bold text-sm hover:opacity-90 transition-all shadow-lg shadow-[var(--kyro-primary)]/10 ${action.className || ""}`}
|
|
149
149
|
>
|
|
150
150
|
{action.icon && <action.icon className="w-4 h-4" />}
|
|
151
151
|
{action.label}
|
|
@@ -10,6 +10,7 @@ interface SlidePanelProps {
|
|
|
10
10
|
children: ReactNode;
|
|
11
11
|
width?: "sm" | "md" | "lg" | "xl";
|
|
12
12
|
showOverlay?: boolean;
|
|
13
|
+
accentClass?: string;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export function SlidePanel({
|
|
@@ -19,6 +20,7 @@ export function SlidePanel({
|
|
|
19
20
|
children,
|
|
20
21
|
width = "md",
|
|
21
22
|
showOverlay = false,
|
|
23
|
+
accentClass,
|
|
22
24
|
}: SlidePanelProps) {
|
|
23
25
|
const panelRef = useRef<HTMLDivElement>(null);
|
|
24
26
|
const [hydrated, setHydrated] = useState(false);
|
|
@@ -46,8 +48,8 @@ export function SlidePanel({
|
|
|
46
48
|
const widthClasses = {
|
|
47
49
|
sm: "w-[320px]",
|
|
48
50
|
md: "w-[400px]",
|
|
49
|
-
lg: "w-[
|
|
50
|
-
xl: "w-[
|
|
51
|
+
lg: "w-[550px]",
|
|
52
|
+
xl: "w-[700px]",
|
|
51
53
|
};
|
|
52
54
|
|
|
53
55
|
if (!open || !hydrated) return null;
|
|
@@ -62,7 +64,10 @@ export function SlidePanel({
|
|
|
62
64
|
)}
|
|
63
65
|
<div
|
|
64
66
|
ref={panelRef}
|
|
65
|
-
|
|
67
|
+
data-kyro-slide-panel="true"
|
|
68
|
+
data-kyro-slide-width={width}
|
|
69
|
+
className={`fixed right-0 top-0 bottom-0 z-[99999] ${widthClasses[width]} bg-[var(--kyro-surface)] ${accentClass ? `border-l-2 ${accentClass}` : "border-l border-[var(--kyro-border)]"
|
|
70
|
+
} shadow-2xl flex flex-col animate-slideIn`}
|
|
66
71
|
>
|
|
67
72
|
<div className="flex items-center justify-between px-4 py-3 border-b border-[var(--kyro-border)] bg-[var(--kyro-surface)]">
|
|
68
73
|
<h2 className="text-sm font-semibold text-[var(--kyro-text-primary)]">
|