Additional in-room PTT styling

This commit is contained in:
Robert Long 2022-04-27 16:47:23 -07:00
parent c430ebb3a3
commit b6c926d2c8
5 changed files with 139 additions and 50 deletions

View file

@ -4,35 +4,55 @@ import classNames from "classnames";
import { Avatar } from "./Avatar";
import { getAvatarUrl } from "./matrix-utils";
export function Facepile({ className, client, participants, ...rest }) {
export function Facepile({
className,
client,
participants,
max,
size,
...rest
}) {
const _size = size === "md" ? 36 : 24;
const _overlap = size === "md" ? 8 : 2;
return (
<div
className={classNames(styles.facepile, className)}
className={classNames(
styles.facepile,
{ [styles.md]: size === "md" },
className
)}
title={participants.map((member) => member.name).join(", ")}
style={{ width: participants.length * _size + _overlap }}
{...rest}
>
{participants.slice(0, 3).map((member, i) => {
{participants.slice(0, max).map((member, i) => {
const avatarUrl = member.user?.avatarUrl;
return (
<Avatar
key={member.userId}
size="xs"
src={avatarUrl && getAvatarUrl(client, avatarUrl, 22)}
size={size}
src={avatarUrl && getAvatarUrl(client, avatarUrl, _size)}
fallback={member.name.slice(0, 1).toUpperCase()}
className={styles.avatar}
style={{ left: i * 22 }}
style={{ left: i * (_size - _overlap) }}
/>
);
})}
{participants.length > 3 && (
{participants.length > max && (
<Avatar
key="additional"
size="xs"
fallback={`+${participants.length - 3}`}
size={size}
fallback={`+${participants.length - max}`}
className={styles.avatar}
style={{ left: 3 * 22 }}
style={{ left: max * (_size - _overlap) }}
/>
)}
</div>
);
}
Facepile.defaultProps = {
max: 3,
size: "xs",
};

View file

@ -4,8 +4,16 @@
position: relative;
}
.facepile.md {
height: 36px;
}
.facepile .avatar {
position: absolute;
top: 0;
border: 1px solid var(--bgColor2);
}
.facepile.md .avatar {
border: 2px solid var(--bgColor2);
}

View file

@ -7,6 +7,8 @@ import { ReactComponent as VideoIcon } from "../icons/Video.svg";
import { ReactComponent as DisableVideoIcon } from "../icons/DisableVideo.svg";
import { ReactComponent as HangupIcon } from "../icons/Hangup.svg";
import { ReactComponent as ScreenshareIcon } from "../icons/Screenshare.svg";
import { ReactComponent as SettingsIcon } from "../icons/Settings.svg";
import { ReactComponent as AddUserIcon } from "../icons/AddUser.svg";
import { useButton } from "@react-aria/button";
import { mergeProps, useObjectRef } from "@react-aria/utils";
import { TooltipTrigger } from "../Tooltip";
@ -127,3 +129,25 @@ export function HangupButton({ className, ...rest }) {
</TooltipTrigger>
);
}
export function SettingsButton({ className, ...rest }) {
return (
<TooltipTrigger>
<Button variant="toolbar" {...rest}>
<SettingsIcon />
</Button>
{() => "Settings"}
</TooltipTrigger>
);
}
export function InviteButton({ className, ...rest }) {
return (
<TooltipTrigger>
<Button variant="toolbar" {...rest}>
<AddUserIcon />
</Button>
{() => "Invite"}
</TooltipTrigger>
);
}

View file

@ -2,7 +2,7 @@ import React from "react";
import { useModalTriggerState } from "../Modal";
import { SettingsModal } from "../settings/SettingsModal";
import { InviteModal } from "./InviteModal";
import { Button } from "../button";
import { Button, HangupButton, InviteButton, SettingsButton } from "../button";
import { Header, LeftNav, RightNav, RoomSetupHeaderInfo } from "../Header";
import { ReactComponent as AddUserIcon } from "../icons/AddUser.svg";
import { ReactComponent as SettingsIcon } from "../icons/Settings.svg";
@ -38,39 +38,45 @@ export function PTTCallView({
<LeftNav>
<RoomSetupHeaderInfo roomName={roomName} onPress={onLeave} />
</LeftNav>
<RightNav>
<Button variant="secondaryHangup" onPress={onLeave}>
Leave
</Button>
<Button variant="icon" onPress={() => inviteModalState.open()}>
<AddUserIcon />
</Button>
<Button variant="icon" onPress={() => settingsModalState.open()}>
<SettingsIcon />
</Button>
</RightNav>
<RightNav />
</Header>
<div className={styles.headerSeparator} />
<div className={styles.participants}>
<p>{`${participants.length} user${
participants.length > 1 ? "s" : ""
} connected`}</p>
<Facepile client={client} participants={participants} />
</div>
<div className={styles.center}>
<PTTButton
client={client}
activeSpeaker={activeSpeaker}
groupCall={groupCall}
/>
<p className={styles.actionTip}>Press and hold spacebar to talk</p>
{userMediaFeeds.map((callFeed) => (
<PTTFeed
key={callFeed.userId}
callFeed={callFeed}
audioOutputDevice={audioOutput}
<div className={styles.participants}>
<p>{`${participants.length} ${
participants.length > 1 ? "people" : "person"
} connected`}</p>
<Facepile
size="md"
max={8}
className={styles.facepile}
client={client}
participants={participants}
/>
))}
</div>
<div className={styles.talkingInfo}>
<h2>Talking...</h2>
<p>00:01:24</p>
</div>
<div className={styles.pttButtonContainer}>
<PTTButton
client={client}
activeSpeaker={activeSpeaker}
groupCall={groupCall}
/>
<p className={styles.actionTip}>Press and hold spacebar to talk</p>
{userMediaFeeds.map((callFeed) => (
<PTTFeed
key={callFeed.userId}
callFeed={callFeed}
audioOutputDevice={audioOutput}
/>
))}
</div>
<div className={styles.footer}>
<SettingsButton onPress={() => settingsModalState.open()} />
<HangupButton onPress={onLeave} />
<InviteButton onPress={() => inviteModalState.open()} />
</div>
</div>
{settingsModalState.isOpen && (

View file

@ -2,6 +2,7 @@
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
overflow: hidden;
min-height: 100%;
position: fixed;
@ -9,32 +10,62 @@
width: 100%;
}
.headerSeparator {
width: calc(100% - 40px);
height: 1px;
margin: 0 20px;
background-color: #21262C;
}
.center {
width: 100%;
display: flex;
flex: 1;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 48px;
}
.actionTip {
margin-top: 42px;
margin-bottom: 45px;
font-size: 17px;
}
.participants {
margin: 24px 20px 0 20px;
display: flex;
flex-direction: column;
margin: 20px;
margin-bottom: 67px;
}
.participants > p {
color: #A9B2BC;
margin-bottom: 8px;
}
.facepile {
align-self: center;
}
.talkingInfo {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 38px;
}
.pttButtonContainer {
display: flex;
flex-direction: column;
align-items: center;
}
.footer {
position: relative;
display: flex;
justify-content: center;
align-items: center;
height: 64px;
}
.footer > * {
margin-right: 30px;
}
.footer > :last-child {
margin-right: 0px;
}