Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/app/components/page/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Box, Header, Line, Scroll, Text, as } from 'folds';
import classNames from 'classnames';
import { ContainerColor } from '$styles/ContainerColor.css';
import { ScreenSize, useScreenSizeContext } from '$hooks/useScreenSize';
import { mobileOrTabletLayout } from '$utils/user-agent';
import * as css from './style.css';

type PageRootProps = {
Expand All @@ -16,7 +17,7 @@ export function PageRoot({ nav, children }: PageRootProps) {
return (
<Box grow="Yes" className={ContainerColor({ variant: 'Background' })}>
{nav}
{screenSize !== ScreenSize.Mobile && (
{screenSize !== ScreenSize.Mobile && !mobileOrTabletLayout() && (
<Line variant="Background" size="300" direction="Vertical" />
)}
{children}
Expand Down
5 changes: 3 additions & 2 deletions src/app/pages/MobileFriendly.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ReactNode } from 'react';
import { useMatch } from 'react-router-dom';
import { ScreenSize, useScreenSizeContext } from '$hooks/useScreenSize';
import { mobileOrTabletLayout } from '$utils/user-agent';
import { DIRECT_PATH, EXPLORE_PATH, HOME_PATH, INBOX_PATH, SPACE_PATH } from './paths';

type MobileFriendlyClientNavProps = {
Expand All @@ -15,7 +16,7 @@ export function MobileFriendlyClientNav({ children }: MobileFriendlyClientNavPro
const inboxMatch = useMatch({ path: INBOX_PATH, caseSensitive: true, end: true });

if (
screenSize === ScreenSize.Mobile &&
(screenSize === ScreenSize.Mobile || mobileOrTabletLayout()) &&
!(homeMatch || directMatch || spaceMatch || exploreMatch || inboxMatch)
) {
return null;
Expand All @@ -36,7 +37,7 @@ export function MobileFriendlyPageNav({ path, children }: MobileFriendlyPageNavP
end: true,
});

if (screenSize === ScreenSize.Mobile && !exactPath) {
if ((screenSize === ScreenSize.Mobile || mobileOrTabletLayout()) && !exactPath) {
return null;
}

Expand Down
3 changes: 2 additions & 1 deletion src/app/pages/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { Room } from '$features/room';
import { Lobby } from '$features/lobby';
import { PageRoot } from '$components/page';
import { ScreenSize } from '$hooks/useScreenSize';
import { mobileOrTabletLayout } from '$utils/user-agent';
import { ReceiveSelfDeviceVerification } from '$components/DeviceVerification';
import { AutoRestoreBackupOnVerification } from '$components/BackupRestore';
import { RoomSettingsRenderer } from '$features/room-settings';
Expand Down Expand Up @@ -101,7 +102,7 @@ const getFirstSession = () => {

export const createRouter = (clientConfig: ClientConfig, screenSize: ScreenSize) => {
const { hashRouter } = clientConfig;
const mobile = screenSize === ScreenSize.Mobile;
const mobile = screenSize === ScreenSize.Mobile || mobileOrTabletLayout();

const routes = createRoutesFromElements(
<Route>
Expand Down
20 changes: 20 additions & 0 deletions src/app/utils/user-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ const isMobileOrTablet = (() => {
const { os, device } = result;
if (device.type === 'mobile' || device.type === 'tablet') return true;
if (os.name === 'Android' || os.name === 'iOS') return true;
// iPad on iOS 13+ sends a macOS Safari user agent by default ("Request Desktop Website").
// ua-parser-js therefore reports os.name === 'Mac OS' with no device.type.
// Real Macs never have maxTouchPoints > 1 (Magic Trackpad reports 1 at most in browsers),
// so this safely identifies iPads masquerading as desktop Safari.
if (os.name === 'Mac OS' && navigator.maxTouchPoints > 1) return true;
return false;
})();

Expand All @@ -15,11 +20,26 @@ const normalizeMacName = (os?: string) => {
return os;
};

// True for layout purposes: phones and tablets with native touch UA.
// Intentionally excludes iPads in "Request Desktop Website" mode (macOS UA +
// maxTouchPoints > 1) because those users explicitly want the desktop layout.
const isMobileOrTabletLayout = (() => {
const { os, device } = result;
if (device.type === 'mobile' || device.type === 'tablet') return true;
if (os.name === 'Android' || os.name === 'iOS') return true;
return false;
})();

const isMac = result.os.name === 'Mac OS';

export const ua = () => result;
export const isMacOS = () => isMac;
export const mobileOrTablet = () => isMobileOrTablet;
/**
* Like `mobileOrTablet` but excludes iPads using "Request Desktop Website".
* Use this for layout/nav decisions; use `mobileOrTablet` for touch/keyboard behaviour.
*/
export const mobileOrTabletLayout = () => isMobileOrTabletLayout;

export const deviceDisplayName = (): string => {
const browser = result.browser.name;
Expand Down
Loading