@kyro-cms/admin 0.2.4 → 0.3.0

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 (68) hide show
  1. package/README.md +46 -272
  2. package/package.json +37 -10
  3. package/src/blocks/examples/sample-block-2.tsx +27 -0
  4. package/src/blocks/examples/sample-block.tsx +26 -0
  5. package/src/blocks/index.ts +14 -0
  6. package/src/blocks/registry.ts +38 -0
  7. package/src/blocks/types.ts +23 -0
  8. package/src/components/Admin.tsx +1 -1
  9. package/src/components/ApiKeysManager.tsx +1 -1
  10. package/src/components/AuditLogsPage.tsx +1 -1
  11. package/src/components/AutoForm.tsx +2 -2
  12. package/src/components/BrandingHub.tsx +1 -1
  13. package/src/components/CreateView.tsx +1 -1
  14. package/src/components/DetailView.tsx +1 -1
  15. package/src/components/DeveloperCenter.tsx +1 -1
  16. package/src/components/EnhancedListView.tsx +1 -1
  17. package/src/components/ListView.tsx +1 -1
  18. package/src/components/LoginPage.tsx +1 -1
  19. package/src/components/MediaGallery.tsx +1 -1
  20. package/src/components/UserManagement.tsx +1 -1
  21. package/src/components/WebhookManager.tsx +2 -2
  22. package/src/components/fields/RelationshipBlockField.tsx +1 -1
  23. package/src/components/fields/RelationshipField.tsx +1 -1
  24. package/src/components/fields/UploadField.tsx +1 -6
  25. package/src/components/ui/CommandPalette.tsx +1 -1
  26. package/src/fields/examples/sample-field-2.tsx +30 -0
  27. package/src/fields/examples/sample-field.tsx +30 -0
  28. package/src/fields/index.ts +33 -0
  29. package/src/fields/registry.tsx +46 -0
  30. package/src/fields/types.ts +24 -0
  31. package/src/hooks/data.ts +116 -0
  32. package/src/hooks/examples/sample-hook-2.ts +13 -0
  33. package/src/hooks/examples/sample-hook.ts +12 -0
  34. package/src/hooks/index.ts +19 -0
  35. package/src/hooks/lifecycle.ts +81 -0
  36. package/src/hooks/types.ts +40 -0
  37. package/src/index.ts +78 -0
  38. package/src/integration.ts +52 -0
  39. package/src/pages/api/[collection]/[id]/publish.ts +2 -2
  40. package/src/pages/api/[collection]/[id]/unpublish.ts +2 -2
  41. package/src/pages/api/[collection]/[id]/versions.ts +1 -1
  42. package/src/pages/api/[collection]/[id].ts +2 -2
  43. package/src/pages/api/[collection]/index.ts +2 -2
  44. package/src/pages/api/collections.ts +1 -1
  45. package/src/pages/api/globals/[slug].ts +2 -2
  46. package/src/pages/api/graphql.ts +3 -3
  47. package/src/pages/api/media/folders.ts +1 -1
  48. package/src/pages/api/media/index.ts +1 -1
  49. package/src/pages/api/media/resize.ts +1 -1
  50. package/src/pages/api/slug-availability.ts +2 -2
  51. package/src/pages/api/storage-config.ts +1 -1
  52. package/src/pages/api/storage-status.ts +1 -1
  53. package/src/pages/api/upload.ts +1 -1
  54. package/src/plugins/examples/sample-plugin-2.ts +21 -0
  55. package/src/plugins/examples/sample-plugin.ts +21 -0
  56. package/src/plugins/index.ts +10 -0
  57. package/src/plugins/registry.ts +36 -0
  58. package/src/plugins/types.ts +22 -0
  59. package/src/styles/main.css +2 -41
  60. package/src/theme/ThemeProvider.tsx +238 -0
  61. package/src/theme/index.ts +20 -0
  62. package/src/theme/tokens.ts +222 -0
  63. package/src/components/Modal.tsx +0 -206
  64. package/src/components/index.ts +0 -29
  65. package/src/env.ts +0 -20
  66. package/src/lib/i18n.tsx +0 -353
  67. package/src/lib/validation.ts +0 -250
  68. package/src/pages/api/globals/[slug]/test.ts +0 -171
@@ -0,0 +1,222 @@
1
+ export interface ThemeColors {
2
+ primary?: string;
3
+ secondary?: string;
4
+ background?: string;
5
+ surface?: string;
6
+ text?: string;
7
+ textMuted?: string;
8
+ border?: string;
9
+ success?: string;
10
+ error?: string;
11
+ warning?: string;
12
+ info?: string;
13
+ }
14
+
15
+ export interface ThemeTypography {
16
+ fontFamily?: string;
17
+ fontFamilyMono?: string;
18
+ fontSize?: {
19
+ xs?: string;
20
+ sm?: string;
21
+ md?: string;
22
+ lg?: string;
23
+ xl?: string;
24
+ "2xl"?: string;
25
+ "3xl"?: string;
26
+ "4xl"?: string;
27
+ };
28
+ fontWeight?: {
29
+ normal?: number;
30
+ medium?: number;
31
+ semibold?: number;
32
+ bold?: number;
33
+ };
34
+ }
35
+
36
+ export interface ThemeSpacing {
37
+ xs?: string;
38
+ sm?: string;
39
+ md?: string;
40
+ lg?: string;
41
+ xl?: string;
42
+ "2xl"?: string;
43
+ }
44
+
45
+ export interface ThemeRadius {
46
+ sm?: string;
47
+ md?: string;
48
+ lg?: string;
49
+ full?: string;
50
+ }
51
+
52
+ export interface ThemeShadows {
53
+ sm?: string;
54
+ md?: string;
55
+ lg?: string;
56
+ xl?: string;
57
+ }
58
+
59
+ export interface BlockThemeOverrides {
60
+ card?: {
61
+ background?: string;
62
+ borderRadius?: string;
63
+ padding?: string;
64
+ shadow?: string;
65
+ };
66
+ hero?: {
67
+ background?: string;
68
+ textAlign?: "left" | "center" | "right";
69
+ };
70
+ gallery?: {
71
+ gridColumns?: number;
72
+ gap?: string;
73
+ };
74
+ code?: {
75
+ fontFamily?: string;
76
+ fontSize?: string;
77
+ background?: string;
78
+ };
79
+ }
80
+
81
+ export interface FieldThemeOverrides {
82
+ input?: {
83
+ background?: string;
84
+ border?: string;
85
+ borderRadius?: string;
86
+ padding?: string;
87
+ focusRing?: string;
88
+ };
89
+ select?: {
90
+ background?: string;
91
+ border?: string;
92
+ };
93
+ textarea?: {
94
+ background?: string;
95
+ minHeight?: string;
96
+ };
97
+ richText?: {
98
+ toolbarBackground?: string;
99
+ buttonActive?: string;
100
+ };
101
+ upload?: {
102
+ dropzoneBackground?: string;
103
+ dropzoneActive?: string;
104
+ };
105
+ }
106
+
107
+ export interface KyroTheme {
108
+ id?: string;
109
+ label?: string;
110
+ colors?: ThemeColors;
111
+ typography?: ThemeTypography;
112
+ spacing?: ThemeSpacing;
113
+ borderRadius?: ThemeRadius;
114
+ shadows?: ThemeShadows;
115
+ blocks?: BlockThemeOverrides;
116
+ fields?: FieldThemeOverrides;
117
+ }
118
+
119
+ export const LIGHT_THEME: KyroTheme = {
120
+ id: "light",
121
+ label: "Light",
122
+ colors: {
123
+ primary: "#3b82f6",
124
+ secondary: "#8b5cf6",
125
+ background: "#f8fafc",
126
+ surface: "#ffffff",
127
+ text: "#0f172a",
128
+ textMuted: "#64748b",
129
+ border: "#e2e8f0",
130
+ success: "#22c55e",
131
+ error: "#ef4444",
132
+ warning: "#f59e0b",
133
+ info: "#06b6d4",
134
+ },
135
+ typography: {
136
+ fontFamily: "'Inter', system-ui, -apple-system, sans-serif",
137
+ fontFamilyMono: "'Fira Code', 'Cascadia Code', monospace",
138
+ },
139
+ spacing: {
140
+ xs: "0.25rem",
141
+ sm: "0.5rem",
142
+ md: "1rem",
143
+ lg: "1.5rem",
144
+ xl: "2rem",
145
+ "2xl": "3rem",
146
+ },
147
+ borderRadius: {
148
+ sm: "0.25rem",
149
+ md: "0.5rem",
150
+ lg: "0.75rem",
151
+ full: "9999px",
152
+ },
153
+ shadows: {
154
+ sm: "0 1px 2px rgba(0,0,0,0.05)",
155
+ md: "0 4px 6px -1px rgba(0,0,0,0.1)",
156
+ lg: "0 10px 15px -3px rgba(0,0,0,0.1)",
157
+ xl: "0 20px 25px -5px rgba(0,0,0,0.1)",
158
+ },
159
+ };
160
+
161
+ export const DARK_THEME: KyroTheme = {
162
+ id: "dark",
163
+ label: "Dark",
164
+ colors: {
165
+ primary: "#60a5fa",
166
+ secondary: "#a78bfa",
167
+ background: "#0b1222",
168
+ surface: "#1e293b",
169
+ text: "#f1f5f9",
170
+ textMuted: "#94a3b8",
171
+ border: "#334155",
172
+ success: "#4ade80",
173
+ error: "#f87171",
174
+ warning: "#fbbf24",
175
+ info: "#22d3ee",
176
+ },
177
+ typography: {
178
+ fontFamily: "'Inter', system-ui, -apple-system, sans-serif",
179
+ fontFamilyMono: "'Fira Code', 'Cascadia Code', monospace",
180
+ },
181
+ spacing: {
182
+ xs: "0.25rem",
183
+ sm: "0.5rem",
184
+ md: "1rem",
185
+ lg: "1.5rem",
186
+ xl: "2rem",
187
+ "2xl": "3rem",
188
+ },
189
+ borderRadius: {
190
+ sm: "0.25rem",
191
+ md: "0.5rem",
192
+ lg: "0.75rem",
193
+ full: "9999px",
194
+ },
195
+ shadows: {
196
+ sm: "0 1px 2px rgba(0,0,0,0.3)",
197
+ md: "0 4px 6px -1px rgba(0,0,0,0.4)",
198
+ lg: "0 10px 15px -3px rgba(0,0,0,0.4)",
199
+ xl: "0 20px 25px -5px rgba(0,0,0,0.5)",
200
+ },
201
+ };
202
+
203
+ export function mergeThemes(
204
+ base: KyroTheme,
205
+ overrides: Partial<KyroTheme>,
206
+ ): KyroTheme {
207
+ return {
208
+ ...base,
209
+ ...overrides,
210
+ colors: { ...base.colors, ...overrides.colors },
211
+ typography: { ...base.typography, ...overrides.typography },
212
+ spacing: { ...base.spacing, ...overrides.spacing },
213
+ borderRadius: { ...base.borderRadius, ...overrides.borderRadius },
214
+ shadows: { ...base.shadows, ...overrides.shadows },
215
+ blocks: base.blocks
216
+ ? { ...base.blocks, ...overrides.blocks }
217
+ : overrides.blocks,
218
+ fields: base.fields
219
+ ? { ...base.fields, ...overrides.fields }
220
+ : overrides.fields,
221
+ };
222
+ }
@@ -1,206 +0,0 @@
1
- import React, {
2
- createContext,
3
- useContext,
4
- useState,
5
- useCallback,
6
- type ReactNode,
7
- } from "react";
8
- import {
9
- Modal as UIModal,
10
- ModalContent,
11
- ModalActions,
12
- ConfirmModal,
13
- } from "./ui/Modal";
14
- import { PromptModal } from "./ui/PromptModal";
15
-
16
- export { UIModal as Modal, UIModal, ModalContent, ModalActions, ConfirmModal };
17
-
18
- // ============================================================================
19
- // Global Modal Context for programmatic access
20
- // ============================================================================
21
-
22
- type ModalVariant = "alert" | "confirm" | "prompt";
23
-
24
- interface ModalState {
25
- variant: ModalVariant;
26
- open: boolean;
27
- title: string;
28
- message?: string;
29
- placeholder?: string;
30
- defaultValue?: string;
31
- onConfirm?: (value?: string) => void;
32
- onCancel?: () => void;
33
- danger?: boolean;
34
- }
35
-
36
- const initialState: ModalState = {
37
- variant: "alert",
38
- open: false,
39
- title: "",
40
- message: "",
41
- onConfirm: () => {},
42
- onCancel: () => {},
43
- danger: false,
44
- };
45
-
46
- interface ModalContextType {
47
- showAlert: (title: string, message?: string) => void;
48
- showConfirm: (
49
- title: string,
50
- message: string,
51
- onConfirm: () => void,
52
- options?: { danger?: boolean },
53
- ) => void;
54
- showPrompt: (
55
- title: string,
56
- message: string,
57
- onConfirm: (value: string) => void,
58
- options?: { placeholder?: string; defaultValue?: string },
59
- ) => void;
60
- closeModal: () => void;
61
- }
62
-
63
- const ModalContext = createContext<ModalContextType | null>(null);
64
-
65
- export function useModal() {
66
- const context = useContext(ModalContext);
67
- if (!context) {
68
- throw new Error("useModal must be used within ModalProvider");
69
- }
70
- return context;
71
- }
72
-
73
- interface ModalProviderProps {
74
- children: ReactNode;
75
- }
76
-
77
- export function ModalProvider({ children }: ModalProviderProps) {
78
- const [state, setState] = useState<ModalState>(initialState);
79
- const [inputValue, setInputValue] = useState(state.defaultValue || "");
80
-
81
- const showAlert = useCallback((title: string, message?: string) => {
82
- setState({
83
- variant: "alert",
84
- open: true,
85
- title,
86
- message,
87
- onConfirm: () => setState((s) => ({ ...s, open: false })),
88
- onCancel: () => setState((s) => ({ ...s, open: false })),
89
- });
90
- }, []);
91
-
92
- const showConfirm = useCallback(
93
- (
94
- title: string,
95
- message: string,
96
- onConfirm: () => void,
97
- options?: { danger?: boolean },
98
- ) => {
99
- setState({
100
- variant: "confirm",
101
- open: true,
102
- title,
103
- message,
104
- danger: options?.danger,
105
- onConfirm: () => {
106
- onConfirm();
107
- setState((s) => ({ ...s, open: false }));
108
- },
109
- onCancel: () => setState((s) => ({ ...s, open: false })),
110
- });
111
- },
112
- [],
113
- );
114
-
115
- const showPrompt = useCallback(
116
- (
117
- title: string,
118
- message: string,
119
- onConfirm: (value: string) => void,
120
- options?: { placeholder?: string; defaultValue?: string },
121
- ) => {
122
- setState({
123
- variant: "prompt",
124
- open: true,
125
- title,
126
- message,
127
- placeholder: options?.placeholder,
128
- defaultValue: options?.defaultValue,
129
- onConfirm: (value) => {
130
- onConfirm(value || "");
131
- setState((s) => ({ ...s, open: false }));
132
- },
133
- onCancel: () => setState((s) => ({ ...s, open: false })),
134
- });
135
- },
136
- [],
137
- );
138
-
139
- const closeModal = useCallback(() => {
140
- setState((s) => ({ ...s, open: false }));
141
- }, []);
142
-
143
- // Re-order so imports come first, then showAlert
144
- const handleShowAlert = (title: string, message?: string) => {
145
- setState({
146
- variant: "alert",
147
- open: true,
148
- title,
149
- message,
150
- onConfirm: () => setState((s) => ({ ...s, open: false })),
151
- onCancel: () => setState((s) => ({ ...s, open: false })),
152
- });
153
- };
154
-
155
- return (
156
- <ModalContext.Provider
157
- value={{
158
- showAlert: handleShowAlert,
159
- showConfirm,
160
- showPrompt,
161
- closeModal,
162
- }}
163
- >
164
- {children}
165
- {state.variant === "confirm" && (
166
- <ConfirmModal
167
- open={state.open}
168
- onClose={state.onCancel || closeModal}
169
- onConfirm={() => state.onConfirm?.()}
170
- title={state.title}
171
- message={state.message || ""}
172
- variant={state.danger ? "danger" : "default"}
173
- />
174
- )}
175
- {state.variant === "alert" && (
176
- <UIModal
177
- open={state.open}
178
- onClose={state.onCancel || closeModal}
179
- title={state.title}
180
- size="sm"
181
- footer={
182
- <button
183
- type="button"
184
- onClick={() => state.onConfirm?.()}
185
- 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"
186
- >
187
- OK
188
- </button>
189
- }
190
- >
191
- <p className="text-[var(--kyro-text-secondary)]">{state.message}</p>
192
- </UIModal>
193
- )}
194
- {state.variant === "prompt" && (
195
- <PromptModal
196
- open={state.open}
197
- onClose={state.onCancel || closeModal}
198
- onSubmit={(value) => state.onConfirm?.(value)}
199
- title={state.title}
200
- placeholder={state.placeholder}
201
- defaultValue={state.defaultValue}
202
- />
203
- )}
204
- </ModalContext.Provider>
205
- );
206
- }
@@ -1,29 +0,0 @@
1
- export { Admin } from "./Admin";
2
- export { ListView } from "./ListView";
3
- export { DetailView } from "./DetailView";
4
- export { CreateView } from "./CreateView";
5
- export { Dashboard } from "./Dashboard";
6
- export { AutoForm } from "./AutoForm";
7
- export {
8
- ActionBar,
9
- type ActionBarProps,
10
- type DocumentStatus,
11
- type SaveStatus,
12
- } from "./ActionBar";
13
- export { BulkActionsBar } from "./BulkActionsBar";
14
- export { StatusBadge, CountBadge } from "./StatusBadge";
15
- export { VersionHistoryPanel } from "./VersionHistoryPanel";
16
- export {
17
- ThemeProvider,
18
- LightThemeProvider,
19
- DarkThemeProvider,
20
- useTheme,
21
- type ThemeMode,
22
- } from "./ThemeProvider";
23
- export * from "./ui/Button";
24
- export * from "./ui/Badge";
25
- export * from "./ui/Spinner";
26
- export * from "./ui/Toast";
27
- export { Dropdown, DropdownItem, DropdownSeparator } from "./ui/Dropdown";
28
- export { Modal, ConfirmModal } from "./ui/Modal";
29
- export { SlidePanel } from "./ui/SlidePanel";
package/src/env.ts DELETED
@@ -1,20 +0,0 @@
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
- }