feat: header graph flat design — 3 zones + barre statut + recherche unifiée
CI / lint (push) Successful in 14s
CI / security (push) Successful in 8s
CI / test (push) Successful in 16s
CI / build (push) Successful in 2s

This commit is contained in:
2026-05-30 00:00:59 -04:00
parent 4a916e80db
commit a88be85623
2 changed files with 59 additions and 68 deletions
+28 -27
View File
@@ -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());