Feature: Fabrica de Quadrinhos profissional com geracao paralela, modo apresentacao fullscreen, storyboard interativo, exportacao ZIP e adaptacao mobile
This commit is contained in:
+392
-55
@@ -4442,6 +4442,8 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
|
||||
comicsCharListContainer.appendChild(row);
|
||||
};
|
||||
|
||||
const btnImportTurmaChars = document.getElementById('btnImportTurmaChars');
|
||||
|
||||
if (btnAddHumanChar) {
|
||||
btnAddHumanChar.addEventListener('click', () => {
|
||||
addCharacterRow('', '', false);
|
||||
@@ -4454,6 +4456,37 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
|
||||
});
|
||||
}
|
||||
|
||||
if (btnImportTurmaChars) {
|
||||
btnImportTurmaChars.addEventListener('click', async () => {
|
||||
try {
|
||||
btnImportTurmaChars.disabled = true;
|
||||
btnImportTurmaChars.textContent = '⏳ Carregando...';
|
||||
const res = await fetch('/api/alunos');
|
||||
if (!res.ok) throw new Error('Falha ao obter lista de alunos');
|
||||
const alunos = await res.json();
|
||||
if (!alunos || alunos.length === 0) {
|
||||
await showCustomAlert('Nenhum Aluno', 'Cadastre alunos na seção "Minha Turma" para importá-los automaticamente.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Adiciona os alunos como personagens (até 4 para manter a história focada)
|
||||
const selecionados = alunos.slice(0, 4);
|
||||
comicsCharListContainer.innerHTML = '';
|
||||
selecionados.forEach(aluno => {
|
||||
const generoProvavel = aluno.nome.trim().endsWith('a') ? 'Menina' : 'Menino';
|
||||
addCharacterRow(generoProvavel, aluno.nome.trim(), false);
|
||||
});
|
||||
await showCustomAlert('Turma Importada!', `${selecionados.length} alunos foram adicionados como personagens da história.`);
|
||||
} catch (err) {
|
||||
console.error('Erro ao importar alunos:', err);
|
||||
await showCustomAlert('Erro', 'Não foi possível carregar a lista de alunos: ' + err.message);
|
||||
} finally {
|
||||
btnImportTurmaChars.disabled = false;
|
||||
btnImportTurmaChars.textContent = '+ 🏫 Importar da Turma';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Exibir/ocultar cenário personalizado
|
||||
if (comicsCenarioSelect) {
|
||||
comicsCenarioSelect.addEventListener('change', () => {
|
||||
@@ -4945,18 +4978,14 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
|
||||
currentComicsCharDescEnglish = scriptData.character_description;
|
||||
}
|
||||
|
||||
// 2. Gerar cada quadrinho sequencialmente
|
||||
// 2. Gerar quadrinhos em PARALELO com tracking de progresso em tempo real
|
||||
if (genMode !== 'extend') {
|
||||
generatedPanelsData = [];
|
||||
}
|
||||
const totalPanels = scriptData.panels.length;
|
||||
let completedCount = 0;
|
||||
|
||||
for (let i = 0; i < totalPanels; i++) {
|
||||
const panel = scriptData.panels[i];
|
||||
const progressPercent = 15 + Math.floor((i / totalPanels) * 80);
|
||||
comicsLoaderProgress.style.width = `${progressPercent}%`;
|
||||
comicsLoaderText.textContent = `Ilustrando quadrinho ${i + 1} de ${totalPanels}...`;
|
||||
|
||||
const panelPromises = scriptData.panels.map(async (panel, idx) => {
|
||||
// Injetamos a proporção e estilo de forma reforçada no prompt
|
||||
const fullPrompt = `${panel.image_prompt}, high resolution children book illustration, cute Pixar style, ${selectedComicsRatio === '16:9' ? '16:9 aspect ratio' : '4:3 aspect ratio'}`;
|
||||
|
||||
@@ -4968,65 +4997,43 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
|
||||
|
||||
if (!frameResp.ok) {
|
||||
const err = await frameResp.json();
|
||||
throw new Error(`Erro no quadrinho ${i + 1}: ${err.error}`);
|
||||
throw new Error(`Erro no quadrinho ${panel.panel_number}: ${err.error}`);
|
||||
}
|
||||
|
||||
const frameData = await frameResp.json();
|
||||
generatedPanelsData.push({
|
||||
completedCount++;
|
||||
const progressPercent = 15 + Math.floor((completedCount / totalPanels) * 80);
|
||||
if (comicsLoaderProgress) comicsLoaderProgress.style.width = `${progressPercent}%`;
|
||||
if (comicsLoaderText) comicsLoaderText.textContent = `⚡ Ilustrando em paralelo: ${completedCount}/${totalPanels} quadros concluídos...`;
|
||||
|
||||
return {
|
||||
panel_number: panel.panel_number,
|
||||
imageUrl: frameData.imageUrl,
|
||||
dialogue: panel.dialogue || '',
|
||||
image_prompt: panel.image_prompt || ''
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
const newPanels = await Promise.all(panelPromises);
|
||||
|
||||
// Ordena por panel_number para garantir a sequência correta
|
||||
newPanels.sort((a, b) => a.panel_number - b.panel_number);
|
||||
|
||||
if (genMode === 'extend') {
|
||||
generatedPanelsData = generatedPanelsData.concat(newPanels);
|
||||
} else {
|
||||
generatedPanelsData = newPanels;
|
||||
}
|
||||
|
||||
// Renderizar quadrinhos na tela (todos, incluindo os anteriores caso tenha sido extensão)
|
||||
// Atualizar cabeçalho e metadados
|
||||
comicsResultTitle.textContent = scriptData.title || comicsResultTitle.textContent || 'Fábrica de Quadrinhos Pedagog';
|
||||
comicsGridContainer.innerHTML = '';
|
||||
const metaPanels = document.getElementById('comicsMetaPanels');
|
||||
if (metaPanels) metaPanels.textContent = `🖼️ ${generatedPanelsData.length} Quadros`;
|
||||
const metaRatio = document.getElementById('comicsMetaRatio');
|
||||
if (metaRatio) metaRatio.textContent = `📐 ${selectedComicsRatio} ${selectedComicsRatio === '16:9' ? 'HD' : 'Retrô'}`;
|
||||
|
||||
generatedPanelsData.forEach((panel, index) => {
|
||||
const panelCard = document.createElement('div');
|
||||
panelCard.className = 'comic-panel-card';
|
||||
|
||||
const imgContainer = document.createElement('div');
|
||||
imgContainer.className = `comic-panel-image-container ratio-${selectedComicsRatio.replace(':', '-')}`;
|
||||
|
||||
const img = document.createElement('img');
|
||||
img.className = 'comic-panel-image';
|
||||
img.src = panel.imageUrl || panel.image_url;
|
||||
img.alt = `Quadro ${panel.panel_number}`;
|
||||
imgContainer.appendChild(img);
|
||||
|
||||
// Selo do número
|
||||
const badge = document.createElement('div');
|
||||
badge.className = 'comic-panel-number-badge';
|
||||
badge.textContent = panel.panel_number;
|
||||
imgContainer.appendChild(badge);
|
||||
|
||||
panelCard.appendChild(imgContainer);
|
||||
|
||||
const caption = document.createElement('div');
|
||||
caption.className = 'comic-caption-text';
|
||||
caption.style.cssText = 'padding: 10px 14px; background: var(--bg-primary); border-top: 1px solid var(--border-light);';
|
||||
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.className = 'comic-caption-input';
|
||||
textarea.value = panel.dialogue || '';
|
||||
textarea.placeholder = 'Digite a fala ou legenda do quadrinho...';
|
||||
textarea.style.cssText = 'width: 100%; border: 1px solid var(--border-light); background: var(--bg-secondary); color: var(--text-primary); border-radius: 6px; padding: 8px; font-family: inherit; font-size: 0.85rem; resize: vertical; box-sizing: border-box; min-height: 50px;';
|
||||
|
||||
textarea.addEventListener('input', (e) => {
|
||||
panel.dialogue = e.target.value;
|
||||
if (generatedPanelsData[index]) {
|
||||
generatedPanelsData[index].dialogue = e.target.value;
|
||||
}
|
||||
});
|
||||
|
||||
caption.appendChild(textarea);
|
||||
panelCard.appendChild(caption);
|
||||
|
||||
comicsGridContainer.appendChild(panelCard);
|
||||
});
|
||||
// Renderizar Storyboard Interativo
|
||||
renderComicsStoryboard();
|
||||
|
||||
// Se for uma nova história derivada de um projeto antigo, limpamos o ID para virar um novo projeto independente ao salvar
|
||||
if (genMode === 'new_story' && currentComicsProjectId) {
|
||||
@@ -5053,6 +5060,336 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
|
||||
});
|
||||
}
|
||||
|
||||
// --- RENDERIZADOR DO STORYBOARD PROFISSIONAL DOS QUADRINHOS ---
|
||||
const renderComicsStoryboard = () => {
|
||||
if (!comicsGridContainer) return;
|
||||
comicsGridContainer.innerHTML = '';
|
||||
|
||||
generatedPanelsData.forEach((panel, index) => {
|
||||
const panelCard = document.createElement('div');
|
||||
panelCard.className = 'comic-panel-card';
|
||||
panelCard.dataset.index = index;
|
||||
|
||||
const imgContainer = document.createElement('div');
|
||||
imgContainer.className = `comic-panel-image-container ratio-${selectedComicsRatio.replace(':', '-')}`;
|
||||
|
||||
const img = document.createElement('img');
|
||||
img.className = 'comic-panel-image';
|
||||
img.src = panel.imageUrl || panel.image_url;
|
||||
img.alt = `Quadro ${panel.panel_number}`;
|
||||
img.loading = 'lazy';
|
||||
imgContainer.appendChild(img);
|
||||
|
||||
// Selo de número do quadrinho
|
||||
const badge = document.createElement('div');
|
||||
badge.className = 'comic-panel-number-badge';
|
||||
badge.textContent = panel.panel_number;
|
||||
imgContainer.appendChild(badge);
|
||||
|
||||
// Barra de Ações Rápidas por Quadro (Mobile & Desktop)
|
||||
const actionsOverlay = document.createElement('div');
|
||||
actionsOverlay.className = 'comic-panel-overlay-actions';
|
||||
|
||||
// Botão 🔍 Zoom
|
||||
const btnZoom = document.createElement('button');
|
||||
btnZoom.type = 'button';
|
||||
btnZoom.className = 'btn-comic-action';
|
||||
btnZoom.title = 'Ampliar imagem';
|
||||
btnZoom.innerHTML = '🔍';
|
||||
btnZoom.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
openComicsPresentation(index);
|
||||
});
|
||||
actionsOverlay.appendChild(btnZoom);
|
||||
|
||||
// Botão 🔄 Regenerar Imagem deste Quadro
|
||||
const btnRegen = document.createElement('button');
|
||||
btnRegen.type = 'button';
|
||||
btnRegen.className = 'btn-comic-action';
|
||||
btnRegen.title = 'Regenerar apenas este quadrinho';
|
||||
btnRegen.innerHTML = '🔄';
|
||||
btnRegen.addEventListener('click', async (e) => {
|
||||
e.stopPropagation();
|
||||
await regenerateSinglePanel(index, panelCard, img, btnRegen);
|
||||
});
|
||||
actionsOverlay.appendChild(btnRegen);
|
||||
|
||||
// Botão ✏️ Ver/Editar Prompt
|
||||
const btnPromptToggle = document.createElement('button');
|
||||
btnPromptToggle.type = 'button';
|
||||
btnPromptToggle.className = 'btn-comic-action';
|
||||
btnPromptToggle.title = 'Editar prompt visual';
|
||||
btnPromptToggle.innerHTML = '✏️';
|
||||
actionsOverlay.appendChild(btnPromptToggle);
|
||||
|
||||
// Botão 💾 Baixar Imagem Individual
|
||||
const btnDownloadImg = document.createElement('button');
|
||||
btnDownloadImg.type = 'button';
|
||||
btnDownloadImg.className = 'btn-comic-action';
|
||||
btnDownloadImg.title = 'Baixar esta imagem PNG';
|
||||
btnDownloadImg.innerHTML = '💾';
|
||||
btnDownloadImg.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const a = document.createElement('a');
|
||||
a.href = panel.imageUrl || panel.image_url;
|
||||
a.download = `quadrinho_${panel.panel_number}.png`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
});
|
||||
actionsOverlay.appendChild(btnDownloadImg);
|
||||
|
||||
imgContainer.appendChild(actionsOverlay);
|
||||
panelCard.appendChild(imgContainer);
|
||||
|
||||
// Área de Legenda / Diálogo
|
||||
const caption = document.createElement('div');
|
||||
caption.className = 'comic-caption-text';
|
||||
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.className = 'comic-caption-input';
|
||||
textarea.value = panel.dialogue || '';
|
||||
textarea.placeholder = 'Digite a fala ou legenda do quadrinho...';
|
||||
textarea.style.cssText = 'width: 100%; border: 1px solid var(--border-light); background: var(--bg-secondary); color: var(--text-primary); border-radius: 6px; padding: 8px; font-family: inherit; font-size: 0.85rem; resize: vertical; box-sizing: border-box; min-height: 48px;';
|
||||
|
||||
textarea.addEventListener('input', (e) => {
|
||||
panel.dialogue = e.target.value;
|
||||
if (generatedPanelsData[index]) {
|
||||
generatedPanelsData[index].dialogue = e.target.value;
|
||||
}
|
||||
});
|
||||
caption.appendChild(textarea);
|
||||
|
||||
// Mini-Editor de Prompt Visual (Oculto por padrão, ativado no botão ✏️)
|
||||
const promptBox = document.createElement('div');
|
||||
promptBox.className = 'comic-prompt-details';
|
||||
const promptInput = document.createElement('textarea');
|
||||
promptInput.style.cssText = 'width: 100%; font-size: 0.72rem; padding: 4px; background: var(--bg-primary); color: var(--text-primary); border: 1px solid var(--border-light); border-radius: 4px; resize: vertical; min-height: 40px; box-sizing: border-box;';
|
||||
promptInput.value = panel.image_prompt || '';
|
||||
promptInput.addEventListener('input', (e) => {
|
||||
panel.image_prompt = e.target.value;
|
||||
});
|
||||
promptBox.appendChild(document.createTextNode('Prompt Visual: '));
|
||||
promptBox.appendChild(promptInput);
|
||||
caption.appendChild(promptBox);
|
||||
|
||||
btnPromptToggle.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
promptBox.style.display = promptBox.style.display === 'block' ? 'none' : 'block';
|
||||
});
|
||||
|
||||
panelCard.appendChild(caption);
|
||||
comicsGridContainer.appendChild(panelCard);
|
||||
});
|
||||
};
|
||||
|
||||
// Regenerar um único painel
|
||||
const regenerateSinglePanel = async (index, panelCard, imgElement, btnRegen) => {
|
||||
const panel = generatedPanelsData[index];
|
||||
if (!panel) return;
|
||||
|
||||
try {
|
||||
btnRegen.disabled = true;
|
||||
btnRegen.textContent = '⏳';
|
||||
imgElement.style.opacity = '0.4';
|
||||
|
||||
const promptToUse = panel.image_prompt || 'cute children illustration';
|
||||
const fullPrompt = `${promptToUse}, high resolution children book illustration, cute Pixar style, ${selectedComicsRatio === '16:9' ? '16:9 aspect ratio' : '4:3 aspect ratio'}`;
|
||||
|
||||
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 || 'Erro na regeneração');
|
||||
}
|
||||
|
||||
const data = await resp.json();
|
||||
panel.imageUrl = data.imageUrl;
|
||||
imgElement.src = data.imageUrl + '?v=' + Date.now();
|
||||
imgElement.style.opacity = '1';
|
||||
} catch (err) {
|
||||
console.error('Erro ao regenerar painel:', err);
|
||||
await showCustomAlert('Erro', 'Não foi possível regenerar o quadrinho: ' + err.message);
|
||||
imgElement.style.opacity = '1';
|
||||
} finally {
|
||||
btnRegen.disabled = false;
|
||||
btnRegen.innerHTML = '🔄';
|
||||
}
|
||||
};
|
||||
|
||||
// --- EXPORTAR TODAS AS IMAGENS EM ZIP ---
|
||||
const btnExportComicsZIP = document.getElementById('btnExportComicsZIP');
|
||||
if (btnExportComicsZIP) {
|
||||
btnExportComicsZIP.addEventListener('click', async () => {
|
||||
if (!generatedPanelsData || generatedPanelsData.length === 0) {
|
||||
await showCustomAlert('Aviso', 'Nenhum quadrinho gerado para exportar.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
btnExportComicsZIP.disabled = true;
|
||||
btnExportComicsZIP.textContent = '⏳ Criando ZIP...';
|
||||
|
||||
if (typeof JSZip === 'undefined') {
|
||||
throw new Error('Biblioteca JSZip não carregada.');
|
||||
}
|
||||
|
||||
const zip = new JSZip();
|
||||
const folder = zip.folder('quadrinhos');
|
||||
const title = (comicsResultTitle?.textContent || 'Historia_Quadrinhos').replace(/[^a-zA-Z0-9_-]/g, '_');
|
||||
|
||||
let roteiroTxt = `HISTÓRIA EM QUADRINHOS: ${comicsResultTitle?.textContent || 'Fábrica de Quadrinhos'}\n`;
|
||||
roteiroTxt += `Criado com PedagogIA em ${new Date().toLocaleDateString('pt-BR')}\n\n`;
|
||||
|
||||
for (let i = 0; i < generatedPanelsData.length; i++) {
|
||||
const panel = generatedPanelsData[i];
|
||||
const imgUrl = panel.imageUrl || panel.image_url;
|
||||
roteiroTxt += `[QUADRO ${panel.panel_number}]\nFala/Legenda: ${panel.dialogue || '(Sem fala)'}\nPrompt Visual: ${panel.image_prompt || ''}\n\n`;
|
||||
|
||||
try {
|
||||
const resp = await fetch(imgUrl);
|
||||
const blob = await resp.blob();
|
||||
folder.file(`quadrinho_${panel.panel_number}.jpg`, blob);
|
||||
} catch (fetchErr) {
|
||||
console.warn(`Erro ao incluir imagem ${panel.panel_number} no ZIP:`, fetchErr);
|
||||
}
|
||||
}
|
||||
|
||||
folder.file('roteiro.txt', roteiroTxt);
|
||||
|
||||
const content = await zip.generateAsync({ type: 'blob' });
|
||||
const downloadUrl = URL.createObjectURL(content);
|
||||
const a = document.createElement('a');
|
||||
a.href = downloadUrl;
|
||||
a.download = `${title}_pedagog.zip`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
URL.revokeObjectURL(downloadUrl);
|
||||
|
||||
} catch (err) {
|
||||
console.error('Erro ao gerar ZIP:', err);
|
||||
await showCustomAlert('Erro', 'Não foi possível gerar o ZIP: ' + err.message);
|
||||
} finally {
|
||||
btnExportComicsZIP.disabled = false;
|
||||
btnExportComicsZIP.innerHTML = '<span>📦 Baixar Todas as Imagens (ZIP)</span>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- MODO APRESENTAÇÃO EM TELA CHEIA (LEITURA INFANTIL / MOBILE) ---
|
||||
const comicsPresModal = document.getElementById('comicsPresentationModal');
|
||||
const comicsPresTitle = document.getElementById('comicsPresTitle');
|
||||
const comicsPresImage = document.getElementById('comicsPresImage');
|
||||
const comicsPresCaption = document.getElementById('comicsPresCaption');
|
||||
const comicsPresCounter = document.getElementById('comicsPresCounter');
|
||||
const btnPresPrev = document.getElementById('btnPresPrev');
|
||||
const btnPresNext = document.getElementById('btnPresNext');
|
||||
const btnCloseComicsPresModal = document.getElementById('btnCloseComicsPresModal');
|
||||
const btnComicsPresentationMode = document.getElementById('btnComicsPresentationMode');
|
||||
|
||||
let presCurrentIndex = 0;
|
||||
|
||||
const openComicsPresentation = (index = 0) => {
|
||||
if (!generatedPanelsData || generatedPanelsData.length === 0) return;
|
||||
presCurrentIndex = Math.max(0, Math.min(index, generatedPanelsData.length - 1));
|
||||
if (comicsPresModal) comicsPresModal.style.display = 'flex';
|
||||
updateComicsPresentationView();
|
||||
};
|
||||
|
||||
const closeComicsPresentation = () => {
|
||||
if (comicsPresModal) comicsPresModal.style.display = 'none';
|
||||
};
|
||||
|
||||
const updateComicsPresentationView = () => {
|
||||
if (!generatedPanelsData || generatedPanelsData.length === 0) return;
|
||||
const panel = generatedPanelsData[presCurrentIndex];
|
||||
if (!panel) return;
|
||||
|
||||
if (comicsPresTitle) comicsPresTitle.textContent = comicsResultTitle?.textContent || 'Fábrica de Quadrinhos';
|
||||
if (comicsPresCounter) comicsPresCounter.textContent = `${presCurrentIndex + 1} / ${generatedPanelsData.length}`;
|
||||
if (comicsPresImage) comicsPresImage.src = panel.imageUrl || panel.image_url;
|
||||
if (comicsPresCaption) comicsPresCaption.textContent = panel.dialogue || '(História silenciosa)';
|
||||
|
||||
if (btnPresPrev) btnPresPrev.disabled = presCurrentIndex === 0;
|
||||
if (btnPresNext) btnPresNext.disabled = presCurrentIndex === generatedPanelsData.length - 1;
|
||||
};
|
||||
|
||||
if (btnComicsPresentationMode) {
|
||||
btnComicsPresentationMode.addEventListener('click', () => {
|
||||
openComicsPresentation(0);
|
||||
});
|
||||
}
|
||||
|
||||
if (btnPresPrev) {
|
||||
btnPresPrev.addEventListener('click', () => {
|
||||
if (presCurrentIndex > 0) {
|
||||
presCurrentIndex--;
|
||||
updateComicsPresentationView();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (btnPresNext) {
|
||||
btnPresNext.addEventListener('click', () => {
|
||||
if (presCurrentIndex < generatedPanelsData.length - 1) {
|
||||
presCurrentIndex++;
|
||||
updateComicsPresentationView();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (btnCloseComicsPresModal) {
|
||||
btnCloseComicsPresModal.addEventListener('click', closeComicsPresentation);
|
||||
}
|
||||
|
||||
// Teclado (setas) para o modo apresentação
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if (comicsPresModal && comicsPresModal.style.display === 'flex') {
|
||||
if (e.key === 'ArrowRight' || e.key === 'Space') {
|
||||
if (presCurrentIndex < generatedPanelsData.length - 1) {
|
||||
presCurrentIndex++;
|
||||
updateComicsPresentationView();
|
||||
}
|
||||
} else if (e.key === 'ArrowLeft') {
|
||||
if (presCurrentIndex > 0) {
|
||||
presCurrentIndex--;
|
||||
updateComicsPresentationView();
|
||||
}
|
||||
} else if (e.key === 'Escape') {
|
||||
closeComicsPresentation();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Touch Swipe para smartphones no modo apresentação
|
||||
let touchStartX = 0;
|
||||
if (comicsPresModal) {
|
||||
comicsPresModal.addEventListener('touchstart', (e) => {
|
||||
touchStartX = e.changedTouches[0].screenX;
|
||||
}, { passive: true });
|
||||
|
||||
comicsPresModal.addEventListener('touchend', (e) => {
|
||||
const touchEndX = e.changedTouches[0].screenX;
|
||||
const diff = touchEndX - touchStartX;
|
||||
if (Math.abs(diff) > 50) {
|
||||
if (diff < 0 && presCurrentIndex < generatedPanelsData.length - 1) {
|
||||
// Swipe para a esquerda -> Próximo
|
||||
presCurrentIndex++;
|
||||
updateComicsPresentationView();
|
||||
} else if (diff > 0 && presCurrentIndex > 0) {
|
||||
// Swipe para a direita -> Anterior
|
||||
presCurrentIndex--;
|
||||
updateComicsPresentationView();
|
||||
}
|
||||
}
|
||||
}, { passive: true });
|
||||
}
|
||||
|
||||
// Exportar PDF Retrato (1 por página)
|
||||
if (btnExportComicsPDFPortrait) {
|
||||
btnExportComicsPDFPortrait.addEventListener('click', async () => {
|
||||
|
||||
+75
-20
@@ -1400,9 +1400,10 @@
|
||||
|
||||
<!-- PERSONAGENS -->
|
||||
<div class="settings-group">
|
||||
<label style="color: var(--text-secondary); font-size: 0.82rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<label style="color: var(--text-secondary); font-size: 0.82rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 6px;">
|
||||
<span>5. Personagens da História</span>
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<div style="display: flex; gap: 6px; flex-wrap: wrap;">
|
||||
<button type="button" id="btnImportTurmaChars" class="btn-music-option" style="padding: 3px 8px; font-size: 0.72rem; border-color: #3b82f6; color: #60a5fa; background: rgba(59, 130, 246, 0.08); margin: 0;" title="Carregar crianças da turma atual como personagens">+ 🏫 Importar da Turma</button>
|
||||
<button type="button" id="btnAddHumanChar" class="btn-music-option" style="padding: 3px 8px; font-size: 0.72rem; border-color: var(--brand-pink); color: var(--brand-pink); background: rgba(219, 39, 119, 0.05); margin: 0;">+ 🧒 Humano</button>
|
||||
<button type="button" id="btnAddAnimalChar" class="btn-music-option" style="padding: 3px 8px; font-size: 0.72rem; border-color: var(--brand-pink); color: var(--brand-pink); background: rgba(219, 39, 119, 0.05); margin: 0;">+ 🐾 Animal</button>
|
||||
</div>
|
||||
@@ -1432,45 +1433,66 @@
|
||||
|
||||
<!-- BOTÃO DE AÇÃO -->
|
||||
<button id="btnGenerateComics" style="width: 100%; padding: 12px; background: var(--brand-pink, #db2777); color: white; border: none; border-radius: 10px; font-weight: 700; font-size: 1rem; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 8px; box-shadow: 0 4px 12px rgba(219, 39, 119, 0.3); transition: all 0.2s;">
|
||||
<span>🎨 Criar Quadrinhos Pedagógicos</span>
|
||||
<span>🎨 Criar Quadrinhos Pedagógicos (Geração Paralela ⚡)</span>
|
||||
</button>
|
||||
|
||||
<!-- LOADING DE QUADRINHOS -->
|
||||
<div id="comicsGenerateLoader" style="display: none; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 30px; background: var(--bg-secondary); border-radius: 12px; border: 1px dashed var(--border-light);">
|
||||
<div class="media-spinner" style="border-top-color: var(--brand-pink, #db2777);"></div>
|
||||
<p id="comicsLoaderText" style="color: var(--text-primary); font-weight: 600; font-size: 0.95rem; margin: 0; text-align: center;">Compondo a história pedagógica...</p>
|
||||
<div style="width: 100%; max-width: 250px; height: 6px; background: var(--border-light); border-radius: 3px; overflow: hidden;">
|
||||
<div id="comicsLoaderProgress" style="width: 0%; height: 100%; background: var(--brand-pink, #db2777); transition: width 0.4s ease;"></div>
|
||||
<div style="width: 100%; max-width: 320px; height: 8px; background: var(--border-light); border-radius: 4px; overflow: hidden;">
|
||||
<div id="comicsLoaderProgress" style="width: 0%; height: 100%; background: var(--brand-pink, #db2777); transition: width 0.3s ease;"></div>
|
||||
</div>
|
||||
<span id="comicsLoaderSubtext" style="font-size: 0.78rem; color: var(--text-muted);">Processando quadros em paralelo de alta performance...</span>
|
||||
</div>
|
||||
|
||||
<!-- RESULTADOS DA HISTÓRIA -->
|
||||
<div id="comicsResultArea" style="display: none; flex-direction: column; gap: 20px;">
|
||||
<!-- RESULTADOS DA HISTÓRIA (STORYBOARD STUDIO) -->
|
||||
<div id="comicsResultArea" style="display: none; flex-direction: column; gap: 18px;">
|
||||
|
||||
<h4 id="comicsResultTitle" style="font-family: 'Outfit', sans-serif; font-size: 1.15rem; color: var(--text-primary); margin: 0; text-align: center; font-weight: 700;">Título da História</h4>
|
||||
<!-- BARRA DE CABEÇALHO DO STORYBOARD -->
|
||||
<div style="display: flex; flex-direction: column; gap: 10px; background: var(--bg-secondary); padding: 14px 16px; border-radius: 10px; border: 1px solid var(--border-light);">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px;">
|
||||
<h4 id="comicsResultTitle" style="font-family: 'Outfit', sans-serif; font-size: 1.2rem; color: var(--text-primary); margin: 0; font-weight: 700;">Título da História</h4>
|
||||
<div style="display: flex; gap: 8px; flex-wrap: wrap;">
|
||||
<button type="button" id="btnComicsPresentationMode" class="btn-music-option" style="border-color: #8b5cf6; color: #a78bfa; background: rgba(139, 92, 246, 0.1); font-weight: 600; display: flex; align-items: center; gap: 6px; padding: 6px 14px;">
|
||||
<span>🎬 Apresentar em Tela Cheia</span>
|
||||
</button>
|
||||
<button type="button" id="btnExportComicsZIP" class="btn-music-option" style="border-color: #3b82f6; color: #60a5fa; background: rgba(59, 130, 246, 0.1); font-weight: 600; display: flex; align-items: center; gap: 6px; padding: 6px 14px;">
|
||||
<span>📦 Baixar Todas as Imagens (ZIP)</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CONTÊINER DOS QUADRINHOS -->
|
||||
<div id="comicsGridContainer" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px;">
|
||||
<!-- Gerado dinamicamente: quadrinhos com as imagens e balões de fala correspondentes -->
|
||||
<div id="comicsResultMeta" style="font-size: 0.78rem; color: var(--text-muted); display: flex; gap: 14px; flex-wrap: wrap; border-top: 1px dashed var(--border-light); padding-top: 8px;">
|
||||
<span>🤖 Criado por: <strong>PedagogIA</strong></span>
|
||||
<span id="comicsMetaPanels">🖼️ 5 Quadros</span>
|
||||
<span id="comicsMetaRatio">📐 16:9 HD</span>
|
||||
<span>✨ Dica: Você pode editar o texto dos balões ou regenerar qualquer quadrinho individualmente abaixo!</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- OPÇÕES DE EXPORTAÇÃO -->
|
||||
<!-- CONTÊINER DOS QUADRINHOS EM STORYBOARD -->
|
||||
<div id="comicsGridContainer" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: 18px;">
|
||||
<!-- Gerado dinamicamente: cards de quadrinhos interativos -->
|
||||
</div>
|
||||
|
||||
<!-- OPÇÕES DE EXPORTAÇÃO E VÍDEO -->
|
||||
<div style="background: var(--bg-secondary); padding: 16px; border-radius: 12px; border: 1px solid var(--border-light); display: flex; flex-direction: column; gap: 14px;">
|
||||
|
||||
<h5 style="margin: 0; font-size: 0.9rem; font-weight: 700; text-transform: uppercase; color: var(--text-secondary); letter-spacing: 0.5px;">📥 Opções de Exportação</h5>
|
||||
<h5 style="margin: 0; font-size: 0.9rem; font-weight: 700; text-transform: uppercase; color: var(--text-secondary); letter-spacing: 0.5px;">📥 Mais Formatos de Exportação</h5>
|
||||
|
||||
<!-- DOWNLOAD DE PDF -->
|
||||
<div style="display: flex; flex-direction: column; gap: 6px;">
|
||||
<span style="font-size: 0.8rem; font-weight: 600; color: var(--text-primary);">Salvar como Documento PDF:</span>
|
||||
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;">
|
||||
<button id="btnExportComicsPDFPortrait" class="btn-music-option" style="border-color: #10a37f; color: #10a37f; background: rgba(16, 163, 127, 0.05);">📄 PDF (1 por página - Retrato)</button>
|
||||
<button id="btnExportComicsPDFLandscape" class="btn-music-option" style="border-color: #10a37f; color: #10a37f; background: rgba(16, 163, 127, 0.05);">📄 PDF (2 por página - Paisagem)</button>
|
||||
<span style="font-size: 0.8rem; font-weight: 600; color: var(--text-primary);">Documento PDF para Impressão ou Registro Pedagógico:</span>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px;">
|
||||
<button id="btnExportComicsPDFPortrait" class="btn-music-option" style="border-color: #10a37f; color: #10a37f; background: rgba(16, 163, 127, 0.05); font-weight: 600;">📄 PDF (1 por página - Retrato A4)</button>
|
||||
<button id="btnExportComicsPDFLandscape" class="btn-music-option" style="border-color: #10a37f; color: #10a37f; background: rgba(16, 163, 127, 0.05); font-weight: 600;">📄 PDF (2 por página - Álbum Paisagem)</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- APRESENTAÇÃO EM VÍDEO -->
|
||||
<div style="display: flex; flex-direction: column; gap: 8px; border-top: 1px solid var(--border-light); padding-top: 14px;">
|
||||
<span style="font-size: 0.8rem; font-weight: 600; color: var(--text-primary);">Criar Apresentação de Vídeo Animada:</span>
|
||||
<span style="font-size: 0.8rem; font-weight: 600; color: var(--text-primary);">Criar Apresentação de Vídeo Animada com Música:</span>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
||||
<div class="settings-group" style="gap: 4px;">
|
||||
@@ -1492,7 +1514,7 @@
|
||||
</div>
|
||||
|
||||
<button id="btnCompileComicsVideo" style="padding: 10px; background: var(--brand-pink, #db2777); color: white; border: none; border-radius: 8px; font-weight: 600; font-size: 0.88rem; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 6px; transition: all 0.2s;">
|
||||
<span>🎬 Gerar Apresentação de Vídeo (MP4)</span>
|
||||
<span>🎬 Compilar Apresentação de Vídeo (MP4)</span>
|
||||
</button>
|
||||
|
||||
<!-- Spinner do Vídeo -->
|
||||
@@ -2036,7 +2058,40 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bibliotecas externas para renderizar markdown e blocos de código -->
|
||||
<!-- Modal: Apresentação em Tela Cheia dos Quadrinhos (Modo Leitura Infantil / Lousa / Mobile) -->
|
||||
<div id="comicsPresentationModal" class="comics-presentation-modal" style="display: none;">
|
||||
<div class="comics-pres-header">
|
||||
<div style="display: flex; align-items: center; gap: 10px;">
|
||||
<span style="font-size: 1.3rem;">📖</span>
|
||||
<h3 id="comicsPresTitle" style="margin: 0; font-family: 'Outfit', sans-serif; font-size: 1.1rem; color: #fff;">História em Quadrinhos</h3>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<span id="comicsPresCounter" style="background: rgba(255,255,255,0.15); padding: 4px 12px; border-radius: 20px; font-size: 0.85rem; font-weight: 700; color: #fef08a;">1 / 5</span>
|
||||
<button type="button" id="btnCloseComicsPresModal" style="background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2); color: white; width: 36px; height: 36px; border-radius: 50%; cursor: pointer; font-size: 1.2rem; display: flex; align-items: center; justify-content: center; transition: all 0.2s;">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="comics-pres-stage">
|
||||
<div class="comics-pres-card">
|
||||
<img id="comicsPresImage" class="comics-pres-img" src="" alt="Quadrinho em Apresentação">
|
||||
<div id="comicsPresCaption" class="comics-pres-caption">
|
||||
Falas do quadrinho aparecerão aqui...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="comics-pres-nav">
|
||||
<button type="button" id="btnPresPrev" class="btn-pres-nav">
|
||||
<span>⬅️ Anterior</span>
|
||||
</button>
|
||||
<button type="button" id="btnPresNext" class="btn-pres-nav" style="background: var(--brand-pink, #db2777); font-weight: 700;">
|
||||
<span>Próximo ➡️</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bibliotecas externas para renderizar markdown, PDFs e compactação ZIP -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.1/marked.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||||
|
||||
+219
-21
@@ -3358,22 +3358,22 @@ code {
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
FÁBRICA DE QUADRINHOS
|
||||
FÁBRICA DE QUADRINHOS — STORYBOARD STUDIO & PRESENTATION MODE
|
||||
========================================================================== */
|
||||
.comic-panel-card {
|
||||
position: relative;
|
||||
border: 3px solid #1e293b;
|
||||
background: var(--bg-secondary);
|
||||
box-shadow: 4px 4px 0px #1e293b;
|
||||
border-radius: 8px;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.2s;
|
||||
}
|
||||
.comic-panel-card:hover {
|
||||
transform: translate(-2px, -2px);
|
||||
box-shadow: 6px 6px 0px #1e293b;
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 6px 8px 0px #1e293b;
|
||||
}
|
||||
|
||||
.comic-panel-image-container {
|
||||
@@ -3396,51 +3396,103 @@ code {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.3s ease;
|
||||
display: block;
|
||||
}
|
||||
.comic-panel-card:hover .comic-panel-image {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.comic-panel-overlay-actions {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
z-index: 15;
|
||||
opacity: 0.9;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
.comic-panel-card:hover .comic-panel-overlay-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.btn-comic-action {
|
||||
background: rgba(15, 23, 42, 0.85);
|
||||
color: white;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
backdrop-filter: blur(4px);
|
||||
border-radius: 6px;
|
||||
padding: 4px 7px;
|
||||
font-size: 0.75rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
transition: background 0.2s, transform 0.1s;
|
||||
}
|
||||
.btn-comic-action:hover {
|
||||
background: var(--brand-pink, #db2777);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.comic-speech-bubble {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
background: white;
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border: 2px solid #1e293b;
|
||||
border-radius: 10px;
|
||||
padding: 4px 8px;
|
||||
font-size: 0.72rem;
|
||||
border-radius: 8px;
|
||||
padding: 6px 10px;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
max-width: 65%;
|
||||
box-shadow: 2px 2px 0px rgba(30, 41, 59, 0.15);
|
||||
box-shadow: 2px 2px 0px rgba(30, 41, 59, 0.2);
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.comic-panel-number-badge {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
background: #fef08a; /* Amarelo claro */
|
||||
background: #fef08a; /* Amarelo clássico gibi */
|
||||
color: #1e293b;
|
||||
font-weight: 800;
|
||||
font-size: 0.8rem;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 0.82rem;
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2px solid #1e293b;
|
||||
border-radius: 50%;
|
||||
z-index: 12;
|
||||
box-shadow: 1px 1px 0px #1e293b;
|
||||
box-shadow: 2px 2px 0px #1e293b;
|
||||
}
|
||||
|
||||
.comic-caption-text {
|
||||
padding: 10px 14px;
|
||||
padding: 10px 12px;
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.4;
|
||||
border-top: 1px solid var(--border-light);
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.comic-prompt-details {
|
||||
display: none;
|
||||
font-size: 0.72rem;
|
||||
color: var(--text-muted);
|
||||
background: var(--bg-secondary);
|
||||
padding: 6px 8px;
|
||||
border-radius: 6px;
|
||||
border: 1px dashed var(--border-light);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.btn-comics-qty.active, .btn-comics-bubbles.active, .btn-comics-ratio.active, .btn-comics-char.active {
|
||||
@@ -3448,7 +3500,113 @@ code {
|
||||
border-color: #db2777;
|
||||
color: #f472b6;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 0 8px rgba(219, 39, 119, 0.2);
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
MODO APRESENTAÇÃO / LEITURA (FULLSCREEN STORYBOARD)
|
||||
========================================================================== */
|
||||
.comics-presentation-modal {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 10000;
|
||||
background: rgba(10, 10, 15, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.comics-pres-header {
|
||||
width: 100%;
|
||||
max-width: 1000px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.comics-pres-stage {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
max-width: 960px;
|
||||
position: relative;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.comics-pres-card {
|
||||
max-width: 100%;
|
||||
max-height: 70vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background: #0f172a;
|
||||
border: 4px solid #334155;
|
||||
border-radius: 14px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.8);
|
||||
animation: comicFadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
.comics-pres-img {
|
||||
max-width: 100%;
|
||||
max-height: 55vh;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.comics-pres-caption {
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
color: #0f172a;
|
||||
padding: 16px 24px;
|
||||
box-sizing: border-box;
|
||||
font-size: 1.15rem;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
border-top: 3px solid #1e293b;
|
||||
font-family: 'Fredoka', 'Outfit', sans-serif;
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
|
||||
.comics-pres-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.btn-pres-nav {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
color: white;
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
padding: 10px 20px;
|
||||
border-radius: 30px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.btn-pres-nav:hover:not(:disabled) {
|
||||
background: var(--brand-pink, #db2777);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
.btn-pres-nav:disabled {
|
||||
opacity: 0.3;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
@keyframes comicFadeIn {
|
||||
from { opacity: 0; transform: scale(0.97); }
|
||||
to { opacity: 1; transform: scale(1); }
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
@@ -3635,6 +3793,46 @@ code {
|
||||
overflow-y: auto;
|
||||
padding: 8px 4px;
|
||||
}
|
||||
|
||||
/* Otimização Mobile para a Fábrica de Quadrinhos */
|
||||
#comicsGridContainer {
|
||||
grid-template-columns: 1fr !important;
|
||||
gap: 14px !important;
|
||||
}
|
||||
|
||||
.comic-panel-overlay-actions {
|
||||
opacity: 1 !important;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.btn-comic-action {
|
||||
padding: 6px 9px;
|
||||
font-size: 0.82rem;
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.comics-presentation-modal {
|
||||
padding: 12px 10px !important;
|
||||
}
|
||||
|
||||
.comics-pres-card {
|
||||
max-height: 75vh !important;
|
||||
border-width: 2px !important;
|
||||
}
|
||||
|
||||
.comics-pres-img {
|
||||
max-height: 46vh !important;
|
||||
}
|
||||
|
||||
.comics-pres-caption {
|
||||
font-size: 0.98rem !important;
|
||||
padding: 12px 14px !important;
|
||||
}
|
||||
|
||||
.btn-pres-nav {
|
||||
padding: 8px 16px !important;
|
||||
font-size: 0.9rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Estilos de progresso da IA (Chain of Thought/Etapas) */
|
||||
|
||||
Reference in New Issue
Block a user