the Meme Generator is not working and the Generated Captions is not working and T-Shirt Preview is not working and the Meme Generator is adding the image to the t-shirt a to make it look real
Browse files
meme.html
CHANGED
|
@@ -35,9 +35,9 @@
|
|
| 35 |
<label class="block text-gray-400 mb-2">Style Hint (Optional)</label>
|
| 36 |
<input type="text" placeholder="e.g., crypto meme, sarcastic" class="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-3 focus:outline-none focus:ring-2 focus:ring-red-500">
|
| 37 |
</div>
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
</div>
|
| 42 |
|
| 43 |
<div>
|
|
@@ -58,18 +58,37 @@
|
|
| 58 |
|
| 59 |
<div class="mt-12">
|
| 60 |
<h2 class="text-xl font-bold mb-4">T-Shirt Preview</h2>
|
| 61 |
-
|
| 62 |
<div id="mockupPlaceholder" class="text-center">
|
| 63 |
<i data-feather="t-shirt" class="w-24 h-24 mx-auto text-gray-600 mb-4"></i>
|
| 64 |
<p class="text-gray-500">Your t-shirt mockup will appear here</p>
|
| 65 |
</div>
|
| 66 |
<div id="mockupPreview" class="hidden relative">
|
| 67 |
-
<
|
| 68 |
-
|
| 69 |
-
<
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
</div>
|
| 74 |
</div>
|
| 75 |
</div>
|
|
@@ -130,7 +149,6 @@
|
|
| 130 |
handleImageUpload(file);
|
| 131 |
}
|
| 132 |
});
|
| 133 |
-
|
| 134 |
function handleImageUpload(file) {
|
| 135 |
const reader = new FileReader();
|
| 136 |
reader.onload = (e) => {
|
|
@@ -142,24 +160,24 @@
|
|
| 142 |
};
|
| 143 |
reader.readAsDataURL(file);
|
| 144 |
}
|
| 145 |
-
|
| 146 |
-
// Generate captions
|
| 147 |
generateBtn.addEventListener('click', async () => {
|
| 148 |
if (!uploadedImage) return;
|
| 149 |
|
| 150 |
loadingCaptions.classList.remove('hidden');
|
| 151 |
captionsContainer.classList.add('hidden');
|
| 152 |
noCaptions.classList.add('hidden');
|
|
|
|
| 153 |
|
| 154 |
// Simulate API call with mock captions
|
| 155 |
setTimeout(() => {
|
| 156 |
const captions = generateMockCaptions();
|
| 157 |
displayCaptions(captions);
|
| 158 |
loadingCaptions.classList.add('hidden');
|
|
|
|
| 159 |
}, 1500);
|
| 160 |
});
|
| 161 |
-
|
| 162 |
-
function generateMockCaptions() {
|
| 163 |
const captionTemplates = [
|
| 164 |
"When you finally understand that meme",
|
| 165 |
"Send this to your group chat immediately",
|
|
@@ -196,7 +214,6 @@
|
|
| 196 |
`;
|
| 197 |
captionsContainer.appendChild(captionDiv);
|
| 198 |
});
|
| 199 |
-
|
| 200 |
// Add event listeners to the new buttons
|
| 201 |
document.querySelectorAll('.preview-btn').forEach(btn => {
|
| 202 |
btn.addEventListener('click', (e) => {
|
|
@@ -210,31 +227,96 @@
|
|
| 210 |
const caption = e.target.dataset.caption;
|
| 211 |
currentCaption = caption;
|
| 212 |
showMockup(caption);
|
| 213 |
-
|
| 214 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 215 |
});
|
| 216 |
});
|
| 217 |
-
|
| 218 |
-
captionsContainer.classList.remove('hidden');
|
| 219 |
}
|
| 220 |
-
|
| 221 |
function showMockup(caption) {
|
| 222 |
if (!uploadedImage) return;
|
| 223 |
|
| 224 |
-
|
| 225 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
mockupPlaceholder.classList.add('hidden');
|
| 227 |
mockupPreview.classList.remove('hidden');
|
| 228 |
}
|
| 229 |
-
|
| 230 |
function resetCaptions() {
|
| 231 |
captionsContainer.classList.add('hidden');
|
| 232 |
noCaptions.classList.remove('hidden');
|
| 233 |
mockupPlaceholder.classList.remove('hidden');
|
| 234 |
mockupPreview.classList.add('hidden');
|
|
|
|
| 235 |
}
|
| 236 |
-
|
| 237 |
-
// Style hint input
|
| 238 |
const styleHint = document.querySelector('input[placeholder="e.g., crypto meme, sarcastic"]');
|
| 239 |
if (styleHint) {
|
| 240 |
styleHint.addEventListener('input', (e) => {
|
|
|
|
| 35 |
<label class="block text-gray-400 mb-2">Style Hint (Optional)</label>
|
| 36 |
<input type="text" placeholder="e.g., crypto meme, sarcastic" class="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-3 focus:outline-none focus:ring-2 focus:ring-red-500">
|
| 37 |
</div>
|
| 38 |
+
<button id="generateBtn" class="w-full bg-red-600 hover:bg-red-700 text-white py-3 rounded-lg font-semibold transition disabled:bg-gray-600 disabled:cursor-not-allowed">
|
| 39 |
+
Generate Captions
|
| 40 |
+
</button>
|
| 41 |
</div>
|
| 42 |
|
| 43 |
<div>
|
|
|
|
| 58 |
|
| 59 |
<div class="mt-12">
|
| 60 |
<h2 class="text-xl font-bold mb-4">T-Shirt Preview</h2>
|
| 61 |
+
<div id="mockupContainer" class="bg-gray-800 rounded-xl p-8 flex items-center justify-center min-h-[500px] border border-gray-700">
|
| 62 |
<div id="mockupPlaceholder" class="text-center">
|
| 63 |
<i data-feather="t-shirt" class="w-24 h-24 mx-auto text-gray-600 mb-4"></i>
|
| 64 |
<p class="text-gray-500">Your t-shirt mockup will appear here</p>
|
| 65 |
</div>
|
| 66 |
<div id="mockupPreview" class="hidden relative">
|
| 67 |
+
<!-- T-Shirt SVG Mockup -->
|
| 68 |
+
<svg width="300" height="350" viewBox="0 0 300 350" class="relative">
|
| 69 |
+
<!-- T-Shirt Base -->
|
| 70 |
+
<path d="M75 80 L75 40 L100 20 L120 30 L150 25 L180 30 L200 20 L225 40 L225 80 L200 100 L200 320 L100 320 L100 100 Z"
|
| 71 |
+
fill="#1a1a1a" stroke="#333" stroke-width="2"/>
|
| 72 |
+
<!-- Neckline -->
|
| 73 |
+
<ellipse cx="150" cy="40" rx="25" ry="20" fill="none" stroke="#333" stroke-width="2"/>
|
| 74 |
+
<!-- Sleeves -->
|
| 75 |
+
<path d="M75 80 L50 120 L40 180 L70 180 L100 100" fill="#1a1a1a" stroke="#333" stroke-width="2"/>
|
| 76 |
+
<path d="M225 80 L250 120 L260 180 L230 180 L200 100" fill="#1a1a1a" stroke="#333" stroke-width="2"/>
|
| 77 |
+
|
| 78 |
+
<!-- Design Area -->
|
| 79 |
+
<defs>
|
| 80 |
+
<clipPath id="designArea">
|
| 81 |
+
<rect x="90" y="100" width="120" height="120" rx="5"/>
|
| 82 |
+
</clipPath>
|
| 83 |
+
</defs>
|
| 84 |
+
<rect x="90" y="100" width="120" height="120" rx="5" fill="white" opacity="0.1"/>
|
| 85 |
+
<g clip-path="url(#designArea)">
|
| 86 |
+
<image id="tshirtImage" x="90" y="100" width="120" height="120" preserveAspectRatio="xMidYMid meet"/>
|
| 87 |
+
</g>
|
| 88 |
+
|
| 89 |
+
<!-- Caption Text -->
|
| 90 |
+
<text id="tshirtCaption" x="150" y="240" text-anchor="middle" fill="white" font-size="14" font-weight="bold" font-family="Arial, sans-serif"></text>
|
| 91 |
+
</svg>
|
| 92 |
</div>
|
| 93 |
</div>
|
| 94 |
</div>
|
|
|
|
| 149 |
handleImageUpload(file);
|
| 150 |
}
|
| 151 |
});
|
|
|
|
| 152 |
function handleImageUpload(file) {
|
| 153 |
const reader = new FileReader();
|
| 154 |
reader.onload = (e) => {
|
|
|
|
| 160 |
};
|
| 161 |
reader.readAsDataURL(file);
|
| 162 |
}
|
| 163 |
+
// Generate captions
|
|
|
|
| 164 |
generateBtn.addEventListener('click', async () => {
|
| 165 |
if (!uploadedImage) return;
|
| 166 |
|
| 167 |
loadingCaptions.classList.remove('hidden');
|
| 168 |
captionsContainer.classList.add('hidden');
|
| 169 |
noCaptions.classList.add('hidden');
|
| 170 |
+
generateBtn.disabled = true;
|
| 171 |
|
| 172 |
// Simulate API call with mock captions
|
| 173 |
setTimeout(() => {
|
| 174 |
const captions = generateMockCaptions();
|
| 175 |
displayCaptions(captions);
|
| 176 |
loadingCaptions.classList.add('hidden');
|
| 177 |
+
generateBtn.disabled = false;
|
| 178 |
}, 1500);
|
| 179 |
});
|
| 180 |
+
function generateMockCaptions() {
|
|
|
|
| 181 |
const captionTemplates = [
|
| 182 |
"When you finally understand that meme",
|
| 183 |
"Send this to your group chat immediately",
|
|
|
|
| 214 |
`;
|
| 215 |
captionsContainer.appendChild(captionDiv);
|
| 216 |
});
|
|
|
|
| 217 |
// Add event listeners to the new buttons
|
| 218 |
document.querySelectorAll('.preview-btn').forEach(btn => {
|
| 219 |
btn.addEventListener('click', (e) => {
|
|
|
|
| 227 |
const caption = e.target.dataset.caption;
|
| 228 |
currentCaption = caption;
|
| 229 |
showMockup(caption);
|
| 230 |
+
|
| 231 |
+
// Create success notification
|
| 232 |
+
const notification = document.createElement('div');
|
| 233 |
+
notification.className = 'fixed top-20 right-4 bg-green-600 text-white px-6 py-3 rounded-lg shadow-lg z-50 transform translate-x-full transition-transform duration-300';
|
| 234 |
+
notification.innerHTML = `
|
| 235 |
+
<div class="flex items-center">
|
| 236 |
+
<i data-feather="check-circle" class="w-5 h-5 mr-2"></i>
|
| 237 |
+
<span>Design added to T-Shirt! Scroll down to preview.</span>
|
| 238 |
+
</div>
|
| 239 |
+
`;
|
| 240 |
+
document.body.appendChild(notification);
|
| 241 |
+
feather.replace();
|
| 242 |
+
|
| 243 |
+
// Animate in
|
| 244 |
+
setTimeout(() => {
|
| 245 |
+
notification.style.transform = 'translateX(0)';
|
| 246 |
+
}, 100);
|
| 247 |
+
|
| 248 |
+
// Remove after 3 seconds
|
| 249 |
+
setTimeout(() => {
|
| 250 |
+
notification.style.transform = 'translateX(100%)';
|
| 251 |
+
setTimeout(() => {
|
| 252 |
+
document.body.removeChild(notification);
|
| 253 |
+
}, 300);
|
| 254 |
+
}, 3000);
|
| 255 |
});
|
| 256 |
});
|
| 257 |
+
captionsContainer.classList.remove('hidden');
|
|
|
|
| 258 |
}
|
|
|
|
| 259 |
function showMockup(caption) {
|
| 260 |
if (!uploadedImage) return;
|
| 261 |
|
| 262 |
+
const tshirtImage = document.getElementById('tshirtImage');
|
| 263 |
+
const tshirtCaption = document.getElementById('tshirtCaption');
|
| 264 |
+
|
| 265 |
+
// Set the image on the t-shirt
|
| 266 |
+
tshirtImage.setAttributeNS('http://www.w3.org/1999/xlink', 'href', uploadedImage);
|
| 267 |
+
|
| 268 |
+
// Set the caption with word wrap
|
| 269 |
+
const words = caption.split(' ');
|
| 270 |
+
const maxCharsPerLine = 15;
|
| 271 |
+
let lines = [];
|
| 272 |
+
let currentLine = '';
|
| 273 |
+
|
| 274 |
+
words.forEach(word => {
|
| 275 |
+
if ((currentLine + word).length <= maxCharsPerLine) {
|
| 276 |
+
currentLine += (currentLine ? ' ' : '') + word;
|
| 277 |
+
} else {
|
| 278 |
+
if (currentLine) lines.push(currentLine);
|
| 279 |
+
currentLine = word;
|
| 280 |
+
}
|
| 281 |
+
});
|
| 282 |
+
if (currentLine) lines.push(currentLine);
|
| 283 |
+
|
| 284 |
+
// Clear existing text elements
|
| 285 |
+
const mockupPreview = document.getElementById('mockupPreview');
|
| 286 |
+
const existingTexts = mockupPreview.querySelectorAll('text:not(#tshirtCaption)');
|
| 287 |
+
existingTexts.forEach(text => text.remove());
|
| 288 |
+
|
| 289 |
+
// Add new text elements for each line
|
| 290 |
+
const svg = mockupPreview.querySelector('svg');
|
| 291 |
+
const startY = lines.length === 1 ? 240 : (lines.length === 2 ? 235 : 230);
|
| 292 |
+
|
| 293 |
+
lines.forEach((line, index) => {
|
| 294 |
+
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
| 295 |
+
text.setAttribute('x', '150');
|
| 296 |
+
text.setAttribute('y', startY + (index * 15));
|
| 297 |
+
text.setAttribute('text-anchor', 'middle');
|
| 298 |
+
text.setAttribute('fill', 'white');
|
| 299 |
+
text.setAttribute('font-size', '12');
|
| 300 |
+
text.setAttribute('font-weight', 'bold');
|
| 301 |
+
text.setAttribute('font-family', 'Arial, sans-serif');
|
| 302 |
+
text.textContent = line;
|
| 303 |
+
svg.appendChild(text);
|
| 304 |
+
});
|
| 305 |
+
|
| 306 |
+
// Hide the original text element
|
| 307 |
+
tshirtCaption.style.display = 'none';
|
| 308 |
+
|
| 309 |
mockupPlaceholder.classList.add('hidden');
|
| 310 |
mockupPreview.classList.remove('hidden');
|
| 311 |
}
|
|
|
|
| 312 |
function resetCaptions() {
|
| 313 |
captionsContainer.classList.add('hidden');
|
| 314 |
noCaptions.classList.remove('hidden');
|
| 315 |
mockupPlaceholder.classList.remove('hidden');
|
| 316 |
mockupPreview.classList.add('hidden');
|
| 317 |
+
generateBtn.disabled = !uploadedImage;
|
| 318 |
}
|
| 319 |
+
// Style hint input
|
|
|
|
| 320 |
const styleHint = document.querySelector('input[placeholder="e.g., crypto meme, sarcastic"]');
|
| 321 |
if (styleHint) {
|
| 322 |
styleHint.addEventListener('input', (e) => {
|