Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Samuel Newman
Dan Abramov
and committed by
GitHub
2d827430 3262b834

+28 -28
+8 -11
src/components/Layout/Header/index.tsx
··· 15 15 useBreakpoints, 16 16 useGutters, 17 17 useTheme, 18 + web, 18 19 } from '#/alf' 19 20 import {Button, ButtonIcon, ButtonProps} from '#/components/Button' 20 21 import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeft} from '#/components/icons/Arrow' ··· 29 30 export function Outer({ 30 31 children, 31 32 noBottomBorder, 33 + headerRef, 34 + sticky = true, 32 35 }: { 33 36 children: React.ReactNode 34 37 noBottomBorder?: boolean 38 + headerRef?: React.MutableRefObject<View | null> 39 + sticky?: boolean 35 40 }) { 36 41 const t = useTheme() 37 42 const gutters = useGutters([0, 'base']) ··· 40 45 41 46 return ( 42 47 <View 48 + ref={headerRef} 43 49 style={[ 44 50 a.w_full, 45 51 !noBottomBorder && a.border_b, 46 52 a.flex_row, 47 53 a.align_center, 48 54 a.gap_sm, 55 + sticky && web([a.sticky, {top: 0}, a.z_10, t.atoms.bg]), 49 56 gutters, 50 57 platform({ 51 58 native: [a.pb_xs, {minHeight: 48}], ··· 85 92 } 86 93 87 94 export function Slot({children}: {children?: React.ReactNode}) { 88 - return ( 89 - <View 90 - style={[ 91 - a.z_50, 92 - { 93 - width: HEADER_SLOT_SIZE, 94 - }, 95 - ]}> 96 - {children} 97 - </View> 98 - ) 95 + return <View style={[a.z_50, {width: HEADER_SLOT_SIZE}]}>{children}</View> 99 96 } 100 97 101 98 export function BackButton({onPress, style, ...props}: Partial<ButtonProps>) {
+19 -16
src/view/com/post-thread/PostThread.tsx
··· 32 32 import {useSession} from '#/state/session' 33 33 import {useComposerControls} from '#/state/shell' 34 34 import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies' 35 + import {List, ListMethods} from '#/view/com/util/List' 35 36 import {atoms as a, useTheme} from '#/alf' 37 + import {Header} from '#/components/Layout' 36 38 import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' 37 39 import {Text} from '#/components/Typography' 38 - import {List, ListMethods} from '../util/List' 39 - import {ViewHeader} from '../util/ViewHeader' 40 40 import {PostThreadComposePrompt} from './PostThreadComposePrompt' 41 41 import {PostThreadItem} from './PostThreadItem' 42 42 import {PostThreadLoadMore} from './PostThreadLoadMore' ··· 95 95 const [hiddenRepliesState, setHiddenRepliesState] = React.useState( 96 96 HiddenRepliesState.Hide, 97 97 ) 98 + const headerRef = React.useRef<View | null>(null) 98 99 99 100 const {data: preferences} = usePreferencesQuery() 100 101 const { ··· 284 285 } 285 286 // wait for loading to finish 286 287 if (thread?.type === 'post' && !!thread.parent) { 287 - function onMeasure(pageY: number) { 288 + // Measure synchronously to avoid a layout jump. 289 + const postNode = highlightedPostRef.current 290 + const headerNode = headerRef.current 291 + if (postNode && headerNode) { 292 + let pageY = (postNode as any as Element).getBoundingClientRect().top 293 + pageY -= (headerNode as any as Element).getBoundingClientRect().height 294 + pageY = Math.max(0, pageY) 288 295 ref.current?.scrollToOffset({ 289 296 animated: false, 290 297 offset: pageY, 291 298 }) 292 299 } 293 - // Measure synchronously to avoid a layout jump. 294 - const domNode = highlightedPostRef.current 295 - if (domNode) { 296 - const pageY = (domNode as any as Element).getBoundingClientRect().top 297 - onMeasure(pageY) 298 - } 299 300 didAdjustScrollWeb.current = true 300 301 } 301 302 }, [thread]) ··· 367 368 skeleton?.highlightedPost?.type === 'post' && 368 369 (skeleton.highlightedPost.ctx.isParentLoading || 369 370 Boolean(skeleton?.parents && skeleton.parents.length > 0)) 370 - const showHeader = isNative || !hasParents || !isFetching 371 371 372 372 const renderItem = ({item, index}: {item: RowItem; index: number}) => { 373 373 if (item === REPLY_PROMPT && hasSession) { ··· 484 484 485 485 return ( 486 486 <> 487 - {showHeader && ( 488 - <ViewHeader 489 - title={_(msg({message: `Post`, context: 'description'}))} 490 - showBorder 491 - /> 492 - )} 487 + <Header.Outer sticky={true} headerRef={headerRef}> 488 + <Header.BackButton /> 489 + <Header.Content> 490 + <Header.TitleText> 491 + <Trans context="description">Post</Trans> 492 + </Header.TitleText> 493 + </Header.Content> 494 + <Header.Slot /> 495 + </Header.Outer> 493 496 494 497 <ScrollProvider onMomentumEnd={onMomentumEnd}> 495 498 <List
+1 -1
src/view/screens/Notifications.tsx
··· 121 121 122 122 return ( 123 123 <Layout.Screen testID="notificationsScreen"> 124 - <Layout.Header.Outer noBottomBorder> 124 + <Layout.Header.Outer noBottomBorder sticky={false}> 125 125 <Layout.Header.MenuButton /> 126 126 <Layout.Header.Content> 127 127 <Layout.Header.TitleText>