[Explore] Small fixes (#8145)
* Hover on sugg account * Add subtle hover to all components except feed * Use skeleton states for refetch on focus * Empty results state for sugg users * Filter out pinned posts from feed previews * Add trending header if not top module * Tighten up spacing * Fetch 10 profiles * Update interests copy * Remove refetch on focus * Add PTR * use a map * Update src/screens/Search/modules/ExploreInterestsCard.tsx * fix web double border --------- Co-authored-by: Hailey <me@haileyok.com>
This commit is contained in:
+109
-38
@@ -7,6 +7,7 @@ import {
|
||||
} from '@atproto/api'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
|
||||
import {useGate} from '#/lib/statsig/statsig'
|
||||
@@ -22,9 +23,19 @@ import {
|
||||
import {useGetPopularFeedsQuery} from '#/state/queries/feed'
|
||||
import {Nux, useNux} from '#/state/queries/nuxs'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {useGetSuggestedFeedsQuery} from '#/state/queries/trending/useGetSuggestedFeedsQuery'
|
||||
import {useGetSuggestedUsersQuery} from '#/state/queries/trending/useGetSuggestedUsersQuery'
|
||||
import {useSuggestedStarterPacksQuery} from '#/state/queries/useSuggestedStarterPacksQuery'
|
||||
import {
|
||||
createGetSuggestedFeedsQueryKey,
|
||||
useGetSuggestedFeedsQuery,
|
||||
} from '#/state/queries/trending/useGetSuggestedFeedsQuery'
|
||||
import {
|
||||
getSuggestedUsersQueryKeyRoot,
|
||||
useGetSuggestedUsersQuery,
|
||||
} from '#/state/queries/trending/useGetSuggestedUsersQuery'
|
||||
import {createGetTrendsQueryKey} from '#/state/queries/trending/useGetTrendsQuery'
|
||||
import {
|
||||
createSuggestedStarterPacksQueryKey,
|
||||
useSuggestedStarterPacksQuery,
|
||||
} from '#/state/queries/useSuggestedStarterPacksQuery'
|
||||
import {useProgressGuide} from '#/state/shell/progress-guide'
|
||||
import {isThreadChildAt, isThreadParentAt} from '#/view/com/posts/PostFeed'
|
||||
import {PostFeedItem} from '#/view/com/posts/PostFeedItem'
|
||||
@@ -41,6 +52,7 @@ import {ExploreRecommendations} from '#/screens/Search/modules/ExploreRecommenda
|
||||
import {ExploreTrendingTopics} from '#/screens/Search/modules/ExploreTrendingTopics'
|
||||
import {ExploreTrendingVideos} from '#/screens/Search/modules/ExploreTrendingVideos'
|
||||
import {atoms as a, native, platform, useTheme, web} from '#/alf'
|
||||
import {Admonition} from '#/components/Admonition'
|
||||
import {Button} from '#/components/Button'
|
||||
import * as FeedCard from '#/components/FeedCard'
|
||||
import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDownIcon} from '#/components/icons/Chevron'
|
||||
@@ -49,9 +61,11 @@ import {type Props as IcoProps} from '#/components/icons/common'
|
||||
import {type Props as SVGIconProps} from '#/components/icons/common'
|
||||
import {ListSparkle_Stroke2_Corner0_Rounded as ListSparkle} from '#/components/icons/ListSparkle'
|
||||
import {StarterPack} from '#/components/icons/StarterPack'
|
||||
import {Trending2_Stroke2_Corner2_Rounded as Graph} from '#/components/icons/Trending'
|
||||
import {UserCircle_Stroke2_Corner0_Rounded as Person} from '#/components/icons/UserCircle'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import * as ProfileCard from '#/components/ProfileCard'
|
||||
import {SubtleHover} from '#/components/SubtleHover'
|
||||
import {Text} from '#/components/Typography'
|
||||
import * as ModuleHeader from './components/ModuleHeader'
|
||||
import {
|
||||
@@ -69,33 +83,26 @@ function LoadMore({item}: {item: ExploreScreenItems & {type: 'loadMore'}}) {
|
||||
onPress={item.onLoadMore}
|
||||
style={[a.relative, a.w_full]}>
|
||||
{({hovered, pressed}) => (
|
||||
<View
|
||||
style={[
|
||||
a.flex_1,
|
||||
a.flex_row,
|
||||
a.align_center,
|
||||
a.justify_center,
|
||||
a.px_lg,
|
||||
a.py_md,
|
||||
a.gap_sm,
|
||||
(hovered || pressed) && t.atoms.bg_contrast_25,
|
||||
]}>
|
||||
<Text
|
||||
<>
|
||||
<SubtleHover hover={hovered || pressed} />
|
||||
<View
|
||||
style={[
|
||||
a.leading_snug,
|
||||
hovered ? t.atoms.text : t.atoms.text_contrast_medium,
|
||||
a.flex_1,
|
||||
a.flex_row,
|
||||
a.align_center,
|
||||
a.justify_center,
|
||||
a.px_lg,
|
||||
a.py_md,
|
||||
a.gap_sm,
|
||||
]}>
|
||||
{item.message}
|
||||
</Text>
|
||||
{item.isLoadingMore ? (
|
||||
<Loader size="sm" />
|
||||
) : (
|
||||
<ChevronDownIcon
|
||||
size="sm"
|
||||
style={hovered ? t.atoms.text : t.atoms.text_contrast_medium}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<Text style={[a.leading_snug]}>{item.message}</Text>
|
||||
{item.isLoadingMore ? (
|
||||
<Loader size="sm" />
|
||||
) : (
|
||||
<ChevronDownIcon size="sm" style={t.atoms.text_contrast_medium} />
|
||||
)}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
)
|
||||
@@ -112,6 +119,7 @@ type ExploreScreenItems =
|
||||
title: string
|
||||
icon: React.ComponentType<SVGIconProps>
|
||||
iconSize?: IcoProps['size']
|
||||
bottomBorder?: boolean
|
||||
searchButton?: {
|
||||
label: string
|
||||
metricsTag: MetricEvents['explore:module:searchButtonPress']['module']
|
||||
@@ -147,6 +155,10 @@ type ExploreScreenItems =
|
||||
profile: AppBskyActorDefs.ProfileViewBasic
|
||||
recId?: number
|
||||
}
|
||||
| {
|
||||
type: 'profileEmpty'
|
||||
key: 'profileEmpty'
|
||||
}
|
||||
| {
|
||||
type: 'feed'
|
||||
key: string
|
||||
@@ -203,11 +215,12 @@ export function Explore({
|
||||
const gate = useGate()
|
||||
const guide = useProgressGuide('follow-10')
|
||||
const [selectedInterest, setSelectedInterest] = useState<string | null>(null)
|
||||
// TODO always get at least 10 back
|
||||
// TODO always get at least 10 back TODO still
|
||||
const {
|
||||
data: suggestedUsers,
|
||||
isLoading: suggestedUsersIsLoading,
|
||||
error: suggestedUsersError,
|
||||
isRefetching: suggestedUsersIsRefetching,
|
||||
} = useGetSuggestedUsersQuery({
|
||||
category: selectedInterest,
|
||||
})
|
||||
@@ -227,6 +240,7 @@ export function Explore({
|
||||
data: suggestedSPs,
|
||||
isLoading: isLoadingSuggestedSPs,
|
||||
error: suggestedSPsError,
|
||||
isRefetching: isRefetchingSuggestedSPs,
|
||||
} = useSuggestedStarterPacksQuery()
|
||||
|
||||
const isLoadingMoreFeeds = isFetchingNextFeedsPage && !isLoadingFeeds
|
||||
@@ -262,6 +276,27 @@ export function Explore({
|
||||
},
|
||||
} = useFeedPreviews(suggestedFeeds?.feeds ?? [])
|
||||
|
||||
const qc = useQueryClient()
|
||||
const [isPTR, setIsPTR] = useState(false)
|
||||
const onPTR = useCallback(async () => {
|
||||
setIsPTR(true)
|
||||
await Promise.all([
|
||||
await qc.resetQueries({
|
||||
queryKey: createGetTrendsQueryKey(),
|
||||
}),
|
||||
await qc.resetQueries({
|
||||
queryKey: createSuggestedStarterPacksQueryKey(),
|
||||
}),
|
||||
await qc.resetQueries({
|
||||
queryKey: [getSuggestedUsersQueryKeyRoot],
|
||||
}),
|
||||
await qc.resetQueries({
|
||||
queryKey: createGetSuggestedFeedsQueryKey(),
|
||||
}),
|
||||
])
|
||||
setIsPTR(false)
|
||||
}, [qc, setIsPTR])
|
||||
|
||||
const onLoadMoreFeedPreviews = useCallback(async () => {
|
||||
if (
|
||||
isPendingFeedPreviews ||
|
||||
@@ -305,7 +340,7 @@ export function Explore({
|
||||
},
|
||||
})
|
||||
|
||||
if (suggestedUsersIsLoading) {
|
||||
if (suggestedUsersIsLoading || suggestedUsersIsRefetching) {
|
||||
i.push({type: 'profilePlaceholder', key: 'profilePlaceholder'})
|
||||
} else if (suggestedUsersError) {
|
||||
i.push({
|
||||
@@ -333,14 +368,18 @@ export function Explore({
|
||||
}
|
||||
|
||||
if (profileItems.length === 0) {
|
||||
// no items! remove the header
|
||||
i.pop()
|
||||
i.push({
|
||||
type: 'profileEmpty',
|
||||
key: 'profileEmpty',
|
||||
})
|
||||
} else {
|
||||
i.push(...profileItems)
|
||||
}
|
||||
} else {
|
||||
// no items! remove the header
|
||||
i.pop()
|
||||
i.push({
|
||||
type: 'profileEmpty',
|
||||
key: 'profileEmpty',
|
||||
})
|
||||
}
|
||||
} else {
|
||||
i.push({type: 'profilePlaceholder', key: 'profilePlaceholder'})
|
||||
@@ -352,6 +391,7 @@ export function Explore({
|
||||
moderationOpts,
|
||||
suggestedUsers,
|
||||
suggestedUsersIsLoading,
|
||||
suggestedUsersIsRefetching,
|
||||
suggestedUsersError,
|
||||
])
|
||||
const suggestedFeedsModule = useMemo(() => {
|
||||
@@ -466,7 +506,7 @@ export function Explore({
|
||||
iconSize: 'xl',
|
||||
})
|
||||
|
||||
if (isLoadingSuggestedSPs) {
|
||||
if (isLoadingSuggestedSPs || isRefetchingSuggestedSPs) {
|
||||
Array.from({length: 3}).forEach((__, index) =>
|
||||
i.push({
|
||||
type: 'starterPackSkeleton',
|
||||
@@ -486,7 +526,13 @@ export function Explore({
|
||||
})
|
||||
}
|
||||
return i
|
||||
}, [suggestedSPs, _, isLoadingSuggestedSPs, suggestedSPsError])
|
||||
}, [
|
||||
suggestedSPs,
|
||||
_,
|
||||
isLoadingSuggestedSPs,
|
||||
suggestedSPsError,
|
||||
isRefetchingSuggestedSPs,
|
||||
])
|
||||
const feedPreviewsModule = useMemo(() => {
|
||||
const i: ExploreScreenItems[] = []
|
||||
i.push(...feedPreviewSlices)
|
||||
@@ -520,6 +566,13 @@ export function Explore({
|
||||
if (isNewUser) {
|
||||
i.push(...suggestedFollowsModule)
|
||||
i.push(...suggestedStarterPacksModule)
|
||||
i.push({
|
||||
type: 'header',
|
||||
key: 'trending-topics-header',
|
||||
title: _(msg`Trending topics`),
|
||||
icon: Graph,
|
||||
bottomBorder: true,
|
||||
})
|
||||
i.push(trendingTopicsModule)
|
||||
} else {
|
||||
i.push(trendingTopicsModule)
|
||||
@@ -533,6 +586,7 @@ export function Explore({
|
||||
|
||||
return i
|
||||
}, [
|
||||
_,
|
||||
topBorder,
|
||||
isNewUser,
|
||||
suggestedFollowsModule,
|
||||
@@ -564,7 +618,7 @@ export function Explore({
|
||||
)
|
||||
case 'header': {
|
||||
return (
|
||||
<ModuleHeader.Container>
|
||||
<ModuleHeader.Container bottomBorder={item.bottomBorder}>
|
||||
<ModuleHeader.Icon icon={item.icon} size={item.iconSize} />
|
||||
<ModuleHeader.TitleText>{item.title}</ModuleHeader.TitleText>
|
||||
{item.searchButton && (
|
||||
@@ -623,6 +677,15 @@ export function Explore({
|
||||
/>
|
||||
)
|
||||
}
|
||||
case 'profileEmpty': {
|
||||
return (
|
||||
<View style={[a.px_lg, a.pb_lg]}>
|
||||
<Admonition>
|
||||
<Trans>No results for "{selectedInterest}".</Trans>
|
||||
</Admonition>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
case 'feed': {
|
||||
return (
|
||||
<View
|
||||
@@ -738,7 +801,13 @@ export function Explore({
|
||||
return (
|
||||
<ModuleHeader.Container
|
||||
headerHeight={headerHeight}
|
||||
style={[a.pt_xs, a.border_b, t.atoms.border_contrast_low]}>
|
||||
style={[
|
||||
a.pt_xs,
|
||||
t.atoms.border_contrast_low,
|
||||
native(a.border_b),
|
||||
]}>
|
||||
{/* Very non-scientific way to avoid small gap on scroll */}
|
||||
<View style={[a.absolute, a.inset_0, t.atoms.bg, {top: -2}]} />
|
||||
<ModuleHeader.FeedLink feed={item.feed}>
|
||||
<ModuleHeader.FeedAvatar feed={item.feed} />
|
||||
<View style={[a.flex_1, a.gap_xs]}>
|
||||
@@ -876,6 +945,8 @@ export function Explore({
|
||||
windowSize={9}
|
||||
maxToRenderPerBatch={platform({ios: 5, default: 1})}
|
||||
updateCellsBatchingPeriod={40}
|
||||
refreshing={isPTR}
|
||||
onRefresh={onPTR}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,12 @@ export function Container({
|
||||
style,
|
||||
children,
|
||||
headerHeight,
|
||||
}: {children: React.ReactNode; headerHeight?: number} & ViewStyleProp) {
|
||||
bottomBorder,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
headerHeight?: number
|
||||
bottomBorder?: boolean
|
||||
} & ViewStyleProp) {
|
||||
const t = useTheme()
|
||||
return (
|
||||
<View
|
||||
@@ -31,10 +36,9 @@ export function Container({
|
||||
a.gap_sm,
|
||||
t.atoms.bg,
|
||||
headerHeight && web({position: 'sticky', top: headerHeight}),
|
||||
bottomBorder && [a.border_b, t.atoms.border_contrast_low],
|
||||
style,
|
||||
]}>
|
||||
{/* Very non-scientific way to avoid small gap on scroll */}
|
||||
<View style={[a.absolute, a.inset_0, t.atoms.bg, {top: -2}]} />
|
||||
{children}
|
||||
</View>
|
||||
)
|
||||
|
||||
@@ -19,6 +19,7 @@ import {PlusSmall_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus
|
||||
import {Link} from '#/components/Link'
|
||||
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
||||
import {useStarterPackLink} from '#/components/StarterPack/StarterPackCard'
|
||||
import {SubtleHover} from '#/components/SubtleHover'
|
||||
import {Text} from '#/components/Typography'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
@@ -48,75 +49,80 @@ export function StarterPackCard({
|
||||
.map(item => item.subject)
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
a.w_full,
|
||||
a.p_lg,
|
||||
a.gap_md,
|
||||
a.border,
|
||||
a.rounded_sm,
|
||||
a.overflow_hidden,
|
||||
t.atoms.border_contrast_low,
|
||||
]}>
|
||||
<View aria-hidden style={[a.absolute, a.inset_0, a.z_40]}>
|
||||
<Link
|
||||
to={link.to}
|
||||
label={link.label}
|
||||
style={[a.absolute, a.inset_0]}
|
||||
onHoverIn={link.precache}
|
||||
onPress={link.precache}>
|
||||
<View />
|
||||
</Link>
|
||||
</View>
|
||||
<Link
|
||||
to={link.to}
|
||||
label={link.label}
|
||||
onHoverIn={link.precache}
|
||||
onPress={link.precache}>
|
||||
{s => (
|
||||
<>
|
||||
<SubtleHover hover={s.hovered || s.pressed} />
|
||||
|
||||
<AvatarStack
|
||||
profiles={profiles ?? []}
|
||||
numPending={profileCount}
|
||||
total={view.list?.listItemCount}
|
||||
/>
|
||||
<View
|
||||
style={[
|
||||
a.w_full,
|
||||
a.p_lg,
|
||||
a.gap_md,
|
||||
a.border,
|
||||
a.rounded_sm,
|
||||
a.overflow_hidden,
|
||||
t.atoms.border_contrast_low,
|
||||
]}>
|
||||
<AvatarStack
|
||||
profiles={profiles ?? []}
|
||||
numPending={profileCount}
|
||||
total={view.list?.listItemCount}
|
||||
/>
|
||||
|
||||
<View
|
||||
style={[
|
||||
a.w_full,
|
||||
a.flex_row,
|
||||
a.align_start,
|
||||
a.gap_lg,
|
||||
web({
|
||||
position: 'static',
|
||||
zIndex: 'unset',
|
||||
}),
|
||||
]}>
|
||||
<View style={[a.flex_1]}>
|
||||
<Text
|
||||
emoji
|
||||
style={[a.text_md, a.font_bold, a.leading_snug]}
|
||||
numberOfLines={1}>
|
||||
{view.record.name}
|
||||
</Text>
|
||||
<Text
|
||||
emoji
|
||||
style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}
|
||||
numberOfLines={1}>
|
||||
{view.creator?.did === currentAccount?.did
|
||||
? _(msg`By you`)
|
||||
: _(msg`By ${sanitizeHandle(view.creator.handle, '@')}`)}
|
||||
</Text>
|
||||
</View>
|
||||
<Link
|
||||
to={link.to}
|
||||
label={link.label}
|
||||
onHoverIn={link.precache}
|
||||
onPress={link.precache}
|
||||
variant="solid"
|
||||
color="secondary"
|
||||
size="small"
|
||||
style={[a.z_50]}>
|
||||
<ButtonText>
|
||||
<Trans>Open pack</Trans>
|
||||
</ButtonText>
|
||||
</Link>
|
||||
</View>
|
||||
</View>
|
||||
<View
|
||||
style={[
|
||||
a.w_full,
|
||||
a.flex_row,
|
||||
a.align_start,
|
||||
a.gap_lg,
|
||||
web({
|
||||
position: 'static',
|
||||
zIndex: 'unset',
|
||||
}),
|
||||
]}>
|
||||
<View style={[a.flex_1]}>
|
||||
<Text
|
||||
emoji
|
||||
style={[a.text_md, a.font_bold, a.leading_snug]}
|
||||
numberOfLines={1}>
|
||||
{view.record.name}
|
||||
</Text>
|
||||
<Text
|
||||
emoji
|
||||
style={[
|
||||
a.text_sm,
|
||||
a.leading_snug,
|
||||
t.atoms.text_contrast_medium,
|
||||
]}
|
||||
numberOfLines={1}>
|
||||
{view.creator?.did === currentAccount?.did
|
||||
? _(msg`By you`)
|
||||
: _(msg`By ${sanitizeHandle(view.creator.handle, '@')}`)}
|
||||
</Text>
|
||||
</View>
|
||||
<Link
|
||||
to={link.to}
|
||||
label={link.label}
|
||||
onHoverIn={link.precache}
|
||||
onPress={link.precache}
|
||||
variant="solid"
|
||||
color="secondary"
|
||||
size="small"
|
||||
style={[a.z_50]}>
|
||||
<ButtonText>
|
||||
<Trans>Open pack</Trans>
|
||||
</ButtonText>
|
||||
</Link>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -40,14 +40,14 @@ export function ExploreInterestsCard() {
|
||||
<>
|
||||
<Prompt.Basic
|
||||
control={trendingPrompt}
|
||||
title={_(msg`Your interests`)}
|
||||
title={_(msg`Dismiss interests`)}
|
||||
description={_(
|
||||
msg`You can adjust your interests at any time from your "Content and media" settings.`,
|
||||
msg`You can adjust your interests at any time from "Content and media" settings.`,
|
||||
)}
|
||||
confirmButtonCta={_(
|
||||
msg({
|
||||
message: `Copy that!`,
|
||||
comment: `Confirm button text. Can be a short cheeky phrase that means "OK" e.g. "Copy that!"`,
|
||||
message: `OK`,
|
||||
comment: `Confirm button text.`,
|
||||
}),
|
||||
)}
|
||||
onConfirm={onConfirmClose}
|
||||
|
||||
@@ -17,6 +17,7 @@ import {atoms as a} from '#/alf'
|
||||
import {Button} from '#/components/Button'
|
||||
import * as ProfileCard from '#/components/ProfileCard'
|
||||
import {boostInterests, Tabs} from '#/components/ProgressGuide/FollowDialog'
|
||||
import {SubtleHover} from '#/components/SubtleHover'
|
||||
import {Text} from '#/components/Typography'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
@@ -133,10 +134,7 @@ let Tab = ({
|
||||
a.py_sm,
|
||||
a.border,
|
||||
active || hovered || pressed || focused
|
||||
? [
|
||||
t.atoms.bg_contrast_25,
|
||||
{borderColor: t.atoms.bg_contrast_25.backgroundColor},
|
||||
]
|
||||
? [t.atoms.bg_contrast_25, t.atoms.border_contrast_medium]
|
||||
: [t.atoms.bg, t.atoms.border_contrast_low],
|
||||
]}>
|
||||
<Text
|
||||
@@ -186,47 +184,52 @@ let SuggestedProfileCard = ({
|
||||
{statsig: true},
|
||||
)
|
||||
}}>
|
||||
<View
|
||||
style={[
|
||||
a.w_full,
|
||||
a.py_lg,
|
||||
a.px_lg,
|
||||
a.border_t,
|
||||
t.atoms.border_contrast_low,
|
||||
a.flex_1,
|
||||
]}>
|
||||
<ProfileCard.Outer>
|
||||
<ProfileCard.Header>
|
||||
<ProfileCard.Avatar
|
||||
profile={profile}
|
||||
moderationOpts={moderationOpts}
|
||||
/>
|
||||
<ProfileCard.NameAndHandle
|
||||
profile={profile}
|
||||
moderationOpts={moderationOpts}
|
||||
/>
|
||||
<ProfileCard.FollowButton
|
||||
profile={profile}
|
||||
moderationOpts={moderationOpts}
|
||||
withIcon={false}
|
||||
logContext="ExploreSuggestedAccounts"
|
||||
onFollow={() => {
|
||||
logger.metric(
|
||||
'suggestedUser:follow',
|
||||
{
|
||||
logContext: 'Explore',
|
||||
location: 'Card',
|
||||
recId,
|
||||
position,
|
||||
},
|
||||
{statsig: true},
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</ProfileCard.Header>
|
||||
<ProfileCard.Description profile={profile} numberOfLines={2} />
|
||||
</ProfileCard.Outer>
|
||||
</View>
|
||||
{s => (
|
||||
<>
|
||||
<SubtleHover hover={s.hovered || s.pressed} />
|
||||
<View
|
||||
style={[
|
||||
a.flex_1,
|
||||
a.w_full,
|
||||
a.py_lg,
|
||||
a.px_lg,
|
||||
a.border_t,
|
||||
t.atoms.border_contrast_low,
|
||||
]}>
|
||||
<ProfileCard.Outer>
|
||||
<ProfileCard.Header>
|
||||
<ProfileCard.Avatar
|
||||
profile={profile}
|
||||
moderationOpts={moderationOpts}
|
||||
/>
|
||||
<ProfileCard.NameAndHandle
|
||||
profile={profile}
|
||||
moderationOpts={moderationOpts}
|
||||
/>
|
||||
<ProfileCard.FollowButton
|
||||
profile={profile}
|
||||
moderationOpts={moderationOpts}
|
||||
withIcon={false}
|
||||
logContext="ExploreSuggestedAccounts"
|
||||
onFollow={() => {
|
||||
logger.metric(
|
||||
'suggestedUser:follow',
|
||||
{
|
||||
logContext: 'Explore',
|
||||
location: 'Card',
|
||||
recId,
|
||||
position,
|
||||
},
|
||||
{statsig: true},
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</ProfileCard.Header>
|
||||
<ProfileCard.Description profile={profile} numberOfLines={2} />
|
||||
</ProfileCard.Outer>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</ProfileCard.Link>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import {type Props as SVGIconProps} from '#/components/icons/common'
|
||||
import {Flame_Stroke2_Corner1_Rounded as FlameIcon} from '#/components/icons/Flame'
|
||||
import {Trending3_Stroke2_Corner1_Rounded as TrendingIcon} from '#/components/icons/Trending'
|
||||
import {Link} from '#/components/Link'
|
||||
import {SubtleHover} from '#/components/SubtleHover'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
const TOPIC_COUNT = 5
|
||||
@@ -28,10 +29,10 @@ export function ExploreTrendingTopics() {
|
||||
}
|
||||
|
||||
function Inner() {
|
||||
const {data: trending, error, isLoading} = useGetTrendsQuery()
|
||||
const {data: trending, error, isLoading, isRefetching} = useGetTrendsQuery()
|
||||
const noTopics = !isLoading && !error && !trending?.trends?.length
|
||||
|
||||
return isLoading ? (
|
||||
return isLoading || isRefetching ? (
|
||||
Array.from({length: TOPIC_COUNT}).map((__, i) => (
|
||||
<TrendingTopicRowSkeleton key={i} withPosts={i === 0} />
|
||||
))
|
||||
@@ -92,25 +93,23 @@ export function TrendRow({
|
||||
PressableComponent={Pressable}>
|
||||
{({hovered, pressed}) => (
|
||||
<>
|
||||
<View
|
||||
style={[
|
||||
gutters,
|
||||
a.w_full,
|
||||
a.py_lg,
|
||||
a.flex_row,
|
||||
a.gap_2xs,
|
||||
(hovered || pressed) && t.atoms.bg_contrast_25,
|
||||
]}>
|
||||
<SubtleHover hover={hovered || pressed} />
|
||||
<View style={[gutters, a.w_full, a.py_lg, a.flex_row, a.gap_2xs]}>
|
||||
<View style={[a.flex_1, a.gap_xs]}>
|
||||
<View style={[a.flex_row]}>
|
||||
<Text
|
||||
style={[a.text_md, a.font_bold, a.leading_snug, {width: 20}]}>
|
||||
style={[
|
||||
a.text_md,
|
||||
a.font_bold,
|
||||
a.leading_tight,
|
||||
{width: 20},
|
||||
]}>
|
||||
<Trans comment='The trending topic rank, i.e. "1. March Madness", "2. The Bachelor"'>
|
||||
{rank}.
|
||||
</Trans>
|
||||
</Text>
|
||||
<Text
|
||||
style={[a.text_md, a.font_bold, a.leading_snug]}
|
||||
style={[a.text_md, a.font_bold, a.leading_tight]}
|
||||
numberOfLines={1}>
|
||||
{trend.displayName}
|
||||
</Text>
|
||||
|
||||
Reference in New Issue
Block a user