@kyro-cms/admin 0.5.4 → 0.5.5

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 (38) hide show
  1. package/dist/{EditorClient-YLCGVDXY.cjs → EditorClient-Q23UXR37.cjs} +14 -14
  2. package/dist/{EditorClient-XEUOVAAC.js → EditorClient-T5PASFNR.js} +2 -2
  3. package/dist/chunk-3BGDYKTD.cjs +348 -0
  4. package/dist/chunk-3BGDYKTD.cjs.map +1 -0
  5. package/dist/chunk-EEFXLQVT.js +3 -0
  6. package/dist/chunk-EEFXLQVT.js.map +1 -0
  7. package/dist/index.cjs +462 -1020
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.css +13 -0
  10. package/dist/index.css.map +1 -1
  11. package/dist/index.js +271 -829
  12. package/dist/index.js.map +1 -1
  13. package/package.json +6 -2
  14. package/src/components/AuditLogsPage.tsx +4 -8
  15. package/src/components/Dashboard.tsx +2 -1
  16. package/src/components/DetailView.tsx +9 -2
  17. package/src/components/ListView.tsx +3 -2
  18. package/src/components/MediaGallery.tsx +13 -6
  19. package/src/components/Sidebar.astro +1 -1
  20. package/src/components/ui/Shimmer.tsx +28 -0
  21. package/src/components/users/UserDetail.tsx +1 -1
  22. package/src/components/users/UserForm.tsx +1 -1
  23. package/src/components/users/UsersList.tsx +1 -1
  24. package/src/hooks/useAutoFormState.ts +19 -3
  25. package/src/integration.ts +77 -25
  26. package/src/layouts/AdminLayout.astro +70 -48
  27. package/src/lib/config.ts +6 -1
  28. package/src/lib/globals.ts +56 -20
  29. package/src/pages/index.astro +1 -1
  30. package/src/pages/roles/index.astro +1 -1
  31. package/src/pages/users/[id].astro +2 -2
  32. package/src/styles/main.css +17 -0
  33. package/dist/chunk-7KPIUCGT.js +0 -384
  34. package/dist/chunk-7KPIUCGT.js.map +0 -1
  35. package/dist/chunk-GOACG6R7.cjs +0 -473
  36. package/dist/chunk-GOACG6R7.cjs.map +0 -1
  37. /package/dist/{EditorClient-XEUOVAAC.js.map → EditorClient-Q23UXR37.cjs.map} +0 -0
  38. /package/dist/{EditorClient-YLCGVDXY.cjs.map → EditorClient-T5PASFNR.js.map} +0 -0
@@ -1,24 +1,69 @@
1
- import projectConfig from "kyro:config";
2
1
  import type { BaseAdapter } from "../../../src/registry/types.js";
3
2
 
3
+ export interface GlobalOptions {
4
+ draft?: boolean;
5
+ /** Astro request object — used to pass auth cookies to the API endpoint */
6
+ request?: Request;
7
+ }
8
+
4
9
  /**
5
10
  * Fetches a global document by its slug.
6
- * Works only in environments where kyro:config is available (Astro server).
11
+ * Uses the API endpoint when an Astro request is provided (works for all dialects),
12
+ * falling back to the direct adapter approach.
7
13
  */
8
- export async function getGlobal(slug: string, options?: { draft?: boolean }) {
9
- const db = (projectConfig as Record<string, unknown>).adapter as BaseAdapter;
14
+ export async function getGlobal(slug: string, options?: GlobalOptions) {
15
+ // Strategy 1: Use the API endpoint (works for all dialects, adapter agnostic)
16
+ if (options?.request) {
17
+ try {
18
+ const apiPath = (globalThis as any).__KYRO_API_PATH__ || "/api";
19
+ const cookie = options.request.headers.get("cookie") || "";
20
+ const res = await fetch(`${apiPath}/globals/${slug}`, {
21
+ headers: { Cookie: cookie },
22
+ });
23
+ if (res.ok) {
24
+ const json = await res.json();
25
+ const doc = json.data || null;
26
+ if (!doc) return null;
27
+ // Resolve media fields via the same API endpoint
28
+ const mediaFields = ["siteLogo", "siteFavicon", "siteOgImage"];
29
+ for (const field of mediaFields) {
30
+ if (typeof doc[field] === "string" && doc[field].length > 0) {
31
+ try {
32
+ const mediaRes = await fetch(`${apiPath}/media/${doc[field]}`, {
33
+ headers: { Cookie: cookie },
34
+ });
35
+ if (mediaRes.ok) {
36
+ doc[field] = await mediaRes.json();
37
+ }
38
+ } catch { /* media field stays as ID string */ }
39
+ }
40
+ }
41
+ return doc;
42
+ }
43
+ } catch { /* fall through to adapter */ }
44
+ }
45
+
46
+ // Strategy 2: Direct adapter access (fallback for non-request contexts)
47
+ const global = globalThis as any;
48
+ const projectConfig = global.__KYRO_ADMIN_PROJECT_CONFIG__;
49
+ if (!projectConfig) return null;
50
+
51
+ const db = projectConfig.adapter as BaseAdapter | undefined;
10
52
  if (!db) return null;
11
53
 
12
54
  try {
55
+ // Initialize adapter if needed (DrizzleAdapter needs schema/globals maps)
56
+ if (typeof db.init === "function" && !global.__KYRO_ADAPTER_READY__) {
57
+ await db.init(projectConfig.collections || [], projectConfig.globals || []);
58
+ global.__KYRO_ADAPTER_READY__ = true;
59
+ }
13
60
  const doc = await db.findOne({
14
61
  collection: `_globals_${slug}`,
15
62
  where: {},
16
63
  draft: options?.draft ?? false,
17
64
  });
18
-
19
65
  if (!doc) return null;
20
66
 
21
- // Auto-resolve media IDs for common branding fields
22
67
  const mediaFields = ["siteLogo", "siteFavicon", "siteOgImage"];
23
68
  for (const field of mediaFields) {
24
69
  if (typeof doc[field] === "string" && doc[field].length > 0) {
@@ -27,24 +72,15 @@ export async function getGlobal(slug: string, options?: { draft?: boolean }) {
27
72
  collection: "media",
28
73
  id: doc[field],
29
74
  });
30
- if (mediaDoc) {
31
- doc[field] = mediaDoc;
32
- }
33
- } catch (e) {
34
- console.warn(`Failed to resolve media for field "${field}":`, e);
35
- }
75
+ if (mediaDoc) doc[field] = mediaDoc;
76
+ } catch { /* media field stays as ID string */ }
36
77
  }
37
78
  }
