Download source/src/Motion.tsx from CladeTeam/ouroboros: direct link, hf CLI and curl.
- Browser
- Download file 2.14 kB
-
https://huggingface.co/spaces/CladeTeam/ouroboros/resolve/main/source/src/Motion.tsx
- Command line
-
hf download hf://spaces/CladeTeam/ouroboros/source/src/Motion.tsx
-
curl -L -o Motion.tsx https://huggingface.co/spaces/CladeTeam/ouroboros/resolve/main/source/src/Motion.tsx
2.14 kB
| import {createContext, useContext, useEffect, useState} from 'react'; | |
| import type {ReactNode} from 'react'; | |
| const MotionContext = createContext({enabled:true, reduced:false, paused:false, toggle:()=>{}}); | |
| /** A single preference governs ambient movement, tours and archived playback. */ | |
| export function MotionProvider({children}:{children:ReactNode}) { | |
| const [hidden,setHidden]=useState(document.hidden); | |
| const [reduced,setReduced]=useState(()=>window.matchMedia('(prefers-reduced-motion: reduce)').matches); | |
| const [paused,setPaused]=useState(()=>{try{return sessionStorage.getItem('ouroboros-motion-paused')==='true';}catch{return false;}}); | |
| useEffect(()=>{ | |
| const visibility=()=>setHidden(document.hidden); | |
| document.addEventListener('visibilitychange',visibility); | |
| return()=>document.removeEventListener('visibilitychange',visibility); | |
| },[]); | |
| useEffect(()=>{ | |
| const query=window.matchMedia('(prefers-reduced-motion: reduce)'); | |
| const update=()=>setReduced(query.matches); | |
| query.addEventListener('change',update); | |
| return()=>query.removeEventListener('change',update); | |
| },[]); | |
| useEffect(()=>{ | |
| document.documentElement.dataset.motion=paused||reduced||hidden?'paused':'running'; | |
| try{sessionStorage.setItem('ouroboros-motion-paused',String(paused));}catch{/* Preferences still work when storage is unavailable. */} | |
| },[paused,reduced,hidden]); | |
| return <MotionContext.Provider value={{enabled:!paused&&!reduced&&!hidden,reduced,paused,toggle:()=>setPaused(value=>!value)}}>{children}</MotionContext.Provider>; | |
| } | |
| export function useMotion(){return useContext(MotionContext);} | |
| export function MotionControl(){ | |
| const {enabled,reduced,toggle}=useMotion(); | |
| return <button className="motion-control" type="button" onClick={toggle} disabled={reduced} aria-label={reduced?'Animations off: reduced motion preference':enabled?'Pause page animations':'Resume page animations'} aria-pressed={!enabled} title={reduced?'Following your reduced motion preference':enabled?'Pause page animations':'Resume page animations'}><span aria-hidden="true">{enabled?'Ⅱ':'▷'}</span><span>{enabled?'Motion on':'Motion off'}</span></button>; | |
| } | |