@kyro-cms/admin 0.3.2 → 0.3.5

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 (242) hide show
  1. package/dist/EditorClient-XEUOVAAC.js +466 -0
  2. package/dist/EditorClient-XEUOVAAC.js.map +1 -0
  3. package/dist/EditorClient-YLCGVDXY.cjs +468 -0
  4. package/dist/EditorClient-YLCGVDXY.cjs.map +1 -0
  5. package/dist/chunk-7KPIUCGT.js +384 -0
  6. package/dist/chunk-7KPIUCGT.js.map +1 -0
  7. package/dist/chunk-GOACG6R7.cjs +473 -0
  8. package/dist/chunk-GOACG6R7.cjs.map +1 -0
  9. package/dist/index.cjs +14861 -0
  10. package/dist/index.cjs.map +1 -0
  11. package/dist/index.css +1661 -0
  12. package/dist/index.css.map +1 -0
  13. package/dist/index.d.ts +563 -0
  14. package/dist/index.js +14784 -0
  15. package/dist/index.js.map +1 -0
  16. package/package.json +19 -19
  17. package/src/components/ActionBar.tsx +7 -43
  18. package/src/components/Admin.tsx +138 -277
  19. package/src/components/ApiKeysManager.tsx +428 -419
  20. package/src/components/AuditLogsPage.tsx +35 -39
  21. package/src/components/AuthBridge.tsx +51 -0
  22. package/src/components/AutoForm.tsx +495 -1230
  23. package/src/components/BrandingHub.tsx +18 -19
  24. package/src/components/BulkActionsBar.tsx +1 -1
  25. package/src/components/CreateView.tsx +22 -36
  26. package/src/components/Dashboard.tsx +60 -84
  27. package/src/components/DetailView.tsx +113 -91
  28. package/src/components/DeveloperCenter.tsx +200 -198
  29. package/src/components/FieldRenderer.tsx +206 -0
  30. package/src/components/GraphQLPlayground.tsx +340 -480
  31. package/src/components/ListView.tsx +828 -254
  32. package/src/components/LoginPage.tsx +3 -4
  33. package/src/components/MarketplaceManager.tsx +254 -0
  34. package/src/components/MediaGallery.tsx +856 -1192
  35. package/src/components/PluginsManager.tsx +277 -0
  36. package/src/components/RestPlayground.tsx +398 -560
  37. package/src/components/SessionsManager.tsx +211 -0
  38. package/src/components/Sidebar.astro +179 -151
  39. package/src/components/ThemeProvider.tsx +7 -161
  40. package/src/components/UserManagement.tsx +162 -146
  41. package/src/components/UserMenu.tsx +110 -0
  42. package/src/components/WebhookManager.tsx +305 -367
  43. package/src/components/blocks/AccordionBlock.tsx +4 -4
  44. package/src/components/blocks/ArrayBlock.tsx +3 -3
  45. package/src/components/blocks/BlockEditModal.tsx +8 -8
  46. package/src/components/blocks/BlockWrapper.tsx +61 -0
  47. package/src/components/blocks/ButtonBlock.tsx +4 -4
  48. package/src/components/blocks/ChildBlocksTree.tsx +23 -25
  49. package/src/components/blocks/CodeBlock.tsx +15 -15
  50. package/src/components/blocks/ColumnsBlock.tsx +6 -44
  51. package/src/components/blocks/DividerBlock.tsx +3 -3
  52. package/src/components/blocks/FileBlock.tsx +4 -4
  53. package/src/components/blocks/HeadingBlock.tsx +6 -38
  54. package/src/components/blocks/HeroBlock.tsx +4 -4
  55. package/src/components/blocks/ImageBlock.tsx +4 -4
  56. package/src/components/blocks/LinkBlock.tsx +4 -4
  57. package/src/components/blocks/ListBlock.tsx +3 -3
  58. package/src/components/blocks/ParagraphBlock.tsx +12 -42
  59. package/src/components/blocks/RelationshipBlock.tsx +4 -4
  60. package/src/components/blocks/RichTextBlock.tsx +4 -4
  61. package/src/components/blocks/VStackBlock.tsx +5 -37
  62. package/src/components/blocks/VideoBlock.tsx +4 -4
  63. package/src/components/blocks/types.ts +11 -0
  64. package/src/components/fields/AccordionField.tsx +1 -1
  65. package/src/components/fields/ArrayField.tsx +2 -2
  66. package/src/components/fields/ArrayLayout.tsx +93 -0
  67. package/src/components/fields/BlocksField.tsx +122 -111
  68. package/src/components/fields/ButtonField.tsx +1 -1
  69. package/src/components/fields/CheckboxField.tsx +14 -15
  70. package/src/components/fields/ChildrenField.tsx +2 -2
  71. package/src/components/fields/CodeField.tsx +3 -3
  72. package/src/components/fields/ColumnsField.tsx +2 -2
  73. package/src/components/fields/DateField.tsx +13 -26
  74. package/src/components/fields/EditorClient.tsx +26 -28
  75. package/src/components/fields/FieldLayout.tsx +52 -0
  76. package/src/components/fields/GroupLayout.tsx +35 -0
  77. package/src/components/fields/JSONField.tsx +7 -7
  78. package/src/components/fields/LinkField.tsx +1 -1
  79. package/src/components/fields/MarkdownField.tsx +1 -1
  80. package/src/components/fields/NumberField.tsx +13 -26
  81. package/src/components/fields/PortableTextField.tsx +4 -4
  82. package/src/components/fields/PortableTextRenderer.tsx +1 -1
  83. package/src/components/fields/RelationshipBlockField.tsx +31 -23
  84. package/src/components/fields/RelationshipField.tsx +14 -14
  85. package/src/components/fields/SelectField.tsx +17 -26
  86. package/src/components/fields/TabsLayout.tsx +69 -0
  87. package/src/components/fields/TextField.tsx +85 -38
  88. package/src/components/fields/UploadField.tsx +71 -41
  89. package/src/components/fields/VideoField.tsx +1 -1
  90. package/src/components/fields/extensions/blockComponents.tsx +2 -2
  91. package/src/components/fields/extensions/blocksStore.ts +207 -193
  92. package/src/components/fields/types.ts +22 -0
  93. package/src/components/layout/Layout.tsx +1 -1
  94. package/src/components/ui/ActionMenu.tsx +63 -0
  95. package/src/components/ui/Badge.tsx +59 -5
  96. package/src/components/ui/BlockDrawer.tsx +4 -5
  97. package/src/components/ui/CommandPalette.tsx +58 -36
  98. package/src/components/ui/CommandPaletteWrapper.tsx +18 -17
  99. package/src/components/ui/Dropdown.tsx +18 -16
  100. package/src/components/ui/EmptyState.tsx +25 -0
  101. package/src/components/ui/GlobalModal.tsx +49 -0
  102. package/src/components/ui/IconButton.tsx +44 -0
  103. package/src/components/ui/Modal.tsx +19 -20
  104. package/src/components/ui/PageHeader.tsx +158 -0
  105. package/src/components/ui/Pagination.tsx +61 -0
  106. package/src/components/ui/PromptModal.tsx +1 -1
  107. package/src/components/ui/SearchInput.tsx +57 -0
  108. package/src/components/ui/SeoPreview.tsx +31 -0
  109. package/src/components/ui/SessionModal.tsx +0 -0
  110. package/src/components/ui/SlidePanel.tsx +2 -0
  111. package/src/components/ui/Toast.tsx +65 -122
  112. package/src/components/ui/Toaster.tsx +18 -0
  113. package/src/components/ui/icons.tsx +112 -0
  114. package/src/components/users/UserDetail.tsx +290 -0
  115. package/src/components/users/UserForm.tsx +242 -0
  116. package/src/components/users/UsersList.tsx +338 -0
  117. package/src/env.d.ts +13 -13
  118. package/src/fields/index.ts +2 -1
  119. package/src/global.d.ts +7 -0
  120. package/src/hooks/data.ts +2 -9
  121. package/src/hooks/useAsyncData.ts +36 -0
  122. package/src/hooks/useAutoFormState.ts +527 -0
  123. package/src/hooks/useSelection.ts +49 -0
  124. package/src/hooks/useSession.ts +0 -0
  125. package/src/index.ts +11 -1
  126. package/src/integration.ts +86 -11
  127. package/src/kyro-cms.d.ts +209 -0
  128. package/src/layouts/AdminLayout.astro +128 -11
  129. package/src/layouts/AuthLayout.astro +21 -5
  130. package/src/lib/api.ts +175 -55
  131. package/src/lib/autoform-store.ts +435 -0
  132. package/src/lib/config.ts +82 -34
  133. package/src/lib/createRegistry.ts +29 -0
  134. package/src/lib/default-kyro-config.ts +4 -0
  135. package/src/lib/globals.ts +50 -0
  136. package/src/lib/media-utils.ts +18 -0
  137. package/src/lib/object-utils.ts +77 -0
  138. package/src/lib/paths.ts +61 -0
  139. package/src/lib/stores/index.ts +370 -0
  140. package/src/lib/types.ts +43 -0
  141. package/src/lib/useResourceManager.ts +105 -0
  142. package/src/pages/403.astro +67 -0
  143. package/src/pages/[collection]/[id].astro +14 -180
  144. package/src/pages/[collection]/index.astro +11 -6
  145. package/src/pages/api-explorer.astro +173 -0
  146. package/src/pages/audit/index.astro +2 -0
  147. package/src/pages/auth/login.astro +122 -0
  148. package/src/pages/auth/register.astro +167 -0
  149. package/src/pages/graphql-explorer.astro +59 -0
  150. package/src/pages/{admin/graphql.astro → graphql.astro} +51 -17
  151. package/src/pages/index.astro +577 -0
  152. package/src/pages/index_ALT.astro +3 -0
  153. package/src/pages/keys.astro +11 -0
  154. package/src/pages/marketplace.astro +11 -0
  155. package/src/pages/media.astro +3 -0
  156. package/src/pages/plugins.astro +8 -0
  157. package/src/pages/preview/[collection]/[id].astro +188 -123
  158. package/src/pages/rest-playground.astro +62 -0
  159. package/src/pages/roles/index.astro +183 -76
  160. package/src/pages/sessions.astro +8 -0
  161. package/src/pages/settings/[slug].astro +92 -114
  162. package/src/pages/settings/index.astro +5 -3
  163. package/src/pages/users/[id].astro +25 -154
  164. package/src/pages/users/index.astro +19 -130
  165. package/src/pages/users/new.astro +9 -86
  166. package/src/pages/webhooks.astro +11 -0
  167. package/src/routes.ts +80 -0
  168. package/src/styles/main.css +119 -79
  169. package/src/theme/tokens.ts +1 -0
  170. package/src/vite-env.d.ts +14 -0
  171. package/src/collections/auth/index.ts +0 -155
  172. package/src/collections/portfolio/index.ts +0 -343
  173. package/src/components/ApiExplorer.tsx +0 -325
  174. package/src/components/EnhancedListView.tsx +0 -889
  175. package/src/components/GraphQLExplorer.tsx +0 -675
  176. package/src/components/Icons.tsx +0 -23
  177. package/src/components/StatusBadge.tsx +0 -76
  178. package/src/lib/MediaService.ts +0 -541
  179. package/src/lib/auth/sqlite-adapter.ts +0 -319
  180. package/src/lib/dataStore.ts +0 -226
  181. package/src/lib/db/adapter.ts +0 -54
  182. package/src/lib/db/drizzle-mysql-adapter.ts +0 -194
  183. package/src/lib/db/drizzle-mysql-auth-adapter.ts +0 -327
  184. package/src/lib/db/drizzle-postgres-adapter.ts +0 -202
  185. package/src/lib/db/drizzle-postgres-auth-adapter.ts +0 -304
  186. package/src/lib/db/drizzle-sqlite-adapter.ts +0 -227
  187. package/src/lib/db/drizzle-sqlite-auth-adapter.ts +0 -548
  188. package/src/lib/db/index.ts +0 -449
  189. package/src/lib/db/mongodb-adapter.ts +0 -207
  190. package/src/lib/db/mongodb-auth-adapter.ts +0 -305
  191. package/src/lib/db/schema/mysql-auth.ts +0 -113
  192. package/src/lib/db/schema/mysql-content.ts +0 -20
  193. package/src/lib/db/schema/postgres-auth.ts +0 -116
  194. package/src/lib/db/schema/postgres-content.ts +0 -35
  195. package/src/lib/db/schema/postgres-media.ts +0 -52
  196. package/src/lib/db/schema/postgres-settings.ts +0 -11
  197. package/src/lib/db/schema/sqlite-auth.ts +0 -112
  198. package/src/lib/db/schema/sqlite-content.ts +0 -20
  199. package/src/lib/db/version-adapter.ts +0 -248
  200. package/src/lib/graphql/index.ts +0 -1
  201. package/src/lib/graphql/schema.ts +0 -443
  202. package/src/lib/rate-limit.ts +0 -267
  203. package/src/lib/storage.ts +0 -374
  204. package/src/lib/store.ts +0 -85
  205. package/src/middleware.ts +0 -177
  206. package/src/pages/admin/api-explorer.astro +0 -98
  207. package/src/pages/admin/graphql-explorer.astro +0 -40
  208. package/src/pages/admin/index.astro +0 -286
  209. package/src/pages/admin/keys.astro +0 -8
  210. package/src/pages/admin/rest-playground.astro +0 -44
  211. package/src/pages/admin/webhooks.astro +0 -8
  212. package/src/pages/api/[collection]/[id]/publish.ts +0 -52
  213. package/src/pages/api/[collection]/[id]/unpublish.ts +0 -42
  214. package/src/pages/api/[collection]/[id]/versions.ts +0 -66
  215. package/src/pages/api/[collection]/[id].ts +0 -213
  216. package/src/pages/api/[collection]/index.ts +0 -209
  217. package/src/pages/api/auth/[id].ts +0 -121
  218. package/src/pages/api/auth/audit-logs.ts +0 -57
  219. package/src/pages/api/auth/login.ts +0 -211
  220. package/src/pages/api/auth/logout.ts +0 -66
  221. package/src/pages/api/auth/me.ts +0 -36
  222. package/src/pages/api/auth/refresh.ts +0 -119
  223. package/src/pages/api/auth/register.ts +0 -188
  224. package/src/pages/api/auth/users.ts +0 -97
  225. package/src/pages/api/collections.ts +0 -59
  226. package/src/pages/api/globals/[slug].ts +0 -42
  227. package/src/pages/api/graphql.ts +0 -90
  228. package/src/pages/api/health.ts +0 -426
  229. package/src/pages/api/keys/[id].ts +0 -26
  230. package/src/pages/api/keys/index.ts +0 -75
  231. package/src/pages/api/media/[id].ts +0 -309
  232. package/src/pages/api/media/folders.ts +0 -609
  233. package/src/pages/api/media/index.ts +0 -146
  234. package/src/pages/api/media/resize.ts +0 -267
  235. package/src/pages/api/search.ts +0 -82
  236. package/src/pages/api/slug-availability.ts +0 -70
  237. package/src/pages/api/storage-config.ts +0 -20
  238. package/src/pages/api/storage-status.ts +0 -206
  239. package/src/pages/api/upload.ts +0 -334
  240. package/src/pages/api/webhooks/index.ts +0 -71
  241. package/src/pages/login.astro +0 -82
  242. package/src/pages/register.astro +0 -102
