import { useState, useEffect } from 'react'; import { getAuth, signInAnonymously, signInWithCustomToken } from 'firebase/auth'; import { initializeApp } from 'firebase/app'; import { Loader2, Copy, Sparkles, Wand2 } from 'lucide-react'; // Using lucide-react for icons
// Initialize Firebase with global variables provided by the environment const firebaseConfig = typeof __firebase_config !== 'undefined' ? JSON.parse(__firebase_config) : {}; const app = initializeApp(firebaseConfig); const auth = getAuth(app); const initialAuthToken = typeof __initial_auth_token !== 'undefined' ? __initial_auth_token : '';
// Main App component const App = () => { const [keyword, setKeyword] = useState(''); const [ideas, setIdeas] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const [userId, setUserId] = useState(null); const [isMobile, setIsMobile] = useState(window.innerWidth < 768); // Custom hook-like logic to handle responsive design without an external library useEffect(() => { const handleResize = () => { setIsMobile(window.innerWidth < 768); }; window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); }; }, []);
// Function to sign in to Firebase const signIn = async () => { try { if (initialAuthToken) { await signInWithCustomToken(auth, initialAuthToken); } else { await signInAnonymously(auth); } setUserId(auth.currentUser?.uid); } catch (e) { console.error('Firebase sign-in failed:', e); // In a real app, you would handle this gracefully on the UI. } };
useEffect(() => { signIn(); }, []);
const generateIdeas = async () => { if (!keyword) { setError('Please enter a keyword to generate ideas.'); return; } setLoading(true); setError(''); setIdeas([]);
// Prompt for the LLM API call const prompt = `Generate a list of 5 creative and engaging content ideas (blog post titles and a brief one-sentence outline) based on the keyword "${keyword}". The ideas should be formatted as a numbered list. Each item should have a title and a description.`;
try { const chatHistory = [{ role: "user", parts: [{ text: prompt }] }]; const payload = { contents: chatHistory }; const apiKey = ""; const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-05-20:generateContent?key=${apiKey}`;
let response; let result; let retries = 0; const maxRetries = 5; const baseDelay = 1000;
while (retries < maxRetries) { try { response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (response.status === 429) { retries++; await new Promise(resolve => setTimeout(resolve, baseDelay * Math.pow(2, retries - 1))); continue; }
if (!response.ok) { throw new Error(`API error: ${response.status} ${response.statusText}`); }
result = await response.json(); break;
} catch (e) { if (retries === maxRetries - 1) { throw e; } retries++; await new Promise(resolve => setTimeout(resolve, baseDelay * Math.pow(2, retries - 1))); } }
if (!result || !result.candidates || result.candidates.length === 0) { throw new Error('No candidates found in API response.'); }
const text = result.candidates[0].content.parts[0].text; const parsedIdeas = parseIdeas(text); setIdeas(parsedIdeas);
} catch (e) { console.error('Error generating ideas:', e); setError('Failed to generate ideas. Please try again.'); } finally { setLoading(false); } };
const parseIdeas = (text) => { const lines = text.split('\n').filter(line => line.trim() !== ''); const ideaList = []; let currentIdea = null;
lines.forEach(line => { const titleMatch = line.match(/^\d+\.\s*(.+)/); if (titleMatch) { if (currentIdea) { ideaList.push(currentIdea); } currentIdea = { title: titleMatch[1].trim(), description: '' }; } else if (currentIdea) { currentIdea.description += line.trim() + ' '; } });
if (currentIdea) { ideaList.push(currentIdea); }
return ideaList; };
const handleCopy = (text) => { // Copy text to clipboard using the older but more reliable method in iframes const el = document.createElement('textarea'); el.value = text; document.body.appendChild(el); el.select(); document.execCommand('copy'); document.body.removeChild(el); alert('Idea copied to clipboard!'); // Using custom alert for feedback };
return (
AI Content Idea Generator
Overcome writer's block. Get creative, SEO-friendly content ideas in seconds.
{/* Input section */}
{error &&
{error}
}
{/* Results section */}
) : ideas.length > 0 ? (
Generated Ideas:
{ideas.map((idea, index) => (
{idea.title}
{idea.description.trim()}
))}
) : (
Your generated ideas will appear here.
)}
{/* Custom Alert Box - replaces native alert() */}
); };
// Custom alert function const alert = (message) => { const alertContainer = document.getElementById('custom-alert-container'); const alertBox = document.getElementById('custom-alert-box'); const alertMessage = document.getElementById('custom-alert-message'); const alertOk = document.getElementById('custom-alert-ok');
alertMessage.innerText = message; alertContainer.classList.remove('pointer-events-none'); alertBox.classList.remove('opacity-0', 'scale-95', '-translate-y-4'); alertBox.classList.add('opacity-100', 'scale-100', 'translate-y-0');
const hideAlert = () => { alertBox.classList.remove('opacity-100', 'scale-100', 'translate-y-0'); alertBox.classList.add('opacity-0', 'scale-95', '-translate-y-4'); alertContainer.classList.add('pointer-events-none'); alertOk.removeEventListener('click', hideAlert); };
alertOk.addEventListener('click', hideAlert); };
export default App;