feat: header graph flat design — 3 zones + barre statut + recherche unifiée
This commit is contained in:
parent
4a916e80db
commit
a88be85623
@ -700,53 +700,43 @@
|
||||
<!-- Graph View Modal -->
|
||||
<div class="editor-modal" id="graph-modal">
|
||||
<div class="editor-container" style="max-width:95vw;width:1000px;height:85vh;display:flex;flex-direction:column;">
|
||||
<div class="editor-header" style="flex-wrap:wrap;gap:2px">
|
||||
<div class="editor-actions" style="width:100%;display:flex;align-items:center;gap:6px;flex-wrap:wrap;padding-bottom:4px">
|
||||
<span id="graph-info" style="font-size:0.75rem;color:var(--text-muted);white-space:nowrap"></span>
|
||||
<label style="font-size:0.7rem;color:var(--text-muted)">Profondeur:</label>
|
||||
<input type="range" id="graph-depth" min="0" max="3" value="1" style="width:50px" title="Profondeur d'exploration">
|
||||
<button class="editor-btn" id="graph-full-vault" title="Vue complète du vault" aria-label="Vault complet" style="font-size:0.7rem">🌐 Tout</button>
|
||||
<span style="color:var(--border-color);margin:0 4px">│</span>
|
||||
<i data-lucide="search" style="width:14px;height:14px;color:var(--text-muted);flex-shrink:0"></i>
|
||||
<input type="text" id="graph-search" placeholder="Rechercher un nœud..." style="width:180px;font-size:0.75rem;padding:2px 8px;border-radius:4px;border:1px solid var(--border-color);background:var(--bg-secondary);color:var(--text-primary)">
|
||||
<i data-lucide="tag" style="width:14px;height:14px;color:var(--text-muted);flex-shrink:0;margin-left:4px"></i>
|
||||
<input type="text" id="graph-tag-filter" placeholder="Filtrer par tag..." style="width:140px;font-size:0.75rem;padding:2px 8px;border-radius:4px;border:1px solid var(--border-color);background:var(--bg-secondary);color:var(--text-primary)">
|
||||
<span style="font-size:0.65rem;color:var(--text-muted);margin-left:4px;opacity:0.6;white-space:nowrap">Ctrl+survol = aperçu</span>
|
||||
<!-- Header: 3 zones — titre | recherche | contrôles -->
|
||||
<div class="editor-header" style="display:flex;align-items:center;gap:12px;padding:8px 12px;border-bottom:1px solid var(--border-color)">
|
||||
<div class="editor-title" id="graph-title" style="font-weight:600;font-size:0.9rem;white-space:nowrap;flex-shrink:0;min-width:0;overflow:hidden;text-overflow:ellipsis">Vue Graphique</div>
|
||||
<div style="flex:1;display:flex;justify-content:center">
|
||||
<div style="position:relative;width:100%;max-width:400px">
|
||||
<i data-lucide="search" style="position:absolute;left:10px;top:50%;transform:translateY(-50%);width:14px;height:14px;color:var(--text-muted);pointer-events:none"></i>
|
||||
<input type="text" id="graph-search" placeholder="Rechercher ou #tag..." style="width:100%;font-size:0.8rem;padding:6px 12px 6px 32px;border-radius:8px;border:none;background:var(--bg-secondary);color:var(--text-primary);outline:none;box-shadow:inset 0 1px 3px rgba(0,0,0,0.2)">
|
||||
<span style="position:absolute;right:10px;top:50%;transform:translateY(-50%);font-size:0.6rem;color:var(--text-muted);opacity:0.5;pointer-events:none">Ctrl+survol</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="editor-actions" style="width:100%;display:flex;align-items:center;gap:4px;border-top:1px solid var(--border-color);padding-top:3px">
|
||||
<span style="flex:1"></span>
|
||||
<button class="editor-btn" id="graph-zoom-in" title="Zoom avant" aria-label="Zoom avant">
|
||||
<i data-lucide="zoom-in" style="width:16px;height:16px"></i>
|
||||
</button>
|
||||
<button class="editor-btn" id="graph-zoom-out" title="Zoom arrière" aria-label="Zoom arrière">
|
||||
<i data-lucide="zoom-out" style="width:16px;height:16px"></i>
|
||||
</button>
|
||||
<button class="editor-btn" id="graph-reset" title="Réinitialiser la vue" aria-label="Réinitialiser">
|
||||
<i data-lucide="maximize" style="width:16px;height:16px"></i>
|
||||
</button>
|
||||
<button class="editor-btn" id="graph-export" title="Exporter en PNG" aria-label="Export PNG">
|
||||
<i data-lucide="download" style="width:16px;height:16px"></i>
|
||||
</button>
|
||||
<button class="editor-btn" id="graph-fullscreen" title="Plein écran" aria-label="Plein écran">
|
||||
<i data-lucide="expand" style="width:16px;height:16px"></i>
|
||||
</button>
|
||||
<button class="editor-btn" id="graph-close" title="Fermer" aria-label="Fermer">
|
||||
<i data-lucide="x" style="width:16px;height:16px"></i>
|
||||
</button>
|
||||
<div style="display:flex;align-items:center;gap:2px;flex-shrink:0">
|
||||
<button class="editor-btn" id="graph-full-vault" title="Vue complète du vault" style="font-size:0.7rem;padding:4px 8px">🌐 Tout</button>
|
||||
<span style="font-size:0.65rem;color:var(--text-muted);margin:0 2px">Prof.</span>
|
||||
<input type="range" id="graph-depth" min="0" max="3" value="1" style="width:50px" title="Profondeur">
|
||||
<button class="editor-btn" id="graph-zoom-out" title="Zoom arrière"><i data-lucide="zoom-out" style="width:15px;height:15px"></i></button>
|
||||
<button class="editor-btn" id="graph-zoom-in" title="Zoom avant"><i data-lucide="zoom-in" style="width:15px;height:15px"></i></button>
|
||||
<button class="editor-btn" id="graph-reset" title="Réinitialiser"><i data-lucide="maximize" style="width:15px;height:15px"></i></button>
|
||||
<button class="editor-btn" id="graph-export" title="Exporter PNG"><i data-lucide="download" style="width:15px;height:15px"></i></button>
|
||||
<button class="editor-btn" id="graph-fullscreen" title="Plein écran"><i data-lucide="expand" style="width:15px;height:15px"></i></button>
|
||||
<button class="editor-btn" id="graph-close" title="Fermer"><i data-lucide="x" style="width:16px;height:16px"></i></button>
|
||||
</div>
|
||||
<div class="editor-title" id="graph-title" style="width:100%;font-size:0.85rem;padding-top:2px;border-top:1px solid var(--border-color)">Vue Graphique</div>
|
||||
</div>
|
||||
<div class="editor-body" style="flex:1;overflow:hidden;position:relative;padding:0">
|
||||
<canvas id="graph-canvas" style="width:100%;height:100%;cursor:grab"></canvas>
|
||||
<div id="graph-tooltip" style="display:none;position:absolute;pointer-events:none;background:var(--bg-primary);border:1px solid var(--border-color);border-radius:6px;padding:6px 10px;font-size:0.75rem;color:var(--text-primary);max-width:250px;z-index:10;box-shadow:0 2px 8px rgba(0,0,0,0.3)"></div>
|
||||
<div id="graph-legend" style="position:absolute;bottom:12px;left:12px;display:flex;gap:12px;font-size:0.7rem;color:var(--text-muted);background:var(--bg-primary);padding:6px 12px;border-radius:6px;border:1px solid var(--border-color);align-items:center;flex-wrap:wrap">
|
||||
<label style="cursor:pointer;display:flex;align-items:center;gap:3px"><input type="checkbox" id="graph-filter-dir" checked> 🟦 Dossier</label>
|
||||
<label style="cursor:pointer;display:flex;align-items:center;gap:3px"><input type="checkbox" id="graph-filter-md" checked> 🟩 .md</label>
|
||||
<label style="cursor:pointer;display:flex;align-items:center;gap:3px"><input type="checkbox" id="graph-filter-other" checked> ⬜ Autre</label>
|
||||
<span style="color:var(--text-muted);margin:0 4px">│</span>
|
||||
<span style="color:var(--text-muted)">── Parent</span>
|
||||
<span style="color:var(--accent-color,#2563eb)">┅┅ Wikilink</span>
|
||||
<span style="color:#e74c3c">← Backlink</span>
|
||||
<!-- Status bar + legend -->
|
||||
<div style="position:absolute;bottom:0;left:0;right:0;display:flex;align-items:center;justify-content:space-between;padding:4px 12px;background:var(--bg-primary);border-top:1px solid var(--border-color);font-size:0.7rem;color:var(--text-muted)">
|
||||
<span id="graph-status">—</span>
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<label style="cursor:pointer;display:flex;align-items:center;gap:3px"><input type="checkbox" id="graph-filter-dir" checked> 🟦 Dossier</label>
|
||||
<label style="cursor:pointer;display:flex;align-items:center;gap:3px"><input type="checkbox" id="graph-filter-md" checked> 🟩 .md</label>
|
||||
<label style="cursor:pointer;display:flex;align-items:center;gap:3px"><input type="checkbox" id="graph-filter-other" checked> ⬜ Autre</label>
|
||||
<span style="opacity:0.5">│</span>
|
||||
<span>── Parent</span>
|
||||
<span style="color:var(--accent-color,#2563eb)">┅┅ Wikilink</span>
|
||||
<span style="color:#e74c3c">← Backlink</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -63,7 +63,7 @@ export const GraphViewManager = {
|
||||
|
||||
const modal = document.getElementById('graph-modal');
|
||||
const title = document.getElementById('graph-title');
|
||||
const info = document.getElementById('graph-info');
|
||||
const statusEl = document.getElementById('graph-status');
|
||||
const canvas = document.getElementById('graph-canvas');
|
||||
const depthSlider = document.getElementById('graph-depth');
|
||||
|
||||
@ -74,7 +74,7 @@ export const GraphViewManager = {
|
||||
this._scope = 'directory';
|
||||
|
||||
title.textContent = `Vue Graphique — ${vault}${path ? '/' + path : ''}`;
|
||||
info.textContent = 'Chargement...';
|
||||
statusEl.textContent = 'Chargement...';
|
||||
modal.classList.add('active');
|
||||
|
||||
this._canvas = canvas;
|
||||
@ -93,8 +93,8 @@ export const GraphViewManager = {
|
||||
},
|
||||
|
||||
async _fetchAndRender() {
|
||||
const info = document.getElementById('graph-info');
|
||||
if (!info) return;
|
||||
const statusEl = document.getElementById('graph-status');
|
||||
if (!statusEl) return;
|
||||
|
||||
const cacheKey = this._getCacheKey();
|
||||
|
||||
@ -105,7 +105,7 @@ export const GraphViewManager = {
|
||||
this._edges = cached.edges;
|
||||
this._scope = cached.scope;
|
||||
const scopeLabel = this._scope === 'full' ? 'Vault complet' : 'Dossier';
|
||||
info.textContent = `${this._nodes.length} nœuds, ${this._edges.length} liens · ${scopeLabel} · prof=${this._depth} (cache)`;
|
||||
statusEl.textContent = `${this._nodes.length} nœuds, ${this._edges.length} liens · ${scopeLabel} · prof=${this._depth} (cache)`;
|
||||
this._initLayout();
|
||||
this._startRender();
|
||||
return;
|
||||
@ -134,11 +134,11 @@ export const GraphViewManager = {
|
||||
this._cacheKey = cacheKey;
|
||||
|
||||
const scopeLabel = this._scope === 'full' ? 'Vault complet' : 'Dossier';
|
||||
info.textContent = `${this._nodes.length} nœuds, ${this._edges.length} liens · ${scopeLabel} · prof=${this._depth}`;
|
||||
statusEl.textContent = `${this._nodes.length} nœuds, ${this._edges.length} liens · ${scopeLabel} · prof=${this._depth}`;
|
||||
this._initLayout();
|
||||
this._startRender();
|
||||
} catch (err) {
|
||||
info.textContent = 'Erreur de chargement';
|
||||
statusEl.textContent = 'Erreur de chargement';
|
||||
console.error('Graph error:', err);
|
||||
}
|
||||
},
|
||||
@ -163,19 +163,30 @@ export const GraphViewManager = {
|
||||
|
||||
setSearch(term) {
|
||||
this._searchTerm = term;
|
||||
// For now, use tag filter on backend; client-side highlighting on draw
|
||||
if (term && term.length >= 2) {
|
||||
this.reload();
|
||||
} else if (!term && this._searchTerm !== term) {
|
||||
this.reload();
|
||||
// Parse unified search: #tag → tag filter, otherwise → node search
|
||||
if (term.startsWith('#')) {
|
||||
const tag = term.substring(1).trim();
|
||||
if (tag && tag !== this._tagFilter) {
|
||||
this._tagFilter = tag;
|
||||
this.reload();
|
||||
} else if (!tag && this._tagFilter) {
|
||||
this._tagFilter = '';
|
||||
this.reload();
|
||||
}
|
||||
} else {
|
||||
if (this._tagFilter) {
|
||||
this._tagFilter = '';
|
||||
this.reload();
|
||||
return;
|
||||
}
|
||||
if (term && term.length >= 2) {
|
||||
this.reload();
|
||||
} else if (!term && this._searchTerm !== term) {
|
||||
this.reload();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setTagFilter(tag) {
|
||||
this._tagFilter = tag;
|
||||
this.reload();
|
||||
},
|
||||
|
||||
close() {
|
||||
const modal = document.getElementById('graph-modal');
|
||||
if (modal) modal.classList.remove('active');
|
||||
@ -801,16 +812,6 @@ export function initGraphView() {
|
||||
});
|
||||
}
|
||||
|
||||
// Tag filter input
|
||||
const tagFilterInput = document.getElementById('graph-tag-filter');
|
||||
if (tagFilterInput) {
|
||||
let tagDebounce;
|
||||
tagFilterInput.addEventListener('input', () => {
|
||||
clearTimeout(tagDebounce);
|
||||
tagDebounce = setTimeout(() => gm.setTagFilter(tagFilterInput.value.trim()), 400);
|
||||
});
|
||||
}
|
||||
|
||||
// Export PNG
|
||||
const exportBtn = document.getElementById('graph-export');
|
||||
if (exportBtn) exportBtn.addEventListener('click', () => gm.exportPNG());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user