From d8e5d0ef574e1592e339169967b8cf62e9ef8ba8 Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Mon, 23 Mar 2026 13:46:17 -0400 Subject: [PATCH] Add help modal navigation with table of contents, scroll spy, vault context indicator, and new window button for file viewing --- frontend/app.js | 63 ++++++- frontend/index.html | 450 ++++++++++++++++++++++++++++++++------------ frontend/style.css | 144 +++++++++++++- 3 files changed, 530 insertions(+), 127 deletions(-) diff --git a/frontend/app.js b/frontend/app.js index c23d738..b33df61 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -879,8 +879,15 @@ function syncVaultSelectors() { const filter = document.getElementById("vault-filter"); const quickSelect = document.getElementById("vault-quick-select"); + const contextText = document.getElementById("vault-context-text"); + if (filter) filter.value = selectedContextVault; if (quickSelect) quickSelect.value = selectedContextVault; + + // Update vault context indicator + if (contextText) { + contextText.textContent = selectedContextVault === "all" ? "All" : selectedContextVault; + } } function scrollTreeItemIntoView(element, alignToTop) { @@ -1677,6 +1684,16 @@ openEditor(data.vault, data.path); }); + const openNewWindowBtn = el("button", { class: "btn-action", title: "Ouvrir dans une nouvelle fenêtre" }, [ + icon("external-link", 14), + document.createTextNode("Nouvelle fenêtre"), + ]); + openNewWindowBtn.addEventListener("click", () => { + const currentUrl = window.location.origin + window.location.pathname; + const fileUrl = `${currentUrl}#file=${encodeURIComponent(data.vault)}:${encodeURIComponent(data.path)}`; + window.open(fileUrl, '_blank'); + }); + // Frontmatter let fmSection = null; if (data.frontmatter && Object.keys(data.frontmatter).length > 0) { @@ -1730,7 +1747,7 @@ area.appendChild(el("div", { class: "file-header" }, [ el("div", { class: "file-title" }, [document.createTextNode(data.title)]), tagsDiv, - el("div", { class: "file-actions" }, [copyBtn, sourceBtn, downloadBtn, editBtn]), + el("div", { class: "file-actions" }, [copyBtn, sourceBtn, downloadBtn, editBtn, openNewWindowBtn]), ])); if (fmSection) area.appendChild(fmSection); area.appendChild(mdDiv); @@ -1798,6 +1815,7 @@ modal.classList.add("active"); closeHeaderMenu(); safeCreateIcons(); + initHelpNavigation(); }); closeBtn.addEventListener("click", closeHelpModal); @@ -1814,6 +1832,49 @@ }); } + function initHelpNavigation() { + const helpContent = document.querySelector(".help-content"); + const navLinks = document.querySelectorAll(".help-nav-link"); + + if (!helpContent || !navLinks.length) return; + + // Handle nav link clicks + navLinks.forEach(link => { + link.addEventListener("click", (e) => { + e.preventDefault(); + const targetId = link.getAttribute("href").substring(1); + const targetSection = document.getElementById(targetId); + if (targetSection) { + targetSection.scrollIntoView({ behavior: "smooth", block: "start" }); + } + }); + }); + + // Scroll spy - update active nav link based on scroll position + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const id = entry.target.getAttribute("id"); + navLinks.forEach(link => { + if (link.getAttribute("href") === `#${id}`) { + navLinks.forEach(l => l.classList.remove("active")); + link.classList.add("active"); + } + }); + } + }); + }, { + root: helpContent, + rootMargin: "-20% 0px -70% 0px", + threshold: 0 + }); + + // Observe all sections + document.querySelectorAll(".help-section").forEach(section => { + observer.observe(section); + }); + } + function closeHelpModal() { const modal = document.getElementById("help-modal"); if (modal) modal.classList.remove("active"); diff --git a/frontend/index.html b/frontend/index.html index b82fd6e..33e1de9 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -133,6 +133,10 @@
+
+ + All +
+
-
-
-
📘 Guide d'utilisation
-

Bienvenue dans ObsiGate

-

Explorez vos notes, changez de vault en un clic, filtrez avec les tags et retrouvez immédiatement le bon document grâce à une navigation pensée pour aller vite.

-
- ⚡ Navigation rapide - 🗂️ Multi-vault - 🏷️ Tags intelligents - 📝 Lecture et édition -
-
-
diff --git a/frontend/style.css b/frontend/style.css index 1e1104b..eae105a 100644 --- a/frontend/style.css +++ b/frontend/style.css @@ -118,10 +118,35 @@ a:hover { .header-right { display: flex; + align-items: center; justify-content: flex-end; + gap: 12px; flex: 0 1 auto; } +.vault-context-indicator { + display: flex; + align-items: center; + gap: 6px; + padding: 6px 12px; + background: color-mix(in srgb, var(--accent) 12%, transparent); + border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--border)); + border-radius: 8px; + font-family: 'JetBrains Mono', monospace; + font-size: 0.75rem; + font-weight: 600; + color: var(--accent); + cursor: default; + transition: all 200ms ease; +} +.vault-context-indicator:hover { + background: color-mix(in srgb, var(--accent) 18%, transparent); + border-color: var(--accent); +} +.vault-context-indicator i { + color: var(--accent); +} + .hamburger-btn { display: none; background: none; @@ -907,9 +932,15 @@ select { flex: 1; overflow-y: auto; padding: clamp(16px, 3vw, 40px) clamp(16px, 4vw, 40px) 60px; - transition: background 200ms ease; + transition: background 200ms ease, margin 300ms ease; min-width: 0; } + +/* Center content when sidebar is hidden */ +.sidebar.hidden ~ .content-area { + margin: 0 auto; + max-width: 1200px; +} .content-area::-webkit-scrollbar { width: 8px; } @@ -1475,11 +1506,91 @@ select { .help-body { padding: 0; background: radial-gradient(circle at top right, color-mix(in srgb, var(--accent) 10%, transparent), transparent 30%), var(--bg-primary); + display: flex; + gap: 0; } + +/* Help Navigation Menu */ +.help-nav { + width: 220px; + min-width: 220px; + background: var(--bg-secondary); + border-right: 1px solid var(--border); + padding: 20px 0; + overflow-y: auto; + position: sticky; + top: 0; + height: calc(90vh - 60px); + flex-shrink: 0; +} +.help-nav-title { + font-family: 'JetBrains Mono', monospace; + font-size: 0.75rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--text-muted); + padding: 0 20px 12px; + border-bottom: 1px solid var(--border); + margin-bottom: 8px; +} +.help-nav-list { + list-style: none; + margin: 0; + padding: 0; +} +.help-nav-list li { + margin: 0; +} +.help-nav-link { + display: block; + padding: 8px 20px; + font-size: 0.85rem; + color: var(--text-secondary); + text-decoration: none; + transition: all 150ms ease; + border-left: 3px solid transparent; +} +.help-nav-link:hover { + color: var(--accent); + background: var(--bg-hover); + text-decoration: none; +} +.help-nav-link.active { + color: var(--accent); + background: color-mix(in srgb, var(--accent) 10%, transparent); + border-left-color: var(--accent); + font-weight: 600; +} + .help-content { + flex: 1; max-width: 920px; margin: 0 auto; - padding: 28px 24px 40px; + padding: 28px 32px 40px; + overflow-y: auto; + min-width: 0; +} +.help-lead { + font-size: 1.05rem; + line-height: 1.6; + color: var(--text-primary); + margin-bottom: 16px; +} +.help-footer { + margin-top: 48px; + padding-top: 24px; + border-top: 1px solid var(--border); + text-align: center; + color: var(--text-muted); + font-size: 0.85rem; +} +.help-footer a { + color: var(--accent); + text-decoration: none; +} +.help-footer a:hover { + text-decoration: underline; } .help-content h1, .help-content h2, @@ -1504,6 +1615,17 @@ select { margin: 0 0 12px; color: var(--text-secondary); } +.help-content ul, +.help-content ol { + margin: 8px 0 16px; + padding-left: 24px; + color: var(--text-secondary); +} +.help-content ul li, +.help-content ol li { + margin: 6px 0; + line-height: 1.6; +} .help-content code { font-family: 'JetBrains Mono', monospace; background: var(--code-bg); @@ -1511,6 +1633,11 @@ select { border-radius: 4px; padding: 1px 5px; color: var(--text-primary); + font-size: 0.88em; +} +.help-content strong { + color: var(--text-primary); + font-weight: 600; } .help-hero { @@ -1784,6 +1911,19 @@ select { word-wrap: break-word; } +/* Mobile help navigation */ +@media (max-width: 768px) { + .help-nav { + display: none; + } + .help-content { + padding: 20px 16px 32px; + } + .vault-context-indicator { + display: none; + } +} + /* Mobile editor */ @media (max-width: 768px) { .editor-modal {