Use Button instead of TextLink for show more button (#8480)
* use button instead of TextLink for show more * Match post text size, provide interaction feedback * Move to new Post components dir * Prettier --------- Co-authored-by: Eric Bailey <git@esb.lol>
This commit is contained in:
@@ -1,11 +1,15 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {ActivityIndicator, GestureResponderEvent, Pressable} from 'react-native'
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
type GestureResponderEvent,
|
||||||
|
Pressable,
|
||||||
|
} from 'react-native'
|
||||||
import {Image} from 'expo-image'
|
import {Image} from 'expo-image'
|
||||||
import {AppBskyEmbedExternal} from '@atproto/api'
|
import {type AppBskyEmbedExternal} from '@atproto/api'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {EmbedPlayerParams} from '#/lib/strings/embed-player'
|
import {type EmbedPlayerParams} from '#/lib/strings/embed-player'
|
||||||
import {isIOS, isNative, isWeb} from '#/platform/detection'
|
import {isIOS, isNative, isWeb} from '#/platform/detection'
|
||||||
import {useExternalEmbedsPrefs} from '#/state/preferences'
|
import {useExternalEmbedsPrefs} from '#/state/preferences'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
GestureResponderEvent,
|
type GestureResponderEvent,
|
||||||
Pressable,
|
Pressable,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
useWindowDimensions,
|
useWindowDimensions,
|
||||||
@@ -16,13 +16,16 @@ import Animated, {
|
|||||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||||
import {WebView} from 'react-native-webview'
|
import {WebView} from 'react-native-webview'
|
||||||
import {Image} from 'expo-image'
|
import {Image} from 'expo-image'
|
||||||
import {AppBskyEmbedExternal} from '@atproto/api'
|
import {type AppBskyEmbedExternal} from '@atproto/api'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useNavigation} from '@react-navigation/native'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
|
|
||||||
import {NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
import {EmbedPlayerParams, getPlayerAspect} from '#/lib/strings/embed-player'
|
import {
|
||||||
|
type EmbedPlayerParams,
|
||||||
|
getPlayerAspect,
|
||||||
|
} from '#/lib/strings/embed-player'
|
||||||
import {isNative} from '#/platform/detection'
|
import {isNative} from '#/platform/detection'
|
||||||
import {useExternalEmbedsPrefs} from '#/state/preferences'
|
import {useExternalEmbedsPrefs} from '#/state/preferences'
|
||||||
import {EventStopper} from '#/view/com/util/EventStopper'
|
import {EventStopper} from '#/view/com/util/EventStopper'
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
Pressable,
|
Pressable,
|
||||||
StyleProp,
|
type StyleProp,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View,
|
||||||
ViewStyle,
|
type ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {HITSLOP_20} from '#/lib/constants'
|
import {HITSLOP_20} from '#/lib/constants'
|
||||||
import {EmbedPlayerParams} from '#/lib/strings/embed-player'
|
import {type EmbedPlayerParams} from '#/lib/strings/embed-player'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isWeb} from '#/platform/detection'
|
||||||
import {useAutoplayDisabled} from '#/state/preferences'
|
import {useAutoplayDisabled} from '#/state/preferences'
|
||||||
import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge'
|
import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge'
|
||||||
@@ -22,7 +22,7 @@ import * as Prompt from '#/components/Prompt'
|
|||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {PlayButtonIcon} from '#/components/video/PlayButtonIcon'
|
import {PlayButtonIcon} from '#/components/video/PlayButtonIcon'
|
||||||
import {GifView} from '../../../../../modules/expo-bluesky-gif-view'
|
import {GifView} from '../../../../../modules/expo-bluesky-gif-view'
|
||||||
import {GifViewStateChangeEvent} from '../../../../../modules/expo-bluesky-gif-view/src/GifView.types'
|
import {type GifViewStateChangeEvent} from '../../../../../modules/expo-bluesky-gif-view/src/GifView.types'
|
||||||
|
|
||||||
function PlaybackControls({
|
function PlaybackControls({
|
||||||
onPress,
|
onPress,
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
|||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import * as ListCard from '#/components/ListCard'
|
import * as ListCard from '#/components/ListCard'
|
||||||
import {ContentHider} from '#/components/moderation/ContentHider'
|
import {ContentHider} from '#/components/moderation/ContentHider'
|
||||||
import {EmbedType} from '#/types/bsky/post'
|
import {type EmbedType} from '#/types/bsky/post'
|
||||||
import {CommonProps} from './types'
|
import {type CommonProps} from './types'
|
||||||
|
|
||||||
export function ListEmbed({
|
export function ListEmbed({
|
||||||
embed,
|
embed,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {StyleProp, ViewStyle} from 'react-native'
|
import {type StyleProp, type ViewStyle} from 'react-native'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {msg, plural} from '@lingui/macro'
|
import {msg, plural} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, {useRef} from 'react'
|
import React, {useRef} from 'react'
|
||||||
import {Pressable, StyleProp, View, ViewStyle} from 'react-native'
|
import {Pressable, type StyleProp, View, type ViewStyle} from 'react-native'
|
||||||
import {AppBskyEmbedVideo} from '@atproto/api'
|
import {type AppBskyEmbedVideo} from '@atproto/api'
|
||||||
import {BlueskyVideoView} from '@haileyok/bluesky-video'
|
import {BlueskyVideoView} from '@haileyok/bluesky-video'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react'
|
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
import type React from 'react'
|
||||||
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import {type SvgProps} from 'react-native-svg'
|
||||||
import {SvgProps} from 'react-native-svg'
|
import type React from 'react'
|
||||||
|
|
||||||
import {PressableWithHover} from '#/view/com/util/PressableWithHover'
|
import {PressableWithHover} from '#/view/com/util/PressableWithHover'
|
||||||
import {atoms as a, useTheme, web} from '#/alf'
|
import {atoms as a, useTheme, web} from '#/alf'
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React, {useCallback, useEffect, useRef, useState} from 'react'
|
import {useCallback, useEffect, useRef, useState} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
import type React from 'react'
|
||||||
|
|
||||||
import {isFirefox, isTouchDevice} from '#/lib/browser'
|
import {isFirefox, isTouchDevice} from '#/lib/browser'
|
||||||
import {clamp} from '#/lib/numbers'
|
import {clamp} from '#/lib/numbers'
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import React, {useCallback} from 'react'
|
import {useCallback} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'
|
import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
import type React from 'react'
|
||||||
|
|
||||||
import {isSafari, isTouchDevice} from '#/lib/browser'
|
import {isSafari, isTouchDevice} from '#/lib/browser'
|
||||||
import {atoms as a} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, {useCallback, useState} from 'react'
|
import React, {useCallback, useState} from 'react'
|
||||||
import {ActivityIndicator, View} from 'react-native'
|
import {ActivityIndicator, View} from 'react-native'
|
||||||
import {ImageBackground} from 'expo-image'
|
import {ImageBackground} from 'expo-image'
|
||||||
import {AppBskyEmbedVideo} from '@atproto/api'
|
import {type AppBskyEmbedVideo} from '@atproto/api'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import React, {useCallback, useEffect, useRef, useState} from 'react'
|
import {useCallback, useEffect, useRef, useState} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {AppBskyEmbedVideo} from '@atproto/api'
|
import {type AppBskyEmbedVideo} from '@atproto/api'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
import type React from 'react'
|
||||||
|
|
||||||
import {isFirefox} from '#/lib/browser'
|
import {isFirefox} from '#/lib/browser'
|
||||||
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
|
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import {useCallback, useMemo} from 'react'
|
||||||
|
import {LayoutAnimation, type TextStyle} from 'react-native'
|
||||||
|
import {msg, Trans} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {HITSLOP_10} from '#/lib/constants'
|
||||||
|
import {atoms as a, flatten, type TextStyleProp, useTheme} from '#/alf'
|
||||||
|
import {Button} from '#/components/Button'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
|
export function ShowMoreTextButton({
|
||||||
|
onPress: onPressProp,
|
||||||
|
style,
|
||||||
|
}: TextStyleProp & {onPress: () => void}) {
|
||||||
|
const t = useTheme()
|
||||||
|
const {_} = useLingui()
|
||||||
|
|
||||||
|
const onPress = useCallback(() => {
|
||||||
|
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
|
||||||
|
onPressProp()
|
||||||
|
}, [onPressProp])
|
||||||
|
|
||||||
|
const textStyle = useMemo(() => {
|
||||||
|
return flatten([a.leading_snug, a.text_sm, style]) as TextStyle & {
|
||||||
|
fontSize: number
|
||||||
|
lineHeight: number
|
||||||
|
}
|
||||||
|
}, [style])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
label={_(msg`Expand post text`)}
|
||||||
|
onPress={onPress}
|
||||||
|
style={[
|
||||||
|
a.self_start,
|
||||||
|
{
|
||||||
|
paddingBottom: textStyle.fontSize / 3,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
hitSlop={HITSLOP_10}>
|
||||||
|
{({pressed, hovered}) => (
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
textStyle,
|
||||||
|
{
|
||||||
|
color: t.palette.primary_500,
|
||||||
|
opacity: pressed ? 0.6 : 1,
|
||||||
|
textDecorationLine: hovered ? 'underline' : undefined,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Trans>Show More</Trans>
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -6,13 +6,11 @@ import {
|
|||||||
AtUri,
|
AtUri,
|
||||||
RichText as RichTextAPI,
|
RichText as RichTextAPI,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
import {useActorStatus} from '#/lib/actor-status'
|
||||||
import {MAX_POST_LINES} from '#/lib/constants'
|
import {MAX_POST_LINES} from '#/lib/constants'
|
||||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
import {countLines} from '#/lib/strings/helpers'
|
import {countLines} from '#/lib/strings/helpers'
|
||||||
import {
|
import {
|
||||||
@@ -24,7 +22,6 @@ import {type ThreadItem} from '#/state/queries/usePostThread/types'
|
|||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {type OnPostSuccessData} from '#/state/shell/composer'
|
import {type OnPostSuccessData} from '#/state/shell/composer'
|
||||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||||
import {TextLink} from '#/view/com/util/Link'
|
|
||||||
import {PostMeta} from '#/view/com/util/PostMeta'
|
import {PostMeta} from '#/view/com/util/PostMeta'
|
||||||
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
|
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
|
||||||
import {
|
import {
|
||||||
@@ -40,6 +37,7 @@ import {PostAlerts} from '#/components/moderation/PostAlerts'
|
|||||||
import {PostHider} from '#/components/moderation/PostHider'
|
import {PostHider} from '#/components/moderation/PostHider'
|
||||||
import {type AppModerationCause} from '#/components/Pills'
|
import {type AppModerationCause} from '#/components/Pills'
|
||||||
import {Embed, PostEmbedViewContext} from '#/components/Post/Embed'
|
import {Embed, PostEmbedViewContext} from '#/components/Post/Embed'
|
||||||
|
import {ShowMoreTextButton} from '#/components/Post/ShowMoreTextButton'
|
||||||
import {PostControls} from '#/components/PostControls'
|
import {PostControls} from '#/components/PostControls'
|
||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
import * as Skele from '#/components/Skeleton'
|
import * as Skele from '#/components/Skeleton'
|
||||||
@@ -187,8 +185,6 @@ const ThreadItemPostInner = memo(function ThreadItemPostInner({
|
|||||||
postShadow: Shadow<AppBskyFeedDefs.PostView>
|
postShadow: Shadow<AppBskyFeedDefs.PostView>
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const pal = usePalette('default')
|
|
||||||
const {_} = useLingui()
|
|
||||||
const {openComposer} = useOpenComposer()
|
const {openComposer} = useOpenComposer()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
|
|
||||||
@@ -304,6 +300,7 @@ const ThreadItemPostInner = memo(function ThreadItemPostInner({
|
|||||||
additionalCauses={additionalPostAlerts}
|
additionalCauses={additionalPostAlerts}
|
||||||
/>
|
/>
|
||||||
{richText?.text ? (
|
{richText?.text ? (
|
||||||
|
<>
|
||||||
<RichText
|
<RichText
|
||||||
enableTags
|
enableTags
|
||||||
value={richText}
|
value={richText}
|
||||||
@@ -312,14 +309,13 @@ const ThreadItemPostInner = memo(function ThreadItemPostInner({
|
|||||||
authorHandle={post.author.handle}
|
authorHandle={post.author.handle}
|
||||||
shouldProxyLinks={true}
|
shouldProxyLinks={true}
|
||||||
/>
|
/>
|
||||||
) : undefined}
|
{limitLines && (
|
||||||
{limitLines ? (
|
<ShowMoreTextButton
|
||||||
<TextLink
|
style={[a.text_md]}
|
||||||
text={_(msg`Show More`)}
|
|
||||||
style={pal.link}
|
|
||||||
onPress={onPressShowMore}
|
onPress={onPressShowMore}
|
||||||
href="#"
|
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{post.embed && (
|
{post.embed && (
|
||||||
<View style={[a.pb_xs]}>
|
<View style={[a.pb_xs]}>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {memo, useMemo} from 'react'
|
import {memo, useCallback, useMemo, useState} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {
|
import {
|
||||||
type AppBskyFeedDefs,
|
type AppBskyFeedDefs,
|
||||||
@@ -6,12 +6,10 @@ import {
|
|||||||
AtUri,
|
AtUri,
|
||||||
RichText as RichTextAPI,
|
RichText as RichTextAPI,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
|
|
||||||
import {MAX_POST_LINES} from '#/lib/constants'
|
import {MAX_POST_LINES} from '#/lib/constants'
|
||||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
import {countLines} from '#/lib/strings/helpers'
|
import {countLines} from '#/lib/strings/helpers'
|
||||||
import {
|
import {
|
||||||
@@ -23,7 +21,6 @@ import {type ThreadItem} from '#/state/queries/usePostThread/types'
|
|||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {type OnPostSuccessData} from '#/state/shell/composer'
|
import {type OnPostSuccessData} from '#/state/shell/composer'
|
||||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||||
import {TextLink} from '#/view/com/util/Link'
|
|
||||||
import {PostMeta} from '#/view/com/util/PostMeta'
|
import {PostMeta} from '#/view/com/util/PostMeta'
|
||||||
import {
|
import {
|
||||||
OUTER_SPACE,
|
OUTER_SPACE,
|
||||||
@@ -39,6 +36,7 @@ import {PostAlerts} from '#/components/moderation/PostAlerts'
|
|||||||
import {PostHider} from '#/components/moderation/PostHider'
|
import {PostHider} from '#/components/moderation/PostHider'
|
||||||
import {type AppModerationCause} from '#/components/Pills'
|
import {type AppModerationCause} from '#/components/Pills'
|
||||||
import {Embed, PostEmbedViewContext} from '#/components/Post/Embed'
|
import {Embed, PostEmbedViewContext} from '#/components/Post/Embed'
|
||||||
|
import {ShowMoreTextButton} from '#/components/Post/ShowMoreTextButton'
|
||||||
import {PostControls} from '#/components/PostControls'
|
import {PostControls} from '#/components/PostControls'
|
||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
import * as Skele from '#/components/Skeleton'
|
import * as Skele from '#/components/Skeleton'
|
||||||
@@ -255,8 +253,6 @@ const ThreadItemTreePostInner = memo(function ThreadItemTreePostInner({
|
|||||||
onPostSuccess?: (data: OnPostSuccessData) => void
|
onPostSuccess?: (data: OnPostSuccessData) => void
|
||||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||||
}): React.ReactNode {
|
}): React.ReactNode {
|
||||||
const pal = usePalette('default')
|
|
||||||
const {_} = useLingui()
|
|
||||||
const {openComposer} = useOpenComposer()
|
const {openComposer} = useOpenComposer()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
|
|
||||||
@@ -271,18 +267,18 @@ const ThreadItemTreePostInner = memo(function ThreadItemTreePostInner({
|
|||||||
}),
|
}),
|
||||||
[record],
|
[record],
|
||||||
)
|
)
|
||||||
const [limitLines, setLimitLines] = React.useState(
|
const [limitLines, setLimitLines] = useState(
|
||||||
() => countLines(richText?.text) >= MAX_POST_LINES,
|
() => countLines(richText?.text) >= MAX_POST_LINES,
|
||||||
)
|
)
|
||||||
const threadRootUri = record.reply?.root?.uri || post.uri
|
const threadRootUri = record.reply?.root?.uri || post.uri
|
||||||
const postHref = React.useMemo(() => {
|
const postHref = useMemo(() => {
|
||||||
const urip = new AtUri(post.uri)
|
const urip = new AtUri(post.uri)
|
||||||
return makeProfileLink(post.author, 'post', urip.rkey)
|
return makeProfileLink(post.author, 'post', urip.rkey)
|
||||||
}, [post.uri, post.author])
|
}, [post.uri, post.author])
|
||||||
const threadgateHiddenReplies = useMergedThreadgateHiddenReplies({
|
const threadgateHiddenReplies = useMergedThreadgateHiddenReplies({
|
||||||
threadgateRecord,
|
threadgateRecord,
|
||||||
})
|
})
|
||||||
const additionalPostAlerts: AppModerationCause[] = React.useMemo(() => {
|
const additionalPostAlerts: AppModerationCause[] = useMemo(() => {
|
||||||
const isPostHiddenByThreadgate = threadgateHiddenReplies.has(post.uri)
|
const isPostHiddenByThreadgate = threadgateHiddenReplies.has(post.uri)
|
||||||
const isControlledByViewer =
|
const isControlledByViewer =
|
||||||
new AtUri(threadRootUri).host === currentAccount?.did
|
new AtUri(threadRootUri).host === currentAccount?.did
|
||||||
@@ -297,7 +293,7 @@ const ThreadItemTreePostInner = memo(function ThreadItemTreePostInner({
|
|||||||
: []
|
: []
|
||||||
}, [post, currentAccount?.did, threadgateHiddenReplies, threadRootUri])
|
}, [post, currentAccount?.did, threadgateHiddenReplies, threadRootUri])
|
||||||
|
|
||||||
const onPressReply = React.useCallback(() => {
|
const onPressReply = useCallback(() => {
|
||||||
openComposer({
|
openComposer({
|
||||||
replyTo: {
|
replyTo: {
|
||||||
uri: post.uri,
|
uri: post.uri,
|
||||||
@@ -311,7 +307,7 @@ const ThreadItemTreePostInner = memo(function ThreadItemTreePostInner({
|
|||||||
})
|
})
|
||||||
}, [openComposer, post, record, onPostSuccess, moderation])
|
}, [openComposer, post, record, onPostSuccess, moderation])
|
||||||
|
|
||||||
const onPressShowMore = React.useCallback(() => {
|
const onPressShowMore = useCallback(() => {
|
||||||
setLimitLines(false)
|
setLimitLines(false)
|
||||||
}, [setLimitLines])
|
}, [setLimitLines])
|
||||||
|
|
||||||
@@ -348,7 +344,7 @@ const ThreadItemTreePostInner = memo(function ThreadItemTreePostInner({
|
|||||||
additionalCauses={additionalPostAlerts}
|
additionalCauses={additionalPostAlerts}
|
||||||
/>
|
/>
|
||||||
{richText?.text ? (
|
{richText?.text ? (
|
||||||
<View>
|
<>
|
||||||
<RichText
|
<RichText
|
||||||
enableTags
|
enableTags
|
||||||
value={richText}
|
value={richText}
|
||||||
@@ -357,15 +353,13 @@ const ThreadItemTreePostInner = memo(function ThreadItemTreePostInner({
|
|||||||
authorHandle={post.author.handle}
|
authorHandle={post.author.handle}
|
||||||
shouldProxyLinks={true}
|
shouldProxyLinks={true}
|
||||||
/>
|
/>
|
||||||
</View>
|
{limitLines && (
|
||||||
) : undefined}
|
<ShowMoreTextButton
|
||||||
{limitLines ? (
|
style={[a.text_md]}
|
||||||
<TextLink
|
|
||||||
text={_(msg`Show More`)}
|
|
||||||
style={pal.link}
|
|
||||||
onPress={onPressShowMore}
|
onPress={onPressShowMore}
|
||||||
href="#"
|
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{post.embed && (
|
{post.embed && (
|
||||||
<View style={[a.pb_xs]}>
|
<View style={[a.pb_xs]}>
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import {View} from 'react-native'
|
|||||||
import {
|
import {
|
||||||
Gesture,
|
Gesture,
|
||||||
GestureDetector,
|
GestureDetector,
|
||||||
NativeGesture,
|
type NativeGesture,
|
||||||
} from 'react-native-gesture-handler'
|
} from 'react-native-gesture-handler'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
interpolate,
|
interpolate,
|
||||||
runOnJS,
|
runOnJS,
|
||||||
runOnUI,
|
runOnUI,
|
||||||
SharedValue,
|
type SharedValue,
|
||||||
useAnimatedReaction,
|
useAnimatedReaction,
|
||||||
useAnimatedStyle,
|
useAnimatedStyle,
|
||||||
useSharedValue,
|
useSharedValue,
|
||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
useSafeAreaInsets,
|
useSafeAreaInsets,
|
||||||
} from 'react-native-safe-area-context'
|
} from 'react-native-safe-area-context'
|
||||||
import {useEventListener} from 'expo'
|
import {useEventListener} from 'expo'
|
||||||
import {VideoPlayer} from 'expo-video'
|
import {type VideoPlayer} from 'expo-video'
|
||||||
|
|
||||||
import {tokens} from '#/alf'
|
import {tokens} from '#/alf'
|
||||||
import {atoms as a} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import {useLingui} from '@lingui/react'
|
|||||||
import {useNavigation} from '@react-navigation/native'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
|
import {MAX_POST_LINES} from '#/lib/constants'
|
||||||
import {useAnimatedValue} from '#/lib/hooks/useAnimatedValue'
|
import {useAnimatedValue} from '#/lib/hooks/useAnimatedValue'
|
||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
import {usePalette} from '#/lib/hooks/usePalette'
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
@@ -918,7 +919,8 @@ function AdditionalPostText({post}: {post?: AppBskyFeedDefs.PostView}) {
|
|||||||
{text?.length > 0 && (
|
{text?.length > 0 && (
|
||||||
<Text
|
<Text
|
||||||
emoji
|
emoji
|
||||||
style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}>
|
style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}
|
||||||
|
numberOfLines={MAX_POST_LINES}>
|
||||||
{text}
|
{text}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replie
|
|||||||
import {type PostSource} from '#/state/unstable-post-source'
|
import {type PostSource} from '#/state/unstable-post-source'
|
||||||
import {PostThreadFollowBtn} from '#/view/com/post-thread/PostThreadFollowBtn'
|
import {PostThreadFollowBtn} from '#/view/com/post-thread/PostThreadFollowBtn'
|
||||||
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
|
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 {formatCount} from '#/view/com/util/numeric/format'
|
||||||
import {PostMeta} from '#/view/com/util/PostMeta'
|
import {PostMeta} from '#/view/com/util/PostMeta'
|
||||||
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
|
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
|
||||||
@@ -62,6 +62,7 @@ import {PostAlerts} from '#/components/moderation/PostAlerts'
|
|||||||
import {PostHider} from '#/components/moderation/PostHider'
|
import {PostHider} from '#/components/moderation/PostHider'
|
||||||
import {type AppModerationCause} from '#/components/Pills'
|
import {type AppModerationCause} from '#/components/Pills'
|
||||||
import {Embed, PostEmbedViewContext} from '#/components/Post/Embed'
|
import {Embed, PostEmbedViewContext} from '#/components/Post/Embed'
|
||||||
|
import {ShowMoreTextButton} from '#/components/Post/ShowMoreTextButton'
|
||||||
import {PostControls} from '#/components/PostControls'
|
import {PostControls} from '#/components/PostControls'
|
||||||
import * as Prompt from '#/components/Prompt'
|
import * as Prompt from '#/components/Prompt'
|
||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
@@ -685,15 +686,13 @@ let PostThreadItemLoaded = ({
|
|||||||
authorHandle={post.author.handle}
|
authorHandle={post.author.handle}
|
||||||
shouldProxyLinks={true}
|
shouldProxyLinks={true}
|
||||||
/>
|
/>
|
||||||
</View>
|
{limitLines && (
|
||||||
) : undefined}
|
<ShowMoreTextButton
|
||||||
{limitLines ? (
|
style={[a.text_md]}
|
||||||
<TextLink
|
|
||||||
text={_(msg`Show More`)}
|
|
||||||
style={pal.link}
|
|
||||||
onPress={onPressShowMore}
|
onPress={onPressShowMore}
|
||||||
href="#"
|
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{post.embed && (
|
{post.embed && (
|
||||||
<View style={[a.pb_xs]}>
|
<View style={[a.pb_xs]}>
|
||||||
|
|||||||
+14
-23
@@ -1,4 +1,4 @@
|
|||||||
import React, {useMemo, useState} from 'react'
|
import {useCallback, useMemo, useState} from 'react'
|
||||||
import {type StyleProp, StyleSheet, View, type ViewStyle} from 'react-native'
|
import {type StyleProp, StyleSheet, View, type ViewStyle} from 'react-native'
|
||||||
import {
|
import {
|
||||||
type AppBskyFeedDefs,
|
type AppBskyFeedDefs,
|
||||||
@@ -9,8 +9,7 @@ import {
|
|||||||
RichText as RichTextAPI,
|
RichText as RichTextAPI,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {MAX_POST_LINES} from '#/lib/constants'
|
import {MAX_POST_LINES} from '#/lib/constants'
|
||||||
@@ -27,7 +26,7 @@ import {
|
|||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {precacheProfile} from '#/state/queries/profile'
|
import {precacheProfile} from '#/state/queries/profile'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {Link, TextLink} from '#/view/com/util/Link'
|
import {Link} from '#/view/com/util/Link'
|
||||||
import {PostMeta} from '#/view/com/util/PostMeta'
|
import {PostMeta} from '#/view/com/util/PostMeta'
|
||||||
import {Text} from '#/view/com/util/text/Text'
|
import {Text} from '#/view/com/util/text/Text'
|
||||||
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
|
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
|
||||||
@@ -37,6 +36,7 @@ import {ContentHider} from '#/components/moderation/ContentHider'
|
|||||||
import {LabelsOnMyPost} from '#/components/moderation/LabelsOnMe'
|
import {LabelsOnMyPost} from '#/components/moderation/LabelsOnMe'
|
||||||
import {PostAlerts} from '#/components/moderation/PostAlerts'
|
import {PostAlerts} from '#/components/moderation/PostAlerts'
|
||||||
import {Embed, PostEmbedViewContext} from '#/components/Post/Embed'
|
import {Embed, PostEmbedViewContext} from '#/components/Post/Embed'
|
||||||
|
import {ShowMoreTextButton} from '#/components/Post/ShowMoreTextButton'
|
||||||
import {PostControls} from '#/components/PostControls'
|
import {PostControls} from '#/components/PostControls'
|
||||||
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
@@ -115,7 +115,6 @@ function PostInner({
|
|||||||
}) {
|
}) {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {_} = useLingui()
|
|
||||||
const {openComposer} = useOpenComposer()
|
const {openComposer} = useOpenComposer()
|
||||||
const [limitLines, setLimitLines] = useState(
|
const [limitLines, setLimitLines] = useState(
|
||||||
() => countLines(richText?.text) >= MAX_POST_LINES,
|
() => countLines(richText?.text) >= MAX_POST_LINES,
|
||||||
@@ -128,7 +127,7 @@ function PostInner({
|
|||||||
replyAuthorDid = urip.hostname
|
replyAuthorDid = urip.hostname
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPressReply = React.useCallback(() => {
|
const onPressReply = useCallback(() => {
|
||||||
openComposer({
|
openComposer({
|
||||||
replyTo: {
|
replyTo: {
|
||||||
uri: post.uri,
|
uri: post.uri,
|
||||||
@@ -141,18 +140,18 @@ function PostInner({
|
|||||||
})
|
})
|
||||||
}, [openComposer, post, record, moderation])
|
}, [openComposer, post, record, moderation])
|
||||||
|
|
||||||
const onPressShowMore = React.useCallback(() => {
|
const onPressShowMore = useCallback(() => {
|
||||||
setLimitLines(false)
|
setLimitLines(false)
|
||||||
}, [setLimitLines])
|
}, [setLimitLines])
|
||||||
|
|
||||||
const onBeforePress = React.useCallback(() => {
|
const onBeforePress = useCallback(() => {
|
||||||
precacheProfile(queryClient, post.author)
|
precacheProfile(queryClient, post.author)
|
||||||
}, [queryClient, post.author])
|
}, [queryClient, post.author])
|
||||||
|
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const isMe = replyAuthorDid === currentAccount?.did
|
const isMe = replyAuthorDid === currentAccount?.did
|
||||||
|
|
||||||
const [hover, setHover] = React.useState(false)
|
const [hover, setHover] = useState(false)
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
href={itemHref}
|
href={itemHref}
|
||||||
@@ -227,7 +226,7 @@ function PostInner({
|
|||||||
style={[a.py_xs]}
|
style={[a.py_xs]}
|
||||||
/>
|
/>
|
||||||
{richText.text ? (
|
{richText.text ? (
|
||||||
<View style={styles.postTextContainer}>
|
<View>
|
||||||
<RichText
|
<RichText
|
||||||
enableTags
|
enableTags
|
||||||
testID="postText"
|
testID="postText"
|
||||||
@@ -237,15 +236,13 @@ function PostInner({
|
|||||||
authorHandle={post.author.handle}
|
authorHandle={post.author.handle}
|
||||||
shouldProxyLinks={true}
|
shouldProxyLinks={true}
|
||||||
/>
|
/>
|
||||||
</View>
|
{limitLines && (
|
||||||
) : undefined}
|
<ShowMoreTextButton
|
||||||
{limitLines ? (
|
style={[a.text_md]}
|
||||||
<TextLink
|
|
||||||
text={_(msg`Show More`)}
|
|
||||||
style={pal.link}
|
|
||||||
onPress={onPressShowMore}
|
onPress={onPressShowMore}
|
||||||
href="#"
|
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{post.embed ? (
|
{post.embed ? (
|
||||||
<Embed
|
<Embed
|
||||||
@@ -290,12 +287,6 @@ const styles = StyleSheet.create({
|
|||||||
alert: {
|
alert: {
|
||||||
marginBottom: 6,
|
marginBottom: 6,
|
||||||
},
|
},
|
||||||
postTextContainer: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
flexWrap: 'wrap',
|
|
||||||
overflow: 'hidden',
|
|
||||||
},
|
|
||||||
replyLine: {
|
replyLine: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: 36,
|
left: 36,
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import {
|
|||||||
setUnstablePostSource,
|
setUnstablePostSource,
|
||||||
} from '#/state/unstable-post-source'
|
} from '#/state/unstable-post-source'
|
||||||
import {FeedNameText} from '#/view/com/util/FeedInfoText'
|
import {FeedNameText} from '#/view/com/util/FeedInfoText'
|
||||||
import {Link, TextLink, TextLinkOnWebOnly} from '#/view/com/util/Link'
|
import {Link, TextLinkOnWebOnly} from '#/view/com/util/Link'
|
||||||
import {PostMeta} from '#/view/com/util/PostMeta'
|
import {PostMeta} from '#/view/com/util/PostMeta'
|
||||||
import {Text} from '#/view/com/util/text/Text'
|
import {Text} from '#/view/com/util/text/Text'
|
||||||
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
|
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
|
||||||
@@ -54,6 +54,7 @@ import {PostAlerts} from '#/components/moderation/PostAlerts'
|
|||||||
import {type AppModerationCause} from '#/components/Pills'
|
import {type AppModerationCause} from '#/components/Pills'
|
||||||
import {Embed} from '#/components/Post/Embed'
|
import {Embed} from '#/components/Post/Embed'
|
||||||
import {PostEmbedViewContext} from '#/components/Post/Embed/types'
|
import {PostEmbedViewContext} from '#/components/Post/Embed/types'
|
||||||
|
import {ShowMoreTextButton} from '#/components/Post/ShowMoreTextButton'
|
||||||
import {PostControls} from '#/components/PostControls'
|
import {PostControls} from '#/components/PostControls'
|
||||||
import {DiscoverDebug} from '#/components/PostControls/DiscoverDebug'
|
import {DiscoverDebug} from '#/components/PostControls/DiscoverDebug'
|
||||||
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
||||||
@@ -501,8 +502,6 @@ let PostContent = ({
|
|||||||
post: AppBskyFeedDefs.PostView
|
post: AppBskyFeedDefs.PostView
|
||||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const pal = usePalette('default')
|
|
||||||
const {_} = useLingui()
|
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const [limitLines, setLimitLines] = useState(
|
const [limitLines, setLimitLines] = useState(
|
||||||
() => countLines(richText.text) >= MAX_POST_LINES,
|
() => countLines(richText.text) >= MAX_POST_LINES,
|
||||||
@@ -547,7 +546,7 @@ let PostContent = ({
|
|||||||
additionalCauses={additionalPostAlerts}
|
additionalCauses={additionalPostAlerts}
|
||||||
/>
|
/>
|
||||||
{richText.text ? (
|
{richText.text ? (
|
||||||
<View style={styles.postTextContainer}>
|
<>
|
||||||
<RichText
|
<RichText
|
||||||
enableTags
|
enableTags
|
||||||
testID="postText"
|
testID="postText"
|
||||||
@@ -557,15 +556,10 @@ let PostContent = ({
|
|||||||
authorHandle={postAuthor.handle}
|
authorHandle={postAuthor.handle}
|
||||||
shouldProxyLinks={true}
|
shouldProxyLinks={true}
|
||||||
/>
|
/>
|
||||||
</View>
|
{limitLines && (
|
||||||
) : undefined}
|
<ShowMoreTextButton style={[a.text_md]} onPress={onPressShowMore} />
|
||||||
{limitLines ? (
|
)}
|
||||||
<TextLink
|
</>
|
||||||
text={_(msg`Show More`)}
|
|
||||||
style={pal.link}
|
|
||||||
onPress={onPressShowMore}
|
|
||||||
href="#"
|
|
||||||
/>
|
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{postEmbed ? (
|
{postEmbed ? (
|
||||||
<View style={[a.pb_xs]}>
|
<View style={[a.pb_xs]}>
|
||||||
@@ -689,13 +683,6 @@ const styles = StyleSheet.create({
|
|||||||
marginTop: 6,
|
marginTop: 6,
|
||||||
marginBottom: 6,
|
marginBottom: 6,
|
||||||
},
|
},
|
||||||
postTextContainer: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
flexWrap: 'wrap',
|
|
||||||
paddingBottom: 2,
|
|
||||||
overflow: 'hidden',
|
|
||||||
},
|
|
||||||
contentHiderChild: {
|
contentHiderChild: {
|
||||||
marginTop: 6,
|
marginTop: 6,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user