diff --git a/src/app/components/BackRouteHandler.tsx b/src/app/components/BackRouteHandler.tsx new file mode 100644 index 00000000..fa3d7592 --- /dev/null +++ b/src/app/components/BackRouteHandler.tsx @@ -0,0 +1,86 @@ +import { ReactNode, useCallback } from 'react'; +import { matchPath, useLocation, useNavigate } from 'react-router-dom'; +import { + getDirectPath, + getExplorePath, + getHomePath, + getInboxPath, + getSpacePath, +} from '../pages/pathUtils'; +import { DIRECT_PATH, EXPLORE_PATH, HOME_PATH, INBOX_PATH, SPACE_PATH } from '../pages/paths'; + +type BackRouteHandlerProps = { + children: (onBack: () => void) => ReactNode; +}; +export function BackRouteHandler({ children }: BackRouteHandlerProps) { + const navigate = useNavigate(); + const location = useLocation(); + + const goBack = useCallback(() => { + if ( + matchPath( + { + path: HOME_PATH, + caseSensitive: true, + end: false, + }, + location.pathname + ) + ) { + navigate(getHomePath()); + return; + } + if ( + matchPath( + { + path: DIRECT_PATH, + caseSensitive: true, + end: false, + }, + location.pathname + ) + ) { + navigate(getDirectPath()); + return; + } + const spaceMatch = matchPath( + { + path: SPACE_PATH, + caseSensitive: true, + end: false, + }, + location.pathname + ); + if (spaceMatch?.params.spaceIdOrAlias) { + navigate(getSpacePath(spaceMatch.params.spaceIdOrAlias)); + return; + } + if ( + matchPath( + { + path: EXPLORE_PATH, + caseSensitive: true, + end: false, + }, + location.pathname + ) + ) { + navigate(getExplorePath()); + return; + } + if ( + matchPath( + { + path: INBOX_PATH, + caseSensitive: true, + end: false, + }, + location.pathname + ) + ) { + navigate(getInboxPath()); + } + }, [navigate, location]); + + return children(goBack); +} diff --git a/src/app/components/page/Page.tsx b/src/app/components/page/Page.tsx index 4ccb1ec0..a8b9ea04 100644 --- a/src/app/components/page/Page.tsx +++ b/src/app/components/page/Page.tsx @@ -87,15 +87,17 @@ export const Page = as<'div'>(({ className, ...props }, ref) => ( /> )); -export const PageHeader = as<'div'>(({ className, ...props }, ref) => ( -
-)); +export const PageHeader = as<'div', css.PageHeaderVariants>( + ({ className, balance, ...props }, ref) => ( +
+ ) +); export const PageContent = as<'div'>(({ className, ...props }, ref) => (
diff --git a/src/app/components/page/style.css.ts b/src/app/components/page/style.css.ts index 4807a227..23f2da49 100644 --- a/src/app/components/page/style.css.ts +++ b/src/app/components/page/style.css.ts @@ -1,4 +1,5 @@ import { style } from '@vanilla-extract/css'; +import { recipe, RecipeVariants } from '@vanilla-extract/recipes'; import { DefaultReset, color, config, toRem } from 'folds'; export const PageNav = style({ @@ -33,11 +34,21 @@ export const PageNavContent = style({ paddingBottom: config.space.S700, }); -export const PageHeader = style({ - paddingLeft: config.space.S400, - paddingRight: config.space.S200, - borderBottomWidth: config.borderWidth.B300, +export const PageHeader = recipe({ + base: { + paddingLeft: config.space.S400, + paddingRight: config.space.S200, + borderBottomWidth: config.borderWidth.B300, + }, + variants: { + balance: { + true: { + paddingLeft: config.space.S200, + }, + }, + }, }); +export type PageHeaderVariants = RecipeVariants; export const PageContent = style([ DefaultReset, diff --git a/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx b/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx index 1cec6599..028cd560 100644 --- a/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx +++ b/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Box, Scroll, Text, toRem } from 'folds'; +import { Box, Icon, IconButton, Icons, Scroll, Text, toRem } from 'folds'; import { useAtomValue } from 'jotai'; import { RoomCard } from '../../components/room-card'; import { RoomTopicViewer } from '../../components/room-topic-viewer'; @@ -8,6 +8,8 @@ import { RoomSummaryLoader } from '../../components/RoomSummaryLoader'; import { useRoomNavigate } from '../../hooks/useRoomNavigate'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { allRoomsAtom } from '../../state/room-list/roomList'; +import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../components/BackRouteHandler'; type JoinBeforeNavigateProps = { roomIdOrAlias: string; eventId?: string; viaServers?: string[] }; export function JoinBeforeNavigate({ @@ -18,6 +20,7 @@ export function JoinBeforeNavigate({ const mx = useMatrixClient(); const allRooms = useAtomValue(allRoomsAtom); const { navigateRoom, navigateSpace } = useRoomNavigate(); + const screenSize = useScreenSizeContext(); const handleView = (roomId: string) => { if (mx.getRoom(roomId)?.isSpaceRoom()) { @@ -29,11 +32,24 @@ export function JoinBeforeNavigate({ return ( - - - - {roomIdOrAlias} - + + + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + )} + + )} + + + + {roomIdOrAlias} + + diff --git a/src/app/features/lobby/LobbyHeader.tsx b/src/app/features/lobby/LobbyHeader.tsx index e01d3ad5..fa415bd2 100644 --- a/src/app/features/lobby/LobbyHeader.tsx +++ b/src/app/features/lobby/LobbyHeader.tsx @@ -31,6 +31,8 @@ import { IPowerLevels, usePowerLevelsAPI } from '../../hooks/usePowerLevels'; import { UseStateProvider } from '../../components/UseStateProvider'; import { LeaveSpacePrompt } from '../../components/leave-space-prompt'; import { stopPropagation } from '../../utils/keyboard'; +import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../components/BackRouteHandler'; type LobbyMenuProps = { roomId: string; @@ -123,6 +125,7 @@ export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) { const space = useSpace(); const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer'); const [menuAnchor, setMenuAnchor] = useState(); + const screenSize = useScreenSizeContext(); const name = useRoomName(space); const avatarMxc = useRoomAvatar(space); @@ -133,42 +136,72 @@ export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) { }; return ( - + - - - {showProfile && ( - <> - - {nameInitials(name)}} - /> - - - {name} - - + {screenSize === ScreenSize.Mobile ? ( + <> + + + {(onBack) => ( + + + + )} + + + + {showProfile && ( + + {name} + + )} + + + ) : ( + <> + + + {showProfile && ( + <> + + {nameInitials(name)}} + /> + + + {name} + + + )} + + + )} + + {screenSize !== ScreenSize.Mobile && ( + + Members + + } + > + {(triggerRef) => ( + setPeopleDrawer((drawer) => !drawer)}> + + + )} + )} - - - - Members - - } - > - {(triggerRef) => ( - setPeopleDrawer((drawer) => !drawer)}> - - - )} - + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + + + )} + + )} - - ( - - )} - /> - + {screenSize !== ScreenSize.Mobile && ( + + ( + + )} + /> + + )} {name} diff --git a/src/app/pages/client/explore/Featured.tsx b/src/app/pages/client/explore/Featured.tsx index 4838127f..f056cbb5 100644 --- a/src/app/pages/client/explore/Featured.tsx +++ b/src/app/pages/client/explore/Featured.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Box, Icon, Icons, Scroll, Text } from 'folds'; +import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds'; import { useAtomValue } from 'jotai'; import { useClientConfig } from '../../../hooks/useClientConfig'; import { RoomCard, RoomCardGrid } from '../../../components/room-card'; @@ -9,21 +9,38 @@ import { Page, PageContent, PageContentCenter, + PageHeader, PageHero, PageHeroSection, } from '../../../components/page'; import { RoomTopicViewer } from '../../../components/room-topic-viewer'; import * as css from './style.css'; import { useRoomNavigate } from '../../../hooks/useRoomNavigate'; +import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../../components/BackRouteHandler'; export function FeaturedRooms() { const { featuredCommunities } = useClientConfig(); const { rooms, spaces } = featuredCommunities ?? {}; const allRooms = useAtomValue(allRoomsAtom); + const screenSize = useScreenSizeContext(); const { navigateSpace, navigateRoom } = useRoomNavigate(); return ( + {screenSize === ScreenSize.Mobile && ( + + + + {(onBack) => ( + + + + )} + + + + )} diff --git a/src/app/pages/client/explore/Server.tsx b/src/app/pages/client/explore/Server.tsx index 1a81c225..1f493df1 100644 --- a/src/app/pages/client/explore/Server.tsx +++ b/src/app/pages/client/explore/Server.tsx @@ -13,6 +13,7 @@ import { Button, Chip, Icon, + IconButton, Icons, Input, Line, @@ -42,6 +43,8 @@ import { allRoomsAtom } from '../../../state/room-list/roomList'; import { useRoomNavigate } from '../../../hooks/useRoomNavigate'; import { getMxIdServer } from '../../../utils/matrix'; import { stopPropagation } from '../../../utils/keyboard'; +import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../../components/BackRouteHandler'; const useServerSearchParams = (searchParams: URLSearchParams): ExploreServerPathSearchParams => useMemo( @@ -344,6 +347,7 @@ export function PublicRooms() { const userServer = userId && getMxIdServer(userId); const allRooms = useAtomValue(allRoomsAtom); const { navigateSpace, navigateRoom } = useRoomNavigate(); + const screenSize = useScreenSizeContext(); const [searchParams] = useSearchParams(); const serverSearchParams = useServerSearchParams(searchParams); @@ -466,7 +470,7 @@ export function PublicRooms() { return ( - + {isSearch ? ( <> @@ -482,20 +486,34 @@ export function PublicRooms() { - + {screenSize !== ScreenSize.Mobile && } Search - + ) : ( - - - - {server} - - + <> + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + )} + + )} + + + {screenSize !== ScreenSize.Mobile && } + + {server} + + + + )} diff --git a/src/app/pages/client/home/Search.tsx b/src/app/pages/client/home/Search.tsx index af7b1eb9..d5ddfb77 100644 --- a/src/app/pages/client/home/Search.tsx +++ b/src/app/pages/client/home/Search.tsx @@ -1,21 +1,38 @@ import React, { useRef } from 'react'; -import { Box, Icon, Icons, Text, Scroll } from 'folds'; +import { Box, Icon, Icons, Text, Scroll, IconButton } from 'folds'; import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page'; import { MessageSearch } from '../../../features/message-search'; import { useHomeRooms } from './useHomeRooms'; +import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../../components/BackRouteHandler'; export function HomeSearch() { const scrollRef = useRef(null); const rooms = useHomeRooms(); + const screenSize = useScreenSizeContext(); return ( - - - - - Message Search - + + + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + )} + + )} + + + {screenSize !== ScreenSize.Mobile && } + + Message Search + + + diff --git a/src/app/pages/client/inbox/Invites.tsx b/src/app/pages/client/inbox/Invites.tsx index 06e5f6c6..18993081 100644 --- a/src/app/pages/client/inbox/Invites.tsx +++ b/src/app/pages/client/inbox/Invites.tsx @@ -4,6 +4,7 @@ import { Box, Button, Icon, + IconButton, Icons, Overlay, OverlayBackdrop, @@ -39,6 +40,8 @@ import { RoomTopicViewer } from '../../../components/room-topic-viewer'; import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback'; import { useRoomNavigate } from '../../../hooks/useRoomNavigate'; import { useRoomTopic } from '../../../hooks/useRoomMeta'; +import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../../components/BackRouteHandler'; const COMPACT_CARD_WIDTH = 548; @@ -205,6 +208,7 @@ export function Invites() { useCallback(() => containerRef.current, []), useCallback((width) => setCompact(width <= COMPACT_CARD_WIDTH), []) ); + const screenSize = useScreenSizeContext(); const { navigateRoom, navigateSpace } = useRoomNavigate(); @@ -225,12 +229,26 @@ export function Invites() { return ( - - - - - Invitations - + + + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + )} + + )} + + + {screenSize !== ScreenSize.Mobile && } + + Invitations + + + diff --git a/src/app/pages/client/inbox/Notifications.tsx b/src/app/pages/client/inbox/Notifications.tsx index 3425b519..6a8160d8 100644 --- a/src/app/pages/client/inbox/Notifications.tsx +++ b/src/app/pages/client/inbox/Notifications.tsx @@ -78,6 +78,8 @@ import { UserAvatar } from '../../../components/user-avatar'; import { EncryptedContent } from '../../../features/room/message'; import { useMentionClickHandler } from '../../../hooks/useMentionClickHandler'; import { useSpoilerClickHandler } from '../../../hooks/useSpoilerClickHandler'; +import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../../components/BackRouteHandler'; type RoomNotificationsGroup = { roomId: string; @@ -484,6 +486,7 @@ export function Notifications() { const mx = useMatrixClient(); const [mediaAutoLoad] = useSetting(settingsAtom, 'mediaAutoLoad'); const [urlPreview] = useSetting(settingsAtom, 'urlPreview'); + const screenSize = useScreenSizeContext(); const { navigateRoom } = useRoomNavigate(); const [searchParams, setSearchParams] = useSearchParams(); @@ -549,12 +552,26 @@ export function Notifications() { return ( - - - - - Notification Messages - + + + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + )} + + )} + + + {screenSize !== ScreenSize.Mobile && } + + Notification Messages + + + diff --git a/src/app/pages/client/space/Search.tsx b/src/app/pages/client/space/Search.tsx index 6e7ac57d..017262b5 100644 --- a/src/app/pages/client/space/Search.tsx +++ b/src/app/pages/client/space/Search.tsx @@ -1,5 +1,5 @@ import React, { useRef } from 'react'; -import { Box, Icon, Icons, Text, Scroll } from 'folds'; +import { Box, Icon, Icons, Text, Scroll, IconButton } from 'folds'; import { useAtomValue } from 'jotai'; import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page'; import { MessageSearch } from '../../../features/message-search'; @@ -9,11 +9,14 @@ import { allRoomsAtom } from '../../../state/room-list/roomList'; import { mDirectAtom } from '../../../state/mDirectList'; import { roomToParentsAtom } from '../../../state/room/roomToParents'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; +import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../../components/BackRouteHandler'; export function SpaceSearch() { const mx = useMatrixClient(); const scrollRef = useRef(null); const space = useSpace(); + const screenSize = useScreenSizeContext(); const mDirects = useAtomValue(mDirectAtom); const roomToParents = useAtomValue(roomToParentsAtom); @@ -25,12 +28,26 @@ export function SpaceSearch() { return ( - - - - - Message Search - + + + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + )} + + )} + + + {screenSize !== ScreenSize.Mobile && } + + Message Search + + +