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) => `
${new Date( req.timestamp ).toLocaleString()}
${JSON.stringify(
                  req.request,
                  null,
                  2
                )}
` ) .join(""); document.getElementById("requestsModal").style.display = "block"; } catch (error) { showStatus("Error fetching requests", "error"); console.error(error); } } function closeModal() { document.getElementById("requestsModal").style.display = "none"; } function toggleTheme() { isDarkMode = !isDarkMode; document.documentElement.setAttribute( "data-theme", isDarkMode ? "dark" : "light" ); document.querySelector(".theme-toggle").textContent = isDarkMode ? "☀️" : "🌙"; } function showStatus(message, type) { const status = document.getElementById("status"); status.textContent = message; status.style.color = type === "success" ? "var(--success)" : "#ef4444"; status.style.display = "block"; setTimeout(() => { status.style.display = "none"; }, 3000); } // Event Listeners document.addEventListener("DOMContentLoaded", () => { loadAvailableFonts(); setupColorPickers(); // Font family change listeners document.getElementById("quoteFontFamily").addEventListener("change", (e) => { updateFontVariations("quote", e.target.value); }); document .getElementById("authorFontFamily") .addEventListener("change", (e) => { updateFontVariations("author", e.target.value); }); // Check system theme preference if ( window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ) { toggleTheme(); } // Setup bar width value display const barWidthSlider = document.getElementById("barWidth"); const barWidthValue = document.getElementById("barWidthValue"); barWidthSlider.addEventListener("input", () => { barWidthValue.textContent = `${barWidthSlider.value}px`; }); }); // Close modal when clicking outside window.onclick = function (event) { const modal = document.getElementById("requestsModal"); if (event.target === modal) { closeModal(); } };