diff --git a/public/app.js b/public/app.js index 530a173..3c34a56 100644 --- a/public/app.js +++ b/public/app.js @@ -7368,16 +7368,25 @@ document.addEventListener('DOMContentLoaded', () => { const panelCartazesHistorico = document.getElementById('panelCartazesHistorico'); const cartazTituloInput = document.getElementById('cartazTituloInput'); - const cartazTemaInput = document.getElementById('cartazTemaInput'); - const cartazLayoutSelect = document.getElementById('cartazLayoutSelect'); + const cartazSubtituloInput = document.getElementById('cartazSubtituloInput'); + const cartazCardsInput = document.getElementById('cartazCardsInput'); + const cartazRodapeInput = document.getElementById('cartazRodapeInput'); + const cartazTemplateSelect = document.getElementById('cartazTemplateSelect'); + const cartazTurmaSelect = document.getElementById('cartazTurmaSelect'); + const btnCartazResetTemplate = document.getElementById('btnCartazResetTemplate'); + const cartazBgColor = document.getElementById('cartazBgColor'); const cartazTextColor = document.getElementById('cartazTextColor'); const cartazFontSelect = document.getElementById('cartazFontSelect'); const cartazBorderSelect = document.getElementById('cartazBorderSelect'); const cartazPromptImagem = document.getElementById('cartazPromptImagem'); + const btnGenerateCartazImage = document.getElementById('btnGenerateCartazImage'); + const btnRemoveCartazImage = document.getElementById('btnRemoveCartazImage'); const btnGenerateCartaz = document.getElementById('btnGenerateCartaz'); const cartazGenerateLoader = document.getElementById('cartazGenerateLoader'); + const btnExportCartazPNG = document.getElementById('btnExportCartazPNG'); + const btnExportCartazPDF = document.getElementById('btnExportCartazPDF'); const btnEditCartazToggle = document.getElementById('btnEditCartazToggle'); const btnPrintCartaz = document.getElementById('btnPrintCartaz'); const cartazEditArea = document.getElementById('cartazEditArea'); @@ -7395,31 +7404,206 @@ document.addEventListener('DOMContentLoaded', () => { let activeCartazData = null; - // Toggle Modal - if (barBtnCartazes) { - barBtnCartazes.addEventListener('click', () => { - cartazesModal.style.display = 'flex'; - switchCartazTab('criar'); - }); - } - - if (btnCloseCartazesModal) { - btnCloseCartazesModal.addEventListener('click', () => { - if (canvasModeActive) { - exitCanvasMode(); - } - cartazesModal.style.display = 'none'; - }); - } - - cartazesModal.addEventListener('click', (e) => { - if (e.target === cartazesModal) { - if (canvasModeActive) { - exitCanvasMode(); - } - cartazesModal.style.display = 'none'; + // DICIONÁRIO DE TEMPLATES PEDAGÓGICOS PRÉ-CONFIGURADOS + const CARTAZ_TEMPLATES = { + combinados: { + titulo: "🌟 Combinados da Nossa Turma", + subtitulo: "Educação Infantil • Convivência e Respeito", + cards: [ + "🤝 Cuidamos dos nossos amigos com carinho", + "🧸 Guardamos os brinquedos nos cantos certos", + "🤫 Falamos baixinho na roda de conversa", + "🧼 Lavamos as mãos antes do lanche", + "👂 Ouvimos a professora e os colegas com atenção" + ], + rodape: "Educando com afeto, empatia e respeito mútuo", + bg: "#fff9eb", + text: "#2d3748", + font: "'Fredoka', sans-serif", + prompt: "Children holding hands happily in a colorful kindergarten classroom, cute 3D Pixar illustration, bright warm colors, no text" + }, + rotina: { + titulo: "🍏 Rotina Diária & Lanche Saudável", + subtitulo: "Desenvolvimento de Autonomia e Hábitos Saudáveis", + cards: [ + "🌅 Roda de Acolhida e Canções do Bom Dia", + "🧼 Higiene e Lavagem Cuidadosa das Mãos", + "🍎 Hora do Lanche: Servir-se sem desperdícios", + "🌳 Vivências no Parque, Areia e Natureza", + "😴 Roda de Histórias, Livros e Relaxamento" + ], + rodape: "Promovendo a autonomia e o autocuidado no cotidiano", + bg: "#f0fdf4", + text: "#166534", + font: "'Fredoka', sans-serif", + prompt: "Cute children having healthy fruit snack at kindergarten table, friendly cartoon vector style, bright colors, no text" + }, + aniversarios: { + titulo: "🎂 Mural dos Aniversariantes", + subtitulo: "Celebrando a vida e o crescimento das nossas crianças!", + cards: [ + "🎈 Que cada dia seja repleto de brincadeiras!", + "🎉 Parabéns aos aniversariantes do mês!", + "🌟 Muita saúde, descobertas e sorrisos!" + ], + rodape: "Com todo carinho da Professora e dos Colegas", + bg: "#fdf2f8", + text: "#9d174d", + font: "'Fredoka', sans-serif", + prompt: "Festive colorful birthday balloons and confetti with smiling animal mascots, cute 3D Pixar illustration, no text" + }, + brinquedos: { + titulo: "🧸 Organização dos Brinquedos e Cantos", + subtitulo: "Nosso espaço escolar é de todos nós!", + cards: [ + "🧩 Blocos de montar: Caixa Azul", + "🚗 Carrinhos e transportes: Caixa Verde", + "📚 Livros de histórias: Estante Baixa", + "🎨 Tintas e massinhas: Armário de Artes" + ], + rodape: "Cuidar dos materiais é um ato de carinho e respeito", + bg: "#eff6ff", + text: "#1e40af", + font: "'Fredoka', sans-serif", + prompt: "Cute organized classroom toy shelf with colorful wooden blocks and teddy bears, cartoon style, no text" + }, + bncc_eu_outro: { + titulo: "🤝 O Eu, o Outro e o Nós", + subtitulo: "Campo de Experiência BNCC • EI02EO / EI03EO", + cards: [ + "🌟 Reconhecer e valorizar suas próprias qualidades", + "💖 Desenvolver empatia e respeito aos sentimentos alheios", + "🗣️ Resolver pequenos conflitos através do diálogo", + "🎨 Compartilhar materiais e respeitar a vez dos amigos" + ], + rodape: "BNCC Educação Infantil • Identidade, Autonomia e Convivência", + bg: "#eff6ff", + text: "#1e40af", + font: "'Outfit', sans-serif", + prompt: "Children of diverse backgrounds smiling together and sharing toys, gentle watercolor illustration, no text" + }, + bncc_corpo: { + titulo: "🏃 Corpo, Gestos e Movimentos", + subtitulo: "Campo de Experiência BNCC • EI02CG / EI03CG", + cards: [ + "🤸 Circuitos motores, equilíbrio, saltos e giros", + "🎶 Cantigas de roda e expressão corporal rítmica", + "🚲 Deslocamentos espaciais e controle corporal", + "⚽ Gincanas cooperativas e respeito a regras" + ], + rodape: "BNCC Educação Infantil • Corporeidade, Saúde e Movimento", + bg: "#fdf2f8", + text: "#9d174d", + font: "'Fredoka', sans-serif", + prompt: "Cute children running, jumping, and playing ring around the rosie outdoors, lively vibrant illustration, no text" + }, + bncc_tracos: { + titulo: "🎨 Traços, Sons, Cores e Formas", + subtitulo: "Campo de Experiência BNCC • EI02TS / EI03TS", + cards: [ + "🖌️ Pinturas com texturas e tintas naturais", + "🥁 Exploração de instrumentos musicais e ritmos", + "🖍️ Desenhos livres de observação e imaginação", + "🎭 Esculturas com massinha, argila e sucatas" + ], + rodape: "BNCC Educação Infantil • Sensibilidade, Expressão e Arte", + bg: "#fff9eb", + text: "#b45309", + font: "'Caveat', cursive", + prompt: "Children happily painting on big canvases with colorful paint splashes, cute art studio, no text" + }, + bncc_escuta: { + titulo: "📖 Escuta, Fala, Pensamento e Imaginação", + subtitulo: "Campo de Experiência BNCC • EI02EF / EI03EF", + cards: [ + "📚 Roda de contação e manuseio de livros infantis", + "🗣️ Expressão oral de ideias, sentimentos e histórias", + "🎵 Cantigas, parlendas, rimas e trava-línguas", + "✍️ Contato lúdico com a função social da escrita" + ], + rodape: "BNCC Educação Infantil • Linguagem e Letramento Inicial", + bg: "#f0fdf4", + text: "#15803d", + font: "'Fredoka', sans-serif", + prompt: "Teacher reading an open fairy tale storybook to cozy circle of children, magical soft glow, Pixar 3D, no text" + }, + bncc_espacos: { + titulo: "🔍 Espaços, Tempos, Quantidades e Relações", + subtitulo: "Campo de Experiência BNCC • EI02ET / EI03ET", + cards: [ + "🌱 Observação do plantio na horta e natureza", + "🔢 Contagem lúdica com elementos concretos", + "📐 Identificação de formas geométricas no ambiente", + "⏳ Noções de tempo: ontem, hoje, amanhã e rotina" + ], + rodape: "BNCC Educação Infantil • Curiosidade e Investigação Científica", + bg: "#eff6ff", + text: "#1e3a8a", + font: "'Outfit', sans-serif", + prompt: "Kids exploring green garden with magnifying glass and planting flowers, vibrant clean illustration, no text" + }, + mindlab_regras: { + titulo: "♟️ Cantinho dos Jogos Mind Lab", + subtitulo: "Metodologia de Jogos & Desenvolvimento Socioemocional", + cards: [ + "🎯 Pensar antes de agir e planejar sua jogada", + "🤝 Saber ganhar e saber perder com elegância", + "⏳ Aguardar a sua vez com calma e autocontrole", + "💡 Aprender com as tentativas e criar novas estratégias" + ], + rodape: "Mind Lab Brasil • Jogos Pedagógicos e Habilidades do Século XXI", + bg: "#f8fafc", + text: "#1e293b", + font: "'Outfit', sans-serif", + prompt: "Children happily playing a wooden tabletop board game together, focus and teamwork, 3D Pixar, no text" + }, + mindlab_cooperacao: { + titulo: "🧩 Desafios de Raciocínio & Cooperação", + subtitulo: "Metodologia Mind Lab • Resolução de Problemas", + cards: [ + "👥 O trabalho em equipe nos leva mais longe", + "🔍 Escuta atenta das ideias dos colegas", + "🚀 Cada desafio é uma oportunidade de aprender" + ], + rodape: "Desenvolvendo liderança, empatia e tomada de decisão", + bg: "#f0fdf4", + text: "#166534", + font: "'Fredoka', sans-serif", + prompt: "Children putting together giant colorful puzzle pieces together, cooperation, joyful 3D illustration, no text" + }, + aviso_pais: { + titulo: "📌 Recado Importante para as Famílias", + subtitulo: "Comunicação Escola & Comunidade Escolar", + cards: [ + "📅 Próxima Reunião Pedagógica: Sexta-feira às 17h", + "🎒 Trazer uma muda de roupa extra identificada", + "👟 Uso de calçado confortável para o dia de parque", + "💧 Manter a garrafinha de água individual na mochila" + ], + rodape: "A parceria entre escola e família é fundamental para o sucesso das crianças!", + bg: "#fff9eb", + text: "#1e293b", + font: "'Outfit', sans-serif", + prompt: "Friendly cartoon school bulletin board with colorful notes and cheerful mascot, clean vector, no text" + }, + mostra_cultural: { + titulo: "🎉 Convite: Mostra Pedagógica & Cultural", + subtitulo: "Venha prestigiar as produções e vivências dos nossos pequenos!", + cards: [ + "🎨 Exposição dos Painéis de Arte e Garatujas", + "📸 Linha do Tempo das Descobertas do Semestre", + "🎶 Apresentação Musical e Parlendas da Turma", + "🌿 Visitação guiada à Horta e Projetos Coletivos" + ], + rodape: "Contamos com a presença de todas as famílias!", + bg: "#fdf2f8", + text: "#831843", + font: "'Playfair Display', serif", + prompt: "Joyful school festival decoration with colorful bunting banners and children artworks, vibrant light, no text" } - }); + }; + + // Switch Tab function switchCartazTab(tab) { @@ -7428,7 +7612,6 @@ document.addEventListener('DOMContentLoaded', () => { tabCartazesHistorico.classList.remove('active'); panelCartazesCriar.style.display = 'flex'; panelCartazesHistorico.style.display = 'none'; - tabCartazesCriar.style.color = 'var(--text-primary)'; tabCartazesHistorico.style.color = 'var(--text-secondary)'; } else { @@ -7436,7 +7619,6 @@ document.addEventListener('DOMContentLoaded', () => { tabCartazesHistorico.classList.add('active'); panelCartazesCriar.style.display = 'none'; panelCartazesHistorico.style.display = 'flex'; - tabCartazesCriar.style.color = 'var(--text-secondary)'; tabCartazesHistorico.style.color = 'var(--text-primary)'; loadCartazesHistory(); @@ -7446,6 +7628,39 @@ document.addEventListener('DOMContentLoaded', () => { if (tabCartazesCriar) tabCartazesCriar.addEventListener('click', () => switchCartazTab('criar')); if (tabCartazesHistorico) tabCartazesHistorico.addEventListener('click', () => switchCartazTab('historico')); + // RENDERIZAR CONTEÚDO DO CARTAZ EM TEMPO REAL + function renderCartazContentFromInputs() { + const rawCards = (cartazCardsInput?.value || '').split('\n').map(l => l.trim()).filter(l => l.length > 0); + const subtitulo = (cartazSubtituloInput?.value || '').trim(); + const rodape = (cartazRodapeInput?.value || '').trim(); + + let html = ''; + if (subtitulo) { + html += `
${subtitulo}
`; + } + + if (rawCards.length > 0) { + html += `
`; + rawCards.forEach((line) => { + html += ` +
+ ${line} +
+ `; + }); + html += `
`; + } else { + html += `

Digite os destaques ou escolha um modelo ao lado.

`; + } + + if (rodape) { + html += `
${rodape}
`; + } + + cartazPreviewContent.innerHTML = html; + if (cartazHtmlEditor) cartazHtmlEditor.value = html; + } + // Live Style Updates function updateLivePreview() { const bg = cartazBgColor.value; @@ -7459,60 +7674,11 @@ document.addEventListener('DOMContentLoaded', () => { cartazPrintableArea.style.color = text; cartazPrintableArea.style.fontFamily = font; - const tamanho = document.getElementById('cartazTamanhoSelect') ? document.getElementById('cartazTamanhoSelect').value : 'A4'; - - const FORMAT_SIZES = { - 'A4': { retrato: 380, paisagem: 537 }, - 'A3': { retrato: 480, paisagem: 679 }, - 'A2': { retrato: 580, paisagem: 820 }, - 'A1': { retrato: 680, paisagem: 962 } - }; - - const maxW = FORMAT_SIZES[tamanho]?.[orientacao] || FORMAT_SIZES['A4']['retrato']; - cartazPrintableArea.style.width = '100%'; - cartazPrintableArea.style.maxWidth = `${maxW}px`; + cartazPrintableArea.style.maxWidth = orientacao === 'paisagem' ? '680px' : '480px'; cartazPrintableArea.style.aspectRatio = orientacao === 'paisagem' ? '1.414 / 1' : '1 / 1.414'; cartazPrintableArea.style.height = 'auto'; - if (orientacao === 'paisagem') { - cartazPreviewContent.style.flexDirection = 'row'; - cartazPreviewContent.style.flexWrap = 'wrap'; - cartazPreviewContent.style.justifyContent = 'center'; - cartazPreviewContent.style.alignContent = 'flex-start'; - cartazPreviewContent.style.gap = '12px'; - - setTimeout(() => { - Array.from(cartazPreviewContent.children).forEach(child => { - child.style.flex = '1 1 calc(50% - 12px)'; - child.style.boxSizing = 'border-box'; - child.style.margin = '0'; - child.style.background = 'rgba(255,255,255,0.25)'; - child.style.padding = '12px'; - child.style.borderRadius = '8px'; - child.style.border = '1px solid rgba(0,0,0,0.05)'; - }); - }, 0); - } else { - cartazPreviewContent.style.flexDirection = 'column'; - cartazPreviewContent.style.flexWrap = 'nowrap'; - cartazPreviewContent.style.justifyContent = 'flex-start'; - cartazPreviewContent.style.gap = '12px'; - - setTimeout(() => { - Array.from(cartazPreviewContent.children).forEach(child => { - child.style.flex = '0 0 auto'; - child.style.width = '100%'; - child.style.boxSizing = 'border-box'; - child.style.margin = '0'; - child.style.background = 'rgba(255,255,255,0.25)'; - child.style.padding = '12px'; - child.style.borderRadius = '8px'; - child.style.border = '1px solid rgba(0,0,0,0.05)'; - }); - }, 0); - } - cartazPreviewTitle.textContent = title; cartazPreviewTitle.style.borderColor = text; @@ -7523,14 +7689,27 @@ document.addEventListener('DOMContentLoaded', () => { } } + // Event Listeners para inputs em tempo real + [ + cartazTituloInput, + cartazSubtituloInput, + cartazCardsInput, + cartazRodapeInput + ].forEach(elem => { + if (elem) { + elem.addEventListener('input', () => { + renderCartazContentFromInputs(); + updateLivePreview(); + }); + } + }); + [ cartazBgColor, cartazTextColor, cartazFontSelect, cartazBorderSelect, - cartazTituloInput, - document.getElementById('cartazOrientacaoSelect'), - document.getElementById('cartazTamanhoSelect') + document.getElementById('cartazOrientacaoSelect') ].forEach(elem => { if (elem) elem.addEventListener('input', updateLivePreview); if (elem && elem.tagName === 'SELECT') elem.addEventListener('change', updateLivePreview); @@ -7539,67 +7718,96 @@ document.addEventListener('DOMContentLoaded', () => { // Preset Palettes document.querySelectorAll('.btn-palette-preset').forEach(btn => { btn.addEventListener('click', (e) => { - const bg = e.target.dataset.bg; - const text = e.target.dataset.text; + const bg = btn.dataset.bg; + const text = btn.dataset.text; cartazBgColor.value = bg; cartazTextColor.value = text; updateLivePreview(); }); }); - // Toggle HTML Editor - if (btnEditCartazToggle) { - btnEditCartazToggle.addEventListener('click', () => { - if (cartazEditArea.style.display === 'none') { - cartazEditArea.style.display = 'flex'; - btnEditCartazToggle.textContent = '👁️ Ocultar Editor'; - } else { - cartazEditArea.style.display = 'none'; - btnEditCartazToggle.textContent = '✏️ Editar Conteúdo'; + // Gerar Ilustração com IA (MiniMax T2I) + if (btnGenerateCartazImage) { + btnGenerateCartazImage.addEventListener('click', async () => { + const prompt = (cartazPromptImagem?.value || '').trim(); + if (!prompt) { + await showCustomAlert('Aviso', 'Digite uma descrição para a ilustração no campo acima.'); + return; + } + + try { + btnGenerateCartazImage.disabled = true; + btnGenerateCartazImage.textContent = '⏳ Gerando com IA...'; + + const fullPrompt = `${prompt}, high resolution children book illustration, cute Pixar 3D, colorful, no text, clean vector`; + + const resp = await fetch('/api/comics/generate-frame', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ prompt: fullPrompt }) + }); + + if (!resp.ok) { + const err = await resp.json(); + throw new Error(err.error || 'Falha ao gerar ilustração'); + } + + const data = await resp.json(); + if (data.imageUrl) { + cartazPreviewImage.src = data.imageUrl; + cartazPreviewImageContainer.style.display = 'block'; + updateLivePreview(); + await showCustomAlert('Ilustração Pronta!', 'A imagem foi gerada e adicionada ao cartaz com sucesso.'); + } + } catch (err) { + console.error('Erro ao gerar ilustração do cartaz:', err); + await showCustomAlert('Erro', 'Não foi possível gerar a ilustração: ' + err.message); + } finally { + btnGenerateCartazImage.disabled = false; + btnGenerateCartazImage.innerHTML = '🪄 Gerar Ilustração com IA'; } }); } - // Update from Editor - if (btnUpdateCartazPreview) { - btnUpdateCartazPreview.addEventListener('click', () => { - cartazPreviewContent.innerHTML = cartazHtmlEditor.value; + if (btnRemoveCartazImage) { + btnRemoveCartazImage.addEventListener('click', () => { + cartazPreviewImage.src = ''; + cartazPreviewImageContainer.style.display = 'none'; + if (cartazPromptImagem) cartazPromptImagem.value = ''; + updateLivePreview(); }); } - // Generate Poster + // --- GERAR CONTEÚDO COM PEDAGOGIA (IA) --- if (btnGenerateCartaz) { btnGenerateCartaz.addEventListener('click', async () => { - const titulo = cartazTituloInput.value.trim(); - const tema = cartazTemaInput.value.trim(); - const layout = cartazLayoutSelect.value; - const promptImagem = cartazPromptImagem.value.trim(); - const tamanho = document.getElementById('cartazTamanhoSelect') ? document.getElementById('cartazTamanhoSelect').value : 'A4'; - const orientacao = document.getElementById('cartazOrientacaoSelect') ? document.getElementById('cartazOrientacaoSelect').value : 'retrato'; + const titulo = (cartazTituloInput?.value || '').trim(); + const subtitulo = (cartazSubtituloInput?.value || '').trim(); + const promptImagem = (cartazPromptImagem?.value || '').trim(); + const orientacao = document.getElementById('cartazOrientacaoSelect')?.value || 'retrato'; - if (!titulo || !tema) { - showToast('Por favor, defina o Título e o Tema do Cartaz.', 'error'); + if (!titulo) { + await showCustomAlert('Aviso', 'Por favor, informe ao menos o Título Principal do Cartaz.'); return; } btnGenerateCartaz.disabled = true; - cartazGenerateLoader.style.display = 'flex'; + if (cartazGenerateLoader) cartazGenerateLoader.style.display = 'flex'; try { const res = await fetch('/api/cartazes/generate', { method: 'POST', headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${localStorage.getItem('token')}` + 'Content-Type': 'application/json' }, body: JSON.stringify({ titulo, - tema, - corFundo: cartazBgColor.value, - corTexto: cartazTextColor.value, - layout, + tema: subtitulo || titulo, + corFundo: cartazBgColor?.value || '#fff9eb', + corTexto: cartazTextColor?.value || '#2d3748', + layout: 'educativo', promptImagem, - tamanho, + tamanho: 'A4', orientacao }) }); @@ -7608,28 +7816,111 @@ document.addEventListener('DOMContentLoaded', () => { if (res.ok) { activeCartazData = data; - // Preencher Preview - cartazPreviewContent.innerHTML = data.conteudo; - cartazHtmlEditor.value = data.conteudo; - + if (data.conteudo) { + // Extrair texto limpo de tópicos/cards para o input editável + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = data.conteudo; + const items = Array.from(tempDiv.querySelectorAll('li, p, div')).map(el => el.textContent.trim()).filter(t => t.length > 5 && !t.toLowerCase().includes(titulo.toLowerCase())); + + if (items.length > 0) { + cartazCardsInput.value = items.slice(0, 6).join('\n'); + } else { + cartazCardsInput.value = tempDiv.textContent.trim(); + } + } + if (data.imagemUrl) { cartazPreviewImage.src = data.imagemUrl; cartazPreviewImageContainer.style.display = 'block'; - } else { - cartazPreviewImageContainer.style.display = 'none'; } + renderCartazContentFromInputs(); updateLivePreview(); - showToast('Cartaz criado e salvo com sucesso!', 'success'); + showToast('Cartaz diagramado pela PedagogIA com sucesso!', 'success'); } else { - showToast(data.error || 'Erro ao gerar cartaz.', 'error'); + await showCustomAlert('Erro', data.error || 'Erro ao gerar cartaz com IA.'); } } catch (err) { - console.error(err); - showToast('Erro ao se conectar com o servidor.', 'error'); + console.error('Erro ao gerar cartaz:', err); + await showCustomAlert('Erro', 'Não foi possível conectar ao assistente: ' + err.message); } finally { btnGenerateCartaz.disabled = false; - cartazGenerateLoader.style.display = 'none'; + if (cartazGenerateLoader) cartazGenerateLoader.style.display = 'none'; + } + }); + } + + // --- EXPORTAR PNG EM ALTA RESOLUÇÃO --- + if (btnExportCartazPNG) { + btnExportCartazPNG.addEventListener('click', async () => { + try { + btnExportCartazPNG.disabled = true; + btnExportCartazPNG.textContent = '⏳ Gerando PNG...'; + + if (typeof html2canvas === 'undefined') { + throw new Error('Biblioteca html2canvas não disponível.'); + } + + const canvas = await html2canvas(cartazPrintableArea, { + scale: 3, // Alta resolução 300 DPI equivalente + useCORS: true, + logging: false, + backgroundColor: cartazBgColor.value || '#fff9eb' + }); + + const title = (cartazTituloInput.value || 'cartaz_pedagog').replace(/[^a-zA-Z0-9_-]/g, '_').toLowerCase(); + const link = document.createElement('a'); + link.download = `${title}.png`; + link.href = canvas.toDataURL('image/png'); + document.body.appendChild(link); + link.click(); + link.remove(); + + } catch (err) { + console.error('Erro ao exportar PNG:', err); + await showCustomAlert('Erro', 'Não foi possível gerar o PNG: ' + err.message); + } finally { + btnExportCartazPNG.disabled = false; + btnExportCartazPNG.textContent = '🖼️ Baixar PNG'; + } + }); + } + + // --- EXPORTAR PDF IMPRIMÍVEL --- + if (btnExportCartazPDF) { + btnExportCartazPDF.addEventListener('click', async () => { + try { + btnExportCartazPDF.disabled = true; + btnExportCartazPDF.textContent = '⏳ Criando PDF...'; + + if (typeof html2canvas === 'undefined' || typeof window.jspdf === 'undefined') { + throw new Error('Bibliotecas de PDF necessárias não disponíveis.'); + } + + const orientacao = document.getElementById('cartazOrientacaoSelect')?.value === 'paisagem' ? 'l' : 'p'; + const canvas = await html2canvas(cartazPrintableArea, { + scale: 3, + useCORS: true, + logging: false, + backgroundColor: cartazBgColor.value || '#fff9eb' + }); + + const imgData = canvas.toDataURL('image/jpeg', 0.95); + const { jsPDF } = window.jspdf; + const pdf = new jsPDF(orientacao, 'pt', 'a4'); + const pdfWidth = orientacao === 'l' ? 842 : 595; + const pdfHeight = orientacao === 'l' ? 595 : 842; + + pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight); + const title = (cartazTituloInput.value || 'cartaz_pedagog').replace(/[^a-zA-Z0-9_-]/g, '_').toLowerCase(); + pdf.save(`${title}.pdf`); + + } catch (err) { + console.error('Erro ao exportar PDF:', err); + await showCustomAlert('Erro', 'Não foi possível gerar o PDF: ' + err.message); + } finally { + btnExportCartazPDF.disabled = false; + btnExportCartazPDF.textContent = '📄 Baixar PDF'; } }); } diff --git a/public/index.html b/public/index.html index 6549da5..db14b4b 100644 --- a/public/index.html +++ b/public/index.html @@ -1797,107 +1797,141 @@
-
+
- -
-

1. Definições do Cartaz

+ +
-
- - +
+

📋 1. Modelo & Conteúdo

+
- + +
- - -
- -
- - + + + + + + + + + + + + + + + + + + + + + +
-
+ +
- - +
-

2. Estilo e Cores

- -
-
- - -
-
- - -
+ +
+ +
- -
- - - - -
+ +
-
-
- +
+ + +
+ +
+ + +
+ + +

🎨 2. Estilo e Cores

+ +
+
+
-
- +
+
+
- - + +
+ + + + + +
- + +
+
+ + + - @@ -1963,12 +1997,14 @@
-
-

👁️ Visualização do Cartaz

-
- - - +
+

👁️ Visualização em Tempo Real

+
+ + + + +
@@ -2090,7 +2126,8 @@
- + +