import React, { useState, useRef, useEffect } from "https://esm.sh/react";
import { createRoot } from "https://esm.sh/react-dom/client";
interface MemeTemplate {
id: string;
name: string;
url: string;
}
interface TextPosition {
x: number;
y: number;
maxWidth: number;
color: string;
}
function App() {
const [templates, setTemplates] = useState<MemeTemplate[]>([]);
const [selectedTemplate, setSelectedTemplate] = useState<string>("");
const [topText, setTopText] = useState<string>("");
const [bottomText, setBottomText] = useState<string>("");
const [memeUrl, setMemeUrl] = useState<string>("");
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
fetch("/templates")
.then(response => response.json())
.then(data => setTemplates(data));
}, []);
const getTextPositions = (imageWidth: number, imageHeight: number, templateId: string): [TextPosition, TextPosition] => {
const defaultColor = "white";
switch (templateId) {
case "1":
return [
{ x: imageWidth * 0.7, y: imageHeight * 0.25, maxWidth: imageWidth * 0.5, color: "black" },
{ x: imageWidth * 0.7, y: imageHeight * 0.75, maxWidth: imageWidth * 0.5, color: "black" }
];
case "2":
return [
{ x: imageWidth * 0.6, y: imageHeight * 0.1, maxWidth: imageWidth * 0.3, color: defaultColor },
{ x: imageWidth * 0.8, y: imageHeight * 0.1, maxWidth: imageWidth * 0.3, color: defaultColor }
];
case "3":
return [
{ x: imageWidth * 0.5, y: imageHeight * 0.1, maxWidth: imageWidth * 0.8, color: defaultColor },
{ x: imageWidth * 0.5, y: imageHeight * 0.9, maxWidth: imageWidth * 0.8, color: defaultColor }
];
case "4":
return [
{ x: imageWidth * 0.5, y: imageHeight * 0.15, maxWidth: imageWidth * 0.8, color: defaultColor },
{ x: imageWidth * 0.5, y: imageHeight * 0.95, maxWidth: imageWidth * 0.8, color: defaultColor }
];
case "5":
return [
{ x: imageWidth * 0.5, y: imageHeight * 0.7, maxWidth: imageWidth * 0.8, color: defaultColor },
{ x: imageWidth * 0.5, y: imageHeight * 0.9, maxWidth: imageWidth * 0.8, color: defaultColor }
];
default:
return [
{ x: imageWidth * 0.5, y: imageHeight * 0.1, maxWidth: imageWidth * 0.9, color: defaultColor },
{ x: imageWidth * 0.5, y: imageHeight * 0.9, maxWidth: imageWidth * 0.9, color: defaultColor }
];
}
};
const generateMeme = () => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
const selectedImage = templates.find(t => t.id === selectedTemplate);
if (!selectedImage) return;
const image = new Image();
image.crossOrigin = "anonymous";
image.onload = () => {
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0);
const fontSize = Math.floor(image.height / 15);
ctx.font = `bold ${fontSize}px Impact, sans-serif`;
ctx.textAlign = "center";
const [topPosition, bottomPosition] = getTextPositions(image.width, image.height, selectedTemplate);
const drawText = (text: string, position: TextPosition) => {
ctx.fillStyle = position.color;
ctx.strokeStyle = "black";
ctx.lineWidth = Math.floor(fontSize / 15);