diff options
author | Samuel Newman <mozzius@protonmail.com> | 2024-12-18 16:58:20 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-18 16:58:20 +0000 |
commit | 2d827430eeff14b44944aaae282dbbe3f52f0fbf (patch) | |
tree | 17e087c29c6ac85746c1ac6f0804dcba0034f386 | |
parent | 3262b8342026388a31547645c8543068cada6daf (diff) | |
download | voidsky-2d827430eeff14b44944aaae282dbbe3f52f0fbf.tar.zst |
Web sticky headers for most screens (#7153)
* web sticky headers, with opt-out for notifs * rm from postthread * Fix jump --------- Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
-rw-r--r-- | src/components/Layout/Header/index.tsx | 19 | ||||
-rw-r--r-- | src/view/com/post-thread/PostThread.tsx | 35 | ||||
-rw-r--r-- | src/view/screens/Notifications.tsx | 2 |
3 files changed, 28 insertions, 28 deletions
diff --git a/src/components/Layout/Header/index.tsx b/src/components/Layout/Header/index.tsx index 16b484cea..2d0fc149e 100644 --- a/src/components/Layout/Header/index.tsx +++ b/src/components/Layout/Header/index.tsx @@ -15,6 +15,7 @@ import { useBreakpoints, useGutters, useTheme, + web, } from '#/alf' import {Button, ButtonIcon, ButtonProps} from '#/components/Button' import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeft} from '#/components/icons/Arrow' @@ -29,9 +30,13 @@ import {Text} from '#/components/Typography' export function Outer({ children, noBottomBorder, + headerRef, + sticky = true, }: { children: React.ReactNode noBottomBorder?: boolean + headerRef?: React.MutableRefObject<View | null> + sticky?: boolean }) { const t = useTheme() const gutters = useGutters([0, 'base']) @@ -40,12 +45,14 @@ export function Outer({ return ( <View + ref={headerRef} style={[ a.w_full, !noBottomBorder && a.border_b, a.flex_row, a.align_center, a.gap_sm, + sticky && web([a.sticky, {top: 0}, a.z_10, t.atoms.bg]), gutters, platform({ native: [a.pb_xs, {minHeight: 48}], @@ -85,17 +92,7 @@ export function Content({ } export function Slot({children}: {children?: React.ReactNode}) { - return ( - <View - style={[ - a.z_50, - { - width: HEADER_SLOT_SIZE, - }, - ]}> - {children} - </View> - ) + return <View style={[a.z_50, {width: HEADER_SLOT_SIZE}]}>{children}</View> } export function BackButton({onPress, style, ...props}: Partial<ButtonProps>) { diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx index 477d77aff..af58edcbf 100644 --- a/src/view/com/post-thread/PostThread.tsx +++ b/src/view/com/post-thread/PostThread.tsx @@ -32,11 +32,11 @@ import {usePreferencesQuery} from '#/state/queries/preferences' import {useSession} from '#/state/session' import {useComposerControls} from '#/state/shell' import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies' +import {List, ListMethods} from '#/view/com/util/List' import {atoms as a, useTheme} from '#/alf' +import {Header} from '#/components/Layout' import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' import {Text} from '#/components/Typography' -import {List, ListMethods} from '../util/List' -import {ViewHeader} from '../util/ViewHeader' import {PostThreadComposePrompt} from './PostThreadComposePrompt' import {PostThreadItem} from './PostThreadItem' import {PostThreadLoadMore} from './PostThreadLoadMore' @@ -95,6 +95,7 @@ export function PostThread({uri}: {uri: string | undefined}) { const [hiddenRepliesState, setHiddenRepliesState] = React.useState( HiddenRepliesState.Hide, ) + const headerRef = React.useRef<View | null>(null) const {data: preferences} = usePreferencesQuery() const { @@ -284,18 +285,18 @@ export function PostThread({uri}: {uri: string | undefined}) { } // wait for loading to finish if (thread?.type === 'post' && !!thread.parent) { - function onMeasure(pageY: number) { + // Measure synchronously to avoid a layout jump. + const postNode = highlightedPostRef.current + const headerNode = headerRef.current + if (postNode && headerNode) { + let pageY = (postNode as any as Element).getBoundingClientRect().top + pageY -= (headerNode as any as Element).getBoundingClientRect().height + pageY = Math.max(0, pageY) ref.current?.scrollToOffset({ animated: false, offset: pageY, }) } - // Measure synchronously to avoid a layout jump. - const domNode = highlightedPostRef.current - if (domNode) { - const pageY = (domNode as any as Element).getBoundingClientRect().top - onMeasure(pageY) - } didAdjustScrollWeb.current = true } }, [thread]) @@ -367,7 +368,6 @@ export function PostThread({uri}: {uri: string | undefined}) { skeleton?.highlightedPost?.type === 'post' && (skeleton.highlightedPost.ctx.isParentLoading || Boolean(skeleton?.parents && skeleton.parents.length > 0)) - const showHeader = isNative || !hasParents || !isFetching const renderItem = ({item, index}: {item: RowItem; index: number}) => { if (item === REPLY_PROMPT && hasSession) { @@ -484,12 +484,15 @@ export function PostThread({uri}: {uri: string | undefined}) { return ( <> - {showHeader && ( - <ViewHeader - title={_(msg({message: `Post`, context: 'description'}))} - showBorder - /> - )} + <Header.Outer sticky={true} headerRef={headerRef}> + <Header.BackButton /> + <Header.Content> + <Header.TitleText> + <Trans context="description">Post</Trans> + </Header.TitleText> + </Header.Content> + <Header.Slot /> + </Header.Outer> <ScrollProvider onMomentumEnd={onMomentumEnd}> <List diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx index 4794cdcd0..1880fb816 100644 --- a/src/view/screens/Notifications.tsx +++ b/src/view/screens/Notifications.tsx @@ -121,7 +121,7 @@ export function NotificationsScreen({}: Props) { return ( <Layout.Screen testID="notificationsScreen"> - <Layout.Header.Outer noBottomBorder> + <Layout.Header.Outer noBottomBorder sticky={false}> <Layout.Header.MenuButton /> <Layout.Header.Content> <Layout.Header.TitleText> |