@kyro-cms/admin 0.9.0 → 0.9.1
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/index.cjs +11960 -11006
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +67 -65
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +563 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.js +12183 -11238
- package/dist/index.js.map +1 -1
- package/package.json +15 -11
- package/src/components/ActionBar.tsx +27 -14
- package/src/components/Admin.tsx +1 -1
- package/src/components/ApiKeysManager.tsx +5 -5
- package/src/components/AutoForm.tsx +585 -369
- package/src/components/BrandingHub.tsx +7 -4
- package/src/components/CreateView.tsx +2 -0
- package/src/components/DetailView.tsx +71 -56
- package/src/components/DeveloperCenter.tsx +8 -6
- package/src/components/FieldRenderer.tsx +94 -19
- package/src/components/ListView.tsx +33 -20
- package/src/components/MediaGallery.tsx +219 -194
- package/src/components/PluginsManager.tsx +197 -70
- package/src/components/RestPlayground.tsx +7 -7
- package/src/components/SessionsManager.tsx +1 -1
- package/src/components/SettingsPage.tsx +22 -0
- package/src/components/Sidebar.astro +13 -41
- package/src/components/UserManagement.tsx +153 -15
- package/src/components/UserMenu.tsx +30 -4
- package/src/components/VersionHistoryPanel.tsx +112 -119
- package/src/components/WebhookManager.tsx +6 -4
- package/src/components/blocks/ArrayBlock.tsx +6 -23
- package/src/components/blocks/BlockEditModal.tsx +82 -309
- package/src/components/blocks/CardBlock.tsx +35 -0
- package/src/components/blocks/ChildBlocksTree.tsx +57 -31
- package/src/components/blocks/GenericBlock.tsx +44 -0
- package/src/components/blocks/HeadingSubheadingBlock.tsx +32 -0
- package/src/components/blocks/HeroBlock.tsx +5 -14
- package/src/components/blocks/RichTextBlock.tsx +5 -5
- package/src/components/blocks/index.ts +5 -3
- package/src/components/fields/AccordionField.tsx +2 -2
- package/src/components/fields/ArrayField.tsx +1 -1
- package/src/components/fields/ArrayLayout.tsx +120 -29
- package/src/components/fields/BlocksField.tsx +430 -50
- package/src/components/fields/CardField.tsx +73 -0
- package/src/components/fields/CheckboxField.tsx +7 -3
- package/src/components/fields/DateField.tsx +4 -1
- package/src/components/fields/GroupLayout.tsx +2 -2
- package/src/components/fields/HeadingSubheadingField.tsx +43 -0
- package/src/components/fields/ListField.tsx +2 -2
- package/src/components/fields/NumberField.tsx +4 -1
- package/src/components/fields/RelationshipField.tsx +153 -87
- package/src/components/fields/RichTextField.tsx +781 -0
- package/src/components/fields/SecretField.tsx +102 -0
- package/src/components/fields/SelectField.tsx +19 -6
- package/src/components/fields/TabsLayout.tsx +19 -9
- package/src/components/fields/TextField.tsx +4 -1
- package/src/components/fields/UploadField.tsx +122 -56
- package/src/components/fields/extensions/blockComponents.tsx +103 -174
- package/src/components/fields/extensions/blocksStore.ts +8 -1
- package/src/components/fields/index.ts +4 -2
- package/src/components/ui/PageHeader.tsx +5 -5
- package/src/components/ui/SlidePanel.tsx +8 -3
- package/src/components/ui/icons.tsx +109 -109
- package/src/components/users/UserDetail.tsx +79 -16
- package/src/hooks/useAutoFormState.ts +125 -62
- package/src/integration.ts +148 -46
- package/src/kyro-cms.d.ts +7 -2
- package/src/layouts/AuthLayout.astro +14 -2
- package/src/lib/autoform-store.ts +85 -52
- package/src/lib/change-source.ts +9 -0
- package/src/lib/config.ts +104 -8
- package/src/lib/globals.ts +44 -9
- package/src/lib/normalize-upload-fields.ts +41 -0
- package/src/lib/paths.ts +2 -2
- package/src/lib/resolve-field-value.ts +110 -0
- package/src/lib/shim/use-sync-external-store-with-selector.js +30 -0
- package/src/lib/shim/use-sync-external-store.js +1 -0
- package/src/lib/stores/index.ts +1 -0
- package/src/lib/useResourceManager.ts +4 -4
- package/src/lib/vite-shim-plugin.ts +100 -0
- package/src/pages/[collection]/[id].astro +1 -1
- package/src/pages/preview/[collection]/[id].astro +4 -4
- package/src/pages/settings/[slug].astro +2 -2
- package/src/styles/main.css +60 -54
- package/README.md +0 -46
- package/dist/EditorClient-Q23UXR37.cjs +0 -468
- package/dist/EditorClient-Q23UXR37.cjs.map +0 -1
- package/dist/EditorClient-T5PASFNR.js +0 -466
- package/dist/EditorClient-T5PASFNR.js.map +0 -1
- package/dist/chunk-3BGDYKTD.cjs +0 -348
- package/dist/chunk-3BGDYKTD.cjs.map +0 -1
- package/dist/chunk-EEFXLQVT.js +0 -3
- package/dist/chunk-EEFXLQVT.js.map +0 -1
- package/src/components/blocks/ButtonBlock.tsx +0 -64
- package/src/components/blocks/ColumnsBlock.tsx +0 -55
- package/src/components/blocks/DividerBlock.tsx +0 -43
- package/src/components/blocks/LinkBlock.tsx +0 -65
- package/src/components/blocks/VStackBlock.tsx +0 -29
- package/src/components/fields/EditorClient.tsx +0 -535
- package/src/components/fields/PortableTextField.tsx +0 -155
- package/src/components/fields/PortableTextRenderer.tsx +0 -68
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useSyncExternalStore, useMemo } from "react";
|
|
2
|
+
|
|
3
|
+
export function useSyncExternalStoreWithSelector(
|
|
4
|
+
subscribe,
|
|
5
|
+
getSnapshot,
|
|
6
|
+
getServerSnapshot,
|
|
7
|
+
selector,
|
|
8
|
+
isEqual,
|
|
9
|
+
) {
|
|
10
|
+
const memoizedSelector = useMemo(() => {
|
|
11
|
+
let last, lastSnap, hasMemo = false;
|
|
12
|
+
return (snap) => {
|
|
13
|
+
if (!hasMemo || !Object.is(lastSnap, snap)) {
|
|
14
|
+
const next = selector(snap);
|
|
15
|
+
if (!hasMemo || !(isEqual ? isEqual(last, next) : Object.is(last, next))) {
|
|
16
|
+
last = next;
|
|
17
|
+
lastSnap = snap;
|
|
18
|
+
hasMemo = true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return last;
|
|
22
|
+
};
|
|
23
|
+
}, [selector, isEqual]);
|
|
24
|
+
const getSelection = () => memoizedSelector(getSnapshot());
|
|
25
|
+
const getServerSelection =
|
|
26
|
+
getServerSnapshot != null
|
|
27
|
+
? () => memoizedSelector(getServerSnapshot())
|
|
28
|
+
: undefined;
|
|
29
|
+
return useSyncExternalStore(subscribe, getSelection, getServerSelection);
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useSyncExternalStore } from "react";
|
package/src/lib/stores/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback } from "react";
|
|
2
2
|
import { apiGet, apiPost, apiDelete, apiPatch } from "./api";
|
|
3
|
-
import { useUIStore } from "./stores";
|
|
3
|
+
import { useUIStore, toast } from "./stores";
|
|
4
4
|
|
|
5
5
|
interface UseResourceManagerOptions<T> {
|
|
6
6
|
endpoint: string;
|
|
@@ -16,7 +16,7 @@ export function useResourceManager<T extends { id: string }>(
|
|
|
16
16
|
const [loading, setLoading] = useState(false);
|
|
17
17
|
const [error, setError] = useState<string | null>(null);
|
|
18
18
|
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
|
19
|
-
const { confirm
|
|
19
|
+
const { confirm } = useUIStore();
|
|
20
20
|
|
|
21
21
|
const load = useCallback(async () => {
|
|
22
22
|
setLoading(true);
|
|
@@ -52,12 +52,12 @@ export function useResourceManager<T extends { id: string }>(
|
|
|
52
52
|
options.onSuccess?.("delete", id);
|
|
53
53
|
} catch (e: unknown) {
|
|
54
54
|
const message = e instanceof Error ? e.message : `Failed to delete ${resourceName}`;
|
|
55
|
-
|
|
55
|
+
toast.error(message);
|
|
56
56
|
options.onError?.("delete", e as Error);
|
|
57
57
|
}
|
|
58
58
|
},
|
|
59
59
|
});
|
|
60
|
-
}, [options.endpoint, confirm
|
|
60
|
+
}, [options.endpoint, confirm]);
|
|
61
61
|
|
|
62
62
|
const create = useCallback(async (data: unknown) => {
|
|
63
63
|
setError(null);
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Vite plugin that intercepts `use-sync-external-store/shim` and
|
|
5
|
+
* `use-sync-external-store/shim/with-selector` imports and replaces them
|
|
6
|
+
* with proper ESM implementations.
|
|
7
|
+
*
|
|
8
|
+
* Why this is needed:
|
|
9
|
+
* - xstate-react (and other libs) import these shim files which are CJS-only.
|
|
10
|
+
* - When @kyro-cms/admin is consumed as a local `file:` workspace dependency,
|
|
11
|
+
* Vite skips pre-bundling for its transitive deps entirely, so the raw CJS
|
|
12
|
+
* files are served directly to the browser — which cannot parse them.
|
|
13
|
+
* - resolve.alias does not help because Vite's `resolveExportsOrImports` runs
|
|
14
|
+
* before alias matching for deep sub-path imports.
|
|
15
|
+
* - optimizeDeps.include does not help because it only applies to external npm
|
|
16
|
+
* packages, not transitive deps of local workspace packages.
|
|
17
|
+
* - A virtual Vite plugin with `enforce: "pre"` intercepts the import in the
|
|
18
|
+
* very first step of the resolution pipeline, before the filesystem is touched.
|
|
19
|
+
*
|
|
20
|
+
* useSyncExternalStoreWithSelector is NOT in the React core package, so we
|
|
21
|
+
* provide a minimal, spec-compliant implementation using the native
|
|
22
|
+
* useSyncExternalStore hook from React 18+.
|
|
23
|
+
*/
|
|
24
|
+
export function useSyncExternalStoreShimPlugin(): Plugin {
|
|
25
|
+
const SHIM_ID = "\0virtual:use-sync-external-store-shim";
|
|
26
|
+
const SHIM_WITH_SELECTOR_ID =
|
|
27
|
+
"\0virtual:use-sync-external-store-shim-with-selector";
|
|
28
|
+
|
|
29
|
+
const SHIM_PATHS = new Set([
|
|
30
|
+
"use-sync-external-store/shim",
|
|
31
|
+
"use-sync-external-store/shim/index.js",
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
const SHIM_WITH_SELECTOR_PATHS = new Set([
|
|
35
|
+
"use-sync-external-store/shim/with-selector",
|
|
36
|
+
"use-sync-external-store/shim/with-selector.js",
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
name: "use-sync-external-store-shim-fix",
|
|
41
|
+
enforce: "pre",
|
|
42
|
+
|
|
43
|
+
resolveId(id: string) {
|
|
44
|
+
if (SHIM_PATHS.has(id)) return SHIM_ID;
|
|
45
|
+
if (SHIM_WITH_SELECTOR_PATHS.has(id)) return SHIM_WITH_SELECTOR_ID;
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
load(id: string) {
|
|
49
|
+
if (id === SHIM_ID) {
|
|
50
|
+
// React 18+ ships useSyncExternalStore natively.
|
|
51
|
+
return `export { useSyncExternalStore } from "react";`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (id === SHIM_WITH_SELECTOR_ID) {
|
|
55
|
+
// useSyncExternalStoreWithSelector is not in React core.
|
|
56
|
+
// This is a minimal, spec-compliant implementation that wraps
|
|
57
|
+
// React's native useSyncExternalStore with selector memoisation.
|
|
58
|
+
return `
|
|
59
|
+
import { useSyncExternalStore, useRef, useMemo } from "react";
|
|
60
|
+
|
|
61
|
+
export function useSyncExternalStoreWithSelector(
|
|
62
|
+
subscribe,
|
|
63
|
+
getSnapshot,
|
|
64
|
+
getServerSnapshot,
|
|
65
|
+
selector,
|
|
66
|
+
isEqual
|
|
67
|
+
) {
|
|
68
|
+
const memoRef = useRef(null);
|
|
69
|
+
|
|
70
|
+
const memoizedSelector = useMemo(() => {
|
|
71
|
+
let lastSnapshot = undefined;
|
|
72
|
+
let lastSelection = undefined;
|
|
73
|
+
let hasMemo = false;
|
|
74
|
+
|
|
75
|
+
return (snapshot) => {
|
|
76
|
+
if (!hasMemo || !Object.is(lastSnapshot, snapshot)) {
|
|
77
|
+
const nextSelection = selector(snapshot);
|
|
78
|
+
if (!hasMemo || !(isEqual ? isEqual(lastSelection, nextSelection) : Object.is(lastSelection, nextSelection))) {
|
|
79
|
+
lastSnapshot = snapshot;
|
|
80
|
+
lastSelection = nextSelection;
|
|
81
|
+
hasMemo = true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return lastSelection;
|
|
85
|
+
};
|
|
86
|
+
}, [selector, isEqual]);
|
|
87
|
+
|
|
88
|
+
const getSelection = () => memoizedSelector(getSnapshot());
|
|
89
|
+
const getServerSelection =
|
|
90
|
+
getServerSnapshot !== undefined && getServerSnapshot !== null
|
|
91
|
+
? () => memoizedSelector(getServerSnapshot())
|
|
92
|
+
: undefined;
|
|
93
|
+
|
|
94
|
+
return useSyncExternalStore(subscribe, getSelection, getServerSelection);
|
|
95
|
+
}
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
@@ -58,7 +58,7 @@ const description =
|
|
|
58
58
|
data={doc || {}}
|
|
59
59
|
collectionSlug={collection}
|
|
60
60
|
documentId={id || undefined}
|
|
61
|
-
documentName={doc?.title || doc?.name || doc?.slug || "new-document"}
|
|
61
|
+
documentName={(typeof doc?.title === "object" ? "" : doc?.title) || (typeof doc?.name === "object" ? "" : doc?.name) || doc?.slug || "new-document"}
|
|
62
62
|
/>
|
|
63
63
|
<input type="hidden" id="form-data" name="form-data" value="{}" />
|
|
64
64
|
</form>
|
|
@@ -36,12 +36,12 @@ if (id) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const
|
|
40
|
-
? `Preview: ${doc.title || doc.name || doc.slug || id}`
|
|
39
|
+
const pageTitle = doc
|
|
40
|
+
? `Preview: ${(typeof doc.title === "object" ? "" : doc.title) || (typeof doc.name === "object" ? "" : doc.name) || doc.slug || id}`
|
|
41
41
|
: "Preview";
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
-
<AdminLayout title={
|
|
44
|
+
<AdminLayout title={pageTitle}>
|
|
45
45
|
<Fragment set:html={`<style>${richTextStyles}</style>`} />
|
|
46
46
|
<div class="flex-1 overflow-y-auto space-y-6">
|
|
47
47
|
<div class="surface-tile p-6 flex items-center justify-between">
|
|
@@ -222,7 +222,7 @@ const title = doc
|
|
|
222
222
|
</pre>
|
|
223
223
|
)}
|
|
224
224
|
{(!field.type || ["text", "string"].includes(field.type)) && (
|
|
225
|
-
<p>{value}</p>
|
|
225
|
+
<p>{typeof value === "object" ? JSON.stringify(value) : value}</p>
|
|
226
226
|
)}
|
|
227
227
|
</div>
|
|
228
228
|
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import AdminLayout from "../../layouts/AdminLayout.astro";
|
|
3
3
|
import { globals } from "../../lib/config";
|
|
4
|
-
import {
|
|
4
|
+
import { SettingsPage } from "../../components/SettingsPage";
|
|
5
5
|
|
|
6
6
|
import { adminPath, apiPath } from "../../lib/paths";
|
|
7
7
|
|
|
@@ -112,7 +112,7 @@ const description =
|
|
|
112
112
|
)}
|
|
113
113
|
<form id="settings-form">
|
|
114
114
|
<input type="hidden" id="form-slug" value={slug} />
|
|
115
|
-
<
|
|
115
|
+
<SettingsPage
|
|
116
116
|
client:only="react"
|
|
117
117
|
config={config}
|
|
118
118
|
globalSlug={slug}
|
package/src/styles/main.css
CHANGED
|
@@ -1078,6 +1078,35 @@
|
|
|
1078
1078
|
color: var(--kyro-sidebar-active);
|
|
1079
1079
|
}
|
|
1080
1080
|
|
|
1081
|
+
/* Compact inline array mode */
|
|
1082
|
+
.kyro-form-array--compact .kyro-form-field {
|
|
1083
|
+
margin-bottom: 0 !important;
|
|
1084
|
+
}
|
|
1085
|
+
.kyro-form-array--compact .kyro-form-field > div > :not([hidden]) ~ :not([hidden]) {
|
|
1086
|
+
margin-top: 2px !important;
|
|
1087
|
+
}
|
|
1088
|
+
.kyro-form-array--compact label {
|
|
1089
|
+
font-size: 9px;
|
|
1090
|
+
letter-spacing: 0.08em;
|
|
1091
|
+
margin-bottom: 0;
|
|
1092
|
+
opacity: 0.6;
|
|
1093
|
+
display: block;
|
|
1094
|
+
}
|
|
1095
|
+
.kyro-form-array--compact input:not([type="checkbox"]):not([type="radio"]),
|
|
1096
|
+
.kyro-form-array--compact textarea,
|
|
1097
|
+
.kyro-form-array--compact select {
|
|
1098
|
+
padding: 3px 6px !important;
|
|
1099
|
+
font-size: 11px !important;
|
|
1100
|
+
min-height: 26px !important;
|
|
1101
|
+
border-radius: 4px !important;
|
|
1102
|
+
}
|
|
1103
|
+
.kyro-form-array--compact label > span {
|
|
1104
|
+
display: none;
|
|
1105
|
+
}
|
|
1106
|
+
.kyro-form-array--compact [class*="description"] {
|
|
1107
|
+
display: none !important;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1081
1110
|
/* Blocks field */
|
|
1082
1111
|
.kyro-form-blocks {
|
|
1083
1112
|
display: flex;
|
|
@@ -1364,14 +1393,14 @@
|
|
|
1364
1393
|
color: var(--kyro-text-secondary);
|
|
1365
1394
|
}
|
|
1366
1395
|
|
|
1367
|
-
/* Toast —
|
|
1396
|
+
/* Toast — Colored Flat */
|
|
1368
1397
|
.kyro-toasts-container {
|
|
1369
1398
|
position: fixed;
|
|
1370
|
-
bottom:
|
|
1371
|
-
right:
|
|
1399
|
+
bottom: 16px;
|
|
1400
|
+
right: 16px;
|
|
1372
1401
|
display: flex;
|
|
1373
1402
|
flex-direction: column;
|
|
1374
|
-
gap:
|
|
1403
|
+
gap: 6px;
|
|
1375
1404
|
z-index: 9999;
|
|
1376
1405
|
pointer-events: none;
|
|
1377
1406
|
}
|
|
@@ -1379,82 +1408,59 @@
|
|
|
1379
1408
|
.kyro-toast {
|
|
1380
1409
|
display: flex;
|
|
1381
1410
|
align-items: center;
|
|
1382
|
-
gap:
|
|
1383
|
-
min-width:
|
|
1384
|
-
max-width:
|
|
1385
|
-
padding:
|
|
1386
|
-
background: rgba(11, 18, 34, 0.85);
|
|
1387
|
-
backdrop-filter: blur(12px);
|
|
1388
|
-
-webkit-backdrop-filter: blur(12px);
|
|
1411
|
+
gap: 8px;
|
|
1412
|
+
min-width: 240px;
|
|
1413
|
+
max-width: 340px;
|
|
1414
|
+
padding: 8px 10px;
|
|
1389
1415
|
color: white;
|
|
1390
|
-
border-radius:
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
0
|
|
1394
|
-
0
|
|
1416
|
+
border-radius: 8px;
|
|
1417
|
+
box-shadow:
|
|
1418
|
+
0 2px 4px -1px rgba(0, 0, 0, 0.08),
|
|
1419
|
+
0 8px 16px -4px rgba(0, 0, 0, 0.15),
|
|
1420
|
+
0 16px 24px -8px rgba(0, 0, 0, 0.2);
|
|
1395
1421
|
pointer-events: auto;
|
|
1396
|
-
overflow: hidden;
|
|
1397
1422
|
position: relative;
|
|
1423
|
+
transition: box-shadow 0.2s ease;
|
|
1398
1424
|
}
|
|
1399
1425
|
|
|
1400
|
-
.
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
.kyro-toast-accent {
|
|
1406
|
-
position: absolute;
|
|
1407
|
-
left: 0;
|
|
1408
|
-
top: 0;
|
|
1409
|
-
bottom: 0;
|
|
1410
|
-
width: 4px;
|
|
1411
|
-
background: var(--kyro-primary);
|
|
1412
|
-
}
|
|
1413
|
-
|
|
1414
|
-
.kyro-toast-success .kyro-toast-accent { background: #10b981; }
|
|
1415
|
-
.kyro-toast-error .kyro-toast-accent { background: #ef4444; }
|
|
1416
|
-
.kyro-toast-warning .kyro-toast-accent { background: #f59e0b; }
|
|
1417
|
-
.kyro-toast-info .kyro-toast-accent { background: #3b82f6; }
|
|
1426
|
+
.kyro-toast-success { background: #16a34a; }
|
|
1427
|
+
.kyro-toast-error { background: #dc2626; }
|
|
1428
|
+
.kyro-toast-warning { background: #d97706; }
|
|
1429
|
+
.kyro-toast-info { background: #4f46e5; }
|
|
1418
1430
|
|
|
1419
1431
|
.kyro-toast-icon-container {
|
|
1420
1432
|
flex-shrink: 0;
|
|
1421
|
-
width:
|
|
1422
|
-
height:
|
|
1423
|
-
border-radius: 10px;
|
|
1424
|
-
background: rgba(255, 255, 255, 0.05);
|
|
1433
|
+
width: 20px;
|
|
1434
|
+
height: 20px;
|
|
1425
1435
|
display: flex;
|
|
1426
1436
|
align-items: center;
|
|
1427
1437
|
justify-content: center;
|
|
1428
|
-
color: rgba(255, 255, 255, 0.
|
|
1438
|
+
color: rgba(255, 255, 255, 0.85);
|
|
1429
1439
|
}
|
|
1430
1440
|
|
|
1431
|
-
.kyro-toast-success .kyro-toast-icon-container { color: #10b981; background: rgba(16, 185, 129, 0.1); }
|
|
1432
|
-
.kyro-toast-error .kyro-toast-icon-container { color: #f87171; background: rgba(239, 68, 68, 0.1); }
|
|
1433
|
-
.kyro-toast-warning .kyro-toast-icon-container { color: #fbbf24; background: rgba(245, 158, 11, 0.1); }
|
|
1434
|
-
.kyro-toast-info .kyro-toast-icon-container { color: #60a5fa; background: rgba(59, 130, 246, 0.1); }
|
|
1435
|
-
|
|
1436
1441
|
.kyro-toast-content {
|
|
1437
1442
|
flex: 1;
|
|
1438
1443
|
min-width: 0;
|
|
1439
1444
|
}
|
|
1440
1445
|
|
|
1441
1446
|
.kyro-toast-message {
|
|
1442
|
-
font-size:
|
|
1443
|
-
font-weight:
|
|
1447
|
+
font-size: 12px;
|
|
1448
|
+
font-weight: 500;
|
|
1444
1449
|
letter-spacing: -0.01em;
|
|
1445
|
-
color: rgba(255, 255, 255, 0.
|
|
1446
|
-
line-height: 1.
|
|
1450
|
+
color: rgba(255, 255, 255, 0.92);
|
|
1451
|
+
line-height: 1.3;
|
|
1447
1452
|
}
|
|
1448
1453
|
|
|
1449
1454
|
.kyro-toast-close {
|
|
1450
|
-
padding:
|
|
1451
|
-
border-radius:
|
|
1452
|
-
color: rgba(255, 255, 255, 0.
|
|
1453
|
-
transition: all 0.
|
|
1455
|
+
padding: 3px;
|
|
1456
|
+
border-radius: 4px;
|
|
1457
|
+
color: rgba(255, 255, 255, 0.35);
|
|
1458
|
+
transition: all 0.15s ease;
|
|
1459
|
+
flex-shrink: 0;
|
|
1454
1460
|
}
|
|
1455
1461
|
|
|
1456
1462
|
.kyro-toast-close:hover {
|
|
1457
|
-
background: rgba(255, 255, 255, 0.
|
|
1463
|
+
background: rgba(255, 255, 255, 0.15);
|
|
1458
1464
|
color: white;
|
|
1459
1465
|
}
|
|
1460
1466
|
|
package/README.md
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# Kyro Admin MVP Extensibility
|
|
2
|
-
|
|
3
|
-
This repository contains a minimal, upgrade-safe extension surface for @kyro-cms/admin.
|
|
4
|
-
|
|
5
|
-
- Exposed modules: theme, hooks, plugins, blocks, fields, and the Astro integration (kyroAdmin).
|
|
6
|
-
- MVP samples are included for quick experimentation:
|
|
7
|
-
- MVP Hook samples: sampleHook, sampleHook2
|
|
8
|
-
- MVP Block samples: sampleBlock, sampleBlock2
|
|
9
|
-
- MVP Field samples: sampleField, sampleField2
|
|
10
|
-
- MVP Plugin sample: samplePlugin
|
|
11
|
-
|
|
12
|
-
How to try locally
|
|
13
|
-
|
|
14
|
-
- Build:
|
|
15
|
-
- Run: bun install
|
|
16
|
-
- Run: bun run build
|
|
17
|
-
- Dist artifacts will be emitted in admin/dist
|
|
18
|
-
- Test:
|
|
19
|
-
- Run: bun run test
|
|
20
|
-
- Tests cover MVP hooks; additional MVP tests can be added later
|
|
21
|
-
|
|
22
|
-
Usage notes
|
|
23
|
-
|
|
24
|
-
- kyroAdmin() is available from @kyro-cms/admin/integration and can be wired into Astro config
|
|
25
|
-
- MVP samples are designed to be initial templates for plugin authors; replace or extend with real logic
|
|
26
|
-
|
|
27
|
-
Next steps
|
|
28
|
-
|
|
29
|
-
- Decide on final API shape (per-feature exports vs central namespace)
|
|
30
|
-
- Add more MVP samples for blocks/fields/plugins and write accompanying tests
|
|
31
|
-
- Add documentation explaining how to author plugins and blocks
|
|
32
|
-
- MVP samples are included for quick experimentation:
|
|
33
|
-
- MVP Hook samples: sampleHook, sampleHook2
|
|
34
|
-
- MVP Block samples: sampleBlock, sampleBlock2
|
|
35
|
-
- MVP Field samples: sampleField, sampleField2
|
|
36
|
-
- MVP Plugin sample: samplePlugin
|
|
37
|
-
|
|
38
|
-
Export surface (MVP)
|
|
39
|
-
|
|
40
|
-
- The MVP exports are available per module:
|
|
41
|
-
- @kyro-cms/admin/hooks -> sampleHook, sampleHook2 (and lifecycle/data hooks)
|
|
42
|
-
- @kyro-cms/admin/blocks -> sampleBlock, sampleBlock2 (and registry)
|
|
43
|
-
- @kyro-cms/admin/fields -> sampleField, sampleField2 (and registry)
|
|
44
|
-
- @kyro-cms/admin/plugins -> samplePlugin, samplePlugin2 (and registry)
|
|
45
|
-
- The main integration (kyroAdmin) is available via @kyro-cms/admin/integration
|
|
46
|
-
- The theme module is available via @kyro-cms/admin/theme
|