BCM — Componente: Botão Gerar PDF

BCM — Botão "Gerar PDF"

Componente reutilizável para geração de PDF client-side via html2pdf.js. Inclui: botão flutuante fixo, variante inline, estado de loading animado, marca d'água de rodapé, e CSS de impressão otimizado para o design system do projeto.

Para usar em qualquer página: copie o bloco <!-- BCM PDF BUTTON --> e cole antes do </body> de qualquer página.

Variantes do botão

O botão flutuante fica fixo no canto inferior direito. Ao clicar, entra em estado de loading com animação de progresso, gera o PDF com html2pdf.js e faz o download automaticamente.

Padrão (flutuante)
Loading (durante geração)
Sucesso

1. Dependência — html2pdf.js via CDN

Adicione esta linha no <head> da página, após as fontes Google:

<!-- html2pdf.js — geração de PDF client-side --> <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js" integrity="sha512-GsLlZN/3F2ErC5ifS5QtgpiJtWd43JWSuIgh7mbzc1x2gSR/QolHkoxzdjo7mwoLMmJDsXC1UYn3ev/xPBBKA==" crossorigin="anonymous"></script>

2. Cole este bloco completo antes do </body>

Substitua {{TITULO_DA_PAGINA}} pelo título real de cada página (ex.: "Linha do Tempo", "Ataques ao BCM").

<!-- ════════════════════════════════════════ BCM PDF BUTTON — Componente v1.0 Colar antes de </body> em qualquer página Substituir {{TITULO_DA_PAGINA}} pelo título real ════════════════════════════════════════ --> <!-- CSS do botão --> <style> .bcm-pdf-btn { position: fixed; bottom: 32px; right: 32px; z-index: 8000; display: flex; align-items: center; gap: 10px; background: var(--s900); border: 1px solid var(--s600); border-radius: 40px; padding: 10px 20px 10px 14px; cursor: pointer; font-family: var(--font-body); box-shadow: 0 4px 24px rgba(30,18,10,.28), 0 1px 4px rgba(30,18,10,.18); transition: all 0.2s cubic-bezier(0.25,0.46,0.45,0.94); /* Separador decorativo vertical */ outline: none; text-decoration: none; -webkit-font-smoothing: antialiased; } .bcm-pdf-btn:hover { background: var(--s800); border-color: var(--s400); box-shadow: 0 8px 32px rgba(30,18,10,.36), 0 2px 8px rgba(30,18,10,.22); transform: translateY(-2px); } .bcm-pdf-btn:active { transform: translateY(0); box-shadow: 0 2px 8px rgba(30,18,10,.2); } .bcm-pdf-btn-icon { width: 36px; height: 36px; background: var(--s600); border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-shrink: 0; color: var(--s100); transition: background 0.2s; } .bcm-pdf-btn:hover .bcm-pdf-btn-icon { background: var(--s500); } .bcm-pdf-btn-label { font-size: 13px; font-weight: 500; color: var(--white); letter-spacing: 0.04em; line-height: 1; display: block; } .bcm-pdf-btn-sub { font-size: 10px; color: var(--s400); letter-spacing: 0.08em; text-transform: uppercase; display: block; margin-top: 2px; } /* ── Estado loading ── */ .bcm-pdf-btn.bcm-pdf-loading { background: var(--s800); border-color: var(--s700); cursor: not-allowed; pointer-events: none; } .bcm-pdf-btn.bcm-pdf-loading .bcm-pdf-btn-icon { background: var(--s700); } .bcm-pdf-btn.bcm-pdf-loading .bcm-pdf-btn-label { color: var(--s300); } /* ── Estado sucesso ── */ .bcm-pdf-btn.bcm-pdf-success { background: #1A3A1A; border-color: #2A5A2A; pointer-events: none; } .bcm-pdf-btn.bcm-pdf-success .bcm-pdf-btn-icon { background: #2A5A2A; color: #A8D8A8; } /* ── Spinner ── */ @keyframes bcm-spin { to { transform: rotate(360deg); } } .bcm-spin { animation: bcm-spin 1s linear infinite; transform-origin: center; } /* ── Tooltip de teclado ── */ .bcm-pdf-btn::after { content: 'P'; position: absolute; top: -8px; right: 12px; background: var(--s600); color: var(--s100); font-size: 9px; font-weight: 700; letter-spacing: 0.1em; padding: 1px 5px; border-radius: 2px; opacity: 0; transition: opacity 0.2s; pointer-events: none; } .bcm-pdf-btn:focus::after, .bcm-pdf-btn:hover::after { opacity: 1; } /* ── Responsivo: compacto em mobile ── */ @media (max-width: 600px) { .bcm-pdf-btn { bottom: 20px; right: 16px; padding: 10px 14px; border-radius: 50%; width: 52px; height: 52px; justify-content: center; } .bcm-pdf-btn-label, .bcm-pdf-btn-sub { display: none; } .bcm-pdf-btn-icon { margin: 0; } } /* ── CSS de IMPRESSÃO — oculta UI, formata para A4 ── */ @media print { .bcm-pdf-btn, .topbar, .main-nav, .trilha-bar, .stats-bar, .site-footer, .bcm-search-overlay { display: none !important; } body { background: #fff !important; color: #000 !important; } .page-header { width: 100% !important; left: 0 !important; margin-left: 0 !important; break-after: avoid; } .evento-card, .ataque-body, .bcm-tese, .bcm-panel { break-inside: avoid; } a[href]::after { content: none !important; } } </style> <!-- HTML do botão --> <button class="bcm-pdf-btn" id="bcmPdfBtn" onclick="bcmPDF.gerar()" aria-label="Gerar PDF desta página" title="Gerar PDF (tecla P)" type="button"> <span class="bcm-pdf-btn-icon" aria-hidden="true"> <svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.6" viewBox="0 0 24 24"> <path d="M12 3v13M5 14l7 7 7-7"/> <rect x="3" y="19" width="18" height="2" rx="1" fill="currentColor" stroke="none"/> </svg> </span> <span class="bcm-pdf-btn-label">Gerar PDF</span> <span class="bcm-pdf-btn-sub" id="bcmPdfSub">desta página</span> </button> <!-- Script de geração --> <script> (function(){ 'use strict'; // ▶ CONFIGURAÇÃO — alterar por página const CONFIG = { titulo: '{{TITULO_DA_PAGINA}}', // ex.: 'Linha do Tempo' subtitulo: 'verdadeirahistoriadabarra.com.br', supervisor:'Supervisão: Mattos & Mattos Advogados · OAB/RJ 188.310 e 144.717', seletor: 'body', // elemento a capturar (pode ser 'main', '.page-wrap', etc.) arquivo: '{{TITULO_DA_PAGINA}}', // nome do arquivo (sem .pdf) }; const btn = document.getElementById('bcmPdfBtn'); const subLabel = document.getElementById('bcmPdfSub'); const iconWrap = btn ? btn.querySelector('.bcm-pdf-btn-icon') : null; const labelEl = btn ? btn.querySelector('.bcm-pdf-btn-label') : null; // Ícones SVG reutilizáveis const ICON_DOWNLOAD = ` `; const ICON_SPIN = ` `; const ICON_CHECK = ` `; function setEstado(estado) { if (!btn) return; btn.classList.remove('bcm-pdf-loading', 'bcm-pdf-success'); if (estado === 'loading') { btn.classList.add('bcm-pdf-loading'); btn.disabled = true; if (iconWrap) iconWrap.innerHTML = ICON_SPIN; if (labelEl) labelEl.textContent = 'Gerando…'; if (subLabel) subLabel.textContent = 'Preparando'; } else if (estado === 'success') { btn.classList.add('bcm-pdf-success'); if (iconWrap) iconWrap.innerHTML = ICON_CHECK; if (labelEl) labelEl.textContent = 'PDF gerado!'; if (subLabel) subLabel.textContent = 'Download iniciado'; } else { btn.disabled = false; if (iconWrap) iconWrap.innerHTML = ICON_DOWNLOAD; if (labelEl) labelEl.textContent = 'Gerar PDF'; if (subLabel) subLabel.textContent = 'desta página'; } } function progresso(msg) { if (subLabel) subLabel.textContent = msg; } async function gerar() { // Verificar se html2pdf está carregado if (typeof html2pdf === 'undefined') { alert('A biblioteca html2pdf.js não foi carregada. Verifique a tag