@kyro-cms/admin 0.9.0 → 0.9.2

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 (114) hide show
  1. package/dist/index.cjs +11715 -11292
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +67 -65
  4. package/dist/index.css.map +1 -1
  5. package/dist/index.d.cts +564 -0
  6. package/dist/index.d.ts +11 -10
  7. package/dist/index.js +11326 -10912
  8. package/dist/index.js.map +1 -1
  9. package/package.json +16 -12
  10. package/src/components/ActionBar.tsx +25 -161
  11. package/src/components/Admin.tsx +2 -4
  12. package/src/components/ApiKeysManager.tsx +5 -5
  13. package/src/components/AuditLogsPage.tsx +2 -13
  14. package/src/components/AutoForm.tsx +572 -461
  15. package/src/components/BrandingHub.tsx +7 -4
  16. package/src/components/CreateView.tsx +2 -0
  17. package/src/components/DetailView.tsx +52 -65
  18. package/src/components/DeveloperCenter.tsx +8 -6
  19. package/src/components/FieldRenderer.tsx +94 -19
  20. package/src/components/ListView.tsx +57 -216
  21. package/src/components/MediaGallery.tsx +334 -367
  22. package/src/components/PluginsManager.tsx +197 -70
  23. package/src/components/RestPlayground.tsx +59 -52
  24. package/src/components/SessionsManager.tsx +1 -1
  25. package/src/components/SettingsPage.tsx +22 -0
  26. package/src/components/Sidebar.astro +13 -41
  27. package/src/components/UserManagement.tsx +153 -15
  28. package/src/components/UserMenu.tsx +30 -4
  29. package/src/components/VersionHistoryPanel.tsx +112 -119
  30. package/src/components/WebhookManager.tsx +6 -4
  31. package/src/components/blocks/ArrayBlock.tsx +6 -23
  32. package/src/components/blocks/BlockEditModal.tsx +82 -309
  33. package/src/components/blocks/CardBlock.tsx +35 -0
  34. package/src/components/blocks/ChildBlocksTree.tsx +57 -31
  35. package/src/components/blocks/GenericBlock.tsx +44 -0
  36. package/src/components/blocks/HeadingSubheadingBlock.tsx +32 -0
  37. package/src/components/blocks/HeroBlock.tsx +5 -14
  38. package/src/components/blocks/RichTextBlock.tsx +5 -5
  39. package/src/components/blocks/index.ts +5 -3
  40. package/src/components/fields/AccordionField.tsx +2 -2
  41. package/src/components/fields/ArrayField.tsx +1 -1
  42. package/src/components/fields/ArrayLayout.tsx +120 -29
  43. package/src/components/fields/BlocksField.tsx +433 -55
  44. package/src/components/fields/CardField.tsx +73 -0
  45. package/src/components/fields/CheckboxField.tsx +7 -3
  46. package/src/components/fields/DateField.tsx +4 -1
  47. package/src/components/fields/GroupLayout.tsx +2 -2
  48. package/src/components/fields/HeadingSubheadingField.tsx +43 -0
  49. package/src/components/fields/ListField.tsx +2 -2
  50. package/src/components/fields/NumberField.tsx +4 -1
  51. package/src/components/fields/RelationshipBlockField.tsx +2 -3
  52. package/src/components/fields/RelationshipField.tsx +155 -90
  53. package/src/components/fields/RichTextField.tsx +781 -0
  54. package/src/components/fields/SecretField.tsx +102 -0
  55. package/src/components/fields/SelectField.tsx +19 -6
  56. package/src/components/fields/TabsLayout.tsx +19 -9
  57. package/src/components/fields/TextField.tsx +4 -1
  58. package/src/components/fields/UploadField.tsx +122 -56
  59. package/src/components/fields/extensions/blockComponents.tsx +103 -174
  60. package/src/components/fields/extensions/blocksStore.ts +8 -1
  61. package/src/components/fields/index.ts +4 -2
  62. package/src/components/fix_imports.cjs +23 -0
  63. package/src/components/fix_imports2.cjs +19 -0
  64. package/src/components/replace_svgs.cjs +63 -0
  65. package/src/components/ui/Dropdown.tsx +7 -2
  66. package/src/components/ui/Modal.tsx +24 -27
  67. package/src/components/ui/PageHeader.tsx +5 -5
  68. package/src/components/ui/PromptModal.tsx +2 -10
  69. package/src/components/ui/SlidePanel.tsx +10 -13
  70. package/src/components/ui/SplitButton.tsx +107 -0
  71. package/src/components/ui/Toaster.tsx +0 -1
  72. package/src/components/ui/icons.tsx +110 -109
  73. package/src/components/users/UserDetail.tsx +79 -16
  74. package/src/components/users/UsersList.tsx +8 -85
  75. package/src/hooks/useAutoFormState.ts +187 -196
  76. package/src/hooks/useQueue.ts +60 -0
  77. package/src/integration.ts +148 -46
  78. package/src/kyro-cms.d.ts +7 -2
  79. package/src/layouts/AdminLayout.astro +22 -2
  80. package/src/layouts/AuthLayout.astro +67 -7
  81. package/src/lib/autoform-store.ts +90 -53
  82. package/src/lib/change-source.ts +9 -0
  83. package/src/lib/config.ts +104 -8
  84. package/src/lib/globals.ts +48 -11
  85. package/src/lib/normalize-upload-fields.ts +41 -0
  86. package/src/lib/paths.ts +2 -2
  87. package/src/lib/resolve-field-value.ts +110 -0
  88. package/src/lib/shim/use-sync-external-store-with-selector.js +30 -0
  89. package/src/lib/shim/use-sync-external-store.js +1 -0
  90. package/src/lib/stores/index.ts +1 -0
  91. package/src/lib/useResourceManager.ts +4 -4
  92. package/src/lib/vite-shim-plugin.ts +100 -0
  93. package/src/pages/[collection]/[id].astro +1 -1
  94. package/src/pages/auth/register.astro +5 -2
  95. package/src/pages/preview/[collection]/[id].astro +4 -4
  96. package/src/pages/settings/[slug].astro +2 -2
  97. package/src/styles/main.css +60 -54
  98. package/README.md +0 -46
  99. package/dist/EditorClient-Q23UXR37.cjs +0 -468
  100. package/dist/EditorClient-Q23UXR37.cjs.map +0 -1
  101. package/dist/EditorClient-T5PASFNR.js +0 -466
  102. package/dist/EditorClient-T5PASFNR.js.map +0 -1
  103. package/dist/chunk-3BGDYKTD.cjs +0 -348
  104. package/dist/chunk-3BGDYKTD.cjs.map +0 -1
  105. package/dist/chunk-EEFXLQVT.js +0 -3
  106. package/dist/chunk-EEFXLQVT.js.map +0 -1
  107. package/src/components/blocks/ButtonBlock.tsx +0 -64
  108. package/src/components/blocks/ColumnsBlock.tsx +0 -55
  109. package/src/components/blocks/DividerBlock.tsx +0 -43
  110. package/src/components/blocks/LinkBlock.tsx +0 -65
  111. package/src/components/blocks/VStackBlock.tsx +0 -29
  112. package/src/components/fields/EditorClient.tsx +0 -535
  113. package/src/components/fields/PortableTextField.tsx +0 -155
  114. package/src/components/fields/PortableTextRenderer.tsx +0 -68
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kyro-cms/admin",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },
@@ -77,12 +77,19 @@
77
77
  "@dnd-kit/utilities": "^3.2.2",
