let isDarkMode = false; let fontData = []; // Load available fonts when page loads async function loadAvailableFonts() { try { const response = await fetch("/api/fonts"); fontData = await response.json(); // Populate both quote and author font family selects const quoteFontFamily = document.getElementById("quoteFontFamily"); const authorFontFamily = document.getElementById("authorFontFamily"); const fontOptions = fontData .map((font) => ``) .join(""); quoteFontFamily.innerHTML = fontOptions; authorFontFamily.innerHTML = fontOptions; // Initialize variations for both if (fontData.length > 0) { updateFontVariations("quote", fontData[0].family); updateFontVariations("author", fontData[0].family); generateQuote(); } } catch (error) { console.error("Error loading fonts:", error); showStatus("Error loading fonts", "error"); } } // Update font variations based on selected font family function updateFontVariations(type, family) { const font = fontData.find((f) => f.family === family); if (!font) return; const styleSelect = document.getElementById(`${type}FontStyle`); // Get unique styles const styles = new Set(font.variations.map((v) => v.style)); // Update style options styleSelect.innerHTML = Array.from(styles) .map( (style) => `` ) .join(""); } // Format font weight for display function formatFontWeight(weight) { switch (weight) { case "normal": return "Regular"; case "bold": return "Bold"; case "light": return "Light"; case "medium": return "Medium"; default: return weight.charAt(0).toUpperCase() + weight.slice(1); } } // Format font style for display function formatFontStyle(style) { switch (style) { case "normal": return "Normal"; case "italic": return "Italic"; default: return style.charAt(0).toUpperCase() + style.slice(1); } } // Setup color pickers with hex input sync function setupColorPickers() { const colorInputs = document.querySelectorAll('input[type="color"]'); colorInputs.forEach((input) => { const textInput = document.getElementById(input.id + "Text"); // Update text input when color changes input.addEventListener("input", () => { textInput.value = input.value.toUpperCase(); }); // Update color input when valid hex is entered textInput.addEventListener("input", () => { let hex = textInput.value.trim(); if (!hex.startsWith("#")) { hex = "#" + hex; } if (/^#[0-9A-F]{6}$/i.test(hex)) { input.value = hex; } }); // Format hex on blur textInput.addEventListener("blur", () => { let hex = textInput.value.trim(); if (!hex.startsWith("#")) { hex = "#" + hex; } if (/^#[0-9A-F]{6}$/i.test(hex)) { textInput.value = hex.toUpperCase(); input.value = hex; } else { textInput.value = input.value.toUpperCase(); } }); }); } async function generateQuote() { const generateBtn = document.querySelector(".btn-primary"); const btnText = generateBtn.querySelector(".btn-text"); const btnLoader = generateBtn.querySelector(".btn-loader"); try { // Show loading state generateBtn.disabled = true; btnText.style.opacity = "0"; btnLoader.style.display = "block"; document.getElementById("loading").style.display = "flex"; document.getElementById("quoteImage").style.opacity = "0.5"; const data = { text: document.getElementById("quoteText").value, author: document.getElementById("author").value, bgColor: document.getElementById("bgColor").value, barColor: document.getElementById("barColor").value, textColor: document.getElementById("textColor").value, authorColor: document.getElementById("authorColor").value, quoteFontFamily: document.getElementById("quoteFontFamily").value, quoteFontWeight: "bold", // Force bold for quote quoteFontStyle: document.getElementById("quoteFontStyle").value, authorFontFamily: document.getElementById("authorFontFamily").value, authorFontWeight: "normal", // Force normal for author authorFontStyle: document.getElementById("authorFontStyle").value, barWidth: parseInt(document.getElementById("barWidth").value), }; const response = await fetch("/api/generate-quote", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }); const result = await response.json(); if (result.success) { const img = document.getElementById("quoteImage"); img.src = result.imageUrl; img.style.opacity = "1"; showStatus("Quote generated successfully!", "success"); } else { throw new Error(result.error); } } catch (error) { showStatus(error.message || "Error generating quote", "error"); console.error(error); } finally { // Reset loading state generateBtn.disabled = false; btnText.style.opacity = "1"; btnLoader.style.display = "none"; document.getElementById("loading").style.display = "none"; } } function downloadQuote() { const img = document.getElementById("quoteImage"); if (!img.src || img.src === window.location.href) { showStatus("Generate a quote first!", "error"); return; } const link = document.createElement("a"); const timestamp = new Date().toISOString().split("T")[0]; link.download = `quote-${timestamp}.png`; link.href = img.src; link.click(); } async function viewRequests() { try { const response = await fetch("/api/requests-history"); const requests = await response.json(); const requestsList = document.getElementById("requestsList"); requestsList.innerHTML = requests .map( (req) => `
${JSON.stringify( req.request, null, 2 )}