@djangocfg/ui-nextjs 2.1.65 → 2.1.67

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 (92) hide show
  1. package/package.json +13 -8
  2. package/src/blocks/SplitHero/SplitHeroMedia.tsx +2 -1
  3. package/src/stores/index.ts +8 -0
  4. package/src/stores/mediaCache.ts +464 -0
  5. package/src/tools/AudioPlayer/@refactoring/00-PLAN.md +148 -0
  6. package/src/tools/AudioPlayer/@refactoring/01-TYPES.md +301 -0
  7. package/src/tools/AudioPlayer/@refactoring/02-HOOKS.md +281 -0
  8. package/src/tools/AudioPlayer/@refactoring/03-CONTEXT.md +328 -0
  9. package/src/tools/AudioPlayer/@refactoring/04-COMPONENTS.md +251 -0
  10. package/src/tools/AudioPlayer/@refactoring/05-EFFECTS.md +427 -0
  11. package/src/tools/AudioPlayer/@refactoring/06-UTILS-AND-INDEX.md +193 -0
  12. package/src/tools/AudioPlayer/@refactoring/07-EXECUTION-CHECKLIST.md +146 -0
  13. package/src/tools/AudioPlayer/README.md +325 -0
  14. package/src/tools/AudioPlayer/components/AudioEqualizer.tsx +200 -0
  15. package/src/tools/AudioPlayer/components/AudioPlayer.tsx +231 -0
  16. package/src/tools/AudioPlayer/components/AudioShortcutsPopover.tsx +99 -0
  17. package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +147 -0
  18. package/src/tools/AudioPlayer/components/ReactiveCover/effects/GlowEffect.tsx +110 -0
  19. package/src/tools/AudioPlayer/components/ReactiveCover/effects/MeshEffect.tsx +58 -0
  20. package/src/tools/AudioPlayer/components/ReactiveCover/effects/OrbsEffect.tsx +45 -0
  21. package/src/tools/AudioPlayer/components/ReactiveCover/effects/SpotlightEffect.tsx +82 -0
  22. package/src/tools/AudioPlayer/components/ReactiveCover/effects/index.ts +8 -0
  23. package/src/tools/AudioPlayer/components/ReactiveCover/index.ts +6 -0
  24. package/src/tools/AudioPlayer/components/SimpleAudioPlayer.tsx +280 -0
  25. package/src/tools/AudioPlayer/components/VisualizationToggle.tsx +64 -0
  26. package/src/tools/AudioPlayer/components/index.ts +21 -0
  27. package/src/tools/AudioPlayer/context/AudioProvider.tsx +292 -0
  28. package/src/tools/AudioPlayer/context/index.ts +11 -0
  29. package/src/tools/AudioPlayer/context/selectors.ts +96 -0
  30. package/src/tools/AudioPlayer/effects/index.ts +412 -0
  31. package/src/tools/AudioPlayer/hooks/index.ts +29 -0
  32. package/src/tools/AudioPlayer/hooks/useAudioAnalysis.ts +110 -0
  33. package/src/tools/AudioPlayer/hooks/useAudioHotkeys.ts +149 -0
  34. package/src/tools/AudioPlayer/hooks/useSharedWebAudio.ts +106 -0
  35. package/src/tools/AudioPlayer/hooks/useVisualization.tsx +201 -0
  36. package/src/tools/AudioPlayer/index.ts +139 -0
  37. package/src/tools/AudioPlayer/types/audio.ts +107 -0
  38. package/src/tools/AudioPlayer/types/components.ts +98 -0
  39. package/src/tools/AudioPlayer/types/effects.ts +73 -0
  40. package/src/tools/AudioPlayer/types/index.ts +35 -0
  41. package/src/tools/AudioPlayer/utils/formatTime.ts +10 -0
  42. package/src/tools/AudioPlayer/utils/index.ts +5 -0
  43. package/src/tools/ImageViewer/@refactoring/00-PLAN.md +71 -0
  44. package/src/tools/ImageViewer/@refactoring/01-TYPES.md +121 -0
  45. package/src/tools/ImageViewer/@refactoring/02-UTILS.md +143 -0
  46. package/src/tools/ImageViewer/@refactoring/03-HOOKS.md +261 -0
  47. package/src/tools/ImageViewer/@refactoring/04-COMPONENTS.md +427 -0
  48. package/src/tools/ImageViewer/@refactoring/05-EXECUTION-CHECKLIST.md +126 -0
  49. package/src/tools/ImageViewer/README.md +174 -0
  50. package/src/tools/ImageViewer/components/ImageInfo.tsx +44 -0
  51. package/src/tools/ImageViewer/components/ImageToolbar.tsx +150 -0
  52. package/src/tools/ImageViewer/components/ImageViewer.tsx +235 -0
  53. package/src/tools/ImageViewer/components/index.ts +7 -0
  54. package/src/tools/ImageViewer/hooks/index.ts +9 -0
  55. package/src/tools/ImageViewer/hooks/useImageLoading.ts +153 -0
  56. package/src/tools/ImageViewer/hooks/useImageTransform.ts +101 -0
  57. package/src/tools/ImageViewer/index.ts +60 -0
  58. package/src/tools/ImageViewer/types.ts +75 -0
  59. package/src/tools/ImageViewer/utils/constants.ts +59 -0
  60. package/src/tools/ImageViewer/utils/index.ts +16 -0
  61. package/src/tools/ImageViewer/utils/lqip.ts +47 -0
  62. package/src/tools/VideoPlayer/@refactoring/00-PLAN.md +91 -0
  63. package/src/tools/VideoPlayer/@refactoring/01-TYPES.md +284 -0
  64. package/src/tools/VideoPlayer/@refactoring/02-UTILS.md +141 -0
  65. package/src/tools/VideoPlayer/@refactoring/03-HOOKS.md +178 -0
  66. package/src/tools/VideoPlayer/@refactoring/04-COMPONENTS.md +95 -0
  67. package/src/tools/VideoPlayer/@refactoring/05-EXECUTION-CHECKLIST.md +139 -0
  68. package/src/tools/VideoPlayer/README.md +212 -187
  69. package/src/tools/VideoPlayer/{VideoControls.tsx → components/VideoControls.tsx} +8 -9
  70. package/src/tools/VideoPlayer/components/VideoErrorFallback.tsx +174 -0
  71. package/src/tools/VideoPlayer/components/VideoPlayer.tsx +201 -0
  72. package/src/tools/VideoPlayer/components/index.ts +14 -0
  73. package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +52 -0
  74. package/src/tools/VideoPlayer/context/index.ts +8 -0
  75. package/src/tools/VideoPlayer/hooks/index.ts +9 -0
  76. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +109 -0
  77. package/src/tools/VideoPlayer/index.ts +70 -9
  78. package/src/tools/VideoPlayer/providers/NativeProvider.tsx +206 -0
  79. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +401 -0
  80. package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +332 -0
  81. package/src/tools/VideoPlayer/providers/index.ts +8 -0
  82. package/src/tools/VideoPlayer/types/index.ts +38 -0
  83. package/src/tools/VideoPlayer/types/player.ts +116 -0
  84. package/src/tools/VideoPlayer/types/provider.ts +93 -0
  85. package/src/tools/VideoPlayer/types/sources.ts +97 -0
  86. package/src/tools/VideoPlayer/utils/fileSource.ts +78 -0
  87. package/src/tools/VideoPlayer/utils/index.ts +11 -0
  88. package/src/tools/VideoPlayer/utils/resolvers.ts +75 -0
  89. package/src/tools/index.ts +92 -4
  90. package/src/tools/VideoPlayer/NativePlayer.tsx +0 -141
  91. package/src/tools/VideoPlayer/VideoPlayer.tsx +0 -231
  92. package/src/tools/VideoPlayer/types.ts +0 -118
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Effect-related types for audio-reactive visualizations
3
+ */
4
+
5
+ // =============================================================================
6
+ // EFFECT TYPES
7
+ // =============================================================================
8
+
9
+ export type EffectVariant = 'glow' | 'orbs' | 'spotlight' | 'mesh';
10
+ export type EffectIntensity = 'subtle' | 'medium' | 'strong';
11
+ export type EffectColorScheme = 'primary' | 'vibrant' | 'cool' | 'warm';
12
+
13
+ export interface AudioLevels {
14
+ bass: number;
15
+ mid: number;
16
+ high: number;
17
+ overall: number;
18
+ }
19
+
20
+ export interface EffectConfig {
21
+ opacity: number;
22
+ scale: number;
23
+ blur: string;
24
+ }
25
+
26
+ export interface EffectColors {
27
+ colors: string[];
28
+ hueShift: number;
29
+ }
30
+
31
+ export interface EffectLayer {
32
+ inset: number;
33
+ opacity: number;
34
+ scale: number;
35
+ background: string;
36
+ blur: string;
37
+ animation?: string;
38
+ }
39
+
40
+ export interface Orb {
41
+ x: number;
42
+ y: number;
43
+ size: number;
44
+ color: string;
45
+ opacity: number;
46
+ scale: number;
47
+ }
48
+
49
+ export interface MeshGradient {
50
+ width: string;
51
+ height: string;
52
+ top?: string;
53
+ bottom?: string;
54
+ left?: string;
55
+ right?: string;
56
+ color: string;
57
+ opacity: number;
58
+ scale: number;
59
+ rotation: number;
60
+ blur: string;
61
+ isCenter?: boolean;
62
+ }
63
+
64
+ export interface SpotlightData {
65
+ rotation: number;
66
+ inset: number;
67
+ colors: Array<{ color: string; opacity: number }>;
68
+ pulseInset: number;
69
+ pulseOpacity: number;
70
+ pulseScale: number;
71
+ ringOpacity: number;
72
+ ringScale: number;
73
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * AudioPlayer types - re-exports all types
3
+ */
4
+
5
+ // Audio types
6
+ export type {
7
+ AudioSource,
8
+ PlaybackStatus,
9
+ WaveformOptions,
10
+ EqualizerOptions,
11
+ SharedWebAudioContext,
12
+ AudioContextState,
13
+ } from './audio';
14
+
15
+ // Component props
16
+ export type {
17
+ AudioPlayerProps,
18
+ AudioEqualizerProps,
19
+ AudioReactiveCoverProps,
20
+ AudioViewerProps,
21
+ } from './components';
22
+
23
+ // Effect types
24
+ export type {
25
+ EffectVariant,
26
+ EffectIntensity,
27
+ EffectColorScheme,
28
+ AudioLevels,
29
+ EffectConfig,
30
+ EffectColors,
31
+ EffectLayer,
32
+ Orb,
33
+ MeshGradient,
34
+ SpotlightData,
35
+ } from './effects';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * formatTime - Format seconds to mm:ss string
3
+ */
4
+
5
+ export function formatTime(seconds: number): string {
6
+ if (!seconds || !isFinite(seconds) || seconds < 0) return '0:00';
7
+ const mins = Math.floor(seconds / 60);
8
+ const secs = Math.floor(seconds % 60);
9
+ return `${mins}:${secs.toString().padStart(2, '0')}`;
10
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * AudioPlayer utilities - Public API
3
+ */
4
+
5
+ export { formatTime } from './formatTime';
@@ -0,0 +1,71 @@
1
+ # ImageViewer Refactoring Plan
2
+
3
+ ## Overview
4
+
5
+ Decompose the monolithic 589-line `ImageViewer.tsx` into a well-organized module structure similar to AudioPlayer.
6
+
7
+ ## Current Structure (Before)
8
+
9
+ ```
10
+ ImageViewer/
11
+ ├── ImageViewer.tsx (589 lines) - Everything in one file
12
+ ├── index.ts (16 lines)
13
+ └── README.md
14
+ ```
15
+
16
+ **Issues:**
17
+ - Single 589-line file with mixed concerns
18
+ - 2 sub-components inline (ImageToolbar, ImageInfo)
19
+ - 1 utility function inline (createLQIP)
20
+ - 8 separate useState calls
21
+ - Types defined inline
22
+ - Constants hardcoded
23
+
24
+ ## Target Structure (After)
25
+
26
+ ```
27
+ ImageViewer/
28
+ ├── index.ts # Public API
29
+ ├── README.md # Documentation
30
+ ├── components/
31
+ │ ├── index.ts
32
+ │ ├── ImageViewer.tsx # Main component (~150 lines)
33
+ │ ├── ImageToolbar.tsx # Toolbar with zoom/rotate/flip (~130 lines)
34
+ │ └── ImageInfo.tsx # Dimensions display (~35 lines)
35
+ ├── hooks/
36
+ │ ├── index.ts
37
+ │ ├── useImageTransform.ts # Rotation/flip state management
38
+ │ └── useImageLoading.ts # LQIP and loading state
39
+ ├── utils/
40
+ │ ├── index.ts
41
+ │ ├── lqip.ts # LQIP generator utility
42
+ │ └── constants.ts # Zoom presets, size limits
43
+ └── types.ts # All type definitions
44
+ ```
45
+
46
+ ## Benefits
47
+
48
+ 1. **Separation of Concerns** - Each file has single responsibility
49
+ 2. **Testability** - Hooks and utils can be unit tested independently
50
+ 3. **Reusability** - Components can be used standalone
51
+ 4. **Maintainability** - Easier to find and modify specific functionality
52
+ 5. **Code Organization** - Consistent with AudioPlayer structure
53
+
54
+ ## Execution Phases
55
+
56
+ | Phase | Description | Files |
57
+ |-------|-------------|-------|
58
+ | 1 | Create folder structure | components/, hooks/, utils/ |
59
+ | 2 | Extract types | types.ts |
60
+ | 3 | Extract constants and utilities | utils/constants.ts, utils/lqip.ts |
61
+ | 4 | Extract hooks | hooks/useImageTransform.ts, hooks/useImageLoading.ts |
62
+ | 5 | Split components | ImageToolbar.tsx, ImageInfo.tsx |
63
+ | 6 | Refactor main component | ImageViewer.tsx (simplified) |
64
+ | 7 | Update exports | index.ts, components/index.ts, hooks/index.ts |
65
+ | 8 | Cleanup and verify | Delete old file, run pnpm check |
66
+
67
+ ## Risk Assessment
68
+
69
+ - **Low Risk**: Pure extraction with no logic changes
70
+ - **Testing**: Run `pnpm check` after each phase
71
+ - **Rollback**: Keep old file until verification complete
@@ -0,0 +1,121 @@
1
+ # Phase 1: Types Extraction
2
+
3
+ ## Goal
4
+
5
+ Extract all type definitions from ImageViewer.tsx into a dedicated types.ts file.
6
+
7
+ ## Types to Extract
8
+
9
+ ### ImageFile (Props)
10
+ ```typescript
11
+ export interface ImageFile {
12
+ /** Display name for the image */
13
+ name: string;
14
+ /** File path used for change detection and caching */
15
+ path: string;
16
+ /** Optional MIME type */
17
+ mimeType?: string;
18
+ }
19
+ ```
20
+
21
+ ### ImageViewerProps (Props)
22
+ ```typescript
23
+ export interface ImageViewerProps {
24
+ /** Image file metadata */
25
+ file: ImageFile;
26
+ /** Image content as string or ArrayBuffer */
27
+ content: string | ArrayBuffer;
28
+ /** Whether viewer is inside a dialog (hides expand button) */
29
+ inDialog?: boolean;
30
+ }
31
+ ```
32
+
33
+ ### ImageTransform (State)
34
+ ```typescript
35
+ export interface ImageTransform {
36
+ /** Rotation angle: 0, 90, 180, or 270 degrees */
37
+ rotation: number;
38
+ /** Horizontal flip state */
39
+ flipH: boolean;
40
+ /** Vertical flip state */
41
+ flipV: boolean;
42
+ }
43
+ ```
44
+
45
+ ### ZoomPreset (UI)
46
+ ```typescript
47
+ export interface ZoomPreset {
48
+ /** Zoom level (1 = 100%) */
49
+ value: number;
50
+ /** Display label (e.g., "100%") */
51
+ label: string;
52
+ }
53
+ ```
54
+
55
+ ### ImageToolbarProps (Internal)
56
+ ```typescript
57
+ export interface ImageToolbarProps {
58
+ /** Current zoom scale */
59
+ scale: number;
60
+ /** Expand to fullscreen callback */
61
+ onExpand: () => void;
62
+ /** Rotate image callback */
63
+ onRotate: () => void;
64
+ /** Flip horizontal callback */
65
+ onFlipH: () => void;
66
+ /** Flip vertical callback */
67
+ onFlipV: () => void;
68
+ /** Whether horizontal flip is active */
69
+ flipH: boolean;
70
+ /** Whether vertical flip is active */
71
+ flipV: boolean;
72
+ /** Whether inside dialog (hides expand) */
73
+ inDialog?: boolean;
74
+ }
75
+ ```
76
+
77
+ ### ImageInfoProps (Internal)
78
+ ```typescript
79
+ export interface ImageInfoProps {
80
+ /** Blob URL source of the image */
81
+ src: string;
82
+ /** Content key for cache lookup */
83
+ contentKey: string;
84
+ }
85
+ ```
86
+
87
+ ## File Structure
88
+
89
+ ```typescript
90
+ // types.ts
91
+
92
+ /**
93
+ * ImageViewer type definitions
94
+ */
95
+
96
+ // =============================================================================
97
+ // FILE TYPES
98
+ // =============================================================================
99
+
100
+ export interface ImageFile { ... }
101
+
102
+ // =============================================================================
103
+ // COMPONENT PROPS
104
+ // =============================================================================
105
+
106
+ export interface ImageViewerProps { ... }
107
+ export interface ImageToolbarProps { ... }
108
+ export interface ImageInfoProps { ... }
109
+
110
+ // =============================================================================
111
+ // STATE TYPES
112
+ // =============================================================================
113
+
114
+ export interface ImageTransform { ... }
115
+
116
+ // =============================================================================
117
+ // UI TYPES
118
+ // =============================================================================
119
+
120
+ export interface ZoomPreset { ... }
121
+ ```
@@ -0,0 +1,143 @@
1
+ # Phase 2: Utils Extraction
2
+
3
+ ## Goal
4
+
5
+ Extract constants and utility functions into dedicated files.
6
+
7
+ ## Files to Create
8
+
9
+ ### utils/constants.ts
10
+
11
+ ```typescript
12
+ /**
13
+ * ImageViewer constants
14
+ */
15
+
16
+ import type { ZoomPreset } from '../types';
17
+
18
+ // =============================================================================
19
+ // SIZE LIMITS
20
+ // =============================================================================
21
+
22
+ /** Maximum image size before blocking (50MB) */
23
+ export const MAX_IMAGE_SIZE = 50 * 1024 * 1024;
24
+
25
+ /** Image size threshold for warning (10MB) */
26
+ export const WARN_IMAGE_SIZE = 10 * 1024 * 1024;
27
+
28
+ // =============================================================================
29
+ // ZOOM CONFIGURATION
30
+ // =============================================================================
31
+
32
+ /** Minimum zoom level */
33
+ export const MIN_ZOOM = 0.25;
34
+
35
+ /** Maximum zoom level */
36
+ export const MAX_ZOOM = 4;
37
+
38
+ /** Available zoom presets */
39
+ export const ZOOM_PRESETS: ZoomPreset[] = [
40
+ { value: 0.25, label: '25%' },
41
+ { value: 0.5, label: '50%' },
42
+ { value: 1, label: '100%' },
43
+ { value: 2, label: '200%' },
44
+ { value: 4, label: '400%' },
45
+ { value: -1, label: 'Fit' }, // Special value for fit-to-view
46
+ ];
47
+
48
+ // =============================================================================
49
+ // DEFAULT VALUES
50
+ // =============================================================================
51
+
52
+ /** Default transform state */
53
+ export const DEFAULT_TRANSFORM: ImageTransform = {
54
+ rotation: 0,
55
+ flipH: false,
56
+ flipV: false,
57
+ };
58
+ ```
59
+
60
+ ### utils/lqip.ts
61
+
62
+ ```typescript
63
+ /**
64
+ * LQIP (Low-Quality Image Placeholder) generator
65
+ *
66
+ * Creates a tiny blurred preview image for progressive loading.
67
+ */
68
+
69
+ // =============================================================================
70
+ // CONSTANTS
71
+ // =============================================================================
72
+
73
+ const LQIP_SIZE = 32;
74
+ const LQIP_QUALITY = 0.5;
75
+
76
+ // =============================================================================
77
+ // GENERATOR
78
+ // =============================================================================
79
+
80
+ /**
81
+ * Create a low-quality image placeholder from source URL
82
+ *
83
+ * @param src - Full quality image URL
84
+ * @returns Data URL of tiny preview, or null on error
85
+ */
86
+ export async function createLQIP(src: string): Promise<string | null> {
87
+ return new Promise((resolve) => {
88
+ const img = new Image();
89
+
90
+ img.onload = () => {
91
+ try {
92
+ // Calculate aspect-preserving dimensions
93
+ const aspectRatio = img.width / img.height;
94
+ const width = aspectRatio >= 1 ? LQIP_SIZE : Math.round(LQIP_SIZE * aspectRatio);
95
+ const height = aspectRatio >= 1 ? Math.round(LQIP_SIZE / aspectRatio) : LQIP_SIZE;
96
+
97
+ // Create tiny canvas
98
+ const canvas = document.createElement('canvas');
99
+ canvas.width = width;
100
+ canvas.height = height;
101
+
102
+ // Draw and export as JPEG
103
+ const ctx = canvas.getContext('2d');
104
+ if (ctx) {
105
+ ctx.drawImage(img, 0, 0, width, height);
106
+ resolve(canvas.toDataURL('image/jpeg', LQIP_QUALITY));
107
+ } else {
108
+ resolve(null);
109
+ }
110
+ } catch {
111
+ resolve(null);
112
+ }
113
+ };
114
+
115
+ img.onerror = () => resolve(null);
116
+ img.src = src;
117
+ });
118
+ }
119
+ ```
120
+
121
+ ### utils/index.ts
122
+
123
+ ```typescript
124
+ /**
125
+ * ImageViewer utilities - Public API
126
+ */
127
+
128
+ export { createLQIP } from './lqip';
129
+ export {
130
+ MAX_IMAGE_SIZE,
131
+ WARN_IMAGE_SIZE,
132
+ MIN_ZOOM,
133
+ MAX_ZOOM,
134
+ ZOOM_PRESETS,
135
+ DEFAULT_TRANSFORM,
136
+ } from './constants';
137
+ ```
138
+
139
+ ## Notes
140
+
141
+ - Constants are separated for easy modification
142
+ - LQIP is async and handles errors gracefully
143
+ - No dependencies on React in utils