Files
element-call/src/Header.tsx
T

172 lines
3.7 KiB
TypeScript
Raw Normal View History

2023-01-03 16:55:26 +00:00
/*
Copyright 2022-2024 New Vector Ltd.
2023-01-03 16:55:26 +00:00
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
2023-01-03 16:55:26 +00:00
*/
2021-08-19 17:49:45 -07:00
import classNames from "classnames";
import {
type FC,
type HTMLAttributes,
type ReactNode,
forwardRef,
} from "react";
2021-12-02 17:21:37 -08:00
import { Link } from "react-router-dom";
2022-10-10 09:19:10 -04:00
import { useTranslation } from "react-i18next";
import { Heading, Text } from "@vector-im/compound-web";
import { UserProfileIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
2022-07-30 09:50:16 +02:00
2021-08-19 17:49:45 -07:00
import styles from "./Header.module.css";
2023-09-27 19:06:10 -04:00
import Logo from "./icons/Logo.svg?react";
import { Avatar, Size } from "./Avatar";
import { EncryptionLock } from "./room/EncryptionLock";
import { useMediaQuery } from "./useMediaQuery";
2022-07-30 09:50:16 +02:00
interface HeaderProps extends HTMLAttributes<HTMLElement> {
children: ReactNode;
className?: string;
}
2021-08-19 17:49:45 -07:00
2024-05-02 18:44:36 -04:00
export const Header = forwardRef<HTMLElement, HeaderProps>(
({ children, className, ...rest }, ref) => {
return (
<header
ref={ref}
className={classNames(styles.header, className)}
{...rest}
>
{children}
</header>
);
},
);
Header.displayName = "Header";
2021-08-19 17:49:45 -07:00
2022-07-30 09:50:16 +02:00
interface LeftNavProps extends HTMLAttributes<HTMLElement> {
children: ReactNode;
className?: string;
hideMobile?: boolean;
}
2023-09-22 18:05:13 -04:00
export const LeftNav: FC<LeftNavProps> = ({
2022-07-30 09:50:16 +02:00
children,
className,
hideMobile,
...rest
2023-09-22 18:05:13 -04:00
}) => {
2021-08-19 17:49:45 -07:00
return (
2021-11-29 16:19:48 -08:00
<div
2021-12-23 14:40:23 -08:00
className={classNames(
styles.nav,
styles.leftNav,
{ [styles.hideMobile]: hideMobile },
2023-10-11 10:42:04 -04:00
className,
2021-12-23 14:40:23 -08:00
)}
2021-11-29 16:19:48 -08:00
{...rest}
>
2021-08-19 17:49:45 -07:00
{children}
</div>
);
2023-09-22 18:05:13 -04:00
};
2021-08-20 16:23:12 -07:00
2022-07-31 22:09:33 +02:00
interface RightNavProps extends HTMLAttributes<HTMLElement> {
2022-07-30 09:50:16 +02:00
children?: ReactNode;
className?: string;
2022-08-18 18:48:24 -04:00
hideMobile?: boolean;
2022-07-30 09:50:16 +02:00
}
2023-09-22 18:05:13 -04:00
export const RightNav: FC<RightNavProps> = ({
2022-07-30 09:50:16 +02:00
children,
className,
hideMobile,
...rest
2023-09-22 18:05:13 -04:00
}) => {
2021-08-20 16:23:12 -07:00
return (
2021-11-29 16:19:48 -08:00
<div
2022-01-04 16:00:13 -08:00
className={classNames(
styles.nav,
styles.rightNav,
{ [styles.hideMobile]: hideMobile },
2023-10-11 10:42:04 -04:00
className,
2022-01-04 16:00:13 -08:00
)}
2021-11-29 16:19:48 -08:00
{...rest}
>
{children}
</div>
2021-08-20 16:23:12 -07:00
);
2023-09-22 18:05:13 -04:00
};
2021-12-02 17:21:37 -08:00
2022-07-30 09:50:16 +02:00
interface HeaderLogoProps {
className?: string;
}
2023-09-22 18:05:13 -04:00
export const HeaderLogo: FC<HeaderLogoProps> = ({ className }) => {
2022-11-07 12:33:06 +00:00
const { t } = useTranslation();
2021-12-02 17:21:37 -08:00
return (
2022-11-04 18:31:21 +00:00
<Link
className={classNames(styles.headerLogo, className)}
to="/"
2023-11-20 13:00:43 +00:00
aria-label={t("header_label")}
2022-11-04 18:31:21 +00:00
>
2021-12-07 12:20:05 -08:00
<Logo />
2021-12-02 17:21:37 -08:00
</Link>
);
2023-09-22 18:05:13 -04:00
};
2021-12-02 17:21:37 -08:00
interface RoomHeaderInfoProps {
id: string;
name: string;
avatarUrl: string | null;
encrypted: boolean;
2024-04-23 15:15:13 +02:00
participantCount: number | null;
2022-07-30 09:50:16 +02:00
}
export const RoomHeaderInfo: FC<RoomHeaderInfoProps> = ({
id,
name,
avatarUrl,
encrypted,
participantCount,
}) => {
2022-10-10 09:19:10 -04:00
const { t } = useTranslation();
const size = useMediaQuery("(max-width: 550px)") ? "sm" : "lg";
return (
<div className={styles.roomHeaderInfo} data-size={size}>
<Avatar
className={styles.roomAvatar}
id={id}
name={name}
size={size === "sm" ? Size.SM : 56}
src={avatarUrl ?? undefined}
/>
<div className={styles.nameLine}>
<Heading
type={size === "sm" ? "body" : "heading"}
size={size === "sm" ? "lg" : "md"}
weight="semibold"
data-testid="roomHeader_roomName"
>
{name}
</Heading>
<EncryptionLock encrypted={encrypted} />
</div>
2024-04-23 15:15:13 +02:00
{(participantCount ?? 0) > 0 && (
<div className={styles.participantsLine}>
<UserProfileIcon
width={20}
height={20}
2023-11-20 13:00:43 +00:00
aria-label={t("header_participants_label")}
/>
<Text as="span" size="sm" weight="medium">
2024-04-23 15:15:13 +02:00
{t("participant_count", { count: participantCount ?? 0 })}
</Text>
</div>
)}
</div>
);
};