mirror of
https://github.com/samvallad33/vestige.git
synced 2026-07-02 22:01:01 +02:00
feat(dashboard): respect prefers-reduced-motion in the base 3D graph
Disable camera auto-rotate (the dominant continuous motion) when the OS reduce-motion setting is on; live-toggle aware via matchMedia change listener, cleaned up on destroy. Graph stays fully usable (manual orbit/hover/select/live events). Closes the a11y gap where 0 of ~3,200 graph LOC honoured the setting. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a6798c2fca
commit
95750f0a85
1 changed files with 24 additions and 0 deletions
|
|
@ -50,6 +50,20 @@
|
|||
let ctx: SceneContext;
|
||||
let animationId: number;
|
||||
|
||||
// Accessibility: honour the OS "reduce motion" setting. The dominant
|
||||
// continuous motion in the graph is the camera auto-rotate; disabling it
|
||||
// removes the vestibular-trigger while keeping the graph fully usable
|
||||
// (manual orbit, hover, selection, live events all still work). Tracked
|
||||
// reactively so a mid-session OS toggle is respected.
|
||||
let prefersReducedMotion =
|
||||
typeof window !== 'undefined' &&
|
||||
window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
|
||||
let reducedMotionMq: MediaQueryList | null = null;
|
||||
function onReducedMotionChange(e: MediaQueryListEvent) {
|
||||
prefersReducedMotion = e.matches;
|
||||
if (ctx?.controls) ctx.controls.autoRotate = !prefersReducedMotion;
|
||||
}
|
||||
|
||||
// Modules
|
||||
let nodeManager: NodeManager;
|
||||
let edgeManager: EdgeManager;
|
||||
|
|
@ -74,6 +88,15 @@
|
|||
onMount(() => {
|
||||
ctx = createScene(container);
|
||||
|
||||
// Respect reduced-motion: the scene defaults to auto-rotate on; turn it
|
||||
// off up front for users who asked for less motion, and listen for live
|
||||
// OS-setting changes.
|
||||
if (prefersReducedMotion) ctx.controls.autoRotate = false;
|
||||
if (typeof window !== 'undefined' && window.matchMedia) {
|
||||
reducedMotionMq = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||
reducedMotionMq.addEventListener?.('change', onReducedMotionChange);
|
||||
}
|
||||
|
||||
// Nebula background
|
||||
const nebula = createNebulaBackground(ctx.scene);
|
||||
nebulaMaterial = nebula.material;
|
||||
|
|
@ -113,6 +136,7 @@
|
|||
onDestroy(() => {
|
||||
cancelAnimationFrame(animationId);
|
||||
window.removeEventListener('resize', onResize);
|
||||
reducedMotionMq?.removeEventListener?.('change', onReducedMotionChange);
|
||||
container?.removeEventListener('pointermove', onPointerMove);
|
||||
container?.removeEventListener('click', onClick);
|
||||
effects?.dispose();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue