@djangocfg/ui-core 2.1.381 → 2.1.383
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/README.md +85 -21
- package/package.json +5 -12
- package/src/components/boundary/Boundary.tsx +204 -33
- package/src/components/boundary/README.md +249 -0
- package/src/components/boundary/index.ts +9 -2
- package/src/components/index.ts +9 -2
- package/src/components/select/combobox.tsx +47 -19
- package/src/hooks/audio/createSoundBus.ts +172 -0
- package/src/hooks/audio/index.ts +21 -0
- package/src/hooks/audio/useAudioPrefs.ts +91 -0
- package/src/hooks/audio/useNotificationSounds.ts +271 -0
- package/src/hooks/audio/useSoundEffect.ts +78 -0
- package/src/hooks/hotkey/formatHotkey.ts +96 -0
- package/src/hooks/hotkey/index.ts +10 -0
- package/src/hooks/hotkey/useHotkey.ts +106 -34
- package/src/hooks/hotkey/useHotkeyChord.ts +96 -0
- package/src/hooks/hotkey/useHotkeyHelp.ts +68 -0
- package/src/hooks/index.ts +1 -0
- package/src/components/boundary/boundary.story.tsx +0 -109
- package/src/components/data/avatar/avatar.story.tsx +0 -115
- package/src/components/data/badge/badge.story.tsx +0 -56
- package/src/components/data/calendar/calendar.story.tsx +0 -127
- package/src/components/data/carousel/carousel.story.tsx +0 -122
- package/src/components/data/progress/progress.story.tsx +0 -97
- package/src/components/data/table/table.story.tsx +0 -148
- package/src/components/data/toggle/toggle.story.tsx +0 -104
- package/src/components/data/toggle-group/toggle-group.story.tsx +0 -118
- package/src/components/feedback/alert/alert.story.tsx +0 -77
- package/src/components/feedback/empty/empty.story.tsx +0 -115
- package/src/components/feedback/preloader/preloader.story.tsx +0 -86
- package/src/components/feedback/spinner/spinner.story.tsx +0 -66
- package/src/components/forms/button/button.story.tsx +0 -116
- package/src/components/forms/button-download/button-download.story.tsx +0 -112
- package/src/components/forms/button-group/button-group.story.tsx +0 -79
- package/src/components/forms/checkbox/checkbox.story.tsx +0 -89
- package/src/components/forms/input/input.story.tsx +0 -77
- package/src/components/forms/input-group/input-group.story.tsx +0 -119
- package/src/components/forms/input-otp/input-otp.story.tsx +0 -105
- package/src/components/forms/label/label.story.tsx +0 -52
- package/src/components/forms/radio-group/radio-group.story.tsx +0 -113
- package/src/components/forms/slider/slider.story.tsx +0 -134
- package/src/components/forms/switch/switch.story.tsx +0 -98
- package/src/components/forms/textarea/textarea.story.tsx +0 -94
- package/src/components/layout/aspect-ratio/aspect-ratio.story.tsx +0 -94
- package/src/components/layout/card/card.story.tsx +0 -105
- package/src/components/layout/resizable/resizable.story.tsx +0 -119
- package/src/components/layout/scroll-area/scroll-area.story.tsx +0 -172
- package/src/components/layout/separator/separator.story.tsx +0 -69
- package/src/components/layout/skeleton/skeleton.story.tsx +0 -101
- package/src/components/navigation/accordion/accordion.story.tsx +0 -110
- package/src/components/navigation/collapsible/collapsible.story.tsx +0 -133
- package/src/components/navigation/command/command.story.tsx +0 -121
- package/src/components/navigation/context-menu/context-menu.story.tsx +0 -125
- package/src/components/navigation/dropdown-menu/dropdown-menu.story.tsx +0 -208
- package/src/components/navigation/menubar/menubar.story.tsx +0 -152
- package/src/components/navigation/navigation-menu/navigation-menu.story.tsx +0 -154
- package/src/components/navigation/tabs/tabs.story.tsx +0 -98
- package/src/components/overlay/alert-dialog/alert-dialog.story.tsx +0 -104
- package/src/components/overlay/dialog/dialog.story.tsx +0 -212
- package/src/components/overlay/drawer/drawer.story.tsx +0 -359
- package/src/components/overlay/hover-card/hover-card.story.tsx +0 -102
- package/src/components/overlay/popover/popover.story.tsx +0 -127
- package/src/components/overlay/responsive-sheet/responsive-sheet.story.tsx +0 -117
- package/src/components/overlay/sheet/sheet.story.tsx +0 -148
- package/src/components/overlay/tooltip/tooltip.story.tsx +0 -139
- package/src/components/select/combobox-async.story.tsx +0 -215
- package/src/components/select/combobox.story.tsx +0 -226
- package/src/components/select/country-select.story.tsx +0 -261
- package/src/components/select/language-select.story.tsx +0 -264
- package/src/components/select/multi-select.story.tsx +0 -122
- package/src/components/select/select.story.tsx +0 -112
- package/src/components/specialized/copy/copy.story.tsx +0 -77
- package/src/components/specialized/flag/flag.story.tsx +0 -82
- package/src/components/specialized/image-with-fallback/image-with-fallback.story.tsx +0 -105
- package/src/components/specialized/kbd/kbd.story.tsx +0 -113
- package/src/lib/dialog-service/dialog-service.story.tsx +0 -263
- package/src/stories/index.ts +0 -28
- package/src/styles/theme/theme-tokens.story.tsx +0 -157
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { defineStory } from '@djangocfg/playground';
|
|
2
|
-
import {
|
|
3
|
-
Empty,
|
|
4
|
-
EmptyHeader,
|
|
5
|
-
EmptyTitle,
|
|
6
|
-
EmptyDescription,
|
|
7
|
-
EmptyContent,
|
|
8
|
-
EmptyMedia,
|
|
9
|
-
} from '.';
|
|
10
|
-
import { Button } from '../../forms/button';
|
|
11
|
-
import { Inbox, Search, FileQuestion, Plus, RefreshCw } from 'lucide-react';
|
|
12
|
-
|
|
13
|
-
export default defineStory({
|
|
14
|
-
title: 'Core/Empty',
|
|
15
|
-
component: Empty,
|
|
16
|
-
description: 'Empty state placeholder for no content.',
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
export const Default = () => (
|
|
20
|
-
<Empty className="max-w-md mx-auto py-10">
|
|
21
|
-
<EmptyMedia>
|
|
22
|
-
<Inbox className="h-12 w-12 text-muted-foreground" />
|
|
23
|
-
</EmptyMedia>
|
|
24
|
-
<EmptyHeader>
|
|
25
|
-
<EmptyTitle>No items</EmptyTitle>
|
|
26
|
-
<EmptyDescription>
|
|
27
|
-
You don't have any items yet. Create your first one to get started.
|
|
28
|
-
</EmptyDescription>
|
|
29
|
-
</EmptyHeader>
|
|
30
|
-
<EmptyContent>
|
|
31
|
-
<Button>
|
|
32
|
-
<Plus className="mr-2 h-4 w-4" />
|
|
33
|
-
Create Item
|
|
34
|
-
</Button>
|
|
35
|
-
</EmptyContent>
|
|
36
|
-
</Empty>
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
export const SearchNoResults = () => (
|
|
40
|
-
<Empty className="max-w-md mx-auto py-10">
|
|
41
|
-
<EmptyMedia>
|
|
42
|
-
<Search className="h-12 w-12 text-muted-foreground" />
|
|
43
|
-
</EmptyMedia>
|
|
44
|
-
<EmptyHeader>
|
|
45
|
-
<EmptyTitle>No results found</EmptyTitle>
|
|
46
|
-
<EmptyDescription>
|
|
47
|
-
We couldn't find anything matching your search. Try adjusting your filters.
|
|
48
|
-
</EmptyDescription>
|
|
49
|
-
</EmptyHeader>
|
|
50
|
-
<EmptyContent>
|
|
51
|
-
<Button variant="outline">Clear filters</Button>
|
|
52
|
-
</EmptyContent>
|
|
53
|
-
</Empty>
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
export const Error = () => (
|
|
57
|
-
<Empty className="max-w-md mx-auto py-10">
|
|
58
|
-
<EmptyMedia>
|
|
59
|
-
<FileQuestion className="h-12 w-12 text-muted-foreground" />
|
|
60
|
-
</EmptyMedia>
|
|
61
|
-
<EmptyHeader>
|
|
62
|
-
<EmptyTitle>Something went wrong</EmptyTitle>
|
|
63
|
-
<EmptyDescription>
|
|
64
|
-
We encountered an error while loading the data. Please try again.
|
|
65
|
-
</EmptyDescription>
|
|
66
|
-
</EmptyHeader>
|
|
67
|
-
<EmptyContent>
|
|
68
|
-
<Button variant="outline">
|
|
69
|
-
<RefreshCw className="mr-2 h-4 w-4" />
|
|
70
|
-
Retry
|
|
71
|
-
</Button>
|
|
72
|
-
</EmptyContent>
|
|
73
|
-
</Empty>
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
export const NoNotifications = () => (
|
|
77
|
-
<Empty className="max-w-sm mx-auto py-8">
|
|
78
|
-
<EmptyMedia>
|
|
79
|
-
<Inbox className="h-10 w-10 text-muted-foreground" />
|
|
80
|
-
</EmptyMedia>
|
|
81
|
-
<EmptyHeader>
|
|
82
|
-
<EmptyTitle>All caught up!</EmptyTitle>
|
|
83
|
-
<EmptyDescription>
|
|
84
|
-
You have no new notifications.
|
|
85
|
-
</EmptyDescription>
|
|
86
|
-
</EmptyHeader>
|
|
87
|
-
</Empty>
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
export const Simple = () => (
|
|
91
|
-
<Empty className="max-w-xs mx-auto py-6">
|
|
92
|
-
<EmptyHeader>
|
|
93
|
-
<EmptyTitle>No data</EmptyTitle>
|
|
94
|
-
<EmptyDescription>
|
|
95
|
-
Start by adding some data.
|
|
96
|
-
</EmptyDescription>
|
|
97
|
-
</EmptyHeader>
|
|
98
|
-
</Empty>
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
export const InCard = () => (
|
|
102
|
-
<div className="rounded-lg border p-6">
|
|
103
|
-
<Empty>
|
|
104
|
-
<EmptyMedia>
|
|
105
|
-
<Inbox className="h-8 w-8 text-muted-foreground" />
|
|
106
|
-
</EmptyMedia>
|
|
107
|
-
<EmptyHeader>
|
|
108
|
-
<EmptyTitle className="text-base">Empty inbox</EmptyTitle>
|
|
109
|
-
<EmptyDescription className="text-sm">
|
|
110
|
-
No messages to display
|
|
111
|
-
</EmptyDescription>
|
|
112
|
-
</EmptyHeader>
|
|
113
|
-
</Empty>
|
|
114
|
-
</div>
|
|
115
|
-
);
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { defineStory, useSelect, useBoolean } from '@djangocfg/playground';
|
|
2
|
-
import { Preloader, PreloaderSkeleton } from '.';
|
|
3
|
-
|
|
4
|
-
export default defineStory({
|
|
5
|
-
title: 'Core/Preloader',
|
|
6
|
-
component: Preloader,
|
|
7
|
-
description: 'Loading indicators with multiple variants.',
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
export const Interactive = () => {
|
|
11
|
-
const [size] = useSelect('size', {
|
|
12
|
-
options: ['sm', 'md', 'lg', 'xl'] as const,
|
|
13
|
-
defaultValue: 'md',
|
|
14
|
-
label: 'Size',
|
|
15
|
-
description: 'Spinner size',
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
const [showText] = useBoolean('showText', {
|
|
19
|
-
defaultValue: true,
|
|
20
|
-
label: 'Show Text',
|
|
21
|
-
description: 'Display loading text',
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<Preloader
|
|
26
|
-
size={size}
|
|
27
|
-
text={showText ? 'Loading...' : undefined}
|
|
28
|
-
/>
|
|
29
|
-
);
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const Default = () => <Preloader />;
|
|
33
|
-
|
|
34
|
-
export const WithText = () => <Preloader text="Loading data..." />;
|
|
35
|
-
|
|
36
|
-
export const WithDescription = () => (
|
|
37
|
-
<Preloader
|
|
38
|
-
text="Processing"
|
|
39
|
-
description="Please wait while we process your request"
|
|
40
|
-
/>
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
export const Sizes = () => (
|
|
44
|
-
<div className="flex items-center gap-8">
|
|
45
|
-
<div className="flex flex-col items-center gap-2">
|
|
46
|
-
<Preloader size="sm" />
|
|
47
|
-
<span className="text-xs text-muted-foreground">sm</span>
|
|
48
|
-
</div>
|
|
49
|
-
<div className="flex flex-col items-center gap-2">
|
|
50
|
-
<Preloader size="md" />
|
|
51
|
-
<span className="text-xs text-muted-foreground">md</span>
|
|
52
|
-
</div>
|
|
53
|
-
<div className="flex flex-col items-center gap-2">
|
|
54
|
-
<Preloader size="lg" />
|
|
55
|
-
<span className="text-xs text-muted-foreground">lg</span>
|
|
56
|
-
</div>
|
|
57
|
-
<div className="flex flex-col items-center gap-2">
|
|
58
|
-
<Preloader size="xl" />
|
|
59
|
-
<span className="text-xs text-muted-foreground">xl</span>
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
export const InCard = () => (
|
|
65
|
-
<div className="rounded-lg border p-8">
|
|
66
|
-
<Preloader text="Loading content..." size="lg" />
|
|
67
|
-
</div>
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
export const SkeletonDefault = () => <PreloaderSkeleton />;
|
|
71
|
-
|
|
72
|
-
export const SkeletonWithAvatar = () => <PreloaderSkeleton showAvatar />;
|
|
73
|
-
|
|
74
|
-
export const SkeletonLines = () => (
|
|
75
|
-
<div className="max-w-md space-y-6">
|
|
76
|
-
<PreloaderSkeleton lines={2} />
|
|
77
|
-
<PreloaderSkeleton lines={4} />
|
|
78
|
-
<PreloaderSkeleton lines={1} />
|
|
79
|
-
</div>
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
export const SkeletonCard = () => (
|
|
83
|
-
<div className="max-w-sm rounded-lg border p-4">
|
|
84
|
-
<PreloaderSkeleton showAvatar lines={2} />
|
|
85
|
-
</div>
|
|
86
|
-
);
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { defineStory, useSelect } from '@djangocfg/playground';
|
|
2
|
-
import { Spinner } from '.';
|
|
3
|
-
|
|
4
|
-
export default defineStory({
|
|
5
|
-
title: 'Core/Spinner',
|
|
6
|
-
component: Spinner,
|
|
7
|
-
description: 'Loading spinner indicator.',
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
export const Interactive = () => {
|
|
11
|
-
const [size] = useSelect('size', {
|
|
12
|
-
options: ['sm', 'md', 'lg'] as const,
|
|
13
|
-
defaultValue: 'md',
|
|
14
|
-
label: 'Size',
|
|
15
|
-
description: 'Spinner size',
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
const sizeClasses = {
|
|
19
|
-
sm: 'h-4 w-4',
|
|
20
|
-
md: 'h-6 w-6',
|
|
21
|
-
lg: 'h-10 w-10',
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
return <Spinner className={sizeClasses[size]} />;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const Default = () => <Spinner />;
|
|
28
|
-
|
|
29
|
-
export const Sizes = () => (
|
|
30
|
-
<div className="flex items-center gap-4">
|
|
31
|
-
<Spinner className="h-4 w-4" />
|
|
32
|
-
<Spinner className="h-6 w-6" />
|
|
33
|
-
<Spinner className="h-8 w-8" />
|
|
34
|
-
<Spinner className="h-10 w-10" />
|
|
35
|
-
<Spinner className="h-12 w-12" />
|
|
36
|
-
</div>
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
export const InButton = () => (
|
|
40
|
-
<button className="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-primary text-primary-foreground">
|
|
41
|
-
<Spinner className="h-4 w-4" />
|
|
42
|
-
Loading...
|
|
43
|
-
</button>
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
export const Centered = () => (
|
|
47
|
-
<div className="flex items-center justify-center h-40 border rounded-lg">
|
|
48
|
-
<Spinner className="h-8 w-8" />
|
|
49
|
-
</div>
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
export const WithText = () => (
|
|
53
|
-
<div className="flex flex-col items-center gap-2">
|
|
54
|
-
<Spinner className="h-8 w-8" />
|
|
55
|
-
<span className="text-sm text-muted-foreground">Loading data...</span>
|
|
56
|
-
</div>
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
export const FullPage = () => (
|
|
60
|
-
<div className="fixed inset-0 flex items-center justify-center bg-background/80 backdrop-blur-sm">
|
|
61
|
-
<div className="flex flex-col items-center gap-2">
|
|
62
|
-
<Spinner className="h-10 w-10" />
|
|
63
|
-
<span className="text-sm">Please wait...</span>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
);
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { defineStory, useSelect, useBoolean } from '@djangocfg/playground';
|
|
2
|
-
import { Mail, Send, Loader2, ChevronRight, Plus, Trash2 } from 'lucide-react';
|
|
3
|
-
import { Button, ButtonLink } from '.';
|
|
4
|
-
|
|
5
|
-
export default defineStory({
|
|
6
|
-
title: 'Core/Button',
|
|
7
|
-
component: Button,
|
|
8
|
-
description: 'Versatile button component with multiple variants and sizes.',
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
export const Interactive = () => {
|
|
12
|
-
const [variant] = useSelect('variant', {
|
|
13
|
-
options: ['default', 'secondary', 'destructive', 'outline', 'ghost', 'link'] as const,
|
|
14
|
-
defaultValue: 'default',
|
|
15
|
-
label: 'Variant',
|
|
16
|
-
description: 'Button style variant',
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const [size] = useSelect('size', {
|
|
20
|
-
options: ['xs', 'sm', 'default', 'lg', 'huge', 'icon'] as const,
|
|
21
|
-
defaultValue: 'default',
|
|
22
|
-
label: 'Size',
|
|
23
|
-
description: 'Button size',
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
const [loading] = useBoolean('loading', {
|
|
27
|
-
defaultValue: false,
|
|
28
|
-
label: 'Loading',
|
|
29
|
-
description: 'Show loading spinner',
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const [disabled] = useBoolean('disabled', {
|
|
33
|
-
defaultValue: false,
|
|
34
|
-
label: 'Disabled',
|
|
35
|
-
description: 'Disable button',
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<div className="flex flex-wrap gap-4 items-center">
|
|
40
|
-
<Button variant={variant} size={size} loading={loading} disabled={disabled}>
|
|
41
|
-
{size === 'icon' ? <Plus /> : 'Button'}
|
|
42
|
-
</Button>
|
|
43
|
-
<Button variant={variant} size={size} loading={loading} disabled={disabled}>
|
|
44
|
-
<Mail />
|
|
45
|
-
{size !== 'icon' && 'With Icon'}
|
|
46
|
-
</Button>
|
|
47
|
-
</div>
|
|
48
|
-
);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export const Variants = () => (
|
|
52
|
-
<div className="flex flex-wrap gap-4">
|
|
53
|
-
<Button variant="default">Default</Button>
|
|
54
|
-
<Button variant="secondary">Secondary</Button>
|
|
55
|
-
<Button variant="destructive">Destructive</Button>
|
|
56
|
-
<Button variant="outline">Outline</Button>
|
|
57
|
-
<Button variant="ghost">Ghost</Button>
|
|
58
|
-
<Button variant="link">Link</Button>
|
|
59
|
-
</div>
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
export const Sizes = () => (
|
|
63
|
-
<div className="flex flex-wrap gap-4 items-center">
|
|
64
|
-
<Button size="xs">Extra Small</Button>
|
|
65
|
-
<Button size="sm">Small</Button>
|
|
66
|
-
<Button size="default">Default</Button>
|
|
67
|
-
<Button size="lg">Large</Button>
|
|
68
|
-
<Button size="huge">Huge</Button>
|
|
69
|
-
<Button size="icon"><Plus /></Button>
|
|
70
|
-
</div>
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
export const WithIcons = () => (
|
|
74
|
-
<div className="flex flex-wrap gap-4">
|
|
75
|
-
<Button>
|
|
76
|
-
<Mail />
|
|
77
|
-
Login with Email
|
|
78
|
-
</Button>
|
|
79
|
-
<Button variant="secondary">
|
|
80
|
-
Send
|
|
81
|
-
<Send />
|
|
82
|
-
</Button>
|
|
83
|
-
<Button variant="outline">
|
|
84
|
-
Next
|
|
85
|
-
<ChevronRight />
|
|
86
|
-
</Button>
|
|
87
|
-
<Button variant="destructive">
|
|
88
|
-
<Trash2 />
|
|
89
|
-
Delete
|
|
90
|
-
</Button>
|
|
91
|
-
</div>
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
export const Loading = () => (
|
|
95
|
-
<div className="flex flex-wrap gap-4">
|
|
96
|
-
<Button loading>Loading...</Button>
|
|
97
|
-
<Button loading variant="secondary">Processing</Button>
|
|
98
|
-
<Button loading variant="outline">Please wait</Button>
|
|
99
|
-
</div>
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
export const Disabled = () => (
|
|
103
|
-
<div className="flex flex-wrap gap-4">
|
|
104
|
-
<Button disabled>Default</Button>
|
|
105
|
-
<Button disabled variant="secondary">Secondary</Button>
|
|
106
|
-
<Button disabled variant="outline">Outline</Button>
|
|
107
|
-
</div>
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
export const AsLink = () => (
|
|
111
|
-
<div className="flex flex-wrap gap-4">
|
|
112
|
-
<ButtonLink href="https://example.com">External Link</ButtonLink>
|
|
113
|
-
<ButtonLink href="/dashboard" variant="secondary">Dashboard</ButtonLink>
|
|
114
|
-
<ButtonLink href="/settings" variant="outline">Settings</ButtonLink>
|
|
115
|
-
</div>
|
|
116
|
-
);
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { defineStory, useBoolean } from '@djangocfg/playground';
|
|
2
|
-
import { DownloadButton } from '.';
|
|
3
|
-
|
|
4
|
-
export default defineStory({
|
|
5
|
-
title: 'Core/DownloadButton',
|
|
6
|
-
component: DownloadButton,
|
|
7
|
-
description: 'Button with download functionality and status indicators.',
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
export const Interactive = () => {
|
|
11
|
-
const [showStatus] = useBoolean('showStatus', {
|
|
12
|
-
defaultValue: true,
|
|
13
|
-
label: 'Show Status',
|
|
14
|
-
description: 'Show loading/success/error icons',
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<DownloadButton
|
|
19
|
-
url="https://example.com/file.pdf"
|
|
20
|
-
filename="document.pdf"
|
|
21
|
-
showStatus={showStatus}
|
|
22
|
-
>
|
|
23
|
-
Download PDF
|
|
24
|
-
</DownloadButton>
|
|
25
|
-
);
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export const Default = () => (
|
|
29
|
-
<DownloadButton
|
|
30
|
-
url="https://example.com/file.pdf"
|
|
31
|
-
filename="document.pdf"
|
|
32
|
-
>
|
|
33
|
-
Download File
|
|
34
|
-
</DownloadButton>
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
export const IconOnly = () => (
|
|
38
|
-
<DownloadButton
|
|
39
|
-
url="https://example.com/file.pdf"
|
|
40
|
-
filename="document.pdf"
|
|
41
|
-
size="icon"
|
|
42
|
-
/>
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
export const Variants = () => (
|
|
46
|
-
<div className="flex gap-4">
|
|
47
|
-
<DownloadButton
|
|
48
|
-
url="https://example.com/file.pdf"
|
|
49
|
-
variant="default"
|
|
50
|
-
>
|
|
51
|
-
Default
|
|
52
|
-
</DownloadButton>
|
|
53
|
-
<DownloadButton
|
|
54
|
-
url="https://example.com/file.pdf"
|
|
55
|
-
variant="outline"
|
|
56
|
-
>
|
|
57
|
-
Outline
|
|
58
|
-
</DownloadButton>
|
|
59
|
-
<DownloadButton
|
|
60
|
-
url="https://example.com/file.pdf"
|
|
61
|
-
variant="ghost"
|
|
62
|
-
>
|
|
63
|
-
Ghost
|
|
64
|
-
</DownloadButton>
|
|
65
|
-
</div>
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
export const Sizes = () => (
|
|
69
|
-
<div className="flex items-center gap-4">
|
|
70
|
-
<DownloadButton url="https://example.com/file.pdf" size="sm">
|
|
71
|
-
Small
|
|
72
|
-
</DownloadButton>
|
|
73
|
-
<DownloadButton url="https://example.com/file.pdf" size="default">
|
|
74
|
-
Default
|
|
75
|
-
</DownloadButton>
|
|
76
|
-
<DownloadButton url="https://example.com/file.pdf" size="lg">
|
|
77
|
-
Large
|
|
78
|
-
</DownloadButton>
|
|
79
|
-
</div>
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
export const WithCallbacks = () => (
|
|
83
|
-
<DownloadButton
|
|
84
|
-
url="https://example.com/file.pdf"
|
|
85
|
-
filename="report.pdf"
|
|
86
|
-
onDownloadStart={() => console.log('Download started')}
|
|
87
|
-
onDownloadComplete={(name) => console.log(`Downloaded: ${name}`)}
|
|
88
|
-
onDownloadError={(err) => console.error('Error:', err)}
|
|
89
|
-
>
|
|
90
|
-
Download with Callbacks
|
|
91
|
-
</DownloadButton>
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
export const PostRequest = () => (
|
|
95
|
-
<DownloadButton
|
|
96
|
-
url="https://api.example.com/export"
|
|
97
|
-
method="POST"
|
|
98
|
-
body={{ format: 'pdf', includeImages: true }}
|
|
99
|
-
filename="export.pdf"
|
|
100
|
-
>
|
|
101
|
-
Export as PDF
|
|
102
|
-
</DownloadButton>
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
export const DisabledStatus = () => (
|
|
106
|
-
<DownloadButton
|
|
107
|
-
url="https://example.com/file.pdf"
|
|
108
|
-
showStatus={false}
|
|
109
|
-
>
|
|
110
|
-
No Status Icons
|
|
111
|
-
</DownloadButton>
|
|
112
|
-
);
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { defineStory } from '@djangocfg/playground';
|
|
2
|
-
import { ButtonGroup, ButtonGroupSeparator, ButtonGroupText } from '.';
|
|
3
|
-
import { Button } from '../../forms/button';
|
|
4
|
-
import { Bold, Italic, Underline, AlignLeft, AlignCenter, AlignRight, ChevronDown } from 'lucide-react';
|
|
5
|
-
|
|
6
|
-
export default defineStory({
|
|
7
|
-
title: 'Core/ButtonGroup',
|
|
8
|
-
component: ButtonGroup,
|
|
9
|
-
description: 'Group of buttons with connected styling.',
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
export const Default = () => (
|
|
13
|
-
<ButtonGroup>
|
|
14
|
-
<Button variant="outline">First</Button>
|
|
15
|
-
<Button variant="outline">Second</Button>
|
|
16
|
-
<Button variant="outline">Third</Button>
|
|
17
|
-
</ButtonGroup>
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
export const TextFormatting = () => (
|
|
21
|
-
<ButtonGroup>
|
|
22
|
-
<Button variant="outline" size="icon">
|
|
23
|
-
<Bold className="h-4 w-4" />
|
|
24
|
-
</Button>
|
|
25
|
-
<Button variant="outline" size="icon">
|
|
26
|
-
<Italic className="h-4 w-4" />
|
|
27
|
-
</Button>
|
|
28
|
-
<Button variant="outline" size="icon">
|
|
29
|
-
<Underline className="h-4 w-4" />
|
|
30
|
-
</Button>
|
|
31
|
-
</ButtonGroup>
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
export const Alignment = () => (
|
|
35
|
-
<ButtonGroup>
|
|
36
|
-
<Button variant="outline" size="icon">
|
|
37
|
-
<AlignLeft className="h-4 w-4" />
|
|
38
|
-
</Button>
|
|
39
|
-
<Button variant="outline" size="icon">
|
|
40
|
-
<AlignCenter className="h-4 w-4" />
|
|
41
|
-
</Button>
|
|
42
|
-
<Button variant="outline" size="icon">
|
|
43
|
-
<AlignRight className="h-4 w-4" />
|
|
44
|
-
</Button>
|
|
45
|
-
</ButtonGroup>
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
export const WithSeparator = () => (
|
|
49
|
-
<ButtonGroup>
|
|
50
|
-
<Button variant="outline">Edit</Button>
|
|
51
|
-
<ButtonGroupSeparator />
|
|
52
|
-
<Button variant="outline" size="icon">
|
|
53
|
-
<ChevronDown className="h-4 w-4" />
|
|
54
|
-
</Button>
|
|
55
|
-
</ButtonGroup>
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
export const WithText = () => (
|
|
59
|
-
<ButtonGroup>
|
|
60
|
-
<ButtonGroupText>Label</ButtonGroupText>
|
|
61
|
-
<Button variant="outline">Action</Button>
|
|
62
|
-
</ButtonGroup>
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
export const Vertical = () => (
|
|
66
|
-
<ButtonGroup orientation="vertical">
|
|
67
|
-
<Button variant="outline">Top</Button>
|
|
68
|
-
<Button variant="outline">Middle</Button>
|
|
69
|
-
<Button variant="outline">Bottom</Button>
|
|
70
|
-
</ButtonGroup>
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
export const Mixed = () => (
|
|
74
|
-
<ButtonGroup>
|
|
75
|
-
<Button variant="default">Primary</Button>
|
|
76
|
-
<Button variant="outline">Secondary</Button>
|
|
77
|
-
<Button variant="ghost">Tertiary</Button>
|
|
78
|
-
</ButtonGroup>
|
|
79
|
-
);
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
|
-
import { defineStory, useBoolean } from '@djangocfg/playground';
|
|
3
|
-
import { Checkbox } from '.';
|
|
4
|
-
import { Label } from '../../forms/label';
|
|
5
|
-
|
|
6
|
-
export default defineStory({
|
|
7
|
-
title: 'Core/Checkbox',
|
|
8
|
-
component: Checkbox,
|
|
9
|
-
description: 'Checkbox input for boolean selections.',
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
export const Interactive = () => {
|
|
13
|
-
const [disabled] = useBoolean('disabled', {
|
|
14
|
-
defaultValue: false,
|
|
15
|
-
label: 'Disabled',
|
|
16
|
-
description: 'Disable checkbox',
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<div className="flex items-center space-x-2">
|
|
21
|
-
<Checkbox id="terms" disabled={disabled} />
|
|
22
|
-
<Label htmlFor="terms">Accept terms and conditions</Label>
|
|
23
|
-
</div>
|
|
24
|
-
);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const Default = () => (
|
|
28
|
-
<div className="flex items-center space-x-2">
|
|
29
|
-
<Checkbox id="default" />
|
|
30
|
-
<Label htmlFor="default">Default checkbox</Label>
|
|
31
|
-
</div>
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
export const Checked = () => (
|
|
35
|
-
<div className="flex items-center space-x-2">
|
|
36
|
-
<Checkbox id="checked" defaultChecked />
|
|
37
|
-
<Label htmlFor="checked">Checked by default</Label>
|
|
38
|
-
</div>
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
export const Disabled = () => (
|
|
42
|
-
<div className="space-y-4">
|
|
43
|
-
<div className="flex items-center space-x-2">
|
|
44
|
-
<Checkbox id="disabled-unchecked" disabled />
|
|
45
|
-
<Label htmlFor="disabled-unchecked">Disabled unchecked</Label>
|
|
46
|
-
</div>
|
|
47
|
-
<div className="flex items-center space-x-2">
|
|
48
|
-
<Checkbox id="disabled-checked" disabled defaultChecked />
|
|
49
|
-
<Label htmlFor="disabled-checked">Disabled checked</Label>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
export const WithForm = () => {
|
|
55
|
-
const [items, setItems] = useState({
|
|
56
|
-
notifications: true,
|
|
57
|
-
marketing: false,
|
|
58
|
-
updates: true,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<div className="space-y-4">
|
|
63
|
-
<div className="flex items-center space-x-2">
|
|
64
|
-
<Checkbox
|
|
65
|
-
id="notifications"
|
|
66
|
-
checked={items.notifications}
|
|
67
|
-
onCheckedChange={(checked) => setItems({ ...items, notifications: !!checked })}
|
|
68
|
-
/>
|
|
69
|
-
<Label htmlFor="notifications">Receive notifications</Label>
|
|
70
|
-
</div>
|
|
71
|
-
<div className="flex items-center space-x-2">
|
|
72
|
-
<Checkbox
|
|
73
|
-
id="marketing"
|
|
74
|
-
checked={items.marketing}
|
|
75
|
-
onCheckedChange={(checked) => setItems({ ...items, marketing: !!checked })}
|
|
76
|
-
/>
|
|
77
|
-
<Label htmlFor="marketing">Receive marketing emails</Label>
|
|
78
|
-
</div>
|
|
79
|
-
<div className="flex items-center space-x-2">
|
|
80
|
-
<Checkbox
|
|
81
|
-
id="updates"
|
|
82
|
-
checked={items.updates}
|
|
83
|
-
onCheckedChange={(checked) => setItems({ ...items, updates: !!checked })}
|
|
84
|
-
/>
|
|
85
|
-
<Label htmlFor="updates">Receive product updates</Label>
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|
|
88
|
-
);
|
|
89
|
-
};
|