diff options
author | Samuel Newman <mozzius@protonmail.com> | 2025-05-20 18:49:20 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-05-20 18:49:20 +0300 |
commit | a18b25d16c7ff4e5233cc6ca45511ba42b12f55f (patch) | |
tree | 6aca1c86eac4b69fdc1aecd3f081e7e5135c7ebb /src/components/live/LinkPreview.tsx | |
parent | c7101870944a34f874fd80b18c16e38e24d6b51b (diff) | |
download | voidsky-a18b25d16c7ff4e5233cc6ca45511ba42b12f55f.tar.zst |
[Live] Add warning if link is missing image (#8393)
Diffstat (limited to 'src/components/live/LinkPreview.tsx')
-rw-r--r-- | src/components/live/LinkPreview.tsx | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/src/components/live/LinkPreview.tsx b/src/components/live/LinkPreview.tsx new file mode 100644 index 000000000..98320a9e8 --- /dev/null +++ b/src/components/live/LinkPreview.tsx @@ -0,0 +1,98 @@ +import {useState} from 'react' +import {View} from 'react-native' +import {Image} from 'expo-image' +import {Trans} from '@lingui/macro' + +import {type LinkMeta} from '#/lib/link-meta/link-meta' +import {toNiceDomain} from '#/lib/strings/url-helpers' +import {LoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' +import {atoms as a, useTheme} from '#/alf' +import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe' +import {Image_Stroke2_Corner0_Rounded as ImageIcon} from '#/components/icons/Image' +import {Text} from '#/components/Typography' + +export function LinkPreview({ + linkMeta, + loading, +}: { + linkMeta?: LinkMeta + loading: boolean +}) { + const t = useTheme() + const [imageLoadError, setImageLoadError] = useState(false) + + if (!linkMeta && !loading) { + return null + } + + return ( + <View + style={[ + a.w_full, + a.border, + t.atoms.border_contrast_low, + t.atoms.bg, + a.flex_row, + a.rounded_sm, + a.overflow_hidden, + a.align_stretch, + ]}> + <View + style={[ + t.atoms.bg_contrast_25, + {minHeight: 64, width: 114}, + a.justify_center, + a.align_center, + a.gap_xs, + ]}> + {linkMeta?.image && ( + <Image + source={linkMeta.image} + accessibilityIgnoresInvertColors + transition={200} + style={[a.absolute, a.inset_0]} + contentFit="cover" + onLoad={() => setImageLoadError(false)} + onError={() => setImageLoadError(true)} + /> + )} + {linkMeta && (!linkMeta.image || imageLoadError) && ( + <> + <ImageIcon style={[t.atoms.text_contrast_low]} /> + <Text style={[t.atoms.text_contrast_low, a.text_xs, a.text_center]}> + <Trans>No image</Trans> + </Text> + </> + )} + </View> + <View style={[a.flex_1, a.justify_center, a.py_sm, a.gap_xs, a.px_md]}> + {linkMeta ? ( + <> + <Text + numberOfLines={2} + style={[a.leading_snug, a.font_bold, a.text_md]}> + {linkMeta.title || linkMeta.url} + </Text> + <View style={[a.flex_row, a.align_center, a.gap_2xs]}> + <GlobeIcon size="xs" style={[t.atoms.text_contrast_low]} /> + <Text + numberOfLines={1} + style={[ + a.text_xs, + a.leading_snug, + t.atoms.text_contrast_medium, + ]}> + {toNiceDomain(linkMeta.url)} + </Text> + </View> + </> + ) : ( + <> + <LoadingPlaceholder height={16} width={128} /> + <LoadingPlaceholder height={12} width={72} /> + </> + )} + </View> + </View> + ) +} |