linoyts HF Staff commited on
Commit
cf9dbe6
·
verified ·
1 Parent(s): 15f2208

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +573 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Meme Generator
3
- emoji: 💻
4
- colorFrom: purple
5
- colorTo: yellow
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: meme-generator
3
+ emoji: 🐳
4
+ colorFrom: green
5
+ colorTo: green
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,573 @@
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>Meme Generator Pro</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ .dropzone {
11
+ border: 2px dashed #ccc;
12
+ transition: all 0.3s ease;
13
+ }
14
+ .dropzone.active {
15
+ border-color: #4f46e5;
16
+ background-color: rgba(79, 70, 229, 0.05);
17
+ }
18
+ .text-input {
19
+ -webkit-text-stroke: 1px black;
20
+ text-shadow: 2px 2px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000;
21
+ }
22
+ .meme-container {
23
+ position: relative;
24
+ max-width: 100%;
25
+ }
26
+ .meme-text {
27
+ position: absolute;
28
+ width: 100%;
29
+ text-align: center;
30
+ color: white;
31
+ font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
32
+ font-size: 2.5rem;
33
+ word-wrap: break-word;
34
+ cursor: move;
35
+ user-select: none;
36
+ }
37
+ .color-option {
38
+ width: 30px;
39
+ height: 30px;
40
+ border-radius: 50%;
41
+ cursor: pointer;
42
+ transition: transform 0.2s;
43
+ }
44
+ .color-option:hover {
45
+ transform: scale(1.1);
46
+ }
47
+ .font-option {
48
+ padding: 5px 10px;
49
+ border-radius: 5px;
50
+ cursor: pointer;
51
+ transition: all 0.2s;
52
+ }
53
+ .font-option:hover {
54
+ background-color: #e5e7eb;
55
+ }
56
+ .font-option.selected {
57
+ background-color: #4f46e5;
58
+ color: white;
59
+ }
60
+ </style>
61
+ </head>
62
+ <body class="bg-gray-100 min-h-screen">
63
+ <div class="container mx-auto px-4 py-8">
64
+ <header class="text-center mb-8">
65
+ <h1 class="text-4xl font-bold text-indigo-600 mb-2">Meme Generator Pro</h1>
66
+ <p class="text-gray-600">Create hilarious memes in seconds!</p>
67
+ </header>
68
+
69
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
70
+ <!-- Left Panel - Controls -->
71
+ <div class="bg-white rounded-xl shadow-md p-6">
72
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">Meme Controls</h2>
73
+
74
+ <!-- Template Selection -->
75
+ <div class="mb-6">
76
+ <h3 class="text-lg font-medium mb-2 text-gray-700">Choose Template</h3>
77
+ <div class="grid grid-cols-3 gap-2">
78
+ <div class="template-option cursor-pointer" data-template="https://i.imgflip.com/1bij.jpg">
79
+ <img src="https://i.imgflip.com/1bij.jpg" alt="One Does Not Simply" class="rounded-md hover:opacity-80">
80
+ </div>
81
+ <div class="template-option cursor-pointer" data-template="https://i.imgflip.com/1g8my.jpg">
82
+ <img src="https://i.imgflip.com/1g8my.jpg" alt="Distracted Boyfriend" class="rounded-md hover:opacity-80">
83
+ </div>
84
+ <div class="template-option cursor-pointer" data-template="https://i.imgflip.com/9vct.jpg">
85
+ <img src="https://i.imgflip.com/9vct.jpg" alt="Waiting Skeleton" class="rounded-md hover:opacity-80">
86
+ </div>
87
+ <div class="template-option cursor-pointer" data-template="https://i.imgflip.com/1h7in3.jpg">
88
+ <img src="https://i.imgflip.com/1h7in3.jpg" alt="Drake Hotline Bling" class="rounded-md hover:opacity-80">
89
+ </div>
90
+ <div class="template-option cursor-pointer" data-template="https://i.imgflip.com/1ihzfe.jpg">
91
+ <img src="https://i.imgflip.com/1ihzfe.jpg" alt="Batman Slapping Robin" class="rounded-md hover:opacity-80">
92
+ </div>
93
+ <div class="template-option cursor-pointer" data-template="https://i.imgflip.com/30b1gx.jpg">
94
+ <img src="https://i.imgflip.com/30b1gx.jpg" alt="Change My Mind" class="rounded-md hover:opacity-80">
95
+ </div>
96
+ </div>
97
+ </div>
98
+
99
+ <!-- Upload Image -->
100
+ <div class="mb-6">
101
+ <h3 class="text-lg font-medium mb-2 text-gray-700">Or Upload Your Own</h3>
102
+ <div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer">
103
+ <i class="fas fa-cloud-upload-alt text-4xl text-indigo-500 mb-2"></i>
104
+ <p class="text-gray-600">Drag & drop an image here</p>
105
+ <p class="text-sm text-gray-500 mt-1">or click to browse</p>
106
+ <input type="file" id="fileInput" class="hidden" accept="image/*">
107
+ </div>
108
+ </div>
109
+
110
+ <!-- Text Controls -->
111
+ <div class="mb-6">
112
+ <h3 class="text-lg font-medium mb-2 text-gray-700">Add Text</h3>
113
+ <div class="flex mb-4">
114
+ <input type="text" id="topTextInput" placeholder="Top text" class="flex-1 px-3 py-2 border rounded-l-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
115
+ <button id="addTopText" class="bg-indigo-600 text-white px-4 py-2 rounded-r-md hover:bg-indigo-700 transition">Add</button>
116
+ </div>
117
+ <div class="flex">
118
+ <input type="text" id="bottomTextInput" placeholder="Bottom text" class="flex-1 px-3 py-2 border rounded-l-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
119
+ <button id="addBottomText" class="bg-indigo-600 text-white px-4 py-2 rounded-r-md hover:bg-indigo-700 transition">Add</button>
120
+ </div>
121
+ </div>
122
+
123
+ <!-- Text Customization -->
124
+ <div class="mb-6">
125
+ <h3 class="text-lg font-medium mb-2 text-gray-700">Customize Text</h3>
126
+
127
+ <!-- Color Picker -->
128
+ <div class="mb-4">
129
+ <label class="block text-sm font-medium text-gray-700 mb-1">Text Color</label>
130
+ <div class="flex space-x-2">
131
+ <div class="color-option bg-white border border-gray-300" data-color="white"></div>
132
+ <div class="color-option bg-yellow-300" data-color="#fde047"></div>
133
+ <div class="color-option bg-red-500" data-color="#ef4444"></div>
134
+ <div class="color-option bg-green-500" data-color="#22c55e"></div>
135
+ <div class="color-option bg-blue-500" data-color="#3b82f6"></div>
136
+ <div class="color-option bg-black" data-color="black"></div>
137
+ </div>
138
+ </div>
139
+
140
+ <!-- Font Selection -->
141
+ <div class="mb-4">
142
+ <label class="block text-sm font-medium text-gray-700 mb-1">Font</label>
143
+ <div class="flex flex-wrap gap-2">
144
+ <div class="font-option selected" data-font="Impact">Impact</div>
145
+ <div class="font-option" data-font="Arial">Arial</div>
146
+ <div class="font-option" data-font="Comic Sans MS">Comic Sans</div>
147
+ <div class="font-option" data-font="Times New Roman">Times</div>
148
+ <div class="font-option" data-font="Courier New">Courier</div>
149
+ </div>
150
+ </div>
151
+
152
+ <!-- Size Slider -->
153
+ <div>
154
+ <label for="textSize" class="block text-sm font-medium text-gray-700 mb-1">Text Size</label>
155
+ <input type="range" id="textSize" min="20" max="80" value="40" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
156
+ <div class="flex justify-between text-xs text-gray-500 mt-1">
157
+ <span>Small</span>
158
+ <span>Medium</span>
159
+ <span>Large</span>
160
+ </div>
161
+ </div>
162
+ </div>
163
+
164
+ <!-- Download Button -->
165
+ <button id="downloadBtn" class="w-full bg-green-600 text-white py-3 rounded-lg font-semibold hover:bg-green-700 transition flex items-center justify-center">
166
+ <i class="fas fa-download mr-2"></i> Download Meme
167
+ </button>
168
+ </div>
169
+
170
+ <!-- Middle Panel - Preview -->
171
+ <div class="bg-white rounded-xl shadow-md p-6 flex flex-col">
172
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">Meme Preview</h2>
173
+ <div class="flex-1 flex items-center justify-center">
174
+ <div id="memePreview" class="meme-container w-full max-w-md">
175
+ <img id="memeImage" src="https://i.imgflip.com/1bij.jpg" alt="Meme template" class="w-full rounded-lg">
176
+ <!-- Text elements will be added here dynamically -->
177
+ </div>
178
+ </div>
179
+ <div class="mt-4 text-center text-sm text-gray-500">
180
+ <p>Drag text to reposition, click to select for editing</p>
181
+ </div>
182
+ </div>
183
+
184
+ <!-- Right Panel - Recent Memes -->
185
+ <div class="bg-white rounded-xl shadow-md p-6">
186
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">Your Recent Memes</h2>
187
+ <div id="recentMemes" class="grid grid-cols-2 gap-2">
188
+ <!-- Recent memes will appear here -->
189
+ <div class="text-center p-4 bg-gray-100 rounded-lg">
190
+ <i class="fas fa-image text-3xl text-gray-400 mb-2"></i>
191
+ <p class="text-sm text-gray-600">No memes yet</p>
192
+ </div>
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </div>
197
+
198
+ <script>
199
+ document.addEventListener('DOMContentLoaded', function() {
200
+ // DOM Elements
201
+ const dropzone = document.getElementById('dropzone');
202
+ const fileInput = document.getElementById('fileInput');
203
+ const memeImage = document.getElementById('memeImage');
204
+ const memePreview = document.getElementById('memePreview');
205
+ const topTextInput = document.getElementById('topTextInput');
206
+ const bottomTextInput = document.getElementById('bottomTextInput');
207
+ const addTopTextBtn = document.getElementById('addTopText');
208
+ const addBottomTextBtn = document.getElementById('addBottomText');
209
+ const downloadBtn = document.getElementById('downloadBtn');
210
+ const colorOptions = document.querySelectorAll('.color-option');
211
+ const fontOptions = document.querySelectorAll('.font-option');
212
+ const textSizeSlider = document.getElementById('textSize');
213
+ const templateOptions = document.querySelectorAll('.template-option');
214
+ const recentMemesContainer = document.getElementById('recentMemes');
215
+
216
+ // State variables
217
+ let selectedTextElement = null;
218
+ let currentColor = 'white';
219
+ let currentFont = 'Impact';
220
+ let currentSize = 40;
221
+ let recentMemes = [];
222
+
223
+ // Initialize with default template
224
+ updateMemeTemplate('https://i.imgflip.com/1bij.jpg');
225
+
226
+ // Event Listeners
227
+
228
+ // Template selection
229
+ templateOptions.forEach(option => {
230
+ option.addEventListener('click', function() {
231
+ const templateUrl = this.getAttribute('data-template');
232
+ updateMemeTemplate(templateUrl);
233
+ });
234
+ });
235
+
236
+ // Drag and drop functionality
237
+ dropzone.addEventListener('click', () => fileInput.click());
238
+
239
+ fileInput.addEventListener('change', function(e) {
240
+ if (e.target.files.length) {
241
+ const file = e.target.files[0];
242
+ if (file.type.match('image.*')) {
243
+ const reader = new FileReader();
244
+ reader.onload = function(event) {
245
+ updateMemeTemplate(event.target.result);
246
+ };
247
+ reader.readAsDataURL(file);
248
+ }
249
+ }
250
+ });
251
+
252
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
253
+ dropzone.addEventListener(eventName, preventDefaults, false);
254
+ });
255
+
256
+ function preventDefaults(e) {
257
+ e.preventDefault();
258
+ e.stopPropagation();
259
+ }
260
+
261
+ ['dragenter', 'dragover'].forEach(eventName => {
262
+ dropzone.addEventListener(eventName, highlight, false);
263
+ });
264
+
265
+ ['dragleave', 'drop'].forEach(eventName => {
266
+ dropzone.addEventListener(eventName, unhighlight, false);
267
+ });
268
+
269
+ function highlight() {
270
+ dropzone.classList.add('active');
271
+ }
272
+
273
+ function unhighlight() {
274
+ dropzone.classList.remove('active');
275
+ }
276
+
277
+ dropzone.addEventListener('drop', function(e) {
278
+ const dt = e.dataTransfer;
279
+ const file = dt.files[0];
280
+ if (file.type.match('image.*')) {
281
+ const reader = new FileReader();
282
+ reader.onload = function(event) {
283
+ updateMemeTemplate(event.target.result);
284
+ };
285
+ reader.readAsDataURL(file);
286
+ }
287
+ });
288
+
289
+ // Add text functionality
290
+ addTopTextBtn.addEventListener('click', function() {
291
+ addText(topTextInput.value, 'top');
292
+ topTextInput.value = '';
293
+ });
294
+
295
+ addBottomTextBtn.addEventListener('click', function() {
296
+ addText(bottomTextInput.value, 'bottom');
297
+ bottomTextInput.value = '';
298
+ });
299
+
300
+ // Text input enter key support
301
+ topTextInput.addEventListener('keypress', function(e) {
302
+ if (e.key === 'Enter') {
303
+ addText(topTextInput.value, 'top');
304
+ topTextInput.value = '';
305
+ }
306
+ });
307
+
308
+ bottomTextInput.addEventListener('keypress', function(e) {
309
+ if (e.key === 'Enter') {
310
+ addText(bottomTextInput.value, 'bottom');
311
+ bottomTextInput.value = '';
312
+ }
313
+ });
314
+
315
+ // Text customization
316
+ colorOptions.forEach(option => {
317
+ option.addEventListener('click', function() {
318
+ currentColor = this.getAttribute('data-color');
319
+ if (selectedTextElement) {
320
+ selectedTextElement.style.color = currentColor;
321
+ }
322
+ });
323
+ });
324
+
325
+ fontOptions.forEach(option => {
326
+ option.addEventListener('click', function() {
327
+ // Remove selected class from all options
328
+ fontOptions.forEach(opt => opt.classList.remove('selected'));
329
+ // Add to clicked option
330
+ this.classList.add('selected');
331
+
332
+ currentFont = this.getAttribute('data-font');
333
+ if (selectedTextElement) {
334
+ selectedTextElement.style.fontFamily = currentFont;
335
+ }
336
+ });
337
+ });
338
+
339
+ textSizeSlider.addEventListener('input', function() {
340
+ currentSize = parseInt(this.value);
341
+ if (selectedTextElement) {
342
+ selectedTextElement.style.fontSize = `${currentSize}px`;
343
+ }
344
+ });
345
+
346
+ // Download functionality
347
+ downloadBtn.addEventListener('click', downloadMeme);
348
+
349
+ // Functions
350
+
351
+ function updateMemeTemplate(src) {
352
+ memeImage.src = src;
353
+ // Clear existing text elements
354
+ document.querySelectorAll('.meme-text').forEach(el => el.remove());
355
+ selectedTextElement = null;
356
+ }
357
+
358
+ function addText(text, position) {
359
+ if (!text.trim()) return;
360
+
361
+ const textElement = document.createElement('div');
362
+ textElement.className = 'meme-text';
363
+ textElement.textContent = text;
364
+ textElement.style.color = currentColor;
365
+ textElement.style.fontFamily = currentFont;
366
+ textElement.style.fontSize = `${currentSize}px`;
367
+
368
+ if (position === 'top') {
369
+ textElement.style.top = '10px';
370
+ } else {
371
+ textElement.style.bottom = '10px';
372
+ }
373
+
374
+ // Make text draggable
375
+ makeDraggable(textElement);
376
+
377
+ // Select on click
378
+ textElement.addEventListener('click', function(e) {
379
+ e.stopPropagation();
380
+ selectTextElement(textElement);
381
+ });
382
+
383
+ memePreview.appendChild(textElement);
384
+ selectTextElement(textElement);
385
+ }
386
+
387
+ function makeDraggable(element) {
388
+ let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
389
+
390
+ element.onmousedown = dragMouseDown;
391
+
392
+ function dragMouseDown(e) {
393
+ e = e || window.event;
394
+ e.preventDefault();
395
+ // Get the mouse cursor position at startup
396
+ pos3 = e.clientX;
397
+ pos4 = e.clientY;
398
+ document.onmouseup = closeDragElement;
399
+ // Call a function whenever the cursor moves
400
+ document.onmousemove = elementDrag;
401
+ }
402
+
403
+ function elementDrag(e) {
404
+ e = e || window.event;
405
+ e.preventDefault();
406
+ // Calculate the new cursor position
407
+ pos1 = pos3 - e.clientX;
408
+ pos2 = pos4 - e.clientY;
409
+ pos3 = e.clientX;
410
+ pos4 = e.clientY;
411
+ // Set the element's new position
412
+ const top = element.offsetTop - pos2;
413
+ const left = element.offsetLeft - pos1;
414
+
415
+ // Constrain to meme container
416
+ const containerRect = memePreview.getBoundingClientRect();
417
+ const elementRect = element.getBoundingClientRect();
418
+
419
+ if (top >= 0 && top <= containerRect.height - elementRect.height) {
420
+ element.style.top = top + 'px';
421
+ element.style.bottom = '';
422
+ }
423
+
424
+ if (left >= 0 && left <= containerRect.width - elementRect.width) {
425
+ element.style.left = left + 'px';
426
+ element.style.right = '';
427
+ }
428
+ }
429
+
430
+ function closeDragElement() {
431
+ // Stop moving when mouse button is released
432
+ document.onmouseup = null;
433
+ document.onmousemove = null;
434
+ }
435
+ }
436
+
437
+ function selectTextElement(element) {
438
+ // Deselect previous
439
+ if (selectedTextElement) {
440
+ selectedTextElement.style.border = '';
441
+ }
442
+
443
+ // Select new
444
+ selectedTextElement = element;
445
+ element.style.border = '2px dashed rgba(79, 70, 229, 0.7)';
446
+
447
+ // Update inputs to match selected text
448
+ if (element.textContent) {
449
+ if (element.style.top) {
450
+ topTextInput.value = element.textContent;
451
+ } else {
452
+ bottomTextInput.value = element.textContent;
453
+ }
454
+ }
455
+
456
+ // Update customization controls
457
+ currentColor = element.style.color || 'white';
458
+ currentFont = element.style.fontFamily || 'Impact';
459
+ currentSize = parseInt(element.style.fontSize) || 40;
460
+
461
+ // Update slider
462
+ textSizeSlider.value = currentSize;
463
+
464
+ // Update color selection
465
+ colorOptions.forEach(opt => {
466
+ if (opt.getAttribute('data-color') === currentColor) {
467
+ opt.style.border = '2px solid #4f46e5';
468
+ } else {
469
+ opt.style.border = opt.classList.contains('bg-white') ? '1px solid #d1d5db' : '';
470
+ }
471
+ });
472
+
473
+ // Update font selection
474
+ fontOptions.forEach(opt => {
475
+ if (opt.getAttribute('data-font') === currentFont) {
476
+ opt.classList.add('selected');
477
+ } else {
478
+ opt.classList.remove('selected');
479
+ }
480
+ });
481
+ }
482
+
483
+ // Click on preview to deselect
484
+ memePreview.addEventListener('click', function() {
485
+ if (selectedTextElement) {
486
+ selectedTextElement.style.border = '';
487
+ selectedTextElement = null;
488
+ topTextInput.value = '';
489
+ bottomTextInput.value = '';
490
+ }
491
+ });
492
+
493
+ function downloadMeme() {
494
+ if (!memeImage.src) return;
495
+
496
+ // Use html2canvas to capture the meme
497
+ html2canvas(memePreview).then(canvas => {
498
+ const link = document.createElement('a');
499
+ link.download = 'meme.png';
500
+ link.href = canvas.toDataURL('image/png');
501
+ link.click();
502
+
503
+ // Add to recent memes
504
+ addToRecentMemes(canvas.toDataURL('image/png'));
505
+ });
506
+ }
507
+
508
+ function addToRecentMemes(dataUrl) {
509
+ // Limit to 6 recent memes
510
+ if (recentMemes.length >= 6) {
511
+ recentMemes.pop();
512
+ }
513
+
514
+ recentMemes.unshift(dataUrl);
515
+ updateRecentMemesDisplay();
516
+ }
517
+
518
+ function updateRecentMemesDisplay() {
519
+ recentMemesContainer.innerHTML = '';
520
+
521
+ if (recentMemes.length === 0) {
522
+ recentMemesContainer.innerHTML = `
523
+ <div class="text-center p-4 bg-gray-100 rounded-lg">
524
+ <i class="fas fa-image text-3xl text-gray-400 mb-2"></i>
525
+ <p class="text-sm text-gray-600">No memes yet</p>
526
+ </div>
527
+ `;
528
+ return;
529
+ }
530
+
531
+ recentMemes.forEach((meme, index) => {
532
+ const memeElement = document.createElement('div');
533
+ memeElement.className = 'cursor-pointer';
534
+ memeElement.innerHTML = `
535
+ <img src="${meme}" alt="Recent meme ${index + 1}" class="w-full h-auto rounded-lg hover:opacity-90">
536
+ `;
537
+ memeElement.addEventListener('click', function() {
538
+ if (confirm('Load this meme?')) {
539
+ updateMemeTemplate(meme);
540
+ }
541
+ });
542
+ recentMemesContainer.appendChild(memeElement);
543
+ });
544
+ }
545
+
546
+ // Load html2canvas dynamically
547
+ function loadHtml2Canvas() {
548
+ return new Promise((resolve, reject) => {
549
+ const script = document.createElement('script');
550
+ script.src = 'https://html2canvas.hertzen.com/dist/html2canvas.min.js';
551
+ script.onload = resolve;
552
+ script.onerror = reject;
553
+ document.head.appendChild(script);
554
+ });
555
+ }
556
+
557
+ // Load html2canvas when needed
558
+ downloadBtn.addEventListener('click', function() {
559
+ if (typeof html2canvas === 'undefined') {
560
+ loadHtml2Canvas().then(() => {
561
+ downloadMeme();
562
+ }).catch(err => {
563
+ alert('Failed to load image generator. Please try again.');
564
+ console.error(err);
565
+ });
566
+ } else {
567
+ downloadMeme();
568
+ }
569
+ });
570
+ });
571
+ </script>
572
+ <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=linoyts/meme-generator" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
573
+ </html>