@kyro-cms/admin 0.1.6 → 0.1.7

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 (163) hide show
  1. package/README.md +149 -51
  2. package/package.json +53 -6
  3. package/src/collections/auth/index.ts +2 -2
  4. package/src/collections/portfolio/index.ts +343 -0
  5. package/src/components/ActionBar.tsx +153 -16
  6. package/src/components/Admin.tsx +136 -27
  7. package/src/components/ApiExplorer.tsx +325 -0
  8. package/src/components/ApiKeysManager.tsx +563 -0
  9. package/src/components/AuditLogsPage.tsx +664 -0
  10. package/src/components/AutoForm.tsx +1417 -661
  11. package/src/components/BrandingHub.tsx +267 -0
  12. package/src/components/BulkActionsBar.tsx +3 -3
  13. package/src/components/CreateView.tsx +3 -3
  14. package/src/components/Dashboard.tsx +393 -0
  15. package/src/components/DetailView.tsx +199 -57
  16. package/src/components/DeveloperCenter.tsx +403 -0
  17. package/src/components/EnhancedListView.tsx +786 -0
  18. package/src/components/GraphQLExplorer.tsx +675 -0
  19. package/src/components/GraphQLPlayground.tsx +627 -0
  20. package/src/components/ListView.tsx +191 -53
  21. package/src/components/MediaGallery.tsx +1569 -0
  22. package/src/components/Modal.tsx +149 -0
  23. package/src/components/RestPlayground.tsx +951 -0
  24. package/src/components/Sidebar.astro +237 -0
  25. package/src/components/UserManagement.tsx +204 -0
  26. package/src/components/VersionHistoryPanel.tsx +3 -3
  27. package/src/components/WebhookManager.tsx +608 -0
  28. package/src/components/blocks/AccordionBlock.tsx +97 -0
  29. package/src/components/blocks/ArrayBlock.tsx +75 -0
  30. package/src/components/blocks/BlockEditModal.MARKER +12 -0
  31. package/src/components/blocks/BlockEditModal.tsx +774 -0
  32. package/src/components/blocks/ButtonBlock.tsx +165 -0
  33. package/src/components/blocks/ChildBlocksTree.tsx +551 -0
  34. package/src/components/blocks/CodeBlock.tsx +66 -0
  35. package/src/components/blocks/ColumnsBlock.tsx +151 -0
  36. package/src/components/blocks/DividerBlock.tsx +43 -0
  37. package/src/components/blocks/FileBlock.tsx +64 -0
  38. package/src/components/blocks/HeadingBlock.tsx +81 -0
  39. package/src/components/blocks/HeroBlock.tsx +157 -0
  40. package/src/components/blocks/ImageBlock.tsx +83 -0
  41. package/src/components/blocks/LinkBlock.tsx +71 -0
  42. package/src/components/blocks/ListBlock.tsx +39 -0
  43. package/src/components/blocks/ParagraphBlock.tsx +61 -0
  44. package/src/components/blocks/RelationshipBlock.tsx +279 -0
  45. package/src/components/blocks/VStackBlock.tsx +75 -0
  46. package/src/components/blocks/VideoBlock.tsx +45 -0
  47. package/src/components/blocks/index.ts +10 -0
  48. package/src/components/fields/BlocksField.tsx +323 -0
  49. package/src/components/fields/CheckboxField.tsx +15 -9
  50. package/src/components/fields/CodeField.tsx +234 -0
  51. package/src/components/fields/DateField.tsx +38 -11
  52. package/src/components/fields/EditorClient.tsx +271 -0
  53. package/src/components/fields/FileField.tsx +390 -0
  54. package/src/components/fields/HybridContentField.tsx +109 -0
  55. package/src/components/fields/ImageField.tsx +429 -0
  56. package/src/components/fields/JSONField.tsx +361 -0
  57. package/src/components/fields/MarkdownField.tsx +282 -0
  58. package/src/components/fields/NumberField.tsx +42 -12
  59. package/src/components/fields/PortableTextField.tsx +143 -0
  60. package/src/components/fields/PortableTextRenderer.tsx +68 -0
  61. package/src/components/fields/RelationshipField.tsx +231 -59
  62. package/src/components/fields/SelectField.tsx +25 -15
  63. package/src/components/fields/TextField.tsx +45 -14
  64. package/src/components/fields/extensions/blockComponents.tsx +237 -0
  65. package/src/components/fields/extensions/blocksStore.ts +273 -0
  66. package/src/components/fields/index.ts +13 -0
  67. package/src/components/index.ts +1 -2
  68. package/src/components/layout/Header.tsx +2 -2
  69. package/src/components/layout/Layout.tsx +2 -2
  70. package/src/components/ui/Badge.tsx +9 -4
  71. package/src/components/ui/BlockDrawer.tsx +79 -0
  72. package/src/components/ui/Button.tsx +1 -1
  73. package/src/components/ui/CommandPalette.tsx +362 -0
  74. package/src/components/ui/CommandPaletteWrapper.tsx +97 -0
  75. package/src/components/ui/Dropdown.tsx +1 -1
  76. package/src/components/ui/Modal.tsx +37 -12
  77. package/src/components/ui/PromptModal.tsx +94 -0
  78. package/src/components/ui/SlidePanel.tsx +43 -16
  79. package/src/components/ui/Toast.tsx +80 -14
  80. package/src/env.d.ts +16 -0
  81. package/src/env.ts +20 -0
  82. package/src/index.ts +0 -1
  83. package/src/layouts/AdminLayout.astro +164 -170
  84. package/src/layouts/AuthLayout.astro +23 -6
  85. package/src/lib/MediaService.ts +541 -0
  86. package/src/lib/auth/sqlite-adapter.ts +319 -0
  87. package/src/lib/config.ts +22 -6
  88. package/src/lib/dataStore.ts +132 -74
  89. package/src/lib/db/adapter.ts +54 -0
  90. package/src/lib/db/drizzle-mysql-adapter.ts +194 -0
  91. package/src/lib/db/drizzle-mysql-auth-adapter.ts +327 -0
  92. package/src/lib/db/drizzle-postgres-adapter.ts +202 -0
  93. package/src/lib/db/drizzle-postgres-auth-adapter.ts +304 -0
  94. package/src/lib/db/drizzle-sqlite-adapter.ts +227 -0
  95. package/src/lib/db/drizzle-sqlite-auth-adapter.ts +548 -0
  96. package/src/lib/db/index.ts +449 -0
  97. package/src/lib/db/mongodb-adapter.ts +207 -0
  98. package/src/lib/db/mongodb-auth-adapter.ts +305 -0
  99. package/src/lib/db/schema/mysql-auth.ts +113 -0
  100. package/src/lib/db/schema/mysql-content.ts +20 -0
  101. package/src/lib/db/schema/postgres-auth.ts +116 -0
  102. package/src/lib/db/schema/postgres-content.ts +35 -0
  103. package/src/lib/db/schema/postgres-media.ts +52 -0
  104. package/src/lib/db/schema/postgres-settings.ts +11 -0
  105. package/src/lib/db/schema/sqlite-auth.ts +112 -0
  106. package/src/lib/db/schema/sqlite-content.ts +20 -0
  107. package/src/lib/graphql/index.ts +1 -0
  108. package/src/lib/graphql/schema.ts +443 -0
  109. package/src/lib/rate-limit.ts +267 -0
  110. package/src/lib/storage.ts +374 -0
  111. package/src/lib/store.ts +85 -0
  112. package/src/middleware.ts +70 -11
  113. package/src/pages/[collection]/[id].astro +178 -122
  114. package/src/pages/[collection]/index.astro +24 -156
  115. package/src/pages/admin/api-explorer.astro +98 -0
  116. package/src/pages/admin/graphql-explorer.astro +40 -0
  117. package/src/pages/admin/graphql.astro +97 -0
  118. package/src/pages/admin/index.astro +200 -139
  119. package/src/pages/admin/keys.astro +8 -0
  120. package/src/pages/admin/rest-playground.astro +44 -0
  121. package/src/pages/admin/webhooks.astro +8 -0
  122. package/src/pages/api/[collection]/[id]/publish.ts +44 -0
  123. package/src/pages/api/[collection]/[id]/unpublish.ts +42 -0
  124. package/src/pages/api/[collection]/[id]/versions.ts +36 -0
  125. package/src/pages/api/[collection]/[id].ts +102 -159
  126. package/src/pages/api/[collection]/index.ts +151 -230
  127. package/src/pages/api/auth/[id].ts +48 -69
  128. package/src/pages/api/auth/audit-logs.ts +20 -43
  129. package/src/pages/api/auth/login.ts +159 -45
  130. package/src/pages/api/auth/logout.ts +42 -24
  131. package/src/pages/api/auth/refresh.ts +119 -0
  132. package/src/pages/api/auth/register.ts +110 -40
  133. package/src/pages/api/auth/users.ts +22 -97
  134. package/src/pages/api/collections.ts +59 -0
  135. package/src/pages/api/globals/[slug]/test.ts +172 -0
  136. package/src/pages/api/globals/[slug].ts +42 -0
  137. package/src/pages/api/graphql.ts +90 -0
  138. package/src/pages/api/health.ts +417 -40
  139. package/src/pages/api/keys/[id].ts +26 -0
  140. package/src/pages/api/keys/index.ts +75 -0
  141. package/src/pages/api/media/[id].ts +309 -0
  142. package/src/pages/api/media/folders.ts +609 -0
  143. package/src/pages/api/media/index.ts +146 -0
  144. package/src/pages/api/media/resize.ts +267 -0
  145. package/src/pages/api/search.ts +82 -0
  146. package/src/pages/api/slug-availability.ts +70 -0
  147. package/src/pages/api/storage-config.ts +20 -0
  148. package/src/pages/api/storage-status.ts +206 -0
  149. package/src/pages/api/upload.ts +334 -0
  150. package/src/pages/api/webhooks/index.ts +71 -0
  151. package/src/pages/audit/index.astro +2 -104
  152. package/src/pages/login.astro +11 -11
  153. package/src/pages/media.astro +10 -0
  154. package/src/pages/preview/[collection]/[id].astro +178 -0
  155. package/src/pages/register.astro +13 -13
  156. package/src/pages/roles/index.astro +21 -21
  157. package/src/pages/settings/[slug].astro +162 -0
  158. package/src/pages/settings/index.astro +9 -0
  159. package/src/pages/users/[id].astro +29 -21
  160. package/src/pages/users/index.astro +22 -17
  161. package/src/pages/users/new.astro +18 -17
  162. package/src/styles/main.css +553 -128
  163. package/src/components/layout/Sidebar.tsx +0 -497
