@dashadmin/dash-components 1.3.73 → 1.3.74-srcfree.2

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 (111) hide show
  1. package/dist/components/AuditLog/AuditLog.d.ts +27 -0
  2. package/dist/components/AutoCompleteArrayInput/AutoCompleteCheckBoxInput.d.ts +22 -0
  3. package/dist/components/AutoCompleteArrayInput/AutocompleteCheckBoxArrayInput.d.ts +7 -0
  4. package/dist/components/AutoCompleteArrayInputAutoSearch/AutoCompleteCheckBoxInput.d.ts +22 -0
  5. package/dist/components/AutoCompleteArrayInputAutoSearch/AutocompleteCheckBoxArrayInput.d.ts +7 -0
  6. package/dist/components/Json/Json.d.ts +5 -0
  7. package/dist/components/JsonColorSelector/JsonColorSelector.d.ts +5 -0
  8. package/dist/components/JsonColorSelector/JsonColorSelectorEnhanced.d.ts +4 -0
  9. package/dist/components/JsonColorSelector/JsonCssVarValues.d.ts +5 -0
  10. package/dist/components/JsonColorSelector/components/BasicColorSelector.d.ts +9 -0
  11. package/dist/components/JsonColorSelector/components/ColorEditDialog.d.ts +12 -0
  12. package/dist/components/JsonColorSelector/components/ColorPaletteItem.d.ts +7 -0
  13. package/dist/components/JsonColorSelector/components/ImageColorExtractor.d.ts +9 -0
  14. package/dist/components/JsonColorSelector/helpers/functions.d.ts +11 -0
  15. package/dist/components/JsonColorSelector/helpers/paletteDerivation.d.ts +37 -0
  16. package/{src/components/JsonColorSelector/interfaces/interfaces.tsx → dist/components/JsonColorSelector/interfaces/interfaces.d.ts} +6 -8
  17. package/dist/components/JsonColorSelector/useAsyncColorThief.d.ts +11 -0
  18. package/dist/components/ListActive/ListActive.d.ts +10 -0
  19. package/dist/components/ListActive/ListBoolean.d.ts +10 -0
  20. package/dist/components/NotificationPreferences/NotificationPreferences.d.ts +6 -0
  21. package/dist/components/SearchableSelects/RASearchableSelect.d.ts +25 -0
  22. package/dist/components/SearchableSelects/RASearchableSelectCheckboxes.d.ts +35 -0
  23. package/dist/components/SearchableSelects/RASearchableSelectChips.d.ts +33 -0
  24. package/dist/components/SearchableSelects/RASearchableSelectChipsRecordContext.d.ts +30 -0
  25. package/dist/components/SearchableSelects/SearchableSelect.d.ts +25 -0
  26. package/dist/components/SearchableSelects/SearchableSelectCheckboxes.d.ts +29 -0
  27. package/dist/components/SortableDataGrid/SortableDataGrid.d.ts +7 -0
  28. package/dist/components/SortableDataGrid/SortableDataGridBody.d.ts +7 -0
  29. package/dist/components/SortableDataGrid/SortableDataGridHeader.d.ts +6 -0
  30. package/dist/components/SortableDataGrid/SortableDataGridRow.d.ts +5 -0
  31. package/dist/components/Upload/SingleImageUploader.d.ts +8 -0
  32. package/dist/components/custom/PackageCopyMethod.d.ts +15 -0
  33. package/dist/components/custom/PackageRadioButtonGroup.d.ts +8 -0
  34. package/dist/components/dialog/Basic.d.ts +2 -0
  35. package/dist/components/dialog/Correct.d.ts +2 -0
  36. package/dist/components/dialog/Error.d.ts +2 -0
  37. package/dist/components/dialog/Info.d.ts +2 -0
  38. package/dist/components/dialog/InfoV2.d.ts +2 -0
  39. package/dist/components/dialog/NotFound.d.ts +2 -0
  40. package/dist/components/dialog/QuickSearch.d.ts +6 -0
  41. package/dist/components/notifications/NotificationsCenter.d.ts +109 -0
  42. package/dist/components/notifications/index.d.ts +2 -0
  43. package/dist/components/tables/PaginationComponent.d.ts +4 -0
  44. package/dist/components/theme/AppLoadingFallback.d.ts +6 -0
  45. package/dist/components/theme/ErrorBoundary.d.ts +19 -0
  46. package/dist/components/theme/InitialLoader.d.ts +3 -0
  47. package/dist/components/theme/NotFound.d.ts +13 -0
  48. package/dist/components/theme/NotResults.d.ts +7 -0
  49. package/dist/hooks/useDraggable.d.ts +1 -0
  50. package/dist/hooks/useNotifications.d.ts +2 -0
  51. package/dist/hooks/useQuickSearch.d.ts +6 -0
  52. package/{src/index.tsx → dist/index.d.ts} +10 -58
  53. package/dist/utils/setNativeValue.d.ts +2 -0
  54. package/package.json +24 -21
  55. package/src/components/AuditLog/AuditLog.tsx +0 -490
  56. package/src/components/AutoCompleteArrayInput/AutoCompleteCheckBoxInput.tsx +0 -917
  57. package/src/components/AutoCompleteArrayInput/AutocompleteCheckBoxArrayInput.tsx +0 -39
  58. package/src/components/AutoCompleteArrayInputAutoSearch/AutoCompleteCheckBoxInput.tsx +0 -916
  59. package/src/components/AutoCompleteArrayInputAutoSearch/AutocompleteCheckBoxArrayAutoSearch.tsx.wip +0 -42
  60. package/src/components/AutoCompleteArrayInputAutoSearch/AutocompleteCheckBoxArrayInput.tsx +0 -44
  61. package/src/components/Json/Json.tsx +0 -312
  62. package/src/components/JsonColorSelector/JsonColorSelector.tsx +0 -1443
  63. package/src/components/JsonColorSelector/JsonColorSelector.tsx.bkup +0 -746
  64. package/src/components/JsonColorSelector/JsonColorSelectorEnhanced.tsx +0 -1135
  65. package/src/components/JsonColorSelector/JsonCssVarValues.tsx +0 -867
  66. package/src/components/JsonColorSelector/components/BasicColorSelector.tsx +0 -333
  67. package/src/components/JsonColorSelector/components/ColorEditDialog.tsx +0 -495
  68. package/src/components/JsonColorSelector/components/ColorPaletteItem.tsx +0 -80
  69. package/src/components/JsonColorSelector/components/ImageColorExtractor.tsx +0 -420
  70. package/src/components/JsonColorSelector/helpers/functions.tsx +0 -123
  71. package/src/components/JsonColorSelector/helpers/paletteDerivation.ts +0 -367
  72. package/src/components/JsonColorSelector/useAsyncColorThief.tsx +0 -97
  73. package/src/components/ListActive/ListActive.tsx +0 -106
  74. package/src/components/ListActive/ListBoolean.tsx +0 -96
  75. package/src/components/NotificationPreferences/NotificationPreferences.tsx +0 -480
  76. package/src/components/SearchableSelects/RASearchableSelect.tsx +0 -303
  77. package/src/components/SearchableSelects/RASearchableSelectCheckboxes.tsx +0 -617
  78. package/src/components/SearchableSelects/RASearchableSelectChips.tsx +0 -561
  79. package/src/components/SearchableSelects/RASearchableSelectChipsRecordContext.tsx +0 -366
  80. package/src/components/SearchableSelects/SearchableSelect.tsx +0 -323
  81. package/src/components/SearchableSelects/SearchableSelectCheckboxes.tsx +0 -358
  82. package/src/components/SortableDataGrid/README.md +0 -1
  83. package/src/components/SortableDataGrid/SortableDataGrid.tsx +0 -56
  84. package/src/components/SortableDataGrid/SortableDataGridBody.tsx +0 -175
  85. package/src/components/SortableDataGrid/SortableDataGridHeader.tsx +0 -171
  86. package/src/components/SortableDataGrid/SortableDataGridRow.tsx +0 -247
  87. package/src/components/Upload/SingleImageUploader.tsx +0 -55
  88. package/src/components/custom/PackageCopyMethod.tsx +0 -109
  89. package/src/components/custom/PackageRadioButtonGroup.tsx +0 -49
  90. package/src/components/dialog/Basic.tsx +0 -11
  91. package/src/components/dialog/Correct.tsx +0 -16
  92. package/src/components/dialog/Error.tsx +0 -15
  93. package/src/components/dialog/Info.tsx +0 -15
  94. package/src/components/dialog/InfoV2.tsx +0 -35
  95. package/src/components/dialog/NotFound.tsx +0 -18
  96. package/src/components/dialog/QuickSearch.tsx +0 -115
  97. package/src/components/notifications/NotificationsCenter.tsx +0 -743
  98. package/src/components/notifications/index.ts +0 -42
  99. package/src/components/tables/PaginationComponent.tsx +0 -17
  100. package/src/components/theme/AppLoadingFallback.tsx +0 -42
  101. package/src/components/theme/ErrorBoundary.tsx +0 -57
  102. package/src/components/theme/InitialLoader.tsx +0 -16
  103. package/src/components/theme/NotFound.tsx +0 -124
  104. package/src/components/theme/NotResults.tsx +0 -56
  105. package/src/hooks/useDraggable.ts +0 -11
  106. package/src/hooks/useNotifications.ts +0 -14
  107. package/src/hooks/useQuickSearch.tsx +0 -29
  108. package/src/styles/index.less +0 -0
  109. package/src/utils/setNativeValue.tsx +0 -23
  110. /package/{src/components/AuditLog/index.ts → dist/components/AuditLog/index.d.ts} +0 -0
  111. /package/{src/components/NotificationPreferences/index.tsx → dist/components/NotificationPreferences/index.d.ts} +0 -0
