DotSlashGabut commited on
Commit
d823205
Β·
verified Β·
1 Parent(s): 753339f

the ui still not change to dark mode or white mode. fix that - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +946 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Chromagen Color Palette
3
- emoji: 😻
4
- colorFrom: pink
5
- colorTo: indigo
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: chromagen-color-palette
3
+ emoji: 🐳
4
+ colorFrom: yellow
5
+ colorTo: purple
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,946 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>ChromaGen - Advanced Color Generator</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"></script>
9
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/color-thief/2.3.0/color-thief.umd.js"></script>
10
+ <style>
11
+ @keyframes fadeIn {
12
+ from { opacity: 0; transform: translateY(10px); }
13
+ to { opacity: 1; transform: translateY(0); }
14
+ }
15
+
16
+ .color-card {
17
+ animation: fadeIn 0.3s ease-out forwards;
18
+ opacity: 0;
19
+ }
20
+
21
+ .color-card:nth-child(1) { animation-delay: 0.1s; }
22
+ .color-card:nth-child(2) { animation-delay: 0.2s; }
23
+ .color-card:nth-child(3) { animation-delay: 0.3s; }
24
+ .color-card:nth-child(4) { animation-delay: 0.4s; }
25
+ .color-card:nth-child(5) { animation-delay: 0.5s; }
26
+
27
+ .gradient-bg {
28
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
29
+ }
30
+
31
+ .image-preview {
32
+ transition: all 0.3s ease;
33
+ }
34
+
35
+ .image-preview:hover {
36
+ transform: scale(1.02);
37
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
38
+ }
39
+
40
+ .toggle-checkbox:checked {
41
+ right: 0;
42
+ background-color: #4f46e5;
43
+ }
44
+
45
+ .toggle-checkbox:checked + .toggle-label {
46
+ background-color: #4f46e5;
47
+ }
48
+
49
+ .color-swatch {
50
+ transition: all 0.2s ease;
51
+ }
52
+
53
+ .color-swatch:hover {
54
+ transform: scale(1.05);
55
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
56
+ z-index: 10;
57
+ }
58
+ </style>
59
+ </head>
60
+ <body class="bg-gray-100 dark:bg-gray-900 text-gray-800 dark:text-gray-200 transition-colors duration-300">
61
+ <div class="min-h-screen flex flex-col">
62
+ <!-- Header -->
63
+ <header class="gradient-bg text-white py-6 shadow-lg">
64
+ <div class="container mx-auto px-4">
65
+ <div class="flex justify-between items-center">
66
+ <h1 class="text-3xl font-bold tracking-tight">
67
+ <i class="fas fa-palette mr-2"></i> ChromaGen
68
+ </h1>
69
+ <div class="flex items-center space-x-4">
70
+ <div class="flex items-center">
71
+ <span class="mr-2"><i class="fas fa-moon"></i></span>
72
+ <div class="relative inline-block w-12 mr-2 align-middle select-none">
73
+ <input type="checkbox" id="toggle" class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer transition-transform duration-200 ease-in-out" checked/>
74
+ <label for="toggle" class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer transition-colors duration-200 ease-in-out w-12"></label>
75
+ </div>
76
+ <span><i class="fas fa-sun"></i></span>
77
+ </div>
78
+ <button id="info-btn" class="p-2 rounded-full hover:bg-white hover:bg-opacity-20 transition-colors">
79
+ <i class="fas fa-info-circle text-xl"></i>
80
+ </button>
81
+ </div>
82
+ </div>
83
+ <p class="mt-2 opacity-90">Advanced color palette generator with image extraction</p>
84
+ </div>
85
+ </header>
86
+
87
+ <!-- Main Content -->
88
+ <main class="flex-grow container mx-auto px-4 py-8">
89
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
90
+ <!-- Controls Section -->
91
+ <div class="lg:col-span-1 bg-white dark:bg-gray-800 rounded-xl shadow-lg p-6">
92
+ <h2 class="text-xl font-semibold mb-4 flex items-center">
93
+ <i class="fas fa-sliders-h mr-2"></i> Controls
94
+ </h2>
95
+
96
+ <div class="space-y-6">
97
+ <!-- Color Category -->
98
+ <div>
99
+ <label class="block text-sm font-medium mb-2">Color Category</label>
100
+ <select id="color-category" class="w-full p-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition">
101
+ <option value="any">Any Color</option>
102
+ <option value="warm">Warm Colors</option>
103
+ <option value="cool">Cool Colors</option>
104
+ <option value="pastel">Pastel Colors</option>
105
+ <option value="vibrant">Vibrant Colors</option>
106
+ <option value="monochrome">Monochrome</option>
107
+ <option value="analogous">Analogous</option>
108
+ <option value="complementary">Complementary</option>
109
+ <option value="triadic">Triadic</option>
110
+ </select>
111
+ </div>
112
+
113
+ <!-- Color Count -->
114
+ <div>
115
+ <label class="block text-sm font-medium mb-2">Number of Colors</label>
116
+ <input id="color-count" type="range" min="1" max="12" value="5" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700">
117
+ <div class="flex justify-between text-xs text-gray-500 dark:text-gray-400 mt-1">
118
+ <span>1</span>
119
+ <span>12</span>
120
+ </div>
121
+ <div class="text-center mt-1">
122
+ <span id="count-display" class="font-medium">5</span> colors
123
+ </div>
124
+ </div>
125
+
126
+ <!-- Generate Button -->
127
+ <button id="generate-btn" class="w-full py-3 px-4 bg-indigo-600 hover:bg-indigo-700 text-white font-medium rounded-lg shadow-md transition duration-300 flex items-center justify-center">
128
+ <i class="fas fa-random mr-2"></i> Generate Colors
129
+ </button>
130
+
131
+ <!-- Divider -->
132
+ <div class="relative">
133
+ <div class="absolute inset-0 flex items-center">
134
+ <div class="w-full border-t border-gray-300 dark:border-gray-600"></div>
135
+ </div>
136
+ <div class="relative flex justify-center">
137
+ <span class="px-2 bg-white dark:bg-gray-800 text-sm text-gray-500">OR</span>
138
+ </div>
139
+ </div>
140
+
141
+ <!-- Image Extraction -->
142
+ <div>
143
+ <label class="block text-sm font-medium mb-2">Extract from Image</label>
144
+ <div class="flex space-x-2">
145
+ <input id="image-url" type="text" placeholder="Image URL" class="flex-grow p-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition">
146
+ <button id="load-url-btn" class="p-2 bg-gray-200 dark:bg-gray-700 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition">
147
+ <i class="fas fa-link"></i>
148
+ </button>
149
+ </div>
150
+ <div class="mt-2">
151
+ <label for="file-upload" class="cursor-pointer w-full py-2 px-4 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 rounded-lg transition flex items-center justify-center">
152
+ <i class="fas fa-folder-open mr-2"></i> Browse File
153
+ </label>
154
+ <input id="file-upload" type="file" accept="image/*" class="hidden">
155
+ </div>
156
+ </div>
157
+
158
+ <!-- Image Preview -->
159
+ <div id="image-preview-container" class="hidden">
160
+ <label class="block text-sm font-medium mb-2">Image Preview</label>
161
+ <div class="image-preview relative overflow-hidden rounded-lg border border-gray-300 dark:border-gray-600">
162
+ <img id="preview-image" src="" alt="Preview" class="w-full h-auto max-h-48 object-cover">
163
+ <button id="clear-image" class="absolute top-2 right-2 bg-black bg-opacity-50 text-white p-1 rounded-full hover:bg-opacity-70 transition">
164
+ <i class="fas fa-times"></i>
165
+ </button>
166
+ </div>
167
+ <div class="mt-2 flex justify-between">
168
+ <span id="extract-status" class="text-sm text-gray-500 dark:text-gray-400"></span>
169
+ <button id="extract-colors-btn" class="text-sm py-1 px-3 bg-indigo-600 hover:bg-indigo-700 text-white rounded transition">
170
+ Extract Colors
171
+ </button>
172
+ </div>
173
+ </div>
174
+ </div>
175
+ </div>
176
+
177
+ <!-- Results Section -->
178
+ <div class="lg:col-span-2">
179
+ <div class="bg-white dark:bg-gray-800 rounded-xl shadow-lg p-6">
180
+ <div class="flex justify-between items-center mb-4">
181
+ <h2 class="text-xl font-semibold flex items-center">
182
+ <i class="fas fa-swatchbook mr-2"></i> Color Palette
183
+ </h2>
184
+ <div class="flex space-x-2">
185
+ <button id="copy-all-btn" class="p-2 bg-gray-100 dark:bg-gray-700 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-600 transition" title="Copy all colors">
186
+ <i class="fas fa-copy"></i>
187
+ </button>
188
+ <button id="save-palette-btn" class="p-2 bg-gray-100 dark:bg-gray-700 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-600 transition" title="Save palette">
189
+ <i class="fas fa-save"></i>
190
+ </button>
191
+ <button id="export-svg-btn" class="p-2 bg-gray-100 dark:bg-gray-700 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-600 transition" title="Export as SVG">
192
+ <i class="fas fa-file-export"></i>
193
+ </button>
194
+ </div>
195
+ </div>
196
+
197
+ <div id="color-results" class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 gap-4">
198
+ <!-- Colors will be generated here -->
199
+ <div class="color-card">
200
+ <div class="color-swatch h-24 rounded-lg shadow-md mb-2" style="background-color: #4f46e5;"></div>
201
+ <div class="text-center">
202
+ <div class="font-mono text-sm">#4f46e5</div>
203
+ <div class="text-xs text-gray-500 dark:text-gray-400">RGB(79, 70, 229)</div>
204
+ </div>
205
+ </div>
206
+ <div class="color-card">
207
+ <div class="color-swatch h-24 rounded-lg shadow-md mb-2" style="background-color: #10b981;"></div>
208
+ <div class="text-center">
209
+ <div class="font-mono text-sm">#10b981</div>
210
+ <div class="text-xs text-gray-500 dark:text-gray-400">RGB(16, 185, 129)</div>
211
+ </div>
212
+ </div>
213
+ <div class="color-card">
214
+ <div class="color-swatch h-24 rounded-lg shadow-md mb-2" style="background-color: #f59e0b;"></div>
215
+ <div class="text-center">
216
+ <div class="font-mono text-sm">#f59e0b</div>
217
+ <div class="text-xs text-gray-500 dark:text-gray-400">RGB(245, 158, 11)</div>
218
+ </div>
219
+ </div>
220
+ <div class="color-card">
221
+ <div class="color-swatch h-24 rounded-lg shadow-md mb-2" style="background-color: #ef4444;"></div>
222
+ <div class="text-center">
223
+ <div class="font-mono text-sm">#ef4444</div>
224
+ <div class="text-xs text-gray-500 dark:text-gray-400">RGB(239, 68, 68)</div>
225
+ </div>
226
+ </div>
227
+ <div class="color-card">
228
+ <div class="color-swatch h-24 rounded-lg shadow-md mb-2" style="background-color: #8b5cf6;"></div>
229
+ <div class="text-center">
230
+ <div class="font-mono text-sm">#8b5cf6</div>
231
+ <div class="text-xs text-gray-500 dark:text-gray-400">RGB(139, 92, 246)</div>
232
+ </div>
233
+ </div>
234
+ </div>
235
+ </div>
236
+
237
+ <!-- Color Details -->
238
+ <div id="color-details" class="mt-6 bg-white dark:bg-gray-800 rounded-xl shadow-lg p-6 hidden">
239
+ <h2 class="text-xl font-semibold mb-4 flex items-center">
240
+ <i class="fas fa-info-circle mr-2"></i> Color Details
241
+ </h2>
242
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
243
+ <div>
244
+ <div class="flex items-center mb-4">
245
+ <div id="detail-swatch" class="w-16 h-16 rounded-lg shadow-md mr-4"></div>
246
+ <div>
247
+ <div id="detail-hex" class="font-mono text-lg font-bold"></div>
248
+ <div id="detail-rgb" class="text-sm text-gray-500 dark:text-gray-400"></div>
249
+ </div>
250
+ </div>
251
+ <div class="space-y-2">
252
+ <div class="flex justify-between">
253
+ <span>HSL:</span>
254
+ <span id="detail-hsl" class="font-mono"></span>
255
+ </div>
256
+ <div class="flex justify-between">
257
+ <span>HSV:</span>
258
+ <span id="detail-hsv" class="font-mono"></span>
259
+ </div>
260
+ <div class="flex justify-between">
261
+ <span>CMYK:</span>
262
+ <span id="detail-cmyk" class="font-mono"></span>
263
+ </div>
264
+ </div>
265
+ </div>
266
+ <div>
267
+ <h3 class="font-medium mb-2">Color Variations</h3>
268
+ <div class="grid grid-cols-5 gap-2">
269
+ <div class="flex flex-col items-center">
270
+ <div class="w-full h-8 rounded shadow-inner" id="lighten-20"></div>
271
+ <span class="text-xs mt-1">+20%</span>
272
+ </div>
273
+ <div class="flex flex-col items-center">
274
+ <div class="w-full h-8 rounded shadow-inner" id="lighten-10"></div>
275
+ <span class="text-xs mt-1">+10%</span>
276
+ </div>
277
+ <div class="flex flex-col items-center">
278
+ <div class="w-full h-8 rounded shadow-inner border-2 border-white dark:border-gray-800 shadow-lg" id="base-color"></div>
279
+ <span class="text-xs mt-1">Base</span>
280
+ </div>
281
+ <div class="flex flex-col items-center">
282
+ <div class="w-full h-8 rounded shadow-inner" id="darken-10"></div>
283
+ <span class="text-xs mt-1">-10%</span>
284
+ </div>
285
+ <div class="flex flex-col items-center">
286
+ <div class="w-full h-8 rounded shadow-inner" id="darken-20"></div>
287
+ <span class="text-xs mt-1">-20%</span>
288
+ </div>
289
+ </div>
290
+
291
+ <h3 class="font-medium mt-4 mb-2">Accessibility</h3>
292
+ <div class="flex items-center justify-between p-2 rounded bg-gray-100 dark:bg-gray-700">
293
+ <span>AA Normal Text:</span>
294
+ <span id="aa-normal" class="font-medium"></span>
295
+ </div>
296
+ <div class="flex items-center justify-between p-2 rounded mt-1">
297
+ <span>AA Large Text:</span>
298
+ <span id="aa-large" class="font-medium"></span>
299
+ </div>
300
+ <div class="flex items-center justify-between p-2 rounded bg-gray-100 dark:bg-gray-700 mt-1">
301
+ <span>AAA Normal Text:</span>
302
+ <span id="aaa-normal" class="font-medium"></span>
303
+ </div>
304
+ </div>
305
+ </div>
306
+ </div>
307
+ </div>
308
+ </div>
309
+ </main>
310
+
311
+ <!-- Footer -->
312
+ <footer class="bg-gray-200 dark:bg-gray-800 py-4">
313
+ <div class="container mx-auto px-4 text-center text-sm text-gray-600 dark:text-gray-400">
314
+ <p>ChromaGen &copy; 2023 | Advanced Color Palette Generator</p>
315
+ </div>
316
+ </footer>
317
+ </div>
318
+
319
+ <!-- Info Modal -->
320
+ <div id="info-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
321
+ <div class="bg-white dark:bg-gray-800 rounded-xl shadow-xl p-6 max-w-lg w-full mx-4 max-h-[90vh] overflow-y-auto">
322
+ <div class="flex justify-between items-center mb-4">
323
+ <h3 class="text-xl font-semibold">About ChromaGen</h3>
324
+ <button id="close-modal" class="p-2 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700 transition">
325
+ <i class="fas fa-times"></i>
326
+ </button>
327
+ </div>
328
+ <div class="space-y-4">
329
+ <p>ChromaGen is an advanced color palette generator that helps designers and developers create beautiful color schemes.</p>
330
+ <h4 class="font-medium">Features:</h4>
331
+ <ul class="list-disc pl-5 space-y-1">
332
+ <li>Generate random color palettes based on different categories</li>
333
+ <li>Extract color palettes from images (URL or file upload)</li>
334
+ <li>View detailed color information including RGB, HSL, HSV, CMYK</li>
335
+ <li>See color variations (lighten/darken)</li>
336
+ <li>Check color accessibility ratings</li>
337
+ <li>Copy colors or export palettes</li>
338
+ <li>Dark/light mode toggle</li>
339
+ </ul>
340
+ <h4 class="font-medium">How to use:</h4>
341
+ <ol class="list-decimal pl-5 space-y-1">
342
+ <li>Select a color category or use "Any Color"</li>
343
+ <li>Choose how many colors you want in your palette</li>
344
+ <li>Click "Generate Colors" or upload an image to extract colors</li>
345
+ <li>Click on any color to see detailed information</li>
346
+ <li>Use the copy buttons to save colors to your clipboard</li>
347
+ </ol>
348
+ </div>
349
+ </div>
350
+ </div>
351
+
352
+ <!-- Toast Notification -->
353
+ <div id="toast" class="fixed bottom-4 right-4 bg-green-500 text-white px-4 py-2 rounded-lg shadow-lg flex items-center transform translate-y-10 opacity-0 transition-all duration-300 z-50">
354
+ <i class="fas fa-check-circle mr-2"></i>
355
+ <span id="toast-message">Copied to clipboard!</span>
356
+ </div>
357
+
358
+ <script>
359
+ // DOM Elements
360
+ const toggle = document.getElementById('toggle');
361
+ const generateBtn = document.getElementById('generate-btn');
362
+ const colorResults = document.getElementById('color-results');
363
+ const colorCategory = document.getElementById('color-category');
364
+ const colorCount = document.getElementById('color-count');
365
+ const countDisplay = document.getElementById('count-display');
366
+ const fileUpload = document.getElementById('file-upload');
367
+ const imageUrl = document.getElementById('image-url');
368
+ const loadUrlBtn = document.getElementById('load-url-btn');
369
+ const previewImage = document.getElementById('preview-image');
370
+ const imagePreviewContainer = document.getElementById('image-preview-container');
371
+ const clearImage = document.getElementById('clear-image');
372
+ const extractColorsBtn = document.getElementById('extract-colors-btn');
373
+ const extractStatus = document.getElementById('extract-status');
374
+ const colorDetails = document.getElementById('color-details');
375
+ const copyAllBtn = document.getElementById('copy-all-btn');
376
+ const savePaletteBtn = document.getElementById('save-palette-btn');
377
+ const exportSvgBtn = document.getElementById('export-svg-btn');
378
+ const infoBtn = document.getElementById('info-btn');
379
+ const infoModal = document.getElementById('info-modal');
380
+ const closeModal = document.getElementById('close-modal');
381
+ const toast = document.getElementById('toast');
382
+ const toastMessage = document.getElementById('toast-message');
383
+
384
+ // Color Thief instance
385
+ const colorThief = new ColorThief();
386
+
387
+ // Initialize
388
+ document.addEventListener('DOMContentLoaded', () => {
389
+ // Set initial color count display
390
+ countDisplay.textContent = colorCount.value;
391
+
392
+ // Generate initial colors
393
+ generateColors();
394
+
395
+ // Check for saved dark mode preference
396
+ const darkMode = localStorage.getItem('darkMode') === 'true';
397
+ toggle.checked = darkMode;
398
+ if (darkMode) {
399
+ document.documentElement.classList.add('dark');
400
+ } else {
401
+ document.documentElement.classList.remove('dark');
402
+ }
403
+ });
404
+
405
+ // Event Listeners
406
+ toggle.addEventListener('change', toggleDarkMode);
407
+ colorCount.addEventListener('input', updateCountDisplay);
408
+ generateBtn.addEventListener('click', generateColors);
409
+ fileUpload.addEventListener('change', handleFileUpload);
410
+ loadUrlBtn.addEventListener('click', loadImageFromUrl);
411
+ clearImage.addEventListener('click', clearImagePreview);
412
+ extractColorsBtn.addEventListener('click', extractColorsFromImage);
413
+ copyAllBtn.addEventListener('click', copyAllColors);
414
+ savePaletteBtn.addEventListener('click', savePalette);
415
+ exportSvgBtn.addEventListener('click', exportAsSvg);
416
+ infoBtn.addEventListener('click', () => infoModal.classList.remove('hidden'));
417
+ closeModal.addEventListener('click', () => infoModal.classList.add('hidden'));
418
+
419
+ // Close modal when clicking outside
420
+ infoModal.addEventListener('click', (e) => {
421
+ if (e.target === infoModal) {
422
+ infoModal.classList.add('hidden');
423
+ }
424
+ });
425
+
426
+ // Functions
427
+ function toggleDarkMode() {
428
+ const isDarkMode = toggle.checked;
429
+ if (isDarkMode) {
430
+ document.documentElement.classList.add('dark');
431
+ localStorage.setItem('darkMode', 'true');
432
+ } else {
433
+ document.documentElement.classList.remove('dark');
434
+ localStorage.setItem('darkMode', 'false');
435
+ }
436
+ }
437
+
438
+ function updateCountDisplay() {
439
+ countDisplay.textContent = colorCount.value;
440
+ }
441
+
442
+ function generateColors() {
443
+ const count = parseInt(colorCount.value);
444
+ const category = colorCategory.value;
445
+
446
+ // Clear previous results
447
+ colorResults.innerHTML = '';
448
+ colorDetails.classList.add('hidden');
449
+
450
+ // Generate new colors based on category
451
+ let colors = [];
452
+ for (let i = 0; i < count; i++) {
453
+ colors.push(generateColorByCategory(category));
454
+ }
455
+
456
+ // Display colors
457
+ displayColors(colors);
458
+ }
459
+
460
+ function generateColorByCategory(category) {
461
+ switch(category) {
462
+ case 'warm':
463
+ return generateWarmColor();
464
+ case 'cool':
465
+ return generateCoolColor();
466
+ case 'pastel':
467
+ return generatePastelColor();
468
+ case 'vibrant':
469
+ return generateVibrantColor();
470
+ case 'monochrome':
471
+ return generateMonochromeColor();
472
+ case 'analogous':
473
+ return generateAnalogousColor();
474
+ case 'complementary':
475
+ return generateComplementaryColor();
476
+ case 'triadic':
477
+ return generateTriadicColor();
478
+ default:
479
+ return generateRandomColor();
480
+ }
481
+ }
482
+
483
+ function generateRandomColor() {
484
+ return {
485
+ r: Math.floor(Math.random() * 256),
486
+ g: Math.floor(Math.random() * 256),
487
+ b: Math.floor(Math.random() * 256)
488
+ };
489
+ }
490
+
491
+ function generateWarmColor() {
492
+ return {
493
+ r: Math.floor(Math.random() * 156) + 100, // 100-255
494
+ g: Math.floor(Math.random() * 156), // 0-155
495
+ b: Math.floor(Math.random() * 106) // 0-105
496
+ };
497
+ }
498
+
499
+ function generateCoolColor() {
500
+ return {
501
+ r: Math.floor(Math.random() * 106), // 0-105
502
+ g: Math.floor(Math.random() * 156) + 100, // 100-255
503
+ b: Math.floor(Math.random() * 156) + 100 // 100-255
504
+ };
505
+ }
506
+
507
+ function generatePastelColor() {
508
+ return {
509
+ r: Math.floor(Math.random() * 106) + 150, // 150-255
510
+ g: Math.floor(Math.random() * 106) + 150, // 150-255
511
+ b: Math.floor(Math.random() * 106) + 150 // 150-255
512
+ };
513
+ }
514
+
515
+ function generateVibrantColor() {
516
+ // At least two channels at 200+ and one channel at <50
517
+ const channels = ['r', 'g', 'b'];
518
+ const highChannel1 = channels.splice(Math.floor(Math.random() * channels.length), 1)[0];
519
+ const highChannel2 = channels.splice(Math.floor(Math.random() * channels.length), 1)[0];
520
+ const lowChannel = channels[0];
521
+
522
+ const color = { r: 0, g: 0, b: 0 };
523
+ color[highChannel1] = Math.floor(Math.random() * 56) + 200; // 200-255
524
+ color[highChannel2] = Math.floor(Math.random() * 56) + 200; // 200-255
525
+ color[lowChannel] = Math.floor(Math.random() * 50); // 0-49
526
+
527
+ return color;
528
+ }
529
+
530
+ function generateMonochromeColor() {
531
+ const base = Math.floor(Math.random() * 256);
532
+ const variation = Math.floor(Math.random() * 50) - 25; // -25 to +25
533
+ return {
534
+ r: Math.min(255, Math.max(0, base + variation)),
535
+ g: Math.min(255, Math.max(0, base + variation)),
536
+ b: Math.min(255, Math.max(0, base + variation))
537
+ };
538
+ }
539
+
540
+ function generateAnalogousColor() {
541
+ const baseHue = Math.floor(Math.random() * 360);
542
+ const hueVariation = Math.floor(Math.random() * 30) - 15; // -15 to +15
543
+ const hue = (baseHue + hueVariation + 360) % 360;
544
+ return hslToRgb(hue / 360, 0.7, 0.6);
545
+ }
546
+
547
+ function generateComplementaryColor() {
548
+ const baseHue = Math.floor(Math.random() * 360);
549
+ const hue = (baseHue + 180) % 360;
550
+ return hslToRgb(hue / 360, 0.7, 0.6);
551
+ }
552
+
553
+ function generateTriadicColor() {
554
+ const baseHue = Math.floor(Math.random() * 360);
555
+ const hue = (baseHue + 120 * (Math.floor(Math.random() * 3))) % 360;
556
+ return hslToRgb(hue / 360, 0.7, 0.6);
557
+ }
558
+
559
+ function hslToRgb(h, s, l) {
560
+ let r, g, b;
561
+
562
+ if (s === 0) {
563
+ r = g = b = l; // achromatic
564
+ } else {
565
+ const hue2rgb = (p, q, t) => {
566
+ if (t < 0) t += 1;
567
+ if (t > 1) t -= 1;
568
+ if (t < 1/6) return p + (q - p) * 6 * t;
569
+ if (t < 1/2) return q;
570
+ if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
571
+ return p;
572
+ };
573
+
574
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
575
+ const p = 2 * l - q;
576
+
577
+ r = hue2rgb(p, q, h + 1/3);
578
+ g = hue2rgb(p, q, h);
579
+ b = hue2rgb(p, q, h - 1/3);
580
+ }
581
+
582
+ return {
583
+ r: Math.round(r * 255),
584
+ g: Math.round(g * 255),
585
+ b: Math.round(b * 255)
586
+ };
587
+ }
588
+
589
+ function displayColors(colors) {
590
+ colorResults.innerHTML = '';
591
+
592
+ colors.forEach((color, index) => {
593
+ const hex = rgbToHex(color.r, color.g, color.b);
594
+ const rgbText = `RGB(${color.r}, ${color.g}, ${color.b})`;
595
+
596
+ const colorCard = document.createElement('div');
597
+ colorCard.className = 'color-card cursor-pointer';
598
+ colorCard.innerHTML = `
599
+ <div class="color-swatch h-24 rounded-lg shadow-md mb-2" style="background-color: ${hex};"></div>
600
+ <div class="text-center">
601
+ <div class="font-mono text-sm">${hex}</div>
602
+ <div class="text-xs text-gray-500 dark:text-gray-400">${rgbText}</div>
603
+ </div>
604
+ `;
605
+
606
+ // Add click event to show color details
607
+ colorCard.addEventListener('click', () => showColorDetails(color));
608
+
609
+ colorResults.appendChild(colorCard);
610
+ });
611
+ }
612
+
613
+ function showColorDetails(color) {
614
+ const hex = rgbToHex(color.r, color.g, color.b);
615
+ const rgbText = `RGB(${color.r}, ${color.g}, ${color.b})`;
616
+
617
+ // Convert to HSL, HSV, CMYK
618
+ const hsl = rgbToHsl(color.r, color.g, color.b);
619
+ const hsv = rgbToHsv(color.r, color.g, color.b);
620
+ const cmyk = rgbToCmyk(color.r, color.g, color.b);
621
+
622
+ // Update details
623
+ document.getElementById('detail-swatch').style.backgroundColor = hex;
624
+ document.getElementById('detail-hex').textContent = hex;
625
+ document.getElementById('detail-rgb').textContent = rgbText;
626
+ document.getElementById('detail-hsl').textContent = `HSL(${Math.round(hsl.h)}, ${Math.round(hsl.s * 100)}%, ${Math.round(hsl.l * 100)}%)`;
627
+ document.getElementById('detail-hsv').textContent = `HSV(${Math.round(hsv.h)}, ${Math.round(hsv.s * 100)}%, ${Math.round(hsv.v * 100)}%)`;
628
+ document.getElementById('detail-cmyk').textContent = `CMYK(${Math.round(cmyk.c * 100)}%, ${Math.round(cmyk.m * 100)}%, ${Math.round(cmyk.y * 100)}%, ${Math.round(cmyk.k * 100)}%)`;
629
+
630
+ // Update variations
631
+ document.getElementById('base-color').style.backgroundColor = hex;
632
+ document.getElementById('lighten-10').style.backgroundColor = lightenColor(hex, 10);
633
+ document.getElementById('lighten-20').style.backgroundColor = lightenColor(hex, 20);
634
+ document.getElementById('darken-10').style.backgroundColor = darkenColor(hex, 10);
635
+ document.getElementById('darken-20').style.backgroundColor = darkenColor(hex, 20);
636
+
637
+ // Check accessibility
638
+ checkAccessibility(color);
639
+
640
+ // Show details panel
641
+ colorDetails.classList.remove('hidden');
642
+ }
643
+
644
+ function rgbToHex(r, g, b) {
645
+ return '#' + [r, g, b].map(x => {
646
+ const hex = x.toString(16);
647
+ return hex.length === 1 ? '0' + hex : hex;
648
+ }).join('');
649
+ }
650
+
651
+ function rgbToHsl(r, g, b) {
652
+ r /= 255, g /= 255, b /= 255;
653
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
654
+ let h, s, l = (max + min) / 2;
655
+
656
+ if (max === min) {
657
+ h = s = 0; // achromatic
658
+ } else {
659
+ const d = max - min;
660
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
661
+ switch(max) {
662
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
663
+ case g: h = (b - r) / d + 2; break;
664
+ case b: h = (r - g) / d + 4; break;
665
+ }
666
+ h /= 6;
667
+ }
668
+
669
+ return { h: h * 360, s, l };
670
+ }
671
+
672
+ function rgbToHsv(r, g, b) {
673
+ r /= 255, g /= 255, b /= 255;
674
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
675
+ let h, s, v = max;
676
+
677
+ const d = max - min;
678
+ s = max === 0 ? 0 : d / max;
679
+
680
+ if (max === min) {
681
+ h = 0; // achromatic
682
+ } else {
683
+ switch(max) {
684
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
685
+ case g: h = (b - r) / d + 2; break;
686
+ case b: h = (r - g) / d + 4; break;
687
+ }
688
+ h /= 6;
689
+ }
690
+
691
+ return { h: h * 360, s, v };
692
+ }
693
+
694
+ function rgbToCmyk(r, g, b) {
695
+ // Convert RGB to CMY
696
+ let c = 1 - (r / 255);
697
+ let m = 1 - (g / 255);
698
+ let y = 1 - (b / 255);
699
+
700
+ // Find the minimum of CMY
701
+ const minCMY = Math.min(c, m, y);
702
+
703
+ // Convert CMY to CMYK
704
+ c = (c - minCMY) / (1 - minCMY);
705
+ m = (m - minCMY) / (1 - minCMY);
706
+ y = (y - minCMY) / (1 - minCMY);
707
+ const k = minCMY;
708
+
709
+ // Handle the case when all components are 0
710
+ if (isNaN(c)) c = 0;
711
+ if (isNaN(m)) m = 0;
712
+ if (isNaN(y)) y = 0;
713
+
714
+ return { c, m, y, k };
715
+ }
716
+
717
+ function lightenColor(hex, percent) {
718
+ // Convert hex to RGB
719
+ let r = parseInt(hex.substring(1, 3), 16);
720
+ let g = parseInt(hex.substring(3, 5), 16);
721
+ let b = parseInt(hex.substring(5, 7), 16);
722
+
723
+ // Lighten each component
724
+ r = Math.min(255, r + Math.round(2.55 * percent));
725
+ g = Math.min(255, g + Math.round(2.55 * percent));
726
+ b = Math.min(255, b + Math.round(2.55 * percent));
727
+
728
+ // Convert back to hex
729
+ return rgbToHex(r, g, b);
730
+ }
731
+
732
+ function darkenColor(hex, percent) {
733
+ // Convert hex to RGB
734
+ let r = parseInt(hex.substring(1, 3), 16);
735
+ let g = parseInt(hex.substring(3, 5), 16);
736
+ let b = parseInt(hex.substring(5, 7), 16);
737
+
738
+ // Darken each component
739
+ r = Math.max(0, r - Math.round(2.55 * percent));
740
+ g = Math.max(0, g - Math.round(2.55 * percent));
741
+ b = Math.max(0, b - Math.round(2.55 * percent));
742
+
743
+ // Convert back to hex
744
+ return rgbToHex(r, g, b);
745
+ }
746
+
747
+ function checkAccessibility(color) {
748
+ // Calculate relative luminance (WCAG formula)
749
+ const r = color.r / 255;
750
+ const g = color.g / 255;
751
+ const b = color.b / 255;
752
+
753
+ const rSRGB = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
754
+ const gSRGB = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
755
+ const bSRGB = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);
756
+
757
+ const luminance = 0.2126 * rSRGB + 0.7152 * gSRGB + 0.0722 * bSRGB;
758
+
759
+ // Check contrast against white (1.0 luminance)
760
+ const contrastWhite = (1.0 + 0.05) / (luminance + 0.05);
761
+
762
+ // Check contrast against black (0.0 luminance)
763
+ const contrastBlack = (luminance + 0.05) / (0.0 + 0.05);
764
+
765
+ // Determine which has better contrast
766
+ const betterContrast = contrastWhite > contrastBlack ? 'white' : 'black';
767
+ const maxContrast = Math.max(contrastWhite, contrastBlack);
768
+
769
+ // Set accessibility ratings
770
+ document.getElementById('aa-normal').textContent = maxContrast >= 4.5 ? 'βœ” Pass' : 'βœ– Fail';
771
+ document.getElementById('aa-normal').style.color = maxContrast >= 4.5 ? '#10B981' : '#EF4444';
772
+
773
+ document.getElementById('aa-large').textContent = maxContrast >= 3 ? 'βœ” Pass' : 'βœ– Fail';
774
+ document.getElementById('aa-large').style.color = maxContrast >= 3 ? '#10B981' : '#EF4444';
775
+
776
+ document.getElementById('aaa-normal').textContent = maxContrast >= 7 ? 'βœ” Pass' : 'βœ– Fail';
777
+ document.getElementById('aaa-normal').style.color = maxContrast >= 7 ? '#10B981' : '#EF4444';
778
+ }
779
+
780
+ function handleFileUpload(e) {
781
+ const file = e.target.files[0];
782
+ if (!file) return;
783
+
784
+ const reader = new FileReader();
785
+ reader.onload = function(event) {
786
+ previewImage.src = event.target.result;
787
+ imagePreviewContainer.classList.remove('hidden');
788
+ extractStatus.textContent = 'Ready to extract colors';
789
+ };
790
+ reader.readAsDataURL(file);
791
+ }
792
+
793
+ function loadImageFromUrl() {
794
+ const url = imageUrl.value.trim();
795
+ if (!url) return;
796
+
797
+ extractStatus.textContent = 'Loading image...';
798
+ imagePreviewContainer.classList.remove('hidden');
799
+
800
+ // Create a new image to check if the URL is valid
801
+ const img = new Image();
802
+ img.crossOrigin = 'Anonymous';
803
+ img.onload = function() {
804
+ previewImage.src = url;
805
+ extractStatus.textContent = 'Ready to extract colors';
806
+ };
807
+ img.onerror = function() {
808
+ extractStatus.textContent = 'Error loading image. Please check the URL.';
809
+ showToast('Error loading image', 'error');
810
+ };
811
+ img.src = url;
812
+ }
813
+
814
+ function clearImagePreview() {
815
+ previewImage.src = '';
816
+ imagePreviewContainer.classList.add('hidden');
817
+ imageUrl.value = '';
818
+ fileUpload.value = '';
819
+ }
820
+
821
+ function extractColorsFromImage() {
822
+ if (!previewImage.src || previewImage.src.startsWith('data:')) {
823
+ // Local image
824
+ extractStatus.textContent = 'Extracting colors...';
825
+
826
+ try {
827
+ const palette = colorThief.getPalette(previewImage, parseInt(colorCount.value) || 5);
828
+ const colors = palette.map(color => ({ r: color[0], g: color[1], b: color[2] }));
829
+ displayColors(colors);
830
+ extractStatus.textContent = `Extracted ${colors.length} colors`;
831
+ showToast('Colors extracted successfully!');
832
+ } catch (e) {
833
+ extractStatus.textContent = 'Error extracting colors. Try another image.';
834
+ showToast('Error extracting colors', 'error');
835
+ console.error(e);
836
+ }
837
+ } else {
838
+ // Remote image - need to handle CORS
839
+ extractStatus.textContent = 'Extracting colors (may take a moment)...';
840
+
841
+ const img = new Image();
842
+ img.crossOrigin = 'Anonymous';
843
+ img.onload = function() {
844
+ try {
845
+ const palette = colorThief.getPalette(img, parseInt(colorCount.value) || 5);
846
+ const colors = palette.map(color => ({ r: color[0], g: color[1], b: color[2] }));
847
+ displayColors(colors);
848
+ extractStatus.textContent = `Extracted ${colors.length} colors`;
849
+ showToast('Colors extracted successfully!');
850
+ } catch (e) {
851
+ extractStatus.textContent = 'Error extracting colors. Try another image.';
852
+ showToast('Error extracting colors', 'error');
853
+ console.error(e);
854
+ }
855
+ };
856
+ img.onerror = function() {
857
+ extractStatus.textContent = 'Error loading image for extraction.';
858
+ showToast('Error loading image', 'error');
859
+ };
860
+ img.src = previewImage.src;
861
+ }
862
+ }
863
+
864
+ function copyAllColors() {
865
+ const colorCards = document.querySelectorAll('.color-card');
866
+ let colorsText = '';
867
+
868
+ colorCards.forEach(card => {
869
+ const hex = card.querySelector('.font-mono').textContent;
870
+ const rgb = card.querySelector('.text-xs').textContent;
871
+ colorsText += `${hex} ${rgb}\n`;
872
+ });
873
+
874
+ navigator.clipboard.writeText(colorsText.trim())
875
+ .then(() => showToast('All colors copied to clipboard!'))
876
+ .catch(err => showToast('Failed to copy colors', 'error'));
877
+ }
878
+
879
+ function savePalette() {
880
+ const colorCards = document.querySelectorAll('.color-card');
881
+ const paletteName = prompt('Enter a name for your palette:', 'My Color Palette');
882
+
883
+ if (paletteName) {
884
+ const palette = {
885
+ name: paletteName,
886
+ colors: [],
887
+ date: new Date().toISOString()
888
+ };
889
+
890
+ colorCards.forEach(card => {
891
+ const hex = card.querySelector('.font-mono').textContent;
892
+ palette.colors.push(hex);
893
+ });
894
+
895
+ // In a real app, you would save to localStorage or a database
896
+ showToast(`Palette "${paletteName}" saved! (Demo)`);
897
+ }
898
+ }
899
+
900
+ function exportAsSvg() {
901
+ const colorCards = document.querySelectorAll('.color-card');
902
+ const width = 400;
903
+ const height = 200;
904
+ const colorWidth = width / colorCards.length;
905
+
906
+ let svg = `<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">\n`;
907
+
908
+ colorCards.forEach((card, index) => {
909
+ const hex = card.querySelector('.font-mono').textContent;
910
+ svg += ` <rect x="${index * colorWidth}" y="0" width="${colorWidth}" height="${height}" fill="${hex}" />\n`;
911
+ });
912
+
913
+ svg += ` <text x="10" y="30" font-family="Arial" font-size="20" fill="white" stroke="black" stroke-width="0.5">Color Palette</text>\n`;
914
+ svg += '</svg>';
915
+
916
+ // Create download link
917
+ const blob = new Blob([svg], { type: 'image/svg+xml' });
918
+ const url = URL.createObjectURL(blob);
919
+ const a = document.createElement('a');
920
+ a.href = url;
921
+ a.download = 'color-palette.svg';
922
+ document.body.appendChild(a);
923
+ a.click();
924
+ document.body.removeChild(a);
925
+ URL.revokeObjectURL(url);
926
+
927
+ showToast('SVG exported successfully!');
928
+ }
929
+
930
+ function showToast(message, type = 'success') {
931
+ toastMessage.textContent = message;
932
+ toast.className = `fixed bottom-4 right-4 px-4 py-2 rounded-lg shadow-lg flex items-center transform translate-y-10 opacity-0 transition-all duration-300 z-50 ${type === 'success' ? 'bg-green-500' : 'bg-red-500'} text-white`;
933
+
934
+ setTimeout(() => {
935
+ toast.classList.remove('translate-y-10', 'opacity-0');
936
+ toast.classList.add('translate-y-0', 'opacity-100');
937
+ }, 10);
938
+
939
+ setTimeout(() => {
940
+ toast.classList.remove('translate-y-0', 'opacity-100');
941
+ toast.classList.add('translate-y-10', 'opacity-0');
942
+ }, 3000);
943
+ }
944
+ </script>
945
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=DotSlashGabut/chromagen-color-palette" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
946
+ </html>