@djangocfg/layouts 1.2.5 → 1.2.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.
- package/package.json +5 -5
- package/src/auth/context/AuthContext.tsx +10 -6
- package/src/layouts/AppLayout/AppLayout.tsx +82 -55
- package/src/layouts/AppLayout/components/PackageVersions/packageVersions.config.ts +8 -8
- package/src/layouts/AppLayout/index.ts +12 -0
- package/src/layouts/AppLayout/layouts/CfgLayout/CfgLayout.tsx +104 -0
- package/src/layouts/AppLayout/layouts/CfgLayout/README.md +389 -0
- package/src/layouts/AppLayout/layouts/CfgLayout/components/ParentSync.tsx +149 -0
- package/src/layouts/AppLayout/layouts/CfgLayout/components/index.ts +1 -0
- package/src/layouts/AppLayout/layouts/CfgLayout/hooks/index.ts +6 -0
- package/src/layouts/AppLayout/layouts/CfgLayout/hooks/useApp.ts +282 -0
- package/src/layouts/AppLayout/layouts/CfgLayout/index.ts +20 -0
- package/src/layouts/AppLayout/layouts/CfgLayout/types/index.ts +45 -0
- package/src/layouts/UILayout/config/components/data.config.tsx +125 -0
- package/src/layouts/UILayout/config/components/feedback.config.tsx +44 -0
- package/src/layouts/UILayout/config/components/forms.config.tsx +194 -0
- package/src/layouts/UILayout/config/components/layout.config.tsx +95 -0
- package/src/layouts/UILayout/config/components/navigation.config.tsx +50 -0
- package/src/layouts/UILayout/config/components/specialized.config.tsx +250 -0
- package/src/layouts/index.ts +3 -0
- package/src/utils/logger.ts +4 -2
|
@@ -18,10 +18,39 @@ import {
|
|
|
18
18
|
Textarea,
|
|
19
19
|
Switch,
|
|
20
20
|
Slider,
|
|
21
|
+
Combobox,
|
|
22
|
+
InputOTP,
|
|
23
|
+
InputOTPGroup,
|
|
24
|
+
InputOTPSlot,
|
|
25
|
+
PhoneInput,
|
|
26
|
+
Form,
|
|
27
|
+
FormControl,
|
|
28
|
+
FormDescription,
|
|
29
|
+
FormField,
|
|
30
|
+
FormItem,
|
|
31
|
+
FormLabel,
|
|
32
|
+
FormMessage,
|
|
33
|
+
Field,
|
|
21
34
|
} from '@djangocfg/ui';
|
|
22
35
|
import type { ComponentConfig } from './types';
|
|
23
36
|
|
|
24
37
|
export const FORM_COMPONENTS: ComponentConfig[] = [
|
|
38
|
+
{
|
|
39
|
+
name: 'Label',
|
|
40
|
+
category: 'forms',
|
|
41
|
+
description: 'Accessible label component for form inputs',
|
|
42
|
+
importPath: "import { Label } from '@djangocfg/ui';",
|
|
43
|
+
example: `<div className="space-y-2">
|
|
44
|
+
<Label htmlFor="email">Email address</Label>
|
|
45
|
+
<Input id="email" type="email" placeholder="Enter your email" />
|
|
46
|
+
</div>`,
|
|
47
|
+
preview: (
|
|
48
|
+
<div className="space-y-2 max-w-sm">
|
|
49
|
+
<Label htmlFor="demo-email">Email address</Label>
|
|
50
|
+
<Input id="demo-email" type="email" placeholder="Enter your email" />
|
|
51
|
+
</div>
|
|
52
|
+
),
|
|
53
|
+
},
|
|
25
54
|
{
|
|
26
55
|
name: 'Button',
|
|
27
56
|
category: 'forms',
|
|
@@ -168,4 +197,169 @@ export const FORM_COMPONENTS: ComponentConfig[] = [
|
|
|
168
197
|
<Slider defaultValue={[50]} max={100} step={1} className="w-[200px]" />
|
|
169
198
|
),
|
|
170
199
|
},
|
|
200
|
+
{
|
|
201
|
+
name: 'Combobox',
|
|
202
|
+
category: 'forms',
|
|
203
|
+
description: 'Searchable dropdown with autocomplete',
|
|
204
|
+
importPath: "import { Combobox } from '@djangocfg/ui';",
|
|
205
|
+
example: `<Combobox
|
|
206
|
+
options={[
|
|
207
|
+
{ value: "javascript", label: "JavaScript" },
|
|
208
|
+
{ value: "typescript", label: "TypeScript" },
|
|
209
|
+
{ value: "python", label: "Python" },
|
|
210
|
+
{ value: "rust", label: "Rust" },
|
|
211
|
+
]}
|
|
212
|
+
placeholder="Select language..."
|
|
213
|
+
searchPlaceholder="Search language..."
|
|
214
|
+
emptyText="No language found."
|
|
215
|
+
/>`,
|
|
216
|
+
preview: (
|
|
217
|
+
<Combobox
|
|
218
|
+
options={[
|
|
219
|
+
{ value: "javascript", label: "JavaScript" },
|
|
220
|
+
{ value: "typescript", label: "TypeScript" },
|
|
221
|
+
{ value: "python", label: "Python" },
|
|
222
|
+
{ value: "rust", label: "Rust" },
|
|
223
|
+
]}
|
|
224
|
+
placeholder="Select language..."
|
|
225
|
+
searchPlaceholder="Search language..."
|
|
226
|
+
emptyText="No language found."
|
|
227
|
+
className="w-[200px]"
|
|
228
|
+
/>
|
|
229
|
+
),
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
name: 'InputOTP',
|
|
233
|
+
category: 'forms',
|
|
234
|
+
description: 'One-time password input component',
|
|
235
|
+
importPath: "import { InputOTP, InputOTPGroup, InputOTPSlot } from '@djangocfg/ui';",
|
|
236
|
+
example: `<InputOTP maxLength={6}>
|
|
237
|
+
<InputOTPGroup>
|
|
238
|
+
<InputOTPSlot index={0} />
|
|
239
|
+
<InputOTPSlot index={1} />
|
|
240
|
+
<InputOTPSlot index={2} />
|
|
241
|
+
<InputOTPSlot index={3} />
|
|
242
|
+
<InputOTPSlot index={4} />
|
|
243
|
+
<InputOTPSlot index={5} />
|
|
244
|
+
</InputOTPGroup>
|
|
245
|
+
</InputOTP>`,
|
|
246
|
+
preview: (
|
|
247
|
+
<InputOTP maxLength={6}>
|
|
248
|
+
<InputOTPGroup>
|
|
249
|
+
<InputOTPSlot index={0} />
|
|
250
|
+
<InputOTPSlot index={1} />
|
|
251
|
+
<InputOTPSlot index={2} />
|
|
252
|
+
<InputOTPSlot index={3} />
|
|
253
|
+
<InputOTPSlot index={4} />
|
|
254
|
+
<InputOTPSlot index={5} />
|
|
255
|
+
</InputOTPGroup>
|
|
256
|
+
</InputOTP>
|
|
257
|
+
),
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
name: 'PhoneInput',
|
|
261
|
+
category: 'forms',
|
|
262
|
+
description: 'International phone number input with country selector',
|
|
263
|
+
importPath: "import { PhoneInput } from '@djangocfg/ui';",
|
|
264
|
+
example: `<PhoneInput
|
|
265
|
+
defaultCountry="US"
|
|
266
|
+
placeholder="Enter phone number"
|
|
267
|
+
className="max-w-sm"
|
|
268
|
+
/>`,
|
|
269
|
+
preview: (
|
|
270
|
+
<PhoneInput
|
|
271
|
+
defaultCountry="US"
|
|
272
|
+
placeholder="Enter phone number"
|
|
273
|
+
className="max-w-sm"
|
|
274
|
+
/>
|
|
275
|
+
),
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
name: 'Form',
|
|
279
|
+
category: 'forms',
|
|
280
|
+
description: 'React Hook Form wrapper with form validation',
|
|
281
|
+
importPath: "import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@djangocfg/ui';",
|
|
282
|
+
example: `// Requires react-hook-form
|
|
283
|
+
import { useForm } from 'react-hook-form';
|
|
284
|
+
|
|
285
|
+
function MyForm() {
|
|
286
|
+
const form = useForm();
|
|
287
|
+
|
|
288
|
+
return (
|
|
289
|
+
<Form {...form}>
|
|
290
|
+
<form onSubmit={form.handleSubmit(onSubmit)}>
|
|
291
|
+
<FormField
|
|
292
|
+
control={form.control}
|
|
293
|
+
name="username"
|
|
294
|
+
render={({ field }) => (
|
|
295
|
+
<FormItem>
|
|
296
|
+
<FormLabel>Username</FormLabel>
|
|
297
|
+
<FormControl>
|
|
298
|
+
<Input placeholder="Enter username" {...field} />
|
|
299
|
+
</FormControl>
|
|
300
|
+
<FormDescription>
|
|
301
|
+
Your public display name
|
|
302
|
+
</FormDescription>
|
|
303
|
+
<FormMessage />
|
|
304
|
+
</FormItem>
|
|
305
|
+
)}
|
|
306
|
+
/>
|
|
307
|
+
</form>
|
|
308
|
+
</Form>
|
|
309
|
+
);
|
|
310
|
+
}`,
|
|
311
|
+
preview: (
|
|
312
|
+
<div className="p-6 border rounded-md bg-muted/50">
|
|
313
|
+
<p className="text-sm text-muted-foreground mb-4">
|
|
314
|
+
The Form component is a wrapper around React Hook Form with:
|
|
315
|
+
</p>
|
|
316
|
+
<ul className="space-y-2 text-sm text-muted-foreground">
|
|
317
|
+
<li>• Integrated form validation</li>
|
|
318
|
+
<li>• Accessible form fields</li>
|
|
319
|
+
<li>• Error message handling</li>
|
|
320
|
+
<li>• Field descriptions and labels</li>
|
|
321
|
+
<li>• Type-safe with TypeScript</li>
|
|
322
|
+
</ul>
|
|
323
|
+
<p className="text-xs text-muted-foreground mt-4">
|
|
324
|
+
See the <strong>react-hook-form</strong> documentation for usage examples
|
|
325
|
+
</p>
|
|
326
|
+
</div>
|
|
327
|
+
),
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
name: 'Field',
|
|
331
|
+
category: 'forms',
|
|
332
|
+
description: 'Advanced field component with label, description and validation',
|
|
333
|
+
importPath: "import { Field, FieldGroup, FieldSet, FieldLegend } from '@djangocfg/ui';",
|
|
334
|
+
example: `<FieldSet>
|
|
335
|
+
<FieldLegend>Account Information</FieldLegend>
|
|
336
|
+
<FieldGroup>
|
|
337
|
+
<Field>
|
|
338
|
+
<FieldLabel>Username</FieldLabel>
|
|
339
|
+
<Input placeholder="Enter username" />
|
|
340
|
+
<FieldDescription>
|
|
341
|
+
Your unique username for the platform
|
|
342
|
+
</FieldDescription>
|
|
343
|
+
<FieldError>Username is required</FieldError>
|
|
344
|
+
</Field>
|
|
345
|
+
</FieldGroup>
|
|
346
|
+
</FieldSet>`,
|
|
347
|
+
preview: (
|
|
348
|
+
<div className="p-6 border rounded-md bg-muted/50">
|
|
349
|
+
<p className="text-sm text-muted-foreground mb-4">
|
|
350
|
+
Field component provides structured form fields with:
|
|
351
|
+
</p>
|
|
352
|
+
<ul className="space-y-2 text-sm text-muted-foreground">
|
|
353
|
+
<li>• Label and description support</li>
|
|
354
|
+
<li>• Error message handling</li>
|
|
355
|
+
<li>• Field grouping (FieldSet, FieldGroup)</li>
|
|
356
|
+
<li>• Accessible by default</li>
|
|
357
|
+
<li>• Consistent styling</li>
|
|
358
|
+
</ul>
|
|
359
|
+
<p className="text-xs text-muted-foreground mt-4">
|
|
360
|
+
Perfect for complex forms with validation
|
|
361
|
+
</p>
|
|
362
|
+
</div>
|
|
363
|
+
),
|
|
364
|
+
},
|
|
171
365
|
];
|
|
@@ -15,6 +15,13 @@ import {
|
|
|
15
15
|
Skeleton,
|
|
16
16
|
AspectRatio,
|
|
17
17
|
Sticky,
|
|
18
|
+
ScrollArea,
|
|
19
|
+
ScrollBar,
|
|
20
|
+
ResizableHandle,
|
|
21
|
+
ResizablePanel,
|
|
22
|
+
ResizablePanelGroup,
|
|
23
|
+
Section,
|
|
24
|
+
SectionHeader,
|
|
18
25
|
} from '@djangocfg/ui';
|
|
19
26
|
import type { ComponentConfig } from './types';
|
|
20
27
|
|
|
@@ -130,4 +137,92 @@ export const LAYOUT_COMPONENTS: ComponentConfig[] = [
|
|
|
130
137
|
</div>
|
|
131
138
|
),
|
|
132
139
|
},
|
|
140
|
+
{
|
|
141
|
+
name: 'ScrollArea',
|
|
142
|
+
category: 'layout',
|
|
143
|
+
description: 'Custom scrollable area with styled scrollbar',
|
|
144
|
+
importPath: "import { ScrollArea, ScrollBar } from '@djangocfg/ui';",
|
|
145
|
+
example: `<ScrollArea className="h-[200px] w-[350px] rounded-md border p-4">
|
|
146
|
+
<div className="space-y-4">
|
|
147
|
+
{Array.from({ length: 20 }).map((_, i) => (
|
|
148
|
+
<div key={i} className="text-sm">
|
|
149
|
+
Content item {i + 1}
|
|
150
|
+
</div>
|
|
151
|
+
))}
|
|
152
|
+
</div>
|
|
153
|
+
<ScrollBar orientation="vertical" />
|
|
154
|
+
</ScrollArea>`,
|
|
155
|
+
preview: (
|
|
156
|
+
<ScrollArea className="h-[200px] w-[350px] rounded-md border p-4">
|
|
157
|
+
<div className="space-y-4">
|
|
158
|
+
{Array.from({ length: 20 }).map((_, i) => (
|
|
159
|
+
<div key={i} className="text-sm">
|
|
160
|
+
Content item {i + 1} - Scroll to see more content
|
|
161
|
+
</div>
|
|
162
|
+
))}
|
|
163
|
+
</div>
|
|
164
|
+
<ScrollBar orientation="vertical" />
|
|
165
|
+
</ScrollArea>
|
|
166
|
+
),
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: 'Resizable',
|
|
170
|
+
category: 'layout',
|
|
171
|
+
description: 'Resizable panel layout with draggable handles',
|
|
172
|
+
importPath: "import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@djangocfg/ui';",
|
|
173
|
+
example: `<ResizablePanelGroup direction="horizontal" className="max-w-md rounded-lg border">
|
|
174
|
+
<ResizablePanel defaultSize={50}>
|
|
175
|
+
<div className="flex h-[200px] items-center justify-center p-6">
|
|
176
|
+
<span className="font-semibold">Panel One</span>
|
|
177
|
+
</div>
|
|
178
|
+
</ResizablePanel>
|
|
179
|
+
<ResizableHandle />
|
|
180
|
+
<ResizablePanel defaultSize={50}>
|
|
181
|
+
<div className="flex h-[200px] items-center justify-center p-6">
|
|
182
|
+
<span className="font-semibold">Panel Two</span>
|
|
183
|
+
</div>
|
|
184
|
+
</ResizablePanel>
|
|
185
|
+
</ResizablePanelGroup>`,
|
|
186
|
+
preview: (
|
|
187
|
+
<ResizablePanelGroup direction="horizontal" className="max-w-md rounded-lg border">
|
|
188
|
+
<ResizablePanel defaultSize={50}>
|
|
189
|
+
<div className="flex h-[200px] items-center justify-center p-6">
|
|
190
|
+
<span className="font-semibold">Panel One</span>
|
|
191
|
+
</div>
|
|
192
|
+
</ResizablePanel>
|
|
193
|
+
<ResizableHandle />
|
|
194
|
+
<ResizablePanel defaultSize={50}>
|
|
195
|
+
<div className="flex h-[200px] items-center justify-center p-6">
|
|
196
|
+
<span className="font-semibold">Panel Two</span>
|
|
197
|
+
</div>
|
|
198
|
+
</ResizablePanel>
|
|
199
|
+
</ResizablePanelGroup>
|
|
200
|
+
),
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: 'Section',
|
|
204
|
+
category: 'layout',
|
|
205
|
+
description: 'Semantic section container with header',
|
|
206
|
+
importPath: "import { Section, SectionHeader } from '@djangocfg/ui';",
|
|
207
|
+
example: `<Section>
|
|
208
|
+
<SectionHeader
|
|
209
|
+
title="Section Title"
|
|
210
|
+
description="Section description goes here"
|
|
211
|
+
/>
|
|
212
|
+
<div className="p-4">
|
|
213
|
+
Section content goes here...
|
|
214
|
+
</div>
|
|
215
|
+
</Section>`,
|
|
216
|
+
preview: (
|
|
217
|
+
<Section>
|
|
218
|
+
<SectionHeader
|
|
219
|
+
title="Section Title"
|
|
220
|
+
subtitle="Section description goes here"
|
|
221
|
+
/>
|
|
222
|
+
<div className="p-4 border-t">
|
|
223
|
+
<p className="text-sm">Section content goes here...</p>
|
|
224
|
+
</div>
|
|
225
|
+
</Section>
|
|
226
|
+
),
|
|
227
|
+
},
|
|
133
228
|
];
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
BreadcrumbList,
|
|
17
17
|
BreadcrumbPage,
|
|
18
18
|
BreadcrumbSeparator,
|
|
19
|
+
BreadcrumbNavigation,
|
|
19
20
|
Tabs,
|
|
20
21
|
TabsContent,
|
|
21
22
|
TabsList,
|
|
@@ -27,6 +28,7 @@ import {
|
|
|
27
28
|
PaginationLink,
|
|
28
29
|
PaginationNext,
|
|
29
30
|
PaginationPrevious,
|
|
31
|
+
SSRPagination,
|
|
30
32
|
} from '@djangocfg/ui';
|
|
31
33
|
import type { ComponentConfig } from './types';
|
|
32
34
|
|
|
@@ -241,4 +243,52 @@ export const NAVIGATION_COMPONENTS: ComponentConfig[] = [
|
|
|
241
243
|
</Pagination>
|
|
242
244
|
),
|
|
243
245
|
},
|
|
246
|
+
{
|
|
247
|
+
name: 'BreadcrumbNavigation',
|
|
248
|
+
category: 'navigation',
|
|
249
|
+
description: 'Enhanced breadcrumb component with automatic path generation',
|
|
250
|
+
importPath: `import { BreadcrumbNavigation } from '@djangocfg/ui';`,
|
|
251
|
+
example: `<BreadcrumbNavigation
|
|
252
|
+
items={[
|
|
253
|
+
{ label: "Home", href: "/" },
|
|
254
|
+
{ label: "Products", href: "/products" },
|
|
255
|
+
{ label: "Category", href: "/products/category" },
|
|
256
|
+
{ label: "Item", href: "/products/category/item" },
|
|
257
|
+
]}
|
|
258
|
+
/>`,
|
|
259
|
+
preview: (
|
|
260
|
+
<BreadcrumbNavigation
|
|
261
|
+
items={[
|
|
262
|
+
{ label: "Home", href: "/" },
|
|
263
|
+
{ label: "Products", href: "/products" },
|
|
264
|
+
{ label: "Category", href: "/products/category" },
|
|
265
|
+
{ label: "Item", href: "/products/category/item" },
|
|
266
|
+
]}
|
|
267
|
+
/>
|
|
268
|
+
),
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
name: 'SSRPagination',
|
|
272
|
+
category: 'navigation',
|
|
273
|
+
description: 'Server-side rendered pagination component',
|
|
274
|
+
importPath: `import { SSRPagination } from '@djangocfg/ui';`,
|
|
275
|
+
example: `<SSRPagination
|
|
276
|
+
currentPage={2}
|
|
277
|
+
totalPages={10}
|
|
278
|
+
totalItems={100}
|
|
279
|
+
itemsPerPage={10}
|
|
280
|
+
hasNextPage={true}
|
|
281
|
+
hasPreviousPage={true}
|
|
282
|
+
/>`,
|
|
283
|
+
preview: (
|
|
284
|
+
<SSRPagination
|
|
285
|
+
currentPage={2}
|
|
286
|
+
totalPages={10}
|
|
287
|
+
totalItems={100}
|
|
288
|
+
itemsPerPage={10}
|
|
289
|
+
hasNextPage={true}
|
|
290
|
+
hasPreviousPage={true}
|
|
291
|
+
/>
|
|
292
|
+
),
|
|
293
|
+
},
|
|
244
294
|
];
|
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import React from 'react';
|
|
6
|
+
import {
|
|
7
|
+
Button,
|
|
8
|
+
ButtonGroup,
|
|
9
|
+
Empty,
|
|
10
|
+
EmptyHeader,
|
|
11
|
+
EmptyTitle,
|
|
12
|
+
EmptyDescription,
|
|
13
|
+
EmptyContent,
|
|
14
|
+
EmptyMedia,
|
|
15
|
+
Spinner,
|
|
16
|
+
Kbd,
|
|
17
|
+
TokenIcon,
|
|
18
|
+
Toaster,
|
|
19
|
+
InputGroup,
|
|
20
|
+
Item,
|
|
21
|
+
} from '@djangocfg/ui';
|
|
6
22
|
import type { ComponentConfig } from './types';
|
|
7
23
|
|
|
8
24
|
export const SPECIALIZED_COMPONENTS: ComponentConfig[] = [
|
|
@@ -122,4 +138,238 @@ export const SPECIALIZED_COMPONENTS: ComponentConfig[] = [
|
|
|
122
138
|
</div>
|
|
123
139
|
),
|
|
124
140
|
},
|
|
141
|
+
{
|
|
142
|
+
name: 'ButtonGroup',
|
|
143
|
+
category: 'specialized',
|
|
144
|
+
description: 'Group buttons together with shared borders',
|
|
145
|
+
importPath: `import { ButtonGroup, Button } from '@djangocfg/ui';`,
|
|
146
|
+
example: `<ButtonGroup orientation="horizontal">
|
|
147
|
+
<Button variant="outline">Left</Button>
|
|
148
|
+
<Button variant="outline">Center</Button>
|
|
149
|
+
<Button variant="outline">Right</Button>
|
|
150
|
+
</ButtonGroup>`,
|
|
151
|
+
preview: (
|
|
152
|
+
<div className="space-y-4">
|
|
153
|
+
<ButtonGroup orientation="horizontal">
|
|
154
|
+
<Button variant="outline">Left</Button>
|
|
155
|
+
<Button variant="outline">Center</Button>
|
|
156
|
+
<Button variant="outline">Right</Button>
|
|
157
|
+
</ButtonGroup>
|
|
158
|
+
<ButtonGroup orientation="vertical">
|
|
159
|
+
<Button variant="outline">Top</Button>
|
|
160
|
+
<Button variant="outline">Middle</Button>
|
|
161
|
+
<Button variant="outline">Bottom</Button>
|
|
162
|
+
</ButtonGroup>
|
|
163
|
+
</div>
|
|
164
|
+
),
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'Empty',
|
|
168
|
+
category: 'specialized',
|
|
169
|
+
description: 'Empty state component for no data scenarios',
|
|
170
|
+
importPath: `import { Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent, EmptyMedia } from '@djangocfg/ui';`,
|
|
171
|
+
example: `<Empty>
|
|
172
|
+
<EmptyHeader>
|
|
173
|
+
<EmptyMedia>
|
|
174
|
+
<svg>...</svg>
|
|
175
|
+
</EmptyMedia>
|
|
176
|
+
<EmptyTitle>No results found</EmptyTitle>
|
|
177
|
+
<EmptyDescription>
|
|
178
|
+
Try adjusting your search or filter to find what you're looking for.
|
|
179
|
+
</EmptyDescription>
|
|
180
|
+
</EmptyHeader>
|
|
181
|
+
<EmptyContent>
|
|
182
|
+
<Button>Clear filters</Button>
|
|
183
|
+
</EmptyContent>
|
|
184
|
+
</Empty>`,
|
|
185
|
+
preview: (
|
|
186
|
+
<Empty className="border">
|
|
187
|
+
<EmptyHeader>
|
|
188
|
+
<EmptyMedia variant="icon">
|
|
189
|
+
<svg className="size-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
190
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" />
|
|
191
|
+
</svg>
|
|
192
|
+
</EmptyMedia>
|
|
193
|
+
<EmptyTitle>No results found</EmptyTitle>
|
|
194
|
+
<EmptyDescription>
|
|
195
|
+
Try adjusting your search or filter to find what you're looking for.
|
|
196
|
+
</EmptyDescription>
|
|
197
|
+
</EmptyHeader>
|
|
198
|
+
<EmptyContent>
|
|
199
|
+
<Button>Clear filters</Button>
|
|
200
|
+
</EmptyContent>
|
|
201
|
+
</Empty>
|
|
202
|
+
),
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
name: 'Spinner',
|
|
206
|
+
category: 'specialized',
|
|
207
|
+
description: 'Loading spinner indicator',
|
|
208
|
+
importPath: `import { Spinner } from '@djangocfg/ui';`,
|
|
209
|
+
example: `<div className="flex gap-4 items-center">
|
|
210
|
+
<Spinner />
|
|
211
|
+
<Spinner className="size-6" />
|
|
212
|
+
<Spinner className="size-8" />
|
|
213
|
+
</div>`,
|
|
214
|
+
preview: (
|
|
215
|
+
<div className="flex gap-4 items-center">
|
|
216
|
+
<Spinner />
|
|
217
|
+
<Spinner className="size-6" />
|
|
218
|
+
<Spinner className="size-8" />
|
|
219
|
+
</div>
|
|
220
|
+
),
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
name: 'Kbd',
|
|
224
|
+
category: 'specialized',
|
|
225
|
+
description: 'Keyboard key display component',
|
|
226
|
+
importPath: `import { Kbd } from '@djangocfg/ui';`,
|
|
227
|
+
example: `<div className="flex gap-2">
|
|
228
|
+
<Kbd>⌘</Kbd>
|
|
229
|
+
<Kbd>K</Kbd>
|
|
230
|
+
</div>`,
|
|
231
|
+
preview: (
|
|
232
|
+
<div className="space-y-4">
|
|
233
|
+
<div className="flex gap-2 items-center">
|
|
234
|
+
<span className="text-sm">Press</span>
|
|
235
|
+
<Kbd>⌘</Kbd>
|
|
236
|
+
<Kbd>K</Kbd>
|
|
237
|
+
<span className="text-sm">to open</span>
|
|
238
|
+
</div>
|
|
239
|
+
<div className="flex gap-2 items-center">
|
|
240
|
+
<span className="text-sm">Press</span>
|
|
241
|
+
<Kbd>Ctrl</Kbd>
|
|
242
|
+
<span className="text-sm">+</span>
|
|
243
|
+
<Kbd>C</Kbd>
|
|
244
|
+
<span className="text-sm">to copy</span>
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
),
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
name: 'TokenIcon',
|
|
251
|
+
category: 'specialized',
|
|
252
|
+
description: 'Cryptocurrency token icon component',
|
|
253
|
+
importPath: `import { TokenIcon } from '@djangocfg/ui';`,
|
|
254
|
+
example: `<div className="flex gap-4">
|
|
255
|
+
<TokenIcon symbol="btc" size={32} />
|
|
256
|
+
<TokenIcon symbol="eth" size={32} />
|
|
257
|
+
<TokenIcon symbol="usdt" size={32} />
|
|
258
|
+
</div>`,
|
|
259
|
+
preview: (
|
|
260
|
+
<div className="flex gap-4 items-center">
|
|
261
|
+
<TokenIcon symbol="btc" size={32} />
|
|
262
|
+
<TokenIcon symbol="eth" size={32} />
|
|
263
|
+
<TokenIcon symbol="usdt" size={32} />
|
|
264
|
+
<TokenIcon symbol="bnb" size={32} />
|
|
265
|
+
</div>
|
|
266
|
+
),
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
name: 'Sonner (Toaster)',
|
|
270
|
+
category: 'specialized',
|
|
271
|
+
description: 'Toast notifications powered by Sonner library',
|
|
272
|
+
importPath: `import { Toaster } from '@djangocfg/ui';
|
|
273
|
+
import { toast } from 'sonner';`,
|
|
274
|
+
example: `// Add Toaster to your app layout
|
|
275
|
+
<Toaster />
|
|
276
|
+
|
|
277
|
+
// Then use toast anywhere in your app
|
|
278
|
+
toast.success('Operation completed!');
|
|
279
|
+
toast.error('Something went wrong');
|
|
280
|
+
toast.info('New message received');
|
|
281
|
+
toast.promise(
|
|
282
|
+
fetchData(),
|
|
283
|
+
{
|
|
284
|
+
loading: 'Loading...',
|
|
285
|
+
success: 'Data loaded!',
|
|
286
|
+
error: 'Failed to load',
|
|
287
|
+
}
|
|
288
|
+
);`,
|
|
289
|
+
preview: (
|
|
290
|
+
<div className="p-6 border rounded-md bg-muted/50">
|
|
291
|
+
<p className="text-sm text-muted-foreground mb-4">
|
|
292
|
+
Sonner is a powerful toast notification system with:
|
|
293
|
+
</p>
|
|
294
|
+
<ul className="space-y-2 text-sm text-muted-foreground">
|
|
295
|
+
<li>• Promise-based toasts</li>
|
|
296
|
+
<li>• Multiple variants (success, error, info, warning)</li>
|
|
297
|
+
<li>• Custom duration and position</li>
|
|
298
|
+
<li>• Action buttons support</li>
|
|
299
|
+
<li>• Dark mode support</li>
|
|
300
|
+
</ul>
|
|
301
|
+
<p className="text-xs text-muted-foreground mt-4">
|
|
302
|
+
See <strong>sonner</strong> documentation for API details
|
|
303
|
+
</p>
|
|
304
|
+
</div>
|
|
305
|
+
),
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
name: 'InputGroup',
|
|
309
|
+
category: 'specialized',
|
|
310
|
+
description: 'Enhanced input with prefix/suffix addons',
|
|
311
|
+
importPath: `import { InputGroup, Input } from '@djangocfg/ui';`,
|
|
312
|
+
example: `<InputGroup>
|
|
313
|
+
<InputGroupAddon align="inline-start">
|
|
314
|
+
<SearchIcon className="size-4" />
|
|
315
|
+
</InputGroupAddon>
|
|
316
|
+
<Input placeholder="Search..." />
|
|
317
|
+
<InputGroupAddon align="inline-end">
|
|
318
|
+
<Kbd>⌘K</Kbd>
|
|
319
|
+
</InputGroupAddon>
|
|
320
|
+
</InputGroup>`,
|
|
321
|
+
preview: (
|
|
322
|
+
<div className="p-6 border rounded-md bg-muted/50 space-y-4">
|
|
323
|
+
<p className="text-sm text-muted-foreground">
|
|
324
|
+
InputGroup allows you to add prefixes and suffixes to inputs:
|
|
325
|
+
</p>
|
|
326
|
+
<ul className="space-y-2 text-sm text-muted-foreground">
|
|
327
|
+
<li>• Icons and text addons</li>
|
|
328
|
+
<li>• Button addons</li>
|
|
329
|
+
<li>• Keyboard shortcuts display</li>
|
|
330
|
+
<li>• Currency and units</li>
|
|
331
|
+
<li>• Inline and block alignment</li>
|
|
332
|
+
</ul>
|
|
333
|
+
<InputGroup className="max-w-sm">
|
|
334
|
+
<div className="px-3 text-sm text-muted-foreground">$</div>
|
|
335
|
+
<input type="text" placeholder="0.00" className="flex-1 bg-transparent border-0 outline-none px-2" />
|
|
336
|
+
<div className="px-3 text-sm text-muted-foreground">USD</div>
|
|
337
|
+
</InputGroup>
|
|
338
|
+
</div>
|
|
339
|
+
),
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: 'Item',
|
|
343
|
+
category: 'specialized',
|
|
344
|
+
description: 'List item component with variants and layouts',
|
|
345
|
+
importPath: `import { Item, ItemGroup } from '@djangocfg/ui';`,
|
|
346
|
+
example: `<ItemGroup>
|
|
347
|
+
<Item variant="outline" size="default">
|
|
348
|
+
<ItemIcon>
|
|
349
|
+
<FileIcon />
|
|
350
|
+
</ItemIcon>
|
|
351
|
+
<ItemContent>
|
|
352
|
+
<ItemTitle>Document.pdf</ItemTitle>
|
|
353
|
+
<ItemDescription>Updated 2 hours ago</ItemDescription>
|
|
354
|
+
</ItemContent>
|
|
355
|
+
<ItemAction>
|
|
356
|
+
<Button variant="ghost" size="sm">View</Button>
|
|
357
|
+
</ItemAction>
|
|
358
|
+
</Item>
|
|
359
|
+
</ItemGroup>`,
|
|
360
|
+
preview: (
|
|
361
|
+
<div className="p-6 border rounded-md bg-muted/50">
|
|
362
|
+
<p className="text-sm text-muted-foreground mb-4">
|
|
363
|
+
Item component for building lists with:
|
|
364
|
+
</p>
|
|
365
|
+
<ul className="space-y-2 text-sm text-muted-foreground">
|
|
366
|
+
<li>• Multiple variants (default, outline, muted)</li>
|
|
367
|
+
<li>• Icon, content, and action slots</li>
|
|
368
|
+
<li>• Flexible layouts</li>
|
|
369
|
+
<li>• Separator support</li>
|
|
370
|
+
<li>• Perfect for file lists, notifications, etc.</li>
|
|
371
|
+
</ul>
|
|
372
|
+
</div>
|
|
373
|
+
),
|
|
374
|
+
},
|
|
125
375
|
];
|
package/src/layouts/index.ts
CHANGED
package/src/utils/logger.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { createConsola } from 'consola';
|
|
|
3
3
|
/**
|
|
4
4
|
* Universal logger for @djangocfg/layouts
|
|
5
5
|
* Uses consola for beautiful console logging
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* Log levels:
|
|
8
8
|
* - 0: silent
|
|
9
9
|
* - 1: fatal, error
|
|
@@ -12,8 +12,10 @@ import { createConsola } from 'consola';
|
|
|
12
12
|
* - 4: debug
|
|
13
13
|
* - 5: trace, verbose
|
|
14
14
|
*/
|
|
15
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
16
|
+
|
|
15
17
|
export const logger = createConsola({
|
|
16
|
-
level:
|
|
18
|
+
level: isDevelopment ? 4 : 1, // dev: debug, production: errors only
|
|
17
19
|
}).withTag('layouts');
|
|
18
20
|
|
|
19
21
|
// ─────────────────────────────────────────────────────────────────────────
|