Display the list of spaces

This commit is contained in:
2025-11-24 16:05:01 +01:00
parent 0a37688116
commit 820b095be0
11 changed files with 218 additions and 21 deletions

View File

@@ -0,0 +1,54 @@
import React from "react";
import {
MatrixApiProfile,
type UsersMap,
} from "../../api/matrix/MatrixApiProfile";
import { MatrixApiRoom, type Room } from "../../api/matrix/MatrixApiRoom";
import { MatrixSyncApi } from "../../api/MatrixSyncApi";
import { AsyncWidget } from "../AsyncWidget";
import { SpaceSelector } from "./SpaceSelector";
import { Divider } from "@mui/material";
export function MainMessageWidget(): React.ReactElement {
const [rooms, setRooms] = React.useState<Room[] | undefined>();
const [users, setUsers] = React.useState<UsersMap | undefined>();
const load = async () => {
await MatrixSyncApi.Start();
const rooms = await MatrixApiRoom.ListJoined();
setRooms(rooms);
// Get the list of users in rooms
const users = rooms.reduce((prev, r) => {
r.members.forEach((m) => prev.add(m));
return prev;
}, new Set<string>());
setUsers(await MatrixApiProfile.GetMultiple([...users]));
};
return (
<AsyncWidget
loadKey={1}
load={load}
ready={!!rooms && !!users}
errMsg="Failed to initialize messaging component!"
build={() => <_MainMessageWidget rooms={rooms!} users={users!} />}
/>
);
}
function _MainMessageWidget(p: {
rooms: Room[];
users: UsersMap;
}): React.ReactElement {
const [space, setSpace] = React.useState<string | undefined>();
return (
<div style={{ display: "flex", height: "100%" }}>
<SpaceSelector {...p} selectedSpace={space} onChange={setSpace} />
<Divider orientation="vertical" />
<span style={{ flex: 1 }}>todo</span>
</div>
);
}

View File

@@ -0,0 +1,32 @@
import { Icon } from "@mui/material";
import { MatrixApiMedia } from "../../api/matrix/MatrixApiMedia";
import type { UsersMap } from "../../api/matrix/MatrixApiProfile";
import type { Room } from "../../api/matrix/MatrixApiRoom";
import { useUserInfo } from "../dashboard/BaseAuthenticatedPage";
import GroupIcon from "@mui/icons-material/Group";
export function RoomIcon(p: {
room: Room;
users: UsersMap;
}): React.ReactElement {
const user = useUserInfo();
let url = p.room.avatar;
if (!url && p.room.members.length <= 1) url = p.room.members[0];
if (!url && p.room.members.length < 2)
url =
p.room.members[0] == user.info.matrix_user_id
? p.room.members[1]
: p.room.members[0];
if (!url) return <GroupIcon />;
else
return (
<img
src={MatrixApiMedia.MediaURL(url, true)}
style={{ maxWidth: "1em", maxHeight: "1em" }}
/>
);
}

View File

@@ -0,0 +1,53 @@
import HomeIcon from "@mui/icons-material/Home";
import { Button } from "@mui/material";
import React from "react";
import type { UsersMap } from "../../api/matrix/MatrixApiProfile";
import type { Room } from "../../api/matrix/MatrixApiRoom";
import { RoomIcon } from "./RoomIcon";
export function SpaceSelector(p: {
rooms: Room[];
users: UsersMap;
selectedSpace?: string;
onChange: (space?: string) => void;
}): React.ReactElement {
const spaces = React.useMemo(
() => p.rooms.filter((r) => r.is_space),
[p.rooms]
);
return (
<div style={{ display: "flex", flexDirection: "column" }}>
<SpaceButton
icon={<HomeIcon />}
onClick={() => p.onChange()}
selected={p.selectedSpace === undefined}
/>
{spaces.map((s) => (
<SpaceButton
key={s.id}
icon={<RoomIcon room={s} {...p} />}
onClick={() => p.onChange(s.id)}
selected={p.selectedSpace === s.id}
/>
))}
</div>
);
}
function SpaceButton(p: {
selected?: boolean;
icon: React.ReactElement;
onClick: () => void;
}): React.ReactElement {
return (
<Button
variant={p.selected ? "contained" : "text"}
style={{ margin: "2px 5px", padding: "25px 10px", fontSize: "200%" }}
onClick={p.onClick}
>
{p.icon}
</Button>
);
}