chore: remove unused assets and polyfills, add puppeteer for CMYK export automation

This commit is contained in:
Lucas Rayan committed 2026-08-23 12:19:21 -03:00
1 parent 37971056c2
commit 8ad99a971d
15 files changed
+918 -6

No files matched your search

File renamed without changes.
@@ -1960,12 +1960,147 @@ Temperatura: 26.1 C | Umidade: 62.0 %</code></pre>
</p>
</section>
<!-- ══════════════════════ PAINEL DE EXPORTAÇÃO ══════════════════════ -->
<div class="painel-exportacao" id="painelExportacao" style="position: fixed !important; top: 18px !important; right: 20px !important; z-index: 999999 !important; display: flex !important;">
<span class="painel-exportacao-titulo">
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6 9 6 2 18 2 18 9"></polyline>
<path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path>
<rect x="6" y="14" width="12" height="8"></rect>
</svg>
Apostila:
</span>
<button type="button" class="btn-exportar btn-exportar-rgb" id="btnExportarRgb" title="Imprimir ou Salvar em PDF (padrão RGB do navegador)">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
<span>Exportar PDF</span>
</button>
<button type="button" class="btn-exportar btn-exportar-cmyk" id="btnExportarCmyk" title="Exportar PDF convertido para espaço de cor CMYK (ISO Coated) para gráfica">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"></path>
<path d="M2 12h20"></path>
</svg>
<span>Exportar em CMYK</span>
</button>
</div>
<div class="toast-exportacao" id="toastExportacao" style="position: fixed !important; bottom: 24px !important; right: 24px !important; z-index: 1000000 !important;"></div>
<script>
// Tira o aviso do fluxo antes da paginação começar, senão o Paged.js o
// trataria como conteúdo e ele apareceria impresso na primeira página.
let paginacaoConcluida = false;
const painelExportacao = document.getElementById("painelExportacao");
const toastExportacao = document.getElementById("toastExportacao");
function fixarPainelNaTela() {
if (painelExportacao) {
painelExportacao.style.cssText = "position: fixed !important; top: 18px !important; right: 20px !important; z-index: 999999 !important; display: flex !important;";
if (!document.body.contains(painelExportacao)) {
document.body.appendChild(painelExportacao);
}
}
if (toastExportacao) {
toastExportacao.style.cssText = "position: fixed !important; bottom: 24px !important; right: 24px !important; z-index: 1000000 !important;";
if (!document.body.contains(toastExportacao)) {
document.body.appendChild(toastExportacao);
}
}
}
window.PagedConfig = {
before: () => document.querySelector(".aviso-carregando")?.remove(),
before: () => {
document.querySelector(".aviso-carregando")?.remove();
// Remove do fluxo do DOM para o Paged.js não paginar como conteúdo
painelExportacao?.remove();
toastExportacao?.remove();
},
after: () => {
paginacaoConcluida = true;
document.body.classList.add("pagedjs-pronto");
fixarPainelNaTela();
}
};
// Oculta painel na impressão nativa
window.addEventListener("beforeprint", () => {
if (painelExportacao) painelExportacao.style.setProperty("display", "none", "important");
if (toastExportacao) toastExportacao.style.setProperty("display", "none", "important");
});
window.addEventListener("afterprint", () => {
if (painelExportacao) painelExportacao.style.setProperty("display", "flex", "important");
});
function exibirToast(mensagem, tipo = "info", duracao = 4000) {
const toast = document.getElementById("toastExportacao") || toastExportacao;
if (!toast) return;
if (!document.body.contains(toast)) document.body.appendChild(toast);
toast.textContent = mensagem;
toast.className = `toast-exportacao ativo ${tipo}`;
clearTimeout(toast._timer);
toast._timer = setTimeout(() => {
toast.classList.remove("ativo");
}, duracao);
}
document.addEventListener("click", async (e) => {
const btnRgb = e.target.closest("#btnExportarRgb");
const btnCmyk = e.target.closest("#btnExportarCmyk");
if (btnRgb) {
if (!paginacaoConcluida) {
exibirToast("Aguarde a paginação terminar antes de exportar...", "info", 2500);
return;
}
window.print();
}
if (btnCmyk) {
const textoOriginal = btnCmyk.innerHTML;
try {
btnCmyk.disabled = true;
btnCmyk.classList.add("carregando");
btnCmyk.innerHTML = `<span class="spinner-exportar"></span><span>Convertendo CMYK...</span>`;
exibirToast("Gerando PDF e convertendo para CMYK (ISO Coated)... Aguarde alguns segundos.", "info", 8000);
const resposta = await fetch("/api/export-cmyk?modulo=1");
if (!resposta.ok) {
const erroJson = await resposta.json().catch(() => null);
throw new Error(erroJson?.error || "Serviço de conversão indisponível no momento.");
}
const blob = await resposta.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.style.display = "none";
a.href = url;
a.download = "LASER-ESP32-Modulo-1-CMYK.pdf";
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
a.remove();
exibirToast("✅ PDF em CMYK gerado e baixado com sucesso!", "sucesso", 5000);
} catch (erro) {
console.warn("Erro ao gerar CMYK via API:", erro);
exibirToast(
"💡 Dica: execute 'npm run exportar-cmyk 1' no terminal para gerar o arquivo CMYK imediatamente!",
"erro",
7000
);
} finally {
btnCmyk.disabled = false;
btnCmyk.classList.remove("carregando");
btnCmyk.innerHTML = textoOriginal;
}
}
});
</script>
<script src="../assets/paged.polyfill.js"></script>
</body>
File renamed without changes.
File renamed without changes.
@@ -665,6 +665,237 @@ figcaption {
}
}
@media print {
.aviso-carregando { display: none; }
/* -------------------------------------------------------------------------
8. Barra Flutuante de Exportação e Impressão (Apenas em Tela)
------------------------------------------------------------------------- */
.painel-exportacao {
position: fixed !important;
top: 18px !important;
right: 20px !important;
z-index: 999999 !important;
display: flex !important;
align-items: center;
gap: 10px;
background: rgba(6, 38, 57, 0.92);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
padding: 6px 10px;
border-radius: 9999px;
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow:
0 8px 30px rgba(0, 0, 0, 0.4),
0 0 0 1px rgba(0, 0, 0, 0.2);
transition: opacity 0.2s ease, transform 0.2s ease;
}
.painel-exportacao.oculto {
opacity: 0;
pointer-events: none;
transform: translateY(-8px);
}
.painel-exportacao-titulo {
font-family: "Inter", sans-serif;
font-size: 11px;
font-weight: 600;
color: #94a3b8;
padding: 0 4px 0 6px;
letter-spacing: 0.02em;
display: flex;
align-items: center;
gap: 5px;
}
.btn-exportar {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 13px;
border-radius: 9999px;
font-family: "Inter", sans-serif;
font-size: 11.5px;
font-weight: 600;
cursor: pointer;
border: none;
outline: none;
text-decoration: none;
transition: all 0.18s cubic-bezier(0.16, 1, 0.3, 1);
white-space: nowrap;
user-select: none;
}
.btn-exportar svg {
width: 14px;
height: 14px;
flex-shrink: 0;
}
.btn-exportar-rgb {
background: rgba(255, 255, 255, 0.12);
color: #f1f5f9;
border: 1px solid rgba(255, 255, 255, 0.18);
}
.btn-exportar-rgb:hover {
background: rgba(255, 255, 255, 0.2);
color: #ffffff;
transform: translateY(-1px);
}
.btn-exportar-rgb:active {
transform: translateY(0);
background: rgba(255, 255, 255, 0.1);
}
.btn-exportar-cmyk {
background: linear-gradient(135deg, #F77F00, #D62828);
color: #ffffff;
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 2px 10px rgba(214, 40, 40, 0.35);
}
.btn-exportar-cmyk:hover {
background: linear-gradient(135deg, #ff911a, #e63939);
box-shadow: 0 4px 14px rgba(214, 40, 40, 0.5);
transform: translateY(-1px);
}
.btn-exportar-cmyk:active {
transform: translateY(0);
box-shadow: 0 1px 4px rgba(214, 40, 40, 0.3);
}
.btn-exportar:disabled,
.btn-exportar.carregando {
opacity: 0.75;
cursor: wait;
pointer-events: none;
}
.spinner-exportar {
width: 13px;
height: 13px;
border: 2px solid rgba(255, 255, 255, 0.35);
border-top-color: #ffffff;
border-radius: 50%;
animation: girar-spinner 0.75s linear infinite;
}
@keyframes girar-spinner {
to { transform: rotate(360deg); }
}
/* Toast de notificação de exportação */
.toast-exportacao {
position: fixed;
bottom: 24px;
right: 24px;
z-index: 10001;
background: #062639;
color: #e2e8f0;
border: 1px solid #33566a;
padding: 10px 16px;
border-radius: 8px;
font-family: "Inter", sans-serif;
font-size: 12px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.4);
display: flex;
align-items: center;
gap: 10px;
transition: all 0.3s ease;
opacity: 0;
transform: translateY(12px);
pointer-events: none;
}
.toast-exportacao.ativo {
opacity: 1;
transform: translateY(0);
pointer-events: auto;
}
.toast-exportacao.sucesso { border-color: #10b981; }
.toast-exportacao.erro { border-color: #ef4444; }
/* -------------------------------------------------------------------------
9. Regras Especiais para Impressão Física e Geração de PDF (@media print)
------------------------------------------------------------------------- */
@media print {
.aviso-carregando {
display: none !important;
}
/*
BLOCO DE CÓDIGO - TEMA CLARO DE ALTO CONTRASTE
Elimina o fundo escuro pesado no papel e resolve o problema de
sangria de tinta (dot gain) que engolia as letras.
*/
pre {
background: #f8fafc !important;
border: 0.35mm solid #cbd5e1 !important;
color: #0f172a !important;
box-shadow: none !important;
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
}
pre code {
background: transparent !important;
border: none !important;
padding: 0 !important;
color: #0f172a !important;
font-weight: 500 !important;
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
}
pre span {
background: transparent !important;
border: none !important;
padding: 0 !important;
}
/* Cores de sintaxe de alta densidade e seguras para CMYK/P&B */
.c-com {
color: #475569 !important;
font-style: italic !important;
}
.c-key {
color: #6b21a8 !important;
font-weight: 600 !important;
}
.c-fun {
color: #0369a1 !important;
font-weight: 600 !important;
}
.c-str {
color: #15803d !important;
}
.c-num {
color: #b45309 !important;
font-weight: 600 !important;
}
.c-pre {
color: #be185d !important;
font-weight: 600 !important;
}
/* Código inline (apenas fora do pre) */
:not(pre) > code {
background: #f1f5f9 !important;
color: #9a3412 !important;
border: 0.2mm solid #cbd5e1 !important;
padding: 0.4mm 1.2mm !important;
border-radius: 1mm !important;
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
}
}
File renamed without changes.