@kyro-cms/admin 0.1.7 → 0.1.9

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 (71) hide show
  1. package/package.json +7 -2
  2. package/src/components/Admin.tsx +1 -1
  3. package/src/components/AutoForm.tsx +966 -337
  4. package/src/components/CreateView.tsx +1 -1
  5. package/src/components/DetailView.tsx +1 -1
  6. package/src/components/EnhancedListView.tsx +156 -52
  7. package/src/components/ListView.tsx +1 -1
  8. package/src/components/Modal.tsx +65 -8
  9. package/src/components/Sidebar.astro +2 -2
  10. package/src/components/ThemeProvider.tsx +8 -2
  11. package/src/components/blocks/AccordionBlock.tsx +20 -52
  12. package/src/components/blocks/ArrayBlock.tsx +40 -31
  13. package/src/components/blocks/BlockEditModal.tsx +170 -581
  14. package/src/components/blocks/ButtonBlock.tsx +27 -128
  15. package/src/components/blocks/CodeBlock.tsx +88 -40
  16. package/src/components/blocks/ColumnsBlock.tsx +27 -85
  17. package/src/components/blocks/FileBlock.tsx +38 -39
  18. package/src/components/blocks/HeadingBlock.tsx +9 -31
  19. package/src/components/blocks/HeroBlock.tsx +42 -100
  20. package/src/components/blocks/ImageBlock.tsx +6 -7
  21. package/src/components/blocks/LinkBlock.tsx +27 -33
  22. package/src/components/blocks/ListBlock.tsx +47 -26
  23. package/src/components/blocks/RelationshipBlock.tsx +26 -233
  24. package/src/components/blocks/RichTextBlock.tsx +66 -0
  25. package/src/components/blocks/VStackBlock.tsx +23 -37
  26. package/src/components/blocks/VideoBlock.tsx +52 -32
  27. package/src/components/fields/AccordionField.tsx +213 -0
  28. package/src/components/fields/ArrayField.tsx +241 -0
  29. package/src/components/fields/BlocksField.tsx +5 -5
  30. package/src/components/fields/ButtonField.tsx +53 -0
  31. package/src/components/fields/CheckboxField.tsx +7 -3
  32. package/src/components/fields/ChildrenField.tsx +48 -0
  33. package/src/components/fields/CodeField.tsx +154 -94
  34. package/src/components/fields/ColumnsField.tsx +137 -0
  35. package/src/components/fields/DateField.tsx +9 -24
  36. package/src/components/fields/EditorClient.tsx +426 -160
  37. package/src/components/fields/HeadingField.tsx +31 -0
  38. package/src/components/fields/HeroField.tsx +101 -0
  39. package/src/components/fields/JSONField.tsx +7 -27
  40. package/src/components/fields/LinkField.tsx +81 -0
  41. package/src/components/fields/ListField.tsx +74 -0
  42. package/src/components/fields/MarkdownField.tsx +4 -26
  43. package/src/components/fields/NumberField.tsx +9 -27
  44. package/src/components/fields/PortableTextField.tsx +61 -49
  45. package/src/components/fields/RelationshipBlockField.tsx +233 -0
  46. package/src/components/fields/RelationshipField.tsx +59 -13
  47. package/src/components/fields/SelectField.tsx +6 -4
  48. package/src/components/fields/TextField.tsx +9 -24
  49. package/src/components/fields/UploadField.tsx +613 -0
  50. package/src/components/fields/VideoField.tsx +73 -0
  51. package/src/components/fields/extensions/blockComponents.tsx +11 -1
  52. package/src/components/fields/extensions/blocksStore.ts +1 -1
  53. package/src/components/fields/index.ts +12 -1
  54. package/src/components/layout/Layout.tsx +1 -1
  55. package/src/lib/api.ts +163 -0
  56. package/src/lib/config.ts +1 -1
  57. package/src/lib/dataStore.ts +87 -30
  58. package/src/lib/date-utils.ts +69 -0
  59. package/src/lib/db/version-adapter.ts +248 -0
  60. package/src/lib/i18n.tsx +353 -0
  61. package/src/lib/slugify.ts +15 -0
  62. package/src/lib/validation.ts +250 -0
  63. package/src/pages/api/[collection]/[id]/publish.ts +12 -4
  64. package/src/pages/api/[collection]/[id]/versions.ts +39 -9
  65. package/src/pages/api/[collection]/[id].ts +13 -1
  66. package/src/pages/api/[collection]/index.ts +5 -6
  67. package/src/styles/main.css +12 -2
  68. package/src/components/blocks/BlockEditModal.MARKER +0 -12
  69. package/src/components/fields/FileField.tsx +0 -390
  70. package/src/components/fields/HybridContentField.tsx +0 -109
  71. package/src/components/fields/ImageField.tsx +0 -429
@@ -1,14 +1,8 @@
1
- import React, {
2
- useCallback,
3
- useMemo,
4
- useEffect,
5
- useState,
6
- Suspense,
7
- lazy,
8
- } from "react";
1
+ import React, { useCallback, useEffect, useState, Suspense, lazy } from "react";
9
2
  import { githubLight } from "@uiw/codemirror-theme-github";
10
3
  import { aura } from "@uiw/codemirror-theme-aura";
11
- import type { CodeField as CodeFieldType } from "@kyro-cms/core";
4
+ import type { CodeField as CodeFieldType } from "@kyro-cms/core/client";
5
+ import { useTheme } from "../ThemeProvider";
12
6
 
13
7
  interface CodeFieldProps {
14
8
  field: CodeFieldType;
@@ -18,27 +12,24 @@ interface CodeFieldProps {
18
12
  disabled?: boolean;
19
13
  }
20
14
 
21
- // Lazy-loaded CodeMirror wrapper component
22
15
  const CodeMirrorEditor = lazy(() =>
23
16
  import("@uiw/react-codemirror").then((mod) => ({ default: mod.default })),
24
17
  );
25
18
 
26
19
  const LANGUAGES = [
27
- { value: "javascript", label: "JavaScript", ext: "javascript" },
28
- { value: "typescript", label: "TypeScript", ext: "javascript" },
29
- { value: "json", label: "JSON", ext: "json" },
30
- { value: "html", label: "HTML", ext: "html" },
31
- { value: "css", label: "CSS", ext: "css" },
32
- { value: "sql", label: "SQL", ext: "sql" },
33
- { value: "python", label: "Python", ext: "python" },
34
- { value: "rust", label: "Rust", ext: "rust" },
35
- { value: "java", label: "Java", ext: "java" },
36
- { value: "cpp", label: "C++", ext: "cpp" },
37
- { value: "php", label: "PHP", ext: "php" },
38
- { value: "markdown", label: "Markdown", ext: "markdown" },
20
+ { value: "javascript", label: "JavaScript" },
21
+ { value: "typescript", label: "TypeScript" },
22
+ { value: "json", label: "JSON" },
23
+ { value: "html", label: "HTML" },
24
+ { value: "css", label: "CSS" },
25
+ { value: "sql", label: "SQL" },
26
+ { value: "python", label: "Python" },
27
+ { value: "rust", label: "Rust" },
28
+ { value: "java", label: "Java" },
29
+ { value: "php", label: "PHP" },
30
+ { value: "markdown", label: "Markdown" },
39
31
  ];
40
32
 
41
- // Language extension loader
42
33
  const languageExtensions: Record<string, () => Promise<any>> = {
43
34
  javascript: () =>
44
35
  import("@codemirror/lang-javascript").then((m) =>
@@ -85,29 +76,28 @@ export const CodeField: React.FC<CodeFieldProps> = ({
85
76
  const [isDark, setIsDark] = useState(false);
86
77
  const [extensions, setExtensions] = useState<any[]>([]);
87
78
  const [loading, setLoading] = useState(false);
79
+ const [copied, setCopied] = useState(false);
80
+ const [isFullScreen, setIsFullScreen] = useState(false);
88
81
 
82
+ const { theme } = useTheme();
83
+ const accent = theme.colors?.accent || theme.colors?.primary || "#6366f1";
89
84
  const language = field.language?.toLowerCase() || "javascript";
90
85
 
91
86
  useEffect(() => {
92
87
  setIsMounted(true);
93
88
  setIsDark(document.documentElement.classList.contains("dark"));
94
-
95
89
  const observer = new MutationObserver(() => {
96
90
  setIsDark(document.documentElement.classList.contains("dark"));
97
91
  });
98
-
99
92
  observer.observe(document.documentElement, {
100
93
  attributes: true,
101
94
  attributeFilter: ["class"],
102
95
  });
103
-
104
96
  return () => observer.disconnect();
105
97
  }, []);
106
98
 
107
- // Load language extensions dynamically
108
99
  useEffect(() => {
109
100
  if (!isMounted) return;
110
-
111
101
  const loadExtensions = async () => {
112
102
  setLoading(true);
113
103
  try {
@@ -122,113 +112,183 @@ export const CodeField: React.FC<CodeFieldProps> = ({
122
112
  setLoading(false);
123
113
  }
124
114
  };
125
-
126
115
  loadExtensions();
127
116
  }, [language, isMounted]);
128
117
 
129
118
  const handleChange = useCallback(
130
- (val: string) => {
131
- onChange?.(val);
132
- },
119
+ (val: string) => onChange?.(val),
133
120
  [onChange],
134
121
  );
135
122
 
136
- const theme = isDark ? aura : githubLight;
123
+ const handleCopy = useCallback(() => {
124
+ navigator.clipboard.writeText(value);
125
+ setCopied(true);
126
+ setTimeout(() => setCopied(false), 1500);
127
+ }, [value]);
128
+
129
+ const toggleFullScreen = useCallback(() => {
130
+ setIsFullScreen((prev) => !prev);
131
+ document.body.style.overflow = !isFullScreen ? "hidden" : "";
132
+ }, [isFullScreen]);
133
+
134
+ const codeMirrorTheme = isDark ? aura : githubLight;
135
+ const langLabel =
136
+ LANGUAGES.find((l) => l.value === language)?.label || language;
137
+
138
+ const hexToRgba = (hex: string, alpha: number = 1) => {
139
+ const r = parseInt(hex.slice(1, 3), 16);
140
+ const g = parseInt(hex.slice(3, 5), 16);
141
+ const b = parseInt(hex.slice(5, 7), 16);
142
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
143
+ };
137
144
 
138
145
  if (!isMounted) {
139
146
  return (
140
- <div className="kyro-form-field">
141
- <label className="kyro-form-label">
142
- {field.label || field.name}
143
- {field.required && (
144
- <span className="kyro-form-label-required">*</span>
145
- )}
146
- </label>
147
- <div className="h-[300px] bg-[var(--kyro-surface)] animate-pulse rounded-md" />
147
+ <div className="space-y-3">
148
+ <div className="flex items-center gap-3">
149
+ <div className="h-5 w-24 rounded bg-[var(--kyro-surface-accent)] animate-pulse" />
150
+ <div className="h-5 w-16 rounded bg-[var(--kyro-surface-accent)] animate-pulse" />
151
+ </div>
152
+ <div className="h-[280px] rounded-xl bg-[var(--kyro-surface-accent)] animate-pulse" />
148
153
  </div>
149
154
  );
150
155
  }
151
156
 
152
157
  return (
153
- <div className="kyro-form-field">
158
+ <div
159
+ className="group"
160
+ style={
161
+ {
162
+ "--accent": accent,
163
+ "--accent-light": hexToRgba(accent, 0.1),
164
+ "--accent-light-2": hexToRgba(accent, 0.05),
165
+ } as React.CSSProperties
166
+ }
167
+ >
168
+ {/* Header */}
154
169
  <div className="flex items-center justify-between mb-2">
155
- <label className="kyro-form-label">
156
- {field.label || field.name}
157
- {field.required && (
158
- <span className="kyro-form-label-required">*</span>
159
- )}
160
- </label>
161
-
162
- {/* Language indicator */}
163
170
  <div className="flex items-center gap-2">
164
- {loading && (
165
- <span className="text-xs text-[var(--kyro-text-muted)] animate-pulse">
166
- Loading...
167
- </span>
168
- )}
169
- <span className="text-xs text-[var(--kyro-text-muted)]">
170
- {LANGUAGES.find((l) => l.value === language)?.label || language}
171
+ <span className="text-sm font-semibold text-[var(--kyro-text-primary)]">
172
+ {field.label || field.name}
173
+ </span>
174
+ <span
175
+ className="text-[10px] px-1.5 py-0.5 rounded font-semibold transition-colors"
176
+ style={{
177
+ backgroundColor: loading ? "var(--kyro-surface-accent)" : accent,
178
+ color: loading ? "var(--kyro-text-muted)" : "white",
179
+ }}
180
+ >
181
+ {loading ? "..." : langLabel}
171
182
  </span>
172
183
  </div>
184
+
185
+ {/* Action buttons */}
186
+ <div className="flex items-center gap-1">
187
+ <button
188
+ type="button"
189
+ onClick={handleCopy}
190
+ className="text-[10px] px-2 py-0.5 rounded font-medium transition-all"
191
+ style={{
192
+ backgroundColor: copied
193
+ ? "var(--kyro-success)"
194
+ : "var(--kyro-surface-accent)",
195
+ color: copied ? "white" : "var(--kyro-text-secondary)",
196
+ }}
197
+ >
198
+ {copied ? "Copied" : "Copy"}
199
+ </button>
200
+ <button
201
+ type="button"
202
+ onClick={toggleFullScreen}
203
+ className="text-[10px] px-2 py-0.5 rounded font-medium bg-[var(--kyro-surface-accent)] hover:bg-[var(--kyro-border)] transition-all"
204
+ style={{ color: "var(--kyro-text-secondary)" }}
205
+ >
206
+ {isFullScreen ? "Exit" : "Expand"}
207
+ </button>
208
+ </div>
173
209
  </div>
174
210
 
211
+ {/* Editor container */}
175
212
  <div
176
- className={`border border-[var(--kyro-border)] rounded-md overflow-hidden ${
177
- disabled ? "opacity-50 cursor-not-allowed" : ""
178
- } ${error ? "border-red-500" : ""}`}
213
+ className={`relative rounded-md overflow-hidden transition-all duration-200 ${
214
+ isFullScreen ? "fixed inset-4 z-50" : ""
215
+ }`}
216
+ style={{
217
+ backgroundColor: "var(--kyro-surface)",
218
+ borderColor: error ? "var(--kyro-error)" : "var(--kyro-border)",
219
+ borderWidth: "1px",
220
+ }}
179
221
  >
222
+ {/* Top accent bar */}
223
+ <div
224
+ className="absolute top-0 left-0 right-0 h-0.5 transition-all duration-200"
225
+ style={{ backgroundColor: accent }}
226
+ />
227
+
180
228
  <Suspense
181
229
  fallback={
182
- <div className="h-[300px] bg-[var(--kyro-surface)] animate-pulse flex items-center justify-center">
183
- <span className="text-xs text-[var(--kyro-text-muted)]">
184
- Loading editor...
185
- </span>
230
+ <div
231
+ className="h-[280px] flex items-center justify-center"
232
+ style={{ backgroundColor: "var(--kyro-surface)" }}
233
+ >
234
+ <div
235
+ className="w-6 h-6 rounded-full animate-spin"
236
+ style={{
237
+ borderColor: "var(--kyro-border)",
238
+ borderTopColor: accent,
239
+ borderWidth: "2px",
240
+ }}
241
+ />
186
242
  </div>
187
243
  }
188
244
  >
189
245
  <CodeMirrorEditor
190
246
  value={value}
191
- height="300px"
247
+ height={isFullScreen ? "calc(100vh - 100px)" : "280px"}
248
+ width="100%"
192
249
  extensions={extensions}
193
- theme={theme}
250
+ theme={codeMirrorTheme}
194
251
  onChange={handleChange}
195
252
  editable={!disabled}
196
- basicSetup={true}
253
+ basicSetup={{
254
+ lineNumbers: true,
255
+ highlightActiveLine: true,
256
+ bracketMatching: true,
257
+ closeBrackets: true,
258
+ autocompletion: true,
259
+ foldGutter: true,
260
+ }}
197
261
  style={{
198
262
  fontSize: "13px",
199
- fontFamily:
200
- "'Fira Code', 'JetBrains Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', monospace",
263
+ fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
201
264
  }}
202
265
  />
203
266
  </Suspense>
204
- </div>
205
267
 
206
- {/* Editor hints */}
207
- <div className="flex items-center gap-4 mt-2 text-xs text-[var(--kyro-text-muted)]">
208
- <span>
209
- <kbd className="px-1.5 py-0.5 bg-[var(--kyro-surface-accent)] rounded text-[10px] font-mono">
210
- Ctrl+F
211
- </kbd>{" "}
212
- Search
213
- </span>
214
- <span>
215
- <kbd className="px-1.5 py-0.5 bg-[var(--kyro-surface-accent)] rounded text-[10px] font-mono">
216
- Ctrl+Space
217
- </kbd>{" "}
218
- Autocomplete
219
- </span>
220
- <span>
221
- <kbd className="px-1.5 py-0.5 bg-[var(--kyro-surface-accent)] rounded text-[10px] font-mono">
222
- Ctrl+Z
223
- </kbd>{" "}
224
- Undo
225
- </span>
268
+ {/* Error message */}
269
+ {error && (
270
+ <div
271
+ className="absolute bottom-0 left-0 right-0 px-3 py-2 text-xs font-medium"
272
+ style={{
273
+ backgroundColor: "var(--kyro-danger-bg)",
274
+ color: "var(--kyro-error)",
275
+ }}
276
+ >
277
+ {error}
278
+ </div>
279
+ )}
226
280
  </div>
227
281
 
228
- {field.admin?.description && !error && (
229
- <p className="kyro-form-help">{field.admin.description}</p>
230
- )}
231
- {error && <p className="kyro-form-error">{error}</p>}
282
+ {/* Footer */}
283
+ <div
284
+ className="flex items-center justify-between mt-2 text-[10px]"
285
+ style={{ color: "var(--kyro-text-muted)" }}
286
+ >
287
+ <span>{value.split("\n").length} lines</span>
288
+ <span style={{ color: accent }}>CodeMirror</span>
289
+ </div>
232
290
  </div>
233
291
  );
234
292
  };
293
+
294
+ export default CodeField;
@@ -0,0 +1,137 @@
1
+ import React from "react";
2
+ import { ChildBlocksTree } from "../blocks/ChildBlocksTree";
3
+
4
+ interface ColumnData {
5
+ id: number;
6
+ children: any[];
7
+ }
8
+
9
+ interface ColumnsFieldProps {
10
+ columns?: number;
11
+ columnData?: ColumnData[];
12
+ onColumnsChange: (columns: number) => void;
13
+ onUpdateColumnChildren: (columnIndex: number, newChildren: any[]) => void;
14
+ compact?: boolean;
15
+ }
16
+
17
+ export const ColumnsField: React.FC<ColumnsFieldProps> = ({
18
+ columns = 2,
19
+ columnData = [],
20
+ onColumnsChange,
21
+ onUpdateColumnChildren,
22
+ compact = false,
23
+ }) => {
24
+ const normalizedColumnData = Array.from({ length: columns }, (_, i) => ({
25
+ id: i,
26
+ children: columnData[i]?.children || [],
27
+ }));
28
+
29
+ if (compact) {
30
+ return (
31
+ <div className="space-y-2">
32
+ <div className="flex items-center gap-2">
33
+ <span className="text-xs font-medium text-[var(--kyro-text-muted)]">
34
+ Columns:
35
+ </span>
36
+ <div className="flex items-center gap-0.5 bg-[var(--kyro-surface-accent)] rounded-lg p-0.5">
37
+ {Array.from({ length: 6 }, (_, i) => i + 1).map((n) => (
38
+ <button
39
+ key={n}
40
+ type="button"
41
+ onClick={() => onColumnsChange(n)}
42
+ className={`px-2.5 py-1 rounded-md text-xs font-medium transition-all ${
43
+ columns === n
44
+ ? "bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] shadow-sm"
45
+ : "text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)]"
46
+ }`}
47
+ >
48
+ {n}
49
+ </button>
50
+ ))}
51
+ </div>
52
+ </div>
53
+ <div className="overflow-x-auto pb-1">
54
+ <div className="flex gap-2 min-w-fit">
55
+ {normalizedColumnData.map((col, i) => (
56
+ <div
57
+ key={i}
58
+ className="w-[180px] border-2 border-dashed border-[var(--kyro-border)] rounded-lg p-2"
59
+ >
60
+ <div className="flex items-center justify-between mb-1.5 pb-1 border-b border-[var(--kyro-border)]">
61
+ <span className="text-[10px] font-medium text-[var(--kyro-text-muted)]">
62
+ Col {i + 1}
63
+ </span>
64
+ <span className="text-[10px] text-[var(--kyro-text-muted)]">
65
+ {col.children.length}
66
+ </span>
67
+ </div>
68
+ <ChildBlocksTree
69
+ blockId={`col-${i}`}
70
+ children={col.children}
71
+ onUpdateChildren={(c) => onUpdateColumnChildren(i, c)}
72
+ />
73
+ </div>
74
+ ))}
75
+ </div>
76
+ </div>
77
+ </div>
78
+ );
79
+ }
80
+
81
+ return (
82
+ <div className="space-y-4">
83
+ <div className="flex items-center gap-2">
84
+ <span className="text-xs font-medium text-[var(--kyro-text-muted)]">
85
+ Columns:
86
+ </span>
87
+ <div className="flex items-center gap-0.5 bg-[var(--kyro-surface-accent)] rounded-lg p-0.5">
88
+ {Array.from({ length: 6 }, (_, i) => i + 1).map((n) => (
89
+ <button
90
+ key={n}
91
+ type="button"
92
+ onClick={() => onColumnsChange(n)}
93
+ className={`px-3 py-1.5 rounded-md text-xs font-medium transition-all ${
94
+ columns === n
95
+ ? "bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] shadow-sm"
96
+ : "text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)]"
97
+ }`}
98
+ >
99
+ {n}
100
+ </button>
101
+ ))}
102
+ </div>
103
+ </div>
104
+ <div className="overflow-x-auto pb-2">
105
+ <div
106
+ className="grid gap-3 min-w-fit"
107
+ style={{
108
+ gridTemplateColumns: `repeat(${columns}, minmax(200px, 1fr))`,
109
+ }}
110
+ >
111
+ {normalizedColumnData.map((col, i) => (
112
+ <div
113
+ key={i}
114
+ className="border-2 border-dashed border-[var(--kyro-border)] rounded-lg p-3"
115
+ >
116
+ <div className="flex items-center justify-between mb-3 pb-2 border-b border-[var(--kyro-border)]">
117
+ <span className="text-xs font-medium text-[var(--kyro-text-primary)]">
118
+ Column {i + 1}
119
+ </span>
120
+ <span className="text-[10px] text-[var(--kyro-text-muted)]">
121
+ {col.children.length} blocks
122
+ </span>
123
+ </div>
124
+ <ChildBlocksTree
125
+ blockId={`col-${i}`}
126
+ children={col.children}
127
+ onUpdateChildren={(c) => onUpdateColumnChildren(i, c)}
128
+ />
129
+ </div>
130
+ ))}
131
+ </div>
132
+ </div>
133
+ </div>
134
+ );
135
+ };
136
+
137
+ export default ColumnsField;
@@ -1,5 +1,4 @@
1
- import { useEffect, useState } from "react";
2
- import type { DateField as DateFieldType } from "@kyro-cms/core";
1
+ import type { DateField as DateFieldType } from "@kyro-cms/core/client";
3
2
 
4
3
  interface DateFieldComponentProps {
5
4
  field: DateFieldType;
@@ -16,26 +15,14 @@ export default function DateField({
16
15
  error,
17
16
  disabled,
18
17
  }: DateFieldComponentProps) {
19
- const [isDark, setIsDark] = useState(false);
20
-
21
- useEffect(() => {
22
- setIsDark(document.documentElement.classList.contains("dark"));
23
- const observer = new MutationObserver(() => {
24
- setIsDark(document.documentElement.classList.contains("dark"));
25
- });
26
- observer.observe(document.documentElement, {
27
- attributes: true,
28
- attributeFilter: ["class"],
29
- });
30
- return () => observer.disconnect();
31
- }, []);
32
-
33
18
  return (
34
19
  <div className="space-y-1">
35
20
  {field.label && (
36
- <label className="block text-sm font-medium">
21
+ <label className="block text-sm font-medium text-[var(--kyro-text-primary)]">
37
22
  {field.label}
38
- {field.required && <span className="text-red-500 ml-1">*</span>}
23
+ {field.required && (
24
+ <span className="text-[var(--kyro-error)] ml-1">*</span>
25
+ )}
39
26
  </label>
40
27
  )}
41
28
  <input
@@ -48,22 +35,20 @@ export default function DateField({
48
35
  required={field.required}
49
36
  className={`w-full px-3 py-2 border rounded-md text-sm transition-colors ${
50
37
  error
51
- ? "border-red-300 focus:border-red-500 focus:ring-red-500"
38
+ ? "border-[var(--kyro-error)] focus:border-[var(--kyro-error)] focus:ring-[var(--kyro-error)]"
52
39
  : "border-[var(--kyro-border)] focus:border-[var(--kyro-primary)] focus:ring-[var(--kyro-primary)]"
53
40
  } ${
54
41
  disabled || field.admin?.readOnly
55
42
  ? "bg-[var(--kyro-bg-secondary)] text-[var(--kyro-text-secondary)] opacity-50"
56
- : isDark
57
- ? "bg-[var(--kyro-surface)] text-[var(--kyro-text-primary)]"
58
- : "bg-white text-gray-900"
43
+ : "bg-[var(--kyro-surface)] text-[var(--kyro-text-primary)]"
59
44
  }`}
60
45
  />
61
46
  {field.admin?.description && !error && (
62
- <p className="text-xs text-[var(--kyro-text-secondary)]">
47
+ <p className="text-xs text-[var(--kyro-text-muted)]">
63
48
  {field.admin.description}
64
49
  </p>
65
50
  )}
66
- {error && <p className="text-xs text-red-600">{error}</p>}
51
+ {error && <p className="text-xs text-[var(--kyro-error)]">{error}</p>}
67
52
  </div>
68
53
  );
69
54
  }