@kyro-cms/admin 0.1.6 → 0.1.8
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 +54 -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 +137 -28
- 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 +2155 -770
- package/src/components/BrandingHub.tsx +267 -0
- package/src/components/BulkActionsBar.tsx +3 -3
- package/src/components/CreateView.tsx +4 -4
- package/src/components/Dashboard.tsx +393 -0
- package/src/components/DetailView.tsx +200 -58
- package/src/components/DeveloperCenter.tsx +403 -0
- package/src/components/EnhancedListView.tsx +890 -0
- package/src/components/GraphQLExplorer.tsx +675 -0
- package/src/components/GraphQLPlayground.tsx +627 -0
- package/src/components/ListView.tsx +192 -54
- package/src/components/MediaGallery.tsx +1569 -0
- package/src/components/Modal.tsx +206 -0
- package/src/components/RestPlayground.tsx +951 -0
- package/src/components/Sidebar.astro +237 -0
- package/src/components/ThemeProvider.tsx +8 -2
- 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 +65 -0
- package/src/components/blocks/ArrayBlock.tsx +84 -0
- package/src/components/blocks/BlockEditModal.tsx +363 -0
- package/src/components/blocks/ButtonBlock.tsx +64 -0
- package/src/components/blocks/ChildBlocksTree.tsx +551 -0
- package/src/components/blocks/CodeBlock.tsx +114 -0
- package/src/components/blocks/ColumnsBlock.tsx +93 -0
- package/src/components/blocks/DividerBlock.tsx +43 -0
- package/src/components/blocks/FileBlock.tsx +63 -0
- package/src/components/blocks/HeadingBlock.tsx +59 -0
- package/src/components/blocks/HeroBlock.tsx +99 -0
- package/src/components/blocks/ImageBlock.tsx +82 -0
- package/src/components/blocks/LinkBlock.tsx +65 -0
- package/src/components/blocks/ListBlock.tsx +60 -0
- package/src/components/blocks/ParagraphBlock.tsx +61 -0
- package/src/components/blocks/RelationshipBlock.tsx +72 -0
- package/src/components/blocks/RichTextBlock.tsx +66 -0
- package/src/components/blocks/VStackBlock.tsx +61 -0
- package/src/components/blocks/VideoBlock.tsx +65 -0
- package/src/components/blocks/index.ts +10 -0
- package/src/components/fields/AccordionField.tsx +213 -0
- package/src/components/fields/ArrayField.tsx +241 -0
- package/src/components/fields/BlocksField.tsx +323 -0
- package/src/components/fields/ButtonField.tsx +53 -0
- package/src/components/fields/CheckboxField.tsx +18 -8
- package/src/components/fields/ChildrenField.tsx +48 -0
- package/src/components/fields/CodeField.tsx +294 -0
- package/src/components/fields/ColumnsField.tsx +137 -0
- package/src/components/fields/DateField.tsx +24 -12
- package/src/components/fields/EditorClient.tsx +537 -0
- package/src/components/fields/HeadingField.tsx +31 -0
- package/src/components/fields/HeroField.tsx +101 -0
- package/src/components/fields/JSONField.tsx +341 -0
- package/src/components/fields/LinkField.tsx +81 -0
- package/src/components/fields/ListField.tsx +74 -0
- package/src/components/fields/MarkdownField.tsx +260 -0
- package/src/components/fields/NumberField.tsx +25 -13
- package/src/components/fields/PortableTextField.tsx +155 -0
- package/src/components/fields/PortableTextRenderer.tsx +68 -0
- package/src/components/fields/RelationshipBlockField.tsx +233 -0
- package/src/components/fields/RelationshipField.tsx +278 -60
- package/src/components/fields/SelectField.tsx +28 -16
- package/src/components/fields/TextField.tsx +31 -15
- package/src/components/fields/UploadField.tsx +613 -0
- package/src/components/fields/VideoField.tsx +73 -0
- package/src/components/fields/extensions/blockComponents.tsx +247 -0
- package/src/components/fields/extensions/blocksStore.ts +273 -0
- package/src/components/fields/index.ts +24 -0
- package/src/components/index.ts +1 -2
- package/src/components/layout/Header.tsx +2 -2
- package/src/components/layout/Layout.tsx +3 -3
- 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 +23 -6
- package/src/lib/MediaService.ts +541 -0
- package/src/lib/api.ts +163 -0
- package/src/lib/auth/sqlite-adapter.ts +319 -0
- package/src/lib/config.ts +23 -7
- package/src/lib/dataStore.ts +188 -73
- package/src/lib/date-utils.ts +69 -0
- 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/db/version-adapter.ts +248 -0
- package/src/lib/graphql/index.ts +1 -0
- package/src/lib/graphql/schema.ts +443 -0
- package/src/lib/i18n.tsx +353 -0
- package/src/lib/rate-limit.ts +267 -0
- package/src/lib/slugify.ts +15 -0
- package/src/lib/storage.ts +374 -0
- package/src/lib/store.ts +85 -0
- package/src/lib/validation.ts +250 -0
- package/src/middleware.ts +70 -11
- 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 +200 -139
- 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 +52 -0
- package/src/pages/api/[collection]/[id]/unpublish.ts +42 -0
- package/src/pages/api/[collection]/[id]/versions.ts +66 -0
- package/src/pages/api/[collection]/[id].ts +114 -159
- package/src/pages/api/[collection]/index.ts +150 -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 +42 -24
- 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 +11 -11
- package/src/pages/media.astro +10 -0
- package/src/pages/preview/[collection]/[id].astro +178 -0
- package/src/pages/register.astro +13 -13
- 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 +563 -128
- package/src/components/layout/Sidebar.tsx +0 -497
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { createPortal } from "react-dom";
|
|
3
|
+
|
|
4
|
+
interface PromptModalProps {
|
|
5
|
+
open: boolean;
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
onSubmit: (value: string) => void;
|
|
8
|
+
title: string;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
defaultValue?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function PromptModal({
|
|
14
|
+
open,
|
|
15
|
+
onClose,
|
|
16
|
+
onSubmit,
|
|
17
|
+
title,
|
|
18
|
+
placeholder = "",
|
|
19
|
+
defaultValue = "",
|
|
20
|
+
}: PromptModalProps) {
|
|
21
|
+
const [value, setValue] = useState(defaultValue);
|
|
22
|
+
|
|
23
|
+
const handleSubmit = (e: React.FormEvent) => {
|
|
24
|
+
e.preventDefault();
|
|
25
|
+
if (value.trim()) {
|
|
26
|
+
onSubmit(value.trim());
|
|
27
|
+
setValue("");
|
|
28
|
+
onClose();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
if (!open) return null;
|
|
33
|
+
|
|
34
|
+
return createPortal(
|
|
35
|
+
<div className="fixed inset-0 z-[9999] flex items-center justify-center">
|
|
36
|
+
<div
|
|
37
|
+
className="absolute inset-0 bg-black/50 backdrop-blur-sm"
|
|
38
|
+
onClick={onClose}
|
|
39
|
+
/>
|
|
40
|
+
<div className="relative w-full max-w-md mx-4 bg-[var(--kyro-surface)] rounded-lg shadow-2xl animate-in fade-in zoom-in-95 duration-200 border border-[var(--kyro-border)]">
|
|
41
|
+
<div className="flex items-center justify-between px-6 py-4 border-b border-[var(--kyro-border)]">
|
|
42
|
+
<h2 className="text-lg font-semibold text-[var(--kyro-text-primary)]">
|
|
43
|
+
{title}
|
|
44
|
+
</h2>
|
|
45
|
+
<button
|
|
46
|
+
type="button"
|
|
47
|
+
onClick={onClose}
|
|
48
|
+
className="p-1 text-[var(--kyro-text-muted)] hover:text-[var(--kyro-text-primary)] rounded-lg hover:bg-[var(--kyro-surface-accent)] transition-colors"
|
|
49
|
+
>
|
|
50
|
+
<svg
|
|
51
|
+
width="20"
|
|
52
|
+
height="20"
|
|
53
|
+
viewBox="0 0 24 24"
|
|
54
|
+
fill="none"
|
|
55
|
+
stroke="currentColor"
|
|
56
|
+
strokeWidth="2"
|
|
57
|
+
>
|
|
58
|
+
<path d="M18 6L6 18M6 6l12 12" />
|
|
59
|
+
</svg>
|
|
60
|
+
</button>
|
|
61
|
+
</div>
|
|
62
|
+
<form onSubmit={handleSubmit}>
|
|
63
|
+
<div className="px-6 py-4">
|
|
64
|
+
<input
|
|
65
|
+
type="text"
|
|
66
|
+
value={value}
|
|
67
|
+
onChange={(e) => setValue(e.target.value)}
|
|
68
|
+
placeholder={placeholder}
|
|
69
|
+
autoFocus
|
|
70
|
+
className="w-full px-3 py-2 border border-[var(--kyro-input-border)] rounded-lg bg-[var(--kyro-input-bg)] text-[var(--kyro-text-primary)] placeholder-[var(--kyro-text-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--kyro-sidebar-active)] focus:border-transparent"
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
<div className="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">
|
|
74
|
+
<button
|
|
75
|
+
type="button"
|
|
76
|
+
onClick={onClose}
|
|
77
|
+
className="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"
|
|
78
|
+
>
|
|
79
|
+
Cancel
|
|
80
|
+
</button>
|
|
81
|
+
<button
|
|
82
|
+
type="submit"
|
|
83
|
+
disabled={!value.trim()}
|
|
84
|
+
className="px-4 py-2 rounded-lg font-medium text-sm bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] hover:opacity-90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
|
85
|
+
>
|
|
86
|
+
Confirm
|
|
87
|
+
</button>
|
|
88
|
+
</div>
|
|
89
|
+
</form>
|
|
90
|
+
</div>
|
|
91
|
+
</div>,
|
|
92
|
+
document.body,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import React, { useEffect, useRef, type ReactNode } from "react";
|
|
1
|
+
import React, { useEffect, useRef, useState, type ReactNode } from "react";
|
|
2
|
+
import { createPortal } from "react-dom";
|
|
2
3
|
|
|
3
4
|
interface SlidePanelProps {
|
|
4
5
|
open: boolean;
|
|
5
6
|
onClose: () => void;
|
|
6
7
|
title: string;
|
|
7
8
|
children: ReactNode;
|
|
8
|
-
width?: "sm" | "md" | "lg";
|
|
9
|
+
width?: "sm" | "md" | "lg" | "xl";
|
|
10
|
+
showOverlay?: boolean;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export function SlidePanel({
|
|
@@ -14,8 +16,14 @@ export function SlidePanel({
|
|
|
14
16
|
title,
|
|
15
17
|
children,
|
|
16
18
|
width = "md",
|
|
19
|
+
showOverlay = false,
|
|
17
20
|
}: SlidePanelProps) {
|
|
18
21
|
const panelRef = useRef<HTMLDivElement>(null);
|
|
22
|
+
const [hydrated, setHydrated] = useState(false);
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
setHydrated(true);
|
|
26
|
+
}, []);
|
|
19
27
|
|
|
20
28
|
useEffect(() => {
|
|
21
29
|
const handleEscape = (e: KeyboardEvent) => {
|
|
@@ -35,28 +43,37 @@ export function SlidePanel({
|
|
|
35
43
|
|
|
36
44
|
const widthClasses = {
|
|
37
45
|
sm: "w-[320px]",
|
|
38
|
-
md: "w-[
|
|
39
|
-
lg: "w-[
|
|
46
|
+
md: "w-[400px]",
|
|
47
|
+
lg: "w-[500px]",
|
|
48
|
+
xl: "w-[600px]",
|
|
40
49
|
};
|
|
41
50
|
|
|
42
|
-
if (!open) return null;
|
|
51
|
+
if (!open || !hydrated) return null;
|
|
43
52
|
|
|
44
|
-
return (
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
return createPortal(
|
|
54
|
+
<>
|
|
55
|
+
{showOverlay && (
|
|
56
|
+
<div
|
|
57
|
+
className="fixed inset-0 z-[99998] bg-black/50 backdrop-blur-sm"
|
|
58
|
+
onClick={onClose}
|
|
59
|
+
/>
|
|
60
|
+
)}
|
|
47
61
|
<div
|
|
48
62
|
ref={panelRef}
|
|
49
|
-
className={`
|
|
63
|
+
className={`fixed right-0 top-0 bottom-0 z-[99999] ${widthClasses[width]} bg-[var(--kyro-surface)] border-l border-[var(--kyro-border)] shadow-2xl flex flex-col animate-slideIn`}
|
|
50
64
|
>
|
|
51
|
-
<div className="flex items-center justify-between px-
|
|
52
|
-
<h2 className="text-
|
|
65
|
+
<div className="flex items-center justify-between px-4 py-3 border-b border-[var(--kyro-border)] bg-[var(--kyro-surface)]">
|
|
66
|
+
<h2 className="text-sm font-semibold text-[var(--kyro-text-primary)]">
|
|
67
|
+
{title}
|
|
68
|
+
</h2>
|
|
53
69
|
<button
|
|
70
|
+
type="button"
|
|
54
71
|
onClick={onClose}
|
|
55
|
-
className="p-1 text-
|
|
72
|
+
className="p-1.5 text-[var(--kyro-text-muted)] hover:text-[var(--kyro-text-primary)] hover:bg-[var(--kyro-surface-accent)] rounded-lg transition-colors"
|
|
56
73
|
>
|
|
57
74
|
<svg
|
|
58
|
-
width="
|
|
59
|
-
height="
|
|
75
|
+
width="16"
|
|
76
|
+
height="16"
|
|
60
77
|
viewBox="0 0 24 24"
|
|
61
78
|
fill="none"
|
|
62
79
|
stroke="currentColor"
|
|
@@ -66,8 +83,18 @@ export function SlidePanel({
|
|
|
66
83
|
</svg>
|
|
67
84
|
</button>
|
|
68
85
|
</div>
|
|
69
|
-
<div className="flex-1 overflow-y-auto p-
|
|
86
|
+
<div className="flex-1 overflow-y-auto p-4">{children}</div>
|
|
70
87
|
</div>
|
|
71
|
-
|
|
88
|
+
<style>{`
|
|
89
|
+
@keyframes slideIn {
|
|
90
|
+
from { transform: translateX(100%); }
|
|
91
|
+
to { transform: translateX(0); }
|
|
92
|
+
}
|
|
93
|
+
.animate-slideIn {
|
|
94
|
+
animation: slideIn 300ms ease-out;
|
|
95
|
+
}
|
|
96
|
+
`}</style>
|
|
97
|
+
</>,
|
|
98
|
+
document.body,
|
|
72
99
|
);
|
|
73
100
|
}
|
|
@@ -1,21 +1,42 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
useState,
|
|
5
|
+
type ReactNode,
|
|
6
|
+
useCallback,
|
|
7
|
+
} from "react";
|
|
2
8
|
|
|
3
9
|
interface Toast {
|
|
4
10
|
id: string;
|
|
5
|
-
type:
|
|
11
|
+
type: "success" | "error" | "info" | "warning";
|
|
6
12
|
message: string;
|
|
7
13
|
}
|
|
8
14
|
|
|
9
15
|
interface ToastContextType {
|
|
10
16
|
toasts: Toast[];
|
|
11
|
-
addToast: (type: Toast[
|
|
17
|
+
addToast: (type: Toast["type"], message: string) => void;
|
|
12
18
|
removeToast: (id: string) => void;
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
const ToastContext = createContext<ToastContextType | null>(null);
|
|
16
22
|
|
|
23
|
+
export function createToastContext() {
|
|
24
|
+
const [toasts, setToasts] = useState<Toast[]>([]);
|
|
25
|
+
|
|
26
|
+
const addToast = useCallback((type: Toast["type"], message: string) => {
|
|
27
|
+
const id = `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
28
|
+
setToasts((prev) => [...prev, { id, type, message }]);
|
|
29
|
+
}, []);
|
|
30
|
+
|
|
31
|
+
const removeToast = useCallback((id: string) => {
|
|
32
|
+
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
33
|
+
}, []);
|
|
34
|
+
|
|
35
|
+
return { toasts, addToast, removeToast };
|
|
36
|
+
}
|
|
37
|
+
|
|
17
38
|
interface ToastProps {
|
|
18
|
-
type: Toast[
|
|
39
|
+
type: Toast["type"];
|
|
19
40
|
message: string;
|
|
20
41
|
onClose: () => void;
|
|
21
42
|
}
|
|
@@ -23,37 +44,72 @@ interface ToastProps {
|
|
|
23
44
|
export function Toast({ type, message, onClose }: ToastProps) {
|
|
24
45
|
const icons = {
|
|
25
46
|
success: (
|
|
26
|
-
<svg
|
|
47
|
+
<svg
|
|
48
|
+
width="20"
|
|
49
|
+
height="20"
|
|
50
|
+
viewBox="0 0 24 24"
|
|
51
|
+
fill="none"
|
|
52
|
+
stroke="currentColor"
|
|
53
|
+
strokeWidth="2"
|
|
54
|
+
>
|
|
27
55
|
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
|
|
28
56
|
<path d="M22 4L12 14.01l-3-3" />
|
|
29
57
|
</svg>
|
|
30
58
|
),
|
|
31
59
|
error: (
|
|
32
|
-
<svg
|
|
60
|
+
<svg
|
|
61
|
+
width="20"
|
|
62
|
+
height="20"
|
|
63
|
+
viewBox="0 0 24 24"
|
|
64
|
+
fill="none"
|
|
65
|
+
stroke="currentColor"
|
|
66
|
+
strokeWidth="2"
|
|
67
|
+
>
|
|
33
68
|
<circle cx="12" cy="12" r="10" />
|
|
34
69
|
<path d="M15 9l-6 6M9 9l6 6" />
|
|
35
70
|
</svg>
|
|
36
71
|
),
|
|
37
72
|
warning: (
|
|
38
|
-
<svg
|
|
73
|
+
<svg
|
|
74
|
+
width="20"
|
|
75
|
+
height="20"
|
|
76
|
+
viewBox="0 0 24 24"
|
|
77
|
+
fill="none"
|
|
78
|
+
stroke="currentColor"
|
|
79
|
+
strokeWidth="2"
|
|
80
|
+
>
|
|
39
81
|
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
|
|
40
82
|
<path d="M12 9v4M12 17h.01" />
|
|
41
83
|
</svg>
|
|
42
84
|
),
|
|
43
85
|
info: (
|
|
44
|
-
<svg
|
|
86
|
+
<svg
|
|
87
|
+
width="20"
|
|
88
|
+
height="20"
|
|
89
|
+
viewBox="0 0 24 24"
|
|
90
|
+
fill="none"
|
|
91
|
+
stroke="currentColor"
|
|
92
|
+
strokeWidth="2"
|
|
93
|
+
>
|
|
45
94
|
<circle cx="12" cy="12" r="10" />
|
|
46
95
|
<path d="M12 16v-4M12 8h.01" />
|
|
47
96
|
</svg>
|
|
48
|
-
)
|
|
97
|
+
),
|
|
49
98
|
};
|
|
50
99
|
|
|
51
100
|
return (
|
|
52
101
|
<div className={`kyro-toast kyro-toast-${type}`}>
|
|
53
102
|
<span className="kyro-toast-icon">{icons[type]}</span>
|
|
54
103
|
<span className="kyro-toast-message">{message}</span>
|
|
55
|
-
<button className="kyro-toast-close" onClick={onClose}>
|
|
56
|
-
<svg
|
|
104
|
+
<button type="button" className="kyro-toast-close" onClick={onClose}>
|
|
105
|
+
<svg
|
|
106
|
+
width="16"
|
|
107
|
+
height="16"
|
|
108
|
+
viewBox="0 0 24 24"
|
|
109
|
+
fill="none"
|
|
110
|
+
stroke="currentColor"
|
|
111
|
+
strokeWidth="2"
|
|
112
|
+
>
|
|
57
113
|
<path d="M18 6L6 18M6 6l12 12" />
|
|
58
114
|
</svg>
|
|
59
115
|
</button>
|
|
@@ -61,9 +117,19 @@ export function Toast({ type, message, onClose }: ToastProps) {
|
|
|
61
117
|
);
|
|
62
118
|
}
|
|
63
119
|
|
|
64
|
-
export function ToastProvider({
|
|
120
|
+
export function ToastProvider({
|
|
121
|
+
children,
|
|
122
|
+
toasts = [],
|
|
123
|
+
addToast = () => {},
|
|
124
|
+
removeToast = () => {},
|
|
125
|
+
}: {
|
|
126
|
+
children: ReactNode;
|
|
127
|
+
toasts?: Toast[];
|
|
128
|
+
addToast?: (type: Toast["type"], message: string) => void;
|
|
129
|
+
removeToast?: (id: string) => void;
|
|
130
|
+
}) {
|
|
65
131
|
return (
|
|
66
|
-
<ToastContext.Provider value={{ toasts
|
|
132
|
+
<ToastContext.Provider value={{ toasts, addToast, removeToast }}>
|
|
67
133
|
{children}
|
|
68
134
|
</ToastContext.Provider>
|
|
69
135
|
);
|
|
@@ -72,7 +138,7 @@ export function ToastProvider({ children }: { children: ReactNode }) {
|
|
|
72
138
|
export function useToast() {
|
|
73
139
|
const context = useContext(ToastContext);
|
|
74
140
|
if (!context) {
|
|
75
|
-
throw new Error(
|
|
141
|
+
throw new Error("useToast must be used within a ToastProvider");
|
|
76
142
|
}
|
|
77
143
|
return context;
|
|
78
144
|
}
|
package/src/env.d.ts
ADDED
package/src/env.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
const envPath = path.join(process.cwd(), "..", ".env");
|
|
5
|
+
if (fs.existsSync(envPath)) {
|
|
6
|
+
const envContent = fs.readFileSync(envPath, "utf-8");
|
|
7
|
+
envContent.split("\n").forEach((line) => {
|
|
8
|
+
const trimmed = line.trim();
|
|
9
|
+
if (trimmed && !trimmed.startsWith("#")) {
|
|
10
|
+
const eqIndex = trimmed.indexOf("=");
|
|
11
|
+
if (eqIndex > 0) {
|
|
12
|
+
const key = trimmed.substring(0, eqIndex);
|
|
13
|
+
const value = trimmed.substring(eqIndex + 1);
|
|
14
|
+
if (!process.env[key]) {
|
|
15
|
+
process.env[key] = value;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -21,7 +21,6 @@ export {
|
|
|
21
21
|
type ThemeMode,
|
|
22
22
|
} from "./components/ThemeProvider";
|
|
23
23
|
export * from "./components/layout/Header";
|
|
24
|
-
export * from "./components/layout/Sidebar";
|
|
25
24
|
export * from "./components/ui/Button";
|
|
26
25
|
export * from "./components/ui/Badge";
|
|
27
26
|
export * from "./components/ui/Spinner";
|