@@ -1,675 +0,0 @@
1
- import React, { useState, useEffect, useCallback } from "react";
2
-
3
- interface TypeInfo {
4
- name: string;
5
- kind: string;
6
- description?: string;
7
- fields?: FieldInfo[];
8
- inputFields?: FieldInfo[];
9
- enumValues?: { name: string; description?: string; isDeprecated: boolean }[];
10
- isDeprecated?: boolean;
11
- }
12
-
13
- interface FieldInfo {
14
- name: string;
15
- description?: string;
16
- type: string;
17
- args: ArgInfo[];
18
- isDeprecated?: boolean;
19
- deprecationReason?: string;
20
- }
21
-
22
- interface ArgInfo {
23
- name: string;
24
- description?: string;
25
- type: { name?: string; kind?: string } | string;
26
- defaultValue?: string;
27
- }
28
-
29
- interface SchemaInfo {
30
- queryType: { name: string };
31
- mutationType?: { name: string };
32
- subscriptionType?: { name: string };
33
- types: TypeInfo[];
34
- }
35
-
36
- export function GraphQLExplorer({
37
- endpoint = "/api/graphql",
38
- }: {
39
- endpoint?: string;
40
- }) {
41
- const [schema, setSchema] = useState<SchemaInfo | null>(null);
42
- const [loading, setLoading] = useState(true);
43
- const [error, setError] = useState<string | null>(null);
44
- const [searchQuery, setSearchQuery] = useState("");
45
- const [selectedType, setSelectedType] = useState<TypeInfo | null>(null);
46
- const [activeSection, setActiveSection] = useState<
47
- "types" | "queries" | "mutations"
48
- >("types");
49
- const [expandedTypes, setExpandedTypes] = useState<Set<string>>(new Set());
50
-
51
- const fetchSchema = useCallback(async () => {
52
- setLoading(true);
53
- setError(null);
54
- try {
55
- const response = await fetch(endpoint, {
56
- method: "POST",
57
- headers: { "Content-Type": "application/json" },
58
- body: JSON.stringify({
59
- query: `
60
- {
61
- __schema {
62
- queryType { name }
63
- mutationType { name }
64
- subscriptionType { name }
65
- types {
66
- name
67
- kind
68
- description
69
- fields {
70
- name
71
- description
72
- type { name kind }
73
- args {
74
- name
75
- description
76
- type { name kind }
77
- defaultValue
78
- }
79
- isDeprecated
80
- deprecationReason
81
- }
82
- inputFields {
83
- name
84
- description
85
- type { name kind }
86
- defaultValue
87
- }
88
- enumValues {
89
- name
90
- description
91
- isDeprecated
92
- }
93
- }
94
- }
95
- }
96
- `,
97
- }),
98
- });
99
-
100
- const data = await response.json();
101
- if (data.errors) {
102
- setError(data.errors[0]?.message || "Failed to fetch schema");
103
- return;
104
- }
105
- setSchema(data.data.__schema);
106
- } catch (err) {
107
- setError(err instanceof Error ? err.message : "Failed to connect");
108
- } finally {
109
- setLoading(false);
110
- }
111
- }, [endpoint]);
112
-
113
- useEffect(() => {
114
- fetchSchema();
115
- }, [fetchSchema]);
116
-
117
- const scalarTypes = [
118
- "String",
119
- "Int",
120
- "Float",
121
- "Boolean",
122
- "ID",
123
- "JSON",
124
- "DateTime",
125
- ];
126
- const builtInTypes = [
127
- "Query",
128
- "Mutation",
129
- "Subscription",
130
- "__Schema",
131
- "__Type",
132
- "__Field",
133
- "__InputValue",
134
- "__EnumValue",
135
- "__Directive",
136
- ];
137
-
138
- const filteredTypes =
139
- schema?.types.filter((type) => {
140
- if (
141
- !type.name ||
142
- builtInTypes.includes(type.name) ||
143
- type.name.startsWith("__")
144
- )
145
- return false;
146
- if (!searchQuery) return true;
147
- const query = searchQuery.toLowerCase();
148
- if (type.name.toLowerCase().includes(query)) return true;
149
- if (type.description?.toLowerCase().includes(query)) return true;
150
- return false;
151
- }) || [];
152
-
153
- const queryTypes =
154
- schema?.types.filter((t) => t.name === schema.queryType?.name) || [];
155
- const mutationTypes =
156
- schema?.types.filter((t) => t.name === schema.mutationType?.name) || [];
157
-
158
- const toggleType = (name: string) => {
159
- setExpandedTypes((prev) => {
160
- const next = new Set(prev);
161
- if (next.has(name)) next.delete(name);
162
- else next.add(name);
163
- return next;
164
- });
165
- };
166
-
167
- const getTypeColor = (kind: string) => {
168
- switch (kind) {
169
- case "OBJECT":
170
- return "text-blue-400";
171
- case "INPUT_OBJECT":
172
- return "text-orange-400";
173
- case "ENUM":
174
- return "text-purple-400";
175
- case "INTERFACE":
176
- return "text-green-400";
177
- case "SCALAR":
178
- return "text-yellow-400";
179
- case "UNION":
180
- return "text-pink-400";
181
- default:
182
- return "text-gray-400";
183
- }
184
- };
185
-
186
- const formatType = (type: any): string => {
187
- if (!type) return "Unknown";
188
- if (type.name) return type.name;
189
- if (type.kind === "NON_NULL") return `${formatType(type.ofType)}!`;
190
- if (type.kind === "LIST") return `[${formatType(type.ofType)}]`;
191
- return type.kind || "Unknown";
192
- };
193
-
194
- const generateExample = (
195
- type: TypeInfo,
196
- operation: "query" | "mutation" = "query",
197
- ): string => {
198
- const fields =
199
- type.fields?.filter((f) => !f.isDeprecated).slice(0, 5) || [];
200
- const fieldList = fields.map((f) => ` ${f.name}`).join("\n");
201
-
202
- if (operation === "query") {
203
- return `query Get${type.name} {
204
- ${type.name.toLowerCase().replace(/_type$/, "")} {
205
- ${fieldList}
206
- }
207
- }`;
208
- } else {
209
- return `mutation Create${type.name} {
210
- create${type.name}(input: {}) {
211
- ${fieldList}
212
- }
213
- }`;
214
- }
215
- };
216
-
217
- const copyToClipboard = (text: string) => {
218
- navigator.clipboard.writeText(text);
219
- };
220
-
221
- if (loading) {
222
- return (
223
- <div className="flex items-center justify-center h-full">
224
- <div className="text-center">
225
- <div className="animate-spin w-12 h-12 border-2 border-pink-500 border-t-transparent rounded-full mx-auto mb-4" />
226
- <p className="text-[var(--kyro-text-secondary)]">
227
- Fetching schema...
228
- </p>
229
- </div>
230
- </div>
231
- );
232
- }
233
-
234
- if (error) {
235
- return (
236
- <div className="flex items-center justify-center h-full">
237
- <div className="text-center max-w-md">
238
- <div className="w-16 h-16 mx-auto mb-4 rounded-full bg-red-500/10 flex items-center justify-center">
239
- <svg
240
- className="w-8 h-8 text-red-500"
241
- fill="none"
242
- stroke="currentColor"
243
- viewBox="0 0 24 24"
244
- >
245
- <path
246
- strokeLinecap="round"
247
- strokeLinejoin="round"
248
- strokeWidth="2"
249
- d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
250
- />
251
- </svg>
252
- </div>
253
- <h3 className="text-lg font-bold text-[var(--kyro-text-primary)] mb-2">
254
- Connection Error
255
- </h3>
256
- <p className="text-sm text-[var(--kyro-text-secondary)] mb-4">
257
- {error}
258
- </p>
259
- <button type="button"
260
- onClick={fetchSchema}
261
- className="px-4 py-2 bg-pink-500 text-white rounded-lg font-bold text-sm hover:bg-pink-600"
262
- >
263
- Retry
264
- </button>
265
- </div>
266
- </div>
267
- );
268
- }
269
-
270
- return (
271
- <div className="h-full flex gap-6">
272
- {/* Left Panel - Type List */}
273
- <div className="w-80 flex-shrink-0 flex flex-col">
274
- {/* Search */}
275
- <div className="mb-4">
276
- <div className="relative">
277
- <svg
278
- className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--kyro-text-muted)]"
279
- fill="none"
280
- stroke="currentColor"
281
- viewBox="0 0 24 24"
282
- >
283
- <path
284
- strokeLinecap="round"
285
- strokeLinejoin="round"
286
- strokeWidth="2"
287
- d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
288
- />
289
- </svg>
290
- <input
291
- type="text"
292
- value={searchQuery}
293
- onChange={(e) => setSearchQuery(e.target.value)}
294
- placeholder="Search types..."
295
- className="w-full pl-10 pr-4 py-2 bg-[var(--kyro-surface-accent)] border border-[var(--kyro-border)] rounded-lg text-sm focus:outline-none focus:border-pink-500"
296
- />
297
- </div>
298
- </div>
299
-
300
- {/* Section Tabs */}
301
- <div className="flex gap-1 mb-4">
302
- {(["types", "queries", "mutations"] as const).map((section) => (
303
- <button type="button"
304
- key={section}
305
- onClick={() => setActiveSection(section)}
306
- className={`flex-1 px-3 py-1.5 text-xs font-bold rounded transition-colors ${
307
- activeSection === section
308
- ? "bg-pink-500 text-white"
309
- : "text-[var(--kyro-text-secondary)] hover:bg-[var(--kyro-surface-accent)]"
310
- }`}
311
- >
312
- {section.charAt(0).toUpperCase() + section.slice(1)}
313
- </button>
314
- ))}
315
- </div>
316
-
317
- {/* Type List */}
318
- <div className="flex-1 overflow-y-auto space-y-1">
319
- {activeSection === "types" &&
320
- filteredTypes.map((type) => (
321
- <button type="button"
322
- key={type.name}
323
- onClick={() => {
324
- setSelectedType(type);
325
- toggleType(type.name);
326
- }}
327
- className={`w-full text-left px-3 py-2 rounded-lg text-sm transition-colors ${
328
- selectedType?.name === type.name
329
- ? "bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)]"
330
- : "hover:bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)]"
331
- }`}
332
- >
333
- <div className="flex items-center gap-2">
334
- <span
335
- className={`text-xs font-mono ${getTypeColor(type.kind)}`}
336
- >
337
- {type.kind === "OBJECT"
338
- ? "{ }"
339
- : type.kind === "ENUM"
340
- ? "[ ]"
341
- : type.kind === "INPUT_OBJECT"
342
- ? "( )"
343
- : "~"}
344
- </span>
345
- <span className="font-medium">{type.name}</span>
346
- </div>
347
- {type.description && (
348
- <p className="text-xs text-[var(--kyro-text-muted)] mt-1 line-clamp-2">
349
- {type.description}
350
- </p>
351
- )}
352
- </button>
353
- ))}
354
-
355
- {activeSection === "queries" &&
356
- queryTypes.map((type) => (
357
- <div key={type.name}>
358
- <div className="px-3 py-2 text-xs font-bold text-[var(--kyro-text-muted)] uppercase">
359
- {type.name} Root
360
- </div>
361
- {type.fields?.map((field) => (
362
- <button type="button"
363
- key={field.name}
364
- onClick={() => {
365
- const queryType = schema?.types.find((t) => {
366
- const fieldType = field.type as any;
367
- return t.name === (fieldType?.name || fieldType);
368
- });
369
- if (queryType) setSelectedType(queryType);
370
- }}
371
- className="w-full text-left px-3 py-2 rounded-lg text-sm hover:bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)]"
372
- >
373
- <span className="text-green-400 font-mono">
374
- {field.name}
375
- </span>
376
- {field.args.length > 0 && (
377
- <span className="text-[var(--kyro-text-muted)]">
378
- ({field.args.length} args)
379
- </span>
380
- )}
381
- </button>
382
- ))}
383
- </div>
384
- ))}
385
-
386
- {activeSection === "mutations" && (
387
- <>
388
- {mutationTypes.length === 0 && (
389
- <p className="text-sm text-[var(--kyro-text-muted)] px-3 py-4 text-center">
390
- No mutations available
391
- </p>
392
- )}
393
- {mutationTypes.map((type) => (
394
- <div key={type.name}>
395
- <div className="px-3 py-2 text-xs font-bold text-[var(--kyro-text-muted)] uppercase">
396
- {type.name} Root
397
- </div>
398
- {type.fields?.map((field) => (
399
- <button type="button"
400
- key={field.name}
401
- onClick={() => {
402
- const mutationType = schema?.types.find((t) => {
403
- const fieldType = field.type as any;
404
- return t.name === (fieldType?.name || fieldType);
405
- });
406
- if (mutationType) setSelectedType(mutationType);
407
- }}
408
- className="w-full text-left px-3 py-2 rounded-lg text-sm hover:bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)]"
409
- >
410
- <span className="text-red-400 font-mono">
411
- {field.name}
412
- </span>
413
- {field.args.length > 0 && (
414
- <span className="text-[var(--kyro-text-muted)]">
415
- ({field.args.length} args)
416
- </span>
417
- )}
418
- </button>
419
- ))}
420
- </div>
421
- ))}
422
- </>
423
- )}
424
- </div>
425
- </div>
426
-
427
- {/* Right Panel - Type Details */}
428
- <div className="flex-1 flex flex-col min-w-0">
429
- {selectedType ? (
430
- <>
431
- {/* Type Header */}
432
- <div className="mb-6">
433
- <div className="flex items-center gap-3 mb-2">
434
- <span
435
- className={`text-xs font-mono px-2 py-1 rounded bg-[var(--kyro-surface-accent)] ${getTypeColor(selectedType.kind)}`}
436
- >
437
- {selectedType.kind}
438
- </span>
439
- <h2 className="text-2xl font-black text-[var(--kyro-text-primary)]">
440
- {selectedType.name}
441
- </h2>
442
- </div>
443
- {selectedType.description && (
444
- <p className="text-sm text-[var(--kyro-text-secondary)]">
445
- {selectedType.description}
446
- </p>
447
- )}
448
- </div>
449
-
450
- {/* Quick Actions */}
451
- <div className="flex gap-2 mb-6">
452
- <button type="button"
453
- onClick={() =>
454
- copyToClipboard(generateExample(selectedType, "query"))
455
- }
456
- className="flex items-center gap-2 px-4 py-2 bg-[var(--kyro-surface-accent)] border border-[var(--kyro-border)] rounded-lg text-sm hover:bg-[var(--kyro-surface)] transition-colors"
457
- >
458
- <svg
459
- className="w-4 h-4"
460
- fill="none"
461
- stroke="currentColor"
462
- viewBox="0 0 24 24"
463
- >
464
- <path
465
- strokeLinecap="round"
466
- strokeLinejoin="round"
467
- strokeWidth="2"
468
- d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"
469
- />
470
- </svg>
471
- Copy Query
472
- </button>
473
- <button type="button"
474
- onClick={() =>
475
- copyToClipboard(generateExample(selectedType, "mutation"))
476
- }
477
- className="flex items-center gap-2 px-4 py-2 bg-[var(--kyro-surface-accent)] border border-[var(--kyro-border)] rounded-lg text-sm hover:bg-[var(--kyro-surface)] transition-colors"
478
- >
479
- <svg
480
- className="w-4 h-4"
481
- fill="none"
482
- stroke="currentColor"
483
- viewBox="0 0 24 24"
484
- >
485
- <path
486
- strokeLinecap="round"
487
- strokeLinejoin="round"
488
- strokeWidth="2"
489
- d="M12 4v16m8-8H4"
490
- />
491
- </svg>
492
- Copy Mutation
493
- </button>
494
- <a
495
- href={`/admin/graphql?query=${encodeURIComponent(generateExample(selectedType, "query"))}`}
496
- className="flex items-center gap-2 px-4 py-2 bg-pink-500 text-white rounded-lg text-sm hover:bg-pink-600 transition-colors"
497
- >
498
- <svg
499
- className="w-4 h-4"
500
- fill="none"
501
- stroke="currentColor"
502
- viewBox="0 0 24 24"
503
- >
504
- <path
505
- strokeLinecap="round"
506
- strokeLinejoin="round"
507
- strokeWidth="2"
508
- d="M13 10V3L4 14h7v7l9-11h-7z"
509
- />
510
- </svg>
511
- Open in Playground
512
- </a>
513
- </div>
514
-
515
- {/* Fields */}
516
- {selectedType.fields && selectedType.fields.length > 0 && (
517
- <div className="mb-6">
518
- <h3 className="text-sm font-bold text-[var(--kyro-text-primary)] mb-3">
519
- Fields
520
- </h3>
521
- <div className="space-y-3">
522
- {selectedType.fields.map((field) => (
523
- <div
524
- key={field.name}
525
- className="p-4 bg-[var(--kyro-surface-accent)] rounded-lg border border-[var(--kyro-border)]"
526
- >
527
- <div className="flex items-start justify-between mb-2">
528
- <div className="flex items-center gap-2">
529
- <code className="text-sm font-mono text-pink-400">
530
- {field.name}
531
- </code>
532
- {field.args.length > 0 && (
533
- <span className="text-xs text-[var(--kyro-text-muted)]">
534
- ({field.args.map((a) => a.name).join(", ")})
535
- </span>
536
- )}
537
- <span className="text-xs text-[var(--kyro-text-muted)]">
538
- :
539
- </span>
540
- <code className="text-sm font-mono text-blue-400">
541
- {formatType(field.type as any)}
542
- </code>
543
- </div>
544
- {field.isDeprecated && (
545
- <span className="px-2 py-0.5 bg-yellow-500/10 text-yellow-500 text-xs rounded">
546
- Deprecated
547
- </span>
548
- )}
549
- </div>
550
- {field.description && (
551
- <p className="text-xs text-[var(--kyro-text-secondary)] mb-2">
552
- {field.description}
553
- </p>
554
- )}
555
- {field.deprecationReason && (
556
- <p className="text-xs text-yellow-500 italic">
557
- {field.deprecationReason}
558
- </p>
559
- )}
560
- {field.args.length > 0 && (
561
- <div className="mt-2 pl-4 border-l-2 border-[var(--kyro-border)]">
562
- <p className="text-xs font-bold text-[var(--kyro-text-muted)] mb-1">
563
- Arguments:
564
- </p>
565
- {field.args.map((arg) => (
566
- <div
567
- key={arg.name}
568
- className="flex items-center gap-2 text-xs"
569
- >
570
- <code className="text-[var(--kyro-text-secondary)]">
571
- {arg.name}
572
- </code>
573
- <span className="text-[var(--kyro-text-muted)]">
574
- :
575
- </span>
576
- <code className="text-blue-400">
577
- {formatType(arg.type as any)}
578
- </code>
579
- {arg.defaultValue && (
580
- <span className="text-[var(--kyro-text-muted)]">
581
- = {arg.defaultValue}
582
- </span>
583
- )}
584
- </div>
585
- ))}
586
- </div>
587
- )}
588
- </div>
589
- ))}
590
- </div>
591
- </div>
592
- )}
593
-
594
- {/* Input Fields */}
595
- {selectedType.inputFields &&
596
- selectedType.inputFields.length > 0 && (
597
- <div className="mb-6">
598
- <h3 className="text-sm font-bold text-[var(--kyro-text-primary)] mb-3">
599
- Input Fields
600
- </h3>
601
- <div className="space-y-2">
602
- {selectedType.inputFields.map((field) => (
603
- <div
604
- key={field.name}
605
- className="flex items-center gap-3 p-3 bg-[var(--kyro-surface-accent)] rounded-lg"
606
- >
607
- <code className="text-sm font-mono text-orange-400">
608
- {field.name}
609
- </code>
610
- <span className="text-[var(--kyro-text-muted)]">:</span>
611
- <code className="text-sm font-mono text-blue-400">
612
- {formatType(field.type as any)}
613
- </code>
614
- </div>
615
- ))}
616
- </div>
617
- </div>
618
- )}
619
-
620
- {/* Enum Values */}
621
- {selectedType.enumValues && selectedType.enumValues.length > 0 && (
622
- <div className="mb-6">
623
- <h3 className="text-sm font-bold text-[var(--kyro-text-primary)] mb-3">
624
- Enum Values
625
- </h3>
626
- <div className="grid grid-cols-2 gap-2">
627
- {selectedType.enumValues.map((value) => (
628
- <div
629
- key={value.name}
630
- className={`p-3 rounded-lg border ${
631
- value.isDeprecated
632
- ? "bg-yellow-500/5 border-yellow-500/20"
633
- : "bg-[var(--kyro-surface-accent)] border-[var(--kyro-border)]"
634
- }`}
635
- >
636
- <code className="text-sm font-mono text-purple-400">
637
- {value.name}
638
- </code>
639
- {value.isDeprecated && (
640
- <span className="ml-2 text-xs text-yellow-500">
641
- Deprecated
642
- </span>
643
- )}
644
- </div>
645
- ))}
646
- </div>
647
- </div>
648
- )}
649
- </>
650
- ) : (
651
- <div className="flex-1 flex items-center justify-center">
652
- <div className="text-center">
653
- <svg
654
- className="w-16 h-16 mx-auto mb-4 text-[var(--kyro-text-muted)] opacity-50"
655
- fill="none"
656
- stroke="currentColor"
657
- viewBox="0 0 24 24"
658
- >
659
- <path
660
- strokeLinecap="round"
661
- strokeLinejoin="round"
662
- strokeWidth="1.5"
663
- d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
664
- />
665
- </svg>
666
- <p className="text-[var(--kyro-text-secondary)]">
667
- Select a type to view its details
668
- </p>
669
- </div>
670
- </div>
671
- )}
672
- </div>
673
- </div>
674
- );
675
- }
@@ -1,23 +0,0 @@
1
- import React from 'react';
2
- import { Menu, Home, Database, User } from 'lucide-react';
3
-
4
- interface IconProps {
5
- size?: number;
6
- className?: string;
7
- }
8
-
9
- export const MenuIcon: React.FC<IconProps> = ({ size = 24, className = '' }) => (
10
- <Menu size={size} className={className} />
11
- );
12
-
13
- export const HomeIcon: React.FC<IconProps> = ({ size = 18, className = '' }) => (
14
- <Home size={size} className={className} />
15
- );
16
-
17
- export const DatabaseIcon: React.FC<IconProps> = ({ size = 18, className = '' }) => (
18
- <Database size={size} className={className} />
19
- );
20
-
21
- export const UserIcon: React.FC<IconProps> = ({ size = 20, className = '' }) => (
22
- <User size={size} className={className} />
23
- );