@kyro-cms/admin 0.3.2 → 0.3.4

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 (242) hide show
  1. package/dist/EditorClient-XEUOVAAC.js +466 -0
  2. package/dist/EditorClient-XEUOVAAC.js.map +1 -0
  3. package/dist/EditorClient-YLCGVDXY.cjs +468 -0
  4. package/dist/EditorClient-YLCGVDXY.cjs.map +1 -0
  5. package/dist/chunk-7KPIUCGT.js +384 -0
  6. package/dist/chunk-7KPIUCGT.js.map +1 -0
  7. package/dist/chunk-GOACG6R7.cjs +473 -0
  8. package/dist/chunk-GOACG6R7.cjs.map +1 -0
  9. package/dist/index.cjs +14861 -0
  10. package/dist/index.cjs.map +1 -0
  11. package/dist/index.css +1661 -0
  12. package/dist/index.css.map +1 -0
  13. package/dist/index.d.ts +563 -0
  14. package/dist/index.js +14784 -0
  15. package/dist/index.js.map +1 -0
  16. package/package.json +19 -19
  17. package/src/components/ActionBar.tsx +7 -43
  18. package/src/components/Admin.tsx +138 -277
  19. package/src/components/ApiKeysManager.tsx +428 -419
  20. package/src/components/AuditLogsPage.tsx +35 -39
  21. package/src/components/AuthBridge.tsx +51 -0
  22. package/src/components/AutoForm.tsx +495 -1230
  23. package/src/components/BrandingHub.tsx +18 -19
  24. package/src/components/BulkActionsBar.tsx +1 -1
  25. package/src/components/CreateView.tsx +22 -36
  26. package/src/components/Dashboard.tsx +60 -84
  27. package/src/components/DetailView.tsx +113 -91
  28. package/src/components/DeveloperCenter.tsx +200 -198
  29. package/src/components/FieldRenderer.tsx +206 -0
  30. package/src/components/GraphQLPlayground.tsx +340 -480
  31. package/src/components/ListView.tsx +828 -254
  32. package/src/components/LoginPage.tsx +3 -4
  33. package/src/components/MarketplaceManager.tsx +254 -0
  34. package/src/components/MediaGallery.tsx +856 -1192
  35. package/src/components/PluginsManager.tsx +277 -0
  36. package/src/components/RestPlayground.tsx +398 -560
  37. package/src/components/SessionsManager.tsx +211 -0
  38. package/src/components/Sidebar.astro +179 -151
  39. package/src/components/ThemeProvider.tsx +7 -161
  40. package/src/components/UserManagement.tsx +162 -146
  41. package/src/components/UserMenu.tsx +110 -0
  42. package/src/components/WebhookManager.tsx +305 -367
  43. package/src/components/blocks/AccordionBlock.tsx +4 -4
  44. package/src/components/blocks/ArrayBlock.tsx +3 -3
  45. package/src/components/blocks/BlockEditModal.tsx +8 -8
  46. package/src/components/blocks/BlockWrapper.tsx +61 -0
  47. package/src/components/blocks/ButtonBlock.tsx +4 -4
  48. package/src/components/blocks/ChildBlocksTree.tsx +23 -25
  49. package/src/components/blocks/CodeBlock.tsx +15 -15
  50. package/src/components/blocks/ColumnsBlock.tsx +6 -44
  51. package/src/components/blocks/DividerBlock.tsx +3 -3
  52. package/src/components/blocks/FileBlock.tsx +4 -4
  53. package/src/components/blocks/HeadingBlock.tsx +6 -38
  54. package/src/components/blocks/HeroBlock.tsx +4 -4
  55. package/src/components/blocks/ImageBlock.tsx +4 -4
  56. package/src/components/blocks/LinkBlock.tsx +4 -4
  57. package/src/components/blocks/ListBlock.tsx +3 -3
  58. package/src/components/blocks/ParagraphBlock.tsx +12 -42
  59. package/src/components/blocks/RelationshipBlock.tsx +4 -4
  60. package/src/components/blocks/RichTextBlock.tsx +4 -4
  61. package/src/components/blocks/VStackBlock.tsx +5 -37
  62. package/src/components/blocks/VideoBlock.tsx +4 -4
  63. package/src/components/blocks/types.ts +11 -0
  64. package/src/components/fields/AccordionField.tsx +1 -1
  65. package/src/components/fields/ArrayField.tsx +2 -2
  66. package/src/components/fields/ArrayLayout.tsx +93 -0
  67. package/src/components/fields/BlocksField.tsx +122 -111
  68. package/src/components/fields/ButtonField.tsx +1 -1
  69. package/src/components/fields/CheckboxField.tsx +14 -15
  70. package/src/components/fields/ChildrenField.tsx +2 -2
  71. package/src/components/fields/CodeField.tsx +3 -3
  72. package/src/components/fields/ColumnsField.tsx +2 -2
  73. package/src/components/fields/DateField.tsx +13 -26
  74. package/src/components/fields/EditorClient.tsx +26 -28
  75. package/src/components/fields/FieldLayout.tsx +52 -0
  76. package/src/components/fields/GroupLayout.tsx +35 -0
  77. package/src/components/fields/JSONField.tsx +7 -7
  78. package/src/components/fields/LinkField.tsx +1 -1
  79. package/src/components/fields/MarkdownField.tsx +1 -1
  80. package/src/components/fields/NumberField.tsx +13 -26
  81. package/src/components/fields/PortableTextField.tsx +4 -4
  82. package/src/components/fields/PortableTextRenderer.tsx +1 -1
  83. package/src/components/fields/RelationshipBlockField.tsx +31 -23
  84. package/src/components/fields/RelationshipField.tsx +14 -14
  85. package/src/components/fields/SelectField.tsx +17 -26
  86. package/src/components/fields/TabsLayout.tsx +69 -0
  87. package/src/components/fields/TextField.tsx +85 -38
  88. package/src/components/fields/UploadField.tsx +71 -41
  89. package/src/components/fields/VideoField.tsx +1 -1
  90. package/src/components/fields/extensions/blockComponents.tsx +2 -2
  91. package/src/components/fields/extensions/blocksStore.ts +207 -193
  92. package/src/components/fields/types.ts +22 -0
  93. package/src/components/layout/Layout.tsx +1 -1
  94. package/src/components/ui/ActionMenu.tsx +63 -0
  95. package/src/components/ui/Badge.tsx +59 -5
  96. package/src/components/ui/BlockDrawer.tsx +4 -5
  97. package/src/components/ui/CommandPalette.tsx +58 -36
  98. package/src/components/ui/CommandPaletteWrapper.tsx +18 -17
  99. package/src/components/ui/Dropdown.tsx +18 -16
  100. package/src/components/ui/EmptyState.tsx +25 -0
  101. package/src/components/ui/GlobalModal.tsx +49 -0
  102. package/src/components/ui/IconButton.tsx +44 -0
  103. package/src/components/ui/Modal.tsx +19 -20
  104. package/src/components/ui/PageHeader.tsx +158 -0
  105. package/src/components/ui/Pagination.tsx +61 -0
  106. package/src/components/ui/PromptModal.tsx +1 -1
  107. package/src/components/ui/SearchInput.tsx +57 -0
  108. package/src/components/ui/SeoPreview.tsx +31 -0
  109. package/src/components/ui/SessionModal.tsx +0 -0
  110. package/src/components/ui/SlidePanel.tsx +2 -0
  111. package/src/components/ui/Toast.tsx +65 -122
  112. package/src/components/ui/Toaster.tsx +18 -0
  113. package/src/components/ui/icons.tsx +112 -0
  114. package/src/components/users/UserDetail.tsx +290 -0
  115. package/src/components/users/UserForm.tsx +242 -0
  116. package/src/components/users/UsersList.tsx +338 -0
  117. package/src/env.d.ts +13 -13
  118. package/src/fields/index.ts +2 -1
  119. package/src/global.d.ts +7 -0
  120. package/src/hooks/data.ts +2 -9
  121. package/src/hooks/useAsyncData.ts +36 -0
  122. package/src/hooks/useAutoFormState.ts +527 -0
  123. package/src/hooks/useSelection.ts +49 -0
  124. package/src/hooks/useSession.ts +0 -0
  125. package/src/index.ts +11 -1
  126. package/src/integration.ts +86 -11
  127. package/src/kyro-cms.d.ts +209 -0
  128. package/src/layouts/AdminLayout.astro +128 -11
  129. package/src/layouts/AuthLayout.astro +21 -5
  130. package/src/lib/api.ts +175 -55
  131. package/src/lib/autoform-store.ts +435 -0
  132. package/src/lib/config.ts +82 -34
  133. package/src/lib/createRegistry.ts +29 -0
  134. package/src/lib/default-kyro-config.ts +4 -0
  135. package/src/lib/globals.ts +50 -0
  136. package/src/lib/media-utils.ts +18 -0
  137. package/src/lib/object-utils.ts +77 -0
  138. package/src/lib/paths.ts +61 -0
  139. package/src/lib/stores/index.ts +370 -0
  140. package/src/lib/types.ts +43 -0
  141. package/src/lib/useResourceManager.ts +105 -0
  142. package/src/pages/403.astro +67 -0
  143. package/src/pages/[collection]/[id].astro +14 -180
  144. package/src/pages/[collection]/index.astro +11 -6
  145. package/src/pages/api-explorer.astro +173 -0
  146. package/src/pages/audit/index.astro +2 -0
  147. package/src/pages/auth/login.astro +122 -0
  148. package/src/pages/auth/register.astro +167 -0
  149. package/src/pages/graphql-explorer.astro +59 -0
  150. package/src/pages/{admin/graphql.astro → graphql.astro} +51 -17
  151. package/src/pages/index.astro +577 -0
  152. package/src/pages/index_ALT.astro +3 -0
  153. package/src/pages/keys.astro +11 -0
  154. package/src/pages/marketplace.astro +11 -0
  155. package/src/pages/media.astro +3 -0
  156. package/src/pages/plugins.astro +8 -0
  157. package/src/pages/preview/[collection]/[id].astro +188 -123
  158. package/src/pages/rest-playground.astro +62 -0
  159. package/src/pages/roles/index.astro +183 -76
  160. package/src/pages/sessions.astro +8 -0
  161. package/src/pages/settings/[slug].astro +92 -114
  162. package/src/pages/settings/index.astro +5 -3
  163. package/src/pages/users/[id].astro +25 -154
  164. package/src/pages/users/index.astro +19 -130
  165. package/src/pages/users/new.astro +9 -86
  166. package/src/pages/webhooks.astro +11 -0
  167. package/src/routes.ts +80 -0
  168. package/src/styles/main.css +119 -79
  169. package/src/theme/tokens.ts +1 -0
  170. package/src/vite-env.d.ts +14 -0
  171. package/src/collections/auth/index.ts +0 -155
  172. package/src/collections/portfolio/index.ts +0 -343
  173. package/src/components/ApiExplorer.tsx +0 -325
  174. package/src/components/EnhancedListView.tsx +0 -889
  175. package/src/components/GraphQLExplorer.tsx +0 -675
  176. package/src/components/Icons.tsx +0 -23
  177. package/src/components/StatusBadge.tsx +0 -76
  178. package/src/lib/MediaService.ts +0 -541
  179. package/src/lib/auth/sqlite-adapter.ts +0 -319
  180. package/src/lib/dataStore.ts +0 -226
  181. package/src/lib/db/adapter.ts +0 -54
  182. package/src/lib/db/drizzle-mysql-adapter.ts +0 -194
  183. package/src/lib/db/drizzle-mysql-auth-adapter.ts +0 -327
  184. package/src/lib/db/drizzle-postgres-adapter.ts +0 -202
  185. package/src/lib/db/drizzle-postgres-auth-adapter.ts +0 -304
  186. package/src/lib/db/drizzle-sqlite-adapter.ts +0 -227
  187. package/src/lib/db/drizzle-sqlite-auth-adapter.ts +0 -548
  188. package/src/lib/db/index.ts +0 -449
  189. package/src/lib/db/mongodb-adapter.ts +0 -207
  190. package/src/lib/db/mongodb-auth-adapter.ts +0 -305
  191. package/src/lib/db/schema/mysql-auth.ts +0 -113
  192. package/src/lib/db/schema/mysql-content.ts +0 -20
  193. package/src/lib/db/schema/postgres-auth.ts +0 -116
  194. package/src/lib/db/schema/postgres-content.ts +0 -35
  195. package/src/lib/db/schema/postgres-media.ts +0 -52
  196. package/src/lib/db/schema/postgres-settings.ts +0 -11
  197. package/src/lib/db/schema/sqlite-auth.ts +0 -112
  198. package/src/lib/db/schema/sqlite-content.ts +0 -20
  199. package/src/lib/db/version-adapter.ts +0 -248
  200. package/src/lib/graphql/index.ts +0 -1
  201. package/src/lib/graphql/schema.ts +0 -443
  202. package/src/lib/rate-limit.ts +0 -267
  203. package/src/lib/storage.ts +0 -374
  204. package/src/lib/store.ts +0 -85
  205. package/src/middleware.ts +0 -177
  206. package/src/pages/admin/api-explorer.astro +0 -98
  207. package/src/pages/admin/graphql-explorer.astro +0 -40
  208. package/src/pages/admin/index.astro +0 -286
  209. package/src/pages/admin/keys.astro +0 -8
  210. package/src/pages/admin/rest-playground.astro +0 -44
  211. package/src/pages/admin/webhooks.astro +0 -8
  212. package/src/pages/api/[collection]/[id]/publish.ts +0 -52
  213. package/src/pages/api/[collection]/[id]/unpublish.ts +0 -42
  214. package/src/pages/api/[collection]/[id]/versions.ts +0 -66
  215. package/src/pages/api/[collection]/[id].ts +0 -213
  216. package/src/pages/api/[collection]/index.ts +0 -209
  217. package/src/pages/api/auth/[id].ts +0 -121
  218. package/src/pages/api/auth/audit-logs.ts +0 -57
  219. package/src/pages/api/auth/login.ts +0 -211
  220. package/src/pages/api/auth/logout.ts +0 -66
  221. package/src/pages/api/auth/me.ts +0 -36
  222. package/src/pages/api/auth/refresh.ts +0 -119
  223. package/src/pages/api/auth/register.ts +0 -188
  224. package/src/pages/api/auth/users.ts +0 -97
  225. package/src/pages/api/collections.ts +0 -59
  226. package/src/pages/api/globals/[slug].ts +0 -42
  227. package/src/pages/api/graphql.ts +0 -90
  228. package/src/pages/api/health.ts +0 -426
  229. package/src/pages/api/keys/[id].ts +0 -26
  230. package/src/pages/api/keys/index.ts +0 -75
  231. package/src/pages/api/media/[id].ts +0 -309
  232. package/src/pages/api/media/folders.ts +0 -609
  233. package/src/pages/api/media/index.ts +0 -146
  234. package/src/pages/api/media/resize.ts +0 -267
  235. package/src/pages/api/search.ts +0 -82
  236. package/src/pages/api/slug-availability.ts +0 -70
  237. package/src/pages/api/storage-config.ts +0 -20
  238. package/src/pages/api/storage-status.ts +0 -206
  239. package/src/pages/api/upload.ts +0 -334
  240. package/src/pages/api/webhooks/index.ts +0 -71
  241. package/src/pages/login.astro +0 -82
  242. package/src/pages/register.astro +0 -102
