web/roomlist: add pseudo-spaces for unreads and DMs

Fixes #519
This commit is contained in:
Tulir Asokan 2024-12-29 14:40:32 +02:00
parent 5a8139685d
commit 6b01dec307
6 changed files with 75 additions and 7 deletions

View file

@ -17,11 +17,24 @@ import { RoomListEntry, StateStore } from "@/api/statestore/main.ts"
import { DBSpaceEdge, RoomID } from "@/api/types"
export interface RoomListFilter {
id: unknown
id: string
include(room: RoomListEntry): boolean
}
export class SpaceEdgeStore {
export const DirectChatSpace: RoomListFilter = {
id: "fi.mau.gomuks.direct_chats",
include: room => !!room.dm_user_id,
}
export const UnreadsSpace: RoomListFilter = {
id: "fi.mau.gomuks.unreads",
include: room => Boolean(room.unread_messages
|| room.unread_notifications
|| room.unread_highlights
|| room.marked_unread),
}
export class SpaceEdgeStore implements RoomListFilter {
#children: DBSpaceEdge[] = []
#childRooms: Set<RoomID> = new Set()
#flattenedRooms: Set<RoomID> = new Set()

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M480-80q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80Zm0-420ZM160-200v-80h80v-280q0-83 50-147.5T420-792v-28q0-25 17.5-42.5T480-880q25 0 42.5 17.5T540-820v13q-11 22-16 45t-4 47q-10-2-19.5-3.5T480-720q-66 0-113 47t-47 113v280h320v-257q18 8 38.5 12.5T720-520v240h80v80H160Zm560-400q-50 0-85-35t-35-85q0-50 35-85t85-35q50 0 85 35t35 85q0 50-35 85t-85 35Z"/></svg>

After

Width:  |  Height:  |  Size: 480 B

1
web/src/icons/person.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M480-480q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47ZM160-160v-112q0-34 17.5-62.5T224-378q62-31 126-46.5T480-440q66 0 130 15.5T736-378q29 15 46.5 43.5T800-272v112H160Zm80-80h480v-32q0-11-5.5-20T700-306q-54-27-109-40.5T480-360q-56 0-111 13.5T260-306q-9 5-14.5 14t-5.5 20v32Zm240-320q33 0 56.5-23.5T560-640q0-33-23.5-56.5T480-720q-33 0-56.5 23.5T400-640q0 33 23.5 56.5T480-560Zm0-80Zm0 400Z"/></svg>

After

Width:  |  Height:  |  Size: 549 B

1
web/src/icons/tag.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="m240-160 40-160H120l20-80h160l40-160H180l20-80h160l40-160h80l-40 160h160l40-160h80l-40 160h160l-20 80H660l-40 160h160l-20 80H600l-40 160h-80l40-160H360l-40 160h-80Zm140-240h160l40-160H420l-40 160Z"/></svg>

After

Width:  |  Height:  |  Size: 322 B

View file

@ -0,0 +1,52 @@
// gomuks - A Matrix client written in Go.
// Copyright (C) 2024 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// 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/>.
import { JSX } from "react"
import type { RoomListFilter } from "@/api/statestore/space.ts"
import HomeIcon from "@/icons/home.svg?react"
import NotificationsIcon from "@/icons/notifications.svg?react"
import PersonIcon from "@/icons/person.svg?react"
import TagIcon from "@/icons/tag.svg?react"
import "./RoomList.css"
export interface FakeSpaceProps {
space: RoomListFilter | null
setSpace: (space: RoomListFilter | null) => void
isActive: boolean
}
const getFakeSpaceIcon = (space: RoomListFilter | null): JSX.Element | null => {
switch (space?.id) {
case undefined:
return <HomeIcon />
case "fi.mau.gomuks.direct_chats":
return <PersonIcon />
case "fi.mau.gomuks.unreads":
return <NotificationsIcon />
case "fi.mau.gomuks.space_orphans":
return <TagIcon />
default:
return null
}
}
const FakeSpace = ({ space, setSpace, isActive }: FakeSpaceProps) => {
return <div className={`space-entry ${isActive ? "active" : ""}`} onClick={() => setSpace(space)}>
{getFakeSpaceIcon(space)}
</div>
}
export default FakeSpace

View file

@ -14,7 +14,7 @@
// 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/>.
import React, { use, useCallback, useRef, useState } from "react"
import type { RoomListFilter } from "@/api/statestore/space.ts"
import { DirectChatSpace, RoomListFilter, UnreadsSpace } from "@/api/statestore/space.ts"
import type { RoomID } from "@/api/types"
import { useEventAsState } from "@/util/eventdispatcher.ts"
import reverseMap from "@/util/reversemap.ts"
@ -23,9 +23,9 @@ import ClientContext from "../ClientContext.ts"
import MainScreenContext from "../MainScreenContext.ts"
import { keyToString } from "../keybindings.ts"
import Entry from "./Entry.tsx"
import FakeSpace from "./FakeSpace.tsx"
import Space from "./Space.tsx"
import CloseIcon from "@/icons/close.svg?react"
import HomeIcon from "@/icons/home.svg?react"
import SearchIcon from "@/icons/search.svg?react"
import "./RoomList.css"
@ -92,9 +92,9 @@ const RoomList = ({ activeRoomID }: RoomListProps) => {
</button>
</div>
<div className="space-bar">
<div className={`space-entry ${space === null ? "active" : ""}`} onClick={() => setSpace(null)}>
<HomeIcon />
</div>
<FakeSpace space={null} setSpace={setSpace} isActive={space === null} />
<FakeSpace space={DirectChatSpace} setSpace={setSpace} isActive={space?.id === DirectChatSpace.id} />
<FakeSpace space={UnreadsSpace} setSpace={setSpace} isActive={space?.id === UnreadsSpace.id} />
{spaces.map(roomID => <Space
roomID={roomID}
client={client}