feat: affichage PDF avec TOC + frame-src CSP
CI / lint (push) Successful in 23s
CI / security (push) Successful in 14s
CI / test (push) Successful in 27s
CI / build (push) Successful in 8s
CI / e2e (push) Failing after 1m29s
Desktop Build / build-windows (push) Has been cancelled
Desktop Build / build-linux (push) Has been cancelled
CI / lint (push) Successful in 23s
CI / security (push) Successful in 14s
CI / test (push) Successful in 27s
CI / build (push) Successful in 8s
CI / e2e (push) Failing after 1m29s
Desktop Build / build-windows (push) Has been cancelled
Desktop Build / build-linux (push) Has been cancelled
- CSP: ajout frame-src 'self' http://127.0.0.1:* (permet iframe PDF) - pdf_reader.py: extract_pdf_toc() — extrait les bookmarks/outline (pypdf + pymupdf) - main.py: inclut pdf_toc dans la réponse /api/file pour les PDF - viewer.js: sidebar TOC avec liens vers les pages (si bookmarks présents) - style.css: layout .pdf-body flex + .pdf-toc sidebar 240px
This commit is contained in:
+17
-2
@@ -402,10 +402,22 @@ async function renderBacklinksPanel(vault, path, container) {
|
||||
export function renderFile(data) {
|
||||
const area = document.getElementById("content-area");
|
||||
|
||||
// Handle PDF files — render in iframe
|
||||
// Handle PDF files — render in iframe with TOC sidebar
|
||||
if (data.is_pdf) {
|
||||
const pdfUrl = `/api/file/${encodeURIComponent(data.vault)}/pdf/stream?path=${encodeURIComponent(data.path)}`;
|
||||
const pages = data.pdf_metadata && data.pdf_metadata.pages ? data.pdf_metadata.pages : '?';
|
||||
const toc = data.pdf_toc || [];
|
||||
|
||||
let tocHtml = '';
|
||||
if (toc.length > 0) {
|
||||
tocHtml = '<div class="pdf-toc"><h3>Table des matières</h3><ul>';
|
||||
for (const item of toc) {
|
||||
const indent = (item.level - 1) * 16;
|
||||
tocHtml += `<li style="padding-left:${indent}px"><a href="#" onclick="document.querySelector('.pdf-iframe').contentWindow.location.hash='page=${item.page}';return false">${escapeHtml(item.title)}</a> <span class="toc-page">p.${item.page}</span></li>`;
|
||||
}
|
||||
tocHtml += '</ul></div>';
|
||||
}
|
||||
|
||||
area.innerHTML = `
|
||||
<div class="pdf-viewer-container">
|
||||
<div class="pdf-toolbar">
|
||||
@@ -417,7 +429,10 @@ export function renderFile(data) {
|
||||
<i data-lucide="download" style="width:14px;height:14px"></i> Télécharger
|
||||
</button>
|
||||
</div>
|
||||
<iframe src="${pdfUrl}" class="pdf-iframe" title="${escapeHtml(data.title)}"></iframe>
|
||||
<div class="pdf-body">
|
||||
${tocHtml}
|
||||
<iframe src="${pdfUrl}" class="pdf-iframe" title="${escapeHtml(data.title)}"></iframe>
|
||||
</div>
|
||||
</div>`;
|
||||
lucide.createIcons();
|
||||
return;
|
||||
|
||||
@@ -8498,6 +8498,46 @@ body.popup-mode .content-area {
|
||||
border: none;
|
||||
min-height: 70vh;
|
||||
}
|
||||
.pdf-body {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.pdf-toc {
|
||||
width: 240px;
|
||||
flex-shrink: 0;
|
||||
overflow-y: auto;
|
||||
padding: 12px;
|
||||
border-right: 1px solid var(--border);
|
||||
background: var(--surface2);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.pdf-toc h3 {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-dim);
|
||||
}
|
||||
.pdf-toc ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.pdf-toc li {
|
||||
padding: 2px 0;
|
||||
}
|
||||
.pdf-toc a {
|
||||
color: var(--text);
|
||||
text-decoration: none;
|
||||
}
|
||||
.pdf-toc a:hover {
|
||||
color: var(--accent);
|
||||
text-decoration: underline;
|
||||
}
|
||||
.toc-page {
|
||||
color: var(--text-dim);
|
||||
font-size: 0.75rem;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
/* ── PaneManager — Split View ── */
|
||||
.pane-grid {
|
||||
|
||||
Reference in New Issue
Block a user