From b5c6c1a937bda173cb6daae0a8c46693ddcf75cd Mon Sep 17 00:00:00 2001 From: Evan Simkowitz Date: Wed, 14 Aug 2024 21:47:09 -0700 Subject: [PATCH] Create reduced motIon setting (#226) Adds a new setting that emulates the prefers-reduced-motion media query, allowing users to disable Wave animations without affecting other apps on their system. It also honors the prefers-reduced-motion query in case a system-level configuration is present. --- frontend/app/app.tsx | 22 ++++++++++++++++++++-- frontend/app/element/magnify.less | 2 +- frontend/app/store/global.ts | 16 +++++++++------- frontend/layout/lib/tilelayout.less | 2 +- frontend/types/custom.d.ts | 1 + frontend/types/gotypes.d.ts | 1 + pkg/wconfig/settingsconfig.go | 9 +++++---- 7 files changed, 38 insertions(+), 15 deletions(-) diff --git a/frontend/app/app.tsx b/frontend/app/app.tsx index 9625e860..8a9b8785 100644 --- a/frontend/app/app.tsx +++ b/frontend/app/app.tsx @@ -459,8 +459,20 @@ const AppKeyHandlers = () => { }; const AppInner = () => { + const [prefersReducedMotion, setPrefersReducedMotion] = React.useState(false); + const prefersReducedMotionSetting = jotai.useAtomValue(atoms.reducedMotionPreferenceAtom); const client = jotai.useAtomValue(atoms.client); const windowData = jotai.useAtomValue(atoms.waveWindow); + const isFullScreen = jotai.useAtomValue(atoms.isFullScreen); + + React.useEffect(() => { + const reducedMotionQuery = window.matchMedia("(prefers-reduced-motion: reduce)"); + setPrefersReducedMotion(!reducedMotionQuery || reducedMotionQuery.matches); + reducedMotionQuery.addEventListener("change", () => { + setPrefersReducedMotion(reducedMotionQuery.matches); + }); + }, []); + if (client == null || windowData == null) { return (
@@ -470,12 +482,18 @@ const AppInner = () => { ); } - const isFullScreen = jotai.useAtomValue(atoms.isFullScreen); return ( -
+
+ -m diff --git a/frontend/app/element/magnify.less b/frontend/app/element/magnify.less index 48a402f3..e288333c 100644 --- a/frontend/app/element/magnify.less +++ b/frontend/app/element/magnify.less @@ -26,7 +26,7 @@ } } -@media (prefers-reduced-motion) { +.prefers-reduced-motion { .magnify-icon svg { #arrow1, #arrow2 { diff --git a/frontend/app/store/global.ts b/frontend/app/store/global.ts index e0e83b5c..a221951e 100644 --- a/frontend/app/store/global.ts +++ b/frontend/app/store/global.ts @@ -101,16 +101,17 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) { return windowData.activetabid; }); const controlShiftDelayAtom = jotai.atom(false); - const updateStatusAtom = jotai.atom("up-to-date") as jotai.PrimitiveAtom; + const updaterStatusAtom = jotai.atom("up-to-date") as jotai.PrimitiveAtom; try { - globalStore.set(updateStatusAtom, getApi().getUpdaterStatus()); + globalStore.set(updaterStatusAtom, getApi().getUpdaterStatus()); getApi().onUpdaterStatusChange((status) => { console.log("updater status change", status); - globalStore.set(updateStatusAtom, status); + globalStore.set(updaterStatusAtom, status); }); } catch (_) { // do nothing } + const reducedMotionPreferenceAtom = jotai.atom((get) => get(settingsConfigAtom).window.reducedmotion); atoms = { // initialized in wave.ts (will not be null inside of application) windowId: windowIdAtom, @@ -119,12 +120,13 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) { client: clientAtom, waveWindow: windowDataAtom, workspace: workspaceAtom, - settingsConfigAtom: settingsConfigAtom, - tabAtom: tabAtom, + settingsConfigAtom, + tabAtom, activeTabId: activeTabIdAtom, isFullScreen: isFullScreenAtom, - controlShiftDelayAtom: controlShiftDelayAtom, - updaterStatusAtom: updateStatusAtom, + controlShiftDelayAtom, + updaterStatusAtom, + reducedMotionPreferenceAtom, }; } diff --git a/frontend/layout/lib/tilelayout.less b/frontend/layout/lib/tilelayout.less index 81f70570..2ce0ae7e 100644 --- a/frontend/layout/lib/tilelayout.less +++ b/frontend/layout/lib/tilelayout.less @@ -125,7 +125,7 @@ } } -@media (prefers-reduced-motion) { +.prefers-reduced-motion { .tile-layout { &.animate { .tile-node, diff --git a/frontend/types/custom.d.ts b/frontend/types/custom.d.ts index 15bd45a8..2ad52d2d 100644 --- a/frontend/types/custom.d.ts +++ b/frontend/types/custom.d.ts @@ -17,6 +17,7 @@ declare global { activeTabId: jotai.Atom; // derrived from windowDataAtom isFullScreen: jotai.PrimitiveAtom; controlShiftDelayAtom: jotai.PrimitiveAtom; + reducedMotionPreferenceAtom: jotai.Atom; updaterStatusAtom: jotai.PrimitiveAtom; }; diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index f57030be..14ea6c7e 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -616,6 +616,7 @@ declare global { blur: boolean; opacity: number; bgcolor: string; + reducedmotion: boolean; }; // wstore.Workspace diff --git a/pkg/wconfig/settingsconfig.go b/pkg/wconfig/settingsconfig.go index 22beca70..e059715e 100644 --- a/pkg/wconfig/settingsconfig.go +++ b/pkg/wconfig/settingsconfig.go @@ -89,10 +89,11 @@ type TermThemesConfigType map[string]TermThemeType // note we pointers so we preserve nulls type WindowSettingsType struct { - Transparent *bool `json:"transparent"` - Blur *bool `json:"blur"` - Opacity *float64 `json:"opacity"` - BgColor *string `json:"bgcolor"` + Transparent *bool `json:"transparent"` + Blur *bool `json:"blur"` + Opacity *float64 `json:"opacity"` + BgColor *string `json:"bgcolor"` + ReducedMotion *bool `json:"reducedmotion"` } type TelemetrySettingsType struct {