From 5c59ec14c290d2a0867634af926ab7e657c0e189 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Fri, 4 Apr 2025 21:00:38 +0300 Subject: [PATCH 1/4] Match placeholder color with other skeletons (#8129) --- src/components/ProfileCard.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/ProfileCard.tsx b/src/components/ProfileCard.tsx index a374325008..beb09cdc74 100644 --- a/src/components/ProfileCard.tsx +++ b/src/components/ProfileCard.tsx @@ -152,7 +152,7 @@ export function AvatarPlaceholder() { From a0ff9b52aad3349b24118a0222e0f3d78e695887 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 4 Apr 2025 14:08:16 -0500 Subject: [PATCH 2/4] [Explore] Add interests card (#8125) * Add interests card to top of Explore * Add tip to add interests if they have none or deselect * Format * Copy --- src/screens/Search/Explore.tsx | 24 ++++ .../Search/modules/ExploreInterestsCard.tsx | 128 ++++++++++++++++++ src/screens/Settings/SettingsInterests.tsx | 50 ++++--- src/state/queries/nuxs/definitions.ts | 20 ++- 4 files changed, 195 insertions(+), 27 deletions(-) create mode 100644 src/screens/Search/modules/ExploreInterestsCard.tsx diff --git a/src/screens/Search/Explore.tsx b/src/screens/Search/Explore.tsx index 00eb6c4330..088bc5724b 100644 --- a/src/screens/Search/Explore.tsx +++ b/src/screens/Search/Explore.tsx @@ -21,6 +21,7 @@ import { useFeedPreviews, } from '#/state/queries/explore-feed-previews' import {useGetPopularFeedsQuery} from '#/state/queries/feed' +import {Nux, useNux} from '#/state/queries/nuxs' import {usePreferencesQuery} from '#/state/queries/preferences' import {useSuggestedFollowsQuery} from '#/state/queries/suggested-follows' import {useGetSuggestedFeedsQuery} from '#/state/queries/trending/useGetSuggestedFeedsQuery' @@ -36,6 +37,7 @@ import { StarterPackCard, StarterPackCardSkeleton, } from '#/screens/Search/components/StarterPackCard' +import {ExploreInterestsCard} from '#/screens/Search/modules/ExploreInterestsCard' import {ExploreRecommendations} from '#/screens/Search/modules/ExploreRecommendations' import {ExploreTrendingTopics} from '#/screens/Search/modules/ExploreTrendingTopics' import {ExploreTrendingVideos} from '#/screens/Search/modules/ExploreTrendingVideos' @@ -181,6 +183,10 @@ type ExploreScreenItems = key: string } | FeedPreviewItem + | { + type: 'interests-card' + key: 'interests-card' + } export function Explore({ focusSearchInput, @@ -233,6 +239,9 @@ export function Explore({ error: feedsError, fetchNextPage: fetchNextFeedsPage, } = useGetPopularFeedsQuery({limit: 10}) + const interestsNux = useNux(Nux.ExploreInterestsCard) + const showInterestsNux = + interestsNux.status === 'ready' && !interestsNux.nux?.completed const profiles: typeof suggestedProfiles & typeof interestProfiles = !selectedInterest ? suggestedProfiles : interestProfiles @@ -558,6 +567,16 @@ export function Explore({ return i }, [feedPreviewSlices, isFetchingNextPageFeedPreviews]) + const interestsNuxModule = useMemo(() => { + if (!showInterestsNux) return [] + return [ + { + type: 'interests-card', + key: 'interests-card', + }, + ] + }, [showInterestsNux]) + const isNewUser = guide?.guide === 'follow-10' && !guide.isComplete const items = useMemo(() => { const i: ExploreScreenItems[] = [] @@ -565,6 +584,7 @@ export function Explore({ // Dynamic module ordering i.push(topBorder) + i.push(...interestsNuxModule) if (isNewUser) { i.push(...suggestedFollowsModule) i.push(...suggestedStarterPacksModule) @@ -588,6 +608,7 @@ export function Explore({ suggestedFeedsModule, trendingTopicsModule, feedPreviewsModule, + interestsNuxModule, gate, ]) @@ -854,6 +875,9 @@ export function Explore({ /> ) } + case 'interests-card': { + return + } } }, [ diff --git a/src/screens/Search/modules/ExploreInterestsCard.tsx b/src/screens/Search/modules/ExploreInterestsCard.tsx new file mode 100644 index 0000000000..fde5c3b1e9 --- /dev/null +++ b/src/screens/Search/modules/ExploreInterestsCard.tsx @@ -0,0 +1,128 @@ +import {useState} from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {Nux, useSaveNux} from '#/state/queries/nuxs' +import {usePreferencesQuery} from '#/state/queries/preferences' +import {useInterestsDisplayNames} from '#/screens/Onboarding/state' +import {atoms as a, useGutters, useTheme} from '#/alf' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' +import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' +import {Link} from '#/components/Link' +import * as Prompt from '#/components/Prompt' +import {Text} from '#/components/Typography' + +export function ExploreInterestsCard() { + const t = useTheme() + const {_} = useLingui() + const gutters = useGutters([0, 'base']) + const {data: preferences} = usePreferencesQuery() + const interestsDisplayNames = useInterestsDisplayNames() + const {mutateAsync: saveNux} = useSaveNux() + const trendingPrompt = Prompt.usePromptControl() + const [closing, setClosing] = useState(false) + + const onClose = () => { + trendingPrompt.open() + } + const onConfirmClose = () => { + setClosing(true) + // if this fails, they can try again later + saveNux({ + id: Nux.ExploreInterestsCard, + completed: true, + data: undefined, + }).catch(() => {}) + } + + return closing ? null : ( + <> + + + + + + Your interests + + + {preferences?.interests?.tags && + preferences.interests.tags.length > 0 ? ( + + {preferences.interests.tags.map(tag => ( + + + {interestsDisplayNames[tag]} + + + ))} + + ) : null} + + + + Your selected interests help us serve you content you care about. + + + + + + Edit interests + + + + + + + + ) +} diff --git a/src/screens/Settings/SettingsInterests.tsx b/src/screens/Settings/SettingsInterests.tsx index 2665455605..9a61329465 100644 --- a/src/screens/Settings/SettingsInterests.tsx +++ b/src/screens/Settings/SettingsInterests.tsx @@ -14,6 +14,7 @@ import {useAgent} from '#/state/session' import * as Toast from '#/view/com/util/Toast' import {useInterestsDisplayNames} from '#/screens/Onboarding/state' import {atoms as a, useGutters, useTheme} from '#/alf' +import {Admonition} from '#/components/Admonition' import {Divider} from '#/components/Divider' import * as Toggle from '#/components/forms/Toggle' import * as Layout from '#/components/Layout' @@ -47,8 +48,7 @@ export function SettingsInterests() { t.atoms.text_contrast_medium, ]}> - Selecting interests from the list below helps us deliver you - higher quality content. + Your selected interests help us serve you content you care about. @@ -124,25 +124,33 @@ function Inner({ } return ( - - - {INTERESTS.map(interest => { - const name = interestsDisplayNames[interest] - if (!name) return null - return ( - - - - ) - })} - - + <> + {interests.length === 0 && ( + + We recommend selecting at least two interests. + + )} + + + + {INTERESTS.map(interest => { + const name = interestsDisplayNames[interest] + if (!name) return null + return ( + + + + ) + })} + + + ) } diff --git a/src/state/queries/nuxs/definitions.ts b/src/state/queries/nuxs/definitions.ts index 8166602c8a..8eb53a0a43 100644 --- a/src/state/queries/nuxs/definitions.ts +++ b/src/state/queries/nuxs/definitions.ts @@ -1,18 +1,26 @@ -import zod from 'zod' +import type zod from 'zod' -import {BaseNux} from '#/state/queries/nuxs/types' +import {type BaseNux} from '#/state/queries/nuxs/types' export enum Nux { NeueTypography = 'NeueTypography', + ExploreInterestsCard = 'ExploreInterestsCard', } export const nuxNames = new Set(Object.values(Nux)) -export type AppNux = BaseNux<{ - id: Nux.NeueTypography - data: undefined -}> +export type AppNux = BaseNux< + | { + id: Nux.NeueTypography + data: undefined + } + | { + id: Nux.ExploreInterestsCard + data: undefined + } +> export const NuxSchemas: Record | undefined> = { [Nux.NeueTypography]: undefined, + [Nux.ExploreInterestsCard]: undefined, } From aca89d4aea61a50697187464e88ac1b9a4ef40bd Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 4 Apr 2025 18:44:02 -0500 Subject: [PATCH 3/4] [Explore] New suggested follows endpoint (#8130) * Bump SDK * Integrate new endpoint, add profile shadow, For You tab * Format --- package.json | 2 +- src/screens/Search/Explore.tsx | 129 ++++-------------- .../modules/ExploreSuggestedAccounts.tsx | 2 +- src/state/cache/profile-shadow.ts | 2 + .../trending/useGetSuggestedUsersQuery.ts | 71 ++++++++++ yarn.lock | 8 +- 6 files changed, 108 insertions(+), 106 deletions(-) create mode 100644 src/state/queries/trending/useGetSuggestedUsersQuery.ts diff --git a/package.json b/package.json index 6f73a5581b..2ff7557d1b 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "icons:optimize": "svgo -f ./assets/icons" }, "dependencies": { - "@atproto/api": "^0.14.19", + "@atproto/api": "^0.14.20", "@bitdrift/react-native": "^0.6.8", "@braintree/sanitize-url": "^6.0.2", "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet", diff --git a/src/screens/Search/Explore.tsx b/src/screens/Search/Explore.tsx index 088bc5724b..8c41a507a4 100644 --- a/src/screens/Search/Explore.tsx +++ b/src/screens/Search/Explore.tsx @@ -15,7 +15,6 @@ import {sanitizeHandle} from '#/lib/strings/handles' import {logger} from '#/logger' import {type MetricEvents} from '#/logger/metrics' import {useModerationOpts} from '#/state/preferences/moderation-opts' -import {useActorSearchPaginated} from '#/state/queries/actor-search' import { type FeedPreviewItem, useFeedPreviews, @@ -23,8 +22,8 @@ import { import {useGetPopularFeedsQuery} from '#/state/queries/feed' import {Nux, useNux} from '#/state/queries/nuxs' import {usePreferencesQuery} from '#/state/queries/preferences' -import {useSuggestedFollowsQuery} from '#/state/queries/suggested-follows' import {useGetSuggestedFeedsQuery} from '#/state/queries/trending/useGetSuggestedFeedsQuery' +import {useGetSuggestedUsersQuery} from '#/state/queries/trending/useGetSuggestedUsersQuery' import {useSuggestedStarterPacksQuery} from '#/state/queries/useSuggestedStarterPacksQuery' import {useProgressGuide} from '#/state/shell/progress-guide' import {isThreadChildAt, isThreadParentAt} from '#/view/com/posts/PostFeed' @@ -57,7 +56,6 @@ import * as ModuleHeader from './components/ModuleHeader' import { SuggestedAccountsTabBar, SuggestedProfileCard, - useLoadEnoughProfiles, } from './modules/ExploreSuggestedAccounts' function LoadMore({item}: {item: ExploreScreenItems & {type: 'loadMore'}}) { @@ -144,7 +142,7 @@ type ExploreScreenItems = | { type: 'profile' key: string - profile: AppBskyActorDefs.ProfileView + profile: AppBskyActorDefs.ProfileViewBasic recId?: number } | { @@ -203,33 +201,13 @@ export function Explore({ const gate = useGate() const guide = useProgressGuide('follow-10') const [selectedInterest, setSelectedInterest] = useState(null) + // TODO always get at least 10 back const { - data: suggestedProfiles, - hasNextPage: hasNextSuggestedProfilesPage, - isLoading: isLoadingSuggestedProfiles, - isFetchingNextPage: isFetchingNextSuggestedProfilesPage, - error: suggestedProfilesError, - fetchNextPage: fetchNextSuggestedProfilesPage, - } = useSuggestedFollowsQuery({limit: 3, subsequentPageLimit: 10}) - const { - data: interestProfiles, - hasNextPage: hasNextInterestProfilesPage, - isLoading: isLoadingInterestProfiles, - isFetchingNextPage: isFetchingNextInterestProfilesPage, - error: interestProfilesError, - fetchNextPage: fetchNextInterestProfilesPage, - } = useActorSearchPaginated({ - query: selectedInterest || '', - enabled: !!selectedInterest, - limit: 10, - }) - const {isReady: canShowSuggestedProfiles} = useLoadEnoughProfiles({ - interest: selectedInterest, - data: interestProfiles, - isLoading: isLoadingInterestProfiles, - isFetchingNextPage: isFetchingNextInterestProfilesPage, - hasNextPage: hasNextInterestProfilesPage, - fetchNextPage: fetchNextInterestProfilesPage, + data: suggestedUsers, + isLoading: suggestedUsersIsLoading, + error: suggestedUsersError, + } = useGetSuggestedUsersQuery({ + category: selectedInterest, }) const { data: feeds, @@ -243,39 +221,6 @@ export function Explore({ const showInterestsNux = interestsNux.status === 'ready' && !interestsNux.nux?.completed - const profiles: typeof suggestedProfiles & typeof interestProfiles = - !selectedInterest ? suggestedProfiles : interestProfiles - const hasNextProfilesPage = !selectedInterest - ? hasNextSuggestedProfilesPage - : hasNextInterestProfilesPage - const isLoadingProfiles = !selectedInterest - ? isLoadingSuggestedProfiles - : !canShowSuggestedProfiles - const isFetchingNextProfilesPage = !selectedInterest - ? isFetchingNextSuggestedProfilesPage - : !canShowSuggestedProfiles - const profilesError = !selectedInterest - ? suggestedProfilesError - : interestProfilesError - const fetchNextProfilesPage = !selectedInterest - ? fetchNextSuggestedProfilesPage - : fetchNextInterestProfilesPage - - const isLoadingMoreProfiles = isFetchingNextProfilesPage && !isLoadingProfiles - const onLoadMoreProfiles = useCallback(async () => { - if (isFetchingNextProfilesPage || !hasNextProfilesPage || profilesError) - return - try { - await fetchNextProfilesPage() - } catch (err) { - logger.error('Failed to load more suggested follows', {message: err}) - } - }, [ - isFetchingNextProfilesPage, - hasNextProfilesPage, - profilesError, - fetchNextProfilesPage, - ]) const { data: suggestedSPs, isLoading: isLoadingSuggestedSPs, @@ -358,55 +303,42 @@ export function Explore({ }, }) - if (!canShowSuggestedProfiles) { + if (suggestedUsersIsLoading) { i.push({type: 'profilePlaceholder', key: 'profilePlaceholder'}) - } else if (profilesError) { + } else if (suggestedUsersError) { i.push({ type: 'error', - key: 'profilesError', + key: 'suggestedUsersError', message: _(msg`Failed to load suggested follows`), - error: cleanError(profilesError), + error: cleanError(suggestedUsersError), }) } else { - if (profiles !== undefined) { - if (profiles.pages.length > 0 && moderationOpts) { + if (suggestedUsers !== undefined) { + if (suggestedUsers.actors.length > 0 && moderationOpts) { // Currently the responses contain duplicate items. // Needs to be fixed on backend, but let's dedupe to be safe. let seen = new Set() const profileItems: ExploreScreenItems[] = [] - for (const page of profiles.pages) { - for (const actor of page.actors) { - if (!seen.has(actor.did) && !actor.viewer?.following) { - seen.add(actor.did) - profileItems.push({ - type: 'profile', - key: actor.did, - profile: actor, - recId: page.recId, - }) - } + for (const actor of suggestedUsers.actors) { + if (!seen.has(actor.did) && !actor.viewer?.following) { + seen.add(actor.did) + profileItems.push({ + type: 'profile', + key: actor.did, + profile: actor, + }) } } if (profileItems.length === 0) { - if (!hasNextProfilesPage) { - // no items! remove the header - i.pop() - } + // no items! remove the header + i.pop() } else { i.push(...profileItems) } - if (hasNextProfilesPage) { - i.push({ - type: 'loadMore', - key: 'loadMoreProfiles', - message: _(msg`Load more suggested accounts`), - isLoadingMore: isLoadingMoreProfiles, - onLoadMore: onLoadMoreProfiles, - }) - } } else { - console.log('no pages') + // no items! remove the header + i.pop() } } else { i.push({type: 'profilePlaceholder', key: 'profilePlaceholder'}) @@ -414,14 +346,11 @@ export function Explore({ } return i }, [ - profiles, _, - canShowSuggestedProfiles, - hasNextProfilesPage, - isLoadingMoreProfiles, moderationOpts, - onLoadMoreProfiles, - profilesError, + suggestedUsers, + suggestedUsersIsLoading, + suggestedUsersError, ]) const suggestedFeedsModule = useMemo(() => { const i: ExploreScreenItems[] = [] diff --git a/src/screens/Search/modules/ExploreSuggestedAccounts.tsx b/src/screens/Search/modules/ExploreSuggestedAccounts.tsx index 070d75910c..71210823ed 100644 --- a/src/screens/Search/modules/ExploreSuggestedAccounts.tsx +++ b/src/screens/Search/modules/ExploreSuggestedAccounts.tsx @@ -83,7 +83,7 @@ export function SuggestedAccountsTabBar({ }} hasSearchText={false} interestsDisplayNames={{ - all: _(msg`All`), + all: _(msg`For You`), ...interestsDisplayNames, }} TabComponent={Tab} diff --git a/src/state/cache/profile-shadow.ts b/src/state/cache/profile-shadow.ts index 84ebc565c4..82ee44388f 100644 --- a/src/state/cache/profile-shadow.ts +++ b/src/state/cache/profile-shadow.ts @@ -19,6 +19,7 @@ import {findAllProfilesInQueryData as findAllProfilesInProfileQueryData} from '# import {findAllProfilesInQueryData as findAllProfilesInProfileFollowersQueryData} from '#/state/queries/profile-followers' import {findAllProfilesInQueryData as findAllProfilesInProfileFollowsQueryData} from '#/state/queries/profile-follows' import {findAllProfilesInQueryData as findAllProfilesInSuggestedFollowsQueryData} from '#/state/queries/suggested-follows' +import {findAllProfilesInQueryData as findAllProfilesInSuggestedUsersQueryData} from '#/state/queries/trending/useGetSuggestedUsersQuery' import type * as bsky from '#/types/bsky' import {castAsShadow, type Shadow} from './types' @@ -149,6 +150,7 @@ function* findProfilesInCache( yield* findAllProfilesInProfileQueryData(queryClient, did) yield* findAllProfilesInProfileFollowersQueryData(queryClient, did) yield* findAllProfilesInProfileFollowsQueryData(queryClient, did) + yield* findAllProfilesInSuggestedUsersQueryData(queryClient, did) yield* findAllProfilesInSuggestedFollowsQueryData(queryClient, did) yield* findAllProfilesInActorSearchQueryData(queryClient, did) yield* findAllProfilesInListConvosQueryData(queryClient, did) diff --git a/src/state/queries/trending/useGetSuggestedUsersQuery.ts b/src/state/queries/trending/useGetSuggestedUsersQuery.ts new file mode 100644 index 0000000000..eb97ad6666 --- /dev/null +++ b/src/state/queries/trending/useGetSuggestedUsersQuery.ts @@ -0,0 +1,71 @@ +import { + type AppBskyActorDefs, + type AppBskyUnspeccedGetSuggestedUsers, +} from '@atproto/api' +import {type QueryClient, useQuery} from '@tanstack/react-query' + +import { + aggregateUserInterests, + createBskyTopicsHeader, +} from '#/lib/api/feed/utils' +import {getContentLanguages} from '#/state/preferences/languages' +import {STALE} from '#/state/queries' +import {usePreferencesQuery} from '#/state/queries/preferences' +import {useAgent} from '#/state/session' + +export type QueryProps = {category?: string | null} + +export const getSuggestedUsersQueryKeyRoot = 'unspecced-suggested-users' +export const createGetSuggestedUsersQueryKey = (props: QueryProps) => [ + getSuggestedUsersQueryKeyRoot, + ...Object.values(props), +] + +export function useGetSuggestedUsersQuery(props: QueryProps) { + const agent = useAgent() + const {data: preferences} = usePreferencesQuery() + + return useQuery({ + enabled: !!preferences, + refetchOnWindowFocus: true, + staleTime: STALE.MINUTES.ONE, + queryKey: createGetSuggestedUsersQueryKey(props), + queryFn: async () => { + const contentLangs = getContentLanguages().join(',') + const {data} = await agent.app.bsky.unspecced.getSuggestedUsers( + { + category: props.category ?? undefined, + }, + { + headers: { + ...createBskyTopicsHeader(aggregateUserInterests(preferences)), + 'Accept-Language': contentLangs, + }, + }, + ) + + return data + }, + }) +} + +export function* findAllProfilesInQueryData( + queryClient: QueryClient, + did: string, +): Generator { + const responses = + queryClient.getQueriesData({ + queryKey: [getSuggestedUsersQueryKeyRoot], + }) + for (const [_, response] of responses) { + if (!response) { + continue + } + + for (const actor of response.actors) { + if (actor.did === did) { + yield actor + } + } + } +} diff --git a/yarn.lock b/yarn.lock index 0541080f64..88b7c83880 100644 --- a/yarn.lock +++ b/yarn.lock @@ -80,10 +80,10 @@ tlds "^1.234.0" zod "^3.23.8" -"@atproto/api@^0.14.19": - version "0.14.19" - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.14.19.tgz#fef8994e2b14e69a9e3a0aef043c7fcb34d6bf8c" - integrity sha512-YYTqM0K0qk2TP7PguktPzlAQGLTL1bEGz6PgY5kqKJNX4o1318kJYB22DzjJYqV2NUCq0JQ9Lb0oskLvTisEOg== +"@atproto/api@^0.14.20": + version "0.14.20" + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.14.20.tgz#904c85a91748f3203fd929415cb8fb3bc78d35d3" + integrity sha512-Daip22+u9N+EVPk9PsEEVrTfjIqGczXnAT7o2EHGd0JsOzMbp3a6wmW1beKqYDzPf+Dc36/39JeUYYqhB3fKjg== dependencies: "@atproto/common-web" "^0.4.1" "@atproto/lexicon" "^0.4.10" From 0b08128e4a984e302c4675bf6b262272744e69f1 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 4 Apr 2025 18:55:30 -0500 Subject: [PATCH 4/4] [Explore] Design tweaks (#8131) * Fix interests card spacing * Space out AvatarStack * SP icon size * Visual alignment of tab bar and headers * Tweak spacing around search input * Drop text size in sp card overflow count * Tweak --- src/components/AvatarStack.tsx | 6 +++--- src/components/ProgressGuide/FollowDialog.tsx | 13 +++++++++++-- src/screens/Search/Explore.tsx | 5 ++++- src/screens/Search/Shell.tsx | 2 +- src/screens/Search/components/ModuleHeader.tsx | 12 ++---------- src/screens/Search/components/StarterPackCard.tsx | 2 +- src/screens/Search/modules/ExploreInterestsCard.tsx | 5 ++--- .../Search/modules/ExploreSuggestedAccounts.tsx | 6 ++++++ 8 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/components/AvatarStack.tsx b/src/components/AvatarStack.tsx index a341a20611..ae42a7470b 100644 --- a/src/components/AvatarStack.tsx +++ b/src/components/AvatarStack.tsx @@ -19,7 +19,7 @@ export function AvatarStack({ numPending?: number backgroundColor?: string }) { - const halfSize = size / 2 + const translation = size / 3 // overlap by 1/3 const t = useTheme() const moderationOpts = useModerationOpts() @@ -43,7 +43,7 @@ export function AvatarStack({ a.flex_row, a.align_center, a.relative, - {width: size + (items.length - 1) * halfSize}, + {width: size + (items.length - 1) * (size - translation)}, ]}> {items.map((item, i) => ( void interests: string[] @@ -460,6 +468,7 @@ let Tabs = ({ hasSearchText: boolean interestsDisplayNames: Record TabComponent?: React.ComponentType> + contentContainerStyle?: StyleProp }): React.ReactNode => { const listRef = useRef(null) const [scrollX, setScrollX] = useState(0) @@ -520,7 +529,7 @@ let Tabs = ({ + iconSize?: IcoProps['size'] searchButton?: { label: string metricsTag: MetricEvents['explore:module:searchButtonPress']['module'] @@ -461,6 +463,7 @@ export function Explore({ key: 'suggested-starterPacks-header', title: _(msg`Starter Packs`), icon: StarterPack, + iconSize: 'xl', }) if (isLoadingSuggestedSPs) { @@ -562,7 +565,7 @@ export function Explore({ case 'header': { return ( - + {item.title} {item.searchButton && ( )} - + diff --git a/src/screens/Search/components/ModuleHeader.tsx b/src/screens/Search/components/ModuleHeader.tsx index c965046a64..c6411d1c0d 100644 --- a/src/screens/Search/components/ModuleHeader.tsx +++ b/src/screens/Search/components/ModuleHeader.tsx @@ -6,14 +6,7 @@ import {PressableScale} from '#/lib/custom-animations/PressableScale' import {makeCustomFeedLink} from '#/lib/routes/links' import {logger} from '#/logger' import {UserAvatar} from '#/view/com/util/UserAvatar' -import { - atoms as a, - native, - useGutters, - useTheme, - type ViewStyleProp, - web, -} from '#/alf' +import {atoms as a, native, useTheme, type ViewStyleProp, web} from '#/alf' import {Button, ButtonIcon} from '#/components/Button' import * as FeedCard from '#/components/FeedCard' import {sizes as iconSizes} from '#/components/icons/common' @@ -27,13 +20,12 @@ export function Container({ headerHeight, }: {children: React.ReactNode; headerHeight?: number} & ViewStyleProp) { const t = useTheme() - const gutters = useGutters([0, 'base']) return ( 0 ? ( - + )