@kyro-cms/admin 0.1.5 → 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 +52 -5
- 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 +50 -0
- 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 +116 -28
- 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 +286 -0
- 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 +50 -20
- 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 +82 -0
- package/src/pages/media.astro +10 -0
- package/src/pages/preview/[collection]/[id].astro +178 -0
- package/src/pages/register.astro +102 -0
- 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
- package/src/pages/index.astro +0 -225
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
|
2
|
+
import {
|
|
3
|
+
LayoutDashboard,
|
|
4
|
+
FileText,
|
|
5
|
+
Image as ImageIcon,
|
|
6
|
+
Users,
|
|
7
|
+
Plus,
|
|
8
|
+
ArrowUpRight,
|
|
9
|
+
Activity,
|
|
10
|
+
Clock,
|
|
11
|
+
ArrowRight,
|
|
12
|
+
} from "lucide-react";
|
|
13
|
+
|
|
14
|
+
interface DashboardProps {
|
|
15
|
+
collections: any;
|
|
16
|
+
onNavigate: (view: string, collection?: string) => void;
|
|
17
|
+
user: any;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function Dashboard({ collections, onNavigate, user }: DashboardProps) {
|
|
21
|
+
const [stats, setStats] = useState({
|
|
22
|
+
totalDocs: 0,
|
|
23
|
+
totalMedia: 0,
|
|
24
|
+
totalUsers: 0,
|
|
25
|
+
recentActivity: [],
|
|
26
|
+
});
|
|
27
|
+
const [loading, setLoading] = useState(true);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
// Mock data fetching for high-fidelity look
|
|
31
|
+
const timer = setTimeout(() => {
|
|
32
|
+
setStats({
|
|
33
|
+
totalDocs: 124,
|
|
34
|
+
totalMedia: 856,
|
|
35
|
+
totalUsers: 12,
|
|
36
|
+
recentActivity: [
|
|
37
|
+
{
|
|
38
|
+
id: 1,
|
|
39
|
+
type: "edit",
|
|
40
|
+
user: "Daniel Dozie",
|
|
41
|
+
doc: "Getting Started with Kyro",
|
|
42
|
+
collection: "posts",
|
|
43
|
+
time: "2m ago",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: 2,
|
|
47
|
+
type: "create",
|
|
48
|
+
user: "Jane Smith",
|
|
49
|
+
doc: "New Product Launch",
|
|
50
|
+
collection: "products",
|
|
51
|
+
time: "15m ago",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 3,
|
|
55
|
+
type: "upload",
|
|
56
|
+
user: "Daniel Dozie",
|
|
57
|
+
doc: "hero-banner.jpg",
|
|
58
|
+
collection: "media",
|
|
59
|
+
time: "1h ago",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: 4,
|
|
63
|
+
type: "publish",
|
|
64
|
+
user: "System",
|
|
65
|
+
doc: "Weekly Update",
|
|
66
|
+
collection: "posts",
|
|
67
|
+
time: "3h ago",
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
} as any);
|
|
71
|
+
setLoading(false);
|
|
72
|
+
}, 800);
|
|
73
|
+
return () => clearTimeout(timer);
|
|
74
|
+
}, []);
|
|
75
|
+
|
|
76
|
+
const collectionList = Object.entries(collections);
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<div className="w-full space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700 px-8 pb-12">
|
|
80
|
+
{/* Header Section */}
|
|
81
|
+
<div className="flex flex-col lg:flex-row lg:items-center justify-between gap-6 pt-4">
|
|
82
|
+
<div>
|
|
83
|
+
<h1 className="text-4xl font-black tracking-tighter text-[var(--kyro-text-primary)]">
|
|
84
|
+
Welcome back,{" "}
|
|
85
|
+
<span className="text-[var(--kyro-primary)]">
|
|
86
|
+
{user?.email?.split("@")[0] || "Admin"}
|
|
87
|
+
</span>
|
|
88
|
+
</h1>
|
|
89
|
+
<p className="text-[var(--kyro-text-secondary)] mt-1 font-medium italic opacity-70">
|
|
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>
|
|
103
|
+
|
|
104
|
+
{/* Stats Grid */}
|
|
105
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
106
|
+
{[
|
|
107
|
+
{
|
|
108
|
+
label: "Total Content",
|
|
109
|
+
value: stats.totalDocs,
|
|
110
|
+
icon: FileText,
|
|
111
|
+
color: "text-blue-500",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
label: "Media Assets",
|
|
115
|
+
value: stats.totalMedia,
|
|
116
|
+
icon: ImageIcon,
|
|
117
|
+
color: "text-purple-500",
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
label: "Active Users",
|
|
121
|
+
value: stats.totalUsers,
|
|
122
|
+
icon: Users,
|
|
123
|
+
color: "text-green-500",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
label: "System Health",
|
|
127
|
+
value: "100%",
|
|
128
|
+
icon: Activity,
|
|
129
|
+
color: "text-amber-500",
|
|
130
|
+
},
|
|
131
|
+
].map((stat, i) => (
|
|
132
|
+
<div
|
|
133
|
+
key={i}
|
|
134
|
+
className="surface-tile p-6 flex items-center justify-between group hover:border-[var(--kyro-primary)] transition-all duration-500 cursor-default"
|
|
135
|
+
>
|
|
136
|
+
<div>
|
|
137
|
+
<p className="text-[10px] font-black uppercase tracking-[0.2em] opacity-40 mb-1">
|
|
138
|
+
{stat.label}
|
|
139
|
+
</p>
|
|
140
|
+
<h3 className="text-3xl font-black tracking-tighter">
|
|
141
|
+
{loading ? "..." : stat.value}
|
|
142
|
+
</h3>
|
|
143
|
+
</div>
|
|
144
|
+
<div
|
|
145
|
+
className={`p-3 rounded-2xl bg-[var(--kyro-bg-secondary)] group-hover:scale-110 transition-transform duration-500 ${stat.color}`}
|
|
146
|
+
>
|
|
147
|
+
<stat.icon className="w-6 h-6" />
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
))}
|
|
151
|
+
</div>
|
|
152
|
+
|
|
153
|
+
<div className="grid grid-cols-1 lg:grid-cols-[1fr_400px] gap-8">
|
|
154
|
+
{/* Main Content Area: Collections & Insights */}
|
|
155
|
+
<div className="space-y-8 min-w-0">
|
|
156
|
+
<section className="surface-tile p-8">
|
|
157
|
+
<h2 className="text-xl font-black mb-1 tracking-tight flex items-center gap-2">
|
|
158
|
+
<LayoutDashboard className="w-5 h-5 opacity-40" />
|
|
159
|
+
Content Growth
|
|
160
|
+
</h2>
|
|
161
|
+
<p className="text-[10px] font-black uppercase tracking-widest opacity-40 mb-8">
|
|
162
|
+
Snapshot of document velocity over the last 7 days
|
|
163
|
+
</p>
|
|
164
|
+
|
|
165
|
+
{/* SVG Line Chart */}
|
|
166
|
+
<div className="h-48 w-full relative mb-12">
|
|
167
|
+
<svg
|
|
168
|
+
className="w-full h-full"
|
|
169
|
+
viewBox="0 0 1000 200"
|
|
170
|
+
preserveAspectRatio="none"
|
|
171
|
+
>
|
|
172
|
+
<defs>
|
|
173
|
+
<linearGradient
|
|
174
|
+
id="chartGradient"
|
|
175
|
+
x1="0"
|
|
176
|
+
y1="0"
|
|
177
|
+
x2="0"
|
|
178
|
+
y2="1"
|
|
179
|
+
>
|
|
180
|
+
<stop
|
|
181
|
+
offset="0%"
|
|
182
|
+
stopColor="var(--kyro-primary)"
|
|
183
|
+
stopOpacity="0.3"
|
|
184
|
+
/>
|
|
185
|
+
<stop
|
|
186
|
+
offset="100%"
|
|
187
|
+
stopColor="var(--kyro-primary)"
|
|
188
|
+
stopOpacity="0"
|
|
189
|
+
/>
|
|
190
|
+
</linearGradient>
|
|
191
|
+
</defs>
|
|
192
|
+
<path
|
|
193
|
+
d="M0,180 Q100,140 200,160 T400,100 T600,120 T800,40 T1000,60 L1000,200 L0,200 Z"
|
|
194
|
+
fill="url(#chartGradient)"
|
|
195
|
+
className="animate-pulse duration-[4s]"
|
|
196
|
+
/>
|
|
197
|
+
<path
|
|
198
|
+
d="M0,180 Q100,140 200,160 T400,100 T600,120 T800,40 T1000,60"
|
|
199
|
+
fill="none"
|
|
200
|
+
stroke="var(--kyro-primary)"
|
|
201
|
+
strokeWidth="4"
|
|
202
|
+
strokeLinecap="round"
|
|
203
|
+
vectorEffect="non-scaling-stroke"
|
|
204
|
+
className="filter drop-shadow-[0_0_8px_var(--kyro-primary)]"
|
|
205
|
+
/>
|
|
206
|
+
</svg>
|
|
207
|
+
<div className="flex justify-between mt-4 text-[10px] font-black opacity-30 tracking-widest uppercase">
|
|
208
|
+
<span>Mon</span>
|
|
209
|
+
<span>Tue</span>
|
|
210
|
+
<span>Wed</span>
|
|
211
|
+
<span>Thu</span>
|
|
212
|
+
<span>Fri</span>
|
|
213
|
+
<span>Sat</span>
|
|
214
|
+
<span>Sun</span>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
219
|
+
{collectionList.map(([slug, config]: [string, any]) => (
|
|
220
|
+
<div
|
|
221
|
+
key={slug}
|
|
222
|
+
onClick={() => onNavigate("list", slug)}
|
|
223
|
+
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
|
+
>
|
|
225
|
+
<div className="flex items-center justify-between mb-2">
|
|
226
|
+
<h3 className="font-black text-lg tracking-tight group-hover:text-[var(--kyro-primary)] transition-colors">
|
|
227
|
+
{config.label || slug}
|
|
228
|
+
</h3>
|
|
229
|
+
<ArrowUpRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-all" />
|
|
230
|
+
</div>
|
|
231
|
+
<div className="w-full h-1 bg-[var(--kyro-bg-secondary)] rounded-full mb-3 overflow-hidden">
|
|
232
|
+
<div
|
|
233
|
+
className="h-full bg-[var(--kyro-primary)]"
|
|
234
|
+
style={{ width: `${Math.random() * 60 + 20}%` }}
|
|
235
|
+
/>
|
|
236
|
+
</div>
|
|
237
|
+
<p className="text-sm text-[var(--kyro-text-secondary)] line-clamp-1">
|
|
238
|
+
{config.admin?.description || `Manage ${slug} content.`}
|
|
239
|
+
</p>
|
|
240
|
+
</div>
|
|
241
|
+
))}
|
|
242
|
+
</div>
|
|
243
|
+
</section>
|
|
244
|
+
|
|
245
|
+
<section className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
246
|
+
<section className="surface-tile p-6 border border-[var(--kyro-border)] hover:border-[var(--kyro-primary)] transition-all cursor-pointer group">
|
|
247
|
+
<div className="flex items-center justify-between mb-4">
|
|
248
|
+
<h3 className="text-xl font-black tracking-tight group-hover:text-[var(--kyro-primary)] transition-colors flex items-center gap-2">
|
|
249
|
+
<Plus className="w-5 h-5" />
|
|
250
|
+
Quick Links
|
|
251
|
+
</h3>
|
|
252
|
+
</div>
|
|
253
|
+
<div className="space-y-3">
|
|
254
|
+
<button type="button"
|
|
255
|
+
onClick={() => onNavigate("new", "posts")}
|
|
256
|
+
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"
|
|
257
|
+
>
|
|
258
|
+
<span className="text-sm font-bold text-[var(--kyro-text-primary)]">
|
|
259
|
+
New Post
|
|
260
|
+
</span>
|
|
261
|
+
<Plus className="w-4 h-4 text-[var(--kyro-text-secondary)] group-hover/btn:text-[var(--kyro-primary)]" />
|
|
262
|
+
</button>
|
|
263
|
+
<button type="button"
|
|
264
|
+
onClick={() => onNavigate("new", "products")}
|
|
265
|
+
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"
|
|
266
|
+
>
|
|
267
|
+
<span className="text-sm font-bold text-[var(--kyro-text-primary)]">
|
|
268
|
+
New Product
|
|
269
|
+
</span>
|
|
270
|
+
<Plus className="w-4 h-4 text-[var(--kyro-text-secondary)] group-hover/btn:text-[var(--kyro-primary)]" />
|
|
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>
|
|
281
|
+
</div>
|
|
282
|
+
</section>
|
|
283
|
+
|
|
284
|
+
<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
|
+
<div className="relative z-10">
|
|
286
|
+
<h3 className="text-2xl font-black tracking-tighter mb-2">
|
|
287
|
+
Media Library
|
|
288
|
+
</h3>
|
|
289
|
+
<p className="opacity-80 text-sm font-medium mb-6">
|
|
290
|
+
Manage high-fidelity assets with our liquid masonry gallery.
|
|
291
|
+
</p>
|
|
292
|
+
<div className="flex items-center gap-2 font-black text-xs uppercase tracking-widest text-blue-400">
|
|
293
|
+
Open Assets{" "}
|
|
294
|
+
<ArrowRight className="w-4 h-4 group-hover:translate-x-1 transition-transform" />
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
<ImageIcon className="absolute bottom-[-20px] right-[-20px] w-48 h-48 opacity-10 rotate-12 group-hover:scale-110 transition-transform duration-1000" />
|
|
298
|
+
</div>
|
|
299
|
+
</section>
|
|
300
|
+
</div>
|
|
301
|
+
|
|
302
|
+
{/* Sidebar Area: Recent Activity */}
|
|
303
|
+
<div className="space-y-6">
|
|
304
|
+
<section className="surface-tile p-8">
|
|
305
|
+
<h2 className="text-xl font-black mb-6 tracking-tight flex items-center gap-2">
|
|
306
|
+
<Clock className="w-5 h-5 opacity-40" />
|
|
307
|
+
Recent Activity
|
|
308
|
+
</h2>
|
|
309
|
+
<div className="space-y-6">
|
|
310
|
+
{stats.recentActivity.map((act: any) => (
|
|
311
|
+
<div key={act.id} className="flex gap-4 group">
|
|
312
|
+
<div className="mt-1">
|
|
313
|
+
<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-black">
|
|
315
|
+
{act.user[0]}
|
|
316
|
+
</span>
|
|
317
|
+
</div>
|
|
318
|
+
</div>
|
|
319
|
+
<div className="flex-1 border-b border-[var(--kyro-border)] pb-4 group-last:border-none">
|
|
320
|
+
<p className="text-sm font-medium text-[var(--kyro-text-primary)] leading-snug">
|
|
321
|
+
<span className="font-black">{act.user}</span>{" "}
|
|
322
|
+
{act.type === "create"
|
|
323
|
+
? "created"
|
|
324
|
+
: act.type === "edit"
|
|
325
|
+
? "edited"
|
|
326
|
+
: act.type === "publish"
|
|
327
|
+
? "published"
|
|
328
|
+
: "uploaded"}{" "}
|
|
329
|
+
<span className="text-[var(--kyro-primary)] italic">
|
|
330
|
+
"{act.doc}"
|
|
331
|
+
</span>{" "}
|
|
332
|
+
in <span className="opacity-60">{act.collection}</span>
|
|
333
|
+
</p>
|
|
334
|
+
<span className="text-[10px] font-bold uppercase opacity-40 mt-1 block">
|
|
335
|
+
{act.time}
|
|
336
|
+
</span>
|
|
337
|
+
</div>
|
|
338
|
+
</div>
|
|
339
|
+
))}
|
|
340
|
+
</div>
|
|
341
|
+
<button type="button" className="w-full mt-6 py-3 text-xs font-black uppercase tracking-widest text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)] transition-colors border-t border-[var(--kyro-border)] pt-6">
|
|
342
|
+
View Audit Logs
|
|
343
|
+
</button>
|
|
344
|
+
</section>
|
|
345
|
+
|
|
346
|
+
<section className="surface-tile p-8">
|
|
347
|
+
<h2 className="text-xl font-black mb-6 tracking-tight flex items-center gap-2">
|
|
348
|
+
<Activity className="w-5 h-5 opacity-40" />
|
|
349
|
+
System Status
|
|
350
|
+
</h2>
|
|
351
|
+
<div className="space-y-4">
|
|
352
|
+
{[
|
|
353
|
+
{
|
|
354
|
+
label: "Cloud API",
|
|
355
|
+
status: "Optimal",
|
|
356
|
+
pulse: "bg-green-500",
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
label: "Database Node",
|
|
360
|
+
status: "Healthy",
|
|
361
|
+
pulse: "bg-green-500",
|
|
362
|
+
},
|
|
363
|
+
{ label: "Media CDN", status: "Active", pulse: "bg-blue-500" },
|
|
364
|
+
{
|
|
365
|
+
label: "Auth Service",
|
|
366
|
+
status: "Secure",
|
|
367
|
+
pulse: "bg-green-500",
|
|
368
|
+
},
|
|
369
|
+
].map((sys, index) => (
|
|
370
|
+
<div
|
|
371
|
+
key={index}
|
|
372
|
+
className="flex items-center justify-between p-4 bg-[var(--kyro-bg-secondary)] rounded-2xl border border-[var(--kyro-border)]"
|
|
373
|
+
>
|
|
374
|
+
<span className="text-xs font-bold text-[var(--kyro-text-secondary)]">
|
|
375
|
+
{sys.label}
|
|
376
|
+
</span>
|
|
377
|
+
<div className="flex items-center gap-2">
|
|
378
|
+
<span className="text-[10px] font-black uppercase tracking-widest opacity-60">
|
|
379
|
+
{sys.status}
|
|
380
|
+
</span>
|
|
381
|
+
<div
|
|
382
|
+
className={`w-2 h-2 rounded-full ${sys.pulse} animate-pulse shadow-[0_0_8px] shadow-current`}
|
|
383
|
+
/>
|
|
384
|
+
</div>
|
|
385
|
+
</div>
|
|
386
|
+
))}
|
|
387
|
+
</div>
|
|
388
|
+
</section>
|
|
389
|
+
</div>
|
|
390
|
+
</div>
|
|
391
|
+
</div>
|
|
392
|
+
);
|
|
393
|
+
}
|