forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
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}