@djangocfg/ui-nextjs 2.1.89 → 2.1.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/README.md +6 -15
  2. package/package.json +6 -25
  3. package/src/blocks/SplitHero/SplitHeroMedia.tsx +1 -1
  4. package/src/components/index.ts +0 -40
  5. package/src/hooks/index.ts +0 -6
  6. package/src/index.ts +2 -11
  7. package/src/components/button-download.tsx +0 -277
  8. package/src/components/markdown/MarkdownMessage.tsx +0 -340
  9. package/src/components/markdown/index.ts +0 -5
  10. package/src/components/menubar.tsx +0 -275
  11. package/src/components/multi-select-pro/async.tsx +0 -598
  12. package/src/components/multi-select-pro/helpers.tsx +0 -84
  13. package/src/components/multi-select-pro/index.tsx +0 -612
  14. package/src/components/navigation-menu.tsx +0 -154
  15. package/src/components/otp/index.tsx +0 -197
  16. package/src/components/otp/types.ts +0 -133
  17. package/src/components/otp/use-otp-input.ts +0 -225
  18. package/src/components/phone-input.tsx +0 -277
  19. package/src/components/sonner.tsx +0 -32
  20. package/src/hooks/useLocalStorage.ts +0 -300
  21. package/src/hooks/useSessionStorage.ts +0 -290
  22. package/src/lib/index.ts +0 -5
  23. package/src/lib/logger/index.ts +0 -10
  24. package/src/lib/logger/logStore.ts +0 -122
  25. package/src/lib/logger/logger.ts +0 -175
  26. package/src/lib/logger/types.ts +0 -82
  27. package/src/stores/index.ts +0 -8
  28. package/src/stores/mediaCache.ts +0 -534
  29. package/src/tools/AudioPlayer/README.md +0 -206
  30. package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +0 -216
  31. package/src/tools/AudioPlayer/components/HybridSimplePlayer.tsx +0 -280
  32. package/src/tools/AudioPlayer/components/HybridWaveform.tsx +0 -279
  33. package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +0 -149
  34. package/src/tools/AudioPlayer/components/ReactiveCover/effects/GlowEffect.tsx +0 -110
  35. package/src/tools/AudioPlayer/components/ReactiveCover/effects/MeshEffect.tsx +0 -58
  36. package/src/tools/AudioPlayer/components/ReactiveCover/effects/OrbsEffect.tsx +0 -45
  37. package/src/tools/AudioPlayer/components/ReactiveCover/effects/SpotlightEffect.tsx +0 -82
  38. package/src/tools/AudioPlayer/components/ReactiveCover/effects/index.ts +0 -8
  39. package/src/tools/AudioPlayer/components/ReactiveCover/index.ts +0 -6
  40. package/src/tools/AudioPlayer/components/index.ts +0 -22
  41. package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +0 -158
  42. package/src/tools/AudioPlayer/context/index.ts +0 -16
  43. package/src/tools/AudioPlayer/effects/index.ts +0 -412
  44. package/src/tools/AudioPlayer/hooks/index.ts +0 -35
  45. package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +0 -387
  46. package/src/tools/AudioPlayer/hooks/useHybridAudioAnalysis.ts +0 -95
  47. package/src/tools/AudioPlayer/hooks/useVisualization.tsx +0 -207
  48. package/src/tools/AudioPlayer/index.ts +0 -133
  49. package/src/tools/AudioPlayer/types/effects.ts +0 -73
  50. package/src/tools/AudioPlayer/types/index.ts +0 -27
  51. package/src/tools/AudioPlayer/utils/debug.ts +0 -14
  52. package/src/tools/AudioPlayer/utils/formatTime.ts +0 -10
  53. package/src/tools/AudioPlayer/utils/index.ts +0 -6
  54. package/src/tools/ImageViewer/@refactoring/00-PLAN.md +0 -71
  55. package/src/tools/ImageViewer/@refactoring/01-TYPES.md +0 -121
  56. package/src/tools/ImageViewer/@refactoring/02-UTILS.md +0 -143
  57. package/src/tools/ImageViewer/@refactoring/03-HOOKS.md +0 -261
  58. package/src/tools/ImageViewer/@refactoring/04-COMPONENTS.md +0 -427
  59. package/src/tools/ImageViewer/@refactoring/05-EXECUTION-CHECKLIST.md +0 -126
  60. package/src/tools/ImageViewer/README.md +0 -200
  61. package/src/tools/ImageViewer/components/ImageInfo.tsx +0 -44
  62. package/src/tools/ImageViewer/components/ImageToolbar.tsx +0 -150
  63. package/src/tools/ImageViewer/components/ImageViewer.tsx +0 -241
  64. package/src/tools/ImageViewer/components/index.ts +0 -7
  65. package/src/tools/ImageViewer/hooks/index.ts +0 -9
  66. package/src/tools/ImageViewer/hooks/useImageLoading.ts +0 -204
  67. package/src/tools/ImageViewer/hooks/useImageTransform.ts +0 -101
  68. package/src/tools/ImageViewer/index.ts +0 -60
  69. package/src/tools/ImageViewer/types.ts +0 -81
  70. package/src/tools/ImageViewer/utils/constants.ts +0 -59
  71. package/src/tools/ImageViewer/utils/debug.ts +0 -14
  72. package/src/tools/ImageViewer/utils/index.ts +0 -17
  73. package/src/tools/ImageViewer/utils/lqip.ts +0 -47
  74. package/src/tools/JsonForm/JsonSchemaForm.tsx +0 -197
  75. package/src/tools/JsonForm/examples/BotConfigExample.tsx +0 -249
  76. package/src/tools/JsonForm/examples/RealBotConfigExample.tsx +0 -161
  77. package/src/tools/JsonForm/index.ts +0 -46
  78. package/src/tools/JsonForm/templates/ArrayFieldItemTemplate.tsx +0 -47
  79. package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +0 -74
  80. package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +0 -107
  81. package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +0 -35
  82. package/src/tools/JsonForm/templates/FieldTemplate.tsx +0 -62
  83. package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +0 -116
  84. package/src/tools/JsonForm/templates/index.ts +0 -12
  85. package/src/tools/JsonForm/types.ts +0 -83
  86. package/src/tools/JsonForm/utils.ts +0 -213
  87. package/src/tools/JsonForm/widgets/CheckboxWidget.tsx +0 -37
  88. package/src/tools/JsonForm/widgets/ColorWidget.tsx +0 -219
  89. package/src/tools/JsonForm/widgets/NumberWidget.tsx +0 -89
  90. package/src/tools/JsonForm/widgets/SelectWidget.tsx +0 -97
  91. package/src/tools/JsonForm/widgets/SliderWidget.tsx +0 -148
  92. package/src/tools/JsonForm/widgets/SwitchWidget.tsx +0 -35
  93. package/src/tools/JsonForm/widgets/TextWidget.tsx +0 -96
  94. package/src/tools/JsonForm/widgets/index.ts +0 -14
  95. package/src/tools/JsonTree/index.tsx +0 -243
  96. package/src/tools/LottiePlayer/LottiePlayer.client.tsx +0 -213
  97. package/src/tools/LottiePlayer/index.tsx +0 -55
  98. package/src/tools/LottiePlayer/types.ts +0 -108
  99. package/src/tools/LottiePlayer/useLottie.ts +0 -164
  100. package/src/tools/Mermaid/Mermaid.client.tsx +0 -82
  101. package/src/tools/Mermaid/components/MermaidCodeViewer.tsx +0 -95
  102. package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +0 -103
  103. package/src/tools/Mermaid/hooks/index.ts +0 -4
  104. package/src/tools/Mermaid/hooks/useMermaidCleanup.ts +0 -73
  105. package/src/tools/Mermaid/hooks/useMermaidFullscreen.ts +0 -46
  106. package/src/tools/Mermaid/hooks/useMermaidRenderer.ts +0 -226
  107. package/src/tools/Mermaid/hooks/useMermaidValidation.ts +0 -29
  108. package/src/tools/Mermaid/index.tsx +0 -41
  109. package/src/tools/Mermaid/utils/mermaid-helpers.ts +0 -33
  110. package/src/tools/OpenapiViewer/components/EndpointInfo.tsx +0 -149
  111. package/src/tools/OpenapiViewer/components/EndpointsLibrary.tsx +0 -263
  112. package/src/tools/OpenapiViewer/components/PlaygroundLayout.tsx +0 -125
  113. package/src/tools/OpenapiViewer/components/PlaygroundStepper.tsx +0 -100
  114. package/src/tools/OpenapiViewer/components/RequestBuilder.tsx +0 -157
  115. package/src/tools/OpenapiViewer/components/RequestParametersForm.tsx +0 -253
  116. package/src/tools/OpenapiViewer/components/ResponseViewer.tsx +0 -173
  117. package/src/tools/OpenapiViewer/components/VersionSelector.tsx +0 -68
  118. package/src/tools/OpenapiViewer/components/index.ts +0 -14
  119. package/src/tools/OpenapiViewer/constants.ts +0 -39
  120. package/src/tools/OpenapiViewer/context/PlaygroundContext.tsx +0 -337
  121. package/src/tools/OpenapiViewer/hooks/index.ts +0 -8
  122. package/src/tools/OpenapiViewer/hooks/useMobile.ts +0 -10
  123. package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +0 -199
  124. package/src/tools/OpenapiViewer/index.tsx +0 -38
  125. package/src/tools/OpenapiViewer/types.ts +0 -151
  126. package/src/tools/OpenapiViewer/utils/apiKeyManager.ts +0 -149
  127. package/src/tools/OpenapiViewer/utils/formatters.ts +0 -71
  128. package/src/tools/OpenapiViewer/utils/index.ts +0 -9
  129. package/src/tools/OpenapiViewer/utils/versionManager.ts +0 -161
  130. package/src/tools/PrettyCode/PrettyCode.client.tsx +0 -208
  131. package/src/tools/PrettyCode/index.tsx +0 -45
  132. package/src/tools/VideoPlayer/@refactoring/00-PLAN.md +0 -91
  133. package/src/tools/VideoPlayer/@refactoring/01-TYPES.md +0 -284
  134. package/src/tools/VideoPlayer/@refactoring/02-UTILS.md +0 -141
  135. package/src/tools/VideoPlayer/@refactoring/03-HOOKS.md +0 -178
  136. package/src/tools/VideoPlayer/@refactoring/04-COMPONENTS.md +0 -95
  137. package/src/tools/VideoPlayer/@refactoring/05-EXECUTION-CHECKLIST.md +0 -139
  138. package/src/tools/VideoPlayer/README.md +0 -264
  139. package/src/tools/VideoPlayer/components/VideoControls.tsx +0 -138
  140. package/src/tools/VideoPlayer/components/VideoErrorFallback.tsx +0 -174
  141. package/src/tools/VideoPlayer/components/VideoPlayer.tsx +0 -201
  142. package/src/tools/VideoPlayer/components/index.ts +0 -14
  143. package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +0 -52
  144. package/src/tools/VideoPlayer/context/index.ts +0 -8
  145. package/src/tools/VideoPlayer/hooks/index.ts +0 -12
  146. package/src/tools/VideoPlayer/hooks/useVideoPlayerSettings.ts +0 -70
  147. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +0 -116
  148. package/src/tools/VideoPlayer/index.ts +0 -77
  149. package/src/tools/VideoPlayer/providers/NativeProvider.tsx +0 -284
  150. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +0 -505
  151. package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +0 -400
  152. package/src/tools/VideoPlayer/providers/index.ts +0 -8
  153. package/src/tools/VideoPlayer/types/index.ts +0 -38
  154. package/src/tools/VideoPlayer/types/player.ts +0 -116
  155. package/src/tools/VideoPlayer/types/provider.ts +0 -93
  156. package/src/tools/VideoPlayer/types/sources.ts +0 -97
  157. package/src/tools/VideoPlayer/utils/debug.ts +0 -14
  158. package/src/tools/VideoPlayer/utils/fileSource.ts +0 -78
  159. package/src/tools/VideoPlayer/utils/index.ts +0 -12
  160. package/src/tools/VideoPlayer/utils/resolvers.ts +0 -75
  161. package/src/tools/index.ts +0 -170
