@yogiswara/honcho-editor-ui 3.3.4 → 3.4.0
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/components/editor/GalleryAlbum/AlbumImageGallery.d.ts +14 -7
- package/dist/components/editor/GalleryAlbum/AlbumImageGallery.js +207 -5
- package/dist/components/editor/GalleryAlbum/ImageItemComponents.d.ts +25 -0
- package/dist/components/editor/GalleryAlbum/ImageItemComponents.js +179 -0
- package/dist/components/editor/GalleryAlbum/colorsGallery.d.ts +9 -0
- package/dist/components/editor/GalleryAlbum/colorsGallery.js +9 -0
- package/dist/components/editor/GalleryAlbum/svg/Tick.d.ts +2 -0
- package/dist/components/editor/GalleryAlbum/svg/Tick.js +6 -0
- package/dist/components/editor/HBulkAccordionColorAdjustment.js +1 -2
- package/dist/components/editor/HBulkAccordionColorAdjustmentColors.js +1 -1
- package/dist/components/editor/HBulkPresetMobile.d.ts +2 -2
- package/dist/components/editor/HBulkPresetMobile.js +2 -2
- package/dist/components/editor/HImageEditorBulkMobile.d.ts +2 -2
- package/dist/hooks/demo/HonchoEditorBulkDemo.d.ts +0 -3
- package/dist/hooks/demo/HonchoEditorBulkDemo.js +770 -411
- package/dist/hooks/demo/HonchoEditorSingleCleanDemo.d.ts +0 -3
- package/dist/hooks/demo/HonchoEditorSingleCleanDemo.js +882 -354
- package/dist/hooks/demo/index.d.ts +0 -2
- package/dist/hooks/demo/index.js +3 -2
- package/dist/hooks/editor/type.d.ts +15 -13
- package/dist/hooks/editor/useHonchoEditorBulk.d.ts +47 -5
- package/dist/hooks/editor/useHonchoEditorBulk.js +252 -133
- package/dist/hooks/useAdjustmentHistory.js +12 -12
- package/dist/hooks/useAdjustmentHistoryBatch.d.ts +33 -31
- package/dist/hooks/useAdjustmentHistoryBatch.js +703 -170
- package/dist/hooks/usePreset.js +12 -12
- package/dist/index.d.ts +5 -7
- package/dist/index.js +5 -4
- package/dist/services/type.d.ts +14 -0
- package/dist/utils/adjustment.d.ts +1 -1
- package/dist/utils/adjustment.js +15 -14
- package/dist/utils/logger.d.ts +3 -0
- package/dist/utils/logger.js +11 -0
- package/package.json +4 -2
|
@@ -1,354 +1,882 @@
|
|
|
1
|
-
|
|
2
|
-
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
};
|
|
187
|
-
//
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
// import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
3
|
+
// import {
|
|
4
|
+
// Box,
|
|
5
|
+
// Container,
|
|
6
|
+
// Typography,
|
|
7
|
+
// Button,
|
|
8
|
+
// Card,
|
|
9
|
+
// CardMedia,
|
|
10
|
+
// CardContent,
|
|
11
|
+
// Alert,
|
|
12
|
+
// CircularProgress,
|
|
13
|
+
// Paper,
|
|
14
|
+
// Divider,
|
|
15
|
+
// TextField,
|
|
16
|
+
// Stack,
|
|
17
|
+
// Slider,
|
|
18
|
+
// Grid,
|
|
19
|
+
// IconButton,
|
|
20
|
+
// Tooltip,
|
|
21
|
+
// } from '@mui/material';
|
|
22
|
+
// import {
|
|
23
|
+
// NavigateBefore,
|
|
24
|
+
// NavigateNext,
|
|
25
|
+
// Undo,
|
|
26
|
+
// Redo,
|
|
27
|
+
// RestartAlt,
|
|
28
|
+
// ZoomIn,
|
|
29
|
+
// ZoomOut,
|
|
30
|
+
// FitScreen,
|
|
31
|
+
// Home,
|
|
32
|
+
// Palette
|
|
33
|
+
// } from '@mui/icons-material';
|
|
34
|
+
// import { useHonchoEditorSingle } from '../editor/useHonchoEditorSingle';
|
|
35
|
+
// import { useEditorHeadless } from '../../lib/hooks/useEditorHeadless';
|
|
36
|
+
// import { Controller, AdjustmentState, Preset } from '../editor/type';
|
|
37
|
+
// import { Gallery, CreateEditorTaskRequest } from '../editor/type';
|
|
38
|
+
// import { ImageSize } from '../../lib/editor/honcho-editor';
|
|
39
|
+
// // Mock data and controller (same as before)
|
|
40
|
+
// // Mock data for demonstration
|
|
41
|
+
// const createMockGallery = (id: string, adjustments?: Partial<AdjustmentState>): Gallery => ({
|
|
42
|
+
// id,
|
|
43
|
+
// uid: 'demo-user',
|
|
44
|
+
// event_id: 'demo-event',
|
|
45
|
+
// download: {
|
|
46
|
+
// key: `${id}-download`,
|
|
47
|
+
// path: `https://picsum.photos/800/600?random=${id}`,
|
|
48
|
+
// size: 1024000,
|
|
49
|
+
// width: 800,
|
|
50
|
+
// height: 600,
|
|
51
|
+
// },
|
|
52
|
+
// download_edited: {
|
|
53
|
+
// key: `${id}-download-edited`,
|
|
54
|
+
// path: `https://picsum.photos/800/600?random=${id}`,
|
|
55
|
+
// size: 1024000,
|
|
56
|
+
// width: 800,
|
|
57
|
+
// height: 600,
|
|
58
|
+
// },
|
|
59
|
+
// thumbnail: {
|
|
60
|
+
// key: `${id}-thumb`,
|
|
61
|
+
// path: `https://picsum.photos/300/200?random=${id}`,
|
|
62
|
+
// size: 50000,
|
|
63
|
+
// width: 300,
|
|
64
|
+
// height: 200,
|
|
65
|
+
// },
|
|
66
|
+
// thumbnail_edited: {
|
|
67
|
+
// key: `${id}-thumb-edited`,
|
|
68
|
+
// path: `https://picsum.photos/300/200?random=${id}`,
|
|
69
|
+
// size: 50000,
|
|
70
|
+
// width: 300,
|
|
71
|
+
// height: 200,
|
|
72
|
+
// },
|
|
73
|
+
// is_original: true,
|
|
74
|
+
// available: true,
|
|
75
|
+
// show_gallery: true,
|
|
76
|
+
// editor_config: {
|
|
77
|
+
// color_adjustment: {
|
|
78
|
+
// temperature: adjustments?.tempScore || 0,
|
|
79
|
+
// tint: adjustments?.tintScore || 0,
|
|
80
|
+
// vibrance: adjustments?.vibranceScore || 0,
|
|
81
|
+
// saturation: adjustments?.saturationScore || 0,
|
|
82
|
+
// exposure: adjustments?.exposureScore || 0,
|
|
83
|
+
// highlights: adjustments?.highlightsScore || 0,
|
|
84
|
+
// shadows: adjustments?.shadowsScore || 0,
|
|
85
|
+
// whites: adjustments?.whitesScore || 0,
|
|
86
|
+
// blacks: adjustments?.blacksScore || 0,
|
|
87
|
+
// contrast: adjustments?.contrastScore || 0,
|
|
88
|
+
// clarity: adjustments?.clarityScore || 0,
|
|
89
|
+
// sharpness: adjustments?.sharpnessScore || 0,
|
|
90
|
+
// },
|
|
91
|
+
// transformation_adjustment: [],
|
|
92
|
+
// watermarks: [],
|
|
93
|
+
// },
|
|
94
|
+
// log: {
|
|
95
|
+
// created_at: new Date().toISOString(),
|
|
96
|
+
// updated_at: new Date().toISOString(),
|
|
97
|
+
// },
|
|
98
|
+
// });
|
|
99
|
+
// const createMockController = (): Controller => {
|
|
100
|
+
// console.log('🏭 createMockController() called - Creating new mock controller instance');
|
|
101
|
+
// const mockImages = [
|
|
102
|
+
// createMockGallery('1', { tempScore: 5, exposureScore: 2 }),
|
|
103
|
+
// createMockGallery('2', { contrastScore: -3, clarityScore: 8 }),
|
|
104
|
+
// createMockGallery('3', { vibranceScore: 10, saturationScore: 5 }),
|
|
105
|
+
// createMockGallery('4', { tempScore: -8, tintScore: 4 }),
|
|
106
|
+
// createMockGallery('5', { exposureScore: -5, shadowsScore: 15 }),
|
|
107
|
+
// ];
|
|
108
|
+
// return {
|
|
109
|
+
// onGetImage: async (uid: string, imageId: string) => {
|
|
110
|
+
// console.log(`[Controller] 📷 onGetImage called: uid=${uid}, imageId=${imageId}`);
|
|
111
|
+
// await new Promise(resolve => setTimeout(resolve, 300));
|
|
112
|
+
// const image = mockImages.find(img => img.id === imageId);
|
|
113
|
+
// if (!image) throw new Error(`Image ${imageId} not found`);
|
|
114
|
+
// console.log(`[Controller] 📷 onGetImage returning image:`, image.id);
|
|
115
|
+
// return image;
|
|
116
|
+
// },
|
|
117
|
+
// getImageList: async (uid: string, eventId: string, page: number) => {
|
|
118
|
+
// console.log(`[Controller] 📋 getImageList called: uid=${uid}, eventId=${eventId}, page=${page}`);
|
|
119
|
+
// await new Promise(resolve => setTimeout(resolve, 500));
|
|
120
|
+
// const pageSize = 4;
|
|
121
|
+
// const startIndex = (page - 1) * pageSize;
|
|
122
|
+
// const endIndex = startIndex + pageSize;
|
|
123
|
+
// const pageImages = mockImages.slice(startIndex, endIndex);
|
|
124
|
+
// console.log(`[Controller] 📋 getImageList returning ${pageImages.length} images for page ${page}`);
|
|
125
|
+
// return {
|
|
126
|
+
// gallery: pageImages,
|
|
127
|
+
// limit: pageSize,
|
|
128
|
+
// current_page: page,
|
|
129
|
+
// prev_page: page > 1 ? page - 1 : 0,
|
|
130
|
+
// next_page: endIndex < mockImages.length ? page + 1 : 0,
|
|
131
|
+
// sum_of_image: pageImages.length,
|
|
132
|
+
// };
|
|
133
|
+
// },
|
|
134
|
+
// syncConfig: async (uid: string) => {
|
|
135
|
+
// console.log(`[Controller] 🔄 syncConfig called: uid=${uid}`);
|
|
136
|
+
// await new Promise(resolve => setTimeout(resolve, 200));
|
|
137
|
+
// },
|
|
138
|
+
// handleBack: (uid: string, imageId: string) => {
|
|
139
|
+
// console.log(`[Controller] ⬅️ handleBack called: uid=${uid}, imageId=${imageId}`);
|
|
140
|
+
// console.log(`Back to gallery from image: ${imageId}`);
|
|
141
|
+
// },
|
|
142
|
+
// getPresets: async (uid: string) => {
|
|
143
|
+
// console.log(`[Controller] 🎨 getPresets called: uid=${uid}`);
|
|
144
|
+
// await new Promise(resolve => setTimeout(resolve, 300));
|
|
145
|
+
// const presets = [
|
|
146
|
+
// { id: '1', name: 'Warm Sunset', is_default: false, temperature: 15, tint: 5, saturation: 8, vibrance: 12, exposure: 2, contrast: 5, highlights: -10, shadows: 8, whites: 3, blacks: -5, clarity: 4, sharpness: 6 },
|
|
147
|
+
// { id: '2', name: 'Cool Morning', is_default: false, temperature: -12, tint: -3, saturation: -2, vibrance: 5, exposure: 1, contrast: 3, highlights: -5, shadows: 12, whites: 8, blacks: -8, clarity: 6, sharpness: 4 },
|
|
148
|
+
// { id: '3', name: 'High Contrast', is_default: false, temperature: 0, tint: 0, saturation: 5, vibrance: 8, exposure: 0, contrast: 20, highlights: -15, shadows: 15, whites: 10, blacks: -10, clarity: 15, sharpness: 8 },
|
|
149
|
+
// ];
|
|
150
|
+
// console.log(`🎨 getPresets returning ${presets.length} presets`);
|
|
151
|
+
// return presets;
|
|
152
|
+
// },
|
|
153
|
+
// createPreset: async (uid: string, name: string, settings: AdjustmentState) => {
|
|
154
|
+
// console.log(`[Controller] ➕ createPreset called: uid=${uid}, name=${name}`, settings);
|
|
155
|
+
// await new Promise(resolve => setTimeout(resolve, 500));
|
|
156
|
+
// console.log(`Creating preset: ${name}`, settings);
|
|
157
|
+
// },
|
|
158
|
+
// deletePreset: async (uid: string, presetId: string) => {
|
|
159
|
+
// console.log(`[Controller] 🗑️ deletePreset called: uid=${uid}, presetId=${presetId}`);
|
|
160
|
+
// await new Promise(resolve => setTimeout(resolve, 300));
|
|
161
|
+
// console.log(`Deleting preset: ${presetId}`);
|
|
162
|
+
// },
|
|
163
|
+
// updatePreset: async (uid: string, data: Preset) => {
|
|
164
|
+
// console.log(`[Controller] 🔄 updatePreset called: uid=${uid}`, data);
|
|
165
|
+
// await new Promise(resolve => setTimeout(resolve, 300));
|
|
166
|
+
// console.log(`Updating preset:`, data);
|
|
167
|
+
// },
|
|
168
|
+
// createEditorConfig: async (uid: string, payload: CreateEditorTaskRequest) => {
|
|
169
|
+
// console.log(`[Controller] ⚙️ createEditorConfig called: uid=${uid}`, payload);
|
|
170
|
+
// await new Promise(resolve => setTimeout(resolve, 200));
|
|
171
|
+
// console.log('Creating editor config:', payload);
|
|
172
|
+
// },
|
|
173
|
+
// getEditorHistory: async (uid: string, imageId: string) => {
|
|
174
|
+
// console.log(`[Controller] 📚 getEditorHistory called: uid=${uid}, imageId=${imageId}`);
|
|
175
|
+
// await new Promise(resolve => setTimeout(resolve, 200));
|
|
176
|
+
// return { current_task_id: "", history: [] };
|
|
177
|
+
// },
|
|
178
|
+
// getGalleryUpdateTimestamp: async (uid: string, eventId: string) => {
|
|
179
|
+
// console.log(`[Controller] ⏰ getGalleryUpdateTimestamp called: uid=${uid}, eventId=${eventId}`);
|
|
180
|
+
// await new Promise(resolve => setTimeout(resolve, 100));
|
|
181
|
+
// return { gallery: [] };
|
|
182
|
+
// },
|
|
183
|
+
// setHistoryIndex: async (uid: string, imageId: string, taskId: string) => {
|
|
184
|
+
// console.log(`[Controller] 📍 setHistoryIndex called: uid=${uid}, imageId=${imageId}, taskId=${taskId}`);
|
|
185
|
+
// await new Promise(resolve => setTimeout(resolve, 100));
|
|
186
|
+
// console.log(`Setting history index for image ${imageId} to task ${taskId}`);
|
|
187
|
+
// },
|
|
188
|
+
// };
|
|
189
|
+
// };
|
|
190
|
+
// // Dumb Adjustment Slider Component
|
|
191
|
+
// const AdjustmentSlider: React.FC<{
|
|
192
|
+
// label: string;
|
|
193
|
+
// value: number;
|
|
194
|
+
// field: keyof AdjustmentState;
|
|
195
|
+
// onValueChange: (field: keyof AdjustmentState, value: number) => void;
|
|
196
|
+
// onDragStart: () => void;
|
|
197
|
+
// onDragEnd: () => void;
|
|
198
|
+
// isBatchMode: boolean;
|
|
199
|
+
// min?: number;
|
|
200
|
+
// max?: number;
|
|
201
|
+
// step?: number;
|
|
202
|
+
// }> = ({
|
|
203
|
+
// label,
|
|
204
|
+
// value,
|
|
205
|
+
// field,
|
|
206
|
+
// onValueChange,
|
|
207
|
+
// onDragStart,
|
|
208
|
+
// onDragEnd,
|
|
209
|
+
// isBatchMode,
|
|
210
|
+
// min = -100,
|
|
211
|
+
// max = 100,
|
|
212
|
+
// step = 1
|
|
213
|
+
// }) => {
|
|
214
|
+
// return (
|
|
215
|
+
// <Box sx={{ mb: 2 }}>
|
|
216
|
+
// <Typography variant="body2" gutterBottom>
|
|
217
|
+
// {label}: {value}
|
|
218
|
+
// {isBatchMode && (
|
|
219
|
+
// <Box
|
|
220
|
+
// component="span"
|
|
221
|
+
// sx={{
|
|
222
|
+
// ml: 1,
|
|
223
|
+
// px: 1,
|
|
224
|
+
// py: 0.25,
|
|
225
|
+
// backgroundColor: 'warning.main',
|
|
226
|
+
// color: 'warning.contrastText',
|
|
227
|
+
// borderRadius: 1,
|
|
228
|
+
// fontSize: '0.75rem',
|
|
229
|
+
// fontWeight: 'bold'
|
|
230
|
+
// }}
|
|
231
|
+
// >
|
|
232
|
+
// LIVE EDIT
|
|
233
|
+
// </Box>
|
|
234
|
+
// )}
|
|
235
|
+
// </Typography>
|
|
236
|
+
// <Slider
|
|
237
|
+
// value={value}
|
|
238
|
+
// onChange={(_, newValue) => {
|
|
239
|
+
// const numValue = newValue as number;
|
|
240
|
+
// onValueChange(field, numValue);
|
|
241
|
+
// }}
|
|
242
|
+
// onMouseDown={() => {
|
|
243
|
+
// if (!isBatchMode) {
|
|
244
|
+
// onDragStart();
|
|
245
|
+
// }
|
|
246
|
+
// }}
|
|
247
|
+
// onMouseUp={() => {
|
|
248
|
+
// onDragEnd();
|
|
249
|
+
// }}
|
|
250
|
+
// onTouchStart={() => {
|
|
251
|
+
// if (!isBatchMode) {
|
|
252
|
+
// onDragStart();
|
|
253
|
+
// }
|
|
254
|
+
// }}
|
|
255
|
+
// onTouchEnd={() => {
|
|
256
|
+
// onDragEnd();
|
|
257
|
+
// }}
|
|
258
|
+
// min={min}
|
|
259
|
+
// max={max}
|
|
260
|
+
// step={step}
|
|
261
|
+
// valueLabelDisplay="auto"
|
|
262
|
+
// size="small"
|
|
263
|
+
// />
|
|
264
|
+
// </Box>
|
|
265
|
+
// );
|
|
266
|
+
// };
|
|
267
|
+
// // Dumb Preset Card Component
|
|
268
|
+
// const PresetCard: React.FC<{
|
|
269
|
+
// preset: Preset;
|
|
270
|
+
// onApply: (preset: Preset) => void;
|
|
271
|
+
// onDelete: (presetId: string) => void;
|
|
272
|
+
// isActive: boolean;
|
|
273
|
+
// }> = ({ preset, onApply, onDelete, isActive }) => (
|
|
274
|
+
// <Card
|
|
275
|
+
// sx={{
|
|
276
|
+
// border: isActive ? 2 : 1,
|
|
277
|
+
// borderColor: isActive ? 'primary.main' : 'divider',
|
|
278
|
+
// cursor: 'pointer',
|
|
279
|
+
// transition: 'all 0.2s',
|
|
280
|
+
// '&:hover': {
|
|
281
|
+
// boxShadow: 2,
|
|
282
|
+
// transform: 'translateY(-1px)',
|
|
283
|
+
// }
|
|
284
|
+
// }}
|
|
285
|
+
// onClick={() => onApply(preset)}
|
|
286
|
+
// >
|
|
287
|
+
// <CardContent sx={{ p: 2, '&:last-child': { pb: 2 } }}>
|
|
288
|
+
// <Typography variant="subtitle2" gutterBottom>
|
|
289
|
+
// {preset.name}
|
|
290
|
+
// {isActive && ' ✓'}
|
|
291
|
+
// </Typography>
|
|
292
|
+
// <Typography variant="caption" color="text.secondary" display="block" sx={{ mb: 1 }}>
|
|
293
|
+
// Temp: {preset.temperature > 0 ? '+' : ''}{preset.temperature},
|
|
294
|
+
// Exp: {preset.exposure > 0 ? '+' : ''}{preset.exposure},
|
|
295
|
+
// Con: {preset.contrast > 0 ? '+' : ''}{preset.contrast}
|
|
296
|
+
// </Typography>
|
|
297
|
+
// <Box sx={{ mt: 1, display: 'flex', gap: 1 }}>
|
|
298
|
+
// <Button
|
|
299
|
+
// size="small"
|
|
300
|
+
// variant="outlined"
|
|
301
|
+
// onClick={(e) => {
|
|
302
|
+
// e.stopPropagation();
|
|
303
|
+
// onApply(preset);
|
|
304
|
+
// }}
|
|
305
|
+
// >
|
|
306
|
+
// Apply
|
|
307
|
+
// </Button>
|
|
308
|
+
// <Button
|
|
309
|
+
// size="small"
|
|
310
|
+
// variant="outlined"
|
|
311
|
+
// color="error"
|
|
312
|
+
// onClick={(e) => {
|
|
313
|
+
// e.stopPropagation();
|
|
314
|
+
// onDelete(preset.id);
|
|
315
|
+
// }}
|
|
316
|
+
// >
|
|
317
|
+
// Delete
|
|
318
|
+
// </Button>
|
|
319
|
+
// </Box>
|
|
320
|
+
// </CardContent>
|
|
321
|
+
// </Card>
|
|
322
|
+
// );
|
|
323
|
+
// export const HonchoEditorSingleCleanDemo: React.FC = () => {
|
|
324
|
+
// // Initialize mock controller
|
|
325
|
+
// const [controller] = useState(() => createMockController());
|
|
326
|
+
// // UI state (only UI-specific state here)
|
|
327
|
+
// const [showAdjustments, setShowAdjustments] = useState(true);
|
|
328
|
+
// const [newPresetName, setNewPresetName] = useState('');
|
|
329
|
+
// const [isImageLoaded, setIsImageLoaded] = useState(false);
|
|
330
|
+
// // Business logic hook - handles adjustments, presets, navigation
|
|
331
|
+
// const { state, actions } = useHonchoEditorSingle({
|
|
332
|
+
// controller,
|
|
333
|
+
// initImageId: '1',
|
|
334
|
+
// firebaseUid: 'demo-user'
|
|
335
|
+
// });
|
|
336
|
+
// // Editor hook - handles editor operations separately
|
|
337
|
+
// const editorHeadless = useEditorHeadless({
|
|
338
|
+
// scriptUrl: '/honcho-photo-editor.js',
|
|
339
|
+
// wasmUrl: '/honcho-photo-editor.wasm'
|
|
340
|
+
// });
|
|
341
|
+
// // Refs for canvas rendering
|
|
342
|
+
// const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
343
|
+
// // Load image when gallery data changes
|
|
344
|
+
// useEffect(() => {
|
|
345
|
+
// if (state.currentImageData && editorHeadless.isReady && editorHeadless.loadImageFromUrl) {
|
|
346
|
+
// console.log('Loading image to editor:', state.currentImageData.id);
|
|
347
|
+
// setIsImageLoaded(false);
|
|
348
|
+
// const imageUrl = state.currentImageData.raw_edited?.path || state.currentImageData.download.path;
|
|
349
|
+
// editorHeadless.loadImageFromUrl(imageUrl)
|
|
350
|
+
// .then((size: ImageSize) => {
|
|
351
|
+
// console.log('Image loaded successfully:', size);
|
|
352
|
+
// setIsImageLoaded(true);
|
|
353
|
+
// })
|
|
354
|
+
// .catch((error: Error) => {
|
|
355
|
+
// console.error('Error loading image:', error);
|
|
356
|
+
// setIsImageLoaded(false);
|
|
357
|
+
// });
|
|
358
|
+
// }
|
|
359
|
+
// }, [state.currentImageData, editorHeadless.isReady, editorHeadless.loadImageFromUrl]);
|
|
360
|
+
// // Apply adjustments to editor when they change
|
|
361
|
+
// useEffect(() => {
|
|
362
|
+
// if (editorHeadless.editor && isImageLoaded && canvasRef.current) {
|
|
363
|
+
// console.log('Applying adjustments to editor:', state.currentAdjustments);
|
|
364
|
+
// // Get converted adjustments from business logic hook
|
|
365
|
+
// const editorAdjustments = actions.getEditorAdjustments();
|
|
366
|
+
// try {
|
|
367
|
+
// editorHeadless.editor.setAdjustments(editorAdjustments);
|
|
368
|
+
// editorHeadless.editor.processImage();
|
|
369
|
+
// editorHeadless.editor.renderToCanvas(canvasRef.current);
|
|
370
|
+
// console.log('Rendered to canvas successfully');
|
|
371
|
+
// } catch (error) {
|
|
372
|
+
// console.error('Error rendering to canvas:', error);
|
|
373
|
+
// }
|
|
374
|
+
// }
|
|
375
|
+
// }, [state.currentAdjustments, editorHeadless.editor, isImageLoaded, actions]);
|
|
376
|
+
// // Helper functions that only handle UI logic
|
|
377
|
+
// const handleCreatePreset = async () => {
|
|
378
|
+
// if (!newPresetName.trim()) return;
|
|
379
|
+
// try {
|
|
380
|
+
// const preset = await actions.createPreset(newPresetName, state.currentAdjustments);
|
|
381
|
+
// if (preset) {
|
|
382
|
+
// setNewPresetName('');
|
|
383
|
+
// console.log('Preset created successfully:', preset);
|
|
384
|
+
// } else {
|
|
385
|
+
// console.error('Failed to create preset');
|
|
386
|
+
// }
|
|
387
|
+
// } catch (error) {
|
|
388
|
+
// console.error('Error creating preset:', error);
|
|
389
|
+
// }
|
|
390
|
+
// };
|
|
391
|
+
// const navigationNext = useCallback(() => {
|
|
392
|
+
// // Must be set to avoid adjust without image
|
|
393
|
+
// setIsImageLoaded(false);
|
|
394
|
+
// actions.navigateNext();
|
|
395
|
+
// }, [actions]);
|
|
396
|
+
// const navigationPrev = useCallback(() => {
|
|
397
|
+
// // Must be set to avoid adjust without image
|
|
398
|
+
// setIsImageLoaded(false);
|
|
399
|
+
// actions.navigatePrev();
|
|
400
|
+
// }, [actions]);
|
|
401
|
+
// const getAdjustmentSummary = (adjustments: AdjustmentState) => {
|
|
402
|
+
// const summary = [];
|
|
403
|
+
// if (adjustments.tempScore !== 0) summary.push(`Temp: ${adjustments.tempScore > 0 ? '+' : ''}${adjustments.tempScore}`);
|
|
404
|
+
// if (adjustments.exposureScore !== 0) summary.push(`Exp: ${adjustments.exposureScore > 0 ? '+' : ''}${adjustments.exposureScore}`);
|
|
405
|
+
// if (adjustments.contrastScore !== 0) summary.push(`Con: ${adjustments.contrastScore > 0 ? '+' : ''}${adjustments.contrastScore}`);
|
|
406
|
+
// if (adjustments.clarityScore !== 0) summary.push(`Cla: ${adjustments.clarityScore > 0 ? '+' : ''}${adjustments.clarityScore}`);
|
|
407
|
+
// return summary.join(', ') || 'No adjustments';
|
|
408
|
+
// };
|
|
409
|
+
// return (
|
|
410
|
+
// <Container maxWidth="xl" sx={{ py: 4 }}>
|
|
411
|
+
// <Typography variant="h3" gutterBottom align="center">
|
|
412
|
+
// Clean Honcho Editor Single Image Demo
|
|
413
|
+
// </Typography>
|
|
414
|
+
// <Typography variant="subtitle1" align="center" color="text.secondary" gutterBottom>
|
|
415
|
+
// This is a "dumb" view-only component that consumes state from useHonchoEditorSingle
|
|
416
|
+
// </Typography>
|
|
417
|
+
// {(state.galleryError || state.presetsError) && (
|
|
418
|
+
// <Alert severity="error" sx={{ mb: 3 }}>
|
|
419
|
+
// {state.galleryError || state.presetsError}
|
|
420
|
+
// </Alert>
|
|
421
|
+
// )}
|
|
422
|
+
// <Grid container spacing={3}>
|
|
423
|
+
// {/* Main Image Area */}
|
|
424
|
+
// <Grid item xs={12} md={8}>
|
|
425
|
+
// <Paper sx={{ p: 2, mb: 2 }}>
|
|
426
|
+
// <Stack direction="row" justifyContent="space-between" alignItems="center" sx={{ mb: 2 }}>
|
|
427
|
+
// <Typography variant="h6">
|
|
428
|
+
// Image {state.currentImageData?.id}
|
|
429
|
+
// {state.activePreset && ` - ${state.activePreset.name}`}
|
|
430
|
+
// </Typography>
|
|
431
|
+
// <Stack direction="row" spacing={1}>
|
|
432
|
+
// <Tooltip title="Previous Image">
|
|
433
|
+
// <span>
|
|
434
|
+
// <IconButton
|
|
435
|
+
// onClick={navigationPrev}
|
|
436
|
+
// disabled={!state.isPrevAvailable || state.isGalleryLoading}
|
|
437
|
+
// >
|
|
438
|
+
// <NavigateBefore />
|
|
439
|
+
// </IconButton>
|
|
440
|
+
// </span>
|
|
441
|
+
// </Tooltip>
|
|
442
|
+
// <Tooltip title="Next Image">
|
|
443
|
+
// <span>
|
|
444
|
+
// <IconButton
|
|
445
|
+
// onClick={navigationNext}
|
|
446
|
+
// disabled={!state.isNextAvailable || state.isGalleryLoading}
|
|
447
|
+
// >
|
|
448
|
+
// <NavigateNext />
|
|
449
|
+
// </IconButton>
|
|
450
|
+
// </span>
|
|
451
|
+
// </Tooltip>
|
|
452
|
+
// <Tooltip title="Back to Gallery">
|
|
453
|
+
// <IconButton onClick={() => console.log('Back to gallery')}>
|
|
454
|
+
// <Home />
|
|
455
|
+
// </IconButton>
|
|
456
|
+
// </Tooltip>
|
|
457
|
+
// <Divider orientation="vertical" flexItem />
|
|
458
|
+
// <Tooltip title="Zoom In">
|
|
459
|
+
// <IconButton onClick={() => console.log('Zoom in')}>
|
|
460
|
+
// <ZoomIn />
|
|
461
|
+
// </IconButton>
|
|
462
|
+
// </Tooltip>
|
|
463
|
+
// <Tooltip title="Zoom Out">
|
|
464
|
+
// <IconButton onClick={() => console.log('Zoom out')}>
|
|
465
|
+
// <ZoomOut />
|
|
466
|
+
// </IconButton>
|
|
467
|
+
// </Tooltip>
|
|
468
|
+
// <Tooltip title="Fit to Screen">
|
|
469
|
+
// <IconButton onClick={() => console.log('Fit to screen')}>
|
|
470
|
+
// <FitScreen />
|
|
471
|
+
// </IconButton>
|
|
472
|
+
// </Tooltip>
|
|
473
|
+
// <Typography variant="body2" sx={{ alignSelf: 'center', minWidth: '60px' }}>
|
|
474
|
+
// 100%
|
|
475
|
+
// </Typography>
|
|
476
|
+
// </Stack>
|
|
477
|
+
// </Stack>
|
|
478
|
+
// {/* Canvas Container */}
|
|
479
|
+
// <Box
|
|
480
|
+
// sx={{
|
|
481
|
+
// position: 'relative',
|
|
482
|
+
// width: '100%',
|
|
483
|
+
// height: '500px',
|
|
484
|
+
// bgcolor: '#f5f5f5',
|
|
485
|
+
// border: 1,
|
|
486
|
+
// borderColor: 'divider',
|
|
487
|
+
// borderRadius: 1,
|
|
488
|
+
// overflow: 'hidden',
|
|
489
|
+
// display: 'flex',
|
|
490
|
+
// alignItems: 'center',
|
|
491
|
+
// justifyContent: 'center'
|
|
492
|
+
// }}
|
|
493
|
+
// >
|
|
494
|
+
// {/* Status indicator */}
|
|
495
|
+
// {editorHeadless.isReady && (
|
|
496
|
+
// <Box
|
|
497
|
+
// sx={{
|
|
498
|
+
// position: 'absolute',
|
|
499
|
+
// top: 8,
|
|
500
|
+
// right: 8,
|
|
501
|
+
// zIndex: 3,
|
|
502
|
+
// px: 1,
|
|
503
|
+
// py: 0.5,
|
|
504
|
+
// backgroundColor: 'success.main',
|
|
505
|
+
// color: 'success.contrastText',
|
|
506
|
+
// borderRadius: 1,
|
|
507
|
+
// fontSize: '0.75rem',
|
|
508
|
+
// fontWeight: 'bold'
|
|
509
|
+
// }}
|
|
510
|
+
// >
|
|
511
|
+
// EDITOR ACTIVE
|
|
512
|
+
// </Box>
|
|
513
|
+
// )}
|
|
514
|
+
// {state.currentImageData ? (
|
|
515
|
+
// <CardMedia
|
|
516
|
+
// component="img"
|
|
517
|
+
// image={state.currentImageData.download.path}
|
|
518
|
+
// alt={`Image ${state.currentImageData.id}`}
|
|
519
|
+
// sx={{
|
|
520
|
+
// maxWidth: '100%',
|
|
521
|
+
// maxHeight: '100%',
|
|
522
|
+
// objectFit: 'contain',
|
|
523
|
+
// transition: 'transform 0.1s ease-out',
|
|
524
|
+
// opacity: editorHeadless.isReady ? 0.3 : 1,
|
|
525
|
+
// zIndex: 1
|
|
526
|
+
// }}
|
|
527
|
+
// />
|
|
528
|
+
// ) : state.isGalleryLoading ? (
|
|
529
|
+
// <CircularProgress />
|
|
530
|
+
// ) : (
|
|
531
|
+
// <Typography color="text.secondary">No image loaded</Typography>
|
|
532
|
+
// )}
|
|
533
|
+
// {/* Editor Canvas */}
|
|
534
|
+
// <canvas
|
|
535
|
+
// ref={canvasRef}
|
|
536
|
+
// style={{
|
|
537
|
+
// position: 'absolute',
|
|
538
|
+
// top: 0,
|
|
539
|
+
// left: 0,
|
|
540
|
+
// width: '100%',
|
|
541
|
+
// height: '100%',
|
|
542
|
+
// objectFit: 'contain',
|
|
543
|
+
// pointerEvents: 'none',
|
|
544
|
+
// zIndex: state.currentImageData && editorHeadless.isReady ? 2 : 0,
|
|
545
|
+
// opacity: state.currentImageData && editorHeadless.isReady ? 1 : 0,
|
|
546
|
+
// }}
|
|
547
|
+
// />
|
|
548
|
+
// </Box>
|
|
549
|
+
// {/* History Controls */}
|
|
550
|
+
// <Stack direction="row" justifyContent="center" spacing={1} sx={{ mt: 2 }}>
|
|
551
|
+
// <Tooltip title="Undo">
|
|
552
|
+
// <span>
|
|
553
|
+
// <Button
|
|
554
|
+
// variant="outlined"
|
|
555
|
+
// size="small"
|
|
556
|
+
// onClick={actions.undo}
|
|
557
|
+
// disabled={!state.canUndo}
|
|
558
|
+
// startIcon={<Undo />}
|
|
559
|
+
// >
|
|
560
|
+
// Undo
|
|
561
|
+
// </Button>
|
|
562
|
+
// </span>
|
|
563
|
+
// </Tooltip>
|
|
564
|
+
// <Tooltip title="Redo">
|
|
565
|
+
// <span>
|
|
566
|
+
// <Button
|
|
567
|
+
// variant="outlined"
|
|
568
|
+
// size="small"
|
|
569
|
+
// onClick={actions.redo}
|
|
570
|
+
// disabled={!state.canRedo}
|
|
571
|
+
// startIcon={<Redo />}
|
|
572
|
+
// >
|
|
573
|
+
// Redo
|
|
574
|
+
// </Button>
|
|
575
|
+
// </span>
|
|
576
|
+
// </Tooltip>
|
|
577
|
+
// <Tooltip title="Reset All">
|
|
578
|
+
// <Button
|
|
579
|
+
// variant="outlined"
|
|
580
|
+
// size="small"
|
|
581
|
+
// onClick={actions.reset}
|
|
582
|
+
// color="warning"
|
|
583
|
+
// startIcon={<RestartAlt />}
|
|
584
|
+
// >
|
|
585
|
+
// Reset
|
|
586
|
+
// </Button>
|
|
587
|
+
// </Tooltip>
|
|
588
|
+
// </Stack>
|
|
589
|
+
// {/* Current Adjustments Summary */}
|
|
590
|
+
// <Box sx={{ mt: 2, p: 1, bgcolor: 'grey.50', borderRadius: 1 }}>
|
|
591
|
+
// <Typography variant="caption" color="text.secondary">
|
|
592
|
+
// Current Adjustments: {getAdjustmentSummary(state.currentAdjustments)}
|
|
593
|
+
// {state.isBatchMode && (
|
|
594
|
+
// <Box
|
|
595
|
+
// component="span"
|
|
596
|
+
// sx={{
|
|
597
|
+
// ml: 1,
|
|
598
|
+
// px: 1,
|
|
599
|
+
// py: 0.25,
|
|
600
|
+
// backgroundColor: 'warning.main',
|
|
601
|
+
// color: 'warning.contrastText',
|
|
602
|
+
// borderRadius: 1,
|
|
603
|
+
// fontSize: '0.625rem',
|
|
604
|
+
// fontWeight: 'bold'
|
|
605
|
+
// }}
|
|
606
|
+
// >
|
|
607
|
+
// BATCH MODE
|
|
608
|
+
// </Box>
|
|
609
|
+
// )}
|
|
610
|
+
// </Typography>
|
|
611
|
+
// </Box>
|
|
612
|
+
// </Paper>
|
|
613
|
+
// </Grid>
|
|
614
|
+
// {/* Controls Panel */}
|
|
615
|
+
// <Grid item xs={12} md={4}>
|
|
616
|
+
// <Paper sx={{ p: 2, mb: 2 }}>
|
|
617
|
+
// <Stack direction="row" justifyContent="space-between" alignItems="center" sx={{ mb: 2 }}>
|
|
618
|
+
// <Typography variant="h6">Controls</Typography>
|
|
619
|
+
// <Button
|
|
620
|
+
// variant="outlined"
|
|
621
|
+
// size="small"
|
|
622
|
+
// onClick={() => setShowAdjustments(!showAdjustments)}
|
|
623
|
+
// startIcon={<Palette />}
|
|
624
|
+
// >
|
|
625
|
+
// {showAdjustments ? 'Hide' : 'Show'} Adjustments
|
|
626
|
+
// </Button>
|
|
627
|
+
// </Stack>
|
|
628
|
+
// {showAdjustments && (
|
|
629
|
+
// <>
|
|
630
|
+
// {/* Color Adjustments */}
|
|
631
|
+
// <Typography variant="subtitle2" gutterBottom sx={{ mt: 2 }}>
|
|
632
|
+
// Color
|
|
633
|
+
// </Typography>
|
|
634
|
+
// <AdjustmentSlider
|
|
635
|
+
// label="Temperature"
|
|
636
|
+
// value={state.currentAdjustments.tempScore}
|
|
637
|
+
// field="tempScore"
|
|
638
|
+
// onValueChange={actions.updateAdjustment}
|
|
639
|
+
// onDragStart={actions.startBatchMode}
|
|
640
|
+
// onDragEnd={actions.endBatchMode}
|
|
641
|
+
// isBatchMode={state.isBatchMode}
|
|
642
|
+
// />
|
|
643
|
+
// <AdjustmentSlider
|
|
644
|
+
// label="Tint"
|
|
645
|
+
// value={state.currentAdjustments.tintScore}
|
|
646
|
+
// field="tintScore"
|
|
647
|
+
// onValueChange={actions.updateAdjustment}
|
|
648
|
+
// onDragStart={actions.startBatchMode}
|
|
649
|
+
// onDragEnd={actions.endBatchMode}
|
|
650
|
+
// isBatchMode={state.isBatchMode}
|
|
651
|
+
// />
|
|
652
|
+
// <AdjustmentSlider
|
|
653
|
+
// label="Vibrance"
|
|
654
|
+
// value={state.currentAdjustments.vibranceScore}
|
|
655
|
+
// field="vibranceScore"
|
|
656
|
+
// onValueChange={actions.updateAdjustment}
|
|
657
|
+
// onDragStart={actions.startBatchMode}
|
|
658
|
+
// onDragEnd={actions.endBatchMode}
|
|
659
|
+
// isBatchMode={state.isBatchMode}
|
|
660
|
+
// />
|
|
661
|
+
// <AdjustmentSlider
|
|
662
|
+
// label="Saturation"
|
|
663
|
+
// value={state.currentAdjustments.saturationScore}
|
|
664
|
+
// field="saturationScore"
|
|
665
|
+
// onValueChange={actions.updateAdjustment}
|
|
666
|
+
// onDragStart={actions.startBatchMode}
|
|
667
|
+
// onDragEnd={actions.endBatchMode}
|
|
668
|
+
// isBatchMode={state.isBatchMode}
|
|
669
|
+
// />
|
|
670
|
+
// <Divider sx={{ my: 2 }} />
|
|
671
|
+
// {/* Light Adjustments */}
|
|
672
|
+
// <Typography variant="subtitle2" gutterBottom>
|
|
673
|
+
// Light
|
|
674
|
+
// </Typography>
|
|
675
|
+
// <AdjustmentSlider
|
|
676
|
+
// label="Exposure"
|
|
677
|
+
// value={state.currentAdjustments.exposureScore}
|
|
678
|
+
// field="exposureScore"
|
|
679
|
+
// onValueChange={actions.updateAdjustment}
|
|
680
|
+
// onDragStart={actions.startBatchMode}
|
|
681
|
+
// onDragEnd={actions.endBatchMode}
|
|
682
|
+
// isBatchMode={state.isBatchMode}
|
|
683
|
+
// />
|
|
684
|
+
// <AdjustmentSlider
|
|
685
|
+
// label="Contrast"
|
|
686
|
+
// value={state.currentAdjustments.contrastScore}
|
|
687
|
+
// field="contrastScore"
|
|
688
|
+
// onValueChange={actions.updateAdjustment}
|
|
689
|
+
// onDragStart={actions.startBatchMode}
|
|
690
|
+
// onDragEnd={actions.endBatchMode}
|
|
691
|
+
// isBatchMode={state.isBatchMode}
|
|
692
|
+
// />
|
|
693
|
+
// <AdjustmentSlider
|
|
694
|
+
// label="Highlights"
|
|
695
|
+
// value={state.currentAdjustments.highlightsScore}
|
|
696
|
+
// field="highlightsScore"
|
|
697
|
+
// onValueChange={actions.updateAdjustment}
|
|
698
|
+
// onDragStart={actions.startBatchMode}
|
|
699
|
+
// onDragEnd={actions.endBatchMode}
|
|
700
|
+
// isBatchMode={state.isBatchMode}
|
|
701
|
+
// />
|
|
702
|
+
// <AdjustmentSlider
|
|
703
|
+
// label="Shadows"
|
|
704
|
+
// value={state.currentAdjustments.shadowsScore}
|
|
705
|
+
// field="shadowsScore"
|
|
706
|
+
// onValueChange={actions.updateAdjustment}
|
|
707
|
+
// onDragStart={actions.startBatchMode}
|
|
708
|
+
// onDragEnd={actions.endBatchMode}
|
|
709
|
+
// isBatchMode={state.isBatchMode}
|
|
710
|
+
// />
|
|
711
|
+
// <AdjustmentSlider
|
|
712
|
+
// label="Whites"
|
|
713
|
+
// value={state.currentAdjustments.whitesScore}
|
|
714
|
+
// field="whitesScore"
|
|
715
|
+
// onValueChange={actions.updateAdjustment}
|
|
716
|
+
// onDragStart={actions.startBatchMode}
|
|
717
|
+
// onDragEnd={actions.endBatchMode}
|
|
718
|
+
// isBatchMode={state.isBatchMode}
|
|
719
|
+
// />
|
|
720
|
+
// <AdjustmentSlider
|
|
721
|
+
// label="Blacks"
|
|
722
|
+
// value={state.currentAdjustments.blacksScore}
|
|
723
|
+
// field="blacksScore"
|
|
724
|
+
// onValueChange={actions.updateAdjustment}
|
|
725
|
+
// onDragStart={actions.startBatchMode}
|
|
726
|
+
// onDragEnd={actions.endBatchMode}
|
|
727
|
+
// isBatchMode={state.isBatchMode}
|
|
728
|
+
// />
|
|
729
|
+
// <Divider sx={{ my: 2 }} />
|
|
730
|
+
// {/* Detail Adjustments */}
|
|
731
|
+
// <Typography variant="subtitle2" gutterBottom>
|
|
732
|
+
// Details
|
|
733
|
+
// </Typography>
|
|
734
|
+
// <AdjustmentSlider
|
|
735
|
+
// label="Clarity"
|
|
736
|
+
// value={state.currentAdjustments.clarityScore}
|
|
737
|
+
// field="clarityScore"
|
|
738
|
+
// onValueChange={actions.updateAdjustment}
|
|
739
|
+
// onDragStart={actions.startBatchMode}
|
|
740
|
+
// onDragEnd={actions.endBatchMode}
|
|
741
|
+
// isBatchMode={state.isBatchMode}
|
|
742
|
+
// />
|
|
743
|
+
// <AdjustmentSlider
|
|
744
|
+
// label="Sharpness"
|
|
745
|
+
// value={state.currentAdjustments.sharpnessScore}
|
|
746
|
+
// field="sharpnessScore"
|
|
747
|
+
// onValueChange={actions.updateAdjustment}
|
|
748
|
+
// onDragStart={actions.startBatchMode}
|
|
749
|
+
// onDragEnd={actions.endBatchMode}
|
|
750
|
+
// isBatchMode={state.isBatchMode}
|
|
751
|
+
// />
|
|
752
|
+
// </>
|
|
753
|
+
// )}
|
|
754
|
+
// </Paper>
|
|
755
|
+
// {/* Presets Panel */}
|
|
756
|
+
// <Paper sx={{ p: 2 }}>
|
|
757
|
+
// <Stack direction="row" justifyContent="space-between" alignItems="center" sx={{ mb: 2 }}>
|
|
758
|
+
// <Typography variant="h6">
|
|
759
|
+
// Presets ({state.presets.length})
|
|
760
|
+
// </Typography>
|
|
761
|
+
// <Button
|
|
762
|
+
// variant="outlined"
|
|
763
|
+
// size="small"
|
|
764
|
+
// onClick={actions.loadPresets}
|
|
765
|
+
// disabled={state.presetsLoading}
|
|
766
|
+
// >
|
|
767
|
+
// Refresh
|
|
768
|
+
// </Button>
|
|
769
|
+
// </Stack>
|
|
770
|
+
// {state.presetsError && (
|
|
771
|
+
// <Alert severity="error" sx={{ mb: 2 }}>
|
|
772
|
+
// {state.presetsError}
|
|
773
|
+
// </Alert>
|
|
774
|
+
// )}
|
|
775
|
+
// {state.presetsLoading && (
|
|
776
|
+
// <Box display="flex" justifyContent="center" py={2}>
|
|
777
|
+
// <CircularProgress size={20} />
|
|
778
|
+
// </Box>
|
|
779
|
+
// )}
|
|
780
|
+
// {/* Quick Preset Actions */}
|
|
781
|
+
// <Box sx={{ mb: 2 }}>
|
|
782
|
+
// <Typography variant="subtitle2" gutterBottom>
|
|
783
|
+
// Quick Actions
|
|
784
|
+
// </Typography>
|
|
785
|
+
// <Stack direction="row" spacing={1} flexWrap="wrap" useFlexGap>
|
|
786
|
+
// <Button
|
|
787
|
+
// size="small"
|
|
788
|
+
// variant={!state.activePreset ? "contained" : "outlined"}
|
|
789
|
+
// onClick={actions.reset}
|
|
790
|
+
// >
|
|
791
|
+
// Reset All
|
|
792
|
+
// </Button>
|
|
793
|
+
// {state.activePreset && (
|
|
794
|
+
// <Button
|
|
795
|
+
// size="small"
|
|
796
|
+
// variant="outlined"
|
|
797
|
+
// color="info"
|
|
798
|
+
// disabled
|
|
799
|
+
// >
|
|
800
|
+
// Active: {state.activePreset.name}
|
|
801
|
+
// </Button>
|
|
802
|
+
// )}
|
|
803
|
+
// </Stack>
|
|
804
|
+
// </Box>
|
|
805
|
+
// <Divider sx={{ my: 2 }} />
|
|
806
|
+
// <Stack spacing={1} sx={{ maxHeight: '300px', overflowY: 'auto' }}>
|
|
807
|
+
// {state.presets.length === 0 && !state.presetsLoading ? (
|
|
808
|
+
// <Typography variant="body2" color="text.secondary" sx={{ textAlign: 'center', py: 2 }}>
|
|
809
|
+
// No presets available. Create your first preset below!
|
|
810
|
+
// </Typography>
|
|
811
|
+
// ) : (
|
|
812
|
+
// state.presets.map((preset) => (
|
|
813
|
+
// <PresetCard
|
|
814
|
+
// key={preset.id}
|
|
815
|
+
// preset={preset}
|
|
816
|
+
// onApply={actions.applyPreset}
|
|
817
|
+
// onDelete={actions.deletePreset}
|
|
818
|
+
// isActive={state.activePreset?.id === preset.id}
|
|
819
|
+
// />
|
|
820
|
+
// ))
|
|
821
|
+
// )}
|
|
822
|
+
// </Stack>
|
|
823
|
+
// {/* Create New Preset */}
|
|
824
|
+
// <Divider sx={{ my: 2 }} />
|
|
825
|
+
// <Typography variant="subtitle2" gutterBottom>
|
|
826
|
+
// Create New Preset
|
|
827
|
+
// </Typography>
|
|
828
|
+
// <Typography variant="caption" color="text.secondary" display="block" sx={{ mb: 1 }}>
|
|
829
|
+
// Save current adjustments as a new preset
|
|
830
|
+
// </Typography>
|
|
831
|
+
// <Stack direction="row" spacing={1}>
|
|
832
|
+
// <TextField
|
|
833
|
+
// placeholder="Enter preset name..."
|
|
834
|
+
// value={newPresetName}
|
|
835
|
+
// onChange={(e) => setNewPresetName(e.target.value)}
|
|
836
|
+
// size="small"
|
|
837
|
+
// fullWidth
|
|
838
|
+
// onKeyPress={(e) => {
|
|
839
|
+
// if (e.key === 'Enter') {
|
|
840
|
+
// handleCreatePreset();
|
|
841
|
+
// }
|
|
842
|
+
// }}
|
|
843
|
+
// />
|
|
844
|
+
// <Button
|
|
845
|
+
// variant="contained"
|
|
846
|
+
// size="small"
|
|
847
|
+
// onClick={handleCreatePreset}
|
|
848
|
+
// disabled={!newPresetName.trim() || state.presetsLoading}
|
|
849
|
+
// >
|
|
850
|
+
// Create
|
|
851
|
+
// </Button>
|
|
852
|
+
// </Stack>
|
|
853
|
+
// </Paper>
|
|
854
|
+
// </Grid>
|
|
855
|
+
// </Grid>
|
|
856
|
+
// {/* Debug Information */}
|
|
857
|
+
// <Box mt={4}>
|
|
858
|
+
// <Divider />
|
|
859
|
+
// <Typography variant="body2" color="text.secondary" align="center" sx={{ mt: 2 }}>
|
|
860
|
+
// Clean Architecture Demo: This component is "dumb" and only renders UI.
|
|
861
|
+
// All logic is handled by useHonchoEditorSingle hook.
|
|
862
|
+
// </Typography>
|
|
863
|
+
// <Paper sx={{ p: 2, mt: 2, bgcolor: 'grey.50' }}>
|
|
864
|
+
// <Typography variant="caption" display="block">
|
|
865
|
+
// <strong>Debug Info:</strong><br />
|
|
866
|
+
// Current Image: {state.currentImageData?.id} |
|
|
867
|
+
// Gallery Loading: {state.isGalleryLoading ? 'Yes' : 'No'} |
|
|
868
|
+
// Image Loaded: {isImageLoaded ? 'Yes' : 'No'} |
|
|
869
|
+
// Next Available: {state.isNextAvailable ? 'Yes' : 'No'} |
|
|
870
|
+
// Prev Available: {state.isPrevAvailable ? 'Yes' : 'No'} |
|
|
871
|
+
// Active Preset: {state.activePreset?.name || 'None'} |
|
|
872
|
+
// Can Undo: {state.canUndo ? 'Yes' : 'No'} |
|
|
873
|
+
// Can Redo: {state.canRedo ? 'Yes' : 'No'} |
|
|
874
|
+
// Batch Mode: {state.isBatchMode ? 'Yes' : 'No'} |
|
|
875
|
+
// Editor Ready: {editorHeadless.isReady ? 'Yes' : 'No'}
|
|
876
|
+
// </Typography>
|
|
877
|
+
// </Paper>
|
|
878
|
+
// </Box>
|
|
879
|
+
// </Container>
|
|
880
|
+
// );
|
|
881
|
+
// };
|
|
882
|
+
// export default HonchoEditorSingleCleanDemo;
|