Make the footer display more nicely on narrow screens

It needed a bit of tweaking now that we have up to 6 buttons in the footer. I tried to do everything in CSS this time.
This commit is contained in:
Robin
2024-11-08 12:16:59 -05:00
parent 5b94dd6f1a
commit c7e220e310
3 changed files with 147 additions and 106 deletions

View File

@@ -53,7 +53,8 @@ const InnerButton: FC<InnerButtonProps> = ({ raised, ...props }) => {
); );
}; };
interface RaisedHandToggleButtonProps { interface RaisedHandToggleButtonProps
extends ComponentPropsWithoutRef<"button"> {
rtcSession: MatrixRTCSession; rtcSession: MatrixRTCSession;
client: MatrixClient; client: MatrixClient;
} }
@@ -61,6 +62,7 @@ interface RaisedHandToggleButtonProps {
export function RaiseHandToggleButton({ export function RaiseHandToggleButton({
client, client,
rtcSession, rtcSession,
...props
}: RaisedHandToggleButtonProps): ReactNode { }: RaisedHandToggleButtonProps): ReactNode {
const { raisedHands, lowerHand } = useReactions(); const { raisedHands, lowerHand } = useReactions();
const [busy, setBusy] = useState(false); const [busy, setBusy] = useState(false);
@@ -121,6 +123,7 @@ export function RaiseHandToggleButton({
disabled={busy} disabled={busy}
onClick={toggleRaisedHand} onClick={toggleRaisedHand}
raised={isHandRaised} raised={isHandRaised}
{...props}
/> />
); );
} }

View File

@@ -36,12 +36,14 @@ Please see LICENSE in the repository root for full details.
inset-block-end: 0; inset-block-end: 0;
z-index: 1; z-index: 1;
display: grid; display: grid;
grid-template-columns: 1fr auto 1fr; grid-template-columns: minmax(0, var(--inline-content-inset)) 1fr auto 1fr minmax(
grid-template-areas: "logo buttons layout"; 0,
var(--inline-content-inset)
);
grid-template-areas: ". logo buttons layout .";
align-items: center; align-items: center;
gap: var(--cpd-space-3x); gap: var(--cpd-space-3x);
padding-block: var(--cpd-space-4x); padding-block: var(--cpd-space-10x);
padding-inline: var(--inline-content-inset);
background: linear-gradient( background: linear-gradient(
180deg, 180deg,
rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 0%,
@@ -83,6 +85,7 @@ Please see LICENSE in the repository root for full details.
.buttons { .buttons {
grid-area: buttons; grid-area: buttons;
justify-self: center;
display: flex; display: flex;
gap: var(--cpd-space-3x); gap: var(--cpd-space-3x);
} }
@@ -92,15 +95,49 @@ Please see LICENSE in the repository root for full details.
justify-self: end; justify-self: end;
} }
@media (min-height: 400px) { @media (max-width: 660px) {
.footer { .footer {
padding-block: var(--cpd-space-8x); grid-template-areas: ". buttons buttons buttons .";
}
.logo {
display: none;
}
.layout {
display: none !important;
} }
} }
@media (min-height: 800px) { @media (max-width: 370px) {
.raiseHand {
display: none;
}
}
@media (max-width: 340px) {
.invite,
.switchCamera,
.shareScreen {
display: none;
}
@media (max-height: 400px) {
.footer {
display: none;
}
}
}
@media (max-height: 400px) {
.footer { .footer {
padding-block: var(--cpd-space-10x); padding-block: var(--cpd-space-4x);
}
}
@media (max-height: 800px) {
.footer {
padding-block: var(--cpd-space-8x);
} }
} }

View File

@@ -198,7 +198,6 @@ export const InCallView: FC<InCallViewProps> = ({
const containerRef1 = useRef<HTMLDivElement | null>(null); const containerRef1 = useRef<HTMLDivElement | null>(null);
const [containerRef2, bounds] = useMeasure(); const [containerRef2, bounds] = useMeasure();
const boundsValid = bounds.height > 0;
// Merge the refs so they can attach to the same element // Merge the refs so they can attach to the same element
const containerRef = useMergedRefs(containerRef1, containerRef2); const containerRef = useMergedRefs(containerRef1, containerRef2);
@@ -226,10 +225,6 @@ export const InCallView: FC<InCallViewProps> = ({
(muted) => muteStates.audio.setEnabled?.(!muted), (muted) => muteStates.audio.setEnabled?.(!muted),
); );
const mobile = boundsValid && bounds.width <= 660;
const reducedControls = boundsValid && bounds.width <= 340;
const noControls = reducedControls && bounds.height <= 400;
const windowMode = useObservableEagerState(vm.windowMode); const windowMode = useObservableEagerState(vm.windowMode);
const layout = useObservableEagerState(vm.layout); const layout = useObservableEagerState(vm.layout);
const gridMode = useObservableEagerState(vm.gridMode); const gridMode = useObservableEagerState(vm.gridMode);
@@ -511,95 +506,94 @@ export const InCallView: FC<InCallViewProps> = ({
.catch(logger.error); .catch(logger.error);
}, [localParticipant, isScreenShareEnabled]); }, [localParticipant, isScreenShareEnabled]);
let footer: JSX.Element | null; const buttons: JSX.Element[] = [];
if (noControls) {
footer = null;
} else {
const buttons: JSX.Element[] = [];
buttons.push(
<MicButton
key="audio"
muted={!muteStates.audio.enabled}
onClick={toggleMicrophone}
disabled={muteStates.audio.setEnabled === null}
data-testid="incall_mute"
/>,
<VideoButton
key="video"
muted={!muteStates.video.enabled}
onClick={toggleCamera}
disabled={muteStates.video.setEnabled === null}
data-testid="incall_videomute"
/>,
);
if (switchCamera !== null)
buttons.push( buttons.push(
<MicButton <SwitchCameraButton
key="audio" key="switch_camera"
muted={!muteStates.audio.enabled} className={styles.switchCamera}
onClick={toggleMicrophone} onClick={switchCamera}
disabled={muteStates.audio.setEnabled === null}
data-testid="incall_mute"
/>,
<VideoButton
key="video"
muted={!muteStates.video.enabled}
onClick={toggleCamera}
disabled={muteStates.video.setEnabled === null}
data-testid="incall_videomute"
/>, />,
); );
if (!reducedControls) { if (canScreenshare && !hideScreensharing) {
if (switchCamera !== null)
buttons.push(
<SwitchCameraButton key="switch_camera" onClick={switchCamera} />,
);
if (canScreenshare && !hideScreensharing) {
buttons.push(
<ShareScreenButton
key="share_screen"
enabled={isScreenShareEnabled}
onClick={toggleScreensharing}
data-testid="incall_screenshare"
/>,
);
}
if (supportsReactions) {
buttons.push(
<RaiseHandToggleButton
client={client}
rtcSession={rtcSession}
key="4"
/>,
);
}
buttons.push(<SettingsButton key="settings" onClick={openSettings} />);
}
buttons.push( buttons.push(
<EndCallButton <ShareScreenButton
key="end_call" key="share_screen"
onClick={function (): void { className={styles.shareScreen}
onLeave(); enabled={isScreenShareEnabled}
}} onClick={toggleScreensharing}
data-testid="incall_leave" data-testid="incall_screenshare"
/>, />,
); );
footer = (
<div
ref={footerRef}
className={classNames(styles.footer, {
[styles.overlay]: windowMode === "flat",
[styles.hidden]: !showFooter || (!showControls && hideHeader),
})}
>
{!mobile && !hideHeader && (
<div className={styles.logo}>
<LogoMark width={24} height={24} aria-hidden />
<LogoType
width={80}
height={11}
aria-label={import.meta.env.VITE_PRODUCT_NAME || "Element Call"}
/>
</div>
)}
{showControls && <div className={styles.buttons}>{buttons}</div>}
{!mobile && showControls && (
<LayoutToggle
className={styles.layout}
layout={gridMode}
setLayout={setGridMode}
onTouchEnd={onLayoutToggleTouchEnd}
/>
)}
</div>
);
} }
if (supportsReactions) {
buttons.push(
<RaiseHandToggleButton
key="raise_hand"
className={styles.raiseHand}
client={client}
rtcSession={rtcSession}
/>,
);
}
if (layout.type !== "pip")
buttons.push(<SettingsButton key="settings" onClick={openSettings} />);
buttons.push(
<EndCallButton
key="end_call"
onClick={function (): void {
onLeave();
}}
data-testid="incall_leave"
/>,
);
const footer = (
<div
ref={footerRef}
className={classNames(styles.footer, {
[styles.overlay]: windowMode === "flat",
[styles.hidden]: !showFooter || (!showControls && hideHeader),
})}
>
{!hideHeader && (
<div className={styles.logo}>
<LogoMark width={24} height={24} aria-hidden />
<LogoType
width={80}
height={11}
aria-label={import.meta.env.VITE_PRODUCT_NAME || "Element Call"}
/>
</div>
)}
{showControls && <div className={styles.buttons}>{buttons}</div>}
{showControls && (
<LayoutToggle
className={styles.layout}
layout={gridMode}
setLayout={setGridMode}
onTouchEnd={onLayoutToggleTouchEnd}
/>
)}
</div>
);
return ( return (
<div <div
@@ -631,8 +625,11 @@ export const InCallView: FC<InCallViewProps> = ({
/> />
</LeftNav> </LeftNav>
<RightNav> <RightNav>
{!reducedControls && showControls && onShareClick !== null && ( {showControls && onShareClick !== null && (
<InviteButton onClick={onShareClick} /> <InviteButton
className={styles.invite}
onClick={onShareClick}
/>
)} )}
</RightNav> </RightNav>
</Header> </Header>
@@ -644,15 +641,19 @@ export const InCallView: FC<InCallViewProps> = ({
<source src={handSoundMp3} type="audio/mpeg" /> <source src={handSoundMp3} type="audio/mpeg" />
</audio> </audio>
{footer} {footer}
{!noControls && <RageshakeRequestModal {...rageshakeRequestModalProps} />} {layout.type !== "pip" && (
<SettingsModal <>
client={client} <RageshakeRequestModal {...rageshakeRequestModalProps} />
roomId={rtcSession.room.roomId} <SettingsModal
open={settingsModalOpen} client={client}
onDismiss={closeSettings} roomId={rtcSession.room.roomId}
tab={settingsTab} open={settingsModalOpen}
onTabChange={setSettingsTab} onDismiss={closeSettings}
/> tab={settingsTab}
onTabChange={setSettingsTab}
/>
</>
)}
</div> </div>
); );
}; };