Merge pull request #1133 from bluesky-social/eric/fix-thread-ui
fix thread spacing and reply lineszio/stable
commit
872a7f93f4
|
@ -107,7 +107,7 @@ export class PostThreadItemModel {
|
||||||
const itemModel = new PostThreadItemModel(this.rootStore, item)
|
const itemModel = new PostThreadItemModel(this.rootStore, item)
|
||||||
itemModel._depth = this._depth + 1
|
itemModel._depth = this._depth + 1
|
||||||
itemModel._showParentReplyLine =
|
itemModel._showParentReplyLine =
|
||||||
itemModel.parentUri !== highlightedPostUri && replies.length === 0
|
itemModel.parentUri !== highlightedPostUri
|
||||||
if (item.replies?.length) {
|
if (item.replies?.length) {
|
||||||
itemModel._showChildReplyLine = true
|
itemModel._showChildReplyLine = true
|
||||||
itemModel.assignTreeModels(item, highlightedPostUri, false, true)
|
itemModel.assignTreeModels(item, highlightedPostUri, false, true)
|
||||||
|
|
|
@ -34,8 +34,6 @@ import {formatCount} from '../util/numeric/format'
|
||||||
import {TimeElapsed} from 'view/com/util/TimeElapsed'
|
import {TimeElapsed} from 'view/com/util/TimeElapsed'
|
||||||
import {makeProfileLink} from 'lib/routes/links'
|
import {makeProfileLink} from 'lib/routes/links'
|
||||||
|
|
||||||
const PARENT_REPLY_LINE_LENGTH = 8
|
|
||||||
|
|
||||||
export const PostThreadItem = observer(function PostThreadItem({
|
export const PostThreadItem = observer(function PostThreadItem({
|
||||||
item,
|
item,
|
||||||
onPostReply,
|
onPostReply,
|
||||||
|
@ -159,171 +157,189 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
|
|
||||||
if (item._isHighlightedPost) {
|
if (item._isHighlightedPost) {
|
||||||
return (
|
return (
|
||||||
<Link
|
<>
|
||||||
testID={`postThreadItem-by-${item.post.author.handle}`}
|
{item.rootUri !== item.uri && (
|
||||||
style={[styles.outer, styles.outerHighlighted, pal.border, pal.view]}
|
<View style={{paddingLeft: 18, flexDirection: 'row', height: 16}}>
|
||||||
noFeedback
|
<View style={{width: 52}}>
|
||||||
accessible={false}>
|
<View
|
||||||
<PostSandboxWarning />
|
style={[
|
||||||
<View style={styles.layout}>
|
styles.replyLine,
|
||||||
<View style={styles.layoutAvi}>
|
{
|
||||||
<PreviewableUserAvatar
|
flexGrow: 1,
|
||||||
size={52}
|
backgroundColor: pal.colors.replyLine,
|
||||||
did={item.post.author.did}
|
},
|
||||||
handle={item.post.author.handle}
|
]}
|
||||||
avatar={item.post.author.avatar}
|
/>
|
||||||
moderation={item.moderation.avatar}
|
</View>
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.layoutContent}>
|
)}
|
||||||
<View style={[styles.meta, styles.metaExpandedLine1]}>
|
|
||||||
<View style={[s.flexRow]}>
|
<Link
|
||||||
|
testID={`postThreadItem-by-${item.post.author.handle}`}
|
||||||
|
style={[styles.outer, styles.outerHighlighted, pal.border, pal.view]}
|
||||||
|
noFeedback
|
||||||
|
accessible={false}>
|
||||||
|
<PostSandboxWarning />
|
||||||
|
<View style={styles.layout}>
|
||||||
|
<View style={[styles.layoutAvi, {paddingBottom: 8}]}>
|
||||||
|
<PreviewableUserAvatar
|
||||||
|
size={52}
|
||||||
|
did={item.post.author.did}
|
||||||
|
handle={item.post.author.handle}
|
||||||
|
avatar={item.post.author.avatar}
|
||||||
|
moderation={item.moderation.avatar}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.layoutContent}>
|
||||||
|
<View style={[styles.meta, styles.metaExpandedLine1]}>
|
||||||
|
<View style={[s.flexRow]}>
|
||||||
|
<Link
|
||||||
|
style={styles.metaItem}
|
||||||
|
href={authorHref}
|
||||||
|
title={authorTitle}>
|
||||||
|
<Text
|
||||||
|
type="xl-bold"
|
||||||
|
style={[pal.text]}
|
||||||
|
numberOfLines={1}
|
||||||
|
lineHeight={1.2}>
|
||||||
|
{sanitizeDisplayName(
|
||||||
|
item.post.author.displayName ||
|
||||||
|
sanitizeHandle(item.post.author.handle),
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
</Link>
|
||||||
|
<Text type="md" style={[styles.metaItem, pal.textLight]}>
|
||||||
|
·
|
||||||
|
<TimeElapsed timestamp={item.post.indexedAt}>
|
||||||
|
{({timeElapsed}) => <>{timeElapsed}</>}
|
||||||
|
</TimeElapsed>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={s.flex1} />
|
||||||
|
<PostDropdownBtn
|
||||||
|
testID="postDropdownBtn"
|
||||||
|
itemUri={itemUri}
|
||||||
|
itemCid={itemCid}
|
||||||
|
itemHref={itemHref}
|
||||||
|
itemTitle={itemTitle}
|
||||||
|
isAuthor={item.post.author.did === store.me.did}
|
||||||
|
isThreadMuted={item.isThreadMuted}
|
||||||
|
onCopyPostText={onCopyPostText}
|
||||||
|
onOpenTranslate={onOpenTranslate}
|
||||||
|
onToggleThreadMute={onToggleThreadMute}
|
||||||
|
onDeletePost={onDeletePost}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.meta}>
|
||||||
<Link
|
<Link
|
||||||
style={styles.metaItem}
|
style={styles.metaItem}
|
||||||
href={authorHref}
|
href={authorHref}
|
||||||
title={authorTitle}>
|
title={authorTitle}>
|
||||||
<Text
|
<Text type="md" style={[pal.textLight]} numberOfLines={1}>
|
||||||
type="xl-bold"
|
{sanitizeHandle(item.post.author.handle, '@')}
|
||||||
style={[pal.text]}
|
|
||||||
numberOfLines={1}
|
|
||||||
lineHeight={1.2}>
|
|
||||||
{sanitizeDisplayName(
|
|
||||||
item.post.author.displayName ||
|
|
||||||
sanitizeHandle(item.post.author.handle),
|
|
||||||
)}
|
|
||||||
</Text>
|
</Text>
|
||||||
</Link>
|
</Link>
|
||||||
<Text type="md" style={[styles.metaItem, pal.textLight]}>
|
|
||||||
·
|
|
||||||
<TimeElapsed timestamp={item.post.indexedAt}>
|
|
||||||
{({timeElapsed}) => <>{timeElapsed}</>}
|
|
||||||
</TimeElapsed>
|
|
||||||
</Text>
|
|
||||||
</View>
|
</View>
|
||||||
<View style={s.flex1} />
|
</View>
|
||||||
<PostDropdownBtn
|
</View>
|
||||||
testID="postDropdownBtn"
|
<View style={[s.pl10, s.pr10, s.pb10]}>
|
||||||
|
<ContentHider
|
||||||
|
moderation={item.moderation.content}
|
||||||
|
ignoreMute
|
||||||
|
style={styles.contentHider}
|
||||||
|
childContainerStyle={styles.contentHiderChild}>
|
||||||
|
<PostAlerts
|
||||||
|
moderation={item.moderation.content}
|
||||||
|
includeMute
|
||||||
|
style={styles.alert}
|
||||||
|
/>
|
||||||
|
{item.richText?.text ? (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.postTextContainer,
|
||||||
|
styles.postTextLargeContainer,
|
||||||
|
]}>
|
||||||
|
<RichText
|
||||||
|
type="post-text-lg"
|
||||||
|
richText={item.richText}
|
||||||
|
lineHeight={1.3}
|
||||||
|
style={s.flex1}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
) : undefined}
|
||||||
|
{item.post.embed && (
|
||||||
|
<ContentHider moderation={item.moderation.embed} style={s.mb10}>
|
||||||
|
<PostEmbeds embed={item.post.embed} />
|
||||||
|
</ContentHider>
|
||||||
|
)}
|
||||||
|
</ContentHider>
|
||||||
|
<ExpandedPostDetails
|
||||||
|
post={item.post}
|
||||||
|
translatorUrl={translatorUrl}
|
||||||
|
needsTranslation={needsTranslation}
|
||||||
|
/>
|
||||||
|
{hasEngagement ? (
|
||||||
|
<View style={[styles.expandedInfo, pal.border]}>
|
||||||
|
{item.post.repostCount ? (
|
||||||
|
<Link
|
||||||
|
style={styles.expandedInfoItem}
|
||||||
|
href={repostsHref}
|
||||||
|
title={repostsTitle}>
|
||||||
|
<Text testID="repostCount" type="lg" style={pal.textLight}>
|
||||||
|
<Text type="xl-bold" style={pal.text}>
|
||||||
|
{formatCount(item.post.repostCount)}
|
||||||
|
</Text>{' '}
|
||||||
|
{pluralize(item.post.repostCount, 'repost')}
|
||||||
|
</Text>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
{item.post.likeCount ? (
|
||||||
|
<Link
|
||||||
|
style={styles.expandedInfoItem}
|
||||||
|
href={likesHref}
|
||||||
|
title={likesTitle}>
|
||||||
|
<Text testID="likeCount" type="lg" style={pal.textLight}>
|
||||||
|
<Text type="xl-bold" style={pal.text}>
|
||||||
|
{formatCount(item.post.likeCount)}
|
||||||
|
</Text>{' '}
|
||||||
|
{pluralize(item.post.likeCount, 'like')}
|
||||||
|
</Text>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
<View style={[s.pl10, s.pb5]}>
|
||||||
|
<PostCtrls
|
||||||
|
big
|
||||||
itemUri={itemUri}
|
itemUri={itemUri}
|
||||||
itemCid={itemCid}
|
itemCid={itemCid}
|
||||||
itemHref={itemHref}
|
itemHref={itemHref}
|
||||||
itemTitle={itemTitle}
|
itemTitle={itemTitle}
|
||||||
|
author={item.post.author}
|
||||||
|
text={item.richText?.text || record.text}
|
||||||
|
indexedAt={item.post.indexedAt}
|
||||||
isAuthor={item.post.author.did === store.me.did}
|
isAuthor={item.post.author.did === store.me.did}
|
||||||
|
isReposted={!!item.post.viewer?.repost}
|
||||||
|
isLiked={!!item.post.viewer?.like}
|
||||||
isThreadMuted={item.isThreadMuted}
|
isThreadMuted={item.isThreadMuted}
|
||||||
|
onPressReply={onPressReply}
|
||||||
|
onPressToggleRepost={onPressToggleRepost}
|
||||||
|
onPressToggleLike={onPressToggleLike}
|
||||||
onCopyPostText={onCopyPostText}
|
onCopyPostText={onCopyPostText}
|
||||||
onOpenTranslate={onOpenTranslate}
|
onOpenTranslate={onOpenTranslate}
|
||||||
onToggleThreadMute={onToggleThreadMute}
|
onToggleThreadMute={onToggleThreadMute}
|
||||||
onDeletePost={onDeletePost}
|
onDeletePost={onDeletePost}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.meta}>
|
|
||||||
<Link
|
|
||||||
style={styles.metaItem}
|
|
||||||
href={authorHref}
|
|
||||||
title={authorTitle}>
|
|
||||||
<Text type="md" style={[pal.textLight]} numberOfLines={1}>
|
|
||||||
{sanitizeHandle(item.post.author.handle, '@')}
|
|
||||||
</Text>
|
|
||||||
</Link>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</Link>
|
||||||
<View style={[s.pl10, s.pr10, s.pb10]}>
|
</>
|
||||||
<ContentHider
|
|
||||||
moderation={item.moderation.content}
|
|
||||||
ignoreMute
|
|
||||||
style={styles.contentHider}
|
|
||||||
childContainerStyle={styles.contentHiderChild}>
|
|
||||||
<PostAlerts
|
|
||||||
moderation={item.moderation.content}
|
|
||||||
includeMute
|
|
||||||
style={styles.alert}
|
|
||||||
/>
|
|
||||||
{item.richText?.text ? (
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
styles.postTextContainer,
|
|
||||||
styles.postTextLargeContainer,
|
|
||||||
]}>
|
|
||||||
<RichText
|
|
||||||
type="post-text-lg"
|
|
||||||
richText={item.richText}
|
|
||||||
lineHeight={1.3}
|
|
||||||
style={s.flex1}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
) : undefined}
|
|
||||||
{item.post.embed && (
|
|
||||||
<ContentHider moderation={item.moderation.embed} style={s.mb10}>
|
|
||||||
<PostEmbeds embed={item.post.embed} />
|
|
||||||
</ContentHider>
|
|
||||||
)}
|
|
||||||
</ContentHider>
|
|
||||||
<ExpandedPostDetails
|
|
||||||
post={item.post}
|
|
||||||
translatorUrl={translatorUrl}
|
|
||||||
needsTranslation={needsTranslation}
|
|
||||||
/>
|
|
||||||
{hasEngagement ? (
|
|
||||||
<View style={[styles.expandedInfo, pal.border]}>
|
|
||||||
{item.post.repostCount ? (
|
|
||||||
<Link
|
|
||||||
style={styles.expandedInfoItem}
|
|
||||||
href={repostsHref}
|
|
||||||
title={repostsTitle}>
|
|
||||||
<Text testID="repostCount" type="lg" style={pal.textLight}>
|
|
||||||
<Text type="xl-bold" style={pal.text}>
|
|
||||||
{formatCount(item.post.repostCount)}
|
|
||||||
</Text>{' '}
|
|
||||||
{pluralize(item.post.repostCount, 'repost')}
|
|
||||||
</Text>
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
{item.post.likeCount ? (
|
|
||||||
<Link
|
|
||||||
style={styles.expandedInfoItem}
|
|
||||||
href={likesHref}
|
|
||||||
title={likesTitle}>
|
|
||||||
<Text testID="likeCount" type="lg" style={pal.textLight}>
|
|
||||||
<Text type="xl-bold" style={pal.text}>
|
|
||||||
{formatCount(item.post.likeCount)}
|
|
||||||
</Text>{' '}
|
|
||||||
{pluralize(item.post.likeCount, 'like')}
|
|
||||||
</Text>
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
<View style={[s.pl10, s.pb5]}>
|
|
||||||
<PostCtrls
|
|
||||||
big
|
|
||||||
itemUri={itemUri}
|
|
||||||
itemCid={itemCid}
|
|
||||||
itemHref={itemHref}
|
|
||||||
itemTitle={itemTitle}
|
|
||||||
author={item.post.author}
|
|
||||||
text={item.richText?.text || record.text}
|
|
||||||
indexedAt={item.post.indexedAt}
|
|
||||||
isAuthor={item.post.author.did === store.me.did}
|
|
||||||
isReposted={!!item.post.viewer?.repost}
|
|
||||||
isLiked={!!item.post.viewer?.like}
|
|
||||||
isThreadMuted={item.isThreadMuted}
|
|
||||||
onPressReply={onPressReply}
|
|
||||||
onPressToggleRepost={onPressToggleRepost}
|
|
||||||
onPressToggleLike={onPressToggleLike}
|
|
||||||
onCopyPostText={onCopyPostText}
|
|
||||||
onOpenTranslate={onOpenTranslate}
|
|
||||||
onToggleThreadMute={onToggleThreadMute}
|
|
||||||
onDeletePost={onDeletePost}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Link>
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
|
@ -336,26 +352,36 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
pal.border,
|
pal.border,
|
||||||
pal.view,
|
pal.view,
|
||||||
item._showParentReplyLine && styles.noTopBorder,
|
item._showParentReplyLine && styles.noTopBorder,
|
||||||
|
!item._showChildReplyLine && {borderBottomWidth: 1},
|
||||||
]}
|
]}
|
||||||
moderation={item.moderation.content}>
|
moderation={item.moderation.content}>
|
||||||
{item._showParentReplyLine && (
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
styles.parentReplyLine,
|
|
||||||
{borderColor: pal.colors.replyLine},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{item._showChildReplyLine && (
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
styles.childReplyLine,
|
|
||||||
{borderColor: pal.colors.replyLine},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<PostSandboxWarning />
|
<PostSandboxWarning />
|
||||||
<View style={styles.layout}>
|
|
||||||
|
<View
|
||||||
|
style={{flexDirection: 'row', gap: 10, paddingLeft: 8, height: 16}}>
|
||||||
|
<View style={{width: 52}}>
|
||||||
|
{item._showParentReplyLine && (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.replyLine,
|
||||||
|
{
|
||||||
|
flexGrow: 1,
|
||||||
|
backgroundColor: pal.colors.replyLine,
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.layout,
|
||||||
|
{
|
||||||
|
paddingBottom: item._showChildReplyLine ? 0 : 16,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
<View style={styles.layoutAvi}>
|
<View style={styles.layoutAvi}>
|
||||||
<PreviewableUserAvatar
|
<PreviewableUserAvatar
|
||||||
size={52}
|
size={52}
|
||||||
|
@ -364,7 +390,21 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
avatar={item.post.author.avatar}
|
avatar={item.post.author.avatar}
|
||||||
moderation={item.moderation.avatar}
|
moderation={item.moderation.avatar}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{item._showChildReplyLine && (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.replyLine,
|
||||||
|
{
|
||||||
|
flexGrow: 1,
|
||||||
|
backgroundColor: pal.colors.replyLine,
|
||||||
|
marginTop: 4,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.layoutContent}>
|
<View style={styles.layoutContent}>
|
||||||
<PostMeta
|
<PostMeta
|
||||||
author={item.post.author}
|
author={item.post.author}
|
||||||
|
@ -430,7 +470,7 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
<Link
|
<Link
|
||||||
style={[
|
style={[
|
||||||
styles.loadMore,
|
styles.loadMore,
|
||||||
{borderTopColor: pal.colors.border},
|
{borderBottomColor: pal.colors.border},
|
||||||
pal.view,
|
pal.view,
|
||||||
]}
|
]}
|
||||||
href={itemHref}
|
href={itemHref}
|
||||||
|
@ -480,41 +520,22 @@ const styles = StyleSheet.create({
|
||||||
paddingLeft: 10,
|
paddingLeft: 10,
|
||||||
},
|
},
|
||||||
outerHighlighted: {
|
outerHighlighted: {
|
||||||
paddingTop: 2,
|
paddingTop: 16,
|
||||||
paddingLeft: 6,
|
paddingLeft: 10,
|
||||||
paddingRight: 6,
|
paddingRight: 10,
|
||||||
},
|
},
|
||||||
noTopBorder: {
|
noTopBorder: {
|
||||||
borderTopWidth: 0,
|
borderTopWidth: 0,
|
||||||
},
|
},
|
||||||
parentReplyLine: {
|
|
||||||
position: 'absolute',
|
|
||||||
left: 44,
|
|
||||||
top: -1 * PARENT_REPLY_LINE_LENGTH + 6,
|
|
||||||
height: PARENT_REPLY_LINE_LENGTH,
|
|
||||||
borderLeftWidth: 2,
|
|
||||||
},
|
|
||||||
childReplyLine: {
|
|
||||||
position: 'absolute',
|
|
||||||
left: 44,
|
|
||||||
top: 65,
|
|
||||||
bottom: 0,
|
|
||||||
borderLeftWidth: 2,
|
|
||||||
},
|
|
||||||
layout: {
|
layout: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
gap: 10,
|
||||||
|
paddingLeft: 8,
|
||||||
},
|
},
|
||||||
layoutAvi: {
|
layoutAvi: {},
|
||||||
paddingLeft: 10,
|
|
||||||
paddingTop: 10,
|
|
||||||
paddingBottom: 10,
|
|
||||||
marginRight: 10,
|
|
||||||
},
|
|
||||||
layoutContent: {
|
layoutContent: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
paddingRight: 10,
|
paddingRight: 10,
|
||||||
paddingTop: 10,
|
|
||||||
paddingBottom: 10,
|
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
@ -567,10 +588,14 @@ const styles = StyleSheet.create({
|
||||||
loadMore: {
|
loadMore: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
borderTopWidth: 1,
|
borderBottomWidth: 1,
|
||||||
paddingLeft: 80,
|
paddingLeft: 80,
|
||||||
paddingRight: 20,
|
paddingRight: 20,
|
||||||
paddingVertical: 10,
|
paddingVertical: 12,
|
||||||
marginBottom: 8,
|
},
|
||||||
|
replyLine: {
|
||||||
|
width: 2,
|
||||||
|
marginLeft: 'auto',
|
||||||
|
marginRight: 'auto',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue