feat: redesign process-résumé panel, fix hover tooltip scrollbars, open résumé from table view

This commit is contained in:
2026-09-13 13:53:21 +02:00
parent 24a2676859
commit b9eb6d441e
+56 -29
View File
@@ -138,6 +138,7 @@
font:inherit; font-size:12.5px; padding:7px 12px; border-radius:8px; cursor:pointer;
}
.dropdown-btn:hover{ border-color:var(--accent); color:var(--ink); }
.dropdown-btn:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.dropdown-btn .arrow{ font-size:10px; opacity:.6; }
.dropdown-btn[aria-expanded="true"]{ border-color:var(--accent); background:var(--accent-wash); color:var(--ink); }
.dropdown-btn .tag{ background:var(--accent); color:#fff; border-radius:999px; font-size:10.5px; padding:1px 6px; }
@@ -156,6 +157,7 @@
border:0; background:none; color:var(--accent); font:inherit; font-size:12px; cursor:pointer; padding:0;
}
.dropdown-actions button:hover{ text-decoration:underline; }
.dropdown-actions button:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; border-radius:3px; }
.dropdown-list{ max-height:260px; overflow-y:auto; display:flex; flex-direction:column; gap:1px; }
.type-row{
display:flex; align-items:center; gap:8px; padding:5px 4px; border-radius:6px; cursor:pointer; font-size:12.5px;
@@ -173,6 +175,8 @@
border:1px solid var(--border); background:var(--page); color:var(--ink-2);
font:inherit; font-size:11px; padding:3px 8px; border-radius:999px; cursor:pointer;
}
.role-chip:hover{ border-color:var(--accent); color:var(--ink); }
.role-chip:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.role-chip[aria-pressed="true"]{ background:var(--accent-wash); border-color:var(--accent); color:var(--ink); }
.type-row .role-badge{
flex:none; font-size:10px; color:var(--ink-3); background:var(--page);
@@ -185,10 +189,13 @@
.segmented{ display:flex; border:1px solid var(--border); border-radius:8px; overflow:hidden; }
.segmented button{
border:0; background:var(--surface); color:var(--ink-2); font:inherit; font-size:12.5px;
padding:7px 12px; cursor:pointer;
padding:7px 12px; cursor:pointer; transition:background .15s ease, color .15s ease;
}
.segmented button + button{ border-left:1px solid var(--border); }
.segmented button:hover{ background:var(--accent-wash); color:var(--ink); }
.segmented button:focus-visible{ outline:2px solid var(--accent); outline-offset:-2px; }
.segmented button[aria-pressed="true"]{ background:var(--accent); color:#fff; }
.segmented button[aria-pressed="true"]:hover{ background:var(--accent); }
.presets{ display:flex; gap:6px; }
.presets button{
@@ -196,6 +203,7 @@
font:inherit; font-size:12.5px; padding:6px 10px; border-radius:7px; cursor:pointer;
}
.presets button:hover{ border-color:var(--accent); color:var(--ink); }
.presets button:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.presets button[aria-pressed="true"]{ background:var(--accent-wash); border-color:var(--accent); color:var(--ink); }
label.check{ display:flex; align-items:center; gap:6px; font-size:12.5px; color:var(--ink-2); cursor:pointer; }
@@ -229,7 +237,6 @@
border-radius:999px; padding:2px 9px; margin-bottom:10px;
}
.resumo-text{ font-size:13.5px; line-height:1.6; color:var(--ink); margin:0 0 14px; }
.resumo-block{ margin-top:12px; padding-top:12px; border-top:1px solid var(--grid); }
.resumo-label{ font-size:11px; text-transform:uppercase; letter-spacing:.06em; color:var(--ink-3); margin-bottom:6px; }
.resumo-people{ display:flex; flex-wrap:wrap; gap:5px; }
.resumo-people span{
@@ -239,15 +246,15 @@
.resumo-file{ font-size:10.5px; color:var(--ink-3); line-height:1.5; overflow-wrap:anywhere; }
.resumo-processo-btn{
width:100%; text-align:left; font:inherit; font-size:12.5px; font-weight:600; color:var(--accent);
width:100%; text-align:center; font:inherit; font-size:12.5px; font-weight:600; color:var(--accent);
background:var(--accent-wash); border:1px solid var(--border); border-radius:8px; padding:8px 10px;
cursor:pointer;
cursor:pointer; margin-top:12px;
}
.resumo-processo-btn:hover{ border-color:var(--accent); }
#resumoProcessoNum{ display:block; text-align:center; margin-top:2px; }
.resumo-processo-content{
margin-top:10px; max-height:46vh; overflow-y:auto; overflow-wrap:anywhere; font-size:12px;
line-height:1.55; color:var(--ink-2);
margin-top:14px; max-height:60vh; overflow-y:auto; overflow-wrap:anywhere;
font-size:14px; line-height:1.65; color:var(--ink-2);
background:var(--surface); border:1px solid var(--border); border-radius:12px; padding:16px 18px;
}
.resumo-processo-content h1, .resumo-processo-content h2, .resumo-processo-content h3{
font-family:"Source Serif 4",serif; color:var(--ink); margin:12px 0 4px; line-height:1.3;
@@ -298,7 +305,10 @@
}
.selection-ring{ border:2px solid var(--accent); box-shadow:0 0 0 3px var(--accent-wash); }
#tooltip{
position:absolute; pointer-events:none; max-width:320px; z-index:5;
/* fixed (not absolute-in-wrap) so a tall/near-edge tooltip overlays the
page instead of expanding .detail-card's scrollable box and popping a
scrollbar */
position:fixed; pointer-events:none; max-width:320px; z-index:5;
background:var(--surface); border:1px solid var(--border); border-radius:9px;
box-shadow:0 6px 20px rgba(0,0,0,.16); padding:10px 12px; font-size:12.5px;
color:var(--ink-2); line-height:1.5; display:none;
@@ -332,7 +342,11 @@
td.type{ white-space:nowrap; color:var(--ink-2); }
td.people{ color:var(--ink-2); max-width:220px; }
td.text{ color:var(--ink); max-width:520px; }
td.file{ font-family:"IBM Plex Mono",monospace; font-size:10.5px; color:var(--ink-3); max-width:220px; overflow-wrap:anywhere; }
td.file{
font-family:"IBM Plex Mono",monospace; font-size:10.5px; color:var(--ink-3); max-width:220px;
overflow-wrap:anywhere; cursor:pointer;
}
td.file:hover{ color:var(--accent); text-decoration:underline; }
.table-foot{ display:flex; align-items:center; justify-content:center; gap:12px; padding:14px; }
.table-foot button{
border:1px solid var(--border); background:var(--page); color:var(--ink);
@@ -384,8 +398,8 @@
Linha do tempo interativa da <span class="mono">Pet16704</span> (STF) — um ponto por documento, agrupado
pela instituição de origem e posicionado pela data real de juntada — cruzada com o resumo de cada um dos
<strong>53 processos conexos</strong> (o inquérito-mãe <span class="mono">Inq 5026</span> — Operação
Compliance Zero — e os demais inquéritos e petições apartadas, reunidos em <span class="mono">parte1/</span>
e <span class="mono">parte2/</span>). Clique em qualquer ponto da linha do tempo para abrir o resumo do
Compliance Zero — e os demais inquéritos e petições apartadas, reunidos em <span class="mono">resumos/parte1/</span>
e <span class="mono">resumos/parte2/</span>). Clique em qualquer ponto da linha do tempo para abrir o resumo do
documento e, dali, o resumo completo do processo a que ele pertence.
</p>
<div class="stats" id="stats"></div>
@@ -471,22 +485,22 @@
<div class="resumo-id mono" id="resumoId"></div>
<div class="resumo-type" id="resumoType"></div>
<p class="resumo-text" id="resumoText"></p>
<div class="resumo-block" id="resumoPeopleBlock" hidden>
<div id="resumoPeopleBlock" hidden>
<div class="resumo-label">Pessoas mencionadas</div>
<div class="resumo-people" id="resumoPeople"></div>
</div>
<div class="resumo-block">
<div>
<div class="resumo-label">Arquivo-fonte</div>
<div class="resumo-file mono" id="resumoFile"></div>
</div>
<div class="resumo-block">
<div>
<button type="button" class="resumo-processo-btn" id="resumoProcessoBtn" aria-expanded="false">
Ver resumo do processo <span class="mono" id="resumoProcessoNum"></span>
</button>
<div class="resumo-processo-content" id="resumoProcessoContent" hidden></div>
</div>
</aside>
</div>
<div class="resumo-processo-content" id="resumoProcessoContent" hidden></div>
</section>
<section id="tableView" hidden>
@@ -514,8 +528,7 @@
<footer>
<p>
Linha do tempo: <span class="mono">TIMELINE.md</span> e <span class="mono">gitgraph.md</span> (atribuição de
instituição por documento). Da leva original de 615 documentos sem data de juntada identificada, 366 tiveram
Da leva original de 615 documentos sem data de juntada identificada, 366 tiveram
uma data recuperada a partir do próprio texto do documento (data de assinatura/expedição, ex. "Brasília, 10 de
abril de 2026") — marcados no resumo do documento como "data lida no texto", já que não é necessariamente a
data de juntada nos autos. Os 249 restantes ficam de fora do gráfico e aparecem só na tabela. As 292 pessoas do
@@ -526,7 +539,7 @@
</p>
<p>
Resumo dos processos: ao abrir o resumo de um documento, o botão "Ver resumo do processo" busca o arquivo
correspondente em <span class="mono">parte1/</span> ou <span class="mono">parte2/</span> — 53 processos
correspondente em <span class="mono">resumos/parte1/</span> ou <span class="mono">resumos/parte2/</span> — 53 processos
vinculados à Pet16704, lidos e resumidos a partir dos autos originais.
</p>
<p>
@@ -1223,10 +1236,17 @@
var textEl = document.createElement("div"); textEl.className = "text"; textEl.textContent = p.text;
tt.appendChild(row1); tt.appendChild(idEl); tt.appendChild(textEl);
var left = x+16, top = y-10;
if (left + 330 > dtWidth) left = x-330-8;
// tt is position:fixed, so convert the canvas-local x/y into viewport
// coordinates via the canvas's own rect, then clamp to the viewport
// (not the scrollable card) so it never grows .detail-card's overflow.
var rect = dtCanvas.getBoundingClientRect();
var vx = rect.left+x, vy = rect.top+y;
var left = vx+16, top = vy-10;
if (left + 330 > window.innerWidth) left = vx-330-8;
var ttH = tt.offsetHeight;
if (top + ttH > window.innerHeight) top = window.innerHeight-ttH-8;
tt.style.left = left+"px";
tt.style.top = Math.max(0,top)+"px";
tt.style.top = Math.max(8,top)+"px";
}
function clearHover(){
state.hover = null;
@@ -1281,6 +1301,7 @@
function closeResumo(){
state.selected = null;
document.getElementById("resumoPanel").hidden = true;
document.getElementById("resumoProcessoContent").hidden = true;
document.getElementById("selectionRing").style.display = "none";
resizeAll();
}
@@ -1302,7 +1323,7 @@
if (e.key==="Escape" && !document.getElementById("resumoPanel").hidden) closeResumo();
});
/* ---------------- per-process résumé (parte1/parte2 .md, fetched on demand) ---------------- */
/* ---------------- per-process résumé (resumos/parte1,parte2 .md, fetched on demand) ---------------- */
function escapeHtml(s){
return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
@@ -1316,7 +1337,7 @@
s = s.replace(/`([^`]+)`/g, "<code>$1</code>");
return s;
}
// small, purpose-built markdown→HTML pass for the parte1/parte2 résumé
// small, purpose-built markdown→HTML pass for the resumos/parte1,parte2 résumé
// files (headers, bold, inline code, links, "- " lists, paragraphs) — not
// a general CommonMark renderer, just enough for these fairly plain files.
function mdToHtml(md){
@@ -1349,14 +1370,15 @@
}
var processoCache = {}; // process number -> rendered HTML, or null if not found
// parte1/ and parte2/ live one level above web/ in the intended (repo-root)
// deployment, but a local server started from inside web/ (as the README's
// own quickstart does) has no parent directory to serve — so try both
// "../parteN/" and "parteN/" for each folder and use whichever resolves.
// resumos/parte1/ and resumos/parte2/ live one level above web/ in the
// intended (repo-root) deployment, but a local server started from inside
// web/ (as the README's own quickstart does) has no parent directory to
// serve — so try both "../resumos/parteN/" and "resumos/parteN/" for each
// folder and use whichever resolves.
function fetchProcessoMd(num){
var candidates = [
"../parte2/"+num+".md", "../parte1/"+num+".md",
"parte2/"+num+".md", "parte1/"+num+".md"
"../resumos/parte2/"+num+".md", "../resumos/parte1/"+num+".md",
"resumos/parte2/"+num+".md", "resumos/parte1/"+num+".md"
];
function tryNext(i){
if (i >= candidates.length) return null;
@@ -1632,6 +1654,11 @@
tr.appendChild(tdPeople);
var tdFile = document.createElement("td"); tdFile.className="file"; tdFile.textContent = r.file;
tdFile.title = "Ver resumo deste documento";
tdFile.addEventListener("click", function(){
setView("chart");
openResumo(r, laneIndex[r.lane]);
});
tr.appendChild(tdFile);
frag.appendChild(tr);