78
78
  "@graphiql/react": "^0.37.3",
79
79
  "@kyro-cms/core": "file:..",
80
- "@portabletext/editor": "^6.6.3",
81
- "@portabletext/react": "^6.0.3",
82
- "@portabletext/schema": "^2.1.1",
83
- "@portabletext/toolbar": "^7.0.26",
84
- "@portabletext/types": "^4.0.2",
85
80
  "@tailwindcss/vite": "^4.0.0",
81
+ "@tiptap/extension-color": "^3.23.6",
82
+ "@tiptap/extension-highlight": "^3.23.6",
83
+ "@tiptap/extension-image": "^3.23.6",
84
+ "@tiptap/extension-link": "^3.23.6",
85
+ "@tiptap/extension-task-item": "^3.23.6",
86
+ "@tiptap/extension-task-list": "^3.23.6",
87
+ "@tiptap/extension-text-align": "^3.23.6",
88
+ "@tiptap/extension-text-style": "^3.23.6",
89
+ "@tiptap/extension-underline": "^3.23.6",
90
+ "@tiptap/pm": "^3.23.6",
91
+ "@tiptap/react": "^3.23.6",
92
+ "@tiptap/starter-kit": "^3.23.6",
86
93
  "@types/pg": "^8.20.0",
87
94
  "@uiw/codemirror-theme-aura": "^4.25.9",
88
95
  "@uiw/codemirror-theme-dracula": "^4.25.9",
@@ -96,14 +103,11 @@
96
103
  "lucide-react": "^0.475.0",
97
104
  "react": "^19.0.0",
98
105
  "react-dom": "^19.0.0",
99
- "react-icons": "^5.0.0",
100
106
  "react-image-crop": "^11.0.10",
101
- "slate": "^0.124.1",
102
- "slate-history": "^0.113.1",
103
- "slate-react": "^0.124.0",
104
107
  "swup": "^4.9.0",
105
108
  "tailwindcss": "^4.0.0",
106
109
  "unstorage": "^1.17.5",
110
+ "use-sync-external-store": "1.5.0",
107
111
  "zustand": "^5.0.3"
108
112
  },
109
113
  "devDependencies": {
@@ -111,12 +115,12 @@
111
115
  "@types/react": "^19.0.0",
112
116
  "@types/react-dom": "^19.0.0",
113
117
  "dotenv-cli": "^11.0.0",
114
- "tsup": "^6.0.0",
118
+ "tsup": "^8.5.1",
115
119
  "typescript": "^5.7.3",
116
120
  "vitest": "^4.1.4"
117
121
  },
118
122
  "peerDependencies": {
119
- "@kyro-cms/core": "^0.6.0",
123
+ "@kyro-cms/core": "^0.9.2",
120
124
  "react": "^19.0.0",
121
125
  "react-dom": "^19.0.0"
122
126
  },
@@ -1,5 +1,7 @@
1
- import React, { useState, useEffect, useCallback } from "react";
2
- import { Dropdown, DropdownItem, DropdownSeparator } from "./ui/Dropdown";
1
+ import React from "react";
2
+ import { IconPlus, IconSend, IconClock, IconArchive, IconUndo, IconCopy, IconEye, IconTrash2 } from "./ui/icons";
3
+ import { DropdownItem, DropdownSeparator } from "./ui/Dropdown";
4
+ import { SplitButton } from "./ui/SplitButton";
3
5
  import { Spinner } from "./ui/Spinner";
4
6
 
5
7
  export type DocumentStatus = "draft" | "published" | "scheduled" | "archived";
