web/main: also support back button for right panel

This commit is contained in:
Tulir Asokan 2024-12-04 01:49:50 +02:00
parent 1a2833ed53
commit 2f22159da3

View file

@ -13,7 +13,7 @@
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import { JSX, use, useEffect, useInsertionEffect, useLayoutEffect, useMemo, useReducer, useState } from "react" import { JSX, use, useEffect, useInsertionEffect, useLayoutEffect, useMemo, useState } from "react"
import { SyncLoader } from "react-spinners" import { SyncLoader } from "react-spinners"
import Client from "@/api/client.ts" import Client from "@/api/client.ts"
import { RoomStateStore } from "@/api/statestore" import { RoomStateStore } from "@/api/statestore"
@ -43,18 +43,12 @@ function objectIsEqual(a: RightPanelProps | null, b: RightPanelProps | null): bo
return true return true
} }
const rpReducer = (prevState: RightPanelProps | null, newState: RightPanelProps | null) => {
if (objectIsEqual(prevState, newState)) {
return null
}
return newState
}
class ContextFields implements MainScreenContextFields { class ContextFields implements MainScreenContextFields {
public keybindings: Keybindings public keybindings: Keybindings
private rightPanelStack: RightPanelProps[] = []
constructor( constructor(
public setRightPanel: (props: RightPanelProps | null) => void, private directSetRightPanel: (props: RightPanelProps | null) => void,
private directSetActiveRoom: (room: RoomStateStore | null) => void, private directSetActiveRoom: (room: RoomStateStore | null) => void,
private client: Client, private client: Client,
) { ) {
@ -62,12 +56,47 @@ class ContextFields implements MainScreenContextFields {
client.store.switchRoom = this.setActiveRoom client.store.switchRoom = this.setActiveRoom
} }
get currentRightPanel(): RightPanelProps | null {
return this.rightPanelStack.length ? this.rightPanelStack[this.rightPanelStack.length-1] : null
}
setRightPanel = (props: RightPanelProps | null, pushState = true) => {
const isEqual = objectIsEqual(this.currentRightPanel, props)
if (isEqual && !pushState) {
return
}
if (isEqual || props === null) {
const length = this.rightPanelStack.length
this.rightPanelStack = []
this.directSetRightPanel(null)
if (length && pushState) {
history.go(-length)
}
} else {
this.directSetRightPanel(props)
for (let i = this.rightPanelStack.length - 1; i >= 0; i--) {
if (objectIsEqual(this.rightPanelStack[i], props)) {
this.rightPanelStack = this.rightPanelStack.slice(0, i + 1)
if (pushState) {
history.go(i - this.rightPanelStack.length)
}
return
}
} // else:
this.rightPanelStack.push(props)
if (pushState) {
history.pushState({ ...(history.state ?? {}), right_panel: props }, "")
}
}
}
setActiveRoom = (roomID: RoomID | null, pushState = true) => { setActiveRoom = (roomID: RoomID | null, pushState = true) => {
console.log("Switching to room", roomID) console.log("Switching to room", roomID)
const room = (roomID && this.client.store.rooms.get(roomID)) || null const room = (roomID && this.client.store.rooms.get(roomID)) || null
window.activeRoom = room window.activeRoom = room
this.directSetActiveRoom(room) this.directSetActiveRoom(room)
this.setRightPanel(null) this.directSetRightPanel(null)
this.rightPanelStack = []
this.client.store.activeRoomID = room?.roomID ?? null this.client.store.activeRoomID = room?.roomID ?? null
this.keybindings.activeRoom = room this.keybindings.activeRoom = room
if (room) { if (room) {
@ -113,11 +142,11 @@ const SYNC_ERROR_HIDE_DELAY = 30 * 1000
const MainScreen = () => { const MainScreen = () => {
const [activeRoom, directSetActiveRoom] = useState<RoomStateStore | null>(null) const [activeRoom, directSetActiveRoom] = useState<RoomStateStore | null>(null)
const [rightPanel, setRightPanel] = useReducer(rpReducer, null) const [rightPanel, directSetRightPanel] = useState<RightPanelProps | null>(null)
const client = use(ClientContext)! const client = use(ClientContext)!
const syncStatus = useEventAsState(client.syncStatus) const syncStatus = useEventAsState(client.syncStatus)
const context = useMemo( const context = useMemo(
() => new ContextFields(setRightPanel, directSetActiveRoom, client), () => new ContextFields(directSetRightPanel, directSetActiveRoom, client),
[client], [client],
) )
useLayoutEffect(() => { useLayoutEffect(() => {
@ -129,6 +158,7 @@ const MainScreen = () => {
if (roomID !== client.store.activeRoomID) { if (roomID !== client.store.activeRoomID) {
context.setActiveRoom(roomID, false) context.setActiveRoom(roomID, false)
} }
context.setRightPanel(evt.state?.right_panel ?? null, false)
} }
window.addEventListener("popstate", listener) window.addEventListener("popstate", listener)
return () => window.removeEventListener("popstate", listener) return () => window.removeEventListener("popstate", listener)