fix(insights): sidebar user-controlled + cluster chips organisées
All checks were successful
CI / Lint, Unit Tests & Build (push) Successful in 5m25s
CI / Deploy production (on server) (push) Successful in 23s

Sidebar (UX: User Freedom):
- Visible par défaut sur /insights (pas caché par le système)
- Toggle via bouton hamburger: toggle-insights-sidebar event
- Préférence persistée en localStorage (insights-sidebar-collapsed)
- User décide: voir ou cacher le sidebar

Cluster chips:
- Triées par taille (plus grand cluster en premier)
- Compteur de notes par cluster (badge arrondi)
- max-w-[120px] sur le nom pour éviter overflow
- padding/gap plus compacts (px-2.5 py-1 gap-1.5)
This commit is contained in:
Antigravity
2026-07-04 20:37:42 +00:00
parent e48152e294
commit 72f9798e97
3 changed files with 38 additions and 14 deletions

View File

@@ -362,22 +362,27 @@ export function NetworkGraph({
return (
<div ref={containerRef} className="w-full h-full bg-paper dark:bg-[#121212] rounded-3xl overflow-hidden border border-border/40 relative">
{/* Pastilles de cluster — cliquables pour activer le focus */}
<div className="absolute top-6 left-6 z-10 flex flex-wrap gap-2 max-w-[90%]">
{clusters.map(c => {
{/* Pastilles de cluster — triées par taille, avec compteurs */}
<div className="absolute top-6 left-6 z-10 flex flex-wrap gap-1.5 max-w-[85%]">
{[...clusters]
.sort((a, b) => b.noteIds.length - a.noteIds.length)
.map(c => {
const isSelected = String(c.id) === selectedClusterId
return (
<button
key={c.id}
onClick={() => onClusterSelect?.(isSelected ? null : String(c.id))}
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-full border shadow-sm transition-all text-[9px] font-bold uppercase tracking-wider ${
className={`flex items-center gap-1.5 px-2.5 py-1 rounded-full border transition-all text-[9px] font-bold uppercase tracking-wider cursor-pointer focus-visible:ring-2 focus-visible:ring-ochre/50 focus-visible:outline-none ${
isSelected
? 'bg-ink text-white dark:bg-white dark:text-black border-ink dark:border-white scale-105 shadow-md'
: 'bg-white/90 dark:bg-black/80 text-concrete hover:text-ink hover:border-concrete/40 border-border'
: 'bg-white/90 dark:bg-black/80 text-concrete hover:text-ink hover:border-concrete/40 border-border shadow-sm'
}`}
>
<div className="w-1.5 h-1.5 rounded-full" style={{ backgroundColor: c.color }} />
<span>{c.name ?? String(c.id)}</span>
<div className="w-2 h-2 rounded-full shrink-0" style={{ backgroundColor: c.color }} />
<span className="truncate max-w-[120px]">{c.name ?? String(c.id)}</span>
<span className={`text-[8px] px-1 rounded-full shrink-0 ${isSelected ? 'bg-white/20' : 'bg-black/5 dark:bg-white/10'}`}>
{c.noteIds.length}
</span>
</button>
)
})}