From 6bd0a91116506207a066300736dd3ae0b9ce3d58 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Tue, 3 Dec 2024 17:54:26 -0800 Subject: [PATCH] Add WIP UIs for trending topics and suggested starterpacks --- src/components/StarterPack/Suggestions.tsx | 64 ++++++++++ src/components/TrendingTopics.tsx | 79 ++++++++++++ src/view/screens/Search/Explore.tsx | 140 +++++++++++++++++++-- 3 files changed, 272 insertions(+), 11 deletions(-) create mode 100644 src/components/StarterPack/Suggestions.tsx create mode 100644 src/components/TrendingTopics.tsx diff --git a/src/components/StarterPack/Suggestions.tsx b/src/components/StarterPack/Suggestions.tsx new file mode 100644 index 0000000000..53750bd1a7 --- /dev/null +++ b/src/components/StarterPack/Suggestions.tsx @@ -0,0 +1,64 @@ +import {View} from 'react-native' +import {ScrollView} from 'react-native-gesture-handler' +import {AppBskyGraphDefs} from '@atproto/api' + +import {logger} from '#/logger' +import {useModerationOpts} from '#/state/preferences/moderation-opts' +import {atoms as a, useBreakpoints, web} from '#/alf' +import {Embed} from './StarterPackCard' + +const DESKTOP_CARD_WIDTH = 400 +const MOBILE_CARD_WIDTH = 300 + +export function Grid({ + isSuggestionsLoading, + error, + starterPacks, +}: { + isSuggestionsLoading: boolean + starterPacks: AppBskyGraphDefs.StarterPackViewBasic[] + error: Error | null +}) { + const moderationOpts = useModerationOpts() + const {gtMobile} = useBreakpoints() + const width = gtMobile ? DESKTOP_CARD_WIDTH : MOBILE_CARD_WIDTH + const isLoading = isSuggestionsLoading || !moderationOpts + const maxLength = gtMobile ? 4 : 6 + + const content = isLoading ? ( + Array(maxLength) + .fill(0) + .map((_, i) => ( + + {/* TODO */} + + )) + ) : error || !starterPacks.length ? null : ( + <> + {starterPacks.slice(0, maxLength).map(starterPack => ( + + + + ))} + + ) + + if (error || (!isLoading && !starterPacks.length)) { + logger.debug(`Not enough starter packs to show suggested starter packs`) + return null + } + + return ( + + + {content} + + + ) +} diff --git a/src/components/TrendingTopics.tsx b/src/components/TrendingTopics.tsx new file mode 100644 index 0000000000..9f8fb69b79 --- /dev/null +++ b/src/components/TrendingTopics.tsx @@ -0,0 +1,79 @@ +import {View} from 'react-native' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {atoms as a, useTheme} from '#/alf' +import {Link as InternalLink, LinkProps} from '#/components/Link' +import {Text} from '#/components/Typography' + +export function Grid({topics}: {topics: string[]}) { + return ( + + {topics.map(topic => ( + + ))} + + ) +} + +export function Item({topic}: {topic: string}) { + return ( + + + + ) +} + +export function Card({topic}: {topic: string}) { + const t = useTheme() + return ( + + + + ) +} + +export function Link({ + topic, + children, + style, + ...rest +}: { + topic: string +} & Omit) { + const {_} = useLingui() + return ( + + {children} + + ) +} + +export function Topic({topic}: {topic: string}) { + return ( + + + {topic} + + + ) +} diff --git a/src/view/screens/Search/Explore.tsx b/src/view/screens/Search/Explore.tsx index bd2ebe5d5d..22cc7b760e 100644 --- a/src/view/screens/Search/Explore.tsx +++ b/src/view/screens/Search/Explore.tsx @@ -3,6 +3,7 @@ import {View} from 'react-native' import { AppBskyActorDefs, AppBskyFeedDefs, + AppBskyGraphDefs, moderateProfile, ModerationDecision, ModerationOpts, @@ -31,8 +32,12 @@ import {ArrowBottom_Stroke2_Corner0_Rounded as ArrowBottom} from '#/components/i import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' import {Props as SVGIconProps} from '#/components/icons/common' import {ListSparkle_Stroke2_Corner0_Rounded as ListSparkle} from '#/components/icons/ListSparkle' +import {PersonGroup_Stroke2_Corner2_Rounded as PersonGroup} from '#/components/icons/Person' +import {Trending2_Stroke2_Corner2_Rounded as Trending} from '#/components/icons/Trending2' import {UserCircle_Stroke2_Corner0_Rounded as Person} from '#/components/icons/UserCircle' import {Loader} from '#/components/Loader' +import * as StarterPackSuggestions from '#/components/StarterPack/Suggestions' +import * as TrendingTopics from '#/components/TrendingTopics' import {Text} from '#/components/Typography' function SuggestedItemsHeader({ @@ -239,6 +244,16 @@ type ExploreScreenItems = style?: ViewStyleProp['style'] icon: React.ComponentType } + | { + type: 'trendingTopics' + key: string + topics: string[] + } + | { + type: 'suggestedStarterPacks' + key: string + starterPacks: AppBskyGraphDefs.StarterPackViewBasic[] + } | { type: 'profile' key: string @@ -325,17 +340,108 @@ export function Explore() { ]) const items = React.useMemo(() => { - const i: ExploreScreenItems[] = [ - { - type: 'header', - key: 'suggested-follows-header', - title: _(msg`Suggested accounts`), - description: _( - msg`Follow more accounts to get connected to your interests and build your network.`, - ), - icon: Person, - }, - ] + const i: ExploreScreenItems[] = [] + + i.push({ + type: 'header', + key: 'trending-topics-header', + title: _(msg`Trending (beta)`), + description: _(msg`What people are posting about now.`), + icon: Trending, + }) + i.push({ + type: 'trendingTopics', + key: `trending-topics`, + topics: [ + '#atproto', + 'South Korea', + 'Wired', + 'Basket Weaving', + 'Coup', + 'Chappel Roan', + 'the juice', + 'Superman', + '#FCF', + 'Open Web', + ], + }) + + i.push({ + type: 'header', + key: 'starter-packs-header', + title: _(msg`Starter packs`), + description: _(msg`Find accounts to follow based on your interests.`), + icon: PersonGroup, + }) + i.push({ + type: 'suggestedStarterPacks', + key: 'suggested-starter-packs', + starterPacks: [ + { + uri: 'at://did:plc:ragtjsm2j2vknwkz3zp4oxrd/app.bsky.graph.starterpack/3kvaphb2hpf2u', + cid: '', + indexedAt: '', + record: { + $type: 'app.bsky.graph.starterpack', + description: + 'Engineers who work on or discuss the ATProtocol, both at Bluesky and in the community', + list: 'at://did:plc:ragtjsm2j2vknwkz3zp4oxrd/app.bsky.graph.list/3kvaphagg4e2l', + name: 'ATProtocol Hackers', + }, + creator: { + did: 'did:plc:ragtjsm2j2vknwkz3zp4oxrd', + handle: 'pfrazee.com', + displayName: 'Paul Frazee', + }, + }, + { + uri: 'at://did:plc:qrllvid7s54k4hnwtqxwetrf/app.bsky.graph.starterpack/3kvuh7u324m2c', + cid: '', + indexedAt: '', + record: { + $type: 'app.bsky.graph.starterpack', + createdAt: '2024-06-26T23:23:01.073Z', + description: + 'Legal practice, scholarship, journalism, and argument', + feeds: [], + list: 'at://did:plc:qrllvid7s54k4hnwtqxwetrf/app.bsky.graph.list/3kvuh7twnjc2m', + name: 'Bluesky for Law', + }, + creator: { + did: 'did:plc:qrllvid7s54k4hnwtqxwetrf', + handle: 'joshuajfriedman.com', + displayName: 'Joshua J. Friedman', + }, + }, + { + uri: 'at://did:plc:7exlcsle4mjfhu3wnhcgizz6/app.bsky.graph.starterpack/3laotg2fqva2h', + cid: '', + indexedAt: '', + record: { + $type: 'app.bsky.graph.starterpack', + createdAt: '2024-11-11T17:22:22.743Z', + description: 'people who work at the website, the verge dot com', + list: 'at://did:plc:7exlcsle4mjfhu3wnhcgizz6/app.bsky.graph.list/3laotg2bjok2d', + name: 'The Verge staff', + }, + creator: { + did: 'did:plc:7exlcsle4mjfhu3wnhcgizz6', + handle: 'theverge.com', + displayName: 'The Verge', + }, + }, + ], + }) + + i.push({ + type: 'header', + key: 'suggested-follows-header', + title: _(msg`Suggested accounts`), + description: _( + msg`Follow more accounts to get connected to your interests and build your network.`, + ), + icon: Person, + }) if (profiles) { // Currently the responses contain duplicate items. @@ -490,6 +596,18 @@ export function Explore() { /> ) } + case 'trendingTopics': { + return + } + case 'suggestedStarterPacks': { + return ( + + ) + } case 'profile': { return (