—
diff --git a/frontend/js/graph.js b/frontend/js/graph.js
index d30551b..55b255f 100644
--- a/frontend/js/graph.js
+++ b/frontend/js/graph.js
@@ -52,7 +52,8 @@ export const GraphViewManager = {
_searchTerm: '',
_tagFilter: '',
_hoveredNode: null,
- _tooltipEl: null,
+ _infoPanel: null,
+ _previewPanel: null,
_previewCache: {},
_previewPending: null,
_ctrlHoverNode: null,
@@ -69,7 +70,8 @@ export const GraphViewManager = {
if (!modal || !canvas) return;
- this._tooltipEl = document.getElementById('graph-tooltip');
+ this._infoPanel = document.getElementById('graph-info-panel');
+ this._previewPanel = document.getElementById('graph-preview-panel');
this._depth = depthSlider ? parseInt(depthSlider.value) : 1;
this._scope = 'directory';
@@ -532,42 +534,80 @@ export const GraphViewManager = {
},
_showTooltip(node, screenX, screenY, isPreview) {
- if (!this._tooltipEl) return;
- if (isPreview) return; // Preview tooltip handled by _showPreviewTooltip
+ if (isPreview) return; // Handled by _showPreviewTooltip
+ if (!this._infoPanel) return;
const cacheKey = `${this._vault}:${node.path}`;
const cached = this._previewCache[cacheKey];
const meta = cached?.meta;
- // Build metadata summary if available
- let metaHtml = '';
+ // Build metadata summary
+ let metaRows = '';
if (meta?.frontmatter && Object.keys(meta.frontmatter).length > 0) {
const fm = meta.frontmatter;
- const parts = [];
- if (fm.auteur) parts.push(`✍️ ${fm.auteur}`);
- if (fm.date || fm.creation_date) parts.push(`📅 ${fm.date || fm.creation_date}`);
- if (fm.statut) parts.push(`📌 ${fm.statut}`);
- if (fm.publish) parts.push('✅ publié');
- if (fm.favoris) parts.push('⭐ favoris');
- if (parts.length > 0) metaHtml = `
${parts.join(' · ')}`;
+ const rows = [];
+ if (fm.auteur) rows.push(`
✍️ Auteur ${fm.auteur}
`);
+ if (fm.date || fm.creation_date) rows.push(`
📅 Date ${fm.date || fm.creation_date}
`);
+ if (fm.statut) rows.push(`
📌 Statut ${fm.statut}
`);
+ if (fm.catégorie || fm.categorie) rows.push(`
📂 Catégorie ${fm.catégorie || fm.categorie}
`);
+ if (fm.publish) rows.push('
✅ Publié
');
+ if (fm.favoris) rows.push('
⭐ Favoris
');
+ if (rows.length > 0) metaRows = rows.join('');
}
- const tags = (meta?.tags || node.tags || []).slice(0, 5).join(', ');
+ const tags = (meta?.tags || node.tags || []).slice(0, 6);
const inc = node.incoming_count || 0;
const out = node.outgoing_count || 0;
- this._tooltipEl.innerHTML = `
-
${meta?.title || node.name}
- ${node.type === 'file' ? `
${node.path}` : ''}
- ${metaHtml}
- ${tags ? `
🏷️ ${tags}` : ''}
- ${inc + out > 0 ? `
🔗 ${out} sortants · ${inc} entrants` : ''}
- ${node.type === 'file' ? `
Ctrl+survol pour aperçu` : ''}
+ const typeIcon = node.type === 'directory' ? '📁' : '📄';
+ const typeLabel = node.type === 'directory' ? 'Dossier' : (node.path || '').endsWith('.md') ? 'Markdown' : 'Fichier';
+
+ this._infoPanel.innerHTML = `
+
+
${typeIcon}
+
+
${meta?.title || node.name}
+
${node.path}
+
+
+
+ ${typeLabel}
+ ${inc + out > 0 ? `🔗 ${out}→ · ${inc}←` : ''}
+
+ ${metaRows ? `
${metaRows}
` : ''}
+ ${tags.length > 0 ? `
${tags.map(t => `#${t}`).join('')}
` : ''}
+ ${node.type === 'file' ? '
Ctrl+survol = aperçu complet
' : ''}
`;
- this._tooltipEl.style.display = 'block';
- this._tooltipEl.style.maxWidth = '280px';
- this._tooltipEl.style.left = (screenX + 15) + 'px';
- this._tooltipEl.style.top = (screenY - 10) + 'px';
+ this._infoPanel.style.display = 'block';
},
_hideTooltip() {
- if (this._tooltipEl) this._tooltipEl.style.display = 'none';
+ if (this._infoPanel) this._infoPanel.style.display = 'none';
+ if (this._previewPanel) this._previewPanel.style.display = 'none';
+ },
+
+ _showPreviewTooltip(node, preview, screenX, screenY) {
+ if (!this._previewPanel || this._ctrlHoverNode !== node) return;
+ const cacheKey = `${this._vault}:${node.path}`;
+ const cached = this._previewCache[cacheKey];
+ const meta = cached?.meta;
+ // Format frontmatter summary
+ let fmSummary = '';
+ if (meta?.frontmatter && Object.keys(meta.frontmatter).length > 0) {
+ const fm = meta.frontmatter;
+ const items = [];
+ if (fm.auteur) items.push(`✍️ ${fm.auteur}`);
+ if (fm.date || fm.creation_date) items.push(`📅 ${fm.date || fm.creation_date}`);
+ if (fm.statut) items.push(`📌 ${fm.statut}`);
+ if (fm.publish) items.push('✅ publié');
+ if (fm.favoris) items.push('⭐ favoris');
+ if (items.length > 0) fmSummary = `
${items.join(' · ')}
`;
+ }
+ const tags = (meta?.tags || node.tags || []).slice(0, 8);
+ this._previewPanel.innerHTML = `
+
${meta?.title || node.name}
+
${node.path}
+ ${fmSummary}
+ ${tags.length > 0 ? `
${tags.map(t => `#${t}`).join('')}
` : ''}
+
${preview}
+ `;
+ this._previewPanel.style.display = 'block';
},
// --- Advanced controls ---
@@ -702,38 +742,6 @@ export const GraphViewManager = {
}
},
- _showPreviewTooltip(node, preview, screenX, screenY) {
- if (!this._tooltipEl || this._ctrlHoverNode !== node) return;
- const cacheKey = `${this._vault}:${node.path}`;
- const cached = this._previewCache[cacheKey];
- const meta = cached?.meta;
- // Format frontmatter summary
- let fmSummary = '';
- if (meta?.frontmatter && Object.keys(meta.frontmatter).length > 0) {
- const fm = meta.frontmatter;
- const items = [];
- if (fm.auteur) items.push(`✍️ ${fm.auteur}`);
- if (fm.date || fm.creation_date) items.push(`📅 ${fm.date || fm.creation_date}`);
- if (fm.statut) items.push(`📌 ${fm.statut}`);
- if (fm.catégorie || fm.categorie) items.push(`📂 ${fm.catégorie || fm.categorie}`);
- if (fm.publish) items.push('✅ publié');
- if (fm.favoris) items.push('⭐ favoris');
- if (items.length > 0) fmSummary = `
${items.join(' · ')}
`;
- }
- const tags = (meta?.tags || node.tags || []).slice(0, 5).join(', ');
- this._tooltipEl.innerHTML = `
-
${meta?.title || node.name}
-
${node.path}
- ${fmSummary}
- ${tags ? `
🏷️ ${tags}` : ''}
-
${preview}
- `;
- this._tooltipEl.style.display = 'block';
- this._tooltipEl.style.maxWidth = '420px';
- this._tooltipEl.style.left = Math.min(screenX + 15, window.innerWidth - 440) + 'px';
- this._tooltipEl.style.top = Math.min(screenY - 10, window.innerHeight - 220) + 'px';
- },
-
_onMouseUp(e) {
if (this._dragging && this._dragNode) {
const node = this._dragNode.node;