Files
element-web/src/components/views/rooms/RoomListPanel/RoomListHeaderView.tsx
Florian Duros 1e689ac098 Move Flex & Box component into shared component folder (#30357)
* refactor: move Flex component in shared components

* refactor: update imports

* refactor: remove Flex pcss file

* fix: Flex component css override

* test: update snapshots

* fix: html export

* chore: add css module support to jest

* chore: keep old copyright

* refactor: change `mx_Flex` in `ErrorView` to `mx_ErrorView_flexContainer`

* test: update snapshots

* refactor: move Box component in shared components

* refactor: update import and css override

* test: update snapshots
2025-07-22 16:25:45 +00:00

166 lines
5.7 KiB
TypeScript

/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
import React, { type JSX, useState } from "react";
import { IconButton, Menu, MenuItem } from "@vector-im/compound-web";
import ComposeIcon from "@vector-im/compound-design-tokens/assets/web/icons/compose";
import UserAddIcon from "@vector-im/compound-design-tokens/assets/web/icons/user-add";
import ChevronDownIcon from "@vector-im/compound-design-tokens/assets/web/icons/chevron-down";
import RoomIcon from "@vector-im/compound-design-tokens/assets/web/icons/room";
import HomeIcon from "@vector-im/compound-design-tokens/assets/web/icons/home";
import PreferencesIcon from "@vector-im/compound-design-tokens/assets/web/icons/preferences";
import SettingsIcon from "@vector-im/compound-design-tokens/assets/web/icons/settings";
import VideoCallIcon from "@vector-im/compound-design-tokens/assets/web/icons/video-call";
import { _t } from "../../../../languageHandler";
import { Flex } from "../../../../shared-components/utils/Flex";
import {
type RoomListHeaderViewState,
useRoomListHeaderViewModel,
} from "../../../viewmodels/roomlist/RoomListHeaderViewModel";
import { RoomListOptionsMenu } from "./RoomListOptionsMenu";
/**
* The header view for the room list
* The space name is displayed and a compose menu is shown if the user can create rooms
*/
export function RoomListHeaderView(): JSX.Element {
const vm = useRoomListHeaderViewModel();
return (
<Flex
as="header"
className="mx_RoomListHeaderView"
aria-label={_t("room|context_menu|title")}
justify="space-between"
align="center"
data-testid="room-list-header"
>
<Flex className="mx_RoomListHeaderView_title" align="center" gap="var(--cpd-space-1x)">
<h1 title={vm.title}>{vm.title}</h1>
{vm.displaySpaceMenu && <SpaceMenu vm={vm} />}
</Flex>
<Flex align="center" gap="var(--cpd-space-2x)">
<RoomListOptionsMenu vm={vm} />
{/* If we don't display the compose menu, it means that the user can only send DM */}
{vm.displayComposeMenu ? (
<ComposeMenu vm={vm} />
) : (
<IconButton aria-label={_t("action|new_message")} onClick={(e) => vm.createChatRoom(e.nativeEvent)}>
<ComposeIcon color="var(--cpd-color-icon-secondary)" />
</IconButton>
)}
</Flex>
</Flex>
);
}
interface SpaceMenuProps {
/**
* The view model for the room list header
*/
vm: RoomListHeaderViewState;
}
/**
* The space menu for the room list header
*/
function SpaceMenu({ vm }: SpaceMenuProps): JSX.Element {
const [open, setOpen] = useState(false);
return (
<Menu
open={open}
onOpenChange={setOpen}
title={vm.title}
side="right"
align="start"
trigger={
<IconButton className="mx_SpaceMenu_button" aria-label={_t("room_list|open_space_menu")} size="20px">
<ChevronDownIcon color="var(--cpd-color-icon-secondary)" />
</IconButton>
}
>
<MenuItem
Icon={HomeIcon}
label={_t("room_list|space_menu|home")}
onSelect={vm.openSpaceHome}
hideChevron={true}
/>
{vm.canInviteInSpace && (
<MenuItem
Icon={UserAddIcon}
label={_t("action|invite")}
onSelect={vm.inviteInSpace}
hideChevron={true}
/>
)}
<MenuItem
Icon={PreferencesIcon}
label={_t("common|preferences")}
onSelect={vm.openSpacePreferences}
hideChevron={true}
/>
{vm.canAccessSpaceSettings && (
<MenuItem
Icon={SettingsIcon}
label={_t("room_list|space_menu|space_settings")}
onSelect={vm.openSpaceSettings}
hideChevron={true}
/>
)}
</Menu>
);
}
interface ComposeMenuProps {
/**
* The view model for the room list header
*/
vm: RoomListHeaderViewState;
}
/**
* The compose menu for the room list header
*/
function ComposeMenu({ vm }: ComposeMenuProps): JSX.Element {
const [open, setOpen] = useState(false);
return (
<Menu
open={open}
onOpenChange={setOpen}
showTitle={false}
title={_t("action|open_menu")}
side="right"
align="start"
trigger={
<IconButton aria-label={_t("action|add")}>
<ComposeIcon color="var(--cpd-color-icon-secondary)" />
</IconButton>
}
>
<MenuItem
Icon={UserAddIcon}
label={_t("action|new_message")}
onSelect={vm.createChatRoom}
hideChevron={true}
/>
{vm.canCreateRoom && (
<MenuItem Icon={RoomIcon} label={_t("action|new_room")} onSelect={vm.createRoom} hideChevron={true} />
)}
{vm.canCreateVideoRoom && (
<MenuItem
Icon={VideoCallIcon}
label={_t("action|new_video_room")}
onSelect={vm.createVideoRoom}
hideChevron={true}
/>
)}
</Menu>
);
}