@djangocfg/ui-tools 2.1.382 → 2.1.384
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/dist/ChatRoot-JVR3M3H2.mjs +5 -0
- package/dist/{ChatRoot-6IZFM5HM.mjs.map → ChatRoot-JVR3M3H2.mjs.map} +1 -1
- package/dist/ChatRoot-LXIUBOXF.cjs +14 -0
- package/dist/{ChatRoot-LW4XNIKP.cjs.map → ChatRoot-LXIUBOXF.cjs.map} +1 -1
- package/dist/DictationField-U25MEYAL.mjs +4 -0
- package/dist/{DictationField-2ZLQWLYV.mjs.map → DictationField-U25MEYAL.mjs.map} +1 -1
- package/dist/DictationField-XWR5VOID.cjs +13 -0
- package/dist/{DictationField-IPPJ54CU.cjs.map → DictationField-XWR5VOID.cjs.map} +1 -1
- package/dist/{chunk-KMSBGNVC.cjs → chunk-4PFW7MIJ.cjs} +4 -2
- package/dist/chunk-4PFW7MIJ.cjs.map +1 -0
- package/dist/{chunk-4LXG3NBV.mjs → chunk-C2YN6WEO.mjs} +3 -3
- package/dist/chunk-C2YN6WEO.mjs.map +1 -0
- package/dist/{chunk-OZAU3QWD.cjs → chunk-HPK3EWBF.cjs} +8 -8
- package/dist/chunk-HPK3EWBF.cjs.map +1 -0
- package/dist/{chunk-UWVP6LCW.mjs → chunk-PEKBT75W.mjs} +8 -8
- package/dist/chunk-PEKBT75W.mjs.map +1 -0
- package/dist/index.cjs +192 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +78 -6
- package/dist/index.d.ts +78 -6
- package/dist/index.mjs +143 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -13
- package/src/tools/Chat/core/audio/defaults.ts +16 -11
- package/src/tools/Chat/core/audio/sounds/error.ts +3 -0
- package/src/tools/Chat/core/audio/sounds/mention.ts +3 -0
- package/src/tools/Chat/core/audio/sounds/notification.ts +3 -0
- package/src/tools/Chat/core/audio/sounds/received.ts +3 -0
- package/src/tools/Chat/core/audio/sounds/sent.ts +3 -0
- package/src/tools/Chat/core/audio/sounds/start.ts +3 -0
- package/src/tools/Chat/index.ts +15 -0
- package/src/tools/SpeechRecognition/core/audio/defaults.ts +4 -4
- package/dist/ChatRoot-6IZFM5HM.mjs +0 -5
- package/dist/ChatRoot-LW4XNIKP.cjs +0 -14
- package/dist/DictationField-2ZLQWLYV.mjs +0 -4
- package/dist/DictationField-IPPJ54CU.cjs +0 -13
- package/dist/chunk-4LXG3NBV.mjs.map +0 -1
- package/dist/chunk-KMSBGNVC.cjs.map +0 -1
- package/dist/chunk-OZAU3QWD.cjs.map +0 -1
- package/dist/chunk-UWVP6LCW.mjs.map +0 -1
- package/src/audio-assets.d.ts +0 -8
- package/src/components/markdown/MarkdownMessage/MarkdownMessage.story.tsx +0 -771
- package/src/stories/index.ts +0 -63
- package/src/tools/AudioPlayer/AudioPlayer.story.tsx +0 -481
- package/src/tools/Chat/core/audio/sounds/error.mp3 +0 -0
- package/src/tools/Chat/core/audio/sounds/mention.mp3 +0 -0
- package/src/tools/Chat/core/audio/sounds/notification.mp3 +0 -0
- package/src/tools/Chat/core/audio/sounds/received.mp3 +0 -0
- package/src/tools/Chat/core/audio/sounds/sent.mp3 +0 -0
- package/src/tools/Chat/core/audio/sounds/start.mp3 +0 -0
- package/src/tools/Chat/stories/01-basic.story.tsx +0 -64
- package/src/tools/Chat/stories/02-bubbles.story.tsx +0 -21
- package/src/tools/Chat/stories/03-tool-calls.story.tsx +0 -59
- package/src/tools/Chat/stories/04-personas.story.tsx +0 -78
- package/src/tools/Chat/stories/05-launcher.story.tsx +0 -321
- package/src/tools/Chat/stories/06-header.story.tsx +0 -147
- package/src/tools/Chat/stories/07-audio-actions.story.tsx +0 -112
- package/src/tools/Chat/stories/shared/Frame.tsx +0 -21
- package/src/tools/Chat/stories/shared/index.ts +0 -5
- package/src/tools/Chat/stories/shared/messages.ts +0 -39
- package/src/tools/Chat/stories/shared/personas.ts +0 -13
- package/src/tools/Chat/stories/shared/seeds.ts +0 -92
- package/src/tools/Chat/stories/shared/transports.ts +0 -36
- package/src/tools/CodeEditor/CodeEditor.story.tsx +0 -202
- package/src/tools/CronScheduler/CronScheduler.story.tsx +0 -300
- package/src/tools/Gallery/Gallery.story.tsx +0 -237
- package/src/tools/ImageViewer/ImageViewer.story.tsx +0 -85
- package/src/tools/JsonForm/JsonForm.story.tsx +0 -350
- package/src/tools/JsonTree/JsonTree.story.tsx +0 -141
- package/src/tools/LottiePlayer/LottiePlayer.story.tsx +0 -95
- package/src/tools/Map/Map.story.tsx +0 -458
- package/src/tools/MarkdownEditor/MarkdownEditor.story.tsx +0 -225
- package/src/tools/Mermaid/Mermaid.story.tsx +0 -251
- package/src/tools/OpenapiViewer/OpenapiViewer.story.tsx +0 -230
- package/src/tools/PrettyCode/PrettyCode.story.tsx +0 -304
- package/src/tools/SpeechRecognition/stories/01-basic.story.tsx +0 -32
- package/src/tools/SpeechRecognition/stories/02-dictation-field.story.tsx +0 -32
- package/src/tools/SpeechRecognition/stories/03-push-to-talk.story.tsx +0 -27
- package/src/tools/SpeechRecognition/stories/04-mic-meter.story.tsx +0 -35
- package/src/tools/SpeechRecognition/stories/05-custom-engine-http.story.tsx +0 -40
- package/src/tools/SpeechRecognition/stories/06-custom-engine-ws.story.tsx +0 -48
- package/src/tools/SpeechRecognition/stories/07-language-device.story.tsx +0 -57
- package/src/tools/SpeechRecognition/stories/08-errors-permissions.story.tsx +0 -25
- package/src/tools/SpeechRecognition/stories/09-chat-voice.story.tsx +0 -90
- package/src/tools/SpeechRecognition/stories/shared.tsx +0 -123
- package/src/tools/Tour/Tour.story.tsx +0 -279
- package/src/tools/Tree/Tree.story.tsx +0 -620
- package/src/tools/Uploader/Uploader.story.tsx +0 -415
- package/src/tools/VideoPlayer/VideoPlayer.story.tsx +0 -87
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
|
-
import { defineStory, useBoolean, useSelect } from '@djangocfg/playground';
|
|
3
|
-
import {
|
|
4
|
-
Dialog,
|
|
5
|
-
DialogContent,
|
|
6
|
-
DialogDescription,
|
|
7
|
-
DialogHeader,
|
|
8
|
-
DialogTitle,
|
|
9
|
-
DialogTrigger,
|
|
10
|
-
} from '@djangocfg/ui-core/components';
|
|
11
|
-
import { CronScheduler } from './index';
|
|
12
|
-
|
|
13
|
-
export default defineStory({
|
|
14
|
-
title: 'Tools/Cron Scheduler',
|
|
15
|
-
component: CronScheduler,
|
|
16
|
-
description: 'Compact cron expression builder with Apple HIG-style UI.',
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
export const Interactive = () => {
|
|
20
|
-
const [cron, setCron] = useState('0 9 * * 1-5');
|
|
21
|
-
|
|
22
|
-
const [defaultType] = useSelect('defaultType', {
|
|
23
|
-
options: ['daily', 'weekly', 'monthly', 'custom'] as const,
|
|
24
|
-
defaultValue: 'weekly',
|
|
25
|
-
label: 'Default Type',
|
|
26
|
-
description: 'Initial schedule type',
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
const [showPreview] = useBoolean('showPreview', {
|
|
30
|
-
defaultValue: true,
|
|
31
|
-
label: 'Show Preview',
|
|
32
|
-
description: 'Show human-readable preview',
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const [showCronExpression] = useBoolean('showCronExpression', {
|
|
36
|
-
defaultValue: true,
|
|
37
|
-
label: 'Show Cron Expression',
|
|
38
|
-
description: 'Show raw cron expression in preview',
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const [allowCopy] = useBoolean('allowCopy', {
|
|
42
|
-
defaultValue: true,
|
|
43
|
-
label: 'Allow Copy',
|
|
44
|
-
description: 'Enable copy to clipboard',
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
const [timeFormat] = useSelect('timeFormat', {
|
|
48
|
-
options: ['24h', '12h'] as const,
|
|
49
|
-
defaultValue: '24h',
|
|
50
|
-
label: 'Time Format',
|
|
51
|
-
description: 'Time display format',
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
const [disabled] = useBoolean('disabled', {
|
|
55
|
-
defaultValue: false,
|
|
56
|
-
label: 'Disabled',
|
|
57
|
-
description: 'Disable all interactions',
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
return (
|
|
61
|
-
<div className="w-[400px]">
|
|
62
|
-
<CronScheduler
|
|
63
|
-
value={cron}
|
|
64
|
-
onChange={setCron}
|
|
65
|
-
defaultType={defaultType}
|
|
66
|
-
showPreview={showPreview}
|
|
67
|
-
showCronExpression={showCronExpression}
|
|
68
|
-
allowCopy={allowCopy}
|
|
69
|
-
timeFormat={timeFormat}
|
|
70
|
-
disabled={disabled}
|
|
71
|
-
/>
|
|
72
|
-
</div>
|
|
73
|
-
);
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
export const Daily = () => {
|
|
77
|
-
const [cron, setCron] = useState('0 9 * * *');
|
|
78
|
-
|
|
79
|
-
return (
|
|
80
|
-
<div className="w-[400px]">
|
|
81
|
-
<CronScheduler
|
|
82
|
-
value={cron}
|
|
83
|
-
onChange={setCron}
|
|
84
|
-
defaultType="daily"
|
|
85
|
-
showPreview
|
|
86
|
-
/>
|
|
87
|
-
</div>
|
|
88
|
-
);
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
export const Weekly = () => {
|
|
92
|
-
const [cron, setCron] = useState('30 14 * * 1,3,5');
|
|
93
|
-
|
|
94
|
-
return (
|
|
95
|
-
<div className="w-[400px]">
|
|
96
|
-
<CronScheduler
|
|
97
|
-
value={cron}
|
|
98
|
-
onChange={setCron}
|
|
99
|
-
defaultType="weekly"
|
|
100
|
-
showPreview
|
|
101
|
-
/>
|
|
102
|
-
</div>
|
|
103
|
-
);
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
export const Monthly = () => {
|
|
107
|
-
const [cron, setCron] = useState('0 9 1,15 * *');
|
|
108
|
-
|
|
109
|
-
return (
|
|
110
|
-
<div className="w-[400px]">
|
|
111
|
-
<CronScheduler
|
|
112
|
-
value={cron}
|
|
113
|
-
onChange={setCron}
|
|
114
|
-
defaultType="monthly"
|
|
115
|
-
showPreview
|
|
116
|
-
/>
|
|
117
|
-
</div>
|
|
118
|
-
);
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
export const Custom = () => {
|
|
122
|
-
const [cron, setCron] = useState('*/15 9-17 * * 1-5');
|
|
123
|
-
|
|
124
|
-
return (
|
|
125
|
-
<div className="w-[400px]">
|
|
126
|
-
<CronScheduler
|
|
127
|
-
value={cron}
|
|
128
|
-
onChange={setCron}
|
|
129
|
-
defaultType="custom"
|
|
130
|
-
showPreview
|
|
131
|
-
showCronExpression
|
|
132
|
-
/>
|
|
133
|
-
</div>
|
|
134
|
-
);
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
export const WithCronExpression = () => {
|
|
138
|
-
const [cron, setCron] = useState('0 9 * * 1-5');
|
|
139
|
-
|
|
140
|
-
return (
|
|
141
|
-
<div className="w-[400px]">
|
|
142
|
-
<CronScheduler
|
|
143
|
-
value={cron}
|
|
144
|
-
onChange={setCron}
|
|
145
|
-
showPreview
|
|
146
|
-
showCronExpression
|
|
147
|
-
allowCopy
|
|
148
|
-
/>
|
|
149
|
-
</div>
|
|
150
|
-
);
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
export const TwelveHourFormat = () => {
|
|
154
|
-
const [cron, setCron] = useState('0 14 * * *');
|
|
155
|
-
|
|
156
|
-
return (
|
|
157
|
-
<div className="w-[400px]">
|
|
158
|
-
<CronScheduler
|
|
159
|
-
value={cron}
|
|
160
|
-
onChange={setCron}
|
|
161
|
-
showPreview
|
|
162
|
-
timeFormat="12h"
|
|
163
|
-
/>
|
|
164
|
-
</div>
|
|
165
|
-
);
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
export const Disabled = () => (
|
|
169
|
-
<div className="w-[400px]">
|
|
170
|
-
<CronScheduler
|
|
171
|
-
value="0 9 * * 1-5"
|
|
172
|
-
showPreview
|
|
173
|
-
disabled
|
|
174
|
-
/>
|
|
175
|
-
</div>
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
export const Compact = () => {
|
|
179
|
-
const [cron, setCron] = useState('0 9 * * 1-5');
|
|
180
|
-
|
|
181
|
-
return (
|
|
182
|
-
<div className="w-[400px]">
|
|
183
|
-
<CronScheduler
|
|
184
|
-
value={cron}
|
|
185
|
-
onChange={setCron}
|
|
186
|
-
defaultType="weekly"
|
|
187
|
-
showPreview={false}
|
|
188
|
-
/>
|
|
189
|
-
</div>
|
|
190
|
-
);
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
export const Controlled = () => {
|
|
194
|
-
const [cron, setCron] = useState('0 9 * * *');
|
|
195
|
-
|
|
196
|
-
const presets = [
|
|
197
|
-
{ label: 'Every day at 9am', value: '0 9 * * *' },
|
|
198
|
-
{ label: 'Weekdays at 6pm', value: '0 18 * * 1-5' },
|
|
199
|
-
{ label: 'Every Monday', value: '0 0 * * 1' },
|
|
200
|
-
{ label: '1st of month', value: '0 0 1 * *' },
|
|
201
|
-
];
|
|
202
|
-
|
|
203
|
-
return (
|
|
204
|
-
<div className="w-[400px] space-y-4">
|
|
205
|
-
<div className="flex flex-wrap gap-2">
|
|
206
|
-
{presets.map(({ label, value }) => (
|
|
207
|
-
<button
|
|
208
|
-
key={value}
|
|
209
|
-
onClick={() => setCron(value)}
|
|
210
|
-
className={`px-2 py-1 text-xs rounded-md transition-colors ${
|
|
211
|
-
cron === value
|
|
212
|
-
? 'bg-primary text-primary-foreground'
|
|
213
|
-
: 'bg-muted hover:bg-muted/80'
|
|
214
|
-
}`}
|
|
215
|
-
>
|
|
216
|
-
{label}
|
|
217
|
-
</button>
|
|
218
|
-
))}
|
|
219
|
-
</div>
|
|
220
|
-
<CronScheduler
|
|
221
|
-
value={cron}
|
|
222
|
-
onChange={setCron}
|
|
223
|
-
showPreview
|
|
224
|
-
allowCopy
|
|
225
|
-
/>
|
|
226
|
-
</div>
|
|
227
|
-
);
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
export const InDialog = () => {
|
|
231
|
-
const [cron, setCron] = useState('0 9 * * 1-5');
|
|
232
|
-
const [open, setOpen] = useState(false);
|
|
233
|
-
|
|
234
|
-
return (
|
|
235
|
-
<div className="p-4">
|
|
236
|
-
<Dialog open={open} onOpenChange={setOpen}>
|
|
237
|
-
<DialogTrigger asChild>
|
|
238
|
-
<button className="px-4 py-2 bg-primary text-primary-foreground rounded-md">
|
|
239
|
-
Open Schedule Dialog
|
|
240
|
-
</button>
|
|
241
|
-
</DialogTrigger>
|
|
242
|
-
<DialogContent className="max-w-2xl">
|
|
243
|
-
<DialogHeader>
|
|
244
|
-
<DialogTitle>Create Schedule</DialogTitle>
|
|
245
|
-
<DialogDescription>
|
|
246
|
-
Configure a cron schedule for automated execution
|
|
247
|
-
</DialogDescription>
|
|
248
|
-
</DialogHeader>
|
|
249
|
-
<div className="py-4">
|
|
250
|
-
<CronScheduler
|
|
251
|
-
value={cron}
|
|
252
|
-
onChange={setCron}
|
|
253
|
-
showPreview
|
|
254
|
-
showCronExpression
|
|
255
|
-
allowCopy
|
|
256
|
-
/>
|
|
257
|
-
</div>
|
|
258
|
-
</DialogContent>
|
|
259
|
-
</Dialog>
|
|
260
|
-
<div className="mt-4 text-sm text-muted-foreground">
|
|
261
|
-
Current cron: <code className="bg-muted px-1 rounded">{cron}</code>
|
|
262
|
-
</div>
|
|
263
|
-
</div>
|
|
264
|
-
);
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
export const InDialogMonthly = () => {
|
|
268
|
-
const [cron, setCron] = useState('0 9 1,15 * *');
|
|
269
|
-
const [open, setOpen] = useState(false);
|
|
270
|
-
|
|
271
|
-
return (
|
|
272
|
-
<div className="p-4">
|
|
273
|
-
<Dialog open={open} onOpenChange={setOpen}>
|
|
274
|
-
<DialogTrigger asChild>
|
|
275
|
-
<button className="px-4 py-2 bg-primary text-primary-foreground rounded-md">
|
|
276
|
-
Open Monthly Schedule
|
|
277
|
-
</button>
|
|
278
|
-
</DialogTrigger>
|
|
279
|
-
<DialogContent className="max-w-2xl">
|
|
280
|
-
<DialogHeader>
|
|
281
|
-
<DialogTitle>Monthly Schedule</DialogTitle>
|
|
282
|
-
<DialogDescription>
|
|
283
|
-
Test monthly calendar grid inside dialog
|
|
284
|
-
</DialogDescription>
|
|
285
|
-
</DialogHeader>
|
|
286
|
-
<div className="py-4">
|
|
287
|
-
<CronScheduler
|
|
288
|
-
value={cron}
|
|
289
|
-
onChange={setCron}
|
|
290
|
-
defaultType="monthly"
|
|
291
|
-
showPreview
|
|
292
|
-
showCronExpression
|
|
293
|
-
allowCopy
|
|
294
|
-
/>
|
|
295
|
-
</div>
|
|
296
|
-
</DialogContent>
|
|
297
|
-
</Dialog>
|
|
298
|
-
</div>
|
|
299
|
-
);
|
|
300
|
-
};
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
import { defineStory, useBoolean, useSelect, useNumber } from '@djangocfg/playground';
|
|
2
|
-
import { Gallery, GalleryCompact, type GalleryMediaItem, type GalleryAspectRatio } from './index';
|
|
3
|
-
|
|
4
|
-
// Sample images for testing
|
|
5
|
-
const SAMPLE_IMAGES: GalleryMediaItem[] = [
|
|
6
|
-
{
|
|
7
|
-
id: '1',
|
|
8
|
-
src: 'https://images.unsplash.com/photo-1494976388531-d1058494cdd8?w=800',
|
|
9
|
-
thumbnail: 'https://images.unsplash.com/photo-1494976388531-d1058494cdd8?w=200',
|
|
10
|
-
alt: 'Classic car',
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
id: '2',
|
|
14
|
-
src: 'https://images.unsplash.com/photo-1503376780353-7e6692767b70?w=800',
|
|
15
|
-
thumbnail: 'https://images.unsplash.com/photo-1503376780353-7e6692767b70?w=200',
|
|
16
|
-
alt: 'Porsche',
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
id: '3',
|
|
20
|
-
src: 'https://images.unsplash.com/photo-1542362567-b07e54358753?w=800',
|
|
21
|
-
thumbnail: 'https://images.unsplash.com/photo-1542362567-b07e54358753?w=200',
|
|
22
|
-
alt: 'BMW',
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
id: '4',
|
|
26
|
-
src: 'https://images.unsplash.com/photo-1555215695-3004980ad54e?w=800',
|
|
27
|
-
thumbnail: 'https://images.unsplash.com/photo-1555215695-3004980ad54e?w=200',
|
|
28
|
-
alt: 'Mercedes',
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
id: '5',
|
|
32
|
-
src: 'https://images.unsplash.com/photo-1617531653332-bd46c24f2068?w=800',
|
|
33
|
-
thumbnail: 'https://images.unsplash.com/photo-1617531653332-bd46c24f2068?w=200',
|
|
34
|
-
alt: 'Tesla',
|
|
35
|
-
},
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
export default defineStory({
|
|
39
|
-
title: 'Tools/Gallery',
|
|
40
|
-
component: Gallery,
|
|
41
|
-
description: 'Full-featured gallery with lightbox, thumbnails, and keyboard navigation.',
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
export const CarouselMode = () => (
|
|
45
|
-
<div className="max-w-4xl">
|
|
46
|
-
<Gallery
|
|
47
|
-
images={SAMPLE_IMAGES}
|
|
48
|
-
previewMode="carousel"
|
|
49
|
-
showThumbnails
|
|
50
|
-
showControls
|
|
51
|
-
showCounter
|
|
52
|
-
enableLightbox
|
|
53
|
-
enableKeyboard
|
|
54
|
-
aspectRatio={16 / 9}
|
|
55
|
-
/>
|
|
56
|
-
</div>
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
export const GridMode = () => (
|
|
60
|
-
<div className="max-w-4xl">
|
|
61
|
-
<Gallery
|
|
62
|
-
images={SAMPLE_IMAGES}
|
|
63
|
-
previewMode="grid"
|
|
64
|
-
previewCount={5}
|
|
65
|
-
enableLightbox
|
|
66
|
-
aspectRatio={16 / 9}
|
|
67
|
-
/>
|
|
68
|
-
</div>
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
export const WithoutThumbnails = () => (
|
|
72
|
-
<div className="max-w-4xl">
|
|
73
|
-
<Gallery
|
|
74
|
-
images={SAMPLE_IMAGES}
|
|
75
|
-
previewMode="carousel"
|
|
76
|
-
showThumbnails={false}
|
|
77
|
-
showControls
|
|
78
|
-
enableLightbox
|
|
79
|
-
aspectRatio={16 / 9}
|
|
80
|
-
/>
|
|
81
|
-
</div>
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
export const Compact = {
|
|
85
|
-
render: (args: {
|
|
86
|
-
showDots: boolean;
|
|
87
|
-
showArrows: boolean;
|
|
88
|
-
enableZoom: boolean;
|
|
89
|
-
showCounter: boolean;
|
|
90
|
-
}) => (
|
|
91
|
-
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
92
|
-
<div className="rounded-xl border border-border overflow-hidden">
|
|
93
|
-
<div className="aspect-[4/3]">
|
|
94
|
-
<GalleryCompact
|
|
95
|
-
images={SAMPLE_IMAGES}
|
|
96
|
-
showDots={args.showDots}
|
|
97
|
-
showArrows={args.showArrows}
|
|
98
|
-
enableZoom={args.enableZoom}
|
|
99
|
-
showCounter={args.showCounter}
|
|
100
|
-
/>
|
|
101
|
-
</div>
|
|
102
|
-
<div className="p-4">
|
|
103
|
-
<h3 className="font-medium">Vehicle Title</h3>
|
|
104
|
-
<p className="text-sm text-muted-foreground">$25,000</p>
|
|
105
|
-
</div>
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
),
|
|
109
|
-
args: {
|
|
110
|
-
showDots: true,
|
|
111
|
-
showArrows: true,
|
|
112
|
-
enableZoom: true,
|
|
113
|
-
showCounter: false,
|
|
114
|
-
},
|
|
115
|
-
argTypes: {
|
|
116
|
-
showDots: { control: 'boolean', description: 'Show navigation dots' },
|
|
117
|
-
showArrows: { control: 'boolean', description: 'Show arrow buttons' },
|
|
118
|
-
enableZoom: { control: 'boolean', description: 'Enable zoom on hover' },
|
|
119
|
-
showCounter: { control: 'boolean', description: 'Show image counter' },
|
|
120
|
-
},
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
export const SingleImage = () => (
|
|
124
|
-
<div className="w-64">
|
|
125
|
-
<div className="rounded-xl border border-border overflow-hidden">
|
|
126
|
-
<div className="aspect-[4/3]">
|
|
127
|
-
<GalleryCompact images={SAMPLE_IMAGES.slice(0, 1)} enableZoom />
|
|
128
|
-
</div>
|
|
129
|
-
</div>
|
|
130
|
-
</div>
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
export const EmptyState = () => (
|
|
134
|
-
<div className="w-64">
|
|
135
|
-
<div className="rounded-xl border border-border overflow-hidden">
|
|
136
|
-
<div className="aspect-[4/3]">
|
|
137
|
-
<GalleryCompact images={[]} />
|
|
138
|
-
</div>
|
|
139
|
-
</div>
|
|
140
|
-
</div>
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Interactive story using fixture hooks
|
|
145
|
-
* Controls appear automatically in the right sidebar
|
|
146
|
-
*/
|
|
147
|
-
export const Interactive = () => {
|
|
148
|
-
// These hooks auto-register controls in the Properties panel
|
|
149
|
-
const [showDots] = useBoolean('showDots', {
|
|
150
|
-
defaultValue: true,
|
|
151
|
-
label: 'Show Dots',
|
|
152
|
-
description: 'Display navigation dots at the bottom',
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
const [showArrows] = useBoolean('showArrows', {
|
|
156
|
-
defaultValue: true,
|
|
157
|
-
label: 'Show Arrows',
|
|
158
|
-
description: 'Display navigation arrows on hover',
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
const [enableZoom] = useBoolean('enableZoom', {
|
|
162
|
-
defaultValue: true,
|
|
163
|
-
label: 'Enable Zoom',
|
|
164
|
-
description: 'Zoom effect on image hover',
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
const [showCounter] = useBoolean('showCounter', {
|
|
168
|
-
defaultValue: false,
|
|
169
|
-
label: 'Show Counter',
|
|
170
|
-
description: 'Display image counter badge',
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const [maxDots] = useNumber('maxDots', {
|
|
174
|
-
defaultValue: 5,
|
|
175
|
-
min: 1,
|
|
176
|
-
max: 10,
|
|
177
|
-
label: 'Max Dots',
|
|
178
|
-
description: 'Maximum number of dots to display',
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
const [previewMode] = useSelect('previewMode', {
|
|
182
|
-
options: ['carousel', 'grid'] as const,
|
|
183
|
-
defaultValue: 'carousel',
|
|
184
|
-
label: 'Preview Mode',
|
|
185
|
-
description: 'Gallery preview display mode',
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
const [aspectRatio] = useSelect('aspectRatio', {
|
|
189
|
-
options: ['auto', '16/9', '4/3', '3/2', '1/1'] as const,
|
|
190
|
-
defaultValue: '4/3' as GalleryAspectRatio,
|
|
191
|
-
label: 'Aspect Ratio',
|
|
192
|
-
description: 'Image container aspect ratio',
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
return (
|
|
196
|
-
<div className="space-y-8">
|
|
197
|
-
{/* GalleryCompact */}
|
|
198
|
-
<div>
|
|
199
|
-
<h3 className="text-lg font-semibold mb-4">GalleryCompact</h3>
|
|
200
|
-
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
201
|
-
<div className="rounded-xl border border-border overflow-hidden bg-black">
|
|
202
|
-
<GalleryCompact
|
|
203
|
-
images={SAMPLE_IMAGES}
|
|
204
|
-
aspectRatio={aspectRatio}
|
|
205
|
-
showDots={showDots}
|
|
206
|
-
showArrows={showArrows}
|
|
207
|
-
enableZoom={enableZoom}
|
|
208
|
-
showCounter={showCounter}
|
|
209
|
-
maxDots={maxDots}
|
|
210
|
-
/>
|
|
211
|
-
<div className="p-4">
|
|
212
|
-
<h3 className="font-medium">Interactive Card</h3>
|
|
213
|
-
<p className="text-sm text-muted-foreground">Use controls on the right →</p>
|
|
214
|
-
</div>
|
|
215
|
-
</div>
|
|
216
|
-
</div>
|
|
217
|
-
</div>
|
|
218
|
-
|
|
219
|
-
{/* Full Gallery */}
|
|
220
|
-
<div>
|
|
221
|
-
<h3 className="text-lg font-semibold mb-4">Full Gallery ({previewMode})</h3>
|
|
222
|
-
<div className="max-w-4xl">
|
|
223
|
-
<Gallery
|
|
224
|
-
images={SAMPLE_IMAGES}
|
|
225
|
-
previewMode={previewMode}
|
|
226
|
-
showThumbnails
|
|
227
|
-
showControls
|
|
228
|
-
showCounter={showCounter}
|
|
229
|
-
enableLightbox
|
|
230
|
-
enableKeyboard
|
|
231
|
-
aspectRatio={16 / 9}
|
|
232
|
-
/>
|
|
233
|
-
</div>
|
|
234
|
-
</div>
|
|
235
|
-
</div>
|
|
236
|
-
);
|
|
237
|
-
};
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { defineStory, useSelect, useBoolean, useNumber } from '@djangocfg/playground';
|
|
2
|
-
import { ImageViewer } from './index';
|
|
3
|
-
|
|
4
|
-
export default defineStory({
|
|
5
|
-
title: 'Tools/ImageViewer',
|
|
6
|
-
component: ImageViewer,
|
|
7
|
-
description: 'Image viewer with zoom, pan, rotate, flip and gallery navigation.',
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
const IMAGES = [
|
|
11
|
-
{
|
|
12
|
-
file: { name: 'Mountain landscape', path: 'https://picsum.photos/seed/mountain/1200/800' },
|
|
13
|
-
src: 'https://picsum.photos/seed/mountain/1200/800',
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
file: { name: 'City skyline', path: 'https://picsum.photos/seed/city/1200/800' },
|
|
17
|
-
src: 'https://picsum.photos/seed/city/1200/800',
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
file: { name: 'Forest path', path: 'https://picsum.photos/seed/forest/1200/800' },
|
|
21
|
-
src: 'https://picsum.photos/seed/forest/1200/800',
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
file: { name: 'Ocean sunset', path: 'https://picsum.photos/seed/ocean/1200/800' },
|
|
25
|
-
src: 'https://picsum.photos/seed/ocean/1200/800',
|
|
26
|
-
},
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
export const Interactive = () => {
|
|
30
|
-
const [count] = useNumber('imageCount', {
|
|
31
|
-
defaultValue: 4,
|
|
32
|
-
min: 1,
|
|
33
|
-
max: 4,
|
|
34
|
-
label: 'Number of images',
|
|
35
|
-
description: 'How many images to show in gallery',
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
const [initialIndex] = useNumber('initialIndex', {
|
|
39
|
-
defaultValue: 0,
|
|
40
|
-
min: 0,
|
|
41
|
-
max: 3,
|
|
42
|
-
label: 'Initial index',
|
|
43
|
-
description: 'Which image to open first',
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const [inDialog] = useBoolean('inDialog', {
|
|
47
|
-
defaultValue: false,
|
|
48
|
-
label: 'inDialog',
|
|
49
|
-
description: 'Hide the fullscreen expand button',
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
return (
|
|
53
|
-
<div className="w-full h-[500px]">
|
|
54
|
-
<ImageViewer
|
|
55
|
-
images={IMAGES.slice(0, count)}
|
|
56
|
-
initialIndex={Math.min(initialIndex, count - 1)}
|
|
57
|
-
inDialog={inDialog}
|
|
58
|
-
/>
|
|
59
|
-
</div>
|
|
60
|
-
);
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export const SingleImage = () => (
|
|
64
|
-
<div className="w-full h-[500px]">
|
|
65
|
-
<ImageViewer images={[IMAGES[0]]} />
|
|
66
|
-
</div>
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
export const Gallery = () => (
|
|
70
|
-
<div className="w-full h-[500px]">
|
|
71
|
-
<ImageViewer images={IMAGES} initialIndex={0} />
|
|
72
|
-
</div>
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
export const OpenAtIndex = () => (
|
|
76
|
-
<div className="w-full h-[500px]">
|
|
77
|
-
<ImageViewer images={IMAGES} initialIndex={2} />
|
|
78
|
-
</div>
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
export const InDialog = () => (
|
|
82
|
-
<div className="w-full h-[500px]">
|
|
83
|
-
<ImageViewer images={IMAGES} inDialog />
|
|
84
|
-
</div>
|
|
85
|
-
);
|