From 5f880b2487b77dc183deb12807ab1578fd02a05e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 15 Dec 2024 16:27:18 +0200 Subject: [PATCH] web/mainscreen: add animation for entering rooms --- web/src/index.css | 1 + web/src/ui/MainScreen.css | 35 +++++++++++++++++------------------ web/src/ui/MainScreen.tsx | 30 +++++++++++++++++++++++++----- 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/web/src/index.css b/web/src/index.css index 807114e..2d24b41 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -162,6 +162,7 @@ body { html { touch-action: none; + background-color: var(--background-color); } #root { diff --git a/web/src/ui/MainScreen.css b/web/src/ui/MainScreen.css index 9539e76..b1604fb 100644 --- a/web/src/ui/MainScreen.css +++ b/web/src/ui/MainScreen.css @@ -17,25 +17,24 @@ main.matrix-main { } @media screen and (max-width: 45rem) { + &, &.right-panel-open { + grid-template: + "roomlist roomview rightpanel" 1fr + / 100% 100% 100%; + } + /* Note: this timeout must match the one in MainScreen.tsx */ + transition: .3s; + + @media (prefers-reduced-motion: reduce) { + transition: none; + } + + &.room-selected { + translate: -100% 0; + } + &.right-panel-open { - grid-template: "rightpanel" 1fr / 1fr; - > div.room-list-wrapper { - display: none; - } - > div.room-view { - display: none; - } - } - - &.room-selected:not(.right-panel-open) { - grid-template: "roomview" 1fr / 1fr; - > div.room-list-wrapper { - display: none; - } - } - - &:not(.room-selected):not(.right-panel-open) { - grid-template: "roomlist" 1fr / 1fr; + translate: -200% 0; } } diff --git a/web/src/ui/MainScreen.tsx b/web/src/ui/MainScreen.tsx index 68d3476..63724c8 100644 --- a/web/src/ui/MainScreen.tsx +++ b/web/src/ui/MainScreen.tsx @@ -13,7 +13,7 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import { JSX, use, useEffect, useInsertionEffect, useLayoutEffect, useMemo, useState } from "react" +import { JSX, use, useEffect, useInsertionEffect, useLayoutEffect, useMemo, useReducer, useState } from "react" import { SyncLoader } from "react-spinners" import Client from "@/api/client.ts" import { RoomStateStore } from "@/api/statestore" @@ -208,8 +208,20 @@ const handleURLHash = (client: Client) => { return history.state } +type ActiveRoomType = [RoomStateStore | null, RoomStateStore | null] + +const activeRoomReducer = (prev: ActiveRoomType, active: RoomStateStore | "clear-animation" | null): ActiveRoomType => { + if (active === "clear-animation") { + return prev[1] === null ? [null, null] : prev + } else if (window.innerWidth > 720 || window.matchMedia("(prefers-reduced-motion: reduce)").matches) { + return [null, active] + } else { + return [prev[1], active] + } +} + const MainScreen = () => { - const [activeRoom, directSetActiveRoom] = useState(null) + const [[prevActiveRoom, activeRoom], directSetActiveRoom] = useReducer(activeRoomReducer, [null, null] as const) const [rightPanel, directSetRightPanel] = useState(null) const client = use(ClientContext)! const syncStatus = useEventAsState(client.syncStatus) @@ -292,16 +304,24 @@ const MainScreen = () => { Sync is failing } + const renderedRoom = activeRoom ?? prevActiveRoom + useEffect(() => { + if (prevActiveRoom !== null && activeRoom === null) { + // Note: this timeout must match the one in MainScreen.css + const timeout = setTimeout(() => directSetActiveRoom("clear-animation"), 300) + return () => clearTimeout(timeout) + } + }, [activeRoom, prevActiveRoom]) return
{resizeHandle1} - {activeRoom + {renderedRoom ?