forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {useEffect, useMemo} from 'react'
2import {View} from 'react-native'
3import {Image} from 'expo-image'
4import {LinearGradient} from 'expo-linear-gradient'
5import {msg} from '@lingui/macro'
6import {useLingui} from '@lingui/react'
7
8import {isBskyCustomFeedUrl} from '#/lib/strings/url-helpers'
9import {atoms as a, utils} from '#/alf'
10import {Live_Stroke2_Corner0_Rounded as LiveIcon} from '#/components/icons/Live'
11import {Link} from '#/components/Link'
12import {Text} from '#/components/Typography'
13import {useAnalytics} from '#/analytics'
14import {
15 type LiveEventFeed,
16 type LiveEventFeedMetricContext,
17} from '#/features/liveEvents/types'
18
19const roundedStyles = [a.rounded_md, a.curve_continuous]
20
21export function LiveEventFeedCardCompact({
22 feed,
23 metricContext,
24}: {
25 feed: LiveEventFeed
26 metricContext: LiveEventFeedMetricContext
27}) {
28 const {_} = useLingui()
29 const ax = useAnalytics()
30
31 const layout = feed.layouts.compact
32 const overlayColor = layout.overlayColor
33 const textColor = layout.textColor
34 const url = useMemo(() => {
35 // Validated in multiple places on the backend
36 if (isBskyCustomFeedUrl(feed.url)) {
37 return new URL(feed.url).pathname
38 }
39 return '/'
40 }, [feed.url])
41
42 useEffect(() => {
43 ax.metric('liveEvents:feedBanner:seen', {
44 feed: feed.url,
45 context: metricContext,
46 })
47 // eslint-disable-next-line react-hooks/exhaustive-deps
48 }, [])
49
50 return (
51 <Link
52 to={url}
53 label={_(msg`Live event happening now: ${feed.title}`)}
54 style={[a.w_full]}
55 onPress={() => {
56 ax.metric('liveEvents:feedBanner:click', {
57 feed: feed.url,
58 context: metricContext,
59 })
60 }}>
61 {({hovered, pressed}) => (
62 <View style={[roundedStyles, a.shadow_md, a.w_full]}>
63 <View
64 style={[a.w_full, a.align_start, a.overflow_hidden, roundedStyles]}>
65 <Image
66 accessibilityIgnoresInvertColors
67 source={{uri: layout.image}}
68 placeholder={{blurhash: layout.blurhash}}
69 style={[a.absolute, a.inset_0, a.w_full, a.h_full]}
70 contentFit="cover"
71 placeholderContentFit="cover"
72 />
73
74 <LinearGradient
75 colors={[overlayColor, utils.alpha(overlayColor, 0)]}
76 locations={[0, 1]}
77 start={{x: 0, y: 0}}
78 end={{x: 1, y: 0}}
79 style={[
80 a.absolute,
81 a.inset_0,
82 a.transition_opacity,
83 {
84 transitionDuration: '200ms',
85 opacity: hovered || pressed ? 0.6 : 0,
86 },
87 ]}
88 />
89
90 <View style={[a.w_full, a.justify_end]}>
91 <LinearGradient
92 colors={[
93 overlayColor,
94 utils.alpha(overlayColor, 0.7),
95 utils.alpha(overlayColor, 0),
96 ]}
97 locations={[0, 0.8, 1]}
98 start={{x: 0, y: 0}}
99 end={{x: 1, y: 0}}
100 style={[a.absolute, a.inset_0]}
101 />
102
103 <View
104 style={[
105 a.flex_1,
106 a.flex_row,
107 a.align_center,
108 a.gap_xs,
109 a.z_10,
110 a.px_lg,
111 a.py_md,
112 ]}>
113 <LiveIcon size="md" fill={textColor} />
114 <Text
115 numberOfLines={1}
116 style={[
117 a.flex_1,
118 a.leading_snug,
119 a.font_bold,
120 a.text_lg,
121 a.pr_xl,
122 {color: textColor},
123 ]}>
124 {layout.title}
125 </Text>
126 </View>
127 </View>
128 </View>
129 </View>
130 )}
131 </Link>
132 )
133}