Additional in-room PTT styling
This commit is contained in:
		
					parent
					
						
							
								c430ebb3a3
							
						
					
				
			
			
				commit
				
					
						b6c926d2c8
					
				
			
		
					 5 changed files with 139 additions and 50 deletions
				
			
		| 
						 | 
					@ -4,35 +4,55 @@ import classNames from "classnames";
 | 
				
			||||||
import { Avatar } from "./Avatar";
 | 
					import { Avatar } from "./Avatar";
 | 
				
			||||||
import { getAvatarUrl } from "./matrix-utils";
 | 
					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 (
 | 
					  return (
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
      className={classNames(styles.facepile, className)}
 | 
					      className={classNames(
 | 
				
			||||||
 | 
					        styles.facepile,
 | 
				
			||||||
 | 
					        { [styles.md]: size === "md" },
 | 
				
			||||||
 | 
					        className
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
      title={participants.map((member) => member.name).join(", ")}
 | 
					      title={participants.map((member) => member.name).join(", ")}
 | 
				
			||||||
 | 
					      style={{ width: participants.length * _size + _overlap }}
 | 
				
			||||||
      {...rest}
 | 
					      {...rest}
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      {participants.slice(0, 3).map((member, i) => {
 | 
					      {participants.slice(0, max).map((member, i) => {
 | 
				
			||||||
        const avatarUrl = member.user?.avatarUrl;
 | 
					        const avatarUrl = member.user?.avatarUrl;
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
          <Avatar
 | 
					          <Avatar
 | 
				
			||||||
            key={member.userId}
 | 
					            key={member.userId}
 | 
				
			||||||
            size="xs"
 | 
					            size={size}
 | 
				
			||||||
            src={avatarUrl && getAvatarUrl(client, avatarUrl, 22)}
 | 
					            src={avatarUrl && getAvatarUrl(client, avatarUrl, _size)}
 | 
				
			||||||
            fallback={member.name.slice(0, 1).toUpperCase()}
 | 
					            fallback={member.name.slice(0, 1).toUpperCase()}
 | 
				
			||||||
            className={styles.avatar}
 | 
					            className={styles.avatar}
 | 
				
			||||||
            style={{ left: i * 22 }}
 | 
					            style={{ left: i * (_size - _overlap) }}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      })}
 | 
					      })}
 | 
				
			||||||
      {participants.length > 3 && (
 | 
					      {participants.length > max && (
 | 
				
			||||||
        <Avatar
 | 
					        <Avatar
 | 
				
			||||||
          key="additional"
 | 
					          key="additional"
 | 
				
			||||||
          size="xs"
 | 
					          size={size}
 | 
				
			||||||
          fallback={`+${participants.length - 3}`}
 | 
					          fallback={`+${participants.length - max}`}
 | 
				
			||||||
          className={styles.avatar}
 | 
					          className={styles.avatar}
 | 
				
			||||||
          style={{ left: 3 * 22 }}
 | 
					          style={{ left: max * (_size - _overlap) }}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Facepile.defaultProps = {
 | 
				
			||||||
 | 
					  max: 3,
 | 
				
			||||||
 | 
					  size: "xs",
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,8 +4,16 @@
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.facepile.md {
 | 
				
			||||||
 | 
					  height: 36px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.facepile .avatar {
 | 
					.facepile .avatar {
 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
  top: 0;
 | 
					  top: 0;
 | 
				
			||||||
  border: 1px solid var(--bgColor2);
 | 
					  border: 1px solid var(--bgColor2);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.facepile.md .avatar {
 | 
				
			||||||
 | 
					  border: 2px solid var(--bgColor2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,8 @@ import { ReactComponent as VideoIcon } from "../icons/Video.svg";
 | 
				
			||||||
import { ReactComponent as DisableVideoIcon } from "../icons/DisableVideo.svg";
 | 
					import { ReactComponent as DisableVideoIcon } from "../icons/DisableVideo.svg";
 | 
				
			||||||
import { ReactComponent as HangupIcon } from "../icons/Hangup.svg";
 | 
					import { ReactComponent as HangupIcon } from "../icons/Hangup.svg";
 | 
				
			||||||
import { ReactComponent as ScreenshareIcon } from "../icons/Screenshare.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 { useButton } from "@react-aria/button";
 | 
				
			||||||
import { mergeProps, useObjectRef } from "@react-aria/utils";
 | 
					import { mergeProps, useObjectRef } from "@react-aria/utils";
 | 
				
			||||||
import { TooltipTrigger } from "../Tooltip";
 | 
					import { TooltipTrigger } from "../Tooltip";
 | 
				
			||||||
| 
						 | 
					@ -127,3 +129,25 @@ export function HangupButton({ className, ...rest }) {
 | 
				
			||||||
    </TooltipTrigger>
 | 
					    </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>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@ import React from "react";
 | 
				
			||||||
import { useModalTriggerState } from "../Modal";
 | 
					import { useModalTriggerState } from "../Modal";
 | 
				
			||||||
import { SettingsModal } from "../settings/SettingsModal";
 | 
					import { SettingsModal } from "../settings/SettingsModal";
 | 
				
			||||||
import { InviteModal } from "./InviteModal";
 | 
					import { InviteModal } from "./InviteModal";
 | 
				
			||||||
import { Button } from "../button";
 | 
					import { Button, HangupButton, InviteButton, SettingsButton } from "../button";
 | 
				
			||||||
import { Header, LeftNav, RightNav, RoomSetupHeaderInfo } from "../Header";
 | 
					import { Header, LeftNav, RightNav, RoomSetupHeaderInfo } from "../Header";
 | 
				
			||||||
import { ReactComponent as AddUserIcon } from "../icons/AddUser.svg";
 | 
					import { ReactComponent as AddUserIcon } from "../icons/AddUser.svg";
 | 
				
			||||||
import { ReactComponent as SettingsIcon } from "../icons/Settings.svg";
 | 
					import { ReactComponent as SettingsIcon } from "../icons/Settings.svg";
 | 
				
			||||||
| 
						 | 
					@ -38,26 +38,26 @@ export function PTTCallView({
 | 
				
			||||||
        <LeftNav>
 | 
					        <LeftNav>
 | 
				
			||||||
          <RoomSetupHeaderInfo roomName={roomName} onPress={onLeave} />
 | 
					          <RoomSetupHeaderInfo roomName={roomName} onPress={onLeave} />
 | 
				
			||||||
        </LeftNav>
 | 
					        </LeftNav>
 | 
				
			||||||
        <RightNav>
 | 
					        <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>
 | 
					 | 
				
			||||||
      </Header>
 | 
					      </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}>
 | 
					      <div className={styles.center}>
 | 
				
			||||||
 | 
					        <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
 | 
					          <PTTButton
 | 
				
			||||||
            client={client}
 | 
					            client={client}
 | 
				
			||||||
            activeSpeaker={activeSpeaker}
 | 
					            activeSpeaker={activeSpeaker}
 | 
				
			||||||
| 
						 | 
					@ -72,6 +72,12 @@ export function PTTCallView({
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          ))}
 | 
					          ))}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div className={styles.footer}>
 | 
				
			||||||
 | 
					          <SettingsButton onPress={() => settingsModalState.open()} />
 | 
				
			||||||
 | 
					          <HangupButton onPress={onLeave} />
 | 
				
			||||||
 | 
					          <InviteButton onPress={() => inviteModalState.open()} />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {settingsModalState.isOpen && (
 | 
					      {settingsModalState.isOpen && (
 | 
				
			||||||
        <SettingsModal
 | 
					        <SettingsModal
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  flex-direction: column;
 | 
					  flex-direction: column;
 | 
				
			||||||
 | 
					  justify-content: center;
 | 
				
			||||||
  overflow: hidden;
 | 
					  overflow: hidden;
 | 
				
			||||||
  min-height: 100%;
 | 
					  min-height: 100%;
 | 
				
			||||||
  position: fixed;
 | 
					  position: fixed;
 | 
				
			||||||
| 
						 | 
					@ -9,32 +10,62 @@
 | 
				
			||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.headerSeparator {
 | 
					 | 
				
			||||||
  width: calc(100% - 40px);
 | 
					 | 
				
			||||||
  height: 1px;
 | 
					 | 
				
			||||||
  margin: 0 20px;
 | 
					 | 
				
			||||||
  background-color: #21262C;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.center {
 | 
					.center {
 | 
				
			||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  flex: 1;
 | 
					  flex: 1;
 | 
				
			||||||
  flex-direction: column;
 | 
					  flex-direction: column;
 | 
				
			||||||
  justify-content: center;
 | 
					 | 
				
			||||||
  align-items: center;
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  margin-top: 48px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.actionTip {
 | 
					.actionTip {
 | 
				
			||||||
  margin-top: 42px;
 | 
					  margin-top: 42px;
 | 
				
			||||||
 | 
					  margin-bottom: 45px;
 | 
				
			||||||
  font-size: 17px;
 | 
					  font-size: 17px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.participants {
 | 
					.participants {
 | 
				
			||||||
  margin: 24px 20px 0 20px;
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-direction: column;
 | 
				
			||||||
 | 
					  margin: 20px;
 | 
				
			||||||
 | 
					  margin-bottom: 67px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.participants > p {
 | 
					.participants > p {
 | 
				
			||||||
  color: #A9B2BC;
 | 
					  color: #A9B2BC;
 | 
				
			||||||
  margin-bottom: 8px;
 | 
					  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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue