diff --git a/frontend/js/graph.js b/frontend/js/graph.js
index cb465a2..ebdc989 100644
--- a/frontend/js/graph.js
+++ b/frontend/js/graph.js
@@ -523,18 +523,34 @@ export const GraphViewManager = {
_showTooltip(node, screenX, screenY, isPreview) {
if (!this._tooltipEl) return;
if (isPreview) return; // Preview tooltip handled by _showPreviewTooltip
- const tags = (node.tags || []).slice(0, 5).join(', ');
+ const cacheKey = `${this._vault}:${node.path}`;
+ const cached = this._previewCache[cacheKey];
+ const meta = cached?.meta;
+ // Build metadata summary if available
+ let metaHtml = '';
+ 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 tags = (meta?.tags || node.tags || []).slice(0, 5).join(', ');
const inc = node.incoming_count || 0;
const out = node.outgoing_count || 0;
this._tooltipEl.innerHTML = `
- ${node.name}
+ ${meta?.title || node.name}
${node.type === 'file' ? `
${node.path}` : ''}
+ ${metaHtml}
${tags ? `
🏷️ ${tags}` : ''}
${inc + out > 0 ? `
🔗 ${out} sortants · ${inc} entrants` : ''}
-
Ctrl+survol pour aperçu
+ ${node.type === 'file' ? `
Ctrl+survol pour aperçu` : ''}
`;
this._tooltipEl.style.display = 'block';
- this._tooltipEl.style.maxWidth = '250px';
+ this._tooltipEl.style.maxWidth = '280px';
this._tooltipEl.style.left = (screenX + 15) + 'px';
this._tooltipEl.style.top = (screenY - 10) + 'px';
},
@@ -647,35 +663,64 @@ export const GraphViewManager = {
async _fetchPreview(node, screenX, screenY) {
const cacheKey = `${this._vault}:${node.path}`;
if (this._previewCache[cacheKey] !== undefined) {
- this._showPreviewTooltip(node, this._previewCache[cacheKey], screenX, screenY);
+ const cached = this._previewCache[cacheKey];
+ this._showPreviewTooltip(node, cached.preview, screenX, screenY);
return;
}
// Show loading indicator
- this._showPreviewTooltip(node, 'Chargement...', screenX, screenY);
+ this._showPreviewTooltip(node, 'Chargement...', screenX, screenY);
try {
- const data = await api(`/api/file/${encodeURIComponent(this._vault)}/raw?path=${encodeURIComponent(node.path)}`);
- const content = (data.raw || '').substring(0, 400).replace(/\n/g, ' ');
- this._previewCache[cacheKey] = content;
- this._showPreviewTooltip(node, content, screenX, screenY);
+ const data = await api(`/api/file/${encodeURIComponent(this._vault)}?path=${encodeURIComponent(node.path)}`);
+ // Strip HTML tags, keep line breaks, limit to 600 chars
+ const text = (data.html || '').replace(/<[^>]*>/g, '').replace(/\n+/g, '\n').trim();
+ const preview = text.substring(0, 600) + (text.length > 600 ? '…' : '');
+ // Cache both preview text and full metadata for tooltips
+ this._previewCache[cacheKey] = {
+ preview,
+ meta: {
+ title: data.title,
+ frontmatter: data.frontmatter || {},
+ tags: data.tags || [],
+ path: node.path,
+ }
+ };
+ this._showPreviewTooltip(node, preview, screenX, screenY);
} catch {
- this._previewCache[cacheKey] = '(impossible de charger le contenu)';
+ this._previewCache[cacheKey] = { preview: '(impossible de charger)', meta: null };
this._showPreviewTooltip(node, '(impossible de charger le contenu)', screenX, screenY);
}
},
_showPreviewTooltip(node, preview, screenX, screenY) {
if (!this._tooltipEl || this._ctrlHoverNode !== node) return;
- const tags = (node.tags || []).slice(0, 3).join(', ');
+ 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 = `