@kyro-cms/admin 0.9.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.
Files changed (100) hide show
  1. package/dist/index.cjs +11960 -11006
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +67 -65
  4. package/dist/index.css.map +1 -1
  5. package/dist/index.d.cts +563 -0
  6. package/dist/index.d.ts +7 -7
  7. package/dist/index.js +12183 -11238
  8. package/dist/index.js.map +1 -1
  9. package/package.json +15 -11
  10. package/src/components/ActionBar.tsx +27 -14
  11. package/src/components/Admin.tsx +1 -1
  12. package/src/components/ApiKeysManager.tsx +5 -5
  13. package/src/components/AutoForm.tsx +585 -369
  14. package/src/components/BrandingHub.tsx +7 -4
  15. package/src/components/CreateView.tsx +2 -0
  16. package/src/components/DetailView.tsx +71 -56
  17. package/src/components/DeveloperCenter.tsx +8 -6
  18. package/src/components/FieldRenderer.tsx +94 -19
  19. package/src/components/ListView.tsx +33 -20
  20. package/src/components/MediaGallery.tsx +219 -194
  21. package/src/components/PluginsManager.tsx +197 -70
  22. package/src/components/RestPlayground.tsx +7 -7
  23. package/src/components/SessionsManager.tsx +1 -1
  24. package/src/components/SettingsPage.tsx +22 -0
  25. package/src/components/Sidebar.astro +13 -41
  26. package/src/components/UserManagement.tsx +153 -15
  27. package/src/components/UserMenu.tsx +30 -4
  28. package/src/components/VersionHistoryPanel.tsx +112 -119
  29. package/src/components/WebhookManager.tsx +6 -4
  30. package/src/components/blocks/ArrayBlock.tsx +6 -23
  31. package/src/components/blocks/BlockEditModal.tsx +82 -309
  32. package/src/components/blocks/CardBlock.tsx +35 -0
  33. package/src/components/blocks/ChildBlocksTree.tsx +57 -31
  34. package/src/components/blocks/GenericBlock.tsx +44 -0
  35. package/src/components/blocks/HeadingSubheadingBlock.tsx +32 -0
  36. package/src/components/blocks/HeroBlock.tsx +5 -14
  37. package/src/components/blocks/RichTextBlock.tsx +5 -5
  38. package/src/components/blocks/index.ts +5 -3
  39. package/src/components/fields/AccordionField.tsx +2 -2
  40. package/src/components/fields/ArrayField.tsx +1 -1
  41. package/src/components/fields/ArrayLayout.tsx +120 -29
  42. package/src/components/fields/BlocksField.tsx +430 -50
  43. package/src/components/fields/CardField.tsx +73 -0
  44. package/src/components/fields/CheckboxField.tsx +7 -3
  45. package/src/components/fields/DateField.tsx +4 -1
  46. package/src/components/fields/GroupLayout.tsx +2 -2
  47. package/src/components/fields/HeadingSubheadingField.tsx +43 -0
  48. package/src/components/fields/ListField.tsx +2 -2
  49. package/src/components/fields/NumberField.tsx +4 -1
  50. package/src/components/fields/RelationshipField.tsx +153 -87
  51. package/src/components/fields/RichTextField.tsx +781 -0
  52. package/src/components/fields/SecretField.tsx +102 -0
  53. package/src/components/fields/SelectField.tsx +19 -6
  54. package/src/components/fields/TabsLayout.tsx +19 -9
  55. package/src/components/fields/TextField.tsx +4 -1
  56. package/src/components/fields/UploadField.tsx +122 -56
  57. package/src/components/fields/extensions/blockComponents.tsx +103 -174
  58. package/src/components/fields/extensions/blocksStore.ts +8 -1
  59. package/src/components/fields/index.ts +4 -2
  60. package/src/components/ui/PageHeader.tsx +5 -5
  61. package/src/components/ui/SlidePanel.tsx +8 -3
  62. package/src/components/ui/icons.tsx +109 -109
  63. package/src/components/users/UserDetail.tsx +79 -16
  64. package/src/hooks/useAutoFormState.ts +125 -62
  65. package/src/integration.ts +148 -46
  66. package/src/kyro-cms.d.ts +7 -2
  67. package/src/layouts/AuthLayout.astro +14 -2
  68. package/src/lib/autoform-store.ts +85 -52
  69. package/src/lib/change-source.ts +9 -0
  70. package/src/lib/config.ts +104 -8
  71. package/src/lib/globals.ts +44 -9
  72. package/src/lib/normalize-upload-fields.ts +41 -0
  73. package/src/lib/paths.ts +2 -2
  74. package/src/lib/resolve-field-value.ts +110 -0
  75. package/src/lib/shim/use-sync-external-store-with-selector.js +30 -0
  76. package/src/lib/shim/use-sync-external-store.js +1 -0
  77. package/src/lib/stores/index.ts +1 -0
  78. package/src/lib/useResourceManager.ts +4 -4
  79. package/src/lib/vite-shim-plugin.ts +100 -0
  80. package/src/pages/[collection]/[id].astro +1 -1
  81. package/src/pages/preview/[collection]/[id].astro +4 -4
  82. package/src/pages/settings/[slug].astro +2 -2
  83. package/src/styles/main.css +60 -54
  84. package/README.md +0 -46
  85. package/dist/EditorClient-Q23UXR37.cjs +0 -468
  86. package/dist/EditorClient-Q23UXR37.cjs.map +0 -1
  87. package/dist/EditorClient-T5PASFNR.js +0 -466
  88. package/dist/EditorClient-T5PASFNR.js.map +0 -1
  89. package/dist/chunk-3BGDYKTD.cjs +0 -348
  90. package/dist/chunk-3BGDYKTD.cjs.map +0 -1
  91. package/dist/chunk-EEFXLQVT.js +0 -3
  92. package/dist/chunk-EEFXLQVT.js.map +0 -1
  93. package/src/components/blocks/ButtonBlock.tsx +0 -64
  94. package/src/components/blocks/ColumnsBlock.tsx +0 -55
  95. package/src/components/blocks/DividerBlock.tsx +0 -43
  96. package/src/components/blocks/LinkBlock.tsx +0 -65
  97. package/src/components/blocks/VStackBlock.tsx +0 -29
  98. package/src/components/fields/EditorClient.tsx +0 -535
  99. package/src/components/fields/PortableTextField.tsx +0 -155
  100. 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
- Columns3,
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
- columns: <Columns3 className="w-4 h-4" />,
65
- heading: <Heading1 className="w-4 h-4" />,
66
- paragraph: <AlignLeft className="w-4 h-4" />,
67
- divider: <Minus className="w-4 h-4" />,
68
- image: <Image className="w-4 h-4" />,
69
- video: <Video className="w-4 h-4" />,
70
- list: <List className="w-4 h-4" />,
71
- code: <Code className="w-4 h-4" />,
72
- link: <Link className="w-4 h-4" />,
73
- file: <File className="w-4 h-4" />,
74
- vstack: <ArrowDown className="w-4 h-4" />,
75
- button: <MousePointerClick className="w-4 h-4" />,
76
- accordion: <ChevronDown className="w-4 h-4" />,
77
- richtext: <AlignLeft className="w-4 h-4" />,
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
- hero: <Star className="w-4 h-4" />,
80
- array: <ListOrdered className="w-4 h-4" />,
81
- relationship: <Link2 className="w-4 h-4" />,
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
- // Get block component by type
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
- // Check if block type is supported
90
- export function isSupportedBlockType(type: string): boolean {
91
- return type in BLOCK_COMPONENTS;
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 PortableTextField } from "./PortableTextField";
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 { IconType } from "react-icons";
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?: IconType;
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?: IconType;
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
- : "bg-[var(--kyro-primary)] text-white hover:opacity-90"
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 bg-[var(--kyro-primary)] text-white hover:opacity-90 transition-all shadow-lg shadow-[var(--kyro-primary)]/10 ${action.className || ""}`}
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-[500px]",
50
- xl: "w-[600px]",
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
- className={`fixed right-0 top-0 bottom-0 z-[99999] ${widthClasses[width]} bg-[var(--kyro-surface)] border-l border-[var(--kyro-border)] shadow-2xl flex flex-col animate-slideIn`}
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)]">