Add moreParents handling

This commit is contained in:
Eric Bailey
2025-06-05 10:37:34 -05:00
parent c705c431d8
commit 8144eac8a2
8 changed files with 149 additions and 3 deletions
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2Zm0 2a8 8 0 1 0 0 16 8 8 0 0 0 0-16Zm-.63 3.225a1 1 0 0 1 1.337.068l3 3 .068.076a1 1 0 0 1-1.406 1.406l-.076-.068L13 10.414V16a1 1 0 1 1-2 0v-5.586l-1.293 1.293a1 1 0 1 1-1.414-1.414l3-3 .076-.068Z"/></svg>

After

Width:  |  Height:  |  Size: 371 B

+5
View File
@@ -0,0 +1,5 @@
import {createSinglePathSVG} from './TEMPLATE'
export const ArrowTopCircle_Stroke2_Corner0_Rounded = createSinglePathSVG({
path: 'M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2Zm0 2a8 8 0 1 0 0 16 8 8 0 0 0 0-16Zm-.63 3.225a1 1 0 0 1 1.337.068l3 3 .068.076a1 1 0 0 1-1.406 1.406l-.076-.068L13 10.414V16a1 1 0 1 1-2 0v-5.586l-1.293 1.293a1 1 0 1 1-1.414-1.414l3-3 .076-.068Z',
})
@@ -0,0 +1,90 @@
import {memo} from 'react'
import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {type ThreadItem} from '#/state/queries/usePostThread'
import {
LINEAR_AVI_WIDTH,
OUTER_SPACE,
REPLY_LINE_WIDTH,
} from '#/screens/PostThread/const'
import {atoms as a, useTheme} from '#/alf'
import {ArrowTopCircle_Stroke2_Corner0_Rounded as UpIcon} from '#/components/icons/ArrowTopCircle'
import {Link} from '#/components/Link'
import {Text} from '#/components/Typography'
export const ThreadItemReadMoreUp = memo(function ThreadItemReadMoreUp({
item,
}: {
item: Extract<ThreadItem, {type: 'readMoreUp'}>
}) {
const t = useTheme()
const {_} = useLingui()
return (
<Link
label={_(msg`Continue thread`)}
to={item.href}
style={[
a.gap_xs,
{
paddingTop: OUTER_SPACE,
paddingHorizontal: OUTER_SPACE,
},
]}>
{({hovered, pressed}) => {
const interacted = hovered || pressed
return (
<View>
<View style={[a.flex_row, a.align_center, a.gap_md]}>
<View
style={[
a.align_center,
{
width: LINEAR_AVI_WIDTH,
},
]}>
<UpIcon
fill="currentColor"
width={24}
style={[
t.atoms.text_contrast_low,
a.transition_all,
interacted && [t.atoms.text_contrast_high],
]}
/>
</View>
<Text
style={[
a.text_sm,
t.atoms.text_contrast_medium,
interacted && [a.underline],
]}>
<Trans>Continue thread...</Trans>
</Text>
</View>
<View
style={[
a.align_center,
{
width: LINEAR_AVI_WIDTH,
},
]}>
<View
style={[
a.mt_xs,
{
height: OUTER_SPACE / 2,
width: REPLY_LINE_WIDTH,
backgroundColor: t.atoms.border_contrast_low.borderColor,
},
]}
/>
</View>
</View>
)
}}
</Link>
)
})
+5 -2
View File
@@ -24,6 +24,7 @@ import {
} from '#/screens/PostThread/components/ThreadItemPost'
import {ThreadItemPostTombstone} from '#/screens/PostThread/components/ThreadItemPostTombstone'
import {ThreadItemReadMore} from '#/screens/PostThread/components/ThreadItemReadMore'
import {ThreadItemReadMoreUp} from '#/screens/PostThread/components/ThreadItemReadMoreUp'
import {ThreadItemTreePost} from '#/screens/PostThread/components/ThreadItemTreePost'
import {useBreakpoints, web} from '#/alf'
import * as Layout from '#/components/Layout'
@@ -191,8 +192,8 @@ export function Inner({uri}: {uri: string | undefined}) {
}
}
} else {
// ignore parents
if (hasDepth && item.depth < 0) continue
// ignore any parent items
if (item.type === 'readMoreUp' || (hasDepth && item.depth < 0)) continue
// can exit early if we've reached the max children count
if (childrenCount > maxChildrenCount) break
@@ -271,6 +272,8 @@ export function Inner({uri}: {uri: string | undefined}) {
view={thread.state.view === 'tree' ? 'tree' : 'linear'}
/>
)
} else if (item.type === 'readMoreUp') {
return <ThreadItemReadMoreUp item={item} />
} else if (item.type === 'threadPostBlocked') {
return <ThreadItemPostTombstone type="blocked" />
} else if (item.type === 'threadPostNotFound') {
@@ -353,6 +353,16 @@ export function sortAndAnnotateThreadItems(
i++
}
/**
* Only occurs for the first item in the thread, which may have
* additional parents not included in this request.
*/
if (item.value.moreParents) {
metadata.followsReadMoreUp = true
subset.splice(i, 0, views.readMoreUp(metadata))
i++
}
/*
* Calculate the final UI state for the thread item.
*/
@@ -362,6 +372,8 @@ export function sortAndAnnotateThreadItems(
}
}
console.log(threadItems)
return {
threadItems,
hiddenThreadItems,
+10
View File
@@ -100,6 +100,11 @@ export type ThreadItem =
moreReplies: number
skippedIndentIndices: Set<number>
}
| {
type: 'readMoreUp'
key: string
href: string
}
| {
type: 'skeleton'
key: string
@@ -117,6 +122,11 @@ export type TraversalMetadata = {
* calculated on the server.
*/
depth: number
/**
* Indicates if this item is a "read more" link preceding this post that
* continues the thread upwards.
*/
followsReadMoreUp: boolean
/**
* Indicates if the post is the last reply beneath its parent post.
*/
+7 -1
View File
@@ -81,6 +81,10 @@ export function getTraversalMetadata({
* Unknown until after traversal
*/
precedesChildReadMore: false,
/*
* Unknown until after traversal
*/
followsReadMoreUp: false,
postData: {
uri: item.uri,
authorHandle: item.value.post.author.handle,
@@ -124,6 +128,7 @@ export function getThreadPostUI({
repliesSeenCount,
repliesUnhydrated,
precedesChildReadMore,
followsReadMoreUp,
}: TraversalMetadata): Extract<ThreadItem, {type: 'threadPost'}>['ui'] {
// TODO might be able to simplify this
const isReplyAndHasReplies =
@@ -134,7 +139,8 @@ export function getThreadPostUI({
return {
isAnchor: depth === 0,
showParentReplyLine:
!!prevItemDepth && prevItemDepth !== 0 && prevItemDepth < depth,
followsReadMoreUp ||
(!!prevItemDepth && prevItemDepth !== 0 && prevItemDepth < depth),
showChildReplyLine: depth < 0 || isReplyAndHasReplies,
indent: depth,
/*
+19
View File
@@ -124,6 +124,25 @@ export function readMore({
}
}
export function readMoreUp({
postData,
}: TraversalMetadata): Extract<ThreadItem, {type: 'readMoreUp'}> {
const urip = new AtUri(postData.uri)
const href = makeProfileLink(
{
did: urip.host,
handle: postData.authorHandle,
},
'post',
urip.rkey,
)
return {
type: 'readMoreUp' as const,
key: `readMoreUp:${postData.uri}`,
href,
}
}
export function skeleton({
key,
item,