Skip to content

Instantly share code, notes, and snippets.

@shuantsu
Created April 15, 2026 19:23
Show Gist options
  • Select an option

  • Save shuantsu/7c103961ebc71a60caed8b39f530342f to your computer and use it in GitHub Desktop.

Select an option

Save shuantsu/7c103961ebc71a60caed8b39f530342f to your computer and use it in GitHub Desktop.
Programação diária estudo de A Sentinela
(function() {
const article = document.querySelector('#article');
const body = document.querySelector('.bodyTxt');
// 1. EXTRAÇÃO DOS BLOCOS ORIGINAIS
const blocosBase = [];
let currentSub = "Introdução";
Array.from(body.querySelectorAll('h2, p.qu')).forEach(el => {
if (el.tagName === 'H2') {
currentSub = el.textContent.trim();
} else {
const rawNum = el.querySelector('strong')?.textContent || el.textContent;
const match = rawNum.match(/^[\d\s\-,.]+/);
const pGroup = match ? match[0].replace(/[.\s]/g, '') : "N/A";
let peso = 1;
if (pGroup.includes('-')) {
const parts = pGroup.split('-');
peso = parseInt(parts[1]) - parseInt(parts[0]) + 1;
} else if (pGroup.includes(',')) {
peso = pGroup.split(',').length;
}
const primeiroPar = parseInt(pGroup.split(/[-,]/)[0]);
blocosBase.push({
subtitulo: currentSub,
displayNum: pGroup,
primeiroPar: primeiroPar,
pergunta: el.textContent.replace(/^[\d\s\-,.]+/ , '').trim(),
peso: peso
});
}
});
// 2. INTERFACE OTIMIZADA PARA PDF
const win = window.open("", "_blank");
win.document.write(`
<html>
<head>
<title>Planner Sentinela - PDF Friendly</title>
<style>
/* Estilos de Tela */
body { font-family: 'Segoe UI', system-ui, sans-serif; background: #f0f2f5; margin: 0; display: flex; height: 100vh; }
#sidebar { width: 340px; background: #232f3e; color: white; padding: 25px; overflow-y: auto; box-shadow: 4px 0 10px rgba(0,0,0,0.1); flex-shrink: 0; }
#content { flex: 1; padding: 40px; overflow-y: auto; }
.control-item { margin-bottom: 25px; }
label { display: block; margin-bottom: 8px; font-weight: 600; font-size: 12px; color: #aab7c4; text-transform: uppercase; }
select, input { width: 100%; padding: 12px; border-radius: 6px; border: 1px solid #3e4f5f; background: #2d3d4d; color: white; font-size: 14px; outline: none; }
#calendar-container { margin-top: 30px; background: #1b2633; padding: 15px; border-radius: 8px; border: 1px solid #3e4f5f; }
#calendar-header { font-size: 14px; font-weight: bold; text-align: center; margin-bottom: 10px; color: #3498db; text-transform: uppercase; }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; text-align: center; font-size: 11px; }
.cal-day-name { font-weight: bold; color: #8492a6; }
.cal-day { padding: 5px 0; border-radius: 4px; color: #bdc3c7; }
.cal-today { background: #3498db; color: white; font-weight: bold; }
.dia-card { background: white; border-radius: 12px; padding: 25px; margin-bottom: 25px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); border-left: 10px solid #3498db; page-break-inside: avoid; }
.dia-num { font-size: 1.4em; font-weight: 800; color: #1a2a3a; margin-bottom: 15px; border-bottom: 2px solid #f0f0f0; padding-bottom: 10px; display: flex; justify-content: space-between; }
.sub-header { color: #d35400; font-weight: bold; font-size: 12px; text-transform: uppercase; margin: 20px 0 10px 0; display: block; background: #fff5eb; padding: 4px 8px; border-radius: 4px; }
.par-item { padding: 10px 0; border-bottom: 1px solid #f9f9f9; font-size: 15px; color: #2c3e50; display: flex; gap: 10px; }
.par-num { font-weight: bold; color: #3498db; min-width: 45px; }
.count-tag { background: #3498db; color: white; padding: 4px 12px; border-radius: 20px; font-size: 13px; }
/* REGRAS DE IMPRESSÃO (PDF) */
@media print {
body { background: white !important; display: block !important; height: auto !important; }
#sidebar { display: none !important; }
#content { padding: 0 !important; width: 100% !important; overflow: visible !important; }
.dia-card {
box-shadow: none !important;
border: 1px solid #ddd !important;
border-left: 10px solid #3498db !important;
page-break-inside: avoid !important;
margin-bottom: 20px !important;
}
.sub-header { background: #eee !important; color: black !important; -webkit-print-color-adjust: exact; }
.count-tag { border: 1px solid #3498db !important; color: #3498db !important; background: transparent !important; }
h1 { font-size: 18pt !important; margin-bottom: 20px !important; }
}
</style>
</head>
<body>
<div id="sidebar">
<h2 style="margin-top:0; color:#3498db; font-size: 22px;">Planner Dinâmico</h2>
<p style="font-size: 11px; color: #8492a6;">Ajuste os filtros e aperte <b>Ctrl + P</b> para salvar em PDF.</p>
<div class="control-item">
<label>Começar do parágrafo:</label>
<input type="number" id="startPar" value="1" min="1">
</div>
<div class="control-item">
<label>Dias Restantes (N)</label>
<input type="number" id="inputDias" value="6" min="1">
</div>
<div class="control-item">
<label>Fluxo de Subtítulos</label>
<select id="splitSubtitles">
<option value="keep">Finalizar Dia no Subtítulo</option>
<option value="split">Dividir Subtítulo</option>
</select>
</div>
<div id="calendar-container">
<div id="calendar-header"></div>
<div class="cal-grid" id="calendar-grid"></div>
</div>
</div>
<div id="content">
<h1 style="margin-top:0; color: #232f3e;">${article.querySelector('h1')?.textContent.trim()}</h1>
<div id="display"></div>
</div>
<script>
const dadosOriginais = ${JSON.stringify(blocosBase)};
function buildCalendar() {
const now = new Date();
const monthNames = ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"];
document.getElementById('calendar-header').innerText = monthNames[now.getMonth()] + " " + now.getFullYear();
const grid = document.getElementById('calendar-grid');
grid.innerHTML = '';
['D', 'S', 'T', 'Q', 'Q', 'S', 'S'].forEach(d => {
const div = document.createElement('div'); div.className = 'cal-day-name'; div.innerText = d; grid.appendChild(div);
});
const firstDay = new Date(now.getFullYear(), now.getMonth(), 1).getDay();
const daysInMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate();
for (let i = 0; i < firstDay; i++) grid.appendChild(document.createElement('div'));
for (let d = 1; d <= daysInMonth; d++) {
const div = document.createElement('div');
div.className = 'cal-day' + (d === now.getDate() ? ' cal-today' : '');
div.innerText = d; grid.appendChild(div);
}
}
function calcular() {
const startingAt = parseInt(document.getElementById('startPar').value) || 1;
const nDias = parseInt(document.getElementById('inputDias').value) || 1;
const subModo = document.getElementById('splitSubtitles').value;
const filtrados = dadosOriginais.filter(b => {
if (b.displayNum.includes('-')) return parseInt(b.displayNum.split('-')[1]) >= startingAt;
return b.primeiroPar >= startingAt;
});
const cronograma = Array.from({ length: nDias }, () => []);
const totalPeso = filtrados.reduce((acc, b) => acc + b.peso, 0);
const metaDia = totalPeso / nDias;
let diaAtual = 0, pesoAcumulado = 0;
filtrados.forEach((bloco, index) => {
cronograma[diaAtual].push(bloco);
pesoAcumulado += bloco.peso;
if (diaAtual < nDias - 1) {
let trocar = false;
const atingiuMeta = pesoAcumulado >= (metaDia * 0.85);
if (subModo === 'keep') {
const prox = filtrados[index+1];
if (prox && bloco.subtitulo !== prox.subtitulo && (atingiuMeta || pesoAcumulado > metaDia * 0.5)) trocar = true;
else if (pesoAcumulado > metaDia * 1.5) trocar = true;
} else if (atingiuMeta) trocar = true;
if (trocar) { diaAtual++; pesoAcumulado = 0; }
}
});
render(cronograma);
}
function render(cronograma) {
const container = document.getElementById('display');
container.innerHTML = '';
cronograma.forEach((dia, i) => {
if (dia.length === 0) return;
const diaDiv = document.createElement('div');
diaDiv.className = 'dia-card';
const totalP = dia.reduce((acc, b) => acc + b.peso, 0);
let html = '<div class="dia-num"><span>Dia ' + (i+1) + '</span><span class="count-tag">' + totalP + ' parágrafos</span></div>';
let lastSub = "";
dia.forEach(b => {
if (b.subtitulo !== lastSub) {
html += '<span class="sub-header">' + b.subtitulo + '</span>';
lastSub = b.subtitulo;
}
html += '<div class="par-item"><span class="par-num">§ ' + b.displayNum + '</span><span>' + b.pergunta + '</span></div>';
});
diaDiv.innerHTML = html;
container.appendChild(diaDiv);
});
}
document.querySelectorAll('input, select').forEach(el => el.addEventListener('input', calcular));
buildCalendar();
calcular();
</script>
</body>
</html>
`);
win.document.close();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment