@kyro-cms/admin 0.1.6 → 0.1.7
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/README.md +149 -51
- package/package.json +53 -6
- package/src/collections/auth/index.ts +2 -2
- package/src/collections/portfolio/index.ts +343 -0
- package/src/components/ActionBar.tsx +153 -16
- package/src/components/Admin.tsx +136 -27
- package/src/components/ApiExplorer.tsx +325 -0
- package/src/components/ApiKeysManager.tsx +563 -0
- package/src/components/AuditLogsPage.tsx +664 -0
- package/src/components/AutoForm.tsx +1417 -661
- package/src/components/BrandingHub.tsx +267 -0
- package/src/components/BulkActionsBar.tsx +3 -3
- package/src/components/CreateView.tsx +3 -3
- package/src/components/Dashboard.tsx +393 -0
- package/src/components/DetailView.tsx +199 -57
- package/src/components/DeveloperCenter.tsx +403 -0
- package/src/components/EnhancedListView.tsx +786 -0
- package/src/components/GraphQLExplorer.tsx +675 -0
- package/src/components/GraphQLPlayground.tsx +627 -0
- package/src/components/ListView.tsx +191 -53
- package/src/components/MediaGallery.tsx +1569 -0
- package/src/components/Modal.tsx +149 -0
- package/src/components/RestPlayground.tsx +951 -0
- package/src/components/Sidebar.astro +237 -0
- package/src/components/UserManagement.tsx +204 -0
- package/src/components/VersionHistoryPanel.tsx +3 -3
- package/src/components/WebhookManager.tsx +608 -0
- package/src/components/blocks/AccordionBlock.tsx +97 -0
- package/src/components/blocks/ArrayBlock.tsx +75 -0
- package/src/components/blocks/BlockEditModal.MARKER +12 -0
- package/src/components/blocks/BlockEditModal.tsx +774 -0
- package/src/components/blocks/ButtonBlock.tsx +165 -0
- package/src/components/blocks/ChildBlocksTree.tsx +551 -0
- package/src/components/blocks/CodeBlock.tsx +66 -0
- package/src/components/blocks/ColumnsBlock.tsx +151 -0
- package/src/components/blocks/DividerBlock.tsx +43 -0
- package/src/components/blocks/FileBlock.tsx +64 -0
- package/src/components/blocks/HeadingBlock.tsx +81 -0
- package/src/components/blocks/HeroBlock.tsx +157 -0
- package/src/components/blocks/ImageBlock.tsx +83 -0
- package/src/components/blocks/LinkBlock.tsx +71 -0
- package/src/components/blocks/ListBlock.tsx +39 -0
- package/src/components/blocks/ParagraphBlock.tsx +61 -0
- package/src/components/blocks/RelationshipBlock.tsx +279 -0
- package/src/components/blocks/VStackBlock.tsx +75 -0
- package/src/components/blocks/VideoBlock.tsx +45 -0
- package/src/components/blocks/index.ts +10 -0
- package/src/components/fields/BlocksField.tsx +323 -0
- package/src/components/fields/CheckboxField.tsx +15 -9
- package/src/components/fields/CodeField.tsx +234 -0
- package/src/components/fields/DateField.tsx +38 -11
- package/src/components/fields/EditorClient.tsx +271 -0
- package/src/components/fields/FileField.tsx +390 -0
- package/src/components/fields/HybridContentField.tsx +109 -0
- package/src/components/fields/ImageField.tsx +429 -0
- package/src/components/fields/JSONField.tsx +361 -0
- package/src/components/fields/MarkdownField.tsx +282 -0
- package/src/components/fields/NumberField.tsx +42 -12
- package/src/components/fields/PortableTextField.tsx +143 -0
- package/src/components/fields/PortableTextRenderer.tsx +68 -0
- package/src/components/fields/RelationshipField.tsx +231 -59
- package/src/components/fields/SelectField.tsx +25 -15
- package/src/components/fields/TextField.tsx +45 -14
- package/src/components/fields/extensions/blockComponents.tsx +237 -0
- package/src/components/fields/extensions/blocksStore.ts +273 -0
- package/src/components/fields/index.ts +13 -0
- package/src/components/index.ts +1 -2
- package/src/components/layout/Header.tsx +2 -2
- package/src/components/layout/Layout.tsx +2 -2
- package/src/components/ui/Badge.tsx +9 -4
- package/src/components/ui/BlockDrawer.tsx +79 -0
- package/src/components/ui/Button.tsx +1 -1
- package/src/components/ui/CommandPalette.tsx +362 -0
- package/src/components/ui/CommandPaletteWrapper.tsx +97 -0
- package/src/components/ui/Dropdown.tsx +1 -1
- package/src/components/ui/Modal.tsx +37 -12
- package/src/components/ui/PromptModal.tsx +94 -0
- package/src/components/ui/SlidePanel.tsx +43 -16
- package/src/components/ui/Toast.tsx +80 -14
- package/src/env.d.ts +16 -0
- package/src/env.ts +20 -0
- package/src/index.ts +0 -1
- package/src/layouts/AdminLayout.astro +164 -170
- package/src/layouts/AuthLayout.astro +23 -6
- package/src/lib/MediaService.ts +541 -0
- package/src/lib/auth/sqlite-adapter.ts +319 -0
- package/src/lib/config.ts +22 -6
- package/src/lib/dataStore.ts +132 -74
- package/src/lib/db/adapter.ts +54 -0
- package/src/lib/db/drizzle-mysql-adapter.ts +194 -0
- package/src/lib/db/drizzle-mysql-auth-adapter.ts +327 -0
- package/src/lib/db/drizzle-postgres-adapter.ts +202 -0
- package/src/lib/db/drizzle-postgres-auth-adapter.ts +304 -0
- package/src/lib/db/drizzle-sqlite-adapter.ts +227 -0
- package/src/lib/db/drizzle-sqlite-auth-adapter.ts +548 -0
- package/src/lib/db/index.ts +449 -0
- package/src/lib/db/mongodb-adapter.ts +207 -0
- package/src/lib/db/mongodb-auth-adapter.ts +305 -0
- package/src/lib/db/schema/mysql-auth.ts +113 -0
- package/src/lib/db/schema/mysql-content.ts +20 -0
- package/src/lib/db/schema/postgres-auth.ts +116 -0
- package/src/lib/db/schema/postgres-content.ts +35 -0
- package/src/lib/db/schema/postgres-media.ts +52 -0
- package/src/lib/db/schema/postgres-settings.ts +11 -0
- package/src/lib/db/schema/sqlite-auth.ts +112 -0
- package/src/lib/db/schema/sqlite-content.ts +20 -0
- package/src/lib/graphql/index.ts +1 -0
- package/src/lib/graphql/schema.ts +443 -0
- package/src/lib/rate-limit.ts +267 -0
- package/src/lib/storage.ts +374 -0
- package/src/lib/store.ts +85 -0
- package/src/middleware.ts +70 -11
- package/src/pages/[collection]/[id].astro +178 -122
- package/src/pages/[collection]/index.astro +24 -156
- package/src/pages/admin/api-explorer.astro +98 -0
- package/src/pages/admin/graphql-explorer.astro +40 -0
- package/src/pages/admin/graphql.astro +97 -0
- package/src/pages/admin/index.astro +200 -139
- package/src/pages/admin/keys.astro +8 -0
- package/src/pages/admin/rest-playground.astro +44 -0
- package/src/pages/admin/webhooks.astro +8 -0
- package/src/pages/api/[collection]/[id]/publish.ts +44 -0
- package/src/pages/api/[collection]/[id]/unpublish.ts +42 -0
- package/src/pages/api/[collection]/[id]/versions.ts +36 -0
- package/src/pages/api/[collection]/[id].ts +102 -159
- package/src/pages/api/[collection]/index.ts +151 -230
- package/src/pages/api/auth/[id].ts +48 -69
- package/src/pages/api/auth/audit-logs.ts +20 -43
- package/src/pages/api/auth/login.ts +159 -45
- package/src/pages/api/auth/logout.ts +42 -24
- package/src/pages/api/auth/refresh.ts +119 -0
- package/src/pages/api/auth/register.ts +110 -40
- package/src/pages/api/auth/users.ts +22 -97
- package/src/pages/api/collections.ts +59 -0
- package/src/pages/api/globals/[slug]/test.ts +172 -0
- package/src/pages/api/globals/[slug].ts +42 -0
- package/src/pages/api/graphql.ts +90 -0
- package/src/pages/api/health.ts +417 -40
- package/src/pages/api/keys/[id].ts +26 -0
- package/src/pages/api/keys/index.ts +75 -0
- package/src/pages/api/media/[id].ts +309 -0
- package/src/pages/api/media/folders.ts +609 -0
- package/src/pages/api/media/index.ts +146 -0
- package/src/pages/api/media/resize.ts +267 -0
- package/src/pages/api/search.ts +82 -0
- package/src/pages/api/slug-availability.ts +70 -0
- package/src/pages/api/storage-config.ts +20 -0
- package/src/pages/api/storage-status.ts +206 -0
- package/src/pages/api/upload.ts +334 -0
- package/src/pages/api/webhooks/index.ts +71 -0
- package/src/pages/audit/index.astro +2 -104
- package/src/pages/login.astro +11 -11
- package/src/pages/media.astro +10 -0
- package/src/pages/preview/[collection]/[id].astro +178 -0
- package/src/pages/register.astro +13 -13
- package/src/pages/roles/index.astro +21 -21
- package/src/pages/settings/[slug].astro +162 -0
- package/src/pages/settings/index.astro +9 -0
- package/src/pages/users/[id].astro +29 -21
- package/src/pages/users/index.astro +22 -17
- package/src/pages/users/new.astro +18 -17
- package/src/styles/main.css +553 -128
- package/src/components/layout/Sidebar.tsx +0 -497
|
@@ -8,6 +8,7 @@ import { AutoForm } from "./AutoForm";
|
|
|
8
8
|
import { ActionBar, type DocumentStatus, type SaveStatus } from "./ActionBar";
|
|
9
9
|
import { ConfirmModal } from "./ui/Modal";
|
|
10
10
|
import { Spinner } from "./ui/Spinner";
|
|
11
|
+
import { useToast } from "./ui/Toast";
|
|
11
12
|
|
|
12
13
|
interface DetailViewProps {
|
|
13
14
|
config: KyroConfig;
|
|
@@ -36,6 +37,7 @@ export function DetailView({
|
|
|
36
37
|
autosave = true,
|
|
37
38
|
autosaveDelay = 2000,
|
|
38
39
|
}: DetailViewProps) {
|
|
40
|
+
const { addToast } = useToast();
|
|
39
41
|
const [data, setData] = useState<Record<string, unknown>>({});
|
|
40
42
|
const [originalData, setOriginalData] = useState<Record<string, unknown>>({});
|
|
41
43
|
const [loading, setLoading] = useState(true);
|
|
@@ -47,6 +49,7 @@ export function DetailView({
|
|
|
47
49
|
const [createdAt, setCreatedAt] = useState<string | null>(null);
|
|
48
50
|
const [updatedAt, setUpdatedAt] = useState<string | null>(null);
|
|
49
51
|
const [publishedAt, setPublishedAt] = useState<string | null>(null);
|
|
52
|
+
const [justSaved, setJustSaved] = useState(false);
|
|
50
53
|
|
|
51
54
|
const autosaveTimerRef = useRef<NodeJS.Timeout | null>(null);
|
|
52
55
|
const hasChangesRef = useRef(false);
|
|
@@ -57,6 +60,19 @@ export function DetailView({
|
|
|
57
60
|
|
|
58
61
|
const hasChanges = JSON.stringify(data) !== JSON.stringify(originalData);
|
|
59
62
|
|
|
63
|
+
// Auto-set status to draft when there are changes from a published state
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (hasChanges && status === "published") {
|
|
66
|
+
setStatus("draft");
|
|
67
|
+
}
|
|
68
|
+
}, [hasChanges, status]);
|
|
69
|
+
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
if (hasChanges && saveStatus === "saved") {
|
|
72
|
+
setSaveStatus("idle");
|
|
73
|
+
}
|
|
74
|
+
}, [hasChanges, saveStatus]);
|
|
75
|
+
|
|
60
76
|
useEffect(() => {
|
|
61
77
|
if (mode === "global") {
|
|
62
78
|
loadGlobal();
|
|
@@ -150,6 +166,14 @@ export function DetailView({
|
|
|
150
166
|
setSaveStatus("saved");
|
|
151
167
|
setUpdatedAt(new Date().toISOString());
|
|
152
168
|
|
|
169
|
+
// Show green border for 3 seconds after any save
|
|
170
|
+
setJustSaved(true);
|
|
171
|
+
setTimeout(() => setJustSaved(false), 3000);
|
|
172
|
+
|
|
173
|
+
if (!isAutosave) {
|
|
174
|
+
addToast("success", "Saved successfully");
|
|
175
|
+
}
|
|
176
|
+
|
|
153
177
|
setTimeout(() => {
|
|
154
178
|
setSaveStatus("idle");
|
|
155
179
|
}, 2000);
|
|
@@ -157,6 +181,7 @@ export function DetailView({
|
|
|
157
181
|
setSaveStatus("error");
|
|
158
182
|
if (!isAutosave) {
|
|
159
183
|
onError("Failed to save changes");
|
|
184
|
+
addToast("error", "Failed to save changes");
|
|
160
185
|
}
|
|
161
186
|
} finally {
|
|
162
187
|
setSaving(false);
|
|
@@ -174,8 +199,10 @@ export function DetailView({
|
|
|
174
199
|
if (!response.ok) throw new Error("Failed to publish");
|
|
175
200
|
setStatus("published");
|
|
176
201
|
setPublishedAt(new Date().toISOString());
|
|
202
|
+
addToast("success", "Published successfully");
|
|
177
203
|
} catch {
|
|
178
204
|
onError("Failed to publish");
|
|
205
|
+
addToast("error", "Failed to publish");
|
|
179
206
|
} finally {
|
|
180
207
|
setSaving(false);
|
|
181
208
|
}
|
|
@@ -235,30 +262,45 @@ export function DetailView({
|
|
|
235
262
|
);
|
|
236
263
|
}
|
|
237
264
|
|
|
265
|
+
const isSingleLayout =
|
|
266
|
+
mode === "global" || collection?.admin?.layout === "single";
|
|
267
|
+
|
|
238
268
|
return (
|
|
239
269
|
<div className="kyro-detail">
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
270
|
+
{!isSingleLayout && (
|
|
271
|
+
<ActionBar
|
|
272
|
+
status={status}
|
|
273
|
+
saveStatus={saveStatus}
|
|
274
|
+
hasChanges={hasChanges}
|
|
275
|
+
onSave={() => handleSave(false)}
|
|
276
|
+
onPublish={handlePublish}
|
|
277
|
+
onUnpublish={status === "published" ? handleUnpublish : undefined}
|
|
278
|
+
onDuplicate={handleDuplicate}
|
|
279
|
+
onViewHistory={() => {}}
|
|
280
|
+
onPreview={() =>
|
|
281
|
+
window.open(`/preview/${slug}/${documentId}`, "_blank")
|
|
282
|
+
}
|
|
283
|
+
onDelete={() => setShowDeleteConfirm(true)}
|
|
284
|
+
publishedAt={publishedAt}
|
|
285
|
+
updatedAt={updatedAt}
|
|
286
|
+
/>
|
|
287
|
+
)}
|
|
258
288
|
|
|
259
|
-
<div
|
|
260
|
-
|
|
261
|
-
|
|
289
|
+
<div
|
|
290
|
+
className={
|
|
291
|
+
isSingleLayout
|
|
292
|
+
? "w-full pb-32 pt-8"
|
|
293
|
+
: "w-full mx-auto grid grid-cols-1 lg:grid-cols-[1fr_360px] gap-8 pb-32"
|
|
294
|
+
}
|
|
295
|
+
>
|
|
296
|
+
<div className="space-y-8 min-w-0">
|
|
297
|
+
<div className="surface-tile p-8">
|
|
298
|
+
<div className="flex items-center justify-between mb-8 px-1">
|
|
299
|
+
<h2 className="text-[10px] font-black uppercase tracking-[0.2em] opacity-40">
|
|
300
|
+
Core Configuration
|
|
301
|
+
</h2>
|
|
302
|
+
<div className="h-px flex-1 bg-[var(--kyro-border)] ml-6 opacity-30" />
|
|
303
|
+
</div>
|
|
262
304
|
<AutoForm
|
|
263
305
|
config={
|
|
264
306
|
collection
|
|
@@ -267,51 +309,151 @@ export function DetailView({
|
|
|
267
309
|
}
|
|
268
310
|
data={data}
|
|
269
311
|
onChange={setData}
|
|
312
|
+
layout={isSingleLayout ? "single" : "split"}
|
|
313
|
+
onActionSuccess={(message) => addToast("success", message)}
|
|
314
|
+
onActionError={(message) => addToast("error", message)}
|
|
315
|
+
documentStatus={status}
|
|
316
|
+
justSaved={justSaved}
|
|
270
317
|
/>
|
|
318
|
+
{isSingleLayout && (
|
|
319
|
+
<div className="mt-8 pt-8 border-t border-[var(--kyro-border)] flex justify-end gap-3">
|
|
320
|
+
{mode === "collection" && documentId && (
|
|
321
|
+
<button
|
|
322
|
+
type="button"
|
|
323
|
+
onClick={() => setShowDeleteConfirm(true)}
|
|
324
|
+
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"
|
|
325
|
+
>
|
|
326
|
+
Delete
|
|
327
|
+
</button>
|
|
328
|
+
)}
|
|
329
|
+
<button
|
|
330
|
+
type="button"
|
|
331
|
+
onClick={() => handleSave(false)}
|
|
332
|
+
disabled={saving}
|
|
333
|
+
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"
|
|
334
|
+
>
|
|
335
|
+
{saving ? (
|
|
336
|
+
<svg
|
|
337
|
+
className="w-4 h-4 animate-spin"
|
|
338
|
+
viewBox="0 0 24 24"
|
|
339
|
+
fill="none"
|
|
340
|
+
stroke="currentColor"
|
|
341
|
+
strokeWidth="2"
|
|
342
|
+
>
|
|
343
|
+
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
|
344
|
+
</svg>
|
|
345
|
+
) : (
|
|
346
|
+
<svg
|
|
347
|
+
className="w-4 h-4"
|
|
348
|
+
viewBox="0 0 24 24"
|
|
349
|
+
fill="none"
|
|
350
|
+
stroke="currentColor"
|
|
351
|
+
strokeWidth="2"
|
|
352
|
+
>
|
|
353
|
+
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" />
|
|
354
|
+
<polyline points="17 21 17 13 7 13 7 21" />
|
|
355
|
+
<polyline points="7 3 7 8 15 8" />
|
|
356
|
+
</svg>
|
|
357
|
+
)}
|
|
358
|
+
{saving
|
|
359
|
+
? "Saving..."
|
|
360
|
+
: mode === "global"
|
|
361
|
+
? "Save Configuration"
|
|
362
|
+
: "Save Document"}
|
|
363
|
+
</button>
|
|
364
|
+
</div>
|
|
365
|
+
)}
|
|
271
366
|
</div>
|
|
272
367
|
</div>
|
|
273
368
|
|
|
274
|
-
|
|
275
|
-
<div className="
|
|
276
|
-
<div className="
|
|
277
|
-
<h3 className="
|
|
369
|
+
{!isSingleLayout && (
|
|
370
|
+
<div className="space-y-6 animate-in fade-in slide-in-from-right-4 duration-500">
|
|
371
|
+
<div className="surface-tile p-8">
|
|
372
|
+
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] opacity-40 mb-6">
|
|
373
|
+
Metadata
|
|
374
|
+
</h3>
|
|
375
|
+
<div className="space-y-6">
|
|
376
|
+
<div className="flex flex-col gap-2">
|
|
377
|
+
<span className="text-[10px] font-black uppercase tracking-widest opacity-40">
|
|
378
|
+
Dynamic Status
|
|
379
|
+
</span>
|
|
380
|
+
<div>
|
|
381
|
+
<span
|
|
382
|
+
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"}`}
|
|
383
|
+
>
|
|
384
|
+
{status || "draft"}
|
|
385
|
+
</span>
|
|
386
|
+
</div>
|
|
387
|
+
</div>
|
|
388
|
+
<div className="flex flex-col gap-2">
|
|
389
|
+
<span className="text-[10px] font-black uppercase tracking-widest opacity-40">
|
|
390
|
+
Date Created
|
|
391
|
+
</span>
|
|
392
|
+
<span className="text-sm font-bold text-[var(--kyro-text-secondary)]">
|
|
393
|
+
{createdAt
|
|
394
|
+
? new Date(createdAt).toLocaleString("en-US", {
|
|
395
|
+
dateStyle: "medium",
|
|
396
|
+
timeStyle: "short",
|
|
397
|
+
})
|
|
398
|
+
: "N/A"}
|
|
399
|
+
</span>
|
|
400
|
+
</div>
|
|
401
|
+
<div className="flex flex-col gap-2">
|
|
402
|
+
<span className="text-[10px] font-black uppercase tracking-widest opacity-40">
|
|
403
|
+
Last Modified
|
|
404
|
+
</span>
|
|
405
|
+
<span className="text-sm font-bold text-[var(--kyro-text-secondary)]">
|
|
406
|
+
{updatedAt
|
|
407
|
+
? new Date(updatedAt).toLocaleString("en-US", {
|
|
408
|
+
dateStyle: "medium",
|
|
409
|
+
timeStyle: "short",
|
|
410
|
+
})
|
|
411
|
+
: "Just now"}
|
|
412
|
+
</span>
|
|
413
|
+
</div>
|
|
414
|
+
{publishedAt && (
|
|
415
|
+
<div className="flex flex-col gap-2">
|
|
416
|
+
<span className="text-[10px] font-black uppercase tracking-widest opacity-40">
|
|
417
|
+
Public At
|
|
418
|
+
</span>
|
|
419
|
+
<span className="text-sm font-bold text-[var(--kyro-text-secondary)]">
|
|
420
|
+
{new Date(publishedAt).toLocaleString("en-US", {
|
|
421
|
+
dateStyle: "medium",
|
|
422
|
+
timeStyle: "short",
|
|
423
|
+
})}
|
|
424
|
+
</span>
|
|
425
|
+
</div>
|
|
426
|
+
)}
|
|
427
|
+
</div>
|
|
278
428
|
</div>
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
429
|
+
|
|
430
|
+
<div className="surface-tile p-8 bg-[var(--kyro-bg-secondary)]">
|
|
431
|
+
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] opacity-40 mb-4">
|
|
432
|
+
Quick Links
|
|
433
|
+
</h3>
|
|
434
|
+
<div className="space-y-3">
|
|
435
|
+
<button
|
|
436
|
+
type="button"
|
|
437
|
+
className="w-full text-left px-4 py-2 rounded-xl text-xs font-bold hover:bg-[var(--kyro-bg-secondary)] transition-colors"
|
|
288
438
|
>
|
|
289
|
-
|
|
290
|
-
</
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
</
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
</
|
|
439
|
+
Duplicate Document
|
|
440
|
+
</button>
|
|
441
|
+
<button
|
|
442
|
+
type="button"
|
|
443
|
+
className="w-full text-left px-4 py-2 rounded-xl text-xs font-bold hover:bg-[var(--kyro-bg-secondary)] transition-colors"
|
|
444
|
+
>
|
|
445
|
+
View Public Page
|
|
446
|
+
</button>
|
|
447
|
+
<button
|
|
448
|
+
type="button"
|
|
449
|
+
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"
|
|
450
|
+
>
|
|
451
|
+
Delete Entry
|
|
452
|
+
</button>
|
|
303
453
|
</div>
|
|
304
|
-
{publishedAt && (
|
|
305
|
-
<div className="kyro-meta-item">
|
|
306
|
-
<span className="kyro-meta-label">Published</span>
|
|
307
|
-
<span className="kyro-meta-value">
|
|
308
|
-
{new Date(publishedAt).toLocaleString()}
|
|
309
|
-
</span>
|
|
310
|
-
</div>
|
|
311
|
-
)}
|
|
312
454
|
</div>
|
|
313
455
|
</div>
|
|
314
|
-
|
|
456
|
+
)}
|
|
315
457
|
</div>
|
|
316
458
|
|
|
317
459
|
<ConfirmModal
|