@@ -1,497 +0,0 @@
1
- import React, { useState, useEffect } from "react";
2
- import type { CollectionConfig, GlobalConfig } from "@kyro-cms/core";
3
-
4
- interface SidebarProps {
5
- collections: Record<string, CollectionConfig>;
6
- globals: Record<string, GlobalConfig>;
7
- activeCollection: string | null;
8
- activeGlobal: string | null;
9
- onCollectionClick: (name: string) => void;
10
- onGlobalClick: (name: string) => void;
11
- defaultCollapsed?: boolean;
12
- onToggleCollapse?: (collapsed: boolean) => void;
13
- user?: { id: string; email: string; role: string } | null;
14
- onLogout?: () => void;
15
- }
16
-
17
- interface CollectionGroup {
18
- label: string;
19
- collections: [string, CollectionConfig][];
20
- }
21
-
22
- function groupCollections(
23
- entries: [string, CollectionConfig][],
24
- ): CollectionGroup[] {
25
- const groups: Record<string, [string, CollectionConfig][]> = {
26
- content: [],
27
- ecommerce: [],
28
- other: [],
29
- };
30
-
31
- const contentCollections = ["posts", "pages", "media", "categories", "tags"];
32
- const ecommerceCollections = [
33
- "products",
34
- "orders",
35
- "customers",
36
- "coupons",
37
- "inventory",
38
- ];
39
-
40
- for (const [name, config] of entries) {
41
- if (contentCollections.includes(name)) {
42
- groups.content.push([name, config]);
43
- } else if (ecommerceCollections.includes(name)) {
44
- groups.ecommerce.push([name, config]);
45
- } else {
46
- groups.other.push([name, config]);
47
- }
48
- }
49
-
50
- const result: CollectionGroup[] = [];
51
-
52
- if (groups.content.length > 0) {
53
- result.push({ label: "Content", collections: groups.content });
54
- }
55
- if (groups.ecommerce.length > 0) {
56
- result.push({ label: "E-commerce", collections: groups.ecommerce });
57
- }
58
- if (groups.other.length > 0) {
59
- if (groups.content.length === 0 && groups.ecommerce.length === 0) {
60
- result.push({ label: "Collections", collections: groups.other });
61
- } else {
62
- result.push({ label: "Other", collections: groups.other });
63
- }
64
- }
65
-
66
- return result;
67
- }
68
-
69
- function getGlobalIcon(slug: string): React.ReactElement {
70
- const icons: Record<string, React.ReactElement> = {
71
- "site-settings": (
72
- <svg
73
- width="18"
74
- height="18"
75
- viewBox="0 0 24 24"
76
- fill="none"
77
- stroke="currentColor"
78
- strokeWidth="2"
79
- >
80
- <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
81
- <polyline points="9,22 9,12 15,12 15,22" />
82
- </svg>
83
- ),
84
- "seo-settings": (
85
- <svg
86
- width="18"
87
- height="18"
88
- viewBox="0 0 24 24"
89
- fill="none"
90
- stroke="currentColor"
91
- strokeWidth="2"
92
- >
93
- <circle cx="11" cy="11" r="8" />
94
- <path d="m21 21-4.35-4.35" />
95
- </svg>
96
- ),
97
- "social-settings": (
98
- <svg
99
- width="18"
100
- height="18"
101
- viewBox="0 0 24 24"
102
- fill="none"
103
- stroke="currentColor"
104
- strokeWidth="2"
105
- >
106
- <circle cx="18" cy="5" r="3" />
107
- <circle cx="6" cy="12" r="3" />
108
- <circle cx="18" cy="19" r="3" />
109
- <line x1="8.59" y1="13.51" x2="15.42" y2="17.49" />
110
- <line x1="15.41" y1="6.51" x2="8.59" y2="10.49" />
111
- </svg>
112
- ),
113
- "email-settings": (
114
- <svg
115
- width="18"
116
- height="18"
117
- viewBox="0 0 24 24"
118
- fill="none"
119
- stroke="currentColor"
120
- strokeWidth="2"
121
- >
122
- <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" />
123
- <polyline points="22,6 12,13 2,6" />
124
- </svg>
125
- ),
126
- "storage-settings": (
127
- <svg
128
- width="18"
129
- height="18"
130
- viewBox="0 0 24 24"
131
- fill="none"
132
- stroke="currentColor"
133
- strokeWidth="2"
134
- >
135
- <path d="M22 12.22A2 2 0 0 0 21.78 10H20a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h.22" />
136
- <path d="M2 12.22A2 2 0 0 1 2.22 10H4a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2H2.22" />
137
- <path d="M22 4.28A2 2 0 0 0 21.78 2H20a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h.22" />
138
- <path d="M2 4.28A2 2 0 0 1 2.22 2H4a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2H2.22" />
139
- </svg>
140
- ),
141
- "access-settings": (
142
- <svg
143
- width="18"
144
- height="18"
145
- viewBox="0 0 24 24"
146
- fill="none"
147
- stroke="currentColor"
148
- strokeWidth="2"
149
- >
150
- <rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
151
- <path d="M7 11V7a5 5 0 0 1 10 0v4" />
152
- </svg>
153
- ),
154
- "store-settings": (
155
- <svg
156
- width="18"
157
- height="18"
158
- viewBox="0 0 24 24"
159
- fill="none"
160
- stroke="currentColor"
161
- strokeWidth="2"
162
- >
163
- <path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z" />
164
- <path d="M3 6h18" />
165
- <path d="M16 10a4 4 0 0 1-8 0" />
166
- </svg>
167
- ),
168
- "payment-settings": (
169
- <svg
170
- width="18"
171
- height="18"
172
- viewBox="0 0 24 24"
173
- fill="none"
174
- stroke="currentColor"
175
- strokeWidth="2"
176
- >
177
- <rect x="1" y="4" width="22" height="16" rx="2" ry="2" />
178
- <line x1="1" y1="10" x2="23" y2="10" />
179
- </svg>
180
- ),
181
- };
182
-
183
- return (
184
- icons[slug] || (
185
- <svg
186
- width="18"
187
- height="18"
188
- viewBox="0 0 24 24"
189
- fill="none"
190
- stroke="currentColor"
191
- strokeWidth="2"
192
- >
193
- <circle cx="12" cy="12" r="3" />
194
- <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" />
195
- </svg>
196
- )
197
- );
198
- }
199
-
200
- export function Sidebar({
201
- collections,
202
- globals,
203
- activeCollection,
204
- activeGlobal,
205
- onCollectionClick,
206
- onGlobalClick,
207
- defaultCollapsed = false,
208
- onToggleCollapse,
209
- user,
210
- onLogout,
211
- }: SidebarProps) {
212
- const [collapsed, setCollapsed] = useState(() => {
213
- if (typeof window !== "undefined") {
214
- const stored = localStorage.getItem("kyro-sidebar-collapsed");
215
- return stored ? stored === "true" : defaultCollapsed;
216
- }
217
- return defaultCollapsed;
218
- });
219
-
220
- useEffect(() => {
221
- localStorage.setItem("kyro-sidebar-collapsed", String(collapsed));
222
- onToggleCollapse?.(collapsed);
223
- }, [collapsed, onToggleCollapse]);
224
-
225
- const collectionEntries = Object.entries(collections);
226
- const globalEntries = Object.entries(globals);
227
- const collectionGroups = groupCollections(collectionEntries);
228
-
229
- const toggleCollapse = () => {
230
- setCollapsed((prev) => !prev);
231
- };
232
-
233
- return (
234
- <aside className={`kyro-sidebar ${collapsed ? "collapsed" : ""}`}>
235
- <div className="kyro-sidebar-logo">
236
- {!collapsed && <span className="kyro-sidebar-logo-text">Kyro</span>}
237
- {collapsed && (
238
- <div className="w-8 h-8 rounded-lg bg-primary flex items-center justify-center text-white font-bold text-sm">
239
- K
240
- </div>
241
- )}
242
- </div>
243
-
244
- <nav className="kyro-sidebar-nav">
245
- {collectionGroups.map((group) => (
246
- <div key={group.label} className="kyro-sidebar-section">
247
- {!collapsed && (
248
- <div className="kyro-sidebar-section-title">{group.label}</div>
249
- )}
250
- {group.collections.map(([name, config]) => (
251
- <button
252
- key={name}
253
- className={`kyro-sidebar-item ${
254
- activeCollection === name ? "active" : ""
255
- }`}
256
- onClick={() => onCollectionClick(name)}
257
- title={collapsed ? config.label || name : undefined}
258
- >
259
- <CollectionIcon type={name} />
260
- {!collapsed && <span>{config.label || name}</span>}
261
- </button>
262
- ))}
263
- </div>
264
- ))}
265
-
266
- {globalEntries.length > 0 && (
267
- <div className="kyro-sidebar-section">
268
- {!collapsed && (
269
- <div className="kyro-sidebar-section-title">Settings</div>
270
- )}
271
- {globalEntries.map(([name, config]) => (
272
- <button
273
- key={name}
274
- className={`kyro-sidebar-item ${
275
- activeGlobal === name ? "active" : ""
276
- }`}
277
- onClick={() => onGlobalClick(name)}
278
- title={collapsed ? config.label || name : undefined}
279
- >
280
- {getGlobalIcon(name)}
281
- {!collapsed && <span>{config.label || name}</span>}
282
- </button>
283
- ))}
284
- </div>
285
- )}
286
- </nav>
287
-
288
- <div className="kyro-sidebar-footer">
289
- {user && (
290
- <div className="kyro-sidebar-user-info">
291
- {!collapsed && (
292
- <>
293
- <div className="kyro-sidebar-user-email" title={user.email}>
294
- {user.email}
295
- </div>
296
- <div className="kyro-sidebar-user-role">{user.role}</div>
297
- </>
298
- )}
299
- {onLogout && (
300
- <button
301
- className="kyro-sidebar-item kyro-sidebar-logout"
302
- onClick={onLogout}
303
- title={collapsed ? "Logout" : undefined}
304
- >
305
- <svg
306
- width="18"
307
- height="18"
308
- viewBox="0 0 24 24"
309
- fill="none"
310
- stroke="currentColor"
311
- strokeWidth="2"
312
- >
313
- <path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9" />
314
- </svg>
315
- {!collapsed && <span>Logout</span>}
316
- </button>
317
- )}
318
- </div>
319
- )}
320
- <button
321
- className="kyro-sidebar-item"
322
- onClick={toggleCollapse}
323
- title={collapsed ? "Expand sidebar" : "Collapse sidebar"}
324
- >
325
- <svg
326
- width="18"
327
- height="18"
328
- viewBox="0 0 24 24"
329
- fill="none"
330
- stroke="currentColor"
331
- strokeWidth="2"
332
- >
333
- {collapsed ? (
334
- <path d="M13 17l5-5-5-5M6 17l5-5-5-5" />
335
- ) : (
336
- <path d="M11 17l-5-5 5-5M18 17l-5-5 5-5" />
337
- )}
338
- </svg>
339
- {!collapsed && <span>Collapse</span>}
340
- </button>
341
- </div>
342
- </aside>
343
- );
344
- }
345
-
346
- function CollectionIcon({ type }: { type: string }): React.ReactElement {
347
- const iconMap: Record<string, React.ReactElement> = {
348
- posts: (
349
- <svg
350
- width="18"
351
- height="18"
352
- viewBox="0 0 24 24"
353
- fill="none"
354
- stroke="currentColor"
355
- strokeWidth="2"
356
- >
357
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
358
- <path d="M14 2v6h6M16 13H8M16 17H8M10 9H8" />
359
- </svg>
360
- ),
361
- pages: (
362
- <svg
363
- width="18"
364
- height="18"
365
- viewBox="0 0 24 24"
366
- fill="none"
367
- stroke="currentColor"
368
- strokeWidth="2"
369
- >
370
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
371
- <path d="M14 2v6h6" />
372
- </svg>
373
- ),
374
- products: (
375
- <svg
376
- width="18"
377
- height="18"
378
- viewBox="0 0 24 24"
379
- fill="none"
380
- stroke="currentColor"
381
- strokeWidth="2"
382
- >
383
- <path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z" />
384
- <path d="M3 6h18M16 10a4 4 0 0 1-8 0" />
385
- </svg>
386
- ),
387
- orders: (
388
- <svg
389
- width="18"
390
- height="18"
391
- viewBox="0 0 24 24"
392
- fill="none"
393
- stroke="currentColor"
394
- strokeWidth="2"
395
- >
396
- <path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" />
397
- <rect x="8" y="2" width="8" height="4" rx="1" ry="1" />
398
- </svg>
399
- ),
400
- customers: (
401
- <svg
402
- width="18"
403
- height="18"
404
- viewBox="0 0 24 24"
405
- fill="none"
406
- stroke="currentColor"
407
- strokeWidth="2"
408
- >
409
- <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
410
- <circle cx="9" cy="7" r="4" />
411
- <path d="M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75" />
412
- </svg>
413
- ),
414
- media: (
415
- <svg
416
- width="18"
417
- height="18"
418
- viewBox="0 0 24 24"
419
- fill="none"
420
- stroke="currentColor"
421
- strokeWidth="2"
422
- >
423
- <rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
424
- <circle cx="8.5" cy="8.5" r="1.5" />
425
- <path d="M21 15l-5-5L5 21" />
426
- </svg>
427
- ),
428
- categories: (
429
- <svg
430
- width="18"
431
- height="18"
432
- viewBox="0 0 24 24"
433
- fill="none"
434
- stroke="currentColor"
435
- strokeWidth="2"
436
- >
437
- <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" />
438
- </svg>
439
- ),
440
- tags: (
441
- <svg
442
- width="18"
443
- height="18"
444
- viewBox="0 0 24 24"
445
- fill="none"
446
- stroke="currentColor"
447
- strokeWidth="2"
448
- >
449
- <path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z" />
450
- <line x1="7" y1="7" x2="7.01" y2="7" />
451
- </svg>
452
- ),
453
- coupons: (
454
- <svg
455
- width="18"
456
- height="18"
457
- viewBox="0 0 24 24"
458
- fill="none"
459
- stroke="currentColor"
460
- strokeWidth="2"
461
- >
462
- <path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z" />
463
- <line x1="7" y1="7" x2="7.01" y2="7" />
464
- </svg>
465
- ),
466
- inventory: (
467
- <svg
468
- width="18"
469
- height="18"
470
- viewBox="0 0 24 24"
471
- fill="none"
472
- stroke="currentColor"
473
- strokeWidth="2"
474
- >
475
- <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
476
- <polyline points="3.27,6.96 12,12.01 20.73,6.96" />
477
- <line x1="12" y1="22.08" x2="12" y2="12" />
478
- </svg>
479
- ),
480
- };
481
-
482
- return (
483
- iconMap[type] || (
484
- <svg
485
- width="18"
486
- height="18"
487
- viewBox="0 0 24 24"
488
- fill="none"
489
- stroke="currentColor"
490
- strokeWidth="2"
491
- >
492
- <path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" />
493
- <path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" />
494
- </svg>
495
- )
496
- );
497
- }