Bluesky app fork with some witchin' additions 馃挮
at main 98 lines 2.9 kB view raw
1import {useState} from 'react' 2import {View} from 'react-native' 3import {Image} from 'expo-image' 4import {Trans} from '@lingui/macro' 5 6import {type LinkMeta} from '#/lib/link-meta/link-meta' 7import {toNiceDomain} from '#/lib/strings/url-helpers' 8import {LoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 9import {atoms as a, useTheme} from '#/alf' 10import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe' 11import {Image_Stroke2_Corner0_Rounded as ImageIcon} from '#/components/icons/Image' 12import {Text} from '#/components/Typography' 13 14export function LinkPreview({ 15 linkMeta, 16 loading, 17}: { 18 linkMeta?: LinkMeta 19 loading: boolean 20}) { 21 const t = useTheme() 22 const [imageLoadError, setImageLoadError] = useState(false) 23 24 if (!linkMeta && !loading) { 25 return null 26 } 27 28 return ( 29 <View 30 style={[ 31 a.w_full, 32 a.border, 33 t.atoms.border_contrast_low, 34 t.atoms.bg, 35 a.flex_row, 36 a.rounded_sm, 37 a.overflow_hidden, 38 a.align_stretch, 39 ]}> 40 <View 41 style={[ 42 t.atoms.bg_contrast_25, 43 {minHeight: 64, width: 114}, 44 a.justify_center, 45 a.align_center, 46 a.gap_xs, 47 ]}> 48 {linkMeta?.image && ( 49 <Image 50 source={linkMeta.image} 51 accessibilityIgnoresInvertColors 52 transition={200} 53 style={[a.absolute, a.inset_0]} 54 contentFit="cover" 55 onLoad={() => setImageLoadError(false)} 56 onError={() => setImageLoadError(true)} 57 /> 58 )} 59 {linkMeta && (!linkMeta.image || imageLoadError) && ( 60 <> 61 <ImageIcon style={[t.atoms.text_contrast_low]} /> 62 <Text style={[t.atoms.text_contrast_low, a.text_xs, a.text_center]}> 63 <Trans>No image</Trans> 64 </Text> 65 </> 66 )} 67 </View> 68 <View style={[a.flex_1, a.justify_center, a.py_sm, a.gap_xs, a.px_md]}> 69 {linkMeta ? ( 70 <> 71 <Text 72 numberOfLines={2} 73 style={[a.leading_snug, a.font_semi_bold, a.text_md]}> 74 {linkMeta.title || linkMeta.url} 75 </Text> 76 <View style={[a.flex_row, a.align_center, a.gap_2xs]}> 77 <GlobeIcon size="xs" style={[t.atoms.text_contrast_low]} /> 78 <Text 79 numberOfLines={1} 80 style={[ 81 a.text_xs, 82 a.leading_snug, 83 t.atoms.text_contrast_medium, 84 ]}> 85 {toNiceDomain(linkMeta.url)} 86 </Text> 87 </View> 88 </> 89 ) : ( 90 <> 91 <LoadingPlaceholder height={16} width={128} /> 92 <LoadingPlaceholder height={12} width={72} /> 93 </> 94 )} 95 </View> 96 </View> 97 ) 98}