@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.
- package/dist/EditorClient-XEUOVAAC.js +466 -0
- package/dist/EditorClient-XEUOVAAC.js.map +1 -0
- package/dist/EditorClient-YLCGVDXY.cjs +468 -0
- package/dist/EditorClient-YLCGVDXY.cjs.map +1 -0
- package/dist/chunk-7KPIUCGT.js +384 -0
- package/dist/chunk-7KPIUCGT.js.map +1 -0
- package/dist/chunk-GOACG6R7.cjs +473 -0
- package/dist/chunk-GOACG6R7.cjs.map +1 -0
- package/dist/index.cjs +14861 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +1661 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +563 -0
- package/dist/index.js +14784 -0
- package/dist/index.js.map +1 -0
- package/package.json +19 -19
- package/src/components/ActionBar.tsx +7 -43
- package/src/components/Admin.tsx +138 -277
- package/src/components/ApiKeysManager.tsx +428 -419
- package/src/components/AuditLogsPage.tsx +35 -39
- package/src/components/AuthBridge.tsx +51 -0
- package/src/components/AutoForm.tsx +495 -1230
- package/src/components/BrandingHub.tsx +18 -19
- package/src/components/BulkActionsBar.tsx +1 -1
- package/src/components/CreateView.tsx +22 -36
- package/src/components/Dashboard.tsx +60 -84
- package/src/components/DetailView.tsx +113 -91
- package/src/components/DeveloperCenter.tsx +200 -198
- package/src/components/FieldRenderer.tsx +206 -0
- package/src/components/GraphQLPlayground.tsx +340 -480
- package/src/components/ListView.tsx +828 -254
- package/src/components/LoginPage.tsx +3 -4
- package/src/components/MarketplaceManager.tsx +254 -0
- package/src/components/MediaGallery.tsx +856 -1192
- package/src/components/PluginsManager.tsx +277 -0
- package/src/components/RestPlayground.tsx +398 -560
- package/src/components/SessionsManager.tsx +211 -0
- package/src/components/Sidebar.astro +179 -151
- package/src/components/ThemeProvider.tsx +7 -161
- package/src/components/UserManagement.tsx +162 -146
- package/src/components/UserMenu.tsx +110 -0
- package/src/components/WebhookManager.tsx +305 -367
- package/src/components/blocks/AccordionBlock.tsx +4 -4
- package/src/components/blocks/ArrayBlock.tsx +3 -3
- package/src/components/blocks/BlockEditModal.tsx +8 -8
- package/src/components/blocks/BlockWrapper.tsx +61 -0
- package/src/components/blocks/ButtonBlock.tsx +4 -4
- package/src/components/blocks/ChildBlocksTree.tsx +23 -25
- package/src/components/blocks/CodeBlock.tsx +15 -15
- package/src/components/blocks/ColumnsBlock.tsx +6 -44
- package/src/components/blocks/DividerBlock.tsx +3 -3
- package/src/components/blocks/FileBlock.tsx +4 -4
- package/src/components/blocks/HeadingBlock.tsx +6 -38
- package/src/components/blocks/HeroBlock.tsx +4 -4
- package/src/components/blocks/ImageBlock.tsx +4 -4
- package/src/components/blocks/LinkBlock.tsx +4 -4
- package/src/components/blocks/ListBlock.tsx +3 -3
- package/src/components/blocks/ParagraphBlock.tsx +12 -42
- package/src/components/blocks/RelationshipBlock.tsx +4 -4
- package/src/components/blocks/RichTextBlock.tsx +4 -4
- package/src/components/blocks/VStackBlock.tsx +5 -37
- package/src/components/blocks/VideoBlock.tsx +4 -4
- package/src/components/blocks/types.ts +11 -0
- package/src/components/fields/AccordionField.tsx +1 -1
- package/src/components/fields/ArrayField.tsx +2 -2
- package/src/components/fields/ArrayLayout.tsx +93 -0
- package/src/components/fields/BlocksField.tsx +122 -111
- package/src/components/fields/ButtonField.tsx +1 -1
- package/src/components/fields/CheckboxField.tsx +14 -15
- package/src/components/fields/ChildrenField.tsx +2 -2
- package/src/components/fields/CodeField.tsx +3 -3
- package/src/components/fields/ColumnsField.tsx +2 -2
- package/src/components/fields/DateField.tsx +13 -26
- package/src/components/fields/EditorClient.tsx +26 -28
- package/src/components/fields/FieldLayout.tsx +52 -0
- package/src/components/fields/GroupLayout.tsx +35 -0
- package/src/components/fields/JSONField.tsx +7 -7
- package/src/components/fields/LinkField.tsx +1 -1
- package/src/components/fields/MarkdownField.tsx +1 -1
- package/src/components/fields/NumberField.tsx +13 -26
- package/src/components/fields/PortableTextField.tsx +4 -4
- package/src/components/fields/PortableTextRenderer.tsx +1 -1
- package/src/components/fields/RelationshipBlockField.tsx +31 -23
- package/src/components/fields/RelationshipField.tsx +14 -14
- package/src/components/fields/SelectField.tsx +17 -26
- package/src/components/fields/TabsLayout.tsx +69 -0
- package/src/components/fields/TextField.tsx +85 -38
- package/src/components/fields/UploadField.tsx +71 -41
- package/src/components/fields/VideoField.tsx +1 -1
- package/src/components/fields/extensions/blockComponents.tsx +2 -2
- package/src/components/fields/extensions/blocksStore.ts +207 -193
- package/src/components/fields/types.ts +22 -0
- package/src/components/layout/Layout.tsx +1 -1
- package/src/components/ui/ActionMenu.tsx +63 -0
- package/src/components/ui/Badge.tsx +59 -5
- package/src/components/ui/BlockDrawer.tsx +4 -5
- package/src/components/ui/CommandPalette.tsx +58 -36
- package/src/components/ui/CommandPaletteWrapper.tsx +18 -17
- package/src/components/ui/Dropdown.tsx +18 -16
- package/src/components/ui/EmptyState.tsx +25 -0
- package/src/components/ui/GlobalModal.tsx +49 -0
- package/src/components/ui/IconButton.tsx +44 -0
- package/src/components/ui/Modal.tsx +19 -20
- package/src/components/ui/PageHeader.tsx +158 -0
- package/src/components/ui/Pagination.tsx +61 -0
- package/src/components/ui/PromptModal.tsx +1 -1
- package/src/components/ui/SearchInput.tsx +57 -0
- package/src/components/ui/SeoPreview.tsx +31 -0
- package/src/components/ui/SessionModal.tsx +0 -0
- package/src/components/ui/SlidePanel.tsx +2 -0
- package/src/components/ui/Toast.tsx +65 -122
- package/src/components/ui/Toaster.tsx +18 -0
- package/src/components/ui/icons.tsx +112 -0
- package/src/components/users/UserDetail.tsx +290 -0
- package/src/components/users/UserForm.tsx +242 -0
- package/src/components/users/UsersList.tsx +338 -0
- package/src/env.d.ts +13 -13
- package/src/fields/index.ts +2 -1
- package/src/global.d.ts +7 -0
- package/src/hooks/data.ts +2 -9
- package/src/hooks/useAsyncData.ts +36 -0
- package/src/hooks/useAutoFormState.ts +527 -0
- package/src/hooks/useSelection.ts +49 -0
- package/src/hooks/useSession.ts +0 -0
- package/src/index.ts +11 -1
- package/src/integration.ts +86 -11
- package/src/kyro-cms.d.ts +209 -0
- package/src/layouts/AdminLayout.astro +128 -11
- package/src/layouts/AuthLayout.astro +21 -5
- package/src/lib/api.ts +175 -55
- package/src/lib/autoform-store.ts +435 -0
- package/src/lib/config.ts +82 -34
- package/src/lib/createRegistry.ts +29 -0
- package/src/lib/default-kyro-config.ts +4 -0
- package/src/lib/globals.ts +50 -0
- package/src/lib/media-utils.ts +18 -0
- package/src/lib/object-utils.ts +77 -0
- package/src/lib/paths.ts +61 -0
- package/src/lib/stores/index.ts +370 -0
- package/src/lib/types.ts +43 -0
- package/src/lib/useResourceManager.ts +105 -0
- package/src/pages/403.astro +67 -0
- package/src/pages/[collection]/[id].astro +14 -180
- package/src/pages/[collection]/index.astro +11 -6
- package/src/pages/api-explorer.astro +173 -0
- package/src/pages/audit/index.astro +2 -0
- package/src/pages/auth/login.astro +122 -0
- package/src/pages/auth/register.astro +167 -0
- package/src/pages/graphql-explorer.astro +59 -0
- package/src/pages/{admin/graphql.astro → graphql.astro} +51 -17
- package/src/pages/index.astro +577 -0
- package/src/pages/index_ALT.astro +3 -0
- package/src/pages/keys.astro +11 -0
- package/src/pages/marketplace.astro +11 -0
- package/src/pages/media.astro +3 -0
- package/src/pages/plugins.astro +8 -0
- package/src/pages/preview/[collection]/[id].astro +188 -123
- package/src/pages/rest-playground.astro +62 -0
- package/src/pages/roles/index.astro +183 -76
- package/src/pages/sessions.astro +8 -0
- package/src/pages/settings/[slug].astro +92 -114
- package/src/pages/settings/index.astro +5 -3
- package/src/pages/users/[id].astro +25 -154
- package/src/pages/users/index.astro +19 -130
- package/src/pages/users/new.astro +9 -86
- package/src/pages/webhooks.astro +11 -0
- package/src/routes.ts +80 -0
- package/src/styles/main.css +119 -79
- package/src/theme/tokens.ts +1 -0
- package/src/vite-env.d.ts +14 -0
- package/src/collections/auth/index.ts +0 -155
- package/src/collections/portfolio/index.ts +0 -343
- package/src/components/ApiExplorer.tsx +0 -325
- package/src/components/EnhancedListView.tsx +0 -889
- package/src/components/GraphQLExplorer.tsx +0 -675
- package/src/components/Icons.tsx +0 -23
- package/src/components/StatusBadge.tsx +0 -76
- package/src/lib/MediaService.ts +0 -541
- package/src/lib/auth/sqlite-adapter.ts +0 -319
- package/src/lib/dataStore.ts +0 -226
- package/src/lib/db/adapter.ts +0 -54
- package/src/lib/db/drizzle-mysql-adapter.ts +0 -194
- package/src/lib/db/drizzle-mysql-auth-adapter.ts +0 -327
- package/src/lib/db/drizzle-postgres-adapter.ts +0 -202
- package/src/lib/db/drizzle-postgres-auth-adapter.ts +0 -304
- package/src/lib/db/drizzle-sqlite-adapter.ts +0 -227
- package/src/lib/db/drizzle-sqlite-auth-adapter.ts +0 -548
- package/src/lib/db/index.ts +0 -449
- package/src/lib/db/mongodb-adapter.ts +0 -207
- package/src/lib/db/mongodb-auth-adapter.ts +0 -305
- package/src/lib/db/schema/mysql-auth.ts +0 -113
- package/src/lib/db/schema/mysql-content.ts +0 -20
- package/src/lib/db/schema/postgres-auth.ts +0 -116
- package/src/lib/db/schema/postgres-content.ts +0 -35
- package/src/lib/db/schema/postgres-media.ts +0 -52
- package/src/lib/db/schema/postgres-settings.ts +0 -11
- package/src/lib/db/schema/sqlite-auth.ts +0 -112
- package/src/lib/db/schema/sqlite-content.ts +0 -20
- package/src/lib/db/version-adapter.ts +0 -248
- package/src/lib/graphql/index.ts +0 -1
- package/src/lib/graphql/schema.ts +0 -443
- package/src/lib/rate-limit.ts +0 -267
- package/src/lib/storage.ts +0 -374
- package/src/lib/store.ts +0 -85
- package/src/middleware.ts +0 -177
- package/src/pages/admin/api-explorer.astro +0 -98
- package/src/pages/admin/graphql-explorer.astro +0 -40
- package/src/pages/admin/index.astro +0 -286
- package/src/pages/admin/keys.astro +0 -8
- package/src/pages/admin/rest-playground.astro +0 -44
- package/src/pages/admin/webhooks.astro +0 -8
- package/src/pages/api/[collection]/[id]/publish.ts +0 -52
- package/src/pages/api/[collection]/[id]/unpublish.ts +0 -42
- package/src/pages/api/[collection]/[id]/versions.ts +0 -66
- package/src/pages/api/[collection]/[id].ts +0 -213
- package/src/pages/api/[collection]/index.ts +0 -209
- package/src/pages/api/auth/[id].ts +0 -121
- package/src/pages/api/auth/audit-logs.ts +0 -57
- package/src/pages/api/auth/login.ts +0 -211
- package/src/pages/api/auth/logout.ts +0 -66
- package/src/pages/api/auth/me.ts +0 -36
- package/src/pages/api/auth/refresh.ts +0 -119
- package/src/pages/api/auth/register.ts +0 -188
- package/src/pages/api/auth/users.ts +0 -97
- package/src/pages/api/collections.ts +0 -59
- package/src/pages/api/globals/[slug].ts +0 -42
- package/src/pages/api/graphql.ts +0 -90
- package/src/pages/api/health.ts +0 -426
- package/src/pages/api/keys/[id].ts +0 -26
- package/src/pages/api/keys/index.ts +0 -75
- package/src/pages/api/media/[id].ts +0 -309
- package/src/pages/api/media/folders.ts +0 -609
- package/src/pages/api/media/index.ts +0 -146
- package/src/pages/api/media/resize.ts +0 -267
- package/src/pages/api/search.ts +0 -82
- package/src/pages/api/slug-availability.ts +0 -70
- package/src/pages/api/storage-config.ts +0 -20
- package/src/pages/api/storage-status.ts +0 -206
- package/src/pages/api/upload.ts +0 -334
- package/src/pages/api/webhooks/index.ts +0 -71
- package/src/pages/login.astro +0 -82
- package/src/pages/register.astro +0 -102
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
Check,
|
|
11
11
|
RefreshCcw,
|
|
12
12
|
Sparkles,
|
|
13
|
-
} from "
|
|
13
|
+
} from "./ui/icons";
|
|
14
14
|
|
|
15
15
|
export function BrandingHub() {
|
|
16
16
|
const [siteName, setSiteName] = useState("Kyro CMS");
|
|
@@ -73,11 +73,11 @@ export function BrandingHub() {
|
|
|
73
73
|
];
|
|
74
74
|
|
|
75
75
|
return (
|
|
76
|
-
<div className="w-full space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700
|
|
76
|
+
<div className="w-full space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700 pb-32">
|
|
77
77
|
{/* Header */}
|
|
78
78
|
<div className="flex flex-col lg:flex-row lg:items-center justify-between gap-6 pt-4">
|
|
79
79
|
<div>
|
|
80
|
-
<h1 className="text-
|
|
80
|
+
<h1 className="text-xl font-bold tracking-tighter text-[var(--kyro-text-primary)]">
|
|
81
81
|
Branding <span className="text-[var(--kyro-primary)]">Hub</span>
|
|
82
82
|
</h1>
|
|
83
83
|
<p className="text-[var(--kyro-text-secondary)] mt-1 font-medium opacity-60">
|
|
@@ -90,11 +90,10 @@ export function BrandingHub() {
|
|
|
90
90
|
type="button"
|
|
91
91
|
onClick={handleSave}
|
|
92
92
|
disabled={saving}
|
|
93
|
-
className={`flex items-center gap-2 px-8 py-3 rounded-2xl font-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}`}
|
|
93
|
+
className={`flex items-center gap-2 px-8 py-3 rounded-2xl font-bold text-sm shadow-xl transition-all active:scale-95 ${saved
|
|
94
|
+
? "bg-green-500 text-white"
|
|
95
|
+
: "bg-[var(--kyro-primary)] text-white hover:shadow-[var(--kyro-primary)]"
|
|
96
|
+
}`}
|
|
98
97
|
>
|
|
99
98
|
{saving ? (
|
|
100
99
|
<RefreshCcw className="w-4 h-4 animate-spin" />
|
|
@@ -117,12 +116,12 @@ export function BrandingHub() {
|
|
|
117
116
|
<section className="surface-tile p-8 space-y-8">
|
|
118
117
|
<div className="flex items-center gap-3 mb-2">
|
|
119
118
|
<Tag className="w-5 h-5 text-[var(--kyro-primary)]" />
|
|
120
|
-
<h2 className="text-xl font-
|
|
119
|
+
<h2 className="text-xl font-bold tracking-tight">Core Identity</h2>
|
|
121
120
|
</div>
|
|
122
121
|
|
|
123
122
|
<div className="space-y-6">
|
|
124
123
|
<div className="space-y-2">
|
|
125
|
-
<label className="text-[10px] font-
|
|
124
|
+
<label className="text-[10px] font-bold tracking-[0.2em] opacity-40">
|
|
126
125
|
Site Public Name
|
|
127
126
|
</label>
|
|
128
127
|
<input
|
|
@@ -135,7 +134,7 @@ export function BrandingHub() {
|
|
|
135
134
|
</div>
|
|
136
135
|
|
|
137
136
|
<div className="space-y-2">
|
|
138
|
-
<label className="text-[10px] font-
|
|
137
|
+
<label className="text-[10px] font-bold tracking-[0.2em] opacity-40">
|
|
139
138
|
Admin Dashboard Title
|
|
140
139
|
</label>
|
|
141
140
|
<input
|
|
@@ -148,7 +147,7 @@ export function BrandingHub() {
|
|
|
148
147
|
</div>
|
|
149
148
|
|
|
150
149
|
<div className="space-y-2">
|
|
151
|
-
<label className="text-[10px] font-
|
|
150
|
+
<label className="text-[10px] font-bold tracking-[0.2em] opacity-40">
|
|
152
151
|
System Greeting
|
|
153
152
|
</label>
|
|
154
153
|
<textarea
|
|
@@ -166,14 +165,14 @@ export function BrandingHub() {
|
|
|
166
165
|
<section className="surface-tile p-8 space-y-8">
|
|
167
166
|
<div className="flex items-center gap-3 mb-2">
|
|
168
167
|
<Palette className="w-5 h-5 text-[var(--kyro-primary)]" />
|
|
169
|
-
<h2 className="text-xl font-
|
|
168
|
+
<h2 className="text-xl font-bold tracking-tight">
|
|
170
169
|
Visual Aesthetic
|
|
171
170
|
</h2>
|
|
172
171
|
</div>
|
|
173
172
|
|
|
174
173
|
<div className="space-y-8">
|
|
175
174
|
<div className="space-y-4">
|
|
176
|
-
<label className="text-[10px] font-
|
|
175
|
+
<label className="text-[10px] font-bold tracking-[0.2em] opacity-40">
|
|
177
176
|
Primary Brand Color
|
|
178
177
|
</label>
|
|
179
178
|
<div className="grid grid-cols-6 gap-3">
|
|
@@ -191,13 +190,13 @@ export function BrandingHub() {
|
|
|
191
190
|
</div>
|
|
192
191
|
|
|
193
192
|
<div className="space-y-4 pt-4 border-t border-[var(--kyro-border)]">
|
|
194
|
-
<label className="text-[10px] font-
|
|
193
|
+
<label className="text-[10px] font-bold tracking-[0.2em] opacity-40">
|
|
195
194
|
Project Logo (SVG/PNG)
|
|
196
195
|
</label>
|
|
197
196
|
<div className="flex items-center gap-6">
|
|
198
197
|
<div className="w-20 h-20 rounded-2xl bg-[var(--kyro-bg-secondary)] border-2 border-dashed border-[var(--kyro-border)] flex flex-col items-center justify-center text-[var(--kyro-text-secondary)] hover:border-[var(--kyro-primary)] hover:text-[var(--kyro-primary)] cursor-pointer transition-all">
|
|
199
198
|
<ImageIcon className="w-6 h-6 mb-1 opacity-40" />
|
|
200
|
-
<span className="text-[8px] font-
|
|
199
|
+
<span className="text-[8px] font-bold ">
|
|
201
200
|
Upload
|
|
202
201
|
</span>
|
|
203
202
|
</div>
|
|
@@ -219,7 +218,7 @@ export function BrandingHub() {
|
|
|
219
218
|
<section className="lg:col-span-2 surface-tile p-8 overflow-hidden relative group">
|
|
220
219
|
<div className="absolute top-0 right-0 p-8 flex items-center gap-2 text-[var(--kyro-primary)]">
|
|
221
220
|
<Sparkles className="w-4 h-4" />
|
|
222
|
-
<span className="text-[10px] font-
|
|
221
|
+
<span className="text-[10px] font-bold tracking-widest">
|
|
223
222
|
Live Preview
|
|
224
223
|
</span>
|
|
225
224
|
</div>
|
|
@@ -227,11 +226,11 @@ export function BrandingHub() {
|
|
|
227
226
|
<div className="max-w-2xl mx-auto py-12 text-center space-y-6">
|
|
228
227
|
<div className="inline-flex items-center gap-3 px-4 py-2 bg-[var(--kyro-bg-secondary)] rounded-full border border-[var(--kyro-border)]">
|
|
229
228
|
<span className="w-2 h-2 rounded-full bg-green-500 animate-pulse" />
|
|
230
|
-
<span className="text-[10px] font-
|
|
229
|
+
<span className="text-[10px] font-bold tracking-widest opacity-60">
|
|
231
230
|
{adminTitle} Online
|
|
232
231
|
</span>
|
|
233
232
|
</div>
|
|
234
|
-
<h2 className="text-5xl font-
|
|
233
|
+
<h2 className="text-5xl font-bold tracking-tighter leading-none italic">
|
|
235
234
|
Welcome to {siteName}.
|
|
236
235
|
</h2>
|
|
237
236
|
<p className="text-xl font-medium text-[var(--kyro-text-secondary)] opacity-60">
|
|
@@ -3,6 +3,9 @@ import { apiPost } from "../lib/api";
|
|
|
3
3
|
import type { KyroConfig, CollectionConfig } from "@kyro-cms/core/client";
|
|
4
4
|
import { AutoForm } from "./AutoForm";
|
|
5
5
|
import { Spinner } from "./ui/Spinner";
|
|
6
|
+
import { PageHeader } from "./ui/PageHeader";
|
|
7
|
+
import { adminPath } from "../lib/paths";
|
|
8
|
+
|
|
6
9
|
|
|
7
10
|
interface CreateViewProps {
|
|
8
11
|
config: KyroConfig;
|
|
@@ -25,8 +28,9 @@ export function CreateView({
|
|
|
25
28
|
const fields = collection.fields || [];
|
|
26
29
|
const label = collection.label || collection.slug;
|
|
27
30
|
|
|
28
|
-
const handleSubmit = async (e
|
|
29
|
-
e.preventDefault();
|
|
31
|
+
const handleSubmit = async (e?: React.FormEvent) => {
|
|
32
|
+
if (e) e.preventDefault();
|
|
33
|
+
|
|
30
34
|
try {
|
|
31
35
|
setSaving(true);
|
|
32
36
|
await apiPost(`/api/${collection.slug}`, data);
|
|
@@ -40,44 +44,26 @@ export function CreateView({
|
|
|
40
44
|
|
|
41
45
|
return (
|
|
42
46
|
<div className="kyro-detail">
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
<button
|
|
59
|
-
type="button"
|
|
60
|
-
className="kyro-btn kyro-btn-secondary kyro-btn-md"
|
|
61
|
-
onClick={onCancel}
|
|
62
|
-
disabled={saving}
|
|
63
|
-
>
|
|
64
|
-
Cancel
|
|
65
|
-
</button>
|
|
66
|
-
<button
|
|
67
|
-
type="button"
|
|
68
|
-
className="kyro-btn kyro-btn-primary kyro-btn-md"
|
|
69
|
-
onClick={handleSubmit}
|
|
70
|
-
disabled={saving}
|
|
71
|
-
>
|
|
72
|
-
{saving ? <Spinner size="sm" /> : `Create ${label}`}
|
|
73
|
-
</button>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
47
|
+
<PageHeader
|
|
48
|
+
back={{ onClick: onCancel }}
|
|
49
|
+
breadcrumbs={[
|
|
50
|
+
{ label: "Collections" },
|
|
51
|
+
{ label: label, href: `${adminPath}/${collection.slug}` },
|
|
52
|
+
{ label: "New" }
|
|
53
|
+
]}
|
|
54
|
+
title={`Create ${collection.singularLabel || label}`}
|
|
55
|
+
action={{
|
|
56
|
+
label: saving ? "Creating..." : `Create ${collection.singularLabel || label}`,
|
|
57
|
+
onClick: () => handleSubmit(),
|
|
58
|
+
}}
|
|
59
|
+
|
|
60
|
+
/>
|
|
61
|
+
|
|
76
62
|
|
|
77
63
|
<div className="kyro-detail-body">
|
|
78
64
|
<div className="kyro-card">
|
|
79
65
|
<div className="kyro-card-content">
|
|
80
|
-
<form
|
|
66
|
+
<form>
|
|
81
67
|
<AutoForm
|
|
82
68
|
config={{ ...collection, fields }}
|
|
83
69
|
data={data}
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import React, { useState, useEffect } from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Plus,
|
|
8
|
-
ArrowUpRight,
|
|
9
|
-
Activity,
|
|
10
|
-
Clock,
|
|
11
|
-
ArrowRight,
|
|
12
|
-
} from "lucide-react";
|
|
2
|
+
import { LayoutDashboard, FileText, Image as ImageIcon, Users, Plus, ArrowUpRight, Activity, Clock as ClockIcon, ArrowRight } from "./ui/icons";
|
|
3
|
+
import { useAuthStore } from "../lib/stores";
|
|
4
|
+
import { authCollectionSlugs } from "../lib/config";
|
|
5
|
+
import { PageHeader } from "./ui/PageHeader";
|
|
6
|
+
|
|
13
7
|
|
|
14
8
|
interface DashboardProps {
|
|
15
|
-
collections:
|
|
9
|
+
collections: Record<string, unknown>;
|
|
16
10
|
onNavigate: (view: string, collection?: string) => void;
|
|
17
|
-
user:
|
|
11
|
+
user: Record<string, unknown> | null;
|
|
18
12
|
}
|
|
19
13
|
|
|
20
14
|
export function Dashboard({ collections, onNavigate, user }: DashboardProps) {
|
|
15
|
+
const { permissions } = useAuthStore();
|
|
21
16
|
const [stats, setStats] = useState({
|
|
22
17
|
totalDocs: 0,
|
|
23
18
|
totalMedia: 0,
|
|
@@ -67,39 +62,30 @@ export function Dashboard({ collections, onNavigate, user }: DashboardProps) {
|
|
|
67
62
|
time: "3h ago",
|
|
68
63
|
},
|
|
69
64
|
],
|
|
70
|
-
} as
|
|
65
|
+
} as { totalDocs: number; totalMedia: number; totalUsers: number; recentActivity: Array<{ id: number; type: string; user: string; doc: string; collection: string; time: string }> });
|
|
71
66
|
setLoading(false);
|
|
72
67
|
}, 800);
|
|
73
68
|
return () => clearTimeout(timer);
|
|
74
69
|
}, []);
|
|
75
70
|
|
|
76
|
-
const collectionList = Object.entries(collections)
|
|
71
|
+
const collectionList = Object.entries(collections).filter(
|
|
72
|
+
([slug]) =>
|
|
73
|
+
!authCollectionSlugs.includes(slug) &&
|
|
74
|
+
permissions?.collections?.[slug]?.read !== false,
|
|
75
|
+
);
|
|
77
76
|
|
|
78
77
|
return (
|
|
79
78
|
<div className="w-full space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700 px-8 pb-12">
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
Everything looks great in your command center today.
|
|
91
|
-
</p>
|
|
92
|
-
</div>
|
|
93
|
-
<div className="flex items-center gap-3">
|
|
94
|
-
<button type="button"
|
|
95
|
-
onClick={() => onNavigate("create", collectionList[0]?.[0])}
|
|
96
|
-
className="flex items-center gap-2 px-6 py-3 bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] rounded-2xl font-black text-sm shadow-xl active:scale-95 transition-all"
|
|
97
|
-
>
|
|
98
|
-
<Plus className="w-4 h-4" />
|
|
99
|
-
New Document
|
|
100
|
-
</button>
|
|
101
|
-
</div>
|
|
102
|
-
</div>
|
|
79
|
+
<PageHeader
|
|
80
|
+
title={`Welcome back, ${user?.email?.split("@")[0] || "Admin"}`}
|
|
81
|
+
description="Everything looks great in your command center today."
|
|
82
|
+
action={collectionList.length > 0 && permissions?.collections?.[collectionList[0]?.[0]]?.create !== false ? {
|
|
83
|
+
label: "New Document",
|
|
84
|
+
onClick: () => onNavigate("create", collectionList[0]?.[0]),
|
|
85
|
+
icon: Plus,
|
|
86
|
+
} : undefined}
|
|
87
|
+
/>
|
|
88
|
+
|
|
103
89
|
|
|
104
90
|
{/* Stats Grid */}
|
|
105
91
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
@@ -134,10 +120,10 @@ export function Dashboard({ collections, onNavigate, user }: DashboardProps) {
|
|
|
134
120
|
className="surface-tile p-6 flex items-center justify-between group hover:border-[var(--kyro-primary)] transition-all duration-500 cursor-default"
|
|
135
121
|
>
|
|
136
122
|
<div>
|
|
137
|
-
<p className="text-[10px] font-
|
|
123
|
+
<p className="text-[10px] font-bold tracking-[0.2em] opacity-40 mb-1">
|
|
138
124
|
{stat.label}
|
|
139
125
|
</p>
|
|
140
|
-
<h3 className="text-3xl font-
|
|
126
|
+
<h3 className="text-3xl font-bold tracking-tighter">
|
|
141
127
|
{loading ? "..." : stat.value}
|
|
142
128
|
</h3>
|
|
143
129
|
</div>
|
|
@@ -154,11 +140,11 @@ export function Dashboard({ collections, onNavigate, user }: DashboardProps) {
|
|
|
154
140
|
{/* Main Content Area: Collections & Insights */}
|
|
155
141
|
<div className="space-y-8 min-w-0">
|
|
156
142
|
<section className="surface-tile p-8">
|
|
157
|
-
<h2 className="text-xl font-
|
|
143
|
+
<h2 className="text-xl font-bold mb-1 tracking-tight flex items-center gap-2">
|
|
158
144
|
<LayoutDashboard className="w-5 h-5 opacity-40" />
|
|
159
145
|
Content Growth
|
|
160
146
|
</h2>
|
|
161
|
-
<p className="text-[10px] font-
|
|
147
|
+
<p className="text-[10px] font-bold tracking-widest opacity-40 mb-8">
|
|
162
148
|
Snapshot of document velocity over the last 7 days
|
|
163
149
|
</p>
|
|
164
150
|
|
|
@@ -204,7 +190,7 @@ export function Dashboard({ collections, onNavigate, user }: DashboardProps) {
|
|
|
204
190
|
className="filter drop-shadow-[0_0_8px_var(--kyro-primary)]"
|
|
205
191
|
/>
|
|
206
192
|
</svg>
|
|
207
|
-
<div className="flex justify-between mt-4 text-[10px] font-
|
|
193
|
+
<div className="flex justify-between mt-4 text-[10px] font-bold opacity-30 tracking-widest ">
|
|
208
194
|
<span>Mon</span>
|
|
209
195
|
<span>Tue</span>
|
|
210
196
|
<span>Wed</span>
|
|
@@ -216,14 +202,14 @@ export function Dashboard({ collections, onNavigate, user }: DashboardProps) {
|
|
|
216
202
|
</div>
|
|
217
203
|
|
|
218
204
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
219
|
-
{collectionList.map(([slug, config]: [string,
|
|
205
|
+
{collectionList.map(([slug, config]: [string, Record<string, unknown>]) => (
|
|
220
206
|
<div
|
|
221
207
|
key={slug}
|
|
222
208
|
onClick={() => onNavigate("list", slug)}
|
|
223
209
|
className="p-6 rounded-2xl border border-[var(--kyro-border)] hover:border-[var(--kyro-primary)] bg-[var(--kyro-bg-secondary)] hover:bg-[var(--kyro-surface)] transition-all cursor-pointer group"
|
|
224
210
|
>
|
|
225
211
|
<div className="flex items-center justify-between mb-2">
|
|
226
|
-
<h3 className="font-
|
|
212
|
+
<h3 className="font-bold text-lg tracking-tight group-hover:text-[var(--kyro-primary)] transition-colors">
|
|
227
213
|
{config.label || slug}
|
|
228
214
|
</h3>
|
|
229
215
|
<ArrowUpRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-all" />
|
|
@@ -245,51 +231,41 @@ export function Dashboard({ collections, onNavigate, user }: DashboardProps) {
|
|
|
245
231
|
<section className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
246
232
|
<section className="surface-tile p-6 border border-[var(--kyro-border)] hover:border-[var(--kyro-primary)] transition-all cursor-pointer group">
|
|
247
233
|
<div className="flex items-center justify-between mb-4">
|
|
248
|
-
<h3 className="text-xl font-
|
|
234
|
+
<h3 className="text-xl font-bold tracking-tight group-hover:text-[var(--kyro-primary)] transition-colors flex items-center gap-2">
|
|
249
235
|
<Plus className="w-5 h-5" />
|
|
250
236
|
Quick Links
|
|
251
237
|
</h3>
|
|
252
238
|
</div>
|
|
253
239
|
<div className="space-y-3">
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
</button>
|
|
272
|
-
<button type="button"
|
|
273
|
-
onClick={() => onNavigate("new", "pages")}
|
|
274
|
-
className="w-full flex items-center justify-between p-4 bg-[var(--kyro-bg-secondary)] border border-[var(--kyro-border)] rounded-xl hover:bg-[var(--kyro-surface-accent)] hover:border-[var(--kyro-primary)] transition-all group/btn"
|
|
275
|
-
>
|
|
276
|
-
<span className="text-sm font-bold text-[var(--kyro-text-primary)]">
|
|
277
|
-
New Page
|
|
278
|
-
</span>
|
|
279
|
-
<Plus className="w-4 h-4 text-[var(--kyro-text-secondary)] group-hover/btn:text-[var(--kyro-primary)]" />
|
|
280
|
-
</button>
|
|
240
|
+
{collectionList
|
|
241
|
+
.filter(([slug]) => permissions?.collections?.[slug]?.create !== false)
|
|
242
|
+
.map(([slug]) => (
|
|
243
|
+
<button type="button"
|
|
244
|
+
key={slug}
|
|
245
|
+
onClick={() => onNavigate("new", slug)}
|
|
246
|
+
className="w-full flex items-center justify-between p-4 bg-[var(--kyro-bg-secondary)] border border-[var(--kyro-border)] rounded-xl hover:bg-[var(--kyro-surface-accent)] hover:border-[var(--kyro-primary)] transition-all group/btn"
|
|
247
|
+
>
|
|
248
|
+
<span className="text-sm font-medium text-[var(--kyro-text-primary)]">
|
|
249
|
+
New {(collections[slug] as Record<string, unknown>)?.singularLabel || (collections[slug] as Record<string, unknown>)?.label || slug}
|
|
250
|
+
</span>
|
|
251
|
+
<Plus className="w-4 h-4 text-[var(--kyro-text-secondary)] group-hover/btn:text-[var(--kyro-primary)]" />
|
|
252
|
+
</button>
|
|
253
|
+
))}
|
|
254
|
+
{collectionList.every(([slug]) => permissions?.collections?.[slug]?.create === false) && (
|
|
255
|
+
<p className="text-sm text-[var(--kyro-text-secondary)] py-2">No collections available for creation.</p>
|
|
256
|
+
)}
|
|
281
257
|
</div>
|
|
282
258
|
</section>
|
|
283
259
|
|
|
284
260
|
<div className="surface-tile p-8 bg-[#0f172a] text-white border-none shadow-2xl shadow-blue-500/10 overflow-hidden relative group cursor-pointer">
|
|
285
261
|
<div className="relative z-10">
|
|
286
|
-
<h3 className="text-2xl font-
|
|
262
|
+
<h3 className="text-2xl font-bold tracking-tighter mb-2">
|
|
287
263
|
Media Library
|
|
288
264
|
</h3>
|
|
289
265
|
<p className="opacity-80 text-sm font-medium mb-6">
|
|
290
266
|
Manage high-fidelity assets with our liquid masonry gallery.
|
|
291
267
|
</p>
|
|
292
|
-
<div className="flex items-center gap-2 font-
|
|
268
|
+
<div className="flex items-center gap-2 font-bold text-xs tracking-widest text-blue-400">
|
|
293
269
|
Open Assets{" "}
|
|
294
270
|
<ArrowRight className="w-4 h-4 group-hover:translate-x-1 transition-transform" />
|
|
295
271
|
</div>
|
|
@@ -302,23 +278,23 @@ export function Dashboard({ collections, onNavigate, user }: DashboardProps) {
|
|
|
302
278
|
{/* Sidebar Area: Recent Activity */}
|
|
303
279
|
<div className="space-y-6">
|
|
304
280
|
<section className="surface-tile p-8">
|
|
305
|
-
<h2 className="text-xl font-
|
|
306
|
-
<
|
|
281
|
+
<h2 className="text-xl font-bold mb-6 tracking-tight flex items-center gap-2">
|
|
282
|
+
<ClockIcon className="w-5 h-5 opacity-40" />
|
|
307
283
|
Recent Activity
|
|
308
284
|
</h2>
|
|
309
285
|
<div className="space-y-6">
|
|
310
|
-
{stats.recentActivity.map((act:
|
|
286
|
+
{stats.recentActivity.map((act: Record<string, unknown>) => (
|
|
311
287
|
<div key={act.id} className="flex gap-4 group">
|
|
312
288
|
<div className="mt-1">
|
|
313
289
|
<div className="w-8 h-8 rounded-full bg-[var(--kyro-bg-secondary)] flex items-center justify-center border border-[var(--kyro-border)] group-hover:bg-[var(--kyro-primary)] transition-colors">
|
|
314
|
-
<span className="text-[10px] font-
|
|
290
|
+
<span className="text-[10px] font-bold">
|
|
315
291
|
{act.user[0]}
|
|
316
292
|
</span>
|
|
317
293
|
</div>
|
|
318
294
|
</div>
|
|
319
295
|
<div className="flex-1 border-b border-[var(--kyro-border)] pb-4 group-last:border-none">
|
|
320
296
|
<p className="text-sm font-medium text-[var(--kyro-text-primary)] leading-snug">
|
|
321
|
-
<span className="font-
|
|
297
|
+
<span className="font-bold">{act.user}</span>{" "}
|
|
322
298
|
{act.type === "create"
|
|
323
299
|
? "created"
|
|
324
300
|
: act.type === "edit"
|
|
@@ -331,20 +307,20 @@ export function Dashboard({ collections, onNavigate, user }: DashboardProps) {
|
|
|
331
307
|
</span>{" "}
|
|
332
308
|
in <span className="opacity-60">{act.collection}</span>
|
|
333
309
|
</p>
|
|
334
|
-
<span className="text-[10px] font-bold
|
|
310
|
+
<span className="text-[10px] font-bold opacity-40 mt-1 block">
|
|
335
311
|
{act.time}
|
|
336
312
|
</span>
|
|
337
313
|
</div>
|
|
338
314
|
</div>
|
|
339
315
|
))}
|
|
340
316
|
</div>
|
|
341
|
-
<button type="button" className="w-full mt-6 py-3 text-xs font-
|
|
317
|
+
<button type="button" className="w-full mt-6 py-3 text-xs font-bold tracking-widest text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)] transition-colors border-t border-[var(--kyro-border)] pt-6">
|
|
342
318
|
View Audit Logs
|
|
343
319
|
</button>
|
|
344
320
|
</section>
|
|
345
321
|
|
|
346
322
|
<section className="surface-tile p-8">
|
|
347
|
-
<h2 className="text-xl font-
|
|
323
|
+
<h2 className="text-xl font-bold mb-6 tracking-tight flex items-center gap-2">
|
|
348
324
|
<Activity className="w-5 h-5 opacity-40" />
|
|
349
325
|
System Status
|
|
350
326
|
</h2>
|
|
@@ -375,7 +351,7 @@ export function Dashboard({ collections, onNavigate, user }: DashboardProps) {
|
|
|
375
351
|
{sys.label}
|
|
376
352
|
</span>
|
|
377
353
|
<div className="flex items-center gap-2">
|
|
378
|
-
<span className="text-[10px] font-
|
|
354
|
+
<span className="text-[10px] font-bold tracking-widest opacity-60">
|
|
379
355
|
{sys.status}
|
|
380
356
|
</span>
|
|
381
357
|
<div
|