Add basic mobile styling
This commit is contained in:
parent
b6c926d2c8
commit
e3cec93669
4 changed files with 80 additions and 30 deletions
|
@ -4,6 +4,18 @@ import classNames from "classnames";
|
||||||
import { Avatar } from "./Avatar";
|
import { Avatar } from "./Avatar";
|
||||||
import { getAvatarUrl } from "./matrix-utils";
|
import { getAvatarUrl } from "./matrix-utils";
|
||||||
|
|
||||||
|
const overlapMap = {
|
||||||
|
xs: 2,
|
||||||
|
sm: 4,
|
||||||
|
md: 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
const sizeMap = {
|
||||||
|
xs: 24,
|
||||||
|
sm: 32,
|
||||||
|
md: 36,
|
||||||
|
};
|
||||||
|
|
||||||
export function Facepile({
|
export function Facepile({
|
||||||
className,
|
className,
|
||||||
client,
|
client,
|
||||||
|
@ -12,18 +24,14 @@ export function Facepile({
|
||||||
size,
|
size,
|
||||||
...rest
|
...rest
|
||||||
}) {
|
}) {
|
||||||
const _size = size === "md" ? 36 : 24;
|
const _size = sizeMap[size];
|
||||||
const _overlap = size === "md" ? 8 : 2;
|
const _overlap = overlapMap[size];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(styles.facepile, styles[size], className)}
|
||||||
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 }}
|
style={{ width: participants.length * (_size - _overlap) + _overlap }}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
{participants.slice(0, max).map((member, i) => {
|
{participants.slice(0, max).map((member, i) => {
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
.facepile {
|
.facepile {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 24px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.facepile.xs {
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.facepile.sm {
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
.facepile.md {
|
.facepile.md {
|
||||||
height: 36px;
|
height: 36px;
|
||||||
}
|
}
|
||||||
|
@ -15,5 +22,5 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.facepile.md .avatar {
|
.facepile.md .avatar {
|
||||||
border: 2px solid var(--bgColor2);
|
border-width: 2px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ import { Facepile } from "../Facepile";
|
||||||
import { PTTButton } from "./PTTButton";
|
import { PTTButton } from "./PTTButton";
|
||||||
import { PTTFeed } from "./PTTFeed";
|
import { PTTFeed } from "./PTTFeed";
|
||||||
import { useMediaHandler } from "../settings/useMediaHandler";
|
import { useMediaHandler } from "../settings/useMediaHandler";
|
||||||
|
import useMeasure from "react-use-measure";
|
||||||
|
import { ResizeObserver } from "@juggle/resize-observer";
|
||||||
|
|
||||||
export function PTTCallView({
|
export function PTTCallView({
|
||||||
groupCall,
|
groupCall,
|
||||||
|
@ -31,9 +33,11 @@ export function PTTCallView({
|
||||||
const { modalState: settingsModalState, modalProps: settingsModalProps } =
|
const { modalState: settingsModalState, modalProps: settingsModalProps } =
|
||||||
useModalTriggerState();
|
useModalTriggerState();
|
||||||
const { audioOutput } = useMediaHandler();
|
const { audioOutput } = useMediaHandler();
|
||||||
|
const [containerRef, bounds] = useMeasure({ polyfill: ResizeObserver });
|
||||||
|
const facepileSize = bounds.width < 800 ? "sm" : "md";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.pttCallView}>
|
<div className={styles.pttCallView} ref={containerRef}>
|
||||||
<Header className={styles.header}>
|
<Header className={styles.header}>
|
||||||
<LeftNav>
|
<LeftNav>
|
||||||
<RoomSetupHeaderInfo roomName={roomName} onPress={onLeave} />
|
<RoomSetupHeaderInfo roomName={roomName} onPress={onLeave} />
|
||||||
|
@ -46,18 +50,24 @@ export function PTTCallView({
|
||||||
participants.length > 1 ? "people" : "person"
|
participants.length > 1 ? "people" : "person"
|
||||||
} connected`}</p>
|
} connected`}</p>
|
||||||
<Facepile
|
<Facepile
|
||||||
size="md"
|
size={facepileSize}
|
||||||
max={8}
|
max={8}
|
||||||
className={styles.facepile}
|
className={styles.facepile}
|
||||||
client={client}
|
client={client}
|
||||||
participants={participants}
|
participants={participants}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.talkingInfo}>
|
<div className={styles.footer}>
|
||||||
<h2>Talking...</h2>
|
<SettingsButton onPress={() => settingsModalState.open()} />
|
||||||
<p>00:01:24</p>
|
<HangupButton onPress={onLeave} />
|
||||||
|
<InviteButton onPress={() => inviteModalState.open()} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.pttButtonContainer}>
|
<div className={styles.pttButtonContainer}>
|
||||||
|
<div className={styles.talkingInfo}>
|
||||||
|
<h2>Talking...</h2>
|
||||||
|
<p>00:01:24</p>
|
||||||
|
</div>
|
||||||
<PTTButton
|
<PTTButton
|
||||||
client={client}
|
client={client}
|
||||||
activeSpeaker={activeSpeaker}
|
activeSpeaker={activeSpeaker}
|
||||||
|
@ -72,11 +82,6 @@ export function PTTCallView({
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.footer}>
|
|
||||||
<SettingsButton onPress={() => settingsModalState.open()} />
|
|
||||||
<HangupButton onPress={onLeave} />
|
|
||||||
<InviteButton onPress={() => inviteModalState.open()} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{settingsModalState.isOpen && (
|
{settingsModalState.isOpen && (
|
||||||
|
|
|
@ -16,20 +16,12 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actionTip {
|
|
||||||
margin-top: 42px;
|
|
||||||
margin-bottom: 45px;
|
|
||||||
font-size: 17px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.participants {
|
.participants {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
margin-bottom: 67px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.participants > p {
|
.participants > p {
|
||||||
|
@ -45,21 +37,29 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 38px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pttButtonContainer {
|
.pttButtonContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actionTip {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 17px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
|
||||||
height: 64px;
|
height: 64px;
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer > * {
|
.footer > * {
|
||||||
|
@ -68,4 +68,34 @@
|
||||||
|
|
||||||
.footer > :last-child {
|
.footer > :last-child {
|
||||||
margin-right: 0px;
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 800px) {
|
||||||
|
.participants {
|
||||||
|
margin-bottom: 67px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.talkingInfo {
|
||||||
|
margin-bottom: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
margin-top: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actionTip {
|
||||||
|
margin-top: 42px;
|
||||||
|
margin-bottom: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pttButtonContainer {
|
||||||
|
flex: auto;
|
||||||
|
margin-bottom: 0;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
flex: auto;
|
||||||
|
order: 4;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue