Secure Daily Inspirational Quotes Generator

Daily Inspirational Quote

Fetching your daily inspiration...

Your Favorite Quotes

- ${fav.author || 'Unknown'}

`).join(''); lucide.createIcons(); }; // --- CORE LOGIC --- const getDailyQuote = async () => { const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const dailyQuoteRef = doc(db, `/artifacts/${appId}/users/${userId}/daily_quotes`, todayKey); const docSnap = await getDoc(dailyQuoteRef); if (docSnap.exists()) { // Quote for today already exists, display it displayQuote(docSnap.data()); } else { // No quote for today, fetch a new one using Gemini API try { const prompt = `Generate a single, unique, and inspirational quote. Return it as a JSON object with 'text' and 'author' keys. For example: {"text": "The only way to do great work is to love what you do.", "author": "Steve Jobs"}`; const payload = { contents: [{ role: "user", parts: [{ text: prompt }] }], generationConfig: { responseMimeType: "application/json", responseSchema: { type: "OBJECT", properties: { "text": { "type": "STRING" }, "author": { "type": "STRING" } }, required: ["text", "author"] } } }; const apiKey = ""; // Provided by the environment const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-05-20:generateContent?key=${apiKey}`; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`API request failed with status ${response.status}`); } const result = await response.json(); const jsonText = result?.candidates?.[0]?.content?.parts?.[0]?.text; if (!jsonText) { throw new Error("Invalid or empty response from API."); } const quoteData = JSON.parse(jsonText); // Save the new quote to Firestore for today await setDoc(dailyQuoteRef, quoteData); displayQuote(quoteData); } catch (error) { console.error("Error fetching new quote:", error); DOM.quoteLoader.innerHTML = `

Could not fetch inspiration today. Please try again later.

`; } } }; // --- FIRESTORE OPERATIONS --- const saveToFavorites = async () => { if (!currentQuote) return; DOM.favoriteBtn.disabled = true; const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; // Use a hash of the quote text as a unique ID to prevent duplicates const quoteId = await digestMessage(currentQuote.text); const favoriteRef = doc(db, `/artifacts/${appId}/users/${userId}/favorite_quotes`, quoteId); await setDoc(favoriteRef, currentQuote); DOM.favoriteBtn.disabled = false; }; const removeFromFavorites = async (quoteId) => { const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const favoriteRef = doc(db, `/artifacts/${appId}/users/${userId}/favorite_quotes`, quoteId); await deleteDoc(favoriteRef); }; // --- PDF EXPORT --- const downloadPDF = () => { if (!currentQuote) return; const { jsPDF } = window.jspdf; const doc = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' }); const pageWidth = doc.internal.pageSize.getWidth(); const text = `"${currentQuote.text}"`; const author = `- ${currentQuote.author || 'Unknown'}`; doc.setFontSize(18); const splitText = doc.splitTextToSize(text, pageWidth - 40); const textHeight = splitText.length * 10; const yPos = (doc.internal.pageSize.getHeight() / 2) - (textHeight / 2); doc.text(splitText, pageWidth / 2, yPos, { align: 'center' }); doc.setFontSize(14); doc.text(author, pageWidth - 20, yPos + textHeight + 10, { align: 'right' }); doc.save(`inspirational_quote_${todayKey}.pdf`); }; // --- UTILITY --- async function digestMessage(message) { const msgUint8 = new TextEncoder().encode(message); const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); return hashHex; } // --- INITIALIZATION --- document.addEventListener('DOMContentLoaded', async () => { // Assign DOM elements Object.assign(DOM, { currentDate: document.getElementById('current-date'), quoteLoader: document.getElementById('quote-loader'), quoteContent: document.getElementById('quote-content'), quoteText: document.getElementById('quote-text'), quoteAuthor: document.getElementById('quote-author'), favoriteBtn: document.getElementById('favorite-btn'), downloadPdfBtn: document.getElementById('download-pdf-btn'), favoritesList: document.getElementById('favorites-list'), noFavoritesMessage: document.getElementById('no-favorites-message') }); DOM.currentDate.textContent = new Date().toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); // Event Listeners DOM.favoriteBtn.addEventListener('click', saveToFavorites); DOM.downloadPdfBtn.addEventListener('click', downloadPDF); DOM.favoritesList.addEventListener('click', (e) => { const removeBtn = e.target.closest('.remove-favorite-btn'); if (removeBtn) { removeFromFavorites(removeBtn.dataset.id); } }); // Firebase Initialization try { const firebaseConfig = JSON.parse(typeof __firebase_config !== 'undefined' ? __firebase_config : '{}'); const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; if (!firebaseConfig.apiKey) throw new Error("Firebase config missing."); const app = initializeApp(firebaseConfig); db = getFirestore(app); auth = getAuth(app); onAuthStateChanged(auth, (user) => { if (user) { userId = user.uid; if (favoritesUnsubscribe) favoritesUnsubscribe(); getDailyQuote(); // Fetch the main quote for today const favoritesCollection = collection(db, `/artifacts/${appId}/users/${userId}/favorite_quotes`); favoritesUnsubscribe = onSnapshot(query(favoritesCollection), (snapshot) => { const favorites = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); renderFavorites(favorites); }); } }); if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) await signInWithCustomToken(auth, __initial_auth_token); else await signInAnonymously(auth); } catch (error) { console.error("Init Error:", error); DOM.quoteLoader.innerHTML = `

Could not connect to the service. ${error.message}

`; } lucide.createIcons(); });
Scroll to Top