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;
client: MatrixClient;
}
@@ -61,6 +62,7 @@ interface RaisedHandToggleButtonProps {
export function RaiseHandToggleButton({
client,
rtcSession,
...props
}: RaisedHandToggleButtonProps): ReactNode {
const { raisedHands, lowerHand } = useReactions();
const [busy, setBusy] = useState(false);
@@ -121,6 +123,7 @@ export function RaiseHandToggleButton({
disabled={busy}
onClick={toggleRaisedHand}
raised={isHandRaised}
{...props}
/>
);
}

View File

@@ -36,12 +36,14 @@ Please see LICENSE in the repository root for full details.
inset-block-end: 0;
z-index: 1;
display: grid;
grid-template-columns: 1fr auto 1fr;
grid-template-areas: "logo buttons layout";
grid-template-columns: minmax(0, var(--inline-content-inset)) 1fr auto 1fr minmax(
0,
var(--inline-content-inset)
);
grid-template-areas: ". logo buttons layout .";
align-items: center;
gap: var(--cpd-space-3x);
padding-block: var(--cpd-space-4x);
padding-inline: var(--inline-content-inset);
padding-block: var(--cpd-space-10x);
background: linear-gradient(
180deg,
rgba(0, 0, 0, 0) 0%,
@@ -83,6 +85,7 @@ Please see LICENSE in the repository root for full details.
.buttons {
grid-area: buttons;
justify-self: center;
display: flex;
gap: var(--cpd-space-3x);
}
@@ -92,15 +95,49 @@ Please see LICENSE in the repository root for full details.
justify-self: end;
}
@media (min-height: 400px) {
@media (max-width: 660px) {
.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 {
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 [containerRef2, bounds] = useMeasure();
const boundsValid = bounds.height > 0;
// Merge the refs so they can attach to the same element
const containerRef = useMergedRefs(containerRef1, containerRef2);
@@ -226,10 +225,6 @@ export const InCallView: FC<InCallViewProps> = ({
(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 layout = useObservableEagerState(vm.layout);
const gridMode = useObservableEagerState(vm.gridMode);
@@ -511,95 +506,94 @@ export const InCallView: FC<InCallViewProps> = ({
.catch(logger.error);
}, [localParticipant, isScreenShareEnabled]);
let footer: JSX.Element | null;
if (noControls) {
footer = null;
} else {
const buttons: JSX.Element[] = [];
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(
<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"
<SwitchCameraButton
key="switch_camera"
className={styles.switchCamera}
onClick={switchCamera}
/>,
);
if (!reducedControls) {
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} />);
}
if (canScreenshare && !hideScreensharing) {
buttons.push(
<EndCallButton
key="end_call"
onClick={function (): void {
onLeave();
}}
data-testid="incall_leave"
<ShareScreenButton
key="share_screen"
className={styles.shareScreen}
enabled={isScreenShareEnabled}
onClick={toggleScreensharing}
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 (
<div
@@ -631,8 +625,11 @@ export const InCallView: FC<InCallViewProps> = ({
/>
</LeftNav>
<RightNav>
{!reducedControls && showControls && onShareClick !== null && (
<InviteButton onClick={onShareClick} />
{showControls && onShareClick !== null && (
<InviteButton
className={styles.invite}
onClick={onShareClick}
/>
)}
</RightNav>
</Header>
@@ -644,15 +641,19 @@ export const InCallView: FC<InCallViewProps> = ({
<source src={handSoundMp3} type="audio/mpeg" />
</audio>
{footer}
{!noControls && <RageshakeRequestModal {...rageshakeRequestModalProps} />}
<SettingsModal
client={client}
roomId={rtcSession.room.roomId}
open={settingsModalOpen}
onDismiss={closeSettings}
tab={settingsTab}
onTabChange={setSettingsTab}
/>
{layout.type !== "pip" && (
<>
<RageshakeRequestModal {...rageshakeRequestModalProps} />
<SettingsModal
client={client}
roomId={rtcSession.room.roomId}
open={settingsModalOpen}
onDismiss={closeSettings}
tab={settingsTab}
onTabChange={setSettingsTab}
/>
</>
)}
</div>
);
};