@djangocfg/ui-tools 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 +132 -899
- package/dist/ChatRoot-6IZFM5HM.mjs +5 -0
- package/dist/{ChatRoot-EJC5Y2YM.cjs.map → ChatRoot-6IZFM5HM.mjs.map} +1 -1
- package/dist/ChatRoot-LW4XNIKP.cjs +14 -0
- package/dist/{ChatRoot-QOSKJPM6.mjs.map → ChatRoot-LW4XNIKP.cjs.map} +1 -1
- package/dist/DictationField-U25MEYAL.mjs +4 -0
- package/dist/DictationField-U25MEYAL.mjs.map +1 -0
- package/dist/DictationField-XWR5VOID.cjs +13 -0
- package/dist/DictationField-XWR5VOID.cjs.map +1 -0
- package/dist/{DocsLayout-2YKPXZYO.mjs → DocsLayout-2P3ONDWJ.mjs} +3 -3
- package/dist/{DocsLayout-2YKPXZYO.mjs.map → DocsLayout-2P3ONDWJ.mjs.map} +1 -1
- package/dist/{DocsLayout-Q4KS3QWW.cjs → DocsLayout-2YZNS5VK.cjs} +8 -8
- package/dist/{DocsLayout-Q4KS3QWW.cjs.map → DocsLayout-2YZNS5VK.cjs.map} +1 -1
- package/dist/chunk-4PFW7MIJ.cjs +837 -0
- package/dist/chunk-4PFW7MIJ.cjs.map +1 -0
- package/dist/chunk-C2YN6WEO.mjs +833 -0
- package/dist/chunk-C2YN6WEO.mjs.map +1 -0
- package/dist/{chunk-XACCHZH2.cjs → chunk-FIRK5CEH.cjs} +42 -4
- package/dist/chunk-FIRK5CEH.cjs.map +1 -0
- package/dist/{chunk-NWUT327A.mjs → chunk-HIK6BPL7.mjs} +38 -5
- package/dist/chunk-HIK6BPL7.mjs.map +1 -0
- package/dist/chunk-OZAU3QWD.cjs +2493 -0
- package/dist/chunk-OZAU3QWD.cjs.map +1 -0
- package/dist/chunk-UWVP6LCW.mjs +2447 -0
- package/dist/chunk-UWVP6LCW.mjs.map +1 -0
- package/dist/index.cjs +1668 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1215 -107
- package/dist/index.d.ts +1215 -107
- package/dist/index.mjs +1555 -50
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -15
- package/src/audio-assets.d.ts +8 -0
- package/src/components/markdown/MarkdownMessage/CollapseToggle.tsx +3 -1
- package/src/components/markdown/MarkdownMessage/components.tsx +2 -5
- package/src/tools/Chat/README.md +347 -530
- package/src/tools/Chat/components/Attachments.tsx +6 -1
- package/src/tools/Chat/components/ChatRoot.tsx +30 -2
- package/src/tools/Chat/components/Composer.tsx +20 -3
- package/src/tools/Chat/components/ErrorBanner.tsx +7 -3
- package/src/tools/Chat/components/MessageActions.tsx +3 -1
- package/src/tools/Chat/components/MessageBubble.tsx +6 -5
- package/src/tools/Chat/components/MessageList.tsx +87 -1
- package/src/tools/Chat/components/ToolCalls.tsx +21 -3
- package/src/tools/Chat/context/ChatProvider.tsx +21 -3
- package/src/tools/Chat/core/audio/audioBus.ts +10 -163
- package/src/tools/Chat/core/audio/defaults.ts +43 -0
- package/src/tools/Chat/core/audio/index.ts +1 -0
- package/src/tools/Chat/core/audio/preferences.ts +5 -59
- 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/core/audio/types.ts +28 -0
- package/src/tools/Chat/core/reducer.ts +33 -0
- package/src/tools/Chat/core/transport/index.ts +13 -0
- package/src/tools/Chat/core/transport/mappers/index.ts +6 -0
- package/src/tools/Chat/core/transport/mappers/pydantic-ai.ts +142 -0
- package/src/tools/Chat/core/transport/pydantic-ai-transport.ts +208 -0
- package/src/tools/Chat/core/transport/sse.ts +18 -5
- package/src/tools/Chat/hooks/index.ts +25 -0
- package/src/tools/Chat/hooks/useAutoFocusOnStreamEnd.ts +5 -3
- package/src/tools/Chat/hooks/useChat.ts +28 -0
- package/src/tools/Chat/hooks/useChatAudio.ts +59 -180
- package/src/tools/Chat/hooks/useChatDockPrefs.ts +74 -0
- package/src/tools/Chat/hooks/useChatReset.ts +70 -0
- package/src/tools/Chat/hooks/useChatUnread.ts +87 -0
- package/src/tools/Chat/hooks/useFocusOnEmptyClick.ts +111 -0
- package/src/tools/Chat/hooks/useVisitorFingerprint.ts +48 -0
- package/src/tools/Chat/index.ts +84 -1
- package/src/tools/Chat/launcher/ChatDock.tsx +263 -0
- package/src/tools/Chat/launcher/ChatFAB.tsx +349 -0
- package/src/tools/Chat/launcher/ChatGreeting.tsx +200 -0
- package/src/tools/Chat/launcher/ChatHeader.tsx +76 -0
- package/src/tools/Chat/launcher/ChatHeaderActionButton.tsx +87 -0
- package/src/tools/Chat/launcher/ChatHeaderAudioToggle.tsx +47 -0
- package/src/tools/Chat/launcher/ChatHeaderLanguageButton.tsx +179 -0
- package/src/tools/Chat/launcher/ChatHeaderModeToggle.tsx +57 -0
- package/src/tools/Chat/launcher/ChatHeaderResetButton.tsx +93 -0
- package/src/tools/Chat/launcher/ChatLauncher.tsx +321 -0
- package/src/tools/Chat/launcher/ChatUnreadPreview.tsx +197 -0
- package/src/tools/Chat/launcher/index.ts +46 -0
- package/src/tools/Chat/launcher/useChatPresence.ts +44 -0
- package/src/tools/Chat/styles/bubbleTokens.ts +71 -0
- package/src/tools/Chat/styles/index.ts +16 -0
- package/src/tools/Chat/styles/useChatStyles.ts +101 -0
- package/src/tools/Chat/types/attachment.ts +25 -0
- package/src/tools/Chat/types/config.ts +48 -0
- package/src/tools/Chat/types/events.ts +35 -0
- package/src/tools/Chat/types/index.ts +34 -0
- package/src/tools/Chat/types/labels.ts +38 -0
- package/src/tools/Chat/types/message.ts +32 -0
- package/src/tools/Chat/types/persona.ts +31 -0
- package/src/tools/Chat/types/session.ts +43 -0
- package/src/tools/Chat/types/tool-call.ts +17 -0
- package/src/tools/Chat/types/transport.ts +28 -0
- package/src/tools/Chat/types.ts +5 -240
- package/src/tools/MarkdownEditor/MarkdownEditor.tsx +50 -14
- package/src/tools/MarkdownEditor/index.ts +1 -1
- package/src/tools/SpeechRecognition/README.md +336 -0
- package/src/tools/SpeechRecognition/__tests__/ids.test.ts +15 -0
- package/src/tools/SpeechRecognition/__tests__/language.test.ts +59 -0
- package/src/tools/SpeechRecognition/__tests__/reducer.test.ts +71 -0
- package/src/tools/SpeechRecognition/__tests__/transcript.test.ts +52 -0
- package/src/tools/SpeechRecognition/components/DevicePicker.tsx +49 -0
- package/src/tools/SpeechRecognition/components/DictationButton.tsx +93 -0
- package/src/tools/SpeechRecognition/components/EngineBadge.tsx +30 -0
- package/src/tools/SpeechRecognition/components/ErrorBanner.tsx +52 -0
- package/src/tools/SpeechRecognition/components/LanguagePicker.tsx +63 -0
- package/src/tools/SpeechRecognition/components/MicMeter.tsx +63 -0
- package/src/tools/SpeechRecognition/components/PushToTalkHint.tsx +51 -0
- package/src/tools/SpeechRecognition/components/TranscriptView.tsx +55 -0
- package/src/tools/SpeechRecognition/components/index.ts +16 -0
- package/src/tools/SpeechRecognition/context/SpeechRecognitionProvider.tsx +47 -0
- package/src/tools/SpeechRecognition/context/index.ts +6 -0
- package/src/tools/SpeechRecognition/core/audio/defaults.ts +24 -0
- package/src/tools/SpeechRecognition/core/engine/external.ts +222 -0
- package/src/tools/SpeechRecognition/core/engine/http.ts +147 -0
- package/src/tools/SpeechRecognition/core/engine/index.ts +52 -0
- package/src/tools/SpeechRecognition/core/engine/mediarecorder.ts +105 -0
- package/src/tools/SpeechRecognition/core/engine/websocket.ts +211 -0
- package/src/tools/SpeechRecognition/core/engine/webspeech.ts +188 -0
- package/src/tools/SpeechRecognition/core/ids.ts +11 -0
- package/src/tools/SpeechRecognition/core/index.ts +14 -0
- package/src/tools/SpeechRecognition/core/language.ts +78 -0
- package/src/tools/SpeechRecognition/core/languages-catalog.ts +229 -0
- package/src/tools/SpeechRecognition/core/logger.ts +3 -0
- package/src/tools/SpeechRecognition/core/reducer.ts +105 -0
- package/src/tools/SpeechRecognition/core/transcript.ts +36 -0
- package/src/tools/SpeechRecognition/hooks/index.ts +14 -0
- package/src/tools/SpeechRecognition/hooks/useDictation.ts +59 -0
- package/src/tools/SpeechRecognition/hooks/useEnginePrefs.ts +15 -0
- package/src/tools/SpeechRecognition/hooks/useMicDevices.ts +57 -0
- package/src/tools/SpeechRecognition/hooks/useMicLevel.ts +52 -0
- package/src/tools/SpeechRecognition/hooks/usePushToTalk.ts +85 -0
- package/src/tools/SpeechRecognition/hooks/useResolvedLanguage.ts +28 -0
- package/src/tools/SpeechRecognition/hooks/useSpeechLanguageInfo.ts +108 -0
- package/src/tools/SpeechRecognition/hooks/useSpeechRecognition.ts +188 -0
- package/src/tools/SpeechRecognition/hooks/useVoiceSupport.ts +78 -0
- package/src/tools/SpeechRecognition/index.ts +82 -0
- package/src/tools/SpeechRecognition/lazy.tsx +19 -0
- package/src/tools/SpeechRecognition/store/index.ts +2 -0
- package/src/tools/SpeechRecognition/store/prefsStore.ts +54 -0
- package/src/tools/SpeechRecognition/types.ts +133 -0
- package/src/tools/SpeechRecognition/widgets/DictationField.tsx +105 -0
- package/src/tools/SpeechRecognition/widgets/VoiceComposerSlot.tsx +305 -0
- package/src/tools/SpeechRecognition/widgets/VoiceMessageRecorder.tsx +88 -0
- package/src/tools/SpeechRecognition/widgets/index.ts +6 -0
- package/dist/ChatRoot-EJC5Y2YM.cjs +0 -14
- package/dist/ChatRoot-QOSKJPM6.mjs +0 -5
- package/dist/chunk-NWUT327A.mjs.map +0 -1
- package/dist/chunk-QLMKCSR6.mjs +0 -2420
- package/dist/chunk-QLMKCSR6.mjs.map +0 -1
- package/dist/chunk-SI5RD2GD.cjs +0 -2460
- package/dist/chunk-SI5RD2GD.cjs.map +0 -1
- package/dist/chunk-XACCHZH2.cjs.map +0 -1
- package/src/components/markdown/MarkdownMessage/MarkdownMessage.story.tsx +0 -771
- package/src/stories/index.ts +0 -33
- package/src/tools/AudioPlayer/AudioPlayer.story.tsx +0 -481
- package/src/tools/Chat/Chat.story.tsx +0 -1457
- 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/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,304 +0,0 @@
|
|
|
1
|
-
import { defineStory, useSelect, useBoolean } from '@djangocfg/playground';
|
|
2
|
-
import PrettyCode from './index';
|
|
3
|
-
|
|
4
|
-
export default defineStory({
|
|
5
|
-
title: 'Tools/Pretty Code',
|
|
6
|
-
component: PrettyCode,
|
|
7
|
-
description: 'Syntax highlighted code block with copy button.',
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
// ─── Samples ──────────────────────────────────────────────────────────────────
|
|
11
|
-
|
|
12
|
-
const LONG_CODE_SAMPLES = {
|
|
13
|
-
typescript: `import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
14
|
-
|
|
15
|
-
export type Status = 'idle' | 'loading' | 'success' | 'error';
|
|
16
|
-
|
|
17
|
-
export interface PaginationParams {
|
|
18
|
-
page: number;
|
|
19
|
-
pageSize: number;
|
|
20
|
-
sortBy?: string;
|
|
21
|
-
sortOrder?: 'asc' | 'desc';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function useVehicles(initialParams?: Partial<PaginationParams>) {
|
|
25
|
-
const [status, setStatus] = useState<Status>('idle');
|
|
26
|
-
const [data, setData] = useState<unknown[]>([]);
|
|
27
|
-
const [error, setError] = useState<Error | null>(null);
|
|
28
|
-
const abortRef = useRef<AbortController | null>(null);
|
|
29
|
-
|
|
30
|
-
const [params, setParams] = useState<PaginationParams>({
|
|
31
|
-
page: 1,
|
|
32
|
-
pageSize: 20,
|
|
33
|
-
...initialParams,
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const fetch = useCallback(async (p: PaginationParams) => {
|
|
37
|
-
abortRef.current?.abort();
|
|
38
|
-
abortRef.current = new AbortController();
|
|
39
|
-
setStatus('loading');
|
|
40
|
-
try {
|
|
41
|
-
const query = new URLSearchParams({
|
|
42
|
-
page: String(p.page),
|
|
43
|
-
pageSize: String(p.pageSize),
|
|
44
|
-
});
|
|
45
|
-
const res = await window.fetch(\`/api/vehicles?\${query}\`, {
|
|
46
|
-
signal: abortRef.current.signal,
|
|
47
|
-
});
|
|
48
|
-
if (!res.ok) throw new Error(\`HTTP \${res.status}\`);
|
|
49
|
-
const json = await res.json();
|
|
50
|
-
setData(json.data);
|
|
51
|
-
setStatus('success');
|
|
52
|
-
} catch (err) {
|
|
53
|
-
if ((err as Error).name === 'AbortError') return;
|
|
54
|
-
setError(err as Error);
|
|
55
|
-
setStatus('error');
|
|
56
|
-
}
|
|
57
|
-
}, []);
|
|
58
|
-
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
fetch(params);
|
|
61
|
-
return () => abortRef.current?.abort();
|
|
62
|
-
}, [params, fetch]);
|
|
63
|
-
|
|
64
|
-
return { status, data, error, params, setParams };
|
|
65
|
-
}`,
|
|
66
|
-
|
|
67
|
-
python: `from __future__ import annotations
|
|
68
|
-
|
|
69
|
-
import asyncio
|
|
70
|
-
import logging
|
|
71
|
-
from dataclasses import dataclass, field
|
|
72
|
-
from datetime import datetime
|
|
73
|
-
from enum import StrEnum
|
|
74
|
-
|
|
75
|
-
import httpx
|
|
76
|
-
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
77
|
-
|
|
78
|
-
logger = logging.getLogger(__name__)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
class FuelType(StrEnum):
|
|
82
|
-
GASOLINE = "gasoline"
|
|
83
|
-
DIESEL = "diesel"
|
|
84
|
-
ELECTRIC = "electric"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
class Vehicle(BaseModel):
|
|
88
|
-
model_config = ConfigDict(from_attributes=True)
|
|
89
|
-
|
|
90
|
-
id: str
|
|
91
|
-
make: str
|
|
92
|
-
model: str
|
|
93
|
-
year: int
|
|
94
|
-
fuel_type: FuelType
|
|
95
|
-
created_at: datetime = Field(default_factory=datetime.utcnow)
|
|
96
|
-
|
|
97
|
-
@field_validator("year")
|
|
98
|
-
@classmethod
|
|
99
|
-
def validate_year(cls, v: int) -> int:
|
|
100
|
-
if not (1900 <= v <= datetime.utcnow().year + 1):
|
|
101
|
-
raise ValueError(f"Invalid year: {v}")
|
|
102
|
-
return v
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
@dataclass
|
|
106
|
-
class VehicleRepository:
|
|
107
|
-
base_url: str
|
|
108
|
-
|
|
109
|
-
async def list(self, page: int = 1, page_size: int = 20) -> list[Vehicle]:
|
|
110
|
-
async with httpx.AsyncClient(base_url=self.base_url) as client:
|
|
111
|
-
response = await client.get(
|
|
112
|
-
"/vehicles",
|
|
113
|
-
params={"page": page, "page_size": page_size},
|
|
114
|
-
)
|
|
115
|
-
response.raise_for_status()
|
|
116
|
-
payload = response.json()
|
|
117
|
-
return [Vehicle.model_validate(v) for v in payload["data"]]`,
|
|
118
|
-
|
|
119
|
-
javascript: `class EventBus {
|
|
120
|
-
#listeners = new Map();
|
|
121
|
-
#wildcards = new Set();
|
|
122
|
-
|
|
123
|
-
on(event, handler) {
|
|
124
|
-
if (event === '*') {
|
|
125
|
-
this.#wildcards.add(handler);
|
|
126
|
-
return () => this.#wildcards.delete(handler);
|
|
127
|
-
}
|
|
128
|
-
if (!this.#listeners.has(event)) {
|
|
129
|
-
this.#listeners.set(event, new Set());
|
|
130
|
-
}
|
|
131
|
-
this.#listeners.get(event).add(handler);
|
|
132
|
-
return () => this.#listeners.get(event)?.delete(handler);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
once(event, handler) {
|
|
136
|
-
const unsub = this.on(event, (...args) => {
|
|
137
|
-
unsub();
|
|
138
|
-
handler(...args);
|
|
139
|
-
});
|
|
140
|
-
return unsub;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
emit(event, payload) {
|
|
144
|
-
this.#listeners.get(event)?.forEach(h => h(payload));
|
|
145
|
-
this.#wildcards.forEach(h => h(event, payload));
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const bus = new EventBus();
|
|
150
|
-
bus.on('*', (event, payload) => console.debug(\`[bus] \${event}\`, payload));
|
|
151
|
-
bus.emit('vehicle:created', { id: 'v_001', make: 'BMW' });`,
|
|
152
|
-
|
|
153
|
-
css: `:root {
|
|
154
|
-
--radius-md: 0.5rem;
|
|
155
|
-
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
156
|
-
--transition-base: 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.card {
|
|
160
|
-
border-radius: var(--radius-md);
|
|
161
|
-
border: 1px solid hsl(var(--border));
|
|
162
|
-
background: hsl(var(--card));
|
|
163
|
-
box-shadow: var(--shadow-sm);
|
|
164
|
-
transition: box-shadow var(--transition-base);
|
|
165
|
-
|
|
166
|
-
&:hover {
|
|
167
|
-
box-shadow: var(--shadow-md);
|
|
168
|
-
transform: translateY(-1px);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
@keyframes shimmer {
|
|
173
|
-
from { background-position: -200% 0; }
|
|
174
|
-
to { background-position: 200% 0; }
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
.card--skeleton .card-title {
|
|
178
|
-
background: linear-gradient(90deg, hsl(var(--muted)) 25%, hsl(var(--muted-foreground) / 0.1) 50%, hsl(var(--muted)) 75%);
|
|
179
|
-
background-size: 200% 100%;
|
|
180
|
-
animation: shimmer 1.5s infinite;
|
|
181
|
-
}`,
|
|
182
|
-
|
|
183
|
-
html: `<!DOCTYPE html>
|
|
184
|
-
<html lang="en">
|
|
185
|
-
<head>
|
|
186
|
-
<meta charset="UTF-8" />
|
|
187
|
-
<title>Sample</title>
|
|
188
|
-
</head>
|
|
189
|
-
<body>
|
|
190
|
-
<div id="root"></div>
|
|
191
|
-
<script type="module" src="/entry.tsx"></script>
|
|
192
|
-
</body>
|
|
193
|
-
</html>`,
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
// ─── Stories ──────────────────────────────────────────────────────────────────
|
|
197
|
-
|
|
198
|
-
/** Interactive — language, variant, compact, scrollIsolation all toggleable.
|
|
199
|
-
* Replaces the old per-language / per-mode / per-flag stories which were
|
|
200
|
-
* just this component with different defaults. */
|
|
201
|
-
export const Interactive = () => {
|
|
202
|
-
const [language] = useSelect('language', {
|
|
203
|
-
options: ['typescript', 'javascript', 'python', 'css', 'html'] as const,
|
|
204
|
-
defaultValue: 'typescript',
|
|
205
|
-
label: 'Language',
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
const [variant] = useSelect('variant', {
|
|
209
|
-
options: ['card', 'plain'] as const,
|
|
210
|
-
defaultValue: 'card',
|
|
211
|
-
label: 'Variant',
|
|
212
|
-
description: 'card = full chrome, plain = bare highlighted code',
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
const [isCompact] = useBoolean('isCompact', {
|
|
216
|
-
defaultValue: false,
|
|
217
|
-
label: 'Compact',
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
const [scrollIsolation] = useBoolean('scrollIsolation', {
|
|
221
|
-
defaultValue: true,
|
|
222
|
-
label: 'Scroll isolation',
|
|
223
|
-
description: 'Require click before the block captures scroll (card only)',
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
return (
|
|
227
|
-
<PrettyCode
|
|
228
|
-
data={LONG_CODE_SAMPLES[language]}
|
|
229
|
-
language={language}
|
|
230
|
-
variant={variant}
|
|
231
|
-
isCompact={isCompact}
|
|
232
|
-
scrollIsolation={scrollIsolation}
|
|
233
|
-
/>
|
|
234
|
-
);
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
/** Variants — ``card`` vs ``plain`` side by side. The card has its own
|
|
238
|
-
* border, hover toolbar, and can internally scroll when a ``maxLines``
|
|
239
|
-
* cap is hit. The plain variant is chrome-less for embedding inside
|
|
240
|
-
* an existing scroll container (e.g. a response panel), where the
|
|
241
|
-
* parent surface owns chrome and scroll. */
|
|
242
|
-
export const Variants = () => (
|
|
243
|
-
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 max-w-6xl">
|
|
244
|
-
<section className="space-y-2">
|
|
245
|
-
<h3 className="text-sm font-semibold">variant="card" (default)</h3>
|
|
246
|
-
<p className="text-xs text-muted-foreground">
|
|
247
|
-
Border, background, hover toolbar with Copy + language tag.
|
|
248
|
-
</p>
|
|
249
|
-
<PrettyCode data={LONG_CODE_SAMPLES.typescript} language="typescript" variant="card" />
|
|
250
|
-
</section>
|
|
251
|
-
<section className="space-y-2">
|
|
252
|
-
<h3 className="text-sm font-semibold">variant="plain"</h3>
|
|
253
|
-
<p className="text-xs text-muted-foreground">
|
|
254
|
-
Chrome-less. No border, no background, no toolbar. Flows into the
|
|
255
|
-
parent scroll container.
|
|
256
|
-
</p>
|
|
257
|
-
<PrettyCode data={LONG_CODE_SAMPLES.typescript} language="typescript" variant="plain" />
|
|
258
|
-
</section>
|
|
259
|
-
</div>
|
|
260
|
-
);
|
|
261
|
-
|
|
262
|
-
/** LongCode — stress test for multi-column layouts and long snippets. */
|
|
263
|
-
export const LongCode = () => (
|
|
264
|
-
<div className="flex flex-col gap-6 max-w-4xl">
|
|
265
|
-
<div className="h-96">
|
|
266
|
-
<PrettyCode data={LONG_CODE_SAMPLES.typescript} language="typescript" maxLines={30} />
|
|
267
|
-
</div>
|
|
268
|
-
<div className="h-96">
|
|
269
|
-
<PrettyCode data={LONG_CODE_SAMPLES.python} language="python" maxLines={30} />
|
|
270
|
-
</div>
|
|
271
|
-
<div className="h-96">
|
|
272
|
-
<PrettyCode data={LONG_CODE_SAMPLES.javascript} language="javascript" maxLines={30} />
|
|
273
|
-
</div>
|
|
274
|
-
</div>
|
|
275
|
-
);
|
|
276
|
-
|
|
277
|
-
/** ScrollIsolation — both states side-by-side so the difference is
|
|
278
|
-
* obvious without toggling. The isolation flag matters most when the
|
|
279
|
-
* block is embedded in a scrolling page: without it, wheel-scrolling
|
|
280
|
-
* anywhere over the block "captures" the wheel and the page itself
|
|
281
|
-
* stops scrolling — click-to-unlock avoids that surprise. */
|
|
282
|
-
export const ScrollIsolation = () => (
|
|
283
|
-
<div className="flex flex-col gap-8 max-w-4xl">
|
|
284
|
-
<section className="space-y-2">
|
|
285
|
-
<h3 className="text-sm font-semibold">scrollIsolation=true (default)</h3>
|
|
286
|
-
<p className="text-xs text-muted-foreground">
|
|
287
|
-
Hover to see the hint; click to unlock wheel-scroll inside the block.
|
|
288
|
-
</p>
|
|
289
|
-
<div className="h-64">
|
|
290
|
-
<PrettyCode data={LONG_CODE_SAMPLES.typescript} language="typescript" maxLines={15} scrollIsolation />
|
|
291
|
-
</div>
|
|
292
|
-
</section>
|
|
293
|
-
<section className="space-y-2">
|
|
294
|
-
<h3 className="text-sm font-semibold">scrollIsolation=false</h3>
|
|
295
|
-
<p className="text-xs text-muted-foreground">
|
|
296
|
-
Wheel-scroll captured immediately — use when the block has no
|
|
297
|
-
surrounding page-level scroll to compete with.
|
|
298
|
-
</p>
|
|
299
|
-
<div className="h-64">
|
|
300
|
-
<PrettyCode data={LONG_CODE_SAMPLES.typescript} language="typescript" maxLines={15} scrollIsolation={false} />
|
|
301
|
-
</div>
|
|
302
|
-
</section>
|
|
303
|
-
</div>
|
|
304
|
-
);
|
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useState } from 'react';
|
|
4
|
-
import { defineStory, useSelect } from '@djangocfg/playground';
|
|
5
|
-
import { Button, Card, CardContent, CardHeader, CardTitle } from '@djangocfg/ui-core/components';
|
|
6
|
-
import { Tour, useTour } from './index';
|
|
7
|
-
import type { Tour as TourConfig } from './types';
|
|
8
|
-
|
|
9
|
-
export default defineStory({
|
|
10
|
-
title: 'Tools/Tour',
|
|
11
|
-
component: Tour,
|
|
12
|
-
description: 'Onboarding tours with spotlight highlighting and keyboard navigation.',
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
// Demo tours
|
|
16
|
-
const demoTours: TourConfig[] = [
|
|
17
|
-
{
|
|
18
|
-
id: 'basic',
|
|
19
|
-
steps: [
|
|
20
|
-
{
|
|
21
|
-
id: 'welcome',
|
|
22
|
-
target: '[data-tour-step-id="header"]',
|
|
23
|
-
title: 'Welcome to the Demo',
|
|
24
|
-
content: 'This tour will show you the main features of this page.',
|
|
25
|
-
position: 'bottom',
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
id: 'sidebar',
|
|
29
|
-
target: '[data-tour-step-id="sidebar"]',
|
|
30
|
-
title: 'Navigation Sidebar',
|
|
31
|
-
content: 'Use this sidebar to navigate between different sections.',
|
|
32
|
-
position: 'right',
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
id: 'content',
|
|
36
|
-
target: '[data-tour-step-id="main-content"]',
|
|
37
|
-
title: 'Main Content Area',
|
|
38
|
-
content: 'This is where all your content will be displayed.',
|
|
39
|
-
position: 'top',
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
id: 'actions',
|
|
43
|
-
target: '[data-tour-step-id="action-button"]',
|
|
44
|
-
title: 'Quick Actions',
|
|
45
|
-
content: 'Click here to perform quick actions.',
|
|
46
|
-
position: 'left',
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
id: 'cards',
|
|
52
|
-
defaults: {
|
|
53
|
-
spotlightPadding: 12,
|
|
54
|
-
},
|
|
55
|
-
steps: [
|
|
56
|
-
{
|
|
57
|
-
id: 'step-1',
|
|
58
|
-
target: '[data-tour-step-id="card-1"]',
|
|
59
|
-
title: 'First Card',
|
|
60
|
-
content: 'This card shows important information.',
|
|
61
|
-
position: 'bottom',
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
id: 'step-2',
|
|
65
|
-
target: '[data-tour-step-id="card-2"]',
|
|
66
|
-
title: 'Second Card',
|
|
67
|
-
content: 'Another important card with different data.',
|
|
68
|
-
position: 'bottom',
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
id: 'step-3',
|
|
72
|
-
target: '[data-tour-step-id="card-3"]',
|
|
73
|
-
title: 'Third Card',
|
|
74
|
-
content: 'The last card in this row.',
|
|
75
|
-
position: 'bottom',
|
|
76
|
-
nextLabel: 'Complete Tour',
|
|
77
|
-
},
|
|
78
|
-
],
|
|
79
|
-
},
|
|
80
|
-
];
|
|
81
|
-
|
|
82
|
-
// Demo component with tour targets
|
|
83
|
-
function DemoLayout() {
|
|
84
|
-
const { start, isActive, currentStepIndex, totalSteps } = useTour();
|
|
85
|
-
|
|
86
|
-
return (
|
|
87
|
-
<div className="min-h-[500px] rounded-lg bg-muted/30 p-4">
|
|
88
|
-
{/* Header */}
|
|
89
|
-
<header
|
|
90
|
-
data-tour-step-id="header"
|
|
91
|
-
className="mb-4 rounded-lg bg-primary p-4 text-primary-foreground"
|
|
92
|
-
>
|
|
93
|
-
<div className="flex items-center justify-between">
|
|
94
|
-
<h1 className="text-xl font-bold">Tour Demo</h1>
|
|
95
|
-
<div className="flex gap-2">
|
|
96
|
-
<Button
|
|
97
|
-
variant="secondary"
|
|
98
|
-
size="sm"
|
|
99
|
-
onClick={() => start('basic')}
|
|
100
|
-
disabled={isActive}
|
|
101
|
-
>
|
|
102
|
-
Basic Tour
|
|
103
|
-
</Button>
|
|
104
|
-
<Button
|
|
105
|
-
variant="secondary"
|
|
106
|
-
size="sm"
|
|
107
|
-
onClick={() => start('cards')}
|
|
108
|
-
disabled={isActive}
|
|
109
|
-
>
|
|
110
|
-
Cards Tour
|
|
111
|
-
</Button>
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
114
|
-
</header>
|
|
115
|
-
|
|
116
|
-
<div className="flex gap-4">
|
|
117
|
-
{/* Sidebar */}
|
|
118
|
-
<aside
|
|
119
|
-
data-tour-step-id="sidebar"
|
|
120
|
-
className="w-48 rounded-lg bg-card p-4 shadow"
|
|
121
|
-
>
|
|
122
|
-
<nav className="space-y-2">
|
|
123
|
-
<div className="rounded bg-muted p-2 text-sm">Dashboard</div>
|
|
124
|
-
<div className="rounded p-2 text-sm hover:bg-muted">Settings</div>
|
|
125
|
-
<div className="rounded p-2 text-sm hover:bg-muted">Profile</div>
|
|
126
|
-
<div className="rounded p-2 text-sm hover:bg-muted">Help</div>
|
|
127
|
-
</nav>
|
|
128
|
-
</aside>
|
|
129
|
-
|
|
130
|
-
{/* Main content */}
|
|
131
|
-
<main className="flex-1 space-y-4">
|
|
132
|
-
<div
|
|
133
|
-
data-tour-step-id="main-content"
|
|
134
|
-
className="rounded-lg bg-card p-6 shadow"
|
|
135
|
-
>
|
|
136
|
-
<h2 className="mb-4 text-lg font-semibold">Main Content</h2>
|
|
137
|
-
<p className="text-muted-foreground">
|
|
138
|
-
This is the main content area.
|
|
139
|
-
{isActive && (
|
|
140
|
-
<span className="ml-2 text-primary">
|
|
141
|
-
(Step {currentStepIndex + 1} of {totalSteps})
|
|
142
|
-
</span>
|
|
143
|
-
)}
|
|
144
|
-
</p>
|
|
145
|
-
|
|
146
|
-
<Button data-tour-step-id="action-button" className="mt-4">
|
|
147
|
-
Quick Action
|
|
148
|
-
</Button>
|
|
149
|
-
</div>
|
|
150
|
-
|
|
151
|
-
{/* Cards row */}
|
|
152
|
-
<div className="grid grid-cols-3 gap-4">
|
|
153
|
-
<Card data-tour-step-id="card-1">
|
|
154
|
-
<CardHeader>
|
|
155
|
-
<CardTitle className="text-base">Card 1</CardTitle>
|
|
156
|
-
</CardHeader>
|
|
157
|
-
<CardContent>
|
|
158
|
-
<p className="text-sm text-muted-foreground">First card content.</p>
|
|
159
|
-
</CardContent>
|
|
160
|
-
</Card>
|
|
161
|
-
|
|
162
|
-
<Card data-tour-step-id="card-2">
|
|
163
|
-
<CardHeader>
|
|
164
|
-
<CardTitle className="text-base">Card 2</CardTitle>
|
|
165
|
-
</CardHeader>
|
|
166
|
-
<CardContent>
|
|
167
|
-
<p className="text-sm text-muted-foreground">Second card content.</p>
|
|
168
|
-
</CardContent>
|
|
169
|
-
</Card>
|
|
170
|
-
|
|
171
|
-
<Card data-tour-step-id="card-3">
|
|
172
|
-
<CardHeader>
|
|
173
|
-
<CardTitle className="text-base">Card 3</CardTitle>
|
|
174
|
-
</CardHeader>
|
|
175
|
-
<CardContent>
|
|
176
|
-
<p className="text-sm text-muted-foreground">Third card content.</p>
|
|
177
|
-
</CardContent>
|
|
178
|
-
</Card>
|
|
179
|
-
</div>
|
|
180
|
-
</main>
|
|
181
|
-
</div>
|
|
182
|
-
</div>
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export const Interactive = () => {
|
|
187
|
-
const [progressVariant] = useSelect('progressVariant', {
|
|
188
|
-
options: ['dots', 'bar', 'fraction', 'none'] as const,
|
|
189
|
-
defaultValue: 'dots',
|
|
190
|
-
label: 'Progress Variant',
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
return (
|
|
194
|
-
<Tour
|
|
195
|
-
tours={demoTours}
|
|
196
|
-
progressVariant={progressVariant}
|
|
197
|
-
onStart={(id) => console.log('Tour started:', id)}
|
|
198
|
-
onComplete={(id) => console.log('Tour completed:', id)}
|
|
199
|
-
onSkip={(id, step) => console.log('Tour skipped:', id, 'at step', step)}
|
|
200
|
-
onStepChange={(index, step, direction) =>
|
|
201
|
-
console.log('Step:', index, step.id, direction)
|
|
202
|
-
}
|
|
203
|
-
>
|
|
204
|
-
<DemoLayout />
|
|
205
|
-
</Tour>
|
|
206
|
-
);
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
export const WithProgressBar = () => (
|
|
210
|
-
<Tour tours={demoTours} progressVariant="bar">
|
|
211
|
-
<DemoLayout />
|
|
212
|
-
</Tour>
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
export const WithFraction = () => (
|
|
216
|
-
<Tour tours={demoTours} progressVariant="fraction">
|
|
217
|
-
<DemoLayout />
|
|
218
|
-
</Tour>
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
export const NoSpotlight = () => (
|
|
222
|
-
<Tour tours={demoTours} spotlight={false}>
|
|
223
|
-
<DemoLayout />
|
|
224
|
-
</Tour>
|
|
225
|
-
);
|
|
226
|
-
|
|
227
|
-
export const CloseOnOverlayClick = () => (
|
|
228
|
-
<Tour tours={demoTours} closeOnOverlayClick>
|
|
229
|
-
<DemoLayout />
|
|
230
|
-
</Tour>
|
|
231
|
-
);
|
|
232
|
-
|
|
233
|
-
export const NoSkipButton = () => (
|
|
234
|
-
<Tour tours={demoTours} showSkipButton={false}>
|
|
235
|
-
<DemoLayout />
|
|
236
|
-
</Tour>
|
|
237
|
-
);
|
|
238
|
-
|
|
239
|
-
export const WithArrow = () => (
|
|
240
|
-
<Tour tours={demoTours} showArrow>
|
|
241
|
-
<DemoLayout />
|
|
242
|
-
</Tour>
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
export const WithBlur = () => (
|
|
246
|
-
<Tour tours={demoTours} spotlightBlur={4} spotlightOpacity={0.3}>
|
|
247
|
-
<DemoLayout />
|
|
248
|
-
</Tour>
|
|
249
|
-
);
|
|
250
|
-
|
|
251
|
-
export const WithArrowAndBlur = () => (
|
|
252
|
-
<Tour tours={demoTours} showArrow spotlightBlur={3} spotlightOpacity={0.4}>
|
|
253
|
-
<DemoLayout />
|
|
254
|
-
</Tour>
|
|
255
|
-
);
|
|
256
|
-
|
|
257
|
-
export const WithPulseRing = () => (
|
|
258
|
-
<Tour tours={demoTours} pulseRing>
|
|
259
|
-
<DemoLayout />
|
|
260
|
-
</Tour>
|
|
261
|
-
);
|
|
262
|
-
|
|
263
|
-
export const NoAnimation = () => (
|
|
264
|
-
<Tour tours={demoTours} animated={false}>
|
|
265
|
-
<DemoLayout />
|
|
266
|
-
</Tour>
|
|
267
|
-
);
|
|
268
|
-
|
|
269
|
-
export const FullFeatured = () => (
|
|
270
|
-
<Tour
|
|
271
|
-
tours={demoTours}
|
|
272
|
-
showArrow
|
|
273
|
-
spotlightBlur={2}
|
|
274
|
-
spotlightOpacity={0.4}
|
|
275
|
-
pulseRing
|
|
276
|
-
>
|
|
277
|
-
<DemoLayout />
|
|
278
|
-
</Tour>
|
|
279
|
-
);
|