Handle errors, short posts

This commit is contained in:
Eric Bailey
2024-10-31 12:04:45 -05:00
parent 265d0f2122
commit 644c747a95
2 changed files with 89 additions and 34 deletions
@@ -7,7 +7,10 @@ import {useLingui} from '@lingui/react'
import {parseAltFromGIFDescription} from '#/lib/gif-alt-text' import {parseAltFromGIFDescription} from '#/lib/gif-alt-text'
import {shareUrl} from '#/lib/sharing' import {shareUrl} from '#/lib/sharing'
import {parseEmbedPlayerFromUrl} from '#/lib/strings/embed-player' import {
EmbedPlayerParams,
parseEmbedPlayerFromUrl,
} from '#/lib/strings/embed-player'
import {toNiceDomain} from '#/lib/strings/url-helpers' import {toNiceDomain} from '#/lib/strings/url-helpers'
import {isNative} from '#/platform/detection' import {isNative} from '#/platform/detection'
import {useExternalEmbedsPrefs} from '#/state/preferences' import {useExternalEmbedsPrefs} from '#/state/preferences'
@@ -32,11 +35,7 @@ export const ExternalLinkEmbed = ({
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
hideAlt?: boolean hideAlt?: boolean
}) => { }) => {
const {_} = useLingui()
const t = useTheme()
const externalEmbedPrefs = useExternalEmbedsPrefs() const externalEmbedPrefs = useExternalEmbedsPrefs()
const niceUrl = toNiceDomain(link.uri)
const imageUri = link.thumb
const embedPlayerParams = React.useMemo(() => { const embedPlayerParams = React.useMemo(() => {
const params = parseEmbedPlayerFromUrl(link.uri) const params = parseEmbedPlayerFromUrl(link.uri)
@@ -44,13 +43,6 @@ export const ExternalLinkEmbed = ({
return params return params
} }
}, [link.uri, externalEmbedPrefs]) }, [link.uri, externalEmbedPrefs])
const hasMedia = Boolean(imageUri || embedPlayerParams)
const onShareExternal = useCallback(() => {
if (link.uri && isNative) {
shareUrl(link.uri)
}
}, [link.uri])
if (embedPlayerParams?.source === 'tenor') { if (embedPlayerParams?.source === 'tenor') {
const parsedAlt = parseAltFromGIFDescription(link.description) const parsedAlt = parseAltFromGIFDescription(link.description)
@@ -78,6 +70,38 @@ export const ExternalLinkEmbed = ({
) )
} }
return (
<ExternalLinkEmbedCard
link={link}
onOpen={onOpen}
embedPlayerParams={embedPlayerParams}
style={style}
/>
)
}
export function ExternalLinkEmbedCard({
link,
onOpen,
embedPlayerParams,
style,
}: {
link: AppBskyEmbedExternal.ViewExternal
onOpen?: () => void
embedPlayerParams?: EmbedPlayerParams
style?: StyleProp<ViewStyle>
}) {
const t = useTheme()
const {_} = useLingui()
const niceUrl = toNiceDomain(link.uri)
const hasMedia = Boolean(link.thumb || embedPlayerParams)
const onShareExternal = useCallback(() => {
if (link.uri && isNative) {
shareUrl(link.uri)
}
}, [link.uri])
return ( return (
<Link <Link
label={link.title || _(msg`Open link to ${niceUrl}`)} label={link.title || _(msg`Open link to ${niceUrl}`)}
@@ -98,12 +122,12 @@ export const ExternalLinkEmbed = ({
? t.atoms.border_contrast_high ? t.atoms.border_contrast_high
: t.atoms.border_contrast_low, : t.atoms.border_contrast_low,
]}> ]}>
{imageUri && !embedPlayerParams ? ( {link.thumb && !embedPlayerParams ? (
<Image <Image
style={{ style={{
aspectRatio: 1.91, aspectRatio: 1.91,
}} }}
source={{uri: imageUri}} source={{uri: link.thumb}}
accessibilityIgnoresInvertColors accessibilityIgnoresInvertColors
/> />
) : undefined} ) : undefined}
+51 -20
View File
@@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import {LayoutChangeEvent,ScrollView, View} from 'react-native' import {LayoutChangeEvent, ScrollView, View} from 'react-native'
import {LinearGradient} from 'expo-linear-gradient' import {LinearGradient} from 'expo-linear-gradient'
import {AppBskyEmbedExternal} from '@atproto/api' import {AppBskyEmbedExternal} from '@atproto/api'
import {msg} from '@lingui/macro' import {msg} from '@lingui/macro'
@@ -9,6 +9,7 @@ import {useQuery} from '@tanstack/react-query'
import {shareUrl} from '#/lib/sharing' import {shareUrl} from '#/lib/sharing'
import {toNiceDomain} from '#/lib/strings/url-helpers' import {toNiceDomain} from '#/lib/strings/url-helpers'
import {isNative} from '#/platform/detection' import {isNative} from '#/platform/detection'
import {ExternalLinkEmbedCard} from '#/view/com/util/post-embeds/ExternalLinkEmbed'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {Divider} from '#/components/Divider' import {Divider} from '#/components/Divider'
@@ -19,6 +20,8 @@ import {Link} from '#/components/Link'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
const MAX_HEIGHT = 400
export function GithubGist({ export function GithubGist({
info, info,
id, id,
@@ -28,10 +31,10 @@ export function GithubGist({
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {_} = useLingui()
const [footerHeight, setFooterHeight] = React.useState(100) const [footerHeight, setFooterHeight] = React.useState(97) // magic #
const [showMore, setShowMore] = React.useState(false) const [showMore, setShowMore] = React.useState<boolean | undefined>()
const {data: files, isLoading} = useQuery({ const {data: files, error} = useQuery({
queryKey: ['gist', id], queryKey: ['gist', id],
async queryFn() { async queryFn() {
const url = `https://api.github.com/gists/${id}` const url = `https://api.github.com/gists/${id}`
@@ -62,10 +65,25 @@ export function GithubGist({
[setFooterHeight], [setFooterHeight],
) )
const onCodeLayout = React.useCallback(
(e: LayoutChangeEvent) => {
if (e.nativeEvent.layout.height < 400) {
setShowMore(true)
} else {
setShowMore(false)
}
},
[setShowMore],
)
const onShowMore = React.useCallback(() => { const onShowMore = React.useCallback(() => {
setShowMore(true) setShowMore(true)
}, [setShowMore]) }, [setShowMore])
if (error) {
return <ExternalLinkEmbedCard link={info} />
}
return ( return (
<View <View
style={[ style={[
@@ -78,16 +96,29 @@ export function GithubGist({
t.atoms.border_contrast_low, t.atoms.border_contrast_low,
]}> ]}>
<View style={[t.atoms.bg_contrast_25]}> <View style={[t.atoms.bg_contrast_25]}>
{isLoading || !files ? ( {error ? null : !files ? ( // handled above
<View style={[a.px_lg]}> <View style={[a.p_lg]}>
<Loader /> <Loader />
</View> </View>
) : ( ) : (
<View style={[a.relative]}> <View style={[a.relative]}>
<View style={[a.relative]}> <View style={[a.relative]}>
<ScrollView <ScrollView
style={[a.pt_lg, {maxHeight: showMore ? undefined : 500}]}> style={[
<ScrollView horizontal style={[{paddingBottom: footerHeight}]}> a.pt_lg,
{
maxHeight:
showMore === undefined
? MAX_HEIGHT
: showMore
? undefined
: MAX_HEIGHT,
},
]}>
<ScrollView
horizontal
style={[{paddingBottom: footerHeight}]}
onLayout={onCodeLayout}>
<View> <View>
<View <View
style={[ style={[
@@ -127,14 +158,14 @@ export function GithubGist({
</ScrollView> </ScrollView>
</ScrollView> </ScrollView>
{!showMore && <View style={[a.absolute, a.inset_0]} />} {showMore === false && <View style={[a.absolute, a.inset_0]} />}
</View> </View>
<View <View
style={[a.absolute, a.inset_0, a.p_lg, {top: 'auto'}]} style={[a.absolute, a.inset_0, a.p_lg, {top: 'auto'}]}
onLayout={onFooterLayout}> onLayout={onFooterLayout}>
{!showMore && ( <View style={[a.absolute, a.inset_0]}>
<View style={[a.absolute, a.inset_0]}> {showMore === false && (
<View <View
style={[ style={[
a.absolute, a.absolute,
@@ -163,15 +194,15 @@ export function GithubGist({
<ButtonIcon icon={Chevron} size="sm" position="right" /> <ButtonIcon icon={Chevron} size="sm" position="right" />
</Button> </Button>
</View> </View>
<LinearGradient )}
colors={['rgba(0,0,0,0)', 'rgba(0,0,0,0.5)']} <LinearGradient
locations={[0, 1]} colors={['rgba(0,0,0,0)', 'rgba(0,0,0,0.5)']}
start={{x: 0, y: 0}} locations={[0, 1]}
end={{x: 0, y: 1}} start={{x: 0, y: 0}}
style={[a.absolute, a.inset_0]} end={{x: 0, y: 1}}
/> style={[a.absolute, a.inset_0]}
</View> />
)} </View>
<Link <Link
label={info.title || _(msg`Open this Gist`)} label={info.title || _(msg`Open this Gist`)}