Feature: Estudio de Cartazes profissional com templates BNCC/Educacao Infantil/MindLab, integracao de turma, live editor e exportacao PDF/PNG

This commit is contained in:
2026-08-31 11:12:57 +00:00
parent 36f72f56dc
commit 1ef002ff1a
2 changed files with 521 additions and 193 deletions
+415 -124
View File
@@ -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 += `<div style="text-align: center; font-size: 1.15rem; font-weight: 600; opacity: 0.9; margin-bottom: 12px; letter-spacing: 0.3px;">${subtitulo}</div>`;
}
if (rawCards.length > 0) {
html += `<div style="display: flex; flex-direction: column; gap: 10px; width: 100%;">`;
rawCards.forEach((line) => {
html += `
<div style="background: rgba(255, 255, 255, 0.4); backdrop-filter: blur(4px); border: 2px solid rgba(0, 0, 0, 0.08); border-radius: 12px; padding: 12px 16px; font-size: 1.05rem; font-weight: 600; display: flex; align-items: center; gap: 10px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);">
<span>${line}</span>
</div>
`;
});
html += `</div>`;
} else {
html += `<p style="text-align: center; color: rgba(0,0,0,0.4); font-style: italic; padding: 20px 0;">Digite os destaques ou escolha um modelo ao lado.</p>`;
}
if (rodape) {
html += `<div style="margin-top: auto; padding-top: 14px; text-align: center; font-size: 0.85rem; font-weight: 600; opacity: 0.75; border-top: 1px dashed rgba(0,0,0,0.15);">${rodape}</div>`;
}
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 = '<span>🪄 Gerar Ilustração com IA</span>';
}
});
}
// 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';
}
});
}