feat(insights): bouton Fit view sur le graphe — reset zoom + clear focus
- zoomRef stocke le behavior d3.zoom pour accès externe au useEffect - handleFitView: d3.zoomIdentity reset (600ms transition) + clear selectedClusterId - Bouton Maximize2 en haut à droite du graphe avec aria-label - cursor-pointer + focus-visible:ring pour a11y
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"lastRunAtMs": 1782633053032,
|
"lastRunAtMs": 1782633053032,
|
||||||
"turnsSinceLastRun": 6,
|
"turnsSinceLastRun": 7,
|
||||||
"lastTranscriptMtimeMs": 1782633052959.9294,
|
"lastTranscriptMtimeMs": 1782633052959.9294,
|
||||||
"lastProcessedGenerationId": "fa1ae817-7a99-4fd6-8b50-8407600557dd",
|
"lastProcessedGenerationId": "5c41c5b1-0c40-4c8e-a6df-b22e873df8f6",
|
||||||
"trialStartedAtMs": null
|
"trialStartedAtMs": null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { useEffect, useRef } from 'react'
|
import { useEffect, useRef } from 'react'
|
||||||
import * as d3 from 'd3'
|
import * as d3 from 'd3'
|
||||||
|
import { Maximize2 } from 'lucide-react'
|
||||||
|
|
||||||
interface Note {
|
interface Note {
|
||||||
id: string
|
id: string
|
||||||
@@ -49,6 +50,7 @@ export function NetworkGraph({
|
|||||||
}: NetworkGraphProps) {
|
}: NetworkGraphProps) {
|
||||||
const svgRef = useRef<SVGSVGElement>(null)
|
const svgRef = useRef<SVGSVGElement>(null)
|
||||||
const containerRef = useRef<HTMLDivElement>(null)
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
|
const zoomRef = useRef<any>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!svgRef.current || !containerRef.current) return
|
if (!svgRef.current || !containerRef.current) return
|
||||||
@@ -67,6 +69,7 @@ export function NetworkGraph({
|
|||||||
g.attr('transform', event.transform)
|
g.attr('transform', event.transform)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
zoomRef.current = zoom
|
||||||
svg.call(zoom as any)
|
svg.call(zoom as any)
|
||||||
|
|
||||||
// Filter notes with cluster assignments
|
// Filter notes with cluster assignments
|
||||||
@@ -348,6 +351,15 @@ export function NetworkGraph({
|
|||||||
}
|
}
|
||||||
}, [notes, clusters, bridgeNotes, onNoteSelect, selectedClusterId])
|
}, [notes, clusters, bridgeNotes, onNoteSelect, selectedClusterId])
|
||||||
|
|
||||||
|
const handleFitView = () => {
|
||||||
|
if (!svgRef.current || !zoomRef.current) return
|
||||||
|
d3.select(svgRef.current)
|
||||||
|
.transition()
|
||||||
|
.duration(600)
|
||||||
|
.call(zoomRef.current.transform, d3.zoomIdentity)
|
||||||
|
onClusterSelect?.(null)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={containerRef} className="w-full h-full bg-paper dark:bg-[#121212] rounded-3xl overflow-hidden border border-border/40 relative">
|
<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 */}
|
{/* Pastilles de cluster — cliquables pour activer le focus */}
|
||||||
@@ -378,6 +390,15 @@ export function NetworkGraph({
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{/* Fit view button */}
|
||||||
|
<button
|
||||||
|
onClick={handleFitView}
|
||||||
|
className="absolute top-6 right-6 z-10 flex items-center gap-1.5 px-3 py-1.5 rounded-full border border-border/40 bg-white/90 dark:bg-black/80 text-concrete hover:text-ink dark:hover:text-dark-ink hover:border-concrete/40 text-[9px] font-bold uppercase tracking-wider transition-all shadow-sm cursor-pointer focus-visible:ring-2 focus-visible:ring-ochre/50 focus-visible:outline-none backdrop-blur-sm"
|
||||||
|
aria-label={fitViewLabel}
|
||||||
|
>
|
||||||
|
<Maximize2 size={11} />
|
||||||
|
{fitViewLabel}
|
||||||
|
</button>
|
||||||
<svg ref={svgRef} className="w-full h-full" />
|
<svg ref={svgRef} className="w-full h-full" />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user