class InkBoard { constructor() { this.currentCreationId = null; this.currentSection = 'create'; this.init(); } init() { this.setupEventListeners(); this.loadGallery(); this.showSection('create'); } setupEventListeners() { document.getElementById('scene-form').addEventListener('submit', (e) => { e.preventDefault(); this.generateContent(); }); document.getElementById('save-journal').addEventListener('click', () => { this.saveJournal(); }); document.getElementById('journalModal').addEventListener('hidden.bs.modal', () => { this.currentCreationId = null; document.getElementById('journal-text').value = ''; }); } async generateContent() { const sceneIdea = document.getElementById('scene-idea').value.trim(); if (!sceneIdea) { this.showAlert('Please enter a scene idea', 'danger'); return; } try { this.showLoading(true); this.setButtonLoading(true); const response = await fetch('/generate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ scene_idea: sceneIdea }) }); const data = await response.json(); if (data.success) { this.displayResult(data); this.loadGallery(); document.getElementById('scene-idea').value = ''; this.showAlert('Story and image generated successfully!', 'success'); } else { this.showAlert(data.error || 'Failed to generate content', 'danger'); } } catch (error) { console.error('Error generating content:', error); this.showAlert('Network error. Please try again.', 'danger'); } finally { this.showLoading(false); this.setButtonLoading(false); } } displayResult(data) { const resultsSection = document.getElementById('results-section'); const imageSection = data.image_url ? `
Generated Scene
` : ''; const storyColClass = data.image_url ? 'col-lg-6' : 'col-12'; const downloadButton = data.image_url ? ` ` : ''; const resultHTML = `

Your Creation

${imageSection}
Your Story

${data.story}

${downloadButton}
`; resultsSection.innerHTML = resultHTML; resultsSection.scrollIntoView({ behavior: 'smooth' }); } async loadGallery() { try { const response = await fetch('/get_creations'); const data = await response.json(); const galleryGrid = document.getElementById('gallery-grid'); if (data.creations && data.creations.length > 0) { const galleryHTML = data.creations.map(creation => this.createGalleryItem(creation)).join(''); galleryGrid.innerHTML = galleryHTML; } else { galleryGrid.innerHTML = `
No creations yet

Start by describing a scene above!

`; } } catch (error) { console.error('Error loading gallery:', error); } } createGalleryItem(creation) { const journalEntry = creation.journal_entry ? `
Journal Entry:

${creation.journal_entry}

` : ''; const imageSection = creation.image_url ? ` Scene: ${creation.scene_idea}` : ''; const downloadButton = creation.image_url ? ` ` : ''; return ` `; } openJournal(creationId, existingText = '') { this.currentCreationId = creationId; document.getElementById('journal-text').value = existingText; const modal = new bootstrap.Modal(document.getElementById('journalModal')); modal.show(); } async saveJournal() { if (!this.currentCreationId) { this.showAlert('No creation selected', 'danger'); return; } const journalText = document.getElementById('journal-text').value.trim(); try { const response = await fetch('/save_journal', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ creation_id: this.currentCreationId, journal_entry: journalText }) }); const data = await response.json(); if (data.success) { this.showAlert('Journal entry saved!', 'success'); this.loadGallery(); const modal = bootstrap.Modal.getInstance(document.getElementById('journalModal')); modal.hide(); } else { this.showAlert(data.error || 'Failed to save journal', 'danger'); } } catch (error) { console.error('Error saving journal:', error); this.showAlert('Network error. Please try again.', 'danger'); } } downloadImage(imageUrl) { const link = document.createElement('a'); link.href = imageUrl; link.download = `inkboard-creation-${Date.now()}.png`; link.target = '_blank'; document.body.appendChild(link); link.click(); document.body.removeChild(link); this.showAlert('Image download started!', 'success'); } showLoading(show) { const loadingSection = document.getElementById('loading-section'); const resultsSection = document.getElementById('results-section'); if (show) { loadingSection.classList.remove('d-none'); resultsSection.innerHTML = ''; } else { loadingSection.classList.add('d-none'); } } setButtonLoading(loading) { const btn = document.getElementById('generate-btn'); const btnText = btn.querySelector('.btn-text'); const spinner = btn.querySelector('.spinner-border'); if (loading) { btn.classList.add('loading'); btn.disabled = true; btnText.classList.add('d-none'); spinner.classList.remove('d-none'); } else { btn.classList.remove('loading'); btn.disabled = false; btnText.classList.remove('d-none'); spinner.classList.add('d-none'); } } showAlert(message, type) { const existingAlert = document.querySelector('.alert'); if (existingAlert) existingAlert.remove(); const alert = document.createElement('div'); alert.className = `alert alert-${type} alert-dismissible fade show`; alert.innerHTML = `${message} `; const main = document.querySelector('main'); main.insertBefore(alert, main.firstChild); setTimeout(() => { if (alert.parentNode) alert.remove(); }, 5000); } showSection(sectionName) { document.querySelectorAll('.dashboard-section').forEach(section => { section.classList.add('d-none'); }); document.querySelectorAll('.btn-nav').forEach(btn => { btn.classList.remove('active'); }); const targetSection = document.getElementById(`${sectionName}-section`); if (targetSection) targetSection.classList.remove('d-none'); const buttonSelectors = { 'create': 'Create Story', 'gallery': 'Gallery', 'journal': 'Journal' }; document.querySelectorAll('.btn-nav').forEach(btn => { if (btn.textContent.trim().includes(buttonSelectors[sectionName])) { btn.classList.add('active'); } }); this.currentSection = sectionName; if (sectionName === 'gallery') { this.loadGallery(); } else if (sectionName === 'journal') { this.loadJournalEntries(); } } async loadJournalEntries() { try { const response = await fetch('/get_creations'); const data = await response.json(); const journalContainer = document.getElementById('journal-entries'); const entriesWithJournal = data.creations?.filter(creation => creation.journal_entry) || []; if (entriesWithJournal.length > 0) { const journalHTML = entriesWithJournal.map(creation => `
${creation.scene_idea}

${creation.journal_entry}

`).join(''); journalContainer.innerHTML = journalHTML; } else { journalContainer.innerHTML = `
No journal entries yet
`; } } catch (error) { console.error('Error loading journal entries:', error); } } } // Initialize const inkBoard = new InkBoard();