diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/SubtleHover.tsx | 34 | ||||
-rw-r--r-- | src/screens/Search/Explore.tsx | 147 | ||||
-rw-r--r-- | src/screens/Search/components/ModuleHeader.tsx | 10 | ||||
-rw-r--r-- | src/screens/Search/components/StarterPackCard.tsx | 140 | ||||
-rw-r--r-- | src/screens/Search/modules/ExploreInterestsCard.tsx | 8 | ||||
-rw-r--r-- | src/screens/Search/modules/ExploreSuggestedAccounts.tsx | 93 | ||||
-rw-r--r-- | src/screens/Search/modules/ExploreTrendingTopics.tsx | 25 | ||||
-rw-r--r-- | src/state/queries/explore-feed-previews.tsx | 66 | ||||
-rw-r--r-- | src/state/queries/trending/useGetSuggestedFeedsQuery.ts | 3 | ||||
-rw-r--r-- | src/state/queries/trending/useGetSuggestedUsersQuery.ts | 4 | ||||
-rw-r--r-- | src/state/queries/trending/useGetTrendsQuery.ts | 1 | ||||
-rw-r--r-- | src/state/queries/useSuggestedStarterPacksQuery.ts | 3 |
12 files changed, 344 insertions, 190 deletions
diff --git a/src/components/SubtleHover.tsx b/src/components/SubtleHover.tsx new file mode 100644 index 000000000..bb5911baa --- /dev/null +++ b/src/components/SubtleHover.tsx @@ -0,0 +1,34 @@ +import {View} from 'react-native' + +import {atoms as a, useTheme, type ViewStyleProp} from '#/alf' + +export function SubtleHover({style, hover}: ViewStyleProp & {hover: boolean}) { + const t = useTheme() + + let opacity: number + switch (t.name) { + case 'dark': + opacity = 0.4 + break + case 'dim': + opacity = 0.45 + break + case 'light': + opacity = 0.5 + break + } + + return ( + <View + style={[ + a.absolute, + a.inset_0, + a.pointer_events_none, + a.transition_opacity, + t.atoms.bg_contrast_25, + style, + {opacity: hover ? opacity : 0}, + ]} + /> + ) +} diff --git a/src/screens/Search/Explore.tsx b/src/screens/Search/Explore.tsx index 61ec36785..e29b85f76 100644 --- a/src/screens/Search/Explore.tsx +++ b/src/screens/Search/Explore.tsx @@ -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'] @@ -148,6 +156,10 @@ type ExploreScreenItems = recId?: number } | { + type: 'profileEmpty' + key: 'profileEmpty' + } + | { type: 'feed' key: string feed: AppBskyFeedDefs.GeneratorView @@ -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} /> ) } diff --git a/src/screens/Search/components/ModuleHeader.tsx b/src/screens/Search/components/ModuleHeader.tsx index c6411d1c0..9c208d2b2 100644 --- a/src/screens/Search/components/ModuleHeader.tsx +++ b/src/screens/Search/components/ModuleHeader.tsx @@ -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> ) diff --git a/src/screens/Search/components/StarterPackCard.tsx b/src/screens/Search/components/StarterPackCard.tsx index 1b9f94828..fcb0ef068 100644 --- a/src/screens/Search/components/StarterPackCard.tsx +++ b/src/screens/Search/components/StarterPackCard.tsx @@ -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> ) } diff --git a/src/screens/Search/modules/ExploreInterestsCard.tsx b/src/screens/Search/modules/ExploreInterestsCard.tsx index 00a15111a..00014ffc6 100644 --- a/src/screens/Search/modules/ExploreInterestsCard.tsx +++ b/src/screens/Search/modules/ExploreInterestsCard.tsx @@ -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} diff --git a/src/screens/Search/modules/ExploreSuggestedAccounts.tsx b/src/screens/Search/modules/ExploreSuggestedAccounts.tsx index 6d36ef1a7..8d66dfbc1 100644 --- a/src/screens/Search/modules/ExploreSuggestedAccounts.tsx +++ b/src/screens/Search/modules/ExploreSuggestedAccounts.tsx @@ -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> ) } diff --git a/src/screens/Search/modules/ExploreTrendingTopics.tsx b/src/screens/Search/modules/ExploreTrendingTopics.tsx index 75ca19351..167f6d193 100644 --- a/src/screens/Search/modules/ExploreTrendingTopics.tsx +++ b/src/screens/Search/modules/ExploreTrendingTopics.tsx @@ -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> diff --git a/src/state/queries/explore-feed-previews.tsx b/src/state/queries/explore-feed-previews.tsx index fcf9194db..2aee8b6b3 100644 --- a/src/state/queries/explore-feed-previews.tsx +++ b/src/state/queries/explore-feed-previews.tsx @@ -34,6 +34,41 @@ const RQKEY_ROOT = 'feed-previews' const RQKEY = (feeds: string[]) => [RQKEY_ROOT, feeds] const LIMIT = 8 // sliced to 6, overfetch to account for moderation +const PINNED_POST_URIS: Record<string, boolean> = { + // 📰 News + 'at://did:plc:kkf4naxqmweop7dv4l2iqqf5/app.bsky.feed.post/3lgh27w2ngc2b': + true, + // Gardening + 'at://did:plc:5rw2on4i56btlcajojaxwcat/app.bsky.feed.post/3kjorckgcwc27': + true, + // Web Development Trending + 'at://did:plc:m2sjv3wncvsasdapla35hzwj/app.bsky.feed.post/3lfaw445axs22': + true, + // Anime & Manga EN + 'at://did:plc:tazrmeme4dzahimsykusrwrk/app.bsky.feed.post/3knxx2gmkns2y': + true, + // 📽️ Film + 'at://did:plc:2hwwem55ce6djnk6bn62cstr/app.bsky.feed.post/3llhpzhbq7c2g': + true, + // PopSky + 'at://did:plc:lfdf4srj43iwdng7jn35tjsp/app.bsky.feed.post/3lbblgly65c2g': + true, + // Science + 'at://did:plc:hu2obebw3nhfj667522dahfg/app.bsky.feed.post/3kl33otd6ob2s': + true, + // Birds! 🦉 + 'at://did:plc:ffkgesg3jsv2j7aagkzrtcvt/app.bsky.feed.post/3lbg4r57yk22d': + true, + // Astronomy + 'at://did:plc:xy2zorw2ys47poflotxthlzg/app.bsky.feed.post/3kyzye4lujs2w': + true, + // What's Cooking 🍽️ + 'at://did:plc:geoqe3qls5mwezckxxsewys2/app.bsky.feed.post/3lfqhgvxbqc2q': + true, + // BookSky 💙📚 #booksky + 'at://did:plc:geoqe3qls5mwezckxxsewys2/app.bsky.feed.post/3kgrm2rw5ww2e': + true, +} export type FeedPreviewItem = | { @@ -181,19 +216,24 @@ export function useFeedPreviews( feedContext: item.feedContext, reason: item.reason, feedPostUri: item.feedPostUri, - items: item.items.slice(0, 6).map((subItem, i) => { - const feedPostSliceItem: FeedPostSliceItem = { - _reactKey: `${item._reactKey}-${i}-${subItem.post.uri}`, - uri: subItem.post.uri, - post: subItem.post, - record: subItem.record, - moderation: moderations[i], - parentAuthor: subItem.parentAuthor, - isParentBlocked: subItem.isParentBlocked, - isParentNotFound: subItem.isParentNotFound, - } - return feedPostSliceItem - }), + items: item.items + .slice(0, 6) + .filter(subItem => { + return !PINNED_POST_URIS[subItem.post.uri] + }) + .map((subItem, i) => { + const feedPostSliceItem: FeedPostSliceItem = { + _reactKey: `${item._reactKey}-${i}-${subItem.post.uri}`, + uri: subItem.post.uri, + post: subItem.post, + record: subItem.record, + moderation: moderations[i], + parentAuthor: subItem.parentAuthor, + isParentBlocked: subItem.isParentBlocked, + isParentNotFound: subItem.isParentNotFound, + } + return feedPostSliceItem + }), } if (slice.isIncompleteThread && slice.items.length >= 3) { const beforeLast = slice.items.length - 2 diff --git a/src/state/queries/trending/useGetSuggestedFeedsQuery.ts b/src/state/queries/trending/useGetSuggestedFeedsQuery.ts index 55b633af0..eef71f1ca 100644 --- a/src/state/queries/trending/useGetSuggestedFeedsQuery.ts +++ b/src/state/queries/trending/useGetSuggestedFeedsQuery.ts @@ -20,8 +20,7 @@ export function useGetSuggestedFeedsQuery() { return useQuery({ enabled: !!preferences, - refetchOnWindowFocus: true, - staleTime: STALE.MINUTES.ONE, + staleTime: STALE.MINUTES.THREE, queryKey: createGetSuggestedFeedsQueryKey(), queryFn: async () => { const contentLangs = getContentLanguages().join(',') diff --git a/src/state/queries/trending/useGetSuggestedUsersQuery.ts b/src/state/queries/trending/useGetSuggestedUsersQuery.ts index eb97ad666..c8c3f0089 100644 --- a/src/state/queries/trending/useGetSuggestedUsersQuery.ts +++ b/src/state/queries/trending/useGetSuggestedUsersQuery.ts @@ -27,14 +27,14 @@ export function useGetSuggestedUsersQuery(props: QueryProps) { return useQuery({ enabled: !!preferences, - refetchOnWindowFocus: true, - staleTime: STALE.MINUTES.ONE, + staleTime: STALE.MINUTES.THREE, queryKey: createGetSuggestedUsersQueryKey(props), queryFn: async () => { const contentLangs = getContentLanguages().join(',') const {data} = await agent.app.bsky.unspecced.getSuggestedUsers( { category: props.category ?? undefined, + limit: 10, }, { headers: { diff --git a/src/state/queries/trending/useGetTrendsQuery.ts b/src/state/queries/trending/useGetTrendsQuery.ts index 02386a505..94a5b0cba 100644 --- a/src/state/queries/trending/useGetTrendsQuery.ts +++ b/src/state/queries/trending/useGetTrendsQuery.ts @@ -25,7 +25,6 @@ export function useGetTrendsQuery() { return useQuery({ enabled: !!preferences, - refetchOnWindowFocus: true, staleTime: STALE.MINUTES.THREE, queryKey: createGetTrendsQueryKey(), queryFn: async () => { diff --git a/src/state/queries/useSuggestedStarterPacksQuery.ts b/src/state/queries/useSuggestedStarterPacksQuery.ts index cda3c28ab..3ec030ac0 100644 --- a/src/state/queries/useSuggestedStarterPacksQuery.ts +++ b/src/state/queries/useSuggestedStarterPacksQuery.ts @@ -20,8 +20,7 @@ export function useSuggestedStarterPacksQuery() { return useQuery({ enabled: !!preferences, - refetchOnWindowFocus: true, - staleTime: STALE.MINUTES.ONE, + staleTime: STALE.MINUTES.THREE, queryKey: createSuggestedStarterPacksQueryKey(), async queryFn() { const {data} = await agent.app.bsky.unspecced.getSuggestedStarterPacks( |