@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
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
import "../styles/main.css";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const collections = registry.getCollections();
|
|
3
|
+
import { nonAuthCollections, collections, globals } from "@/lib/config";
|
|
4
|
+
import { CommandPaletteWrapper } from "@/components/ui/CommandPaletteWrapper";
|
|
5
|
+
import Sidebar from "../components/Sidebar.astro";
|
|
7
6
|
|
|
8
7
|
interface Props {
|
|
9
8
|
title: string;
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
const { title } = Astro.props;
|
|
12
|
+
const user = Astro.locals.user;
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
<!doctype html>
|
|
@@ -19,179 +19,173 @@ const { title } = Astro.props;
|
|
|
19
19
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
20
20
|
<title>{title} - Kyro CMS</title>
|
|
21
21
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
22
|
+
<script is:inline>
|
|
23
|
+
(() => {
|
|
24
|
+
const getTheme = () => {
|
|
25
|
+
const stored = localStorage.getItem("theme");
|
|
26
|
+
if (stored) return stored;
|
|
27
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
28
|
+
? "dark"
|
|
29
|
+
: "light";
|
|
30
|
+
};
|
|
31
|
+
const theme = getTheme();
|
|
32
|
+
if (theme === "dark") {
|
|
33
|
+
document.documentElement.classList.add("dark");
|
|
34
|
+
} else {
|
|
35
|
+
document.documentElement.classList.remove("dark");
|
|
36
|
+
}
|
|
37
|
+
})();
|
|
38
|
+
</script>
|
|
22
39
|
</head>
|
|
23
|
-
<body class="bg-[
|
|
40
|
+
<body class="bg-[var(--kyro-bg)] antialiased text-[var(--kyro-text-primary)]">
|
|
24
41
|
<div class="flex h-screen p-6 gap-6 overflow-hidden">
|
|
25
|
-
|
|
26
|
-
<aside
|
|
27
|
-
class="surface-tile w-[320px] flex flex-col flex-shrink-0 overflow-hidden"
|
|
28
|
-
>
|
|
29
|
-
<!-- Logo Section -->
|
|
30
|
-
<div class="px-4 py-8">
|
|
31
|
-
<div class="flex items-center gap-4">
|
|
32
|
-
<span class="text-3xl font-black tracking-tighter text-[#0b1222]"
|
|
33
|
-
>KYRO.</span
|
|
34
|
-
>
|
|
35
|
-
</div>
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
<!-- Navigation -->
|
|
39
|
-
<nav class="flex-1 px-4 overflow-y-auto">
|
|
40
|
-
<div class="space-y-2 mt-4">
|
|
41
|
-
<a
|
|
42
|
-
href="/"
|
|
43
|
-
class={`flex items-center gap-4 px-6 py-4 rounded-2xl transition-all font-bold ${
|
|
44
|
-
title === "Dashboard"
|
|
45
|
-
? "bg-[#0b1222] text-white shadow-lg"
|
|
46
|
-
: "text-[#64748b] hover:bg-gray-50 hover:text-[#0b1222]"
|
|
47
|
-
}`}
|
|
48
|
-
>
|
|
49
|
-
<svg
|
|
50
|
-
class="w-5 h-5"
|
|
51
|
-
fill="none"
|
|
52
|
-
stroke="currentColor"
|
|
53
|
-
viewBox="0 0 24 24"
|
|
54
|
-
><path
|
|
55
|
-
stroke-linecap="round"
|
|
56
|
-
stroke-linejoin="round"
|
|
57
|
-
stroke-width="2.5"
|
|
58
|
-
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"
|
|
59
|
-
></path></svg
|
|
60
|
-
>
|
|
61
|
-
<span>Dashboard</span>
|
|
62
|
-
</a>
|
|
63
|
-
|
|
64
|
-
<div class="pt-8 pb-4">
|
|
65
|
-
<p
|
|
66
|
-
class="px-6 text-[10px] font-black text-[#64748b] uppercase tracking-[0.3em] opacity-50"
|
|
67
|
-
>
|
|
68
|
-
Authentication
|
|
69
|
-
</p>
|
|
70
|
-
</div>
|
|
71
|
-
|
|
72
|
-
<a
|
|
73
|
-
href="/users"
|
|
74
|
-
class={`flex items-center gap-4 px-6 py-4 rounded-2xl transition-all font-bold ${
|
|
75
|
-
title === "Users"
|
|
76
|
-
? "bg-[#0b1222] text-white shadow-lg"
|
|
77
|
-
: "text-[#64748b] hover:bg-gray-50 hover:text-[#0b1222]"
|
|
78
|
-
}`}
|
|
79
|
-
>
|
|
80
|
-
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
81
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"></path>
|
|
82
|
-
</svg>
|
|
83
|
-
<span>Users</span>
|
|
84
|
-
</a>
|
|
85
|
-
|
|
86
|
-
<a
|
|
87
|
-
href="/roles"
|
|
88
|
-
class={`flex items-center gap-4 px-6 py-4 rounded-2xl transition-all font-bold ${
|
|
89
|
-
title === "Roles"
|
|
90
|
-
? "bg-[#0b1222] text-white shadow-lg"
|
|
91
|
-
: "text-[#64748b] hover:bg-gray-50 hover:text-[#0b1222]"
|
|
92
|
-
}`}
|
|
93
|
-
>
|
|
94
|
-
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
95
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>
|
|
96
|
-
</svg>
|
|
97
|
-
<span>Roles</span>
|
|
98
|
-
</a>
|
|
99
|
-
|
|
100
|
-
<a
|
|
101
|
-
href="/audit"
|
|
102
|
-
class={`flex items-center gap-4 px-6 py-4 rounded-2xl transition-all font-bold ${
|
|
103
|
-
title === "Audit Logs"
|
|
104
|
-
? "bg-[#0b1222] text-white shadow-lg"
|
|
105
|
-
: "text-[#64748b] hover:bg-gray-50 hover:text-[#0b1222]"
|
|
106
|
-
}`}
|
|
107
|
-
>
|
|
108
|
-
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
109
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
|
110
|
-
</svg>
|
|
111
|
-
<span>Audit Logs</span>
|
|
112
|
-
</a>
|
|
113
|
-
|
|
114
|
-
<div class="pt-8 pb-4">
|
|
115
|
-
<p
|
|
116
|
-
class="px-6 text-[10px] font-black text-[#64748b] uppercase tracking-[0.3em] opacity-50"
|
|
117
|
-
>
|
|
118
|
-
Collections
|
|
119
|
-
</p>
|
|
120
|
-
</div>
|
|
121
|
-
|
|
122
|
-
{
|
|
123
|
-
collections.map((col) => (
|
|
124
|
-
<a
|
|
125
|
-
href={`/${col.slug}`}
|
|
126
|
-
class="flex items-center gap-4 px-6 py-4 rounded-2xl text-[#64748b] font-bold transition-all hover:bg-gray-50 hover:text-[#0b1222] group"
|
|
127
|
-
>
|
|
128
|
-
<div class="w-2 h-2 rounded-full bg-gray-200 group-hover:bg-[#0b1222] transition-colors" />
|
|
129
|
-
<span>{col.label}</span>
|
|
130
|
-
</a>
|
|
131
|
-
))
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
<div class="pt-8 pb-4">
|
|
135
|
-
<p
|
|
136
|
-
class="px-6 text-[10px] font-black text-[#64748b] uppercase tracking-[0.3em] opacity-50"
|
|
137
|
-
>
|
|
138
|
-
System
|
|
139
|
-
</p>
|
|
140
|
-
</div>
|
|
141
|
-
|
|
142
|
-
<a
|
|
143
|
-
href="/admin"
|
|
144
|
-
class="flex items-center gap-4 px-6 py-4 rounded-2xl text-[#64748b] font-bold transition-all hover:bg-gray-50 hover:text-[#0b1222]"
|
|
145
|
-
>
|
|
146
|
-
<svg
|
|
147
|
-
class="w-5 h-5"
|
|
148
|
-
fill="none"
|
|
149
|
-
stroke="currentColor"
|
|
150
|
-
viewBox="0 0 24 24"
|
|
151
|
-
><path
|
|
152
|
-
stroke-linecap="round"
|
|
153
|
-
stroke-linejoin="round"
|
|
154
|
-
stroke-width="2.5"
|
|
155
|
-
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
|
156
|
-
></path><path
|
|
157
|
-
stroke-linecap="round"
|
|
158
|
-
stroke-linejoin="round"
|
|
159
|
-
stroke-width="2.5"
|
|
160
|
-
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path></svg
|
|
161
|
-
>
|
|
162
|
-
<span>Settings</span>
|
|
163
|
-
</a>
|
|
164
|
-
</div>
|
|
165
|
-
</nav>
|
|
166
|
-
|
|
167
|
-
<!-- User Section Tile-Adjacent -->
|
|
168
|
-
<div class="p-10 mt-auto bg-gray-50/50">
|
|
169
|
-
<div class="flex flex-col items-center text-center">
|
|
170
|
-
<div class="relative mb-5">
|
|
171
|
-
<img
|
|
172
|
-
src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?q=80&w=150&auto=format&fit=crop"
|
|
173
|
-
class="w-20 h-20 rounded-full object-cover border-4 border-white shadow-md"
|
|
174
|
-
alt="Emily Jonson"
|
|
175
|
-
/>
|
|
176
|
-
<div
|
|
177
|
-
class="absolute bottom-1 right-1 w-5 h-5 bg-orange-400 border-4 border-white rounded-full"
|
|
178
|
-
>
|
|
179
|
-
</div>
|
|
180
|
-
</div>
|
|
181
|
-
<h3 class="font-black text-lg text-[#0b1222] tracking-tight">
|
|
182
|
-
Emily Jonson
|
|
183
|
-
</h3>
|
|
184
|
-
<p class="text-xs text-[#64748b] mt-1 uppercase tracking-widest">
|
|
185
|
-
jonson@bress.com
|
|
186
|
-
</p>
|
|
187
|
-
</div>
|
|
188
|
-
</div>
|
|
189
|
-
</aside>
|
|
42
|
+
<Sidebar title={title} user={user} />
|
|
190
43
|
|
|
191
44
|
<!-- Main Content Column -->
|
|
192
45
|
<main class="flex-1 flex flex-col gap-6 overflow-hidden">
|
|
193
46
|
<slot />
|
|
194
47
|
</main>
|
|
195
48
|
</div>
|
|
49
|
+
|
|
50
|
+
<!-- Logout Confirmation Modal -->
|
|
51
|
+
<div
|
|
52
|
+
id="logout-modal"
|
|
53
|
+
class="fixed inset-0 z-50 hidden flex items-center justify-center"
|
|
54
|
+
>
|
|
55
|
+
<div
|
|
56
|
+
class="absolute inset-0 bg-black/50 backdrop-blur-sm"
|
|
57
|
+
id="logout-modal-backdrop"
|
|
58
|
+
>
|
|
59
|
+
</div>
|
|
60
|
+
<div
|
|
61
|
+
class="relative w-full max-w-sm mx-4 bg-[var(--kyro-surface)] rounded-lg shadow-2xl border border-[var(--kyro-border)]"
|
|
62
|
+
>
|
|
63
|
+
<div
|
|
64
|
+
class="flex items-center justify-between px-6 py-4 border-b border-[var(--kyro-border)]"
|
|
65
|
+
>
|
|
66
|
+
<h2 class="text-lg font-semibold text-[var(--kyro-text-primary)]">
|
|
67
|
+
Sign Out
|
|
68
|
+
</h2>
|
|
69
|
+
</div>
|
|
70
|
+
<div class="px-6 py-4">
|
|
71
|
+
<p class="text-[var(--kyro-text-secondary)]">
|
|
72
|
+
Are you sure you want to sign out?
|
|
73
|
+
</p>
|
|
74
|
+
</div>
|
|
75
|
+
<div
|
|
76
|
+
class="flex items-center justify-end gap-3 px-6 py-4 border-t border-[var(--kyro-border)] bg-[var(--kyro-surface-accent)] rounded-b-lg"
|
|
77
|
+
>
|
|
78
|
+
<button
|
|
79
|
+
id="logout-modal-cancel"
|
|
80
|
+
class="px-4 py-2 rounded-lg font-medium text-sm border border-[var(--kyro-border)] text-[var(--kyro-text-secondary)] hover:bg-[var(--kyro-surface-accent)] hover:text-[var(--kyro-text-primary)] transition-colors"
|
|
81
|
+
>Cancel</button
|
|
82
|
+
>
|
|
83
|
+
<button
|
|
84
|
+
id="logout-modal-confirm"
|
|
85
|
+
class="px-4 py-2 rounded-lg font-medium text-sm bg-red-500 text-white hover:bg-red-600 transition-colors"
|
|
86
|
+
>Sign Out</button
|
|
87
|
+
>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<!-- Command Palette (React) -->
|
|
93
|
+
<CommandPaletteWrapper
|
|
94
|
+
client:only="react"
|
|
95
|
+
collections={collections}
|
|
96
|
+
globals={globals}
|
|
97
|
+
/>
|
|
98
|
+
|
|
99
|
+
<!-- Theme UI Logic -->
|
|
100
|
+
<script is:inline>
|
|
101
|
+
const lightBtn = document.getElementById("theme-light-btn");
|
|
102
|
+
const darkBtn = document.getElementById("theme-dark-btn");
|
|
103
|
+
|
|
104
|
+
const updateUI = (theme) => {
|
|
105
|
+
const isDark = theme === "dark";
|
|
106
|
+
|
|
107
|
+
// Update Buttons
|
|
108
|
+
if (isDark) {
|
|
109
|
+
darkBtn?.classList.add(
|
|
110
|
+
"bg-[var(--kyro-sidebar-active)]",
|
|
111
|
+
"text-[var(--kyro-sidebar-text-active)]",
|
|
112
|
+
"shadow-lg",
|
|
113
|
+
);
|
|
114
|
+
darkBtn?.classList.remove("text-[var(--kyro-text-secondary)]");
|
|
115
|
+
lightBtn?.classList.remove(
|
|
116
|
+
"bg-[var(--kyro-sidebar-active)]",
|
|
117
|
+
"text-[var(--kyro-sidebar-text-active)]",
|
|
118
|
+
"shadow-lg",
|
|
119
|
+
);
|
|
120
|
+
lightBtn?.classList.add("text-[var(--kyro-text-secondary)]");
|
|
121
|
+
} else {
|
|
122
|
+
lightBtn?.classList.add(
|
|
123
|
+
"bg-[var(--kyro-sidebar-active)]",
|
|
124
|
+
"text-[var(--kyro-sidebar-text-active)]",
|
|
125
|
+
"shadow-lg",
|
|
126
|
+
);
|
|
127
|
+
lightBtn?.classList.remove("text-[var(--kyro-text-secondary)]");
|
|
128
|
+
darkBtn?.classList.remove(
|
|
129
|
+
"bg-[var(--kyro-sidebar-active)]",
|
|
130
|
+
"text-[var(--kyro-sidebar-text-active)]",
|
|
131
|
+
"shadow-lg",
|
|
132
|
+
);
|
|
133
|
+
darkBtn?.classList.add("text-[var(--kyro-text-secondary)]");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Update Document
|
|
137
|
+
if (isDark) {
|
|
138
|
+
document.documentElement.classList.add("dark");
|
|
139
|
+
} else {
|
|
140
|
+
document.documentElement.classList.remove("dark");
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// Initial Sync
|
|
145
|
+
const currentTheme =
|
|
146
|
+
localStorage.getItem("theme") ||
|
|
147
|
+
(window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
148
|
+
? "dark"
|
|
149
|
+
: "light");
|
|
150
|
+
updateUI(currentTheme);
|
|
151
|
+
|
|
152
|
+
// Listeners
|
|
153
|
+
lightBtn?.addEventListener("click", () => {
|
|
154
|
+
localStorage.setItem("theme", "light");
|
|
155
|
+
updateUI("light");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
darkBtn?.addEventListener("click", () => {
|
|
159
|
+
localStorage.setItem("theme", "dark");
|
|
160
|
+
updateUI("dark");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// System Preference Listener
|
|
164
|
+
window
|
|
165
|
+
.matchMedia("(prefers-color-scheme: dark)")
|
|
166
|
+
.addEventListener("change", (e) => {
|
|
167
|
+
if (!localStorage.getItem("theme")) {
|
|
168
|
+
updateUI(e.matches ? "dark" : "light");
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Logout Modal
|
|
173
|
+
const logoutModal = document.getElementById("logout-modal");
|
|
174
|
+
const logoutBackdrop = document.getElementById("logout-modal-backdrop");
|
|
175
|
+
const logoutCancel = document.getElementById("logout-modal-cancel");
|
|
176
|
+
const logoutConfirm = document.getElementById("logout-modal-confirm");
|
|
177
|
+
|
|
178
|
+
document.getElementById("logout-btn")?.addEventListener("click", () => {
|
|
179
|
+
logoutModal?.classList.remove("hidden");
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const closeLogoutModal = () => logoutModal?.classList.add("hidden");
|
|
183
|
+
|
|
184
|
+
logoutBackdrop?.addEventListener("click", closeLogoutModal);
|
|
185
|
+
logoutCancel?.addEventListener("click", closeLogoutModal);
|
|
186
|
+
logoutConfirm?.addEventListener("click", () => {
|
|
187
|
+
window.location.href = "/login";
|
|
188
|
+
});
|
|
189
|
+
</script>
|
|
196
190
|
</body>
|
|
197
191
|
</html>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
import "../styles/main.css";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
title: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { title } = Astro.props;
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<!doctype html>
|
|
12
|
+
<html lang="en">
|
|
13
|
+
<head>
|
|
14
|
+
<meta charset="UTF-8" />
|
|
15
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
16
|
+
<title>{title} - Kyro CMS</title>
|
|
17
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
18
|
+
<script is:inline>
|
|
19
|
+
(() => {
|
|
20
|
+
const getTheme = () => {
|
|
21
|
+
const stored = localStorage.getItem("theme");
|
|
22
|
+
if (stored) return stored;
|
|
23
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
24
|
+
};
|
|
25
|
+
const theme = getTheme();
|
|
26
|
+
if (theme === "dark") {
|
|
27
|
+
document.documentElement.classList.add("dark");
|
|
28
|
+
} else {
|
|
29
|
+
document.documentElement.classList.remove("dark");
|
|
30
|
+
}
|
|
31
|
+
})();
|
|
32
|
+
</script>
|
|
33
|
+
</head>
|
|
34
|
+
<body class="bg-[var(--kyro-bg)] antialiased text-[var(--kyro-text-primary)]">
|
|
35
|
+
<div class="min-h-screen flex flex-col items-center justify-center p-6">
|
|
36
|
+
<div class="w-full max-w-md flex flex-col items-center">
|
|
37
|
+
<!-- Logo -->
|
|
38
|
+
<div class="w-full text-center mb-8">
|
|
39
|
+
<a href="/" class="inline-block">
|
|
40
|
+
<span class="text-4xl font-black tracking-tighter text-[var(--kyro-text-primary)]">KYRO.</span>
|
|
41
|
+
</a>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class="w-full flex justify-center">
|
|
45
|
+
<slot />
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</body>
|
|
50
|
+
</html>
|