chore: remove unused assets and polyfills, add puppeteer for CMYK export automation
This commit is contained in:
1 parent
37971056c2
commit
8ad99a971d
15 files changed
+918
-6
No files matched your search
File renamed without changes.
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.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Reference in new issue
Block a user