@@ -1,427 +0,0 @@
1
- # Phase 4: Components Extraction
2
-
3
- ## Goal
4
-
5
- Split the monolithic ImageViewer.tsx into separate component files.
6
-
7
- ## Files to Create
8
-
9
- ### components/ImageToolbar.tsx
10
-
11
- Floating toolbar with zoom/rotate/flip controls.
12
-
13
- ```typescript
14
- 'use client';
15
-
16
- /**
17
- * ImageToolbar - Floating toolbar for image controls
18
- */
19
-
20
- import { useCallback } from 'react';
21
- import { Button, cn } from '@djangocfg/ui-core';
22
- import {
23
- ZoomIn,
24
- ZoomOut,
25
- RotateCw,
26
- FlipHorizontal,
27
- FlipVertical,
28
- Maximize2,
29
- Expand,
30
- } from 'lucide-react';
31
- import {
32
- DropdownMenu,
33
- DropdownMenuContent,
34
- DropdownMenuItem,
35
- DropdownMenuTrigger,
36
- } from '../../components/dropdown-menu';
37
- import { useControls } from 'react-zoom-pan-pinch';
38
- import { ZOOM_PRESETS, MIN_ZOOM, MAX_ZOOM } from '../utils';
39
- import type { ImageToolbarProps } from '../types';
40
-
41
- export function ImageToolbar({
42
- scale,
43
- onExpand,
44
- onRotate,
45
- onFlipH,
46
- onFlipV,
47
- flipH,
48
- flipV,
49
- inDialog = false,
50
- }: ImageToolbarProps) {
51
- const { zoomIn, zoomOut, resetTransform, centerView, setTransform } = useControls();
52
-
53
- // Calculate zoom label
54
- const zoomLabel = `${Math.round(scale * 100)}%`;
55
-
56
- // Handle zoom preset selection
57
- const handleZoomPreset = useCallback(
58
- (value: number) => {
59
- if (value === -1) {
60
- // Fit to view
61
- resetTransform();
62
- } else {
63
- setTransform(0, 0, value);
64
- centerView(value);
65
- }
66
- },
67
- [resetTransform, setTransform, centerView]
68
- );
69
-
70
- return (
71
- <div className="absolute bottom-4 left-1/2 -translate-x-1/2 z-10 flex items-center gap-1 bg-background/95 backdrop-blur-sm border rounded-lg p-1.5 shadow-lg">
72
- {/* Zoom Out */}
73
- <Button
74
- variant="ghost"
75
- size="icon"
76
- className="h-8 w-8"
77
- onClick={() => zoomOut()}
78
- disabled={scale <= MIN_ZOOM}
79
- title="Zoom out"
80
- >
81
- <ZoomOut className="h-4 w-4" />
82
- </Button>
83
-
84
- {/* Zoom Dropdown */}
85
- <DropdownMenu>
86
- <DropdownMenuTrigger asChild>
87
- <Button variant="ghost" size="sm" className="h-8 min-w-16 px-2 font-mono text-xs">
88
- {zoomLabel}
89
- </Button>
90
- </DropdownMenuTrigger>
91
- <DropdownMenuContent align="center">
92
- {ZOOM_PRESETS.map((preset) => (
93
- <DropdownMenuItem
94
- key={preset.value}
95
- onClick={() => handleZoomPreset(preset.value)}
96
- >
97
- {preset.label}
98
- </DropdownMenuItem>
99
- ))}
100
- </DropdownMenuContent>
101
- </DropdownMenu>
102
-
103
- {/* Zoom In */}
104
- <Button
105
- variant="ghost"
106
- size="icon"
107
- className="h-8 w-8"
108
- onClick={() => zoomIn()}
109
- disabled={scale >= MAX_ZOOM}
110
- title="Zoom in"
111
- >
112
- <ZoomIn className="h-4 w-4" />
113
- </Button>
114
-
115
- <div className="w-px h-6 bg-border mx-1" />
116
-
117
- {/* Fit to View */}
118
- <Button
119
- variant="ghost"
120
- size="icon"
121
- className="h-8 w-8"
122
- onClick={() => resetTransform()}
123
- title="Fit to view"
124
- >
125
- <Maximize2 className="h-4 w-4" />
126
- </Button>
127
-
128
- {/* Rotate */}
129
- <Button
130
- variant="ghost"
131
- size="icon"
132
- className="h-8 w-8"
133
- onClick={onRotate}
134
- title="Rotate 90°"
135
- >
136
- <RotateCw className="h-4 w-4" />
137
- </Button>
138
-
139
- {/* Flip Horizontal */}
140
- <Button
141
- variant="ghost"
142
- size="icon"
143
- className={cn('h-8 w-8', flipH && 'bg-muted text-primary')}
144
- onClick={onFlipH}
145
- title="Flip horizontal"
146
- >
147
- <FlipHorizontal className="h-4 w-4" />
148
- </Button>
149
-
150
- {/* Flip Vertical */}
151
- <Button
152
- variant="ghost"
153
- size="icon"
154
- className={cn('h-8 w-8', flipV && 'bg-muted text-primary')}
155
- onClick={onFlipV}
156
- title="Flip vertical"
157
- >
158
- <FlipVertical className="h-4 w-4" />
159
- </Button>
160
-
161
- {/* Expand (hidden in dialog) */}
162
- {!inDialog && (
163
- <>
164
- <div className="w-px h-6 bg-border mx-1" />
165
- <Button
166
- variant="ghost"
167
- size="icon"
168
- className="h-8 w-8"
169
- onClick={onExpand}
170
- title="Expand fullscreen"
171
- >
172
- <Expand className="h-4 w-4" />
173
- </Button>
174
- </>
175
- )}
176
- </div>
177
- );
178
- }
179
- ```
180
-
181
- ### components/ImageInfo.tsx
182
-
183
- Displays image dimensions badge.
184
-
185
- ```typescript
186
- 'use client';
187
-
188
- /**
189
- * ImageInfo - Displays image dimensions
190
- */
191
-
192
- import { useEffect, useState } from 'react';
193
- import { useImageCache } from '../../../stores/mediaCache';
194
- import type { ImageInfoProps } from '../types';
195
-
196
- export function ImageInfo({ src, contentKey }: ImageInfoProps) {
197
- const { getDimensions, cacheDimensions } = useImageCache();
198
-
199
- const [dimensions, setDimensions] = useState<{ width: number; height: number } | null>(
200
- () => getDimensions(contentKey)
201
- );
202
-
203
- useEffect(() => {
204
- // Already have dimensions
205
- if (dimensions) return;
206
-
207
- // Load image to get dimensions
208
- const img = new Image();
209
- img.onload = () => {
210
- const dims = { width: img.naturalWidth, height: img.naturalHeight };
211
- cacheDimensions(contentKey, dims);
212
- setDimensions(dims);
213
- };
214
- img.src = src;
215
- }, [src, contentKey, dimensions, cacheDimensions]);
216
-
217
- if (!dimensions) return null;
218
-
219
- return (
220
- <div className="absolute top-2 right-2 z-10 px-2 py-1 text-xs font-mono bg-background/80 backdrop-blur-sm border rounded text-muted-foreground">
221
- {dimensions.width} × {dimensions.height}
222
- </div>
223
- );
224
- }
225
- ```
226
-
227
- ### components/ImageViewer.tsx
228
-
229
- Main component, now simplified.
230
-
231
- ```typescript
232
- 'use client';
233
-
234
- /**
235
- * ImageViewer - Image display with zoom/pan/rotate capabilities
236
- */
237
-
238
- import { useRef, useEffect, useCallback, useState } from 'react';
239
- import { TransformWrapper, TransformComponent, useControls } from 'react-zoom-pan-pinch';
240
- import { Dialog, DialogContent, Alert, AlertDescription, cn } from '@djangocfg/ui-core';
241
- import { AlertCircle, ImageIcon } from 'lucide-react';
242
-
243
- import { ImageToolbar } from './ImageToolbar';
244
- import { ImageInfo } from './ImageInfo';
245
- import { useImageTransform, useImageLoading } from '../hooks';
246
- import { MIN_ZOOM, MAX_ZOOM } from '../utils';
247
- import type { ImageViewerProps } from '../types';
248
-
249
- // Controls wrapper for accessing zoom state
250
- function ImageViewerContent({
251
- file,
252
- src,
253
- lqip,
254
- isLoading,
255
- isReady,
256
- contentKey,
257
- isLarge,
258
- transform,
259
- transformStyle,
260
- rotate,
261
- flipH,
262
- flipV,
263
- onExpand,
264
- inDialog,
265
- }: /* props type */) {
266
- const { zoomIn, zoomOut, resetTransform } = useControls();
267
- const [scale, setScale] = useState(1);
268
-
269
- // Keyboard shortcuts
270
- useEffect(() => {
271
- const handleKeyDown = (e: KeyboardEvent) => {
272
- if (e.key === '+' || e.key === '=') zoomIn();
273
- if (e.key === '-') zoomOut();
274
- if (e.key === '0') resetTransform();
275
- if (e.key === 'r' || e.key === 'R') rotate();
276
- };
277
-
278
- window.addEventListener('keydown', handleKeyDown);
279
- return () => window.removeEventListener('keydown', handleKeyDown);
280
- }, [zoomIn, zoomOut, resetTransform, rotate]);
281
-
282
- return (
283
- <>
284
- <ImageToolbar
285
- scale={scale}
286
- onExpand={onExpand}
287
- onRotate={rotate}
288
- onFlipH={flipH}
289
- onFlipV={flipV}
290
- flipH={transform.flipH}
291
- flipV={transform.flipV}
292
- inDialog={inDialog}
293
- />
294
-
295
- <ImageInfo src={src} contentKey={contentKey} />
296
-
297
- <TransformComponent wrapperClass="!w-full !h-full" contentClass="!w-full !h-full">
298
- <div className="relative w-full h-full flex items-center justify-center">
299
- {/* LQIP placeholder */}
300
- {isLarge && lqip && !isReady && (
301
- <img
302
- src={lqip}
303
- alt=""
304
- aria-hidden="true"
305
- className="absolute inset-0 w-full h-full object-contain blur-lg scale-105"
306
- />
307
- )}
308
-
309
- {/* Main image */}
310
- <img
311
- src={src}
312
- alt={file.name}
313
- className={cn(
314
- 'max-w-full max-h-full object-contain transition-opacity',
315
- isLoading && 'opacity-50'
316
- )}
317
- style={{ transform: transformStyle }}
318
- draggable={false}
319
- />
320
- </div>
321
- </TransformComponent>
322
- </>
323
- );
324
- }
325
-
326
- export function ImageViewer({ file, content, inDialog = false }: ImageViewerProps) {
327
- const [dialogOpen, setDialogOpen] = useState(false);
328
-
329
- // Loading state
330
- const {
331
- src,
332
- lqip,
333
- isLoading,
334
- isReady,
335
- error,
336
- contentKey,
337
- isOversized,
338
- isLarge,
339
- } = useImageLoading({ content, mimeType: file.mimeType });
340
-
341
- // Transform state
342
- const { transform, rotate, flipH, flipV, transformStyle } = useImageTransform({
343
- resetKey: file.path,
344
- });
345
-
346
- // Error state
347
- if (error || isOversized) {
348
- return (
349
- <Alert variant="destructive">
350
- <AlertCircle className="h-4 w-4" />
351
- <AlertDescription>{error || 'Image too large to display'}</AlertDescription>
352
- </Alert>
353
- );
354
- }
355
-
356
- // Loading state (no src yet)
357
- if (!src) {
358
- return (
359
- <div className="flex items-center justify-center h-64 bg-muted/30">
360
- <ImageIcon className="h-8 w-8 text-muted-foreground animate-pulse" />
361
- </div>
362
- );
363
- }
364
-
365
- const viewer = (
366
- <TransformWrapper
367
- initialScale={1}
368
- minScale={MIN_ZOOM}
369
- maxScale={MAX_ZOOM}
370
- centerOnInit
371
- limitToBounds={false}
372
- onTransformed={(_, state) => {/* update scale */}}
373
- >
374
- <ImageViewerContent
375
- file={file}
376
- src={src}
377
- lqip={lqip}
378
- isLoading={isLoading}
379
- isReady={isReady}
380
- contentKey={contentKey}
381
- isLarge={isLarge}
382
- transform={transform}
383
- transformStyle={transformStyle}
384
- rotate={rotate}
385
- flipH={flipH}
386
- flipV={flipV}
387
- onExpand={() => setDialogOpen(true)}
388
- inDialog={inDialog}
389
- />
390
- </TransformWrapper>
391
- );
392
-
393
- return (
394
- <>
395
- <div className="relative w-full h-[400px] overflow-hidden bg-checkerboard rounded-lg">
396
- {viewer}
397
- </div>
398
-
399
- {/* Fullscreen dialog */}
400
- <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
401
- <DialogContent className="max-w-[95vw] max-h-[95vh] p-0">
402
- <ImageViewer file={file} content={content} inDialog />
403
- </DialogContent>
404
- </Dialog>
405
- </>
406
- );
407
- }
408
- ```
409
-
410
- ### components/index.ts
411
-
412
- ```typescript
413
- /**
414
- * ImageViewer components - Public API
415
- */
416
-
417
- export { ImageViewer } from './ImageViewer';
418
- export { ImageToolbar } from './ImageToolbar';
419
- export { ImageInfo } from './ImageInfo';
420
- ```
421
-
422
- ## Notes
423
-
424
- - ImageToolbar uses `useControls` from react-zoom-pan-pinch
425
- - ImageInfo caches dimensions for performance
426
- - Main component orchestrates everything
427
- - Fullscreen dialog renders nested ImageViewer with `inDialog` flag
@@ -1,126 +0,0 @@
1
- # Execution Checklist
2
-
3
- ## Pre-flight
4
-
5
- - [ ] Read current ImageViewer.tsx
6
- - [ ] Backup or rename original file
7
- - [ ] Create folder structure
8
-
9
- ## Phase 1: Folder Structure
10
-
11
- - [ ] Create `components/` directory
12
- - [ ] Create `hooks/` directory
13
- - [ ] Create `utils/` directory
14
-
15
- ```bash
16
- mkdir -p components hooks utils
17
- ```
18
-
19
- ## Phase 2: Types
20
-
21
- - [ ] Create `types.ts` with all interfaces
22
- - ImageFile
23
- - ImageViewerProps
24
- - ImageTransform
25
- - ZoomPreset
26
- - ImageToolbarProps
27
- - ImageInfoProps
28
- - [ ] Run `pnpm check`
29
-
30
- ## Phase 3: Utils
31
-
32
- - [ ] Create `utils/constants.ts`
33
- - MAX_IMAGE_SIZE, WARN_IMAGE_SIZE
34
- - MIN_ZOOM, MAX_ZOOM
35
- - ZOOM_PRESETS
36
- - DEFAULT_TRANSFORM
37
- - [ ] Create `utils/lqip.ts`
38
- - createLQIP function
39
- - [ ] Create `utils/index.ts`
40
- - Re-export all
41
- - [ ] Run `pnpm check`
42
-
43
- ## Phase 4: Hooks
44
-
45
- - [ ] Create `hooks/useImageTransform.ts`
46
- - Transform state management
47
- - rotate, flipH, flipV callbacks
48
- - transformStyle computed value
49
- - [ ] Create `hooks/useImageLoading.ts`
50
- - Blob URL management
51
- - LQIP generation
52
- - Loading/error states
53
- - [ ] Create `hooks/index.ts`
54
- - Re-export all
55
- - [ ] Run `pnpm check`
56
-
57
- ## Phase 5: Components
58
-
59
- - [ ] Create `components/ImageToolbar.tsx`
60
- - Zoom controls
61
- - Rotate/flip buttons
62
- - Preset dropdown
63
- - [ ] Create `components/ImageInfo.tsx`
64
- - Dimensions display
65
- - [ ] Create `components/ImageViewer.tsx`
66
- - Main component (simplified)
67
- - Uses hooks
68
- - Includes fullscreen dialog
69
- - [ ] Create `components/index.ts`
70
- - Re-export all
71
- - [ ] Run `pnpm check`
72
-
73
- ## Phase 6: Main Index
74
-
75
- - [ ] Update `index.ts` with new imports
76
- - Export ImageViewer from components
77
- - Export types
78
- - Export hooks (if public)
79
- - [ ] Run `pnpm check`
80
-
81
- ## Phase 7: Cleanup
82
-
83
- - [ ] Delete old `ImageViewer.tsx`
84
- - [ ] Verify all exports work
85
- - [ ] Run `pnpm check`
86
- - [ ] Run `pnpm build` (optional)
87
-
88
- ## Post-flight
89
-
90
- - [ ] Test in browser
91
- - [ ] Verify zoom/pan/rotate work
92
- - [ ] Verify fullscreen works
93
- - [ ] Verify LQIP loads for large images
94
- - [ ] Verify error states display
95
-
96
- ## Final Structure
97
-
98
- ```
99
- ImageViewer/
100
- ├── index.ts
101
- ├── types.ts
102
- ├── README.md
103
- ├── components/
104
- │ ├── index.ts
105
- │ ├── ImageViewer.tsx
106
- │ ├── ImageToolbar.tsx
107
- │ └── ImageInfo.tsx
108
- ├── hooks/
109
- │ ├── index.ts
110
- │ ├── useImageTransform.ts
111
- │ └── useImageLoading.ts
112
- └── utils/
113
- ├── index.ts
114
- ├── constants.ts
115
- └── lqip.ts
116
- ```
117
-
118
- ## Metrics
119
-
120
- | Metric | Before | After |
121
- |--------|--------|-------|
122
- | Main file lines | 589 | ~150 |
123
- | Total files | 3 | 12 |
124
- | Sub-components | 2 inline | 2 separate |
125
- | Custom hooks | 0 | 2 |
126
- | Utility files | 0 | 2 |