diff --git a/src/components/ShowMore.tsx b/src/components/ShowMore.tsx
new file mode 100644
index 0000000000..b8bd0c5b27
--- /dev/null
+++ b/src/components/ShowMore.tsx
@@ -0,0 +1,31 @@
+import {useCallback} from 'react'
+import {LayoutAnimation} from 'react-native'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {HITSLOP_10} from '#/lib/constants'
+import {atoms as a} from '#/alf'
+import {Button, ButtonText} from '#/components/Button'
+
+export function ShowMore({onPress: onPressProp}: {onPress: () => void}) {
+ const {_} = useLingui()
+
+ const onPress = useCallback(() => {
+ LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
+ onPressProp()
+ }, [onPressProp])
+
+ return (
+
+ )
+}
diff --git a/src/screens/PostThread/components/ThreadItemPost.tsx b/src/screens/PostThread/components/ThreadItemPost.tsx
index 1f63b10cd9..4dc31ce700 100644
--- a/src/screens/PostThread/components/ThreadItemPost.tsx
+++ b/src/screens/PostThread/components/ThreadItemPost.tsx
@@ -6,13 +6,11 @@ import {
AtUri,
RichText as RichTextAPI,
} from '@atproto/api'
-import {msg, Trans} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
+import {Trans} from '@lingui/macro'
import {useActorStatus} from '#/lib/actor-status'
import {MAX_POST_LINES} from '#/lib/constants'
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
-import {usePalette} from '#/lib/hooks/usePalette'
import {makeProfileLink} from '#/lib/routes/links'
import {countLines} from '#/lib/strings/helpers'
import {
@@ -24,7 +22,6 @@ import {type ThreadItem} from '#/state/queries/usePostThread/types'
import {useSession} from '#/state/session'
import {type OnPostSuccessData} from '#/state/shell/composer'
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
-import {TextLink} from '#/view/com/util/Link'
import {PostEmbeds, PostEmbedViewContext} from '#/view/com/util/post-embeds'
import {PostMeta} from '#/view/com/util/PostMeta'
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
@@ -42,6 +39,7 @@ import {PostHider} from '#/components/moderation/PostHider'
import {type AppModerationCause} from '#/components/Pills'
import {PostControls} from '#/components/PostControls'
import {RichText} from '#/components/RichText'
+import {ShowMore} from '#/components/ShowMore'
import * as Skele from '#/components/Skeleton'
import {SubtleWebHover} from '#/components/SubtleWebHover'
import {Text} from '#/components/Typography'
@@ -187,8 +185,6 @@ const ThreadItemPostInner = memo(function ThreadItemPostInner({
postShadow: Shadow
}) {
const t = useTheme()
- const pal = usePalette('default')
- const {_} = useLingui()
const {openComposer} = useOpenComposer()
const {currentAccount} = useSession()
@@ -313,14 +309,7 @@ const ThreadItemPostInner = memo(function ThreadItemPostInner({
shouldProxyLinks={true}
/>
) : undefined}
- {limitLines ? (
-
- ) : undefined}
+ {limitLines && }
{post.embed && (
void
threadgateRecord?: AppBskyFeedThreadgate.Record
}): React.ReactNode {
- const pal = usePalette('default')
- const {_} = useLingui()
const {openComposer} = useOpenComposer()
const {currentAccount} = useSession()
@@ -271,18 +267,18 @@ const ThreadItemTreePostInner = memo(function ThreadItemTreePostInner({
}),
[record],
)
- const [limitLines, setLimitLines] = React.useState(
+ const [limitLines, setLimitLines] = useState(
() => countLines(richText?.text) >= MAX_POST_LINES,
)
const threadRootUri = record.reply?.root?.uri || post.uri
- const postHref = React.useMemo(() => {
+ const postHref = useMemo(() => {
const urip = new AtUri(post.uri)
return makeProfileLink(post.author, 'post', urip.rkey)
}, [post.uri, post.author])
const threadgateHiddenReplies = useMergedThreadgateHiddenReplies({
threadgateRecord,
})
- const additionalPostAlerts: AppModerationCause[] = React.useMemo(() => {
+ const additionalPostAlerts: AppModerationCause[] = useMemo(() => {
const isPostHiddenByThreadgate = threadgateHiddenReplies.has(post.uri)
const isControlledByViewer =
new AtUri(threadRootUri).host === currentAccount?.did
@@ -297,7 +293,7 @@ const ThreadItemTreePostInner = memo(function ThreadItemTreePostInner({
: []
}, [post, currentAccount?.did, threadgateHiddenReplies, threadRootUri])
- const onPressReply = React.useCallback(() => {
+ const onPressReply = useCallback(() => {
openComposer({
replyTo: {
uri: post.uri,
@@ -311,7 +307,7 @@ const ThreadItemTreePostInner = memo(function ThreadItemTreePostInner({
})
}, [openComposer, post, record, onPostSuccess, moderation])
- const onPressShowMore = React.useCallback(() => {
+ const onPressShowMore = useCallback(() => {
setLimitLines(false)
}, [setLimitLines])
@@ -359,14 +355,7 @@ const ThreadItemTreePostInner = memo(function ThreadItemTreePostInner({
/>
) : undefined}
- {limitLines ? (
-
- ) : undefined}
+ {limitLines && }
{post.embed && (
0 && (
+ style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}
+ numberOfLines={MAX_POST_LINES}>
{text}
)}
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index 5184047cbb..75c202f8fe 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -44,7 +44,7 @@ import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replie
import {type PostSource} from '#/state/unstable-post-source'
import {PostThreadFollowBtn} from '#/view/com/post-thread/PostThreadFollowBtn'
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
-import {Link, TextLink} from '#/view/com/util/Link'
+import {Link} from '#/view/com/util/Link'
import {formatCount} from '#/view/com/util/numeric/format'
import {PostEmbeds, PostEmbedViewContext} from '#/view/com/util/post-embeds'
import {PostMeta} from '#/view/com/util/PostMeta'
@@ -65,6 +65,7 @@ import {type AppModerationCause} from '#/components/Pills'
import {PostControls} from '#/components/PostControls'
import * as Prompt from '#/components/Prompt'
import {RichText} from '#/components/RichText'
+import {ShowMore} from '#/components/ShowMore'
import {SubtleWebHover} from '#/components/SubtleWebHover'
import {Text} from '#/components/Typography'
import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton'
@@ -687,14 +688,7 @@ let PostThreadItemLoaded = ({
/>
) : undefined}
- {limitLines ? (
-
- ) : undefined}
+ {limitLines && }
{post.embed && (
countLines(richText?.text) >= MAX_POST_LINES,
@@ -128,7 +127,7 @@ function PostInner({
replyAuthorDid = urip.hostname
}
- const onPressReply = React.useCallback(() => {
+ const onPressReply = useCallback(() => {
openComposer({
replyTo: {
uri: post.uri,
@@ -141,18 +140,18 @@ function PostInner({
})
}, [openComposer, post, record, moderation])
- const onPressShowMore = React.useCallback(() => {
+ const onPressShowMore = useCallback(() => {
setLimitLines(false)
}, [setLimitLines])
- const onBeforePress = React.useCallback(() => {
+ const onBeforePress = useCallback(() => {
precacheProfile(queryClient, post.author)
}, [queryClient, post.author])
const {currentAccount} = useSession()
const isMe = replyAuthorDid === currentAccount?.did
- const [hover, setHover] = React.useState(false)
+ const [hover, setHover] = useState(false)
return (
) : undefined}
- {limitLines ? (
-
- ) : undefined}
+ {limitLines && }
{post.embed ? (
{
- const pal = usePalette('default')
- const {_} = useLingui()
const {currentAccount} = useSession()
const [limitLines, setLimitLines] = useState(
() => countLines(richText.text) >= MAX_POST_LINES,
@@ -558,14 +557,7 @@ let PostContent = ({
/>
) : undefined}
- {limitLines ? (
-
- ) : undefined}
+ {limitLines && }
{postEmbed ? (