feat(media): refonte carte Bonpote-aligned 11 ecoles pastel + header RAG->MEDIA

- auteurs-pensees.json: 11 ecoles (suppression marxismes-ecologiques, fusion Marx+Saito->ecosocialisme), palette pastel, positions x_hint/y_hint Bonpote-aligned
- CartePensees.vue: texte ecole blanc->#1a1a1a, background #f5f3f0, linkDistance 130, charge -50, forceX/forceY ajoutescode pour ancrer auteurs pres de leur ecole principale
- app.vue: onglet desktop RAG->MEDIA sans badge, menu mobile to=/rag->to=/media avec active state conditionnel
This commit is contained in:
Jules Neny
2026-05-12 11:27:16 +02:00
parent c6295ea228
commit 1b1e373bea
3 changed files with 71 additions and 61 deletions

View File

@@ -1,5 +1,5 @@
<template>
<div style="width: 100%; height: 100%; position: relative; background: var(--nav-bg);">
<div style="width: 100%; height: 100%; position: relative; background: #f5f3f0;">
<svg ref="svgRef" style="width: 100%; height: 100%;"></svg>
<div ref="tooltipRef" style="
position: absolute; pointer-events: none;
@@ -59,12 +59,30 @@ async function initGraph() {
a.ecoles.filter(e => e !== a.ecole_principale).forEach(e => links.push({ source: a.id, target: `ecole-${e}`, strength: 0.25 }))
})
// Precalculer les positions cibles des ecoles pour ancrer les auteurs proches
const ecolePositions = new Map<string, { tx: number; ty: number }>()
ecoleNodes.forEach(e => { ecolePositions.set(e.ecoleId, { tx: e.x, ty: e.y }) })
if (simulation) simulation.stop()
simulation = d3.forceSimulation(allNodes)
.force('link', d3.forceLink(links).id((d: any) => d.id).distance(90).strength((d: any) => d.strength ?? 0.5))
.force('charge', d3.forceManyBody().strength(-80))
.force('link', d3.forceLink(links).id((d: any) => d.id).distance(130).strength((d: any) => d.strength ?? 0.5))
.force('charge', d3.forceManyBody().strength(-50))
.force('center', d3.forceCenter(W / 2, H / 2))
.force('collision', d3.forceCollide().radius((d: any) => d.r + 5))
.force('forceX', d3.forceX<any>((d: any) => {
if (d.type === 'auteur') {
const pos = ecolePositions.get(d.ecole_principale)
return pos ? pos.tx : W / 2
}
return W / 2
}).strength(0.08))
.force('forceY', d3.forceY<any>((d: any) => {
if (d.type === 'auteur') {
const pos = ecolePositions.get(d.ecole_principale)
return pos ? pos.ty : H / 2
}
return H / 2
}).strength(0.08))
d3LinkSel = g.append('g').selectAll('line').data(links).join('line')
.attr('stroke', 'rgba(150,150,150,0.3)').attr('stroke-width', 1.2)
@@ -84,7 +102,7 @@ async function initGraph() {
.attr('stroke-width', (d: any) => d.type === 'ecole' ? 3 : 1.5)
d3NodeSel.filter((d: any) => d.type === 'ecole').append('text')
.attr('text-anchor', 'middle').attr('dy', '0.35em').attr('font-size', '10px').attr('font-weight', '700').attr('fill', 'white')
.attr('text-anchor', 'middle').attr('dy', '0.35em').attr('font-size', '10px').attr('font-weight', '700').attr('fill', '#1a1a1a')
.style('pointer-events', 'none')
.each(function(d: any) {
const el = d3.select(this as any)