Handle errors, short posts
This commit is contained in:
@@ -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}
|
||||||
|
|||||||
@@ -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`)}
|
||||||
|
|||||||
Reference in New Issue
Block a user