feat: navigation entre documents via les liens Markdown

Intercepte les clics sur les liens dans le contenu rendu : les liens
internes (.md) chargent le document dans l'app, les liens HTTP s'ouvrent
dans le navigateur système. Restructure aussi la sidebar avec un footer
fixe pour les boutons Personnaliser/Accueil.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 14:35:50 +02:00
parent d47e93b3c3
commit b8ba15d832
3 changed files with 86 additions and 28 deletions
+33
View File
@@ -4,6 +4,37 @@ const win = window.__TAURI__.window.getCurrentWindow();
const titlebarTitle = document.getElementById('titlebar-title');
const content = document.querySelector('#content');
function resolveRelativePath(currentFile, href) {
const sep = currentFile.includes('\\') ? '\\' : '/';
const dir = currentFile.split(sep).slice(0, -1).join(sep);
const parts = [...dir.split(sep), ...href.split('/')];
const resolved = [];
for (const part of parts) {
if (part === '..') resolved.pop();
else if (part !== '.') resolved.push(part);
}
return resolved.join(sep);
}
function wireLinks(filePath, mode, sidebarEl) {
content.querySelectorAll('a[href]').forEach(a => {
const href = a.getAttribute('href');
if (!href || href.startsWith('#')) return;
if (/^https?:\/\//.test(href)) {
a.setAttribute('target', '_blank');
a.setAttribute('rel', 'noopener noreferrer');
return;
}
a.addEventListener('click', async e => {
e.preventDefault();
const resolved = resolveRelativePath(filePath, href);
await loadPage(resolved, mode, sidebarEl);
});
});
}
export async function loadPage(filePath, mode, sidebarEl) {
try {
const html = await convertFile(filePath);
@@ -27,6 +58,8 @@ export async function loadPage(filePath, mode, sidebarEl) {
}
}
}
wireLinks(filePath, mode, sidebarEl);
} catch (err) {
content.innerHTML = `<p class="error">Impossible de charger le fichier : ${err}</p>`;
}