@kyro-cms/admin 0.3.1 → 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
@@ -1,4 +1,4 @@
1
- import { useState, useEffect, useCallback, useRef } from "react";
1
+ import React, { useState, useEffect, useCallback } from "react";
2
2
  import { apiGet, apiPatch, apiPost, apiDelete } from "../lib/api";
3
3
  import type {
4
4
  KyroConfig,
@@ -7,9 +7,13 @@ import type {
7
7
  } from "@kyro-cms/core/client";
8
8
  import { AutoForm } from "./AutoForm";
9
9
  import { ActionBar, type DocumentStatus, type SaveStatus } from "./ActionBar";
10
- import { ConfirmModal } from "./ui/Modal";
11
10
  import { Spinner } from "./ui/Spinner";
12
11
  import { useToast } from "./ui/Toast";
12
+ import { useUIStore } from "../lib/stores";
13
+ import { PageHeader } from "./ui/PageHeader";
14
+ import { Badge } from "./ui/Badge";
15
+ import { adminPath } from "../lib/paths";
16
+
13
17
 
14
18
  interface DetailViewProps {
15
19
  config: KyroConfig;
@@ -21,8 +25,6 @@ interface DetailViewProps {
21
25
  onDelete?: () => void;
22
26
  onError: (message: string) => void;
23
27
  mode?: "collection" | "global";
24
- autosave?: boolean;
25
- autosaveDelay?: number;
26
28
  }
27
29
 
28
30
  export function DetailView({
@@ -35,26 +37,21 @@ export function DetailView({
35
37
  onDelete,
36
38
  onError,
37
39
  mode = "collection",
38
- autosave = true,
39
- autosaveDelay = 2000,
40
40
  }: DetailViewProps) {
41
41
  const { addToast } = useToast();
42
+ const { confirm, alert } = useUIStore();
42
43
  const [data, setData] = useState<Record<string, unknown>>({});
43
44
  const [originalData, setOriginalData] = useState<Record<string, unknown>>({});
44
45
  const [loading, setLoading] = useState(true);
45
46
  const [saving, setSaving] = useState(false);
46
47
  const [saveStatus, setSaveStatus] = useState<SaveStatus>("idle");
47
48
  const [deleting, setDeleting] = useState(false);
48
- const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
49
49
  const [status, setStatus] = useState<DocumentStatus>("draft");
50
50
  const [createdAt, setCreatedAt] = useState<string | null>(null);
51
51
  const [updatedAt, setUpdatedAt] = useState<string | null>(null);
52
52
  const [publishedAt, setPublishedAt] = useState<string | null>(null);
53
53
  const [justSaved, setJustSaved] = useState(false);
54
54
 
55
- const autosaveTimerRef = useRef<NodeJS.Timeout | null>(null);
56
- const hasChangesRef = useRef(false);
57
-
58
55
  const fields = global?.fields || collection?.fields || [];
59
56
  const label = global?.label || collection?.label || "Document";
60
57
  const slug = global?.slug || collection?.slug || "";
@@ -80,39 +77,23 @@ export function DetailView({
80
77
  } else if (documentId) {
81
78
  loadDocument();
82
79
  }
83
- }, [documentId, mode]);
84
-
85
- useEffect(() => {
86
- hasChangesRef.current = hasChanges;
87
- }, [hasChanges]);
88
-
89
- useEffect(() => {
90
- if (autosave && hasChanges && !loading) {
91
- if (autosaveTimerRef.current) {
92
- clearTimeout(autosaveTimerRef.current);
93
- }
94
- autosaveTimerRef.current = setTimeout(() => {
95
- if (hasChangesRef.current) {
96
- handleSave(true);
97
- }
98
- }, autosaveDelay);
99
- }
80
+ }, [documentId, mode, slug]);
100
81
 
101
- return () => {
102
- if (autosaveTimerRef.current) {
103
- clearTimeout(autosaveTimerRef.current);
104
- }
105
- };
106
- }, [data, autosave, autosaveDelay]);
107
82
 
108
83
  const loadDocument = async () => {
109
84
  try {
110
85
  setLoading(true);
111
- const result = await apiGet(`/api/${slug}/${documentId}`);
86
+ const result = (await apiGet(`/api/${slug}/${documentId}`, { autoToast: false }) as {
87
+ data?: Record<string, unknown>;
88
+ status?: string;
89
+ createdAt?: string;
90
+ updatedAt?: string;
91
+ publishedAt?: string;
92
+ });
112
93
  const docData = result.data || {};
113
94
  setData(docData);
114
95
  setOriginalData(docData);
115
- setStatus(result.status || "draft");
96
+ setStatus((result.status || "draft") as DocumentStatus);
116
97
  setCreatedAt(result.createdAt || null);
117
98
  setUpdatedAt(result.updatedAt || null);
118
99
  setPublishedAt(result.publishedAt || null);
@@ -126,7 +107,11 @@ export function DetailView({
126
107
  const loadGlobal = async () => {
127
108
  try {
128
109
  setLoading(true);
129
- const result = await apiGet(`/api/globals/${slug}`);
110
+ const result = (await apiGet(`/api/globals/${slug}`, { autoToast: false }) as {
111
+ data?: Record<string, unknown>;
112
+ createdAt?: string;
113
+ updatedAt?: string;
114
+ });
130
115
  const globalData = result.data || {};
131
116
  setData(globalData);
132
117
  setOriginalData(globalData);
@@ -148,12 +133,15 @@ export function DetailView({
148
133
  ? `/api/globals/${slug}`
149
134
  : `/api/${slug}/${documentId}`;
150
135
 
151
- await apiPatch(endpoint, data);
136
+ const result = (await apiPatch(endpoint, data) as { data?: Record<string, unknown> });
137
+ const savedData = (result && (result.data || result)) || data;
152
138
 
153
139
  if (!isAutosave) {
154
- setOriginalData(data);
140
+ setOriginalData(savedData);
155
141
  onSave();
156
142
  }
143
+
144
+ setData(savedData);
157
145
  setSaveStatus("saved");
158
146
  setUpdatedAt(new Date().toISOString());
159
147
 
@@ -162,7 +150,7 @@ export function DetailView({
162
150
  setTimeout(() => setJustSaved(false), 3000);
163
151
 
164
152
  if (!isAutosave) {
165
- addToast("success", "Saved successfully");
153
+ addToast?.("success", "Saved successfully");
166
154
  }
167
155
 
168
156
  setTimeout(() => {
@@ -172,7 +160,7 @@ export function DetailView({
172
160
  setSaveStatus("error");
173
161
  if (!isAutosave) {
174
162
  onError("Failed to save changes");
175
- addToast("error", "Failed to save changes");
163
+ addToast?.("error", "Failed to save changes");
176
164
  }
177
165
  } finally {
178
166
  setSaving(false);
@@ -187,10 +175,10 @@ export function DetailView({
187
175
  await apiPost(`/api/${slug}/${documentId}/publish`);
188
176
  setStatus("published");
189
177
  setPublishedAt(new Date().toISOString());
190
- addToast("success", "Published successfully");
178
+ addToast?.("success", "Published successfully");
191
179
  } catch {
192
180
  onError("Failed to publish");
193
- addToast("error", "Failed to publish");
181
+ addToast?.("error", "Failed to publish");
194
182
  } finally {
195
183
  setSaving(false);
196
184
  }
@@ -210,24 +198,36 @@ export function DetailView({
210
198
 
211
199
  const handleDuplicate = async () => {
212
200
  try {
213
- await apiPost(`/api/${slug}/${documentId}/duplicate`);
201
+ console.log(`[Duplicate] Calling /api/${slug}/${documentId}/duplicate`);
202
+ const result = await apiPost(`/api/${slug}/${documentId}/duplicate`);
203
+ console.log("[Duplicate] Success:", result);
214
204
  onError("Document duplicated successfully");
215
- } catch {
216
- onError("Failed to duplicate document");
205
+ } catch (err: unknown) {
206
+ console.error("[Duplicate] Error:", err);
207
+ const message = err instanceof Error ? err.message : "Failed to duplicate document";
208
+ onError(message);
217
209
  }
218
210
  };
219
211
 
220
- const handleDelete = async () => {
221
- try {
222
- setDeleting(true);
223
- await apiDelete(`/api/${slug}/${documentId}`);
224
- onDelete?.();
225
- } catch {
226
- onError("Failed to delete document");
227
- } finally {
228
- setDeleting(false);
229
- setShowDeleteConfirm(false);
230
- }
212
+ const handleDeleteTrigger = () => {
213
+ confirm({
214
+ title: `Delete ${label}?`,
215
+ message: "This action cannot be undone.",
216
+ variant: "danger",
217
+ onConfirm: async () => {
218
+ try {
219
+ setDeleting(true);
220
+ await apiDelete(`/api/${slug}/${documentId}`);
221
+ onDelete?.();
222
+ } catch (err: unknown) {
223
+ console.error("[Delete] Error:", err);
224
+ const message = err instanceof Error ? err.message : "Failed to delete document";
225
+ alert({ title: "Error", message });
226
+ } finally {
227
+ setDeleting(false);
228
+ }
229
+ }
230
+ });
231
231
  };
232
232
 
233
233
  if (loading) {
@@ -245,7 +245,33 @@ export function DetailView({
245
245
 
246
246
  return (
247
247
  <div className="kyro-detail">
248
+ <PageHeader
249
+ back={{ onClick: onBack }}
250
+ breadcrumbs={[
251
+ { label: mode === "global" ? "Globals" : "Collections" },
252
+ {
253
+ label: label,
254
+ href: mode === "collection" ? `${adminPath}/${slug}` : undefined
255
+ },
256
+ { label: mode === "global" ? "Edit" : documentId ? "Edit" : "New" }
257
+ ]}
258
+ title={
259
+ (mode === "global" ? label : (data[collection?.admin?.useAsTitle || "title"] as string || data.name as string || documentId || `New ${collection?.singularLabel || label}`))
260
+ }
261
+ metadata={[
262
+ <Badge
263
+ key="status"
264
+ variant={status === "published" ? "success" : "warning"}
265
+ dot
266
+ className="text-[10px] font-bold "
267
+ >
268
+ {status}
269
+ </Badge>
270
+ ]}
271
+ />
272
+
248
273
  {!isSingleLayout && (
274
+
249
275
  <ActionBar
250
276
  status={status}
251
277
  saveStatus={saveStatus}
@@ -254,11 +280,13 @@ export function DetailView({
254
280
  onPublish={handlePublish}
255
281
  onUnpublish={status === "published" ? handleUnpublish : undefined}
256
282
  onDuplicate={handleDuplicate}
257
- onViewHistory={() => {}}
283
+ onViewHistory={() => {
284
+ window.dispatchEvent(new CustomEvent('kyro:show-version-history'));
285
+ }}
258
286
  onPreview={() =>
259
287
  window.open(`/preview/${slug}/${documentId}`, "_blank")
260
288
  }
261
- onDelete={() => setShowDeleteConfirm(true)}
289
+ onDelete={handleDeleteTrigger}
262
290
  publishedAt={publishedAt}
263
291
  updatedAt={updatedAt}
264
292
  />
@@ -274,7 +302,7 @@ export function DetailView({
274
302
  <div className="space-y-8 min-w-0">
275
303
  <div className="surface-tile p-8">
276
304
  <div className="flex items-center justify-between mb-8 px-1">
277
- <h2 className="text-[10px] font-black uppercase tracking-[0.2em] opacity-40">
305
+ <h2 className="text-[10px] font-bold tracking-[0.2em] opacity-40">
278
306
  Core Configuration
279
307
  </h2>
280
308
  <div className="h-px flex-1 bg-[var(--kyro-border)] ml-6 opacity-30" />
@@ -288,8 +316,10 @@ export function DetailView({
288
316
  data={data}
289
317
  onChange={setData}
290
318
  layout={isSingleLayout ? "single" : "split"}
291
- onActionSuccess={(message) => addToast("success", message)}
292
- onActionError={(message) => addToast("error", message)}
319
+ globalSlug={mode === "global" ? slug : undefined}
320
+ collectionSlug={mode === "collection" ? slug : undefined}
321
+ onActionSuccess={(message) => addToast?.("success", message)}
322
+ onActionError={(message) => addToast?.("error", message)}
293
323
  documentStatus={status}
294
324
  justSaved={justSaved}
295
325
  />
@@ -298,8 +328,8 @@ export function DetailView({
298
328
  {mode === "collection" && documentId && (
299
329
  <button
300
330
  type="button"
301
- onClick={() => setShowDeleteConfirm(true)}
302
- className="px-6 py-3 text-red-500 rounded-2xl font-black text-sm hover:bg-red-500/10 active:scale-95 transition-all text-left"
331
+ onClick={handleDeleteTrigger}
332
+ className="kyro-btn kyro-btn-lg kyro-btn-ghost text-[var(--kyro-error)]"
303
333
  >
304
334
  Delete
305
335
  </button>
@@ -308,7 +338,7 @@ export function DetailView({
308
338
  type="button"
309
339
  onClick={() => handleSave(false)}
310
340
  disabled={saving}
311
- className="px-8 py-3 bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] rounded-2xl font-black text-sm shadow-xl hover:shadow-[var(--kyro-primary)] active:scale-95 transition-all flex items-center gap-2"
341
+ className="kyro-btn kyro-btn-lg kyro-btn-primary shadow-xl flex items-center gap-2"
312
342
  >
313
343
  {saving ? (
314
344
  <svg
@@ -347,51 +377,51 @@ export function DetailView({
347
377
  {!isSingleLayout && (
348
378
  <div className="space-y-6 animate-in fade-in slide-in-from-right-4 duration-500">
349
379
  <div className="surface-tile p-8">
350
- <h3 className="text-[10px] font-black uppercase tracking-[0.2em] opacity-40 mb-6">
380
+ <h3 className="text-[10px] font-bold tracking-[0.2em] opacity-40 mb-6">
351
381
  Metadata
352
382
  </h3>
353
383
  <div className="space-y-6">
354
384
  <div className="flex flex-col gap-2">
355
- <span className="text-[10px] font-black uppercase tracking-widest opacity-40">
385
+ <span className="text-[10px] font-bold tracking-widest opacity-40">
356
386
  Dynamic Status
357
387
  </span>
358
388
  <div>
359
389
  <span
360
- className={`inline-flex items-center px-3 py-1 rounded-full text-[9px] font-black uppercase tracking-widest ${status === "published" ? "bg-green-500/10 text-green-500" : "bg-amber-500/10 text-amber-500"}`}
390
+ className={`inline-flex items-center px-3 py-1 rounded-full text-[9px] font-bold tracking-widest ${status === "published" ? "bg-green-500/10 text-green-500" : "bg-amber-500/10 text-amber-500"}`}
361
391
  >
362
392
  {status || "draft"}
363
393
  </span>
364
394
  </div>
365
395
  </div>
366
396
  <div className="flex flex-col gap-2">
367
- <span className="text-[10px] font-black uppercase tracking-widest opacity-40">
397
+ <span className="text-[10px] font-bold tracking-widest opacity-40">
368
398
  Date Created
369
399
  </span>
370
400
  <span className="text-sm font-bold text-[var(--kyro-text-secondary)]">
371
401
  {createdAt
372
402
  ? new Date(createdAt).toLocaleString("en-US", {
373
- dateStyle: "medium",
374
- timeStyle: "short",
375
- })
403
+ dateStyle: "medium",
404
+ timeStyle: "short",
405
+ })
376
406
  : "N/A"}
377
407
  </span>
378
408
  </div>
379
409
  <div className="flex flex-col gap-2">
380
- <span className="text-[10px] font-black uppercase tracking-widest opacity-40">
410
+ <span className="text-[10px] font-bold tracking-widest opacity-40">
381
411
  Last Modified
382
412
  </span>
383
413
  <span className="text-sm font-bold text-[var(--kyro-text-secondary)]">
384
414
  {updatedAt
385
415
  ? new Date(updatedAt).toLocaleString("en-US", {
386
- dateStyle: "medium",
387
- timeStyle: "short",
388
- })
416
+ dateStyle: "medium",
417
+ timeStyle: "short",
418
+ })
389
419
  : "Just now"}
390
420
  </span>
391
421
  </div>
392
422
  {publishedAt && (
393
423
  <div className="flex flex-col gap-2">
394
- <span className="text-[10px] font-black uppercase tracking-widest opacity-40">
424
+ <span className="text-[10px] font-bold tracking-widest opacity-40">
395
425
  Public At
396
426
  </span>
397
427
  <span className="text-sm font-bold text-[var(--kyro-text-secondary)]">
@@ -406,25 +436,28 @@ export function DetailView({
406
436
  </div>
407
437
 
408
438
  <div className="surface-tile p-8 bg-[var(--kyro-bg-secondary)]">
409
- <h3 className="text-[10px] font-black uppercase tracking-[0.2em] opacity-40 mb-4">
439
+ <h3 className="text-[10px] font-bold tracking-[0.2em] opacity-40 mb-4">
410
440
  Quick Links
411
441
  </h3>
412
442
  <div className="space-y-3">
413
443
  <button
414
444
  type="button"
415
- className="w-full text-left px-4 py-2 rounded-xl text-xs font-bold hover:bg-[var(--kyro-bg-secondary)] transition-colors"
445
+ onClick={handleDuplicate}
446
+ className="kyro-btn kyro-btn-sm kyro-btn-ghost w-full justify-start"
416
447
  >
417
448
  Duplicate Document
418
449
  </button>
419
450
  <button
420
451
  type="button"
421
- className="w-full text-left px-4 py-2 rounded-xl text-xs font-bold hover:bg-[var(--kyro-bg-secondary)] transition-colors"
452
+ onClick={() => window.open(`/preview/${slug}/${documentId}`, "_blank")}
453
+ className="kyro-btn kyro-btn-sm kyro-btn-ghost w-full justify-start"
422
454
  >
423
455
  View Public Page
424
456
  </button>
425
457
  <button
426
458
  type="button"
427
- className="w-full text-left px-4 py-2 rounded-xl text-xs font-bold text-red-500 hover:bg-red-500/10 transition-colors"
459
+ onClick={handleDeleteTrigger}
460
+ className="kyro-btn kyro-btn-sm kyro-btn-ghost w-full justify-start text-[var(--kyro-error)] hover:bg-[var(--kyro-danger-bg)]"
428
461
  >
429
462
  Delete Entry
430
463
  </button>
@@ -433,17 +466,6 @@ export function DetailView({
433
466
  </div>
434
467
  )}
435
468
  </div>
436
-
437
- <ConfirmModal
438
- open={showDeleteConfirm}
439
- onClose={() => setShowDeleteConfirm(false)}
440
- onConfirm={handleDelete}
441
- title={`Delete ${label}?`}
442
- message="This action cannot be undone."
443
- confirmLabel="Delete"
444
- variant="danger"
445
- loading={deleting}
446
- />
447
469
  </div>
448
470
  );
449
471
  }