@@ -3,12 +3,12 @@ import {
3
3
  useBlockById,
4
4
  useBlockActions,
5
5
  } from "../fields/extensions/blocksStore";
6
- import { ChevronRight, X } from "lucide-react";
6
+ import { ChevronRight, X } from "../ui/icons";
7
7
  import { HeroField } from "../fields/HeroField";
8
8
  import { UploadField } from "../fields/UploadField";
9
9
  import { ChildBlocksTree } from "./ChildBlocksTree";
10
10
 
11
- export const HeroBlock: React.FC<{ block: any; index: number }> = ({
11
+ export const HeroBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
12
12
  block,
13
13
  index,
14
14
  }) => {
@@ -18,7 +18,7 @@ export const HeroBlock: React.FC<{ block: any; index: number }> = ({
18
18
  const data = blockData?.data ?? block.data ?? {};
19
19
  const children = blockData?.children ?? block.children ?? [];
20
20
 
21
- const handleChange = (field: string, value: any) => {
21
+ const handleChange = (field: string, value: unknown) => {
22
22
  updateBlock(block.id, { data: { ...data, [field]: value } });
23
23
  };
24
24
 
@@ -26,7 +26,7 @@ export const HeroBlock: React.FC<{ block: any; index: number }> = ({
26
26
  <div className="block-hero border border-[var(--kyro-border)] rounded-md p-3 mb-2 relative group">
27
27
  <div className="flex items-center justify-between mb-2">
28
28
  <div className="flex items-center gap-2">
29
- <span className="text-xs font-semibold text-[var(--kyro-text-muted)] uppercase">
29
+ <span className="text-xs font-semibold text-[var(--kyro-text-muted)] ">
30
30
  Hero Section
31
31
  </span>
32
32
  </div>
@@ -3,10 +3,10 @@ import {
3
3
  useBlockById,
4
4
  useBlockActions,
5
5
  } from "../fields/extensions/blocksStore";
6
- import { ChevronRight, X } from "lucide-react";
6
+ import { ChevronRight, X } from "../ui/icons";
7
7
  import { UploadField } from "../fields/UploadField";
8
8
 
9
- export const ImageBlock: React.FC<{ block: any; index: number }> = ({
9
+ export const ImageBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
10
10
  block,
11
11
  index,
12
12
  }) => {
@@ -14,14 +14,14 @@ export const ImageBlock: React.FC<{ block: any; index: number }> = ({
14
14
  const { updateBlock, removeBlock, moveBlock } = useBlockActions();
15
15
  const data = blockData?.data || block.data || {};
16
16
 
17
- const handleChange = (field: string, value: any) => {
17
+ const handleChange = (field: string, value: unknown) => {
18
18
  updateBlock(block.id, { data: { ...data, [field]: value } });
19
19
  };
20
20
 
21
21
  return (
22
22
  <div className="block-image border border-[var(--kyro-border)] rounded-lg p-4 mb-4 relative group">
23
23
  <div className="flex items-center justify-between mb-2">
24
- <span className="text-xs font-semibold text-[var(--kyro-text-muted)] uppercase">
24
+ <span className="text-xs font-semibold text-[var(--kyro-text-muted)] ">
25
25
  Image
26
26
  </span>
27
27
  <div className="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
@@ -3,10 +3,10 @@ import {
3
3
  useBlockById,
4
4
  useBlockActions,
5
5
  } from "../fields/extensions/blocksStore";
6
- import { ChevronRight, X } from "lucide-react";
6
+ import { ChevronRight, X } from "../ui/icons";
7
7
  import { LinkField } from "../fields/LinkField";
8
8
 
9
- export const LinkBlock: React.FC<{ block: any; index: number }> = ({
9
+ export const LinkBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
10
10
  block,
11
11
  index,
12
12
  }) => {
@@ -15,14 +15,14 @@ export const LinkBlock: React.FC<{ block: any; index: number }> = ({
15
15
 
16
16
  const data = blockData?.data ?? block.data ?? {};
17
17
 
18
- const handleChange = (field: string, value: any) => {
18
+ const handleChange = (field: string, value: unknown) => {
19
19
  updateBlock(block.id, { data: { ...data, [field]: value } });
20
20
  };
21
21
 
22
22
  return (
23
23
  <div className="block-link border border-[var(--kyro-border)] rounded-md p-2.5 mb-2 relative group">
24
24
  <div className="flex items-center gap-2">
25
- <span className="text-[10px] font-bold text-[var(--kyro-text-muted)] uppercase shrink-0 w-8">
25
+ <span className="text-[10px] font-bold text-[var(--kyro-text-muted)] shrink-0 w-8">
26
26
  Link
27
27
  </span>
28
28
  <div className="flex-1 min-w-0">
@@ -3,10 +3,10 @@ import {
3
3
  useBlockById,
4
4
  useBlockActions,
5
5
  } from "../fields/extensions/blocksStore";
6
- import { ChevronRight, X } from "lucide-react";
6
+ import { ChevronRight, X } from "../ui/icons";
7
7
  import { ListField } from "../fields/ListField";
8
8
 
9
- export const ListBlock: React.FC<{ block: any; index: number }> = ({
9
+ export const ListBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
10
10
  block,
11
11
  index,
12
12
  }) => {
@@ -23,7 +23,7 @@ export const ListBlock: React.FC<{ block: any; index: number }> = ({
23
23
  return (
24
24
  <div className="block-list border border-[var(--kyro-border)] rounded-md p-3 mb-2 relative group">
25
25
  <div className="flex items-center justify-between mb-1">
26
- <span className="text-xs font-semibold text-[var(--kyro-text-muted)] uppercase">
26
+ <span className="text-xs font-semibold text-[var(--kyro-text-muted)] ">
27
27
  List
28
28
  </span>
29
29
  <div className="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
@@ -3,59 +3,29 @@ import {
3
3
  useBlockById,
4
4
  useBlockActions,
5
5
  } from "../fields/extensions/blocksStore";
6
- import { ChevronRight, X } from "lucide-react";
6
+ import { BlockWrapper } from "./BlockWrapper";
7
7
 
8
- export const ParagraphBlock: React.FC<{ block: any; index: number }> = ({
8
+ export const ParagraphBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
9
9
  block,
10
10
  index,
11
11
  }) => {
12
12
  const blockData = useBlockById(block.id);
13
- const { updateBlock, removeBlock, moveBlock } = useBlockActions();
13
+ const { updateBlock } = useBlockActions();
14
14
 
15
15
  const data = blockData?.data || block.data || {};
16
16
 
17
- const handleChange = (field: string, value: any) => {
17
+ const handleChange = (field: string, value: unknown) => {
18
18
  updateBlock(block.id, { data: { ...data, [field]: value } });
19
19
  };
20
20
 
21
21
  return (
22
- <div className="block-paragraph border-l-4 border-[var(--kyro-border)] pl-4 py-2 mb-2 relative group">
23
- <div className="flex items-center justify-between mb-1">
24
- <span className="text-xs font-semibold text-[var(--kyro-text-muted)] uppercase">
25
- Paragraph
26
- </span>
27
- <div className="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
28
- <button type="button"
29
- onClick={() => moveBlock(block.id, "up")}
30
- className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
31
- title="Move up"
32
- >
33
- <ChevronRight className="w-3 h-3 rotate-90" />
34
- </button>
35
- <button type="button"
36
- onClick={() => moveBlock(block.id, "down")}
37
- className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
38
- title="Move down"
39
- >
40
- <ChevronRight className="w-3 h-3" />
41
- </button>
42
- <button type="button"
43
- onClick={() => removeBlock(block.id)}
44
- className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
45
- title="Remove"
46
- >
47
- <X className="w-3 h-3" />
48
- </button>
49
- </div>
50
- </div>
51
- <div>
52
- <textarea
53
- value={data.text || ""}
54
- onChange={(e) => handleChange("text", e.target.value)}
55
- className="w-full px-3 py-3 border border-[var(--kyro-border)] rounded bg-[var(--kyro-surface)] text-[var(--kyro-text-primary)] text-sm min-h-[100px] resize-none"
56
- placeholder="Enter paragraph text..."
57
- />
58
- </div>
59
- </div>
22
+ <BlockWrapper id={block.id} type="paragraph" label="Paragraph">
23
+ <textarea
24
+ value={data.text || ""}
25
+ onChange={(e) => handleChange("text", e.target.value)}
26
+ className="w-full px-3 py-3 border border-[var(--kyro-border)] rounded bg-[var(--kyro-surface)] text-[var(--kyro-text-primary)] text-sm min-h-[100px] resize-none"
27
+ placeholder="Enter paragraph text..."
28
+ />
29
+ </BlockWrapper>
60
30
  );
61
31
  };
@@ -3,10 +3,10 @@ import {
3
3
  useBlockById,
4
4
  useBlockActions,
5
5
  } from "../fields/extensions/blocksStore";
6
- import { ChevronRight, X } from "lucide-react";
6
+ import { ChevronRight, X } from "../ui/icons";
7
7
  import { RelationshipBlockField } from "../fields/RelationshipBlockField";
8
8
 
9
- export const RelationshipBlock: React.FC<{ block: any; index: number }> = ({
9
+ export const RelationshipBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
10
10
  block,
11
11
  index,
12
12
  }) => {
@@ -15,7 +15,7 @@ export const RelationshipBlock: React.FC<{ block: any; index: number }> = ({
15
15
 
16
16
  const data = blockData?.data ?? block.data ?? {};
17
17
 
18
- const handleChange = (field: string, value: any) => {
18
+ const handleChange = (field: string, value: unknown) => {
19
19
  updateBlock(block.id, { data: { ...data, [field]: value } });
20
20
  };
21
21
 
@@ -23,7 +23,7 @@ export const RelationshipBlock: React.FC<{ block: any; index: number }> = ({
23
23
  <div className="block-relationship border border-[var(--kyro-border)] rounded-md p-3 mb-2 relative group">
24
24
  <div className="flex items-center justify-between mb-1">
25
25
  <div className="flex items-center gap-2">
26
- <span className="text-xs font-semibold text-[var(--kyro-text-muted)] uppercase">
26
+ <span className="text-xs font-semibold text-[var(--kyro-text-muted)] ">
27
27
  Relationship
28
28
  </span>
29
29
  <span className="text-[10px] text-[var(--kyro-text-muted)]">
@@ -3,10 +3,10 @@ import {
3
3
  useBlockById,
4
4
  useBlockActions,
5
5
  } from "../fields/extensions/blocksStore";
6
- import { ChevronRight, X, AlignLeft } from "lucide-react";
6
+ import { ChevronRight, X, AlignLeft } from "../ui/icons";
7
7
  import PortableTextField from "../fields/PortableTextField";
8
8
 
9
- export const RichTextBlock: React.FC<{ block: any; index: number }> = ({
9
+ export const RichTextBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
10
10
  block,
11
11
  index,
12
12
  }) => {
@@ -15,7 +15,7 @@ export const RichTextBlock: React.FC<{ block: any; index: number }> = ({
15
15
 
16
16
  const data = blockData?.data || block.data || {};
17
17
 
18
- const handleChange = (newValue: any) => {
18
+ const handleChange = (newValue: unknown) => {
19
19
  updateBlock(block.id, { data: { ...data, content: newValue } });
20
20
  };
21
21
 
@@ -24,7 +24,7 @@ export const RichTextBlock: React.FC<{ block: any; index: number }> = ({
24
24
  <div className="flex items-center justify-between mb-2">
25
25
  <div className="flex items-center gap-2">
26
26
  <AlignLeft className="w-3.5 h-3.5 text-[var(--kyro-primary)]" />
27
- <span className="text-xs font-semibold text-[var(--kyro-text-muted)] uppercase">
27
+ <span className="text-xs font-semibold text-[var(--kyro-text-muted)] ">
28
28
  Rich Text
29
29
  </span>
30
30
  </div>
@@ -3,59 +3,27 @@ import {
3
3
  useBlockById,
4
4
  useBlockActions,
5
5
  } from "../fields/extensions/blocksStore";
6
- import { ChevronRight, X } from "lucide-react";
7
6
  import { ChildrenField } from "../fields/ChildrenField";
7
+ import { BlockWrapper } from "./BlockWrapper";
8
8
 
9
- export const VStackBlock: React.FC<{ block: any; index: number }> = ({
9
+ export const VStackBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
10
10
  block,
11
11
  index,
12
12
  }) => {
13
13
  const blockData = useBlockById(block.id);
14
- const { updateBlock, removeBlock, moveBlock } = useBlockActions();
14
+ const { updateBlock } = useBlockActions();
15
15
 
16
16
  const data = blockData?.data ?? block.data ?? {};
17
17
  const children = blockData?.children ?? block.children ?? [];
18
18
 
19
19
  return (
20
- <div className="block-vstack border border-[var(--kyro-border)] rounded-md p-3 mb-2 relative group">
21
- <div className="flex items-center justify-between mb-1">
22
- <span className="text-xs font-semibold text-[var(--kyro-text-muted)] uppercase">
23
- Stack
24
- </span>
25
- <div className="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
26
- <button
27
- type="button"
28
- onClick={() => moveBlock(block.id, "up")}
29
- className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
30
- title="Move up"
31
- >
32
- <ChevronRight className="w-3 h-3 rotate-90" />
33
- </button>
34
- <button
35
- type="button"
36
- onClick={() => moveBlock(block.id, "down")}
37
- className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
38
- title="Move down"
39
- >
40
- <ChevronRight className="w-3 h-3" />
41
- </button>
42
- <button
43
- type="button"
44
- onClick={() => removeBlock(block.id)}
45
- className="p-1 hover:bg-red-50 rounded text-red-500"
46
- title="Remove"
47
- >
48
- <X className="w-3 h-3" />
49
- </button>
50
- </div>
51
- </div>
52
-
20
+ <BlockWrapper id={block.id} type="vstack" label="Stack">
53
21
  <ChildrenField
54
22
  blockId={block.id}
55
23
  children={children}
56
24
  onUpdateChildren={(c) => updateBlock(block.id, { children: c })}
57
25
  compact
58
26
  />
59
- </div>
27
+ </BlockWrapper>
60
28
  );
61
29
  };
@@ -3,10 +3,10 @@ import {
3
3
  useBlockById,
4
4
  useBlockActions,
5
5
  } from "../fields/extensions/blocksStore";
6
- import { ChevronRight, X } from "lucide-react";
6
+ import { ChevronRight, X } from "../ui/icons";
7
7
  import { VideoField } from "../fields/VideoField";
8
8
 
9
- export const VideoBlock: React.FC<{ block: any; index: number }> = ({
9
+ export const VideoBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
10
10
  block,
11
11
  index,
12
12
  }) => {
@@ -15,14 +15,14 @@ export const VideoBlock: React.FC<{ block: any; index: number }> = ({
15
15
 
16
16
  const data = blockData?.data ?? block.data ?? {};
17
17
 
18
- const handleChange = (field: string, value: any) => {
18
+ const handleChange = (field: string, value: unknown) => {
19
19
  updateBlock(block.id, { data: { ...data, [field]: value } });
20
20
  };
21
21
 
22
22
  return (
23
23
  <div className="block-video border border-[var(--kyro-border)] rounded-md p-3 mb-2 relative group">
24
24
  <div className="flex items-center justify-between mb-1">
25
- <span className="text-xs font-semibold text-[var(--kyro-text-muted)] uppercase">
25
+ <span className="text-xs font-semibold text-[var(--kyro-text-muted)] ">
26
26
  Video
27
27
  </span>
28
28
  <div className="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
@@ -0,0 +1,11 @@
1
+ export interface Block {
2
+ id: string;
3
+ type?: string;
4
+ data?: Record<string, unknown>;
5
+ children?: Block[];
6
+ }
7
+
8
+ export interface BlockComponentProps {
9
+ block: Block;
10
+ index: number;
11
+ }
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { ChevronDown, ChevronUp, Plus, X } from "lucide-react";
2
+ import { ChevronDown, ChevronUp, Plus, X } from "../ui/icons";
3
3
 
4
4
  interface AccordionItem {
5
5
  title: string;
@@ -1,8 +1,8 @@
1
1
  import React from "react";
2
- import { Plus, ChevronDown, ChevronUp, X } from "lucide-react";
2
+ import { Plus, ChevronDown, ChevronUp, X } from "../ui/icons";
3
3
 
4
4
  interface ArrayFieldItem {
5
- [key: string]: any;
5
+ [key: string]: unknown;
6
6
  }
7
7
 
8
8
  interface ArrayFieldProps {
@@ -0,0 +1,93 @@
1
+ import React from "react";
2
+ import type { Field } from "@kyro-cms/core/client";
3
+ import RelationshipField from "./RelationshipField";
4
+
5
+ interface ArrayLayoutProps {
6
+ field: Field;
7
+ value: unknown[];
8
+ onChange: (value: unknown[]) => void;
9
+ renderField: (
10
+ field: Field,
11
+ parentData: Record<string, unknown>,
12
+ onChange: (value: unknown) => void,
13
+ ) => React.ReactNode;
14
+ disabled?: boolean;
15
+ }
16
+
17
+ export function ArrayLayout({
18
+ field,
19
+ value,
20
+ onChange,
21
+ renderField,
22
+ disabled,
23
+ }: ArrayLayoutProps) {
24
+ const items = Array.isArray(value) ? value : [];
25
+ const labelField = (field as Field & { fields?: { name?: string; type?: string; relationTo?: string; label?: string }[] }).fields?.[0]?.name || "user";
26
+ const isRelationship = (field as Field & { fields?: { type?: string }[] }).fields?.[0]?.type === "relationship";
27
+
28
+ return (
29
+ <div className="kyro-form-field">
30
+ <label className="kyro-form-label">{field.label || field.name}</label>
31
+ {isRelationship ? (
32
+ <RelationshipField
33
+ field={{
34
+ name: labelField,
35
+ relationTo: (field as Field & { fields?: { relationTo?: string }[] }).fields?.[0]?.relationTo || "",
36
+ hasMany: true,
37
+ label: (field as Field & { fields?: { label?: string }[] }).fields?.[0]?.label,
38
+ }}
39
+ value={(items as Record<string, unknown>[]).map((i) => i[labelField]).filter(Boolean)}
40
+ onChange={(newValue) => {
41
+ const newItems = (newValue || []).map((id: string) => ({
42
+ [labelField]: id,
43
+ }));
44
+ onChange(newItems);
45
+ }}
46
+ disabled={disabled}
47
+ />
48
+ ) : (
49
+ <div className="kyro-form-array border border-[var(--kyro-border)] bg-[var(--kyro-surface-accent)]/30 rounded-[var(--kyro-radius-md)] p-4 space-y-4">
50
+ {(items as Record<string, unknown>[]).map((item, index) => (
51
+ <div
52
+ key={index}
53
+ className="kyro-form-array-item bg-[var(--kyro-surface)] border border-[var(--kyro-border)] rounded-[var(--kyro-radius-md)] p-4 relative group"
54
+ >
55
+ <div className="flex justify-between items-center mb-4 pb-2 border-b border-[var(--kyro-border)]">
56
+ <span className="text-[10px] font-bold tracking-widest text-[var(--kyro-text-muted)]">
57
+ Item {index + 1}
58
+ </span>
59
+ <button
60
+ type="button"
61
+ disabled={disabled}
62
+ className="text-[11px] font-bold text-[var(--kyro-error)] opacity-50 hover:opacity-100 transition-opacity disabled:opacity-30"
63
+ onClick={() =>
64
+ onChange(items.filter((_: unknown, i: number) => i !== index))
65
+ }
66
+ >
67
+ Remove
68
+ </button>
69
+ </div>
70
+ <div className="space-y-4">
71
+ {(field as Field & { fields?: Field[] }).fields.map((f: Field) =>
72
+ renderField(f, item, (newItem) => {
73
+ const newItems = [...items];
74
+ newItems[index] = newItem;
75
+ onChange(newItems);
76
+ }),
77
+ )}
78
+ </div>
79
+ </div>
80
+ ))}
81
+ <button
82
+ type="button"
83
+ className="w-full py-3 border-2 border-dashed border-[var(--kyro-border)] rounded-[var(--kyro-radius-md)] text-xs font-bold text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-primary)] hover:border-[var(--kyro-primary)] transition-all disabled:opacity-50"
84
+ disabled={disabled}
85
+ onClick={() => onChange([...items, {}])}
86
+ >
87
+ + Add Item
88
+ </button>
89
+ </div>
90
+ )}
91
+ </div>
92
+ );
93
+ }