38
-
39
79
  return doc;
40
- } catch (e) {
41
- return null;
42
- }
80
+ } catch { return null; }
43
81
  }
44
82
 
45
- /**
46
- * Convenience helper to get the site settings.
47
- */
48
- export async function getSiteSettings(options?: { draft?: boolean }) {
83
+ /** Convenience helper to get the site settings. */
84
+ export async function getSiteSettings(options?: GlobalOptions) {
49
85
  return await getGlobal("site-settings", options);
50
86
  }
@@ -13,7 +13,7 @@ const authItems = authCollections.map((slug) => ({
13
13
  ---
14
14
 
15
15
  <AdminLayout title="Dashboard">
16
- <div class="flex-1 overflow-y-auto pr-12 space-y-8">
16
+ <div class="flex-1 overflow-y-auto space-y-8">
17
17
  <!-- Header -->
18
18
  <div class="surface-tile p-6 flex items-center justify-between gap-8">
19
19
  <div class="relative flex-1 max-w-2xl">
@@ -60,7 +60,7 @@ const permissions: Record<string, string[]> = {
60
60
  ---
61
61
 
62
62
  <AdminLayout title="Roles">
63
- <div class="flex-1 overflow-y-auto pr-12 space-y-8">
63
+ <div class="flex-1 overflow-y-auto space-y-8">
64
64
  <!-- Header -->
65
65
  <div class="surface-tile p-6">
66
66
  <h1
@@ -28,7 +28,7 @@ if (id) {
28
28
 
29
29
  <AdminLayout title={user ? user.email : "User"}>
30
30
  {error ? (
31
- <div class="flex-1 overflow-y-auto pr-12 space-y-8">
31
+ <div class="flex-1 overflow-y-auto space-y-8">
32
32
  <div class="surface-tile p-8">
33
33
  <div class="text-center">
34
34
  <p class="text-lg font-bold text-red-500">{error}</p>
@@ -44,7 +44,7 @@ if (id) {
44
44
  adminPath={adminPath}
45
45
  />
46
46
  ) : (
47
- <div class="flex-1 overflow-y-auto pr-12 space-y-8">
47
+ <div class="flex-1 overflow-y-auto space-y-8">
48
48
  <div class="surface-tile p-8 text-center">
49
49
  <p class="text-lg font-bold text-[var(--kyro-text-secondary)]">Loading...</p>
50
50
  </div>
@@ -1502,6 +1502,23 @@
1502
1502
  color: var(--kyro-gray-500);
1503
1503
  }
1504
1504
 
1505
+ /* Shimmer Loading Effect */
1506
+ @keyframes shimmer {
1507
+ 0% { background-position: -200% 0; }
1508
+ 100% { background-position: 200% 0; }
1509
+ }
1510
+
1511
+ .kyro-shimmer {
1512
+ background: linear-gradient(
1513
+ 90deg,
1514
+ var(--kyro-surface-accent) 25%,
1515
+ var(--kyro-border) 50%,
1516
+ var(--kyro-surface-accent) 75%
1517
+ );
1518
+ background-size: 200% 100%;
1519
+ animation: shimmer 1.5s ease-in-out infinite;
1520
+ }
1521
+
1505
1522
  /* Modal — Monochrome */
1506
1523
  .kyro-modal-overlay {
1507
1524
  position: fixed;