Add live event feed card to Explore
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
import {View} from 'react-native'
|
||||
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {LiveEventFeedCardWide} from '#/features/liveEvents/components/LiveEventFeedCardWide'
|
||||
import {useLiveEvents} from '#/features/liveEvents/context'
|
||||
|
||||
export function ExploreScreenLiveEventFeedsBanner() {
|
||||
const t = useTheme()
|
||||
const events = useLiveEvents()
|
||||
const feed = events.feeds.at(0)
|
||||
if (!feed) return null
|
||||
return (
|
||||
<View style={[a.p_lg, a.border_b, t.atoms.border_contrast_low]}>
|
||||
<LiveEventFeedCardWide feed={feed} />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
import {useMemo} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {Image} from 'expo-image'
|
||||
import {LinearGradient} from 'expo-linear-gradient'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {isBskyCustomFeedUrl} from '#/lib/strings/url-helpers'
|
||||
import {atoms as a, useBreakpoints, utils} from '#/alf'
|
||||
import {Link} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {type LiveEventFeed} from '#/features/liveEvents/types'
|
||||
|
||||
const roundedStyles = [a.rounded_lg, a.curve_continuous]
|
||||
|
||||
export function LiveEventFeedCardWide({feed}: {feed: LiveEventFeed}) {
|
||||
const {_} = useLingui()
|
||||
const {gtPhone} = useBreakpoints()
|
||||
|
||||
const image = feed.images.wide
|
||||
const url = useMemo(() => {
|
||||
// Validated in multiple places on the backend
|
||||
if (isBskyCustomFeedUrl(feed.url)) {
|
||||
return new URL(feed.url).pathname
|
||||
}
|
||||
return '/'
|
||||
}, [feed.url])
|
||||
|
||||
return (
|
||||
<Link
|
||||
to={url}
|
||||
label={_(msg`Live event happening now: ${feed.title}`)}
|
||||
style={[a.w_full]}>
|
||||
{({hovered, pressed}) => (
|
||||
<View style={[roundedStyles, a.shadow_md, a.w_full]}>
|
||||
<View
|
||||
style={[
|
||||
a.align_start,
|
||||
roundedStyles,
|
||||
a.overflow_hidden,
|
||||
{
|
||||
aspectRatio: gtPhone ? 576 / 144 : 369 / 100,
|
||||
},
|
||||
]}>
|
||||
<Image
|
||||
accessibilityIgnoresInvertColors
|
||||
source={{
|
||||
uri: image.url,
|
||||
blurhash: image.blurhash,
|
||||
}}
|
||||
style={[a.absolute, a.inset_0]}
|
||||
contentFit="cover"
|
||||
/>
|
||||
|
||||
<LinearGradient
|
||||
colors={[image.overlayColor, utils.alpha(image.overlayColor, 0)]}
|
||||
locations={[0, 1]}
|
||||
start={{x: 0, y: 0}}
|
||||
end={{x: 1, y: 0}}
|
||||
style={[
|
||||
a.absolute,
|
||||
a.inset_0,
|
||||
a.transition_opacity,
|
||||
{
|
||||
transitionDuration: '200ms',
|
||||
opacity: hovered || pressed ? 0.6 : 0,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<View style={[a.flex_1, a.justify_end]}>
|
||||
<LinearGradient
|
||||
colors={[
|
||||
image.overlayColor,
|
||||
utils.alpha(image.overlayColor, 0),
|
||||
]}
|
||||
locations={[0, 1]}
|
||||
start={{x: 0, y: 0}}
|
||||
end={{x: 1, y: 0}}
|
||||
style={[a.absolute, a.inset_0]}
|
||||
/>
|
||||
|
||||
<View
|
||||
style={[
|
||||
a.z_10,
|
||||
gtPhone ? [a.pl_xl, a.pb_lg] : [a.pl_lg, a.pb_md],
|
||||
{paddingRight: 64},
|
||||
]}>
|
||||
<Text
|
||||
style={[
|
||||
a.leading_snug,
|
||||
gtPhone ? a.text_xs : a.text_2xs,
|
||||
{color: 'white', opacity: 0.8},
|
||||
]}>
|
||||
<Trans>Happening now</Trans>
|
||||
</Text>
|
||||
<Text
|
||||
style={[
|
||||
a.leading_snug,
|
||||
a.font_bold,
|
||||
gtPhone ? a.text_3xl : a.text_lg,
|
||||
{color: 'white'},
|
||||
]}>
|
||||
{feed.title}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
@@ -68,6 +68,7 @@ import {Loader} from '#/components/Loader'
|
||||
import * as ProfileCard from '#/components/ProfileCard'
|
||||
import {SubtleHover} from '#/components/SubtleHover'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {ExploreScreenLiveEventFeedsBanner} from '#/features/liveEvents/components/ExploreScreenLiveEventFeedsBanner'
|
||||
import * as ModuleHeader from './components/ModuleHeader'
|
||||
import {
|
||||
SuggestedAccountsTabBar,
|
||||
@@ -201,6 +202,10 @@ type ExploreScreenItems =
|
||||
type: 'interests-card'
|
||||
key: 'interests-card'
|
||||
}
|
||||
| {
|
||||
type: 'liveEventFeedsBanner'
|
||||
key: string
|
||||
}
|
||||
|
||||
export function Explore({
|
||||
focusSearchInput,
|
||||
@@ -684,6 +689,8 @@ export function Explore({
|
||||
i.push(topBorder)
|
||||
i.push(...interestsNuxModule)
|
||||
|
||||
i.push({type: 'liveEventFeedsBanner', key: 'liveEventFeedsBanner'})
|
||||
|
||||
if (useFullExperience) {
|
||||
i.push(trendingTopicsModule)
|
||||
i.push(...suggestedFeedsModule)
|
||||
@@ -998,6 +1005,9 @@ export function Explore({
|
||||
case 'interests-card': {
|
||||
return <ExploreInterestsCard />
|
||||
}
|
||||
case 'liveEventFeedsBanner': {
|
||||
return <ExploreScreenLiveEventFeedsBanner />
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user