@@ -1,420 +0,0 @@
1
- import {
2
- Box,
3
- Button,
4
- IconButton,
5
- Typography,
6
- Card,
7
- CardMedia,
8
- CircularProgress,
9
- Input,
10
- Alert,
11
- TextField,
12
- Divider,
13
- } from '@mui/material';
14
-
15
- import DeleteIcon from '@mui/icons-material/Delete';
16
- import CloudUploadIcon from '@mui/icons-material/CloudUpload';
17
- import PaletteIcon from '@mui/icons-material/Palette';
18
- import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh';
19
- import UpdateIcon from '@mui/icons-material/Update';
20
- import { useState, useEffect, memo, useCallback } from 'react';
21
- import { useTranslate } from 'react-admin';
22
- import { useAsyncColorThief } from '../useAsyncColorThief';
23
- import { getContrastColor, rgbArrayToHex } from '../helpers/functions';
24
- import { KeyValuePair } from '../interfaces/interfaces';
25
- import { useAxios } from 'dash-axios-hook';
26
-
27
- const MAX_IMAGE_MB = 5;
28
-
29
- const ImageColorExtractor = memo<{
30
- onColorsExtracted: (colors: number[][]) => void;
31
- onColorsUpdate?: (newPairs: KeyValuePair[]) => void;
32
- existingPairs?: KeyValuePair[];
33
- /** When false, the OpenAI theme generation UI is hidden — only local extraction applies. */
34
- aiEnabled?: boolean;
35
- /** Local (no-AI) apply: receives the extracted RGB palette so the caller can map it to base colors. */
36
- onApplyLocal?: (palette: number[][]) => void;
37
- }>(({ onColorsExtracted, onColorsUpdate, existingPairs = [], aiEnabled = true, onApplyLocal }) => {
38
- const translate = useTranslate();
39
- const [imageUrl, setImageUrl] = useState<string | null>(null);
40
- const [uploadedFile, setUploadedFile] = useState<File | null>(null);
41
- const [themePrompt, setThemePrompt] = useState<string>('');
42
- const [isGeneratingTheme, setIsGeneratingTheme] = useState<boolean>(false);
43
- const [themeError, setThemeError] = useState<string | null>(null);
44
- const [isDragOver, setIsDragOver] = useState<boolean>(false);
45
-
46
- // Add state to preserve extracted colors independently
47
- const [extractedPalette, setExtractedPalette] = useState<number[][]>([]);
48
-
49
- const axios = useAxios();
50
- const { dominantColor, palette, loading, error } = useAsyncColorThief(imageUrl, {
51
- colorCount: 8,
52
- quality: 10
53
- });
54
-
55
- // Update internal extracted palette state
56
- useEffect(() => {
57
- if (palette && palette.length > 0) {
58
- setExtractedPalette(palette);
59
- onColorsExtracted(palette);
60
- }
61
- }, [palette, onColorsExtracted]);
62
-
63
- // Shared validation + preview setup for a file coming from either the file
64
- // input or a drag-and-drop, so the two paths can never drift apart.
65
- const processFile = useCallback((file: File) => {
66
- // Validate file type
67
- if (!file.type.startsWith('image/')) {
68
- alert(translate('colorSelector.imageExtractor.invalid_file_type'));
69
- return;
70
- }
71
-
72
- // Validate file size
73
- if (file.size > MAX_IMAGE_MB * 1024 * 1024) {
74
- alert(translate('colorSelector.imageExtractor.file_too_large', { limit: MAX_IMAGE_MB }));
75
- return;
76
- }
77
-
78
- setUploadedFile(file);
79
-
80
- // Create preview URL
81
- const previewUrl = URL.createObjectURL(file);
82
- setImageUrl(previewUrl);
83
- }, [translate]);
84
-
85
- // Handle file selection for upload
86
- const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
87
- const file = event.target.files?.[0];
88
- if (file) {
89
- processFile(file);
90
- }
91
- };
92
-
93
- // Drag-and-drop onto the upload dropzone
94
- const handleDragOver = useCallback((event: React.DragEvent<HTMLDivElement>) => {
95
- event.preventDefault();
96
- event.stopPropagation();
97
- setIsDragOver(true);
98
- }, []);
99
-
100
- const handleDragLeave = useCallback((event: React.DragEvent<HTMLDivElement>) => {
101
- event.preventDefault();
102
- event.stopPropagation();
103
- setIsDragOver(false);
104
- }, []);
105
-
106
- const handleDrop = useCallback((event: React.DragEvent<HTMLDivElement>) => {
107
- event.preventDefault();
108
- event.stopPropagation();
109
- setIsDragOver(false);
110
-
111
- const file = event.dataTransfer.files?.[0];
112
- if (file) {
113
- processFile(file);
114
- }
115
- }, [processFile]);
116
-
117
- // Handle image removal
118
- const handleImageRemove = () => {
119
- if (imageUrl && imageUrl.startsWith('blob:')) {
120
- URL.revokeObjectURL(imageUrl);
121
- }
122
-
123
- setImageUrl(null);
124
- setUploadedFile(null);
125
- setExtractedPalette([]); // Clear internal palette state
126
- onColorsExtracted([]); // Clear extracted colors
127
- };
128
-
129
- // Generate theme using AI - Modified to merge with existing colors
130
- const handleGenerateTheme = useCallback(async () => {
131
- if (!extractedPalette || extractedPalette.length === 0) {
132
- setThemeError(translate('colorSelector.imageExtractor.no_palette_error'));
133
- return;
134
- }
135
-
136
- setIsGeneratingTheme(true);
137
- setThemeError(null);
138
-
139
- try {
140
- const response = await axios.post('/tenant/tenant/settings/theme-generator', {
141
- colors: extractedPalette,
142
- prompt: themePrompt,
143
- output_format: 'json'
144
- });
145
-
146
- if (response.status !== 200) {
147
- throw new Error(`HTTP error! status: ${response.status}`);
148
- }
149
-
150
- const result = response.data;
151
-
152
- if (result.success && result.data) {
153
- // Convert the generated theme to KeyValuePair format
154
- const newPairs: KeyValuePair[] = Object.entries(result.data).map(([key, value]) => ({
155
- key,
156
- value: String(value),
157
- id: Math.random().toString(36).substring(2, 11)
158
- }));
159
-
160
- // Merge with existing pairs instead of replacing them
161
- const mergedPairs = [...existingPairs];
162
-
163
- newPairs.forEach(newPair => {
164
- const existingIndex = mergedPairs.findIndex(existing => existing.key === newPair.key);
165
- if (existingIndex >= 0) {
166
- // Update existing pair
167
- mergedPairs[existingIndex] = newPair;
168
- } else {
169
- // Add new pair
170
- mergedPairs.push(newPair);
171
- }
172
- });
173
-
174
- // Update the colors in the parent component
175
- if (onColorsUpdate) {
176
- onColorsUpdate(mergedPairs);
177
- }
178
- } else {
179
- throw new Error(result.message || translate('colorSelector.imageExtractor.theme_generation_failed'));
180
- }
181
- } catch (error) {
182
- console.error('Theme generation error:', error);
183
- setThemeError(
184
- error instanceof Error
185
- ? error.message
186
- : translate('colorSelector.imageExtractor.theme_generation_failed')
187
- );
188
- } finally {
189
- setIsGeneratingTheme(false);
190
- }
191
- }, [extractedPalette, themePrompt, existingPairs, onColorsUpdate, axios, translate]);
192
-
193
- return (
194
- <Box sx={{ mt: 3, p: 3, borderRadius: 2 }}>
195
- <Typography variant="h6" gutterBottom sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
196
- <PaletteIcon />
197
- {aiEnabled
198
- ? translate('colorSelector.imageExtractor.title_ai')
199
- : translate('colorSelector.imageExtractor.title_local')}
200
- </Typography>
201
-
202
- <Divider sx={{ mb: 3 }} />
203
-
204
- {/* Image Upload Section */}
205
- <Box sx={{ mb: 3 }}>
206
- {!imageUrl ? (
207
- <Box
208
- onDragEnter={handleDragOver}
209
- onDragOver={handleDragOver}
210
- onDragLeave={handleDragLeave}
211
- onDrop={handleDrop}
212
- sx={{
213
- textAlign: 'center',
214
- py: 4,
215
- backgroundColor: isDragOver ? 'rgba(25, 118, 210, 0.08)' : 'rgba(0,0,0,0.02)',
216
- borderRadius: 1,
217
- border: isDragOver ? '2px dashed #1976d2' : '2px dashed #e0e0e0',
218
- transition: 'background-color 0.2s ease, border-color 0.2s ease',
219
- }}
220
- >
221
- <Input
222
- type="file"
223
- inputProps={{ accept: 'image/*' }}
224
- onChange={handleFileSelect}
225
- sx={{ display: 'none' }}
226
- id="color-extractor-upload"
227
- />
228
- <Typography variant="body1" color="textSecondary" gutterBottom>
229
- {translate('colorSelector.imageExtractor.upload_prompt')}
230
- </Typography>
231
- <Typography variant="body2" color="textSecondary" sx={{ mb: 2 }}>
232
- {translate('colorSelector.imageExtractor.upload_hint')}
233
- </Typography>
234
- <label htmlFor="color-extractor-upload">
235
- <Button
236
- variant="contained"
237
- component="span"
238
- startIcon={<CloudUploadIcon />}
239
- size="large"
240
- >
241
- {translate('colorSelector.imageExtractor.upload_button')}
242
- </Button>
243
- </label>
244
- <Typography variant="caption" color="textSecondary" sx={{ display: 'block', mt: 1.5 }}>
245
- {translate('colorSelector.imageExtractor.drop_hint')}
246
- </Typography>
247
- </Box>
248
- ) : (
249
- <Card sx={{ maxWidth: 400, mb: 3 }}>
250
- <Box sx={{ position: 'relative' }}>
251
- <CardMedia
252
- component="img"
253
- height="200"
254
- image={imageUrl}
255
- alt={translate('colorSelector.imageExtractor.uploaded_image_alt')}
256
- sx={{ objectFit: 'contain' }}
257
- />
258
- <IconButton
259
- sx={{
260
- position: 'absolute',
261
- top: 8,
262
- right: 8,
263
- backgroundColor: 'rgba(255, 255, 255, 0.9)',
264
- '&:hover': {
265
- backgroundColor: 'rgba(255, 255, 255, 1)',
266
- },
267
- }}
268
- onClick={handleImageRemove}
269
- size="small"
270
- >
271
- <DeleteIcon />
272
- </IconButton>
273
- </Box>
274
- </Card>
275
- )}
276
- </Box>
277
-
278
- {/* Color Extraction Status */}
279
- {loading && (
280
- <Box
281
- sx={{
282
- display: "flex",
283
- alignItems: "center",
284
- gap: 2,
285
- mb: 3,
286
- p: 2,
287
- backgroundColor: 'rgba(25, 118, 210, 0.04)',
288
- borderRadius: 1
289
- }}>
290
- <CircularProgress size={20} />
291
- <Typography>{translate('colorSelector.imageExtractor.extracting')}</Typography>
292
- </Box>
293
- )}
294
-
295
- {error && (
296
- <Alert severity="error" sx={{ mb: 3 }}>
297
- {error}
298
- </Alert>
299
- )}
300
-
301
- {themeError && (
302
- <Alert severity="error" sx={{ mb: 3 }}>
303
- {themeError}
304
- </Alert>
305
- )}
306
-
307
- {/* Extracted Colors Display - Use internal state */}
308
- {extractedPalette && extractedPalette.length > 0 && !loading && (
309
- <Box sx={{ mb: 3 }}>
310
- <Typography variant="subtitle1" gutterBottom>
311
- {translate('colorSelector.imageExtractor.extracted_colors', { count: extractedPalette.length })}
312
- </Typography>
313
-
314
- <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1, mt: 2, mb: 3 }}>
315
- {extractedPalette.map((color, index) => {
316
- const hexColor = rgbArrayToHex(color);
317
- const isDominant = dominantColor &&
318
- color[0] === dominantColor[0] &&
319
- color[1] === dominantColor[1] &&
320
- color[2] === dominantColor[2];
321
-
322
- return (
323
- <Box
324
- key={index}
325
- sx={{
326
- width: 50,
327
- height: 50,
328
- backgroundColor: hexColor,
329
- borderRadius: '50%',
330
- display: 'flex',
331
- alignItems: 'center',
332
- justifyContent: 'center',
333
- border: isDominant ? '3px solid #4caf50' : '2px solid #ccc',
334
- cursor: 'pointer',
335
- transition: 'transform 0.2s',
336
- '&:hover': {
337
- transform: 'scale(1.1)',
338
- },
339
- }}
340
- title={`${hexColor} ${isDominant ? `(${translate('colorSelector.imageExtractor.dominant_label')})` : ''}`}
341
- >
342
- <Typography
343
- variant="caption"
344
- sx={{
345
- color: getContrastColor(hexColor),
346
- fontWeight: 'bold',
347
- fontSize: '0.8rem',
348
- }}
349
- >
350
- {index + 1}
351
- </Typography>
352
- </Box>
353
- );
354
- })}
355
- </Box>
356
-
357
- {/* Theme Generation Controls */}
358
- <Box sx={{ mb: 3 }}>
359
- {aiEnabled && (
360
- <TextField
361
- fullWidth
362
- multiline
363
- rows={2}
364
- placeholder={translate('colorSelector.imageExtractor.theme_description_placeholder')}
365
- value={themePrompt}
366
- onChange={(e) => setThemePrompt(e.target.value)}
367
- sx={{ mb: 2 }}
368
- label={translate('colorSelector.imageExtractor.theme_description_label')}
369
- />
370
- )}
371
-
372
- <Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}>
373
- {onApplyLocal && (
374
- <Button
375
- variant={aiEnabled ? 'outlined' : 'contained'}
376
- startIcon={<UpdateIcon />}
377
- onClick={() => onApplyLocal(extractedPalette)}
378
- color="primary"
379
- >
380
- {translate('colorSelector.imageExtractor.apply_colors_button')}
381
- </Button>
382
- )}
383
- {aiEnabled && (
384
- <Button
385
- variant="contained"
386
- startIcon={isGeneratingTheme ? <CircularProgress size={16} /> : <AutoFixHighIcon />}
387
- onClick={handleGenerateTheme}
388
- disabled={isGeneratingTheme}
389
- color="primary"
390
- >
391
- {isGeneratingTheme
392
- ? translate('colorSelector.imageExtractor.generating_button')
393
- : translate('colorSelector.imageExtractor.generate_button')}
394
- </Button>
395
- )}
396
- </Box>
397
- </Box>
398
-
399
- <Typography variant="body2" color="textSecondary" sx={{ fontStyle: 'italic' }}>
400
- {onApplyLocal && (
401
- <>
402
- • <strong>{translate('colorSelector.imageExtractor.apply_colors_help_label')}</strong>{' '}
403
- {translate('colorSelector.imageExtractor.apply_colors_help_desc')}
404
- <br />
405
- </>
406
- )}
407
- {aiEnabled && (
408
- <>
409
- • <strong>{translate('colorSelector.imageExtractor.generate_help_label')}</strong>{' '}
410
- {translate('colorSelector.imageExtractor.generate_help_desc')}
411
- </>
412
- )}
413
- </Typography>
414
- </Box>
415
- )}
416
- </Box>
417
- );
418
- });
419
-
420
- export default ImageColorExtractor;
@@ -1,123 +0,0 @@
1
- import { ColorFormat, ColorFormatType, KeyValuePair } from "../interfaces/interfaces";
2
-
3
- // Helper function to determine text color based on background
4
- export const getContrastColor = (color: string): string => {
5
- // Handle different color formats
6
- let r: number, g: number, b: number, a: number = 1;
7
-
8
- if (color.startsWith('#')) {
9
- // Hex color
10
- const hex = color.replace('#', '');
11
- if (hex.length === 8) {
12
- // RGBA hex
13
- r = parseInt(hex.substr(0, 2), 16);
14
- g = parseInt(hex.substr(2, 2), 16);
15
- b = parseInt(hex.substr(4, 2), 16);
16
- a = parseInt(hex.substr(6, 2), 16) / 255;
17
- } else {
18
- // RGB hex
19
- r = parseInt(hex.substr(0, 2), 16);
20
- g = parseInt(hex.substr(2, 2), 16);
21
- b = parseInt(hex.substr(4, 2), 16);
22
- }
23
- } else if (color.startsWith('rgb')) {
24
- // RGB/RGBA color
25
- const match = color.match(/rgba?\(([^)]+)\)/);
26
- if (match) {
27
- const values = match[1].split(',').map(v => parseFloat(v.trim()));
28
- [r, g, b, a = 1] = values;
29
- } else {
30
- return '#000000';
31
- }
32
- } else if (color.startsWith('hsl')) {
33
- // For HSL, we'll use a simple approach
34
- return '#000000';
35
- } else {
36
- return '#000000';
37
- }
38
-
39
- // Calculate luminance considering alpha
40
- const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
41
- const effectiveLuminance = luminance * a + (1 - a); // Blend with white background
42
-
43
- return effectiveLuminance > 0.5 ? '#000000' : '#ffffff';
44
- };
45
-
46
- // Helper function to convert color to different formats
47
- // Helper function to convert color to different formats - Updated
48
- export const convertColor = (color: ColorFormat, format: ColorFormatType): string => {
49
- switch (format) {
50
- case 'hex':
51
- // For hex, we'll ignore alpha or convert to 8-digit hex if alpha < 1
52
- if (color.rgb.a !== undefined && color.rgb.a < 1) {
53
- const alpha = Math.round(color.rgb.a * 255);
54
- const alphaHex = alpha.toString(16).padStart(2, '0');
55
- return `${color.hex}${alphaHex}`;
56
- }
57
- return color.hex;
58
- case 'rgb':
59
- return `rgb(${Math.round(color.rgb.r)}, ${Math.round(color.rgb.g)}, ${Math.round(color.rgb.b)})`;
60
- case 'rgba':
61
- const alpha = color.rgb.a !== undefined ? Number(color.rgb.a.toFixed(2)) : 1;
62
- return `rgba(${Math.round(color.rgb.r)}, ${Math.round(color.rgb.g)}, ${Math.round(color.rgb.b)}, ${alpha})`;
63
- case 'hsl':
64
- return `hsl(${Math.round(color.hsl.h)}, ${Math.round(color.hsl.s * 100)}%, ${Math.round(color.hsl.l * 100)}%)`;
65
- case 'hsla':
66
- const hslaAlpha = color.hsl.a !== undefined ? Number(color.hsl.a.toFixed(2)) : 1;
67
- return `hsla(${Math.round(color.hsl.h)}, ${Math.round(color.hsl.s * 100)}%, ${Math.round(color.hsl.l * 100)}%, ${hslaAlpha})`;
68
- default:
69
- return color.hex;
70
- }
71
- };
72
- // Helper function to parse color key and create chips
73
- export const parseColorKey = (key: string) => {
74
- const parts = key.split('--');
75
- const baseName = parts[0];
76
- const mode = parts[1];
77
-
78
- // Split base name by hyphens for individual chips
79
- const baseChips = baseName.split('-').filter(part => part.length > 0);
80
-
81
- return { baseChips, mode };
82
- };
83
-
84
- // Helper function to extract available modes from color keys
85
- export const extractAvailableModes = (pairs: KeyValuePair[]): string[] => {
86
- const modes = new Set<string>();
87
-
88
- pairs.forEach(pair => {
89
- const { mode } = parseColorKey(pair.key);
90
- if (mode) {
91
- modes.add(mode);
92
- }
93
- });
94
-
95
- return Array.from(modes).sort();
96
- };
97
-
98
- // Helper function to get mode icon
99
- export const getModeIcon = (mode: string | undefined): string => {
100
- if (!mode) return '';
101
-
102
- switch (mode.toLowerCase()) {
103
- case 'light':
104
- return '☀️'; // Sun icon
105
- case 'dark':
106
- return '🌙'; // Moon icon
107
- default:
108
- return mode; // Plain text for other modes
109
- }
110
- };
111
-
112
- // Helper function to convert RGB array to hex
113
- export const rgbArrayToHex = (rgb: number[]): string => {
114
- const [r, g, b] = rgb;
115
- return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
116
- };
117
-
118
- // Helper function to convert RGB array to rgb string
119
- export const rgbArrayToRgbString = (rgb: number[]): string => {
120
- const [r, g, b] = rgb;
121
- return `rgb(${r}, ${g}, ${b})`;
122
- };
123
-