@@ -42,81 +44,27 @@ export function ActionBar({
42
44
  return null;
43
45
  };
44
46
 
45
- const getSaveButtonClass = () => {
46
- const base = "kyro-btn kyro-btn-md text-[11px] font-bold tracking-widest transition-all duration-300";
47
- if (saveStatus === "saving") return `${base} bg-[var(--kyro-gray-400)] text-white opacity-70 cursor-wait`;
48
- if (saveStatus === "saved") return `${base} bg-[var(--kyro-success)] border-[var(--kyro-success)] text-white shadow-[0_0_15px_rgba(34,197,94,0.3)]`;
49
- if (saveStatus === "error") return `${base} bg-[var(--kyro-error)] border-[var(--kyro-error)] text-white shadow-[0_0_15px_rgba(239,68,68,0.3)]`;
50
- if (hasChanges) return `${base} bg-[var(--kyro-warning)] border-[var(--kyro-warning)] text-black shadow-[0_0_15px_rgba(255,174,0,0.3)] animate-pulse`;
51
- return `${base} bg-[var(--kyro-gray-500)] border-[var(--kyro-gray-500)] text-white hover:bg-[var(--kyro-gray-600)]`;
52
- };
53
-
54
47
  const getStatusBadge = () => {
55
48
  const statusConfig = {
56
49
  draft: {
57
50
  label: "Draft",
58
51
  class: "bg-gray-100 text-gray-600 border-gray-200",
59
- icon: (
60
- <svg
61
- width="12"
62
- height="12"
63
- viewBox="0 0 24 24"
64
- fill="none"
65
- stroke="currentColor"
66
- strokeWidth="2.5"
67
- >
68
- <path d="M12 2v20M2 12h20" />
69
- </svg>
70
- ),
52
+ icon: <IconPlus className="w-3 h-3" />,
71
53
  },
72
54
  published: {
73
55
  label: "Published",
74
56
  class: "bg-green-100 text-green-700 border-green-200",
75
- icon: (
76
- <svg
77
- width="12"
78
- height="12"
79
- viewBox="0 0 24 24"
80
- fill="none"
81
- stroke="currentColor"
82
- strokeWidth="2.5"
83
- >
84
- <path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z" />
85
- </svg>
86
- ),
57
+ icon: <IconSend className="w-3 h-3" />,
87
58
  },
88
59
  scheduled: {
89
60
  label: "Scheduled",
90
61
  class: "bg-blue-100 text-blue-700 border-blue-200",
91
- icon: (
92
- <svg
93
- width="12"
94
- height="12"
95
- viewBox="0 0 24 24"
96
- fill="none"
97
- stroke="currentColor"
98
- strokeWidth="2.5"
99
- >
100
- <circle cx="12" cy="12" r="10" />
101
- <path d="M12 6v6l4 2" />
102
- </svg>
103
- ),
62
+ icon: <IconClock className="w-3 h-3" />,
104
63
  },
105
64
  archived: {
106
65
  label: "Archived",
107
66
  class: "bg-yellow-100 text-yellow-700 border-yellow-200",
108
- icon: (
109
- <svg
110
- width="12"
111
- height="12"
112
- viewBox="0 0 24 24"
113
- fill="none"
114
- stroke="currentColor"
115
- strokeWidth="2.5"
116
- >
117
- <path d="M21 8v13H3V8M1 3h22v5H1zM10 12h4" />
118
- </svg>
119
- ),
67
+ icon: <IconArchive className="w-3 h-3" />,
120
68
  },
121
69
  };
122
70
  const config = statusConfig[status];
@@ -142,7 +90,7 @@ export function ActionBar({
142
90
  {getStatusBadge()}
143
91
  {getSaveStatusText() && (
144
92
  <span
145
- className={`text-sm ${saveStatus === "error" ? "text-red-500" : "text-gray-500"}`}
93
+ className={`text-sm ${saveStatus === "error" ? "text-[var(--kyro-error)]" : "text-[var(--kyro-text-muted)]"}`}
146
94
  >
147
95
  {saveStatus === "saving" ? (
148
96
  <Spinner size="sm" className="inline mr-1" />
@@ -153,7 +101,7 @@ export function ActionBar({
153
101
  </div>
154
102
  <div className="text-xs space-y-0.5">
155
103
  {updatedAt && (
156
- <div className="text-gray-400">
104
+ <div className="text-[var(--kyro-text-muted)]">
157
105
  Updated: {formatDate(updatedAt)}
158
106
  </div>
159
107
  )}
@@ -170,18 +118,9 @@ export function ActionBar({
170
118
  <button type="button"
171
119
  onClick={onPublish}
172
120
  disabled={saveStatus === "saving"}
173
- className="bg-[var(--kyro-primary)] hover:opacity-90 text-white kyro-btn-md flex items-center gap-2"
121
+ className="kyro-btn kyro-btn-primary kyro-btn-md flex items-center gap-2"
174
122
  >
175
- <svg
176
- width="16"
177
- height="16"
178
- viewBox="0 0 24 24"
179
- fill="none"
180
- stroke="currentColor"
181
- strokeWidth="2.5"
182
- >
183
- <path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z" />
184
- </svg>
123
+ <IconSend className="w-4 h-4" />
185
124
  Publish
186
125
  </button>
187
126
  )}
@@ -189,103 +128,37 @@ export function ActionBar({
189
128
  <button type="button"
190
129
  onClick={onUnpublish}
191
130
  disabled={saveStatus === "saving"}
192
- className="kyro-btn kyro-btn-warning kyro-btn-md flex items-center gap-2"
131
+ className="kyro-btn kyro-btn-secondary kyro-btn-md flex items-center gap-2"
193
132
  >
194
- <svg
195
- width="16"
196
- height="16"
197
- viewBox="0 0 24 24"
198
- fill="none"
199
- stroke="currentColor"
200
- strokeWidth="2.5"
201
- >
202
- <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8M3 3v5h5" />
203
- </svg>
133
+ <IconUndo className="w-4 h-4" />
204
134
  Unpublish
205
135
  </button>
206
136
  )}
207
- <button type="button"
208
- onClick={onSave}
209
- disabled={
210
- saveStatus === "saving" || (!hasChanges && saveStatus !== "error")
211
- }
212
- className={getSaveButtonClass()}
213
- >
214
- {saveStatus === "saving"
215
- ? "Saving..."
216
- : saveStatus === "saved"
217
- ? "Saved"
218
- : "Save"}
219
- </button>
220
137
 
221
- <Dropdown
222
- trigger={
223
- <button type="button" className="kyro-btn kyro-btn-ghost kyro-btn-md p-2">
224
- <svg
225
- width="16"
226
- height="16"
227
- viewBox="0 0 24 24"
228
- fill="none"
229
- stroke="currentColor"
230
- strokeWidth="2"
231
- >
232
- <circle cx="12" cy="12" r="1" />
233
- <circle cx="12" cy="5" r="1" />
234
- <circle cx="12" cy="19" r="1" />
235
- </svg>
236
- </button>
237
- }
138
+ {/* Button Group: Save + Dropdown */}
139
+ <SplitButton
140
+ status={status}
141
+ saveStatus={saveStatus}
142
+ hasChanges={hasChanges}
143
+ onPublish={onSave}
238
144
  >
239
145
  {onDuplicate && (
240
146
  <DropdownItem
241
- onClick={onDuplicate}
242
- icon={
243
- <svg
244
- viewBox="0 0 24 24"
245
- fill="none"
246
- stroke="currentColor"
247
- strokeWidth="2"
248
- >
249
- <rect x="9" y="9" width="13" height="13" rx="2" />
250
- <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
251
- </svg>
252
- }
147
+ icon={<IconCopy className="w-4 h-4" />}
253
148
  >
254
149
  Duplicate
255
150
  </DropdownItem>
256
151
  )}
257
152
  {onViewHistory && (
258
153
  <DropdownItem
259
- onClick={onViewHistory}
260
- icon={
261
- <svg
262
- viewBox="0 0 24 24"
263
- fill="none"
264
- stroke="currentColor"
265
- strokeWidth="2"
266
- >
267
- <circle cx="12" cy="12" r="10" />
268
- <polyline points="12,6 12,12 16,14" />
269
- </svg>
270
- }
154
+ icon={<IconClock className="w-4 h-4" />}
271
155
  >
272
156
  View History
273
157
  </DropdownItem>
274
158
  )}
275
159
  {onPreview && (
276
160
  <DropdownItem
277
- onClick={onPreview}
278
- icon={
279
- <svg
280
- viewBox="0 0 24 24"
281
- fill="none"
282
- stroke="currentColor"
283
- strokeWidth="2"
284
- >
285
- <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
286
- <circle cx="12" cy="12" r="3" />
287
- </svg>
288
- }
161
+ icon={<IconEye className="w-4 h-4" />}
289
162
  >
290
163
  Preview
291
164
  </DropdownItem>
@@ -295,21 +168,12 @@ export function ActionBar({
295
168
  <DropdownItem
296
169
  onClick={onDelete}
297
170
  danger
298
- icon={
299
- <svg
300
- viewBox="0 0 24 24"
301
- fill="none"
302
- stroke="currentColor"
303
- strokeWidth="2"
304
- >
305
- <path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
306
- </svg>
307
- }
171
+ icon={<IconTrash2 className="w-4 h-4" />}
308
172
  >
309
173
  Delete
310
174
  </DropdownItem>
311
175
  )}
312
- </Dropdown>
176
+ </SplitButton>
313
177
  </div>
314
178
  </div>
315
179
  );
@@ -14,7 +14,7 @@ import { WebhookManager } from "./WebhookManager";
14
14
  import { MediaGallery } from "./MediaGallery";
15
15
  import { CommandPalette } from "./ui/CommandPalette";
16
16
  import { GlobalModal } from "./ui/GlobalModal";
17
- import { Toast, ToastProvider } from "./ui/Toast";
17
+ import { Toast } from "./ui/Toast";
18
18
  import { ThemeProvider, type ThemeMode } from "./ThemeProvider";
19
19
  import { toArray, toCollectionMap, toGlobalMap } from "../lib/config";
20
20
  import "../styles/main.css";
@@ -158,7 +158,7 @@ const toasts = useToastStore((state) => state.toasts);
158
158
  collection={collection}
159
159
  documentId={activeDocumentId}
160
160
  onBack={() => setCurrentView("list")}
161
- onSave={() => toast.success("Changes saved")}
161
+ onSave={() => {}}
162
162
  onError={(msg) => toast.error(msg)}
163
163
  />
164
164
  ) : null;
@@ -199,7 +199,6 @@ const toasts = useToastStore((state) => state.toasts);
199
199
 
200
200
  return (
201
201
  <ThemeProvider {...({ mode: theme, onChange: onThemeChange } as any)}>
202
- <ToastProvider>
203
202
  <div className="kyro-admin min-h-screen bg-[var(--kyro-bg)] text-[var(--kyro-text-primary)]">
204
203
  <div className="flex h-screen overflow-hidden">
205
204
  <main className="flex-1 flex flex-col min-w-0 overflow-hidden">
@@ -228,7 +227,6 @@ const toasts = useToastStore((state) => state.toasts);
228
227
  ))}
229
228
  </div>
230
229
  </div>
231
- </ToastProvider>
232
230
  </ThemeProvider>
233
231
  );
234
232
  }
@@ -1,7 +1,7 @@
1
1
  import React, { useState } from "react";
2
2
  import { apiPost } from "../lib/api";
3
3
  import { useResourceManager } from "../lib/useResourceManager";
4
- import { useUIStore } from "../lib/stores";
4
+ import { useUIStore, toast } from "../lib/stores";
5
5
  import {
6
6
  Key, Plus, Trash2, Copy, CheckCircle2, Clock,
7
7
  Shield, Zap, AlertTriangle, Info, Terminal,
@@ -65,7 +65,7 @@ export function ApiKeysManager() {
65
65
  const [copiedId, setCopiedId] = useState<string | null>(null);
66
66
  const [createError, setCreateError] = useState("");
67
67
  const [rotatingId, setRotatingId] = useState<string | null>(null);
68
- const { alert, confirm: kyroConfirm } = useUIStore();
68
+ const { confirm: kyroConfirm } = useUIStore();
69
69
 
70
70
  const handleCreateKey = async () => {
71
71
  if (!newKeyName.trim()) { setCreateError("Name is required"); return; }
@@ -92,7 +92,7 @@ export function ApiKeysManager() {
92
92
  const rotated = await apiPost<ApiKeyItem>(`/api/keys/${key.id}/rotate`);
93
93
  setNewKey(rotated);
94
94
  } catch {
95
- alert({ title: "Error", message: "Failed to rotate key. Please try again." });
95
+ toast.error("Failed to rotate key. Please try again.");
96
96
  } finally {
97
97
  setRotatingId(null);
98
98
  }
@@ -287,7 +287,7 @@ export function ApiKeysManager() {
287
287
  <button
288
288
  type="button"
289
289
  onClick={() => copyToClipboard(newKey.key!, newKey.id)}
290
- className="flex items-center justify-center gap-2 px-8 py-4 bg-[var(--kyro-primary)] text-white rounded-2xl font-bold hover:scale-[1.02] active:scale-[0.98] transition-all shadow-lg shadow-[var(--kyro-primary)]/20"
290
+ className="kyro-btn kyro-btn-primary flex items-center justify-center gap-2 px-8 py-4 rounded-2xl font-bold hover:scale-[1.02] active:scale-[0.98] transition-all shadow-lg shadow-[var(--kyro-primary)]/20"
291
291
  >
292
292
  {copiedId === newKey.id ? <CheckCircle2 className="w-5 h-5" /> : <Copy className="w-5 h-5" />}
293
293
  <span>{copiedId === newKey.id ? "Copied" : "Copy Key"}</span>
@@ -333,7 +333,7 @@ export function ApiKeysManager() {
333
333
  <button
334
334
  type="button"
335
335
  onClick={() => setIsCreateModalOpen(true)}
336
- className="inline-flex items-center gap-3 px-8 py-4 bg-[var(--kyro-primary)] text-white rounded-2xl font-bold hover:scale-[1.05] transition-all shadow-xl shadow-[var(--kyro-primary)]/10"
336
+ className="kyro-btn kyro-btn-primary inline-flex items-center gap-3 px-8 py-4 rounded-2xl font-bold hover:scale-[1.05] transition-all shadow-xl shadow-[var(--kyro-primary)]/10"
337
337
  >
338
338
  <Plus className="w-5 h-5" />
339
339
  Generate API Key
@@ -1,3 +1,4 @@
1
+ import { Search } from "./ui/icons";
1
2
  import React, { useState, useEffect, useCallback } from "react";
2
3
  import { fetchWithAuth } from "../lib/api";
3
4
  import { Modal } from "./ui/Modal";
@@ -230,19 +231,7 @@ export function AuditLogsPage() {
230
231
  {/* Filters */}
231
232
  <div className="surface-tile p-4 flex flex-wrap items-center gap-3">
232
233
  <div className="relative flex-1 min-w-48">
233
- <svg
234
- className="absolute left-3.5 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--kyro-text-muted)]"
235
- fill="none"
236
- stroke="currentColor"
237
- viewBox="0 0 24 24"
238
- >
239
- <path
240
- strokeLinecap="round"
241
- strokeLinejoin="round"
242
- strokeWidth="2"
243
- d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
244
- />
245
- </svg>
234
+ <Search className="w-4 h-4" />
246
235
  <input
247
236
  type="text"
248
237
  placeholder="Search by user email..."