diff --git a/commafeed-client/src/components/ActionButton.tsx b/commafeed-client/src/components/ActionButton.tsx index 6a796614..2a2b5eef 100644 --- a/commafeed-client/src/components/ActionButton.tsx +++ b/commafeed-client/src/components/ActionButton.tsx @@ -5,14 +5,15 @@ import { forwardRef, type MouseEventHandler, type ReactNode } from "react" import { Constants } from "@/app/constants" import { useActionButton } from "@/hooks/useActionButton" +export type Mode = "auto" | "mobile" | "desktop" + interface ActionButtonProps { icon: ReactNode className?: string label?: string | MessageDescriptor onClick?: MouseEventHandler variant?: ActionIconVariant & ButtonVariant - hideLabelOnDesktop?: boolean - showLabelOnMobile?: boolean + mode?: Mode } /** @@ -25,7 +26,9 @@ export const ActionButton = forwardRef((props const label = typeof props.label === "string" ? props.label : props.label && _(props.label) const variant = props.variant ?? "subtle" - const iconOnly = (mobile && !props.showLabelOnMobile) || (!mobile && props.hideLabelOnDesktop) + + const mode: Mode = props.mode ?? "auto" + const iconOnly = mode === "mobile" || (mode === "auto" && mobile) return ( diff --git a/commafeed-client/src/components/header/Header.tsx b/commafeed-client/src/components/header/Header.tsx index 87b0d846..d4d3cc76 100644 --- a/commafeed-client/src/components/header/Header.tsx +++ b/commafeed-client/src/components/header/Header.tsx @@ -2,7 +2,8 @@ import { msg } from "@lingui/core/macro" import { useLingui } from "@lingui/react" import { Box, Center, CloseButton, Divider, Group, Indicator, Popover, TextInput } from "@mantine/core" import { useForm } from "@mantine/form" -import { useEffect } from "react" +import { useElementSize, useViewportSize } from "@mantine/hooks" +import { type ReactNode, type RefCallback, useEffect } from "react" import { TbArrowDown, TbArrowUp, @@ -20,7 +21,7 @@ import { import { markAllAsReadWithConfirmationIfRequired, reloadEntries, search, selectNextEntry, selectPreviousEntry } from "@/app/entries/thunks" import { useAppDispatch, useAppSelector } from "@/app/store" import { changeSettings } from "@/app/user/thunks" -import { ActionButton } from "@/components/ActionButton" +import { ActionButton, type Mode } from "@/components/ActionButton" import { Loader } from "@/components/Loader" import { useActionButton } from "@/hooks/useActionButton" import { useBrowserExtension } from "@/hooks/useBrowserExtension" @@ -31,7 +32,7 @@ function HeaderDivider() { return } -function HeaderToolbar(props: { children: React.ReactNode }) { +function HeaderToolbar(props: { children: ReactNode; ref?: RefCallback }) { const { spacing } = useActionButton() const mobile = useMobile("480px") return mobile ? ( @@ -47,7 +48,7 @@ function HeaderToolbar(props: { children: React.ReactNode }) { {props.children} ) : ( - + {props.children} ) @@ -61,6 +62,13 @@ export function Header() { const searchFromStore = useAppSelector(state => state.entries.search) const { isBrowserExtensionPopup, openSettingsPage, openAppInNewTab } = useBrowserExtension() const dispatch = useAppDispatch() + + const viewport = useViewportSize() + const { ref: headerRef, width: headerWidth } = useElementSize() + const sidebarWidth = useAppSelector(state => state.user.localSettings.sidebarWidth) + const headerTooLarge = headerWidth > viewport.width - sidebarWidth + const mode: Mode = headerTooLarge ? "mobile" : "auto" + const { _ } = useLingui() const searchForm = useForm<{ search: string }>() @@ -94,10 +102,11 @@ export function Header() { return (
- + } label={msg`Previous`} + mode={mode} onClick={async () => await dispatch( selectPreviousEntry({ @@ -111,6 +120,7 @@ export function Header() { } label={msg`Next`} + mode={mode} onClick={async () => await dispatch( selectNextEntry({ @@ -127,11 +137,13 @@ export function Header() { } label={msg`Refresh`} + mode={mode} onClick={async () => await dispatch(reloadEntries())} /> } label={msg`Mark all as read`} + mode={mode} onClick={() => dispatch(markAllAsReadWithConfirmationIfRequired())} /> @@ -140,18 +152,20 @@ export function Header() { : } label={settings.readingMode === "all" ? msg`All` : msg`Unread`} + mode={mode} onClick={toggleReadingMode} /> : } label={settings.readingOrder === "asc" ? msg`Asc` : msg`Desc`} + mode={mode} onClick={toggleReadingOrder} /> - } label={msg`Search`} /> + } label={msg`Search`} mode={mode} /> @@ -169,7 +183,7 @@ export function Header() { - } label={profile?.name} />} /> + } label={profile?.name} mode={mode} />} /> {isBrowserExtensionPopup && ( <> @@ -178,11 +192,13 @@ export function Header() { } label={msg`Extension options`} + mode={mode} onClick={() => openSettingsPage()} /> } label={msg`Open CommaFeed`} + mode={mode} onClick={() => openAppInNewTab()} /> diff --git a/commafeed-client/src/pages/WelcomePage.tsx b/commafeed-client/src/pages/WelcomePage.tsx index 9ccf6489..ed67912d 100644 --- a/commafeed-client/src/pages/WelcomePage.tsx +++ b/commafeed-client/src/pages/WelcomePage.tsx @@ -42,7 +42,7 @@ export function WelcomePage() { icon={} variant="outline" onClick={async () => await login.execute({ name: "demo", password: "demo" })} - showLabelOnMobile + mode="desktop" />
)} @@ -100,7 +100,7 @@ function Buttons() { icon={} variant="outline" onClick={async () => await dispatch(redirectToLogin())} - showLabelOnMobile + mode="desktop" /> {serverInfos?.allowRegistrations && ( } variant="filled" onClick={async () => await dispatch(redirectToRegistration())} - showLabelOnMobile + mode="desktop" /> )} @@ -116,7 +116,7 @@ function Buttons() { label={dark ? msg`Switch to light theme` : msg`Switch to dark theme`} icon={colorScheme === "dark" ? : } onClick={() => toggleColorScheme()} - hideLabelOnDesktop + mode="mobile" /> {isBrowserExtensionPopup && ( @@ -124,7 +124,7 @@ function Buttons() { label={msg`Extension options`} icon={} onClick={() => openSettingsPage()} - hideLabelOnDesktop + mode="mobile" /> )}
diff --git a/commafeed-client/src/pages/app/Layout.tsx b/commafeed-client/src/pages/app/Layout.tsx index 0b44928d..cae8e609 100644 --- a/commafeed-client/src/pages/app/Layout.tsx +++ b/commafeed-client/src/pages/app/Layout.tsx @@ -227,7 +227,7 @@ export default function Layout(props: Readonly) { )} - +