@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.
Files changed (164) hide show
  1. package/README.md +149 -51
  2. package/package.json +52 -5
  3. package/src/collections/auth/index.ts +2 -2
  4. package/src/collections/portfolio/index.ts +343 -0
  5. package/src/components/ActionBar.tsx +153 -16
  6. package/src/components/Admin.tsx +136 -27
  7. package/src/components/ApiExplorer.tsx +325 -0
  8. package/src/components/ApiKeysManager.tsx +563 -0
  9. package/src/components/AuditLogsPage.tsx +664 -0
  10. package/src/components/AutoForm.tsx +1417 -661
  11. package/src/components/BrandingHub.tsx +267 -0
  12. package/src/components/BulkActionsBar.tsx +3 -3
  13. package/src/components/CreateView.tsx +3 -3
  14. package/src/components/Dashboard.tsx +393 -0
  15. package/src/components/DetailView.tsx +199 -57
  16. package/src/components/DeveloperCenter.tsx +403 -0
  17. package/src/components/EnhancedListView.tsx +786 -0
  18. package/src/components/GraphQLExplorer.tsx +675 -0
  19. package/src/components/GraphQLPlayground.tsx +627 -0
  20. package/src/components/ListView.tsx +191 -53
  21. package/src/components/MediaGallery.tsx +1569 -0
  22. package/src/components/Modal.tsx +149 -0
  23. package/src/components/RestPlayground.tsx +951 -0
  24. package/src/components/Sidebar.astro +237 -0
  25. package/src/components/UserManagement.tsx +204 -0
  26. package/src/components/VersionHistoryPanel.tsx +3 -3
  27. package/src/components/WebhookManager.tsx +608 -0
  28. package/src/components/blocks/AccordionBlock.tsx +97 -0
  29. package/src/components/blocks/ArrayBlock.tsx +75 -0
  30. package/src/components/blocks/BlockEditModal.MARKER +12 -0
  31. package/src/components/blocks/BlockEditModal.tsx +774 -0
  32. package/src/components/blocks/ButtonBlock.tsx +165 -0
  33. package/src/components/blocks/ChildBlocksTree.tsx +551 -0
  34. package/src/components/blocks/CodeBlock.tsx +66 -0
  35. package/src/components/blocks/ColumnsBlock.tsx +151 -0
  36. package/src/components/blocks/DividerBlock.tsx +43 -0
  37. package/src/components/blocks/FileBlock.tsx +64 -0
  38. package/src/components/blocks/HeadingBlock.tsx +81 -0
  39. package/src/components/blocks/HeroBlock.tsx +157 -0
  40. package/src/components/blocks/ImageBlock.tsx +83 -0
  41. package/src/components/blocks/LinkBlock.tsx +71 -0
  42. package/src/components/blocks/ListBlock.tsx +39 -0
  43. package/src/components/blocks/ParagraphBlock.tsx +61 -0
  44. package/src/components/blocks/RelationshipBlock.tsx +279 -0
  45. package/src/components/blocks/VStackBlock.tsx +75 -0
  46. package/src/components/blocks/VideoBlock.tsx +45 -0
  47. package/src/components/blocks/index.ts +10 -0
  48. package/src/components/fields/BlocksField.tsx +323 -0
  49. package/src/components/fields/CheckboxField.tsx +15 -9
  50. package/src/components/fields/CodeField.tsx +234 -0
  51. package/src/components/fields/DateField.tsx +38 -11
  52. package/src/components/fields/EditorClient.tsx +271 -0
  53. package/src/components/fields/FileField.tsx +390 -0
  54. package/src/components/fields/HybridContentField.tsx +109 -0
  55. package/src/components/fields/ImageField.tsx +429 -0
  56. package/src/components/fields/JSONField.tsx +361 -0
  57. package/src/components/fields/MarkdownField.tsx +282 -0
  58. package/src/components/fields/NumberField.tsx +42 -12
  59. package/src/components/fields/PortableTextField.tsx +143 -0
  60. package/src/components/fields/PortableTextRenderer.tsx +68 -0
  61. package/src/components/fields/RelationshipField.tsx +231 -59
  62. package/src/components/fields/SelectField.tsx +25 -15
  63. package/src/components/fields/TextField.tsx +45 -14
  64. package/src/components/fields/extensions/blockComponents.tsx +237 -0
  65. package/src/components/fields/extensions/blocksStore.ts +273 -0
  66. package/src/components/fields/index.ts +13 -0
  67. package/src/components/index.ts +1 -2
  68. package/src/components/layout/Header.tsx +2 -2
  69. package/src/components/layout/Layout.tsx +2 -2
  70. package/src/components/ui/Badge.tsx +9 -4
  71. package/src/components/ui/BlockDrawer.tsx +79 -0
  72. package/src/components/ui/Button.tsx +1 -1
  73. package/src/components/ui/CommandPalette.tsx +362 -0
  74. package/src/components/ui/CommandPaletteWrapper.tsx +97 -0
  75. package/src/components/ui/Dropdown.tsx +1 -1
  76. package/src/components/ui/Modal.tsx +37 -12
  77. package/src/components/ui/PromptModal.tsx +94 -0
  78. package/src/components/ui/SlidePanel.tsx +43 -16
  79. package/src/components/ui/Toast.tsx +80 -14
  80. package/src/env.d.ts +16 -0
  81. package/src/env.ts +20 -0
  82. package/src/index.ts +0 -1
  83. package/src/layouts/AdminLayout.astro +164 -170
  84. package/src/layouts/AuthLayout.astro +50 -0
  85. package/src/lib/MediaService.ts +541 -0
  86. package/src/lib/auth/sqlite-adapter.ts +319 -0
  87. package/src/lib/config.ts +22 -6
  88. package/src/lib/dataStore.ts +132 -74
  89. package/src/lib/db/adapter.ts +54 -0
  90. package/src/lib/db/drizzle-mysql-adapter.ts +194 -0
  91. package/src/lib/db/drizzle-mysql-auth-adapter.ts +327 -0
  92. package/src/lib/db/drizzle-postgres-adapter.ts +202 -0
  93. package/src/lib/db/drizzle-postgres-auth-adapter.ts +304 -0
  94. package/src/lib/db/drizzle-sqlite-adapter.ts +227 -0
  95. package/src/lib/db/drizzle-sqlite-auth-adapter.ts +548 -0
  96. package/src/lib/db/index.ts +449 -0
  97. package/src/lib/db/mongodb-adapter.ts +207 -0
  98. package/src/lib/db/mongodb-auth-adapter.ts +305 -0
  99. package/src/lib/db/schema/mysql-auth.ts +113 -0
  100. package/src/lib/db/schema/mysql-content.ts +20 -0
  101. package/src/lib/db/schema/postgres-auth.ts +116 -0
  102. package/src/lib/db/schema/postgres-content.ts +35 -0
  103. package/src/lib/db/schema/postgres-media.ts +52 -0
  104. package/src/lib/db/schema/postgres-settings.ts +11 -0
  105. package/src/lib/db/schema/sqlite-auth.ts +112 -0
  106. package/src/lib/db/schema/sqlite-content.ts +20 -0
  107. package/src/lib/graphql/index.ts +1 -0
  108. package/src/lib/graphql/schema.ts +443 -0
  109. package/src/lib/rate-limit.ts +267 -0
  110. package/src/lib/storage.ts +374 -0
  111. package/src/lib/store.ts +85 -0
  112. package/src/middleware.ts +116 -28
  113. package/src/pages/[collection]/[id].astro +178 -122
  114. package/src/pages/[collection]/index.astro +24 -156
  115. package/src/pages/admin/api-explorer.astro +98 -0
  116. package/src/pages/admin/graphql-explorer.astro +40 -0
  117. package/src/pages/admin/graphql.astro +97 -0
  118. package/src/pages/admin/index.astro +286 -0
  119. package/src/pages/admin/keys.astro +8 -0
  120. package/src/pages/admin/rest-playground.astro +44 -0
  121. package/src/pages/admin/webhooks.astro +8 -0
  122. package/src/pages/api/[collection]/[id]/publish.ts +44 -0
  123. package/src/pages/api/[collection]/[id]/unpublish.ts +42 -0
  124. package/src/pages/api/[collection]/[id]/versions.ts +36 -0
  125. package/src/pages/api/[collection]/[id].ts +102 -159
  126. package/src/pages/api/[collection]/index.ts +151 -230
  127. package/src/pages/api/auth/[id].ts +48 -69
  128. package/src/pages/api/auth/audit-logs.ts +20 -43
  129. package/src/pages/api/auth/login.ts +159 -45
  130. package/src/pages/api/auth/logout.ts +50 -20
  131. package/src/pages/api/auth/refresh.ts +119 -0
  132. package/src/pages/api/auth/register.ts +110 -40
  133. package/src/pages/api/auth/users.ts +22 -97
  134. package/src/pages/api/collections.ts +59 -0
  135. package/src/pages/api/globals/[slug]/test.ts +172 -0
  136. package/src/pages/api/globals/[slug].ts +42 -0
  137. package/src/pages/api/graphql.ts +90 -0
  138. package/src/pages/api/health.ts +417 -40
  139. package/src/pages/api/keys/[id].ts +26 -0
  140. package/src/pages/api/keys/index.ts +75 -0
  141. package/src/pages/api/media/[id].ts +309 -0
  142. package/src/pages/api/media/folders.ts +609 -0
  143. package/src/pages/api/media/index.ts +146 -0
  144. package/src/pages/api/media/resize.ts +267 -0
  145. package/src/pages/api/search.ts +82 -0
  146. package/src/pages/api/slug-availability.ts +70 -0
  147. package/src/pages/api/storage-config.ts +20 -0
  148. package/src/pages/api/storage-status.ts +206 -0
  149. package/src/pages/api/upload.ts +334 -0
  150. package/src/pages/api/webhooks/index.ts +71 -0
  151. package/src/pages/audit/index.astro +2 -104
  152. package/src/pages/login.astro +82 -0
  153. package/src/pages/media.astro +10 -0
  154. package/src/pages/preview/[collection]/[id].astro +178 -0
  155. package/src/pages/register.astro +102 -0
  156. package/src/pages/roles/index.astro +21 -21
  157. package/src/pages/settings/[slug].astro +162 -0
  158. package/src/pages/settings/index.astro +9 -0
  159. package/src/pages/users/[id].astro +29 -21
  160. package/src/pages/users/index.astro +22 -17
  161. package/src/pages/users/new.astro +18 -17
  162. package/src/styles/main.css +553 -128
  163. package/src/components/layout/Sidebar.tsx +0 -497
  164. 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
+ }