From 1e9d80b69c80ee061d1d0eb6688db6a1ae61b566 Mon Sep 17 00:00:00 2001 From: admtracksteel Date: Thu, 3 Sep 2026 10:41:49 +0000 Subject: [PATCH] Modernizacao completa do Estudio de Cartazes Pedagogicos: correcao de abertura, BNCC, upload de fotos, novo motor de IA, edicao direta e suite de exportacao --- public/app.js | 753 +++++++++++++++++++++++++++++++++------------- public/index.html | 326 ++++++++++++++------ public/style.css | 40 +-- server.js | 287 +++++++++++++----- update.sh | 4 + 5 files changed, 1016 insertions(+), 394 deletions(-) diff --git a/public/app.js b/public/app.js index 4828c4c..d82775d 100644 --- a/public/app.js +++ b/public/app.js @@ -2398,6 +2398,7 @@ const initApp = () => { if (btn.id === 'barBtnMusica') return; if (btn.id === 'barBtnHistoria') return; if (btn.id === 'barBtnMindLab') return; + if (btn.id === 'barBtnCartazes') return; // Manipulado separadamente pelo Estúdio de Cartazes const mode = btn.dataset.mode; const text = userInput.value.trim(); @@ -8849,7 +8850,7 @@ document.addEventListener('DOMContentLoaded', () => { } // ============================================================ - // CRIAR CARTAZES + // ESTÚDIO DE CARTAZES PEDAGÓGICOS (PedaGog) // ============================================================ const barBtnCartazes = document.getElementById('barBtnCartazes'); const cartazesModal = document.getElementById('cartazesModal'); @@ -8862,31 +8863,42 @@ document.addEventListener('DOMContentLoaded', () => { const cartazTituloInput = document.getElementById('cartazTituloInput'); const cartazSubtituloInput = document.getElementById('cartazSubtituloInput'); + const cartazBadgeInput = document.getElementById('cartazBadgeInput'); const cartazCardsInput = document.getElementById('cartazCardsInput'); const cartazRodapeInput = document.getElementById('cartazRodapeInput'); const cartazTemplateSelect = document.getElementById('cartazTemplateSelect'); const cartazTurmaSelect = document.getElementById('cartazTurmaSelect'); + const cartazOrientacaoSelect = document.getElementById('cartazOrientacaoSelect'); + const cartazFaixaEtaria = document.getElementById('cartazFaixaEtaria'); + const cartazCampoBncc = document.getElementById('cartazCampoBncc'); const btnCartazResetTemplate = document.getElementById('btnCartazResetTemplate'); + const btnCartazAddLine = document.getElementById('btnCartazAddLine'); const cartazBgColor = document.getElementById('cartazBgColor'); const cartazTextColor = document.getElementById('cartazTextColor'); const cartazFontSelect = document.getElementById('cartazFontSelect'); const cartazBorderSelect = document.getElementById('cartazBorderSelect'); + const cartazCardStyleSelect = document.getElementById('cartazCardStyleSelect'); + const cartazPromptImagem = document.getElementById('cartazPromptImagem'); const btnGenerateCartazImage = document.getElementById('btnGenerateCartazImage'); + const cartazImageUploadInput = document.getElementById('cartazImageUploadInput'); const btnRemoveCartazImage = document.getElementById('btnRemoveCartazImage'); const btnGenerateCartaz = document.getElementById('btnGenerateCartaz'); const cartazGenerateLoader = document.getElementById('cartazGenerateLoader'); + const cartazLoaderText = document.getElementById('cartazLoaderText'); + const btnCopyCartazClipboard = document.getElementById('btnCopyCartazClipboard'); const btnExportCartazPNG = document.getElementById('btnExportCartazPNG'); const btnExportCartazPDF = document.getElementById('btnExportCartazPDF'); - const btnEditCartazToggle = document.getElementById('btnEditCartazToggle'); const btnPrintCartaz = document.getElementById('btnPrintCartaz'); + const btnEditCartazToggle = document.getElementById('btnEditCartazToggle'); const cartazEditArea = document.getElementById('cartazEditArea'); const cartazHtmlEditor = document.getElementById('cartazHtmlEditor'); const btnUpdateCartazPreview = document.getElementById('btnUpdateCartazPreview'); const cartazPrintableArea = document.getElementById('cartazPrintableArea'); + const cartazPreviewBadge = document.getElementById('cartazPreviewBadge'); const cartazPreviewTitle = document.getElementById('cartazPreviewTitle'); const cartazPreviewContent = document.getElementById('cartazPreviewContent'); const cartazPreviewImageContainer = document.getElementById('cartazPreviewImageContainer'); @@ -8902,6 +8914,7 @@ document.addEventListener('DOMContentLoaded', () => { combinados: { titulo: "🌟 Combinados da Nossa Turma", subtitulo: "Educação Infantil • Convivência e Respeito", + badge: "🤝 CONVIVÊNCIA & AFETO", cards: [ "🤝 Cuidamos dos nossos amigos com carinho", "🧸 Guardamos os brinquedos nos cantos certos", @@ -8918,6 +8931,7 @@ document.addEventListener('DOMContentLoaded', () => { rotina: { titulo: "🍏 Rotina Diária & Lanche Saudável", subtitulo: "Desenvolvimento de Autonomia e Hábitos Saudáveis", + badge: "🍎 ROTINA & AUTONOMIA", cards: [ "🌅 Roda de Acolhida e Canções do Bom Dia", "🧼 Higiene e Lavagem Cuidadosa das Mãos", @@ -8925,7 +8939,7 @@ document.addEventListener('DOMContentLoaded', () => { "🌳 Vivências no Parque, Areia e Natureza", "😴 Roda de Histórias, Livros e Relaxamento" ], - rodape: "Promovendo a autonomia e o autocuidado no cotidiano", + rodape: "Promovendo a autonomia e o autocuidado no cotidiano escolar", bg: "#f0fdf4", text: "#166534", font: "'Fredoka', sans-serif", @@ -8934,27 +8948,29 @@ document.addEventListener('DOMContentLoaded', () => { aniversarios: { titulo: "🎂 Mural dos Aniversariantes", subtitulo: "Celebrando a vida e o crescimento das nossas crianças!", + badge: "🎉 CELEBRAÇÃO DA TURMA", cards: [ - "🎈 Que cada dia seja repleto de brincadeiras!", - "🎉 Parabéns aos aniversariantes do mês!", - "🌟 Muita saúde, descobertas e sorrisos!" + "🎈 Que cada dia seja repleto de brincadeiras e sorrisos!", + "🎉 Parabéns aos nossos aniversariantes do mês!", + "🌟 Muita saúde, descobertas e novas amizades!" ], - rodape: "Com todo carinho da Professora e dos Colegas", + rodape: "Com todo o 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!", + titulo: "🧸 Organização dos Brinquedos e Cantinhos", + subtitulo: "Nosso espaço escolar é acolhedor e de todos nós!", + badge: "🧩 ESPAÇO COLETIVO", cards: [ - "🧩 Blocos de montar: Caixa Azul", + "🧩 Blocos de montar: Guardar na Caixa Azul", "🚗 Carrinhos e transportes: Caixa Verde", - "📚 Livros de histórias: Estante Baixa", + "📚 Livros de histórias: Estante Baixa com capa visível", "🎨 Tintas e massinhas: Armário de Artes" ], - rodape: "Cuidar dos materiais é um ato de carinho e respeito", + rodape: "Cuidar dos nossos materiais é um ato de carinho e respeito", bg: "#eff6ff", text: "#1e40af", font: "'Fredoka', sans-serif", @@ -8963,11 +8979,12 @@ document.addEventListener('DOMContentLoaded', () => { bncc_eu_outro: { titulo: "🤝 O Eu, o Outro e o Nós", subtitulo: "Campo de Experiência BNCC • EI02EO / EI03EO", + badge: "📚 BNCC • IDENTIDADE E EMPATIA", cards: [ - "🌟 Reconhecer e valorizar suas próprias qualidades", + "🌟 Reconhecer e valorizar suas próprias qualidades e sentimentos", "💖 Desenvolver empatia e respeito aos sentimentos alheios", "🗣️ Resolver pequenos conflitos através do diálogo", - "🎨 Compartilhar materiais e respeitar a vez dos amigos" + "🎨 Compartilhar materiais e respeitar a vez dos colegas" ], rodape: "BNCC Educação Infantil • Identidade, Autonomia e Convivência", bg: "#eff6ff", @@ -8978,11 +8995,12 @@ document.addEventListener('DOMContentLoaded', () => { bncc_corpo: { titulo: "🏃 Corpo, Gestos e Movimentos", subtitulo: "Campo de Experiência BNCC • EI02CG / EI03CG", + badge: "🤸 BNCC • CORPOREIDADE", cards: [ - "🤸 Circuitos motores, equilíbrio, saltos e giros", + "🤸 Circuitos motores: equilíbrio, saltos, corridas e giros", "🎶 Cantigas de roda e expressão corporal rítmica", - "🚲 Deslocamentos espaciais e controle corporal", - "⚽ Gincanas cooperativas e respeito a regras" + "🚲 Deslocamentos espaciais e consciência do próprio corpo", + "⚽ Gincanas cooperativas e respeito às regras dos jogos" ], rodape: "BNCC Educação Infantil • Corporeidade, Saúde e Movimento", bg: "#fdf2f8", @@ -8993,11 +9011,12 @@ document.addEventListener('DOMContentLoaded', () => { bncc_tracos: { titulo: "🎨 Traços, Sons, Cores e Formas", subtitulo: "Campo de Experiência BNCC • EI02TS / EI03TS", + badge: "🎨 BNCC • ARTE & SENSIBILIDADE", cards: [ - "🖌️ Pinturas com texturas e tintas naturais", - "🥁 Exploração de instrumentos musicais e ritmos", + "🖌️ Pinturas com texturas, pincéis e tintas naturais", + "🥁 Exploração de instrumentos musicais e ritmos sonoros", "🖍️ Desenhos livres de observação e imaginação", - "🎭 Esculturas com massinha, argila e sucatas" + "🎭 Modelagens com massinha caseira, argila e sucatas" ], rodape: "BNCC Educação Infantil • Sensibilidade, Expressão e Arte", bg: "#fff9eb", @@ -9008,11 +9027,12 @@ document.addEventListener('DOMContentLoaded', () => { bncc_escuta: { titulo: "📖 Escuta, Fala, Pensamento e Imaginação", subtitulo: "Campo de Experiência BNCC • EI02EF / EI03EF", + badge: "📚 BNCC • LINGUAGEM & LIVROS", 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" + "📚 Roda diária de contação e manuseio de livros infantis", + "🗣️ Expressão oral de ideias, sentimentos, desejos e histórias", + "🎵 Cantigas, parlendas rimadas e trava-línguas da cultura popular", + "✍️ Contato lúdico com a função social da escrita e do letramento" ], rodape: "BNCC Educação Infantil • Linguagem e Letramento Inicial", bg: "#f0fdf4", @@ -9023,11 +9043,12 @@ document.addEventListener('DOMContentLoaded', () => { bncc_espacos: { titulo: "🔍 Espaços, Tempos, Quantidades e Relações", subtitulo: "Campo de Experiência BNCC • EI02ET / EI03ET", + badge: "🌱 BNCC • CIÊNCIA & INVESTIGAÇÃO", 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" + "🌱 Observação e cuidado com o plantio na horta escolar", + "🔢 Contagem lúdica e comparação com elementos concretos", + "📐 Identificação de formas geométricas nos espaços da sala", + "⏳ Noções de tempo: ontem, hoje, amanhã e estações do ano" ], rodape: "BNCC Educação Infantil • Curiosidade e Investigação Científica", bg: "#eff6ff", @@ -9038,13 +9059,14 @@ document.addEventListener('DOMContentLoaded', () => { mindlab_regras: { titulo: "♟️ Cantinho dos Jogos Mind Lab", subtitulo: "Metodologia de Jogos & Desenvolvimento Socioemocional", + badge: "♟️ MIND LAB • PENSAMENTO ESTRATÉGICO", 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" + "🎯 Pensar antes de agir: planejar a sua jogada com calma", + "🤝 Saber ganhar e saber perder com alegria e respeito", + "⏳ Aguardar a sua vez com autocontrole e atenção", + "💡 Aprender com as tentativas e formular novas estratégias" ], - rodape: "Mind Lab Brasil • Jogos Pedagógicos e Habilidades do Século XXI", + rodape: "Mind Lab Brasil • Jogos Pedagógicos e Habilidades Socioemocionais", bg: "#f8fafc", text: "#1e293b", font: "'Outfit', sans-serif", @@ -9052,13 +9074,14 @@ document.addEventListener('DOMContentLoaded', () => { }, mindlab_cooperacao: { titulo: "🧩 Desafios de Raciocínio & Cooperação", - subtitulo: "Metodologia Mind Lab • Resolução de Problemas", + subtitulo: "Metodologia Mind Lab • Resolução Ativa de Problemas", + badge: "🧩 TRABALHO EM EQUIPE", cards: [ - "👥 O trabalho em equipe nos leva mais longe", - "🔍 Escuta atenta das ideias dos colegas", - "🚀 Cada desafio é uma oportunidade de aprender" + "👥 O trabalho em equipe nos leva sempre mais longe", + "🔍 Escuta atenta e valorização das ideias dos colegas", + "🚀 Cada desafio é uma grande oportunidade de aprender e evoluir" ], - rodape: "Desenvolvendo liderança, empatia e tomada de decisão", + rodape: "Desenvolvendo liderança, empatia e cooperação mútua", bg: "#f0fdf4", text: "#166534", font: "'Fredoka', sans-serif", @@ -9067,13 +9090,14 @@ document.addEventListener('DOMContentLoaded', () => { aviso_pais: { titulo: "📌 Recado Importante para as Famílias", subtitulo: "Comunicação Escola & Comunidade Escolar", + badge: "📢 COMUNICADO OFICIAL", 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", + "🎒 Trazer uma muda de roupa extra identificada com o nome", + "👟 Uso de calçado fechado e confortável para o parque", "💧 Manter a garrafinha de água individual na mochila" ], - rodape: "A parceria entre escola e família é fundamental para o sucesso das crianças!", + rodape: "A parceria entre escola e família é fundamental para nossas crianças!", bg: "#fff9eb", text: "#1e293b", font: "'Outfit', sans-serif", @@ -9082,13 +9106,14 @@ document.addEventListener('DOMContentLoaded', () => { mostra_cultural: { titulo: "🎉 Convite: Mostra Pedagógica & Cultural", subtitulo: "Venha prestigiar as produções e vivências dos nossos pequenos!", + badge: "🎨 CONVITE ESPECIAL", 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" + "🎨 Exposição dos Painéis de Arte e Garatujas das Crianças", + "📸 Linha do Tempo das Descobertas e Brincadeiras do Semestre", + "🎶 Apresentação Musical e Parlendas da Nossa Turma", + "🌿 Visitação guiada aos canteiros e projetos coletivos" ], - rodape: "Contamos com a presença de todas as famílias!", + rodape: "Contamos com a presença e o carinho de todas as famílias!", bg: "#fdf2f8", text: "#831843", font: "'Playfair Display', serif", @@ -9096,24 +9121,68 @@ document.addEventListener('DOMContentLoaded', () => { } }; + // --- CONTROLE DE ABERTURA E FECHAMENTO DO MODAL --- + if (barBtnCartazes) { + barBtnCartazes.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + if (cartazesModal) { + cartazesModal.style.display = 'flex'; + loadTurmasForCartazes(); + if (!cartazTituloInput.value.trim()) { + applyCartazTemplate('combinados'); + } else { + updateLivePreview(); + } + } + }); + } + if (btnCloseCartazesModal) { + btnCloseCartazesModal.addEventListener('click', () => { + if (cartazesModal) cartazesModal.style.display = 'none'; + }); + } - // Switch Tab + // Fechar ao clicar no backdrop ou pressionar Escape + if (cartazesModal) { + cartazesModal.addEventListener('click', (e) => { + if (e.target === cartazesModal) { + cartazesModal.style.display = 'none'; + } + }); + } + + window.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && cartazesModal && cartazesModal.style.display === 'flex') { + cartazesModal.style.display = 'none'; + } + }); + + // Switch de Abas: Criar vs Histórico function switchCartazTab(tab) { if (tab === 'criar') { tabCartazesCriar.classList.add('active'); tabCartazesHistorico.classList.remove('active'); panelCartazesCriar.style.display = 'flex'; panelCartazesHistorico.style.display = 'none'; - tabCartazesCriar.style.color = 'var(--text-primary)'; + tabCartazesCriar.style.background = 'rgba(16, 185, 129, 0.1)'; + tabCartazesCriar.style.borderColor = 'rgba(16, 185, 129, 0.3)'; + tabCartazesCriar.style.color = '#10b981'; + tabCartazesHistorico.style.background = 'transparent'; + tabCartazesHistorico.style.borderColor = 'transparent'; tabCartazesHistorico.style.color = 'var(--text-secondary)'; } else { tabCartazesCriar.classList.remove('active'); tabCartazesHistorico.classList.add('active'); panelCartazesCriar.style.display = 'none'; panelCartazesHistorico.style.display = 'flex'; + tabCartazesCriar.style.background = 'transparent'; + tabCartazesCriar.style.borderColor = 'transparent'; tabCartazesCriar.style.color = 'var(--text-secondary)'; - tabCartazesHistorico.style.color = 'var(--text-primary)'; + tabCartazesHistorico.style.background = 'rgba(16, 185, 129, 0.1)'; + tabCartazesHistorico.style.borderColor = 'rgba(16, 185, 129, 0.3)'; + tabCartazesHistorico.style.color = '#10b981'; loadCartazesHistory(); } } @@ -9121,60 +9190,265 @@ document.addEventListener('DOMContentLoaded', () => { if (tabCartazesCriar) tabCartazesCriar.addEventListener('click', () => switchCartazTab('criar')); if (tabCartazesHistorico) tabCartazesHistorico.addEventListener('click', () => switchCartazTab('historico')); + // Carregar turmas reais do sistema + async function loadTurmasForCartazes() { + if (!cartazTurmaSelect) return; + try { + const res = await fetch('/api/turmas'); + if (!res.ok) return; + const turmas = await res.json(); + + const currentVal = cartazTurmaSelect.value; + cartazTurmaSelect.innerHTML = ''; + turmas.forEach(t => { + const opt = document.createElement('option'); + opt.value = t.id; + opt.textContent = `${t.nome} (${t.ano_letivo || '2026'})`; + cartazTurmaSelect.appendChild(opt); + }); + if (currentVal) cartazTurmaSelect.value = currentVal; + } catch (e) { + console.warn('[Cartazes] Erro ao carregar turmas:', e.message); + } + } + + if (cartazTurmaSelect) { + cartazTurmaSelect.addEventListener('change', () => { + const selectedOpt = cartazTurmaSelect.options[cartazTurmaSelect.selectedIndex]; + if (selectedOpt && selectedOpt.value) { + const turmaNome = selectedOpt.textContent; + if (cartazSubtituloInput && !cartazSubtituloInput.value.trim()) { + cartazSubtituloInput.value = `${turmaNome} • Professora Camila`; + } + if (cartazRodapeInput && !cartazRodapeInput.value.trim()) { + cartazRodapeInput.value = `${turmaNome} • EMEI São Bernardo do Campo`; + } + renderCartazContentFromInputs(); + updateLivePreview(); + } + }); + } + + // APLICAR TEMPLATE PEDAGÓGICO + function applyCartazTemplate(key) { + const tmpl = CARTAZ_TEMPLATES[key]; + if (!tmpl) return; + + if (cartazTituloInput) cartazTituloInput.value = tmpl.titulo; + if (cartazSubtituloInput) cartazSubtituloInput.value = tmpl.subtitulo; + if (cartazBadgeInput) cartazBadgeInput.value = tmpl.badge || ''; + if (cartazCardsInput) cartazCardsInput.value = tmpl.cards.join('\n'); + if (cartazRodapeInput) cartazRodapeInput.value = tmpl.rodape; + if (cartazBgColor) cartazBgColor.value = tmpl.bg; + if (cartazTextColor) cartazTextColor.value = tmpl.text; + if (cartazFontSelect) cartazFontSelect.value = tmpl.font; + if (cartazPromptImagem) cartazPromptImagem.value = tmpl.prompt || ''; + + renderCartazContentFromInputs(); + updateLivePreview(); + } + + if (cartazTemplateSelect) { + cartazTemplateSelect.addEventListener('change', (e) => { + if (e.target.value) { + applyCartazTemplate(e.target.value); + } + }); + } + + // BOTÃO LIMPAR / RESETAR + if (btnCartazResetTemplate) { + btnCartazResetTemplate.addEventListener('click', () => { + if (cartazTemplateSelect) cartazTemplateSelect.value = ''; + if (cartazTituloInput) cartazTituloInput.value = ''; + if (cartazSubtituloInput) cartazSubtituloInput.value = ''; + if (cartazBadgeInput) cartazBadgeInput.value = ''; + if (cartazCardsInput) cartazCardsInput.value = ''; + if (cartazRodapeInput) cartazRodapeInput.value = ''; + if (cartazPromptImagem) cartazPromptImagem.value = ''; + if (cartazPreviewImage) cartazPreviewImage.src = ''; + if (cartazPreviewImageContainer) cartazPreviewImageContainer.style.display = 'none'; + renderCartazContentFromInputs(); + updateLivePreview(); + showToast('Campos limpos com sucesso.', 'info'); + }); + } + + // BOTÃO ADICIONAR LINHA + if (btnCartazAddLine) { + btnCartazAddLine.addEventListener('click', () => { + const current = cartazCardsInput.value.trim(); + cartazCardsInput.value = current ? current + '\n✨ ' : '✨ '; + cartazCardsInput.focus(); + renderCartazContentFromInputs(); + updateLivePreview(); + }); + } + + // INSERÇÃO RÁPIDA DE EMOJIS + document.querySelectorAll('.btn-emoji-insert').forEach(btn => { + btn.addEventListener('click', () => { + const emoji = btn.dataset.emoji; + if (!emoji || !cartazCardsInput) return; + const start = cartazCardsInput.selectionStart || cartazCardsInput.value.length; + const end = cartazCardsInput.selectionEnd || cartazCardsInput.value.length; + const text = cartazCardsInput.value; + cartazCardsInput.value = text.substring(0, start) + emoji + ' ' + text.substring(end); + cartazCardsInput.focus(); + cartazCardsInput.selectionStart = cartazCardsInput.selectionEnd = start + emoji.length + 1; + renderCartazContentFromInputs(); + updateLivePreview(); + }); + }); + + // UPLOAD DE FOTO PRÓPRIA DA PROFESSORA + if (cartazImageUploadInput) { + cartazImageUploadInput.addEventListener('change', async (e) => { + const file = e.target.files?.[0]; + if (!file) return; + + const reader = new FileReader(); + reader.onload = async (event) => { + const base64Data = event.target.result; + try { + showToast('Enviando imagem do cartaz...', 'info'); + const res = await fetch('/api/cartazes/upload-image', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${localStorage.getItem('token')}` + }, + body: JSON.stringify({ base64Data }) + }); + const data = await res.json(); + if (res.ok && data.imageUrl) { + cartazPreviewImage.src = data.imageUrl; + cartazPreviewImageContainer.style.display = 'block'; + updateLivePreview(); + showToast('Foto adicionada ao cartaz com sucesso!', 'success'); + } else { + throw new Error(data.error || 'Erro ao carregar imagem'); + } + } catch (err) { + console.error('[Cartaz Upload]', err); + showToast('Erro ao carregar foto: ' + err.message, 'error'); + } + }; + reader.readAsDataURL(file); + }); + } + + // EDIÇÃO DIRETA NO PREVIEW (WYSIWYG) + if (cartazPreviewTitle) { + cartazPreviewTitle.addEventListener('input', () => { + if (cartazTituloInput) { + cartazTituloInput.value = cartazPreviewTitle.textContent.trim(); + } + }); + } + // 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(); + const orientacao = cartazOrientacaoSelect?.value || 'retrato'; + const cardStyle = cartazCardStyleSelect?.value || 'glass'; + + let cardBoxCss = ''; + if (cardStyle === 'solid') { + cardBoxCss = 'background: #ffffff; color: #1e293b; border: 1px solid rgba(0,0,0,0.12); border-radius: 12px; padding: 12px 16px; font-size: 1.05rem; font-weight: 600; display: flex; align-items: center; gap: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.08);'; + } else if (cardStyle === 'postit') { + cardBoxCss = 'background: #fef08a; color: #713f12; border: 1px solid rgba(0,0,0,0.08); border-radius: 6px; padding: 12px 16px; font-size: 1.05rem; font-weight: 600; display: flex; align-items: center; gap: 10px; box-shadow: 2px 4px 10px rgba(0,0,0,0.12); transform: rotate(-0.5deg);'; + } else if (cardStyle === 'minimal') { + cardBoxCss = 'background: transparent; border: 2px dashed rgba(0,0,0,0.2); border-radius: 10px; padding: 10px 14px; font-size: 1.05rem; font-weight: 600; display: flex; align-items: center; gap: 10px;'; + } else { + // Default: Glass suave + cardBoxCss = 'background: rgba(255, 255, 255, 0.5); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); 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 3px 8px rgba(0, 0, 0, 0.04);'; + } let html = ''; if (subtitulo) { - html += `
${subtitulo}
`; + html += `
${subtitulo}
`; } if (rawCards.length > 0) { - html += `
`; + const isGrid = orientacao === 'paisagem' || orientacao === 'quadrado'; + const containerStyle = isGrid + ? 'display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; width: 100%;' + : 'display: flex; flex-direction: column; gap: 10px; width: 100%;'; + + html += `
`; rawCards.forEach((line) => { html += ` -
+
${line}
`; }); html += `
`; } else { - html += `

Digite os destaques ou escolha um modelo ao lado.

`; + html += `

Digite os destaques ou escolha um modelo ao lado.

`; } if (rodape) { - html += `
${rodape}
`; + html += `
${rodape}
`; } cartazPreviewContent.innerHTML = html; if (cartazHtmlEditor) cartazHtmlEditor.value = html; } - // Live Style Updates + // ATUALIZAÇÃO VISUAL EM TEMPO REAL DO CARTAZ function updateLivePreview() { - const bg = cartazBgColor.value; - const text = cartazTextColor.value; - const font = cartazFontSelect.value; - const border = cartazBorderSelect.value; - const title = cartazTituloInput.value.trim() || 'Título do Cartaz'; - const orientacao = document.getElementById('cartazOrientacaoSelect') ? document.getElementById('cartazOrientacaoSelect').value : 'retrato'; + const bg = cartazBgColor?.value || '#fff9eb'; + const text = cartazTextColor?.value || '#2d3748'; + const font = cartazFontSelect?.value || "'Fredoka', sans-serif"; + const border = cartazBorderSelect?.value || '6px dashed'; + const title = cartazTituloInput?.value.trim() || 'Título do Cartaz'; + const badge = cartazBadgeInput?.value.trim() || ''; + const orientacao = cartazOrientacaoSelect?.value || 'retrato'; cartazPrintableArea.style.backgroundColor = bg; cartazPrintableArea.style.color = text; cartazPrintableArea.style.fontFamily = font; + // Ajuste de proporção física cartazPrintableArea.style.width = '100%'; - 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') { + cartazPrintableArea.style.maxWidth = '720px'; + cartazPrintableArea.style.aspectRatio = '1.414 / 1'; + cartazPrintableArea.style.minHeight = '480px'; + } else if (orientacao === 'quadrado') { + cartazPrintableArea.style.maxWidth = '540px'; + cartazPrintableArea.style.aspectRatio = '1 / 1'; + cartazPrintableArea.style.minHeight = '540px'; + } else { + // Retrato A4 + cartazPrintableArea.style.maxWidth = '480px'; + cartazPrintableArea.style.aspectRatio = '1 / 1.414'; + cartazPrintableArea.style.minHeight = '640px'; + } - cartazPreviewTitle.textContent = title; - cartazPreviewTitle.style.borderColor = text; + // Badge + if (cartazPreviewBadge) { + if (badge) { + cartazPreviewBadge.textContent = badge; + cartazPreviewBadge.style.display = 'inline-block'; + cartazPreviewBadge.style.color = text; + cartazPreviewBadge.style.borderColor = text; + } else { + cartazPreviewBadge.style.display = 'none'; + } + } + // Título + if (cartazPreviewTitle) { + cartazPreviewTitle.textContent = title; + cartazPreviewTitle.style.borderColor = text; + } + + // Borda if (border === 'none') { cartazPrintableArea.style.border = 'none'; } else { @@ -9182,10 +9456,11 @@ document.addEventListener('DOMContentLoaded', () => { } } - // Event Listeners para inputs em tempo real + // Ouvintes de inputs em tempo real [ cartazTituloInput, cartazSubtituloInput, + cartazBadgeInput, cartazCardsInput, cartazRodapeInput ].forEach(elem => { @@ -9202,19 +9477,31 @@ document.addEventListener('DOMContentLoaded', () => { cartazTextColor, cartazFontSelect, cartazBorderSelect, - document.getElementById('cartazOrientacaoSelect') + cartazCardStyleSelect, + cartazOrientacaoSelect ].forEach(elem => { - if (elem) elem.addEventListener('input', updateLivePreview); - if (elem && elem.tagName === 'SELECT') elem.addEventListener('change', updateLivePreview); + if (elem) { + elem.addEventListener('input', () => { + renderCartazContentFromInputs(); + updateLivePreview(); + }); + if (elem.tagName === 'SELECT') { + elem.addEventListener('change', () => { + renderCartazContentFromInputs(); + updateLivePreview(); + }); + } + } }); - // Preset Palettes + // Presets de Paletas document.querySelectorAll('.btn-palette-preset').forEach(btn => { - btn.addEventListener('click', (e) => { + btn.addEventListener('click', () => { const bg = btn.dataset.bg; const text = btn.dataset.text; - cartazBgColor.value = bg; - cartazTextColor.value = text; + if (cartazBgColor) cartazBgColor.value = bg; + if (cartazTextColor) cartazTextColor.value = text; + renderCartazContentFromInputs(); updateLivePreview(); }); }); @@ -9224,13 +9511,13 @@ document.addEventListener('DOMContentLoaded', () => { 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.'); + await showCustomAlert('Aviso', 'Digite uma descrição para a ilustração no campo de texto.'); return; } try { btnGenerateCartazImage.disabled = true; - btnGenerateCartazImage.textContent = '⏳ Gerando com IA...'; + btnGenerateCartazImage.innerHTML = '⏳ Gerando...'; const fullPrompt = `${prompt}, high resolution children book illustration, cute Pixar 3D, colorful, no text, clean vector`; @@ -9250,34 +9537,41 @@ document.addEventListener('DOMContentLoaded', () => { cartazPreviewImage.src = data.imageUrl; cartazPreviewImageContainer.style.display = 'block'; updateLivePreview(); - await showCustomAlert('Ilustração Pronta!', 'A imagem foi gerada e adicionada ao cartaz com sucesso.'); + showToast('Ilustração criada e adicionada com sucesso!', 'success'); } } 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'; + btnGenerateCartazImage.innerHTML = '🪄 Gerar com IA'; } }); } + // Remover Imagem do Cartaz if (btnRemoveCartazImage) { btnRemoveCartazImage.addEventListener('click', () => { - cartazPreviewImage.src = ''; - cartazPreviewImageContainer.style.display = 'none'; + if (cartazPreviewImage) cartazPreviewImage.src = ''; + if (cartazPreviewImageContainer) cartazPreviewImageContainer.style.display = 'none'; if (cartazPromptImagem) cartazPromptImagem.value = ''; + if (cartazImageUploadInput) cartazImageUploadInput.value = ''; updateLivePreview(); + showToast('Imagem removida do cartaz.', 'info'); }); } - // --- GERAR CONTEÚDO COM PEDAGOGIA (IA) --- + // --- GERAR CONTEÚDO COM PEDAGOGIA AVANÇADA (IA) --- if (btnGenerateCartaz) { btnGenerateCartaz.addEventListener('click', async () => { const titulo = (cartazTituloInput?.value || '').trim(); const subtitulo = (cartazSubtituloInput?.value || '').trim(); + const badge = (cartazBadgeInput?.value || '').trim(); const promptImagem = (cartazPromptImagem?.value || '').trim(); - const orientacao = document.getElementById('cartazOrientacaoSelect')?.value || 'retrato'; + const orientacao = cartazOrientacaoSelect?.value || 'retrato'; + const faixaEtaria = cartazFaixaEtaria?.value || ''; + const campoBncc = cartazCampoBncc?.value || ''; + const turmaId = cartazTurmaSelect?.value || ''; if (!titulo) { await showCustomAlert('Aviso', 'Por favor, informe ao menos o Título Principal do Cartaz.'); @@ -9286,16 +9580,23 @@ document.addEventListener('DOMContentLoaded', () => { btnGenerateCartaz.disabled = true; if (cartazGenerateLoader) cartazGenerateLoader.style.display = 'flex'; + if (cartazLoaderText) cartazLoaderText.textContent = 'Diagramando cartaz com inteligência pedagógica...'; try { const res = await fetch('/api/cartazes/generate', { method: 'POST', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify({ titulo, tema: subtitulo || titulo, + subtitulo, + badge, + faixaEtaria, + campoBncc, + turmaId, corFundo: cartazBgColor?.value || '#fff9eb', corTexto: cartazTextColor?.value || '#2d3748', layout: 'educativo', @@ -9309,12 +9610,17 @@ document.addEventListener('DOMContentLoaded', () => { if (res.ok) { activeCartazData = data; - if (data.conteudo) { - // Extrair texto limpo de tópicos/cards para o input editável + if (data.titulo) cartazTituloInput.value = data.titulo; + if (data.subtitulo) cartazSubtituloInput.value = data.subtitulo; + if (data.badge) cartazBadgeInput.value = data.badge; + if (data.rodape) cartazRodapeInput.value = data.rodape; + + if (Array.isArray(data.cards) && data.cards.length > 0) { + cartazCardsInput.value = data.cards.join('\n'); + } else if (data.conteudo) { 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 { @@ -9343,43 +9649,90 @@ document.addEventListener('DOMContentLoaded', () => { }); } - // --- EXPORTAR PNG EM ALTA RESOLUÇÃO --- + // --- FERRAMENTA 1: COPIAR IMAGEM PARA ÁREA DE TRANSFERÊNCIA --- + if (btnCopyCartazClipboard) { + btnCopyCartazClipboard.addEventListener('click', async () => { + try { + btnCopyCartazClipboard.disabled = true; + btnCopyCartazClipboard.textContent = '⏳ Copiando...'; + + if (typeof html2canvas === 'undefined') { + throw new Error('Biblioteca de renderização não carregada.'); + } + + const canvas = await html2canvas(cartazPrintableArea, { + scale: 2.5, + useCORS: true, + logging: false, + backgroundColor: cartazBgColor?.value || '#fff9eb' + }); + + canvas.toBlob(async (blob) => { + if (!blob) throw new Error('Não foi possível gerar a imagem.'); + try { + await navigator.clipboard.write([ + new ClipboardItem({ 'image/png': blob }) + ]); + showToast('📋 Imagem do cartaz copiada! Pode colar direto no WhatsApp ou Word (Ctrl+V).', 'success'); + } catch (clipErr) { + console.warn('Clipboard write failed, fallback to copy dataURL:', clipErr); + // Fallback de download caso o navegador restrinja a Clipboard API + const link = document.createElement('a'); + link.download = `cartaz_${Date.now()}.png`; + link.href = canvas.toDataURL('image/png'); + link.click(); + showToast('Imagem baixada com sucesso.', 'info'); + } + }, 'image/png'); + + } catch (err) { + console.error('Erro ao copiar cartaz:', err); + showToast('Erro ao copiar imagem: ' + err.message, 'error'); + } finally { + btnCopyCartazClipboard.disabled = false; + btnCopyCartazClipboard.textContent = '📋 Copiar Imagem'; + } + }); + } + + // --- FERRAMENTA 2: EXPORTAR PNG EM ALTA RESOLUÇÃO (300 DPI) --- if (btnExportCartazPNG) { btnExportCartazPNG.addEventListener('click', async () => { try { btnExportCartazPNG.disabled = true; - btnExportCartazPNG.textContent = '⏳ Gerando PNG...'; + btnExportCartazPNG.textContent = '⏳ Criando 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 + scale: 3, // Alta resolução para impressão useCORS: true, logging: false, - backgroundColor: cartazBgColor.value || '#fff9eb' + backgroundColor: cartazBgColor?.value || '#fff9eb' }); - const title = (cartazTituloInput.value || 'cartaz_pedagog').replace(/[^a-zA-Z0-9_-]/g, '_').toLowerCase(); + const title = (cartazTituloInput?.value || 'cartaz_pedagog').replace(/[^a-zA-Z0-9_-]/g, '_').toLowerCase(); const link = document.createElement('a'); - link.download = `${title}.png`; + link.download = `${title}_300dpi.png`; link.href = canvas.toDataURL('image/png'); document.body.appendChild(link); link.click(); link.remove(); + showToast('PNG de alta resolução gerado com sucesso!', 'success'); } 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'; + btnExportCartazPNG.textContent = '🖼️ PNG'; } }); } - // --- EXPORTAR PDF IMPRIMÍVEL --- + // --- FERRAMENTA 3: EXPORTAR PDF IMPRIMÍVEL (A4 EXATO) --- if (btnExportCartazPDF) { btnExportCartazPDF.addEventListener('click', async () => { try { @@ -9390,77 +9743,76 @@ document.addEventListener('DOMContentLoaded', () => { throw new Error('Bibliotecas de PDF necessárias não disponíveis.'); } - const orientacao = document.getElementById('cartazOrientacaoSelect')?.value === 'paisagem' ? 'l' : 'p'; + const orientacaoVal = cartazOrientacaoSelect?.value || 'retrato'; + const isLandscape = orientacaoVal === 'paisagem'; + const isSquare = orientacaoVal === 'quadrado'; + const canvas = await html2canvas(cartazPrintableArea, { scale: 3, useCORS: true, logging: false, - backgroundColor: cartazBgColor.value || '#fff9eb' + backgroundColor: cartazBgColor?.value || '#fff9eb' }); - const imgData = canvas.toDataURL('image/jpeg', 0.95); + const imgData = canvas.toDataURL('image/jpeg', 0.96); 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(); + let pdf; + if (isSquare) { + pdf = new jsPDF('p', 'pt', [595, 595]); + pdf.addImage(imgData, 'JPEG', 0, 0, 595, 595); + } else if (isLandscape) { + pdf = new jsPDF('l', 'pt', 'a4'); + pdf.addImage(imgData, 'JPEG', 0, 0, 842, 595); + } else { + pdf = new jsPDF('p', 'pt', 'a4'); + pdf.addImage(imgData, 'JPEG', 0, 0, 595, 842); + } + + const title = (cartazTituloInput?.value || 'cartaz_pedagog').replace(/[^a-zA-Z0-9_-]/g, '_').toLowerCase(); pdf.save(`${title}.pdf`); + showToast('Documento PDF pronto para impressão baixado com sucesso!', 'success'); } 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'; + btnExportCartazPDF.textContent = '📄 PDF'; } }); } - // Print Poster + // --- FERRAMENTA 4: IMPRESSÃO DIRETA --- if (btnPrintCartaz) { btnPrintCartaz.addEventListener('click', () => { - const title = cartazTituloInput.value.trim() || 'Cartaz Pedagógico'; - const bg = cartazBgColor.value; - const text = cartazTextColor.value; - const font = cartazFontSelect.value; - const border = cartazBorderSelect.value; - const tamanho = document.getElementById('cartazTamanhoSelect') ? document.getElementById('cartazTamanhoSelect').value : 'A4'; - const orientacao = document.getElementById('cartazOrientacaoSelect') ? document.getElementById('cartazOrientacaoSelect').value : 'retrato'; - - const imgContainerHtml = cartazPreviewImageContainer.style.display === 'block' && cartazPreviewImageContainer.style.position !== 'absolute' - ? `
` + const title = cartazTituloInput?.value.trim() || 'Cartaz Pedagógico'; + const bg = cartazBgColor?.value || '#fff9eb'; + const text = cartazTextColor?.value || '#2d3748'; + const font = cartazFontSelect?.value || "'Fredoka', sans-serif"; + const border = cartazBorderSelect?.value || '6px dashed'; + const orientacao = cartazOrientacaoSelect?.value || 'retrato'; + + const imgContainerHtml = cartazPreviewImageContainer.style.display === 'block' && cartazPreviewImage.src + ? `
` : ''; - let printContent = ''; - const hasCanvasItems = cartazPrintableArea.querySelectorAll('.canvas-item').length > 0; - - if (hasCanvasItems) { - // Clone printable area and cleanup handles / active state borders for print output - const tempContainer = document.createElement('div'); - tempContainer.innerHTML = cartazPrintableArea.innerHTML; - tempContainer.querySelectorAll('.canvas-resize-handle').forEach(h => h.remove()); - tempContainer.querySelectorAll('.canvas-item').forEach(item => { - item.classList.remove('active-item'); - item.removeAttribute('contenteditable'); - if (item.style.border && item.style.border.includes('dashed')) { - item.style.border = 'none'; - } - }); - printContent = tempContainer.innerHTML; - } else { - printContent = ` -

${title}

- ${imgContainerHtml} -
- ${cartazPreviewContent.innerHTML} -
- `; - } + const badgeHtml = cartazBadgeInput?.value.trim() + ? `
${cartazBadgeInput.value.trim()}
` + : ''; + + const printContent = ` + ${badgeHtml} +

${title}

+ ${imgContainerHtml} +
+ ${cartazPreviewContent.innerHTML} +
+ `; const printWindow = window.open('', '_blank'); printWindow.document.write(` + ${title} - PedaGog @@ -9474,13 +9826,13 @@ document.addEventListener('DOMContentLoaded', () => { box-sizing: border-box; } @page { - size: ${tamanho} ${orientacao === 'paisagem' ? 'landscape' : 'portrait'}; - margin: 10mm; + size: A4 ${orientacao === 'paisagem' ? 'landscape' : 'portrait'}; + margin: 8mm; } body { font-family: ${font}; margin: 0; - padding: 20px; + padding: 10px; background-color: #f7fafc; display: flex; justify-content: center; @@ -9490,61 +9842,35 @@ document.addEventListener('DOMContentLoaded', () => { .cartaz-frame { background-color: ${bg}; color: ${text}; - padding: 40px; + padding: 36px 32px; border-radius: 16px; width: 100%; - max-width: ${orientacao === 'paisagem' ? '1200px' : '800px'}; + max-width: ${orientacao === 'paisagem' ? '1100px' : '780px'}; aspect-ratio: ${orientacao === 'paisagem' ? '1.414 / 1' : '1 / 1.414'}; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); box-sizing: border-box; border: ${border === 'none' ? 'none' : `${border} ${text}`}; display: flex; flex-direction: column; position: relative; overflow: hidden; - container-type: inline-size; } h1 { text-align: center; margin-top: 0; - font-size: 3.5rem; + font-size: 3rem; border-bottom: 3px solid ${text}; - padding-bottom: 16px; - margin-bottom: 30px; + padding-bottom: 14px; + margin-bottom: 24px; } .content-area { - font-size: 1.5rem; + font-size: 1.4rem; line-height: 1.6; + flex: 1; display: flex; - flex-direction: ${orientacao === 'paisagem' ? 'row' : 'column'}; - flex-wrap: wrap; - gap: 20px; + flex-direction: column; justify-content: center; + gap: 16px; } - /* Suporte para cards na content-area */ - .content-area > div, .content-area > p, .content-area > ul { - box-sizing: border-box; - background: rgba(255, 255, 255, 0.3); - padding: 20px; - border-radius: 12px; - box-shadow: 0 2px 4px rgba(0,0,0,0.05); - width: ${orientacao === 'paisagem' ? 'calc(50% - 20px)' : '100%'}; - flex: ${orientacao === 'paisagem' ? '1 1 calc(50% - 20px)' : '0 0 auto'}; - margin: 0; - } - ul { - margin-left: 20px; - } - li { - margin-bottom: 12px; - } - - /* Estilos específicos do Canvas no PDF/Print */ - .canvas-item { - position: absolute !important; - box-sizing: border-box; - } - @media print { body { background: transparent; padding: 0; display: block; } .cartaz-frame { @@ -9552,11 +9878,9 @@ document.addEventListener('DOMContentLoaded', () => { border-radius: 0; max-width: 100%; width: 100%; - height: auto; min-height: 100%; - padding: 30px; + padding: 24px; } - button { display: none; } } @@ -9576,10 +9900,34 @@ document.addEventListener('DOMContentLoaded', () => { }); } - // Load History list + // --- TOGGLE EDITOR DE CÓDIGO HTML --- + if (btnEditCartazToggle) { + btnEditCartazToggle.addEventListener('click', () => { + if (cartazEditArea.style.display === 'none' || !cartazEditArea.style.display) { + cartazEditArea.style.display = 'flex'; + btnEditCartazToggle.style.background = 'rgba(16, 185, 129, 0.2)'; + btnEditCartazToggle.style.color = '#10b981'; + } else { + cartazEditArea.style.display = 'none'; + btnEditCartazToggle.style.background = 'transparent'; + btnEditCartazToggle.style.color = 'var(--text-secondary)'; + } + }); + } + + if (btnUpdateCartazPreview) { + btnUpdateCartazPreview.addEventListener('click', () => { + if (cartazPreviewContent && cartazHtmlEditor) { + cartazPreviewContent.innerHTML = cartazHtmlEditor.value; + showToast('Pré-visualização atualizada do código HTML!', 'info'); + } + }); + } + + // --- HISTÓRICO DE CARTAZES SALVOS --- async function loadCartazesHistory() { if (!cartazesHistoryContainer) return; - cartazesHistoryContainer.innerHTML = '
Carregando histórico...
'; + cartazesHistoryContainer.innerHTML = '
Carregando seus cartazes salvos...
'; try { const res = await fetch('/api/cartazes/list', { @@ -9589,28 +9937,28 @@ document.addEventListener('DOMContentLoaded', () => { cartazesHistoryContainer.innerHTML = ''; if (!data || data.length === 0) { - cartazesNoData.style.display = 'block'; + if (cartazesNoData) cartazesNoData.style.display = 'block'; return; } - cartazesNoData.style.display = 'none'; + if (cartazesNoData) cartazesNoData.style.display = 'none'; data.forEach(item => { const card = document.createElement('div'); card.style.background = 'var(--bg-tertiary)'; card.style.border = '1px solid var(--border-light)'; - card.style.borderRadius = '10px'; - card.style.padding = '16px'; + card.style.borderRadius = '12px'; + card.style.padding = '14px'; card.style.display = 'flex'; card.style.flexDirection = 'column'; card.style.justifyContent = 'space-between'; card.style.gap = '12px'; - card.style.boxShadow = '0 4px 6px rgba(0,0,0,0.1)'; + card.style.boxShadow = '0 4px 8px rgba(0,0,0,0.08)'; const thumbnail = item.imagemUrl - ? `
+ ? `
` - : `
+ : `
${item.titulo}
`; @@ -9618,11 +9966,11 @@ document.addEventListener('DOMContentLoaded', () => {
${thumbnail}
${item.titulo}
-

Foco: ${item.tema}

- Layout: ${item.layout.toUpperCase()} +

${item.tema || 'Foco pedagógico'}

+ Criado em: ${new Date(item.createdAt).toLocaleDateString('pt-BR')}
- +
`; @@ -9639,14 +9987,12 @@ document.addEventListener('DOMContentLoaded', () => { }); const poster = await r.json(); - // Set Inputs - cartazTituloInput.value = poster.titulo; - cartazTemaInput.value = poster.tema; - cartazLayoutSelect.value = poster.layout; - cartazBgColor.value = poster.corFundo; - cartazTextColor.value = poster.corTexto; - cartazHtmlEditor.value = poster.conteudo; - cartazPreviewContent.innerHTML = poster.conteudo; + if (cartazTituloInput) cartazTituloInput.value = poster.titulo || ''; + if (cartazSubtituloInput) cartazSubtituloInput.value = poster.tema || ''; + if (cartazBgColor) cartazBgColor.value = poster.corFundo || '#fff9eb'; + if (cartazTextColor) cartazTextColor.value = poster.corTexto || '#2d3748'; + if (cartazHtmlEditor) cartazHtmlEditor.value = poster.conteudo || ''; + if (cartazPreviewContent) cartazPreviewContent.innerHTML = poster.conteudo || ''; if (poster.imagemUrl) { cartazPreviewImage.src = poster.imagemUrl; @@ -9657,8 +10003,9 @@ document.addEventListener('DOMContentLoaded', () => { updateLivePreview(); switchCartazTab('criar'); + showToast('Cartaz carregado para edição!', 'success'); } catch (err) { - showToast('Erro ao carregar cartaz.', 'error'); + showToast('Erro ao carregar cartaz selecionado.', 'error'); } }); }); @@ -9666,7 +10013,7 @@ document.addEventListener('DOMContentLoaded', () => { // Bind Delete Buttons document.querySelectorAll('.btn-del-cartaz').forEach(btn => { btn.addEventListener('click', async (e) => { - if (!confirm('Tem certeza que deseja apagar este cartaz?')) return; + if (!confirm('Deseja realmente excluir este cartaz?')) return; const id = e.currentTarget.dataset.id; try { const r = await fetch(`/api/cartazes/${id}`, { @@ -9674,7 +10021,7 @@ document.addEventListener('DOMContentLoaded', () => { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` } }); if (r.ok) { - showToast('Cartaz deletado com sucesso.', 'success'); + showToast('Cartaz excluído com sucesso.', 'success'); loadCartazesHistory(); } else { showToast('Erro ao deletar cartaz.', 'error'); diff --git a/public/index.html b/public/index.html index 1eba270..c3b5df8 100644 --- a/public/index.html +++ b/public/index.html @@ -2420,109 +2420,181 @@