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
?