use real data in landing
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import {AppBskyGraphDefs, AtUri} from '@atproto/api'
|
||||||
|
|
||||||
import {isInvalidHandle} from 'lib/strings/handles'
|
import {isInvalidHandle} from 'lib/strings/handles'
|
||||||
|
|
||||||
export function makeProfileLink(
|
export function makeProfileLink(
|
||||||
@@ -35,3 +37,18 @@ export function makeSearchLink(props: {query: string; from?: 'me' | string}) {
|
|||||||
props.query + (props.from ? ` from:${props.from}` : ''),
|
props.query + (props.from ? ` from:${props.from}` : ''),
|
||||||
)}`
|
)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function makeStarterPackLink(
|
||||||
|
starterPackOrName:
|
||||||
|
| AppBskyGraphDefs.StarterPackViewBasic
|
||||||
|
| AppBskyGraphDefs.StarterPackView
|
||||||
|
| string,
|
||||||
|
rkey?: string,
|
||||||
|
) {
|
||||||
|
if (typeof starterPackOrName === 'string') {
|
||||||
|
return `/starter-pack/${starterPackOrName}/${rkey}`
|
||||||
|
} else {
|
||||||
|
const rkey = new AtUri(starterPackOrName.uri).rkey
|
||||||
|
return makeProfileLink(starterPackOrName.creator, 'starter-pack', rkey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export type CommonNavigatorParams = {
|
|||||||
MessagesConversation: {conversation: string; embed?: string}
|
MessagesConversation: {conversation: string; embed?: string}
|
||||||
MessagesSettings: undefined
|
MessagesSettings: undefined
|
||||||
StarterPack: {name: string; rkey: string}
|
StarterPack: {name: string; rkey: string}
|
||||||
StarterPackLanding: {id: string}
|
StarterPackLanding: {name: string; rkey: string}
|
||||||
StarterPackWizard: {
|
StarterPackWizard: {
|
||||||
mode: 'Create' | 'Edit'
|
mode: 'Create' | 'Edit'
|
||||||
id?: string
|
id?: string
|
||||||
@@ -105,6 +105,7 @@ export type AllNavigatorParams = CommonNavigatorParams & {
|
|||||||
MessagesTab: undefined
|
MessagesTab: undefined
|
||||||
Messages: {animation?: 'push' | 'pop'}
|
Messages: {animation?: 'push' | 'pop'}
|
||||||
StarterPack: {name: string; rkey: string}
|
StarterPack: {name: string; rkey: string}
|
||||||
|
StarterPackLanding: {name: string; rkey: string}
|
||||||
StarterPackWizard: {
|
StarterPackWizard: {
|
||||||
mode: 'Create' | 'Edit'
|
mode: 'Create' | 'Edit'
|
||||||
id?: string
|
id?: string
|
||||||
|
|||||||
+1
-1
@@ -41,6 +41,6 @@ export const router = new Router({
|
|||||||
MessagesSettings: '/messages/settings',
|
MessagesSettings: '/messages/settings',
|
||||||
MessagesConversation: '/messages/:conversation',
|
MessagesConversation: '/messages/:conversation',
|
||||||
StarterPack: '/starter-pack/:name/:rkey',
|
StarterPack: '/starter-pack/:name/:rkey',
|
||||||
StarterPackLanding: '/start/:id',
|
StarterPackLanding: '/start/:name/:rkey',
|
||||||
StarterPackWizard: '/starter-pack/create',
|
StarterPackWizard: '/starter-pack/create',
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {ScrollView, View} from 'react-native'
|
import {ScrollView, View} from 'react-native'
|
||||||
import {LinearGradient} from 'expo-linear-gradient'
|
import {LinearGradient} from 'expo-linear-gradient'
|
||||||
|
import {
|
||||||
|
AppBskyActorDefs,
|
||||||
|
AppBskyGraphDefs,
|
||||||
|
AppBskyGraphStarterpack,
|
||||||
|
} from '@atproto/api'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||||
|
|
||||||
import {CommonNavigatorParams} from 'lib/routes/types'
|
import {CommonNavigatorParams} from 'lib/routes/types'
|
||||||
import {useGate} from 'lib/statsig/statsig'
|
import {useResolveDidQuery} from 'state/queries/resolve-uri'
|
||||||
|
import {useStarterPackQuery} from 'state/queries/useStarterPackQuery'
|
||||||
import {useSetMinimalShellMode} from 'state/shell'
|
import {useSetMinimalShellMode} from 'state/shell'
|
||||||
import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
|
import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
|
||||||
import {UserAvatar} from 'view/com/util/UserAvatar'
|
import {UserAvatar} from 'view/com/util/UserAvatar'
|
||||||
@@ -15,94 +21,69 @@ import {Logo} from 'view/icons/Logo'
|
|||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
import {Divider} from '#/components/Divider'
|
import {Divider} from '#/components/Divider'
|
||||||
|
import {ListMaybePlaceholder} from '#/components/Lists'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
/**
|
|
||||||
* TEMPORARY CONTENT, DO NOT TRANSLATE
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* TEMPORARY CONTENT, DO NOT TRANSLATE
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* TEMPORARY CONTENT, DO NOT TRANSLATE
|
|
||||||
*/
|
|
||||||
|
|
||||||
const PLACEHOLDER_USERS = [
|
|
||||||
{
|
|
||||||
displayName: 'Bossett',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:jfhpnnst6flqway4eaeqzj2a/bafkreid42e2su4sju7hl2nm4ouacw3icvvytf7r6gab3pvc2qxhqhc5ji4@jpeg',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: 'hailey',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:oisofpd7lj26yvgiivf3lxsi/bafkreia4lpswywb5yx3gsezqb5io73kt7icw634ks4m4mmbfvp7e62cxku@jpeg',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: 'samuel',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:p2cp5gopk7mgjegy6wadk3ep/bafkreias5vktko4jpg4mwp4audptcbdfkb4o3cfyzt4426mj2h7ewwvg7q@jpeg',
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
displayName: 'Paul “Frazee” 🦋',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:ragtjsm2j2vknwkz3zp4oxrd/bafkreihhpqdyntku66himwor5wlhtdo44hllmngj2ofmbqnm25bdm454wq@jpeg',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: 'Jay',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:oky5czdrnfjpqslsw2a5iclo/bafkreihidru2xruxdxlvvcixc7lbgoudzicjbrdgacdhdhxyfw4yut4nfq@jpeg',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: 'Emily 🦋',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:vjug55kidv6sye7ykr5faxxn/bafkreia63347vwjt4sgfkedgvytodt22ugfck5o36qotwaflsf3qq5xj3y@jpeg',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: 'Rose 🌹',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:qjeavhlw222ppsre4rscd3n2/bafkreiehdi7v7bmz64anqam72ybtkkeodfe22sh7dcsh7m6wei2cf5liye@jpeg',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: 'dan',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:fpruhuo22xkm5o7ttr2ktxdo/bafkreif65cz6sp4cvwue6dnsy7lhy7o7vdelknwd6hermcbzg2npealz5q@jpeg',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export function LandingScreen({
|
export function LandingScreen({
|
||||||
navigation,
|
navigation,
|
||||||
|
route,
|
||||||
}: NativeStackScreenProps<CommonNavigatorParams, 'StarterPackLanding'>) {
|
}: NativeStackScreenProps<CommonNavigatorParams, 'StarterPackLanding'>) {
|
||||||
const {_} = useLingui()
|
const {name, rkey} = route.params
|
||||||
const gate = useGate()
|
|
||||||
const t = useTheme()
|
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: did,
|
||||||
|
isLoading: isLoadingDid,
|
||||||
|
isError: isErrorDid,
|
||||||
|
} = useResolveDidQuery(name)
|
||||||
|
const {
|
||||||
|
data: starterPack,
|
||||||
|
isLoading: isLoadingStarterPack,
|
||||||
|
isError: isErrorStarterPack,
|
||||||
|
} = useStarterPackQuery({did, rkey})
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
setMinimalShellMode(true)
|
||||||
|
return () => {
|
||||||
|
setMinimalShellMode(false)
|
||||||
|
}
|
||||||
|
}, [navigation, setMinimalShellMode])
|
||||||
|
|
||||||
|
if (!did || !starterPack) {
|
||||||
|
return (
|
||||||
|
<ListMaybePlaceholder
|
||||||
|
isLoading={isLoadingDid || isLoadingStarterPack}
|
||||||
|
isError={isErrorDid || isErrorStarterPack}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return <LandingScreenInner starterPack={starterPack} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function LandingScreenInner({
|
||||||
|
starterPack,
|
||||||
|
}: {
|
||||||
|
starterPack: AppBskyGraphDefs.StarterPackView
|
||||||
|
}) {
|
||||||
|
const {record, creator, listItemsSample, feeds, joinedWeekCount} = starterPack
|
||||||
|
const {_} = useLingui()
|
||||||
|
const t = useTheme()
|
||||||
|
|
||||||
const gradient =
|
const gradient =
|
||||||
t.name === 'light'
|
t.name === 'light'
|
||||||
? [t.palette.primary_500, t.palette.primary_300]
|
? [t.palette.primary_500, t.palette.primary_300]
|
||||||
: [t.palette.primary_600, t.palette.primary_400]
|
: [t.palette.primary_600, t.palette.primary_400]
|
||||||
|
|
||||||
const userSets = React.useMemo(() => {
|
const sampleProfiles = listItemsSample?.map(item => item.subject)
|
||||||
return {
|
const userSets = {
|
||||||
first: PLACEHOLDER_USERS.slice(0, 4),
|
first: sampleProfiles?.slice(0, 4),
|
||||||
second: PLACEHOLDER_USERS.slice(4, 8),
|
second: sampleProfiles?.slice(4, 8),
|
||||||
}
|
}
|
||||||
}, [])
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
if (!AppBskyGraphStarterpack.isRecord(record)) {
|
||||||
if (!gate('starter_packs_enabled')) {
|
return null
|
||||||
// @ts-expect-error idk
|
}
|
||||||
navigation.replace('Home')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
setMinimalShellMode(true)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
setMinimalShellMode(false)
|
|
||||||
}
|
|
||||||
}, [gate, navigation, setMinimalShellMode])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CenteredView style={a.flex_1}>
|
<CenteredView style={a.flex_1}>
|
||||||
@@ -117,18 +98,20 @@ export function LandingScreen({
|
|||||||
</View>
|
</View>
|
||||||
<View style={[a.align_center, a.gap_xs]}>
|
<View style={[a.align_center, a.gap_xs]}>
|
||||||
<Text style={[a.font_bold, a.text_5xl, {color: 'white'}]}>
|
<Text style={[a.font_bold, a.text_5xl, {color: 'white'}]}>
|
||||||
Science
|
{record.name}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={[a.font_bold, a.text_md, {color: 'white'}]}>
|
<Text style={[a.font_bold, a.text_md, {color: 'white'}]}>
|
||||||
Starter pack by Bossett
|
Starter pack by {creator.displayName || `@${creator.handle}`}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</LinearGradient>
|
</LinearGradient>
|
||||||
<View style={[a.gap_md, a.mt_lg, a.mx_lg]}>
|
<View style={[a.gap_md, a.mt_lg, a.mx_lg]}>
|
||||||
<Text
|
{!!joinedWeekCount && joinedWeekCount >= 50 && (
|
||||||
style={[a.text_md, a.text_center, t.atoms.text_contrast_medium]}>
|
<Text
|
||||||
186 joined this week
|
style={[a.text_md, a.text_center, t.atoms.text_contrast_medium]}>
|
||||||
</Text>
|
{joinedWeekCount} joined this week!
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
label={_(msg`Join Bluesky now`)}
|
label={_(msg`Join Bluesky now`)}
|
||||||
onPress={() => {}}
|
onPress={() => {}}
|
||||||
@@ -141,39 +124,60 @@ export function LandingScreen({
|
|||||||
</Button>
|
</Button>
|
||||||
<View style={[a.gap_xl, a.mt_md]}>
|
<View style={[a.gap_xl, a.mt_md]}>
|
||||||
<Text style={[a.text_md, t.atoms.text_contrast_medium]}>
|
<Text style={[a.text_md, t.atoms.text_contrast_medium]}>
|
||||||
(This is the description) A collection of feeds and users to get
|
{record.description}
|
||||||
you started with the science community on Bluesky!
|
|
||||||
</Text>
|
</Text>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Text style={[a.text_md, t.atoms.text_contrast_medium]}>
|
{!!feeds?.length && (
|
||||||
Join Bluesky now to subscribe to these feeds:
|
<>
|
||||||
</Text>
|
<Text style={[a.text_md, t.atoms.text_contrast_medium]}>
|
||||||
<View
|
<Trans>Join Bluesky now to subscribe to these feeds:</Trans>
|
||||||
style={[
|
</Text>
|
||||||
t.atoms.bg_contrast_25,
|
<View
|
||||||
a.rounded_sm,
|
style={[
|
||||||
{pointerEvents: 'none'},
|
t.atoms.bg_contrast_25,
|
||||||
]}>
|
a.rounded_sm,
|
||||||
<FeedSourceCard
|
{pointerEvents: 'none'},
|
||||||
feedUri="at://did:plc:jfhpnnst6flqway4eaeqzj2a/app.bsky.feed.generator/for-science"
|
]}>
|
||||||
hideTopBorder={true}
|
<FeedSourceCard
|
||||||
/>
|
feedUri="at://did:plc:jfhpnnst6flqway4eaeqzj2a/app.bsky.feed.generator/for-science"
|
||||||
<FeedSourceCard feedUri="at://did:plc:upmfcx5muayjhkg5sltj625o/app.bsky.feed.generator/aaachrckxlsh2" />
|
hideTopBorder={true}
|
||||||
</View>
|
/>
|
||||||
<Text style={[a.mt_sm, a.text_md, t.atoms.text_contrast_medium]}>
|
<FeedSourceCard feedUri="at://did:plc:upmfcx5muayjhkg5sltj625o/app.bsky.feed.generator/aaachrckxlsh2" />
|
||||||
You'll also follow these people and many others!
|
</View>
|
||||||
</Text>
|
</>
|
||||||
<View
|
)}
|
||||||
style={[
|
|
||||||
t.atoms.bg_contrast_25,
|
{sampleProfiles?.length && (
|
||||||
a.rounded_sm,
|
<>
|
||||||
a.px_xs,
|
<Text
|
||||||
a.py_md,
|
style={[a.mt_sm, a.text_md, t.atoms.text_contrast_medium]}>
|
||||||
a.gap_xl,
|
{feeds?.length ? (
|
||||||
]}>
|
<Trans>
|
||||||
<UserSet users={userSets.first} />
|
You'll also follow these people and many others!
|
||||||
<UserSet users={userSets.second} />
|
</Trans>
|
||||||
</View>
|
) : (
|
||||||
|
<Trans>
|
||||||
|
Follow these people and many others to get started!
|
||||||
|
</Trans>
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
t.atoms.bg_contrast_25,
|
||||||
|
a.rounded_sm,
|
||||||
|
a.px_xs,
|
||||||
|
a.py_md,
|
||||||
|
a.gap_xl,
|
||||||
|
]}>
|
||||||
|
{!!userSets.first?.length && (
|
||||||
|
<ProfilesSet profiles={userSets.first} />
|
||||||
|
)}
|
||||||
|
{!!userSets.second?.length && (
|
||||||
|
<ProfilesSet profiles={userSets.second} />
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
@@ -181,7 +185,7 @@ export function LandingScreen({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function User({displayName, avatar}: {displayName: string; avatar: string}) {
|
function User({displayName, avatar}: {displayName: string; avatar?: string}) {
|
||||||
return (
|
return (
|
||||||
<View style={[a.flex_1, a.align_center, a.gap_sm]}>
|
<View style={[a.flex_1, a.align_center, a.gap_sm]}>
|
||||||
<UserAvatar size={64} avatar={avatar} />
|
<UserAvatar size={64} avatar={avatar} />
|
||||||
@@ -192,13 +196,20 @@ function User({displayName, avatar}: {displayName: string; avatar: string}) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function UserSet({users}: {users: {displayName: string; avatar: string}[]}) {
|
function ProfilesSet({
|
||||||
|
profiles,
|
||||||
|
}: {
|
||||||
|
profiles: AppBskyActorDefs.ProfileViewBasic[]
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<View style={[a.flex_row, a.gap_xs, a.align_center, a.justify_between]}>
|
<View style={[a.flex_row, a.gap_xs, a.align_center, a.justify_between]}>
|
||||||
<User displayName={users[0].displayName} avatar={users[0].avatar} />
|
{profiles.map(profile => (
|
||||||
<User displayName={users[1].displayName} avatar={users[1].avatar} />
|
<User
|
||||||
<User displayName={users[2].displayName} avatar={users[2].avatar} />
|
key={profile.did}
|
||||||
<User displayName={users[3].displayName} avatar={users[3].avatar} />
|
displayName={profile.displayName || `@${profile.handle}`}
|
||||||
|
avatar={profile.avatar}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {AppBskyActorDefs} from '@atproto/api'
|
|||||||
|
|
||||||
import {useBottomBarOffset} from 'lib/hooks/useBottomBarOffset'
|
import {useBottomBarOffset} from 'lib/hooks/useBottomBarOffset'
|
||||||
import {isNative} from 'platform/detection'
|
import {isNative} from 'platform/detection'
|
||||||
|
import {useListMembersQuery} from 'state/queries/list-members'
|
||||||
import {ProfileCardWithFollowBtn} from 'view/com/profile/ProfileCard'
|
import {ProfileCardWithFollowBtn} from 'view/com/profile/ProfileCard'
|
||||||
import {List, ListRef} from 'view/com/util/List'
|
import {List, ListRef} from 'view/com/util/List'
|
||||||
import {SectionRef} from '#/screens/Profile/Sections/types'
|
import {SectionRef} from '#/screens/Profile/Sections/types'
|
||||||
@@ -17,16 +18,19 @@ function keyExtractor(item: AppBskyActorDefs.ProfileViewBasic, index: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ProfilesListProps {
|
interface ProfilesListProps {
|
||||||
profiles: AppBskyActorDefs.ProfileViewBasic[]
|
listUri: string
|
||||||
headerHeight: number
|
headerHeight: number
|
||||||
scrollElRef: ListRef
|
scrollElRef: ListRef
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProfilesList = React.forwardRef<SectionRef, ProfilesListProps>(
|
export const ProfilesList = React.forwardRef<SectionRef, ProfilesListProps>(
|
||||||
function ProfilesListImpl({profiles, headerHeight, scrollElRef}, ref) {
|
function ProfilesListImpl({listUri, headerHeight, scrollElRef}, ref) {
|
||||||
const [initialHeaderHeight] = React.useState(headerHeight)
|
const [initialHeaderHeight] = React.useState(headerHeight)
|
||||||
const bottomBarOffset = useBottomBarOffset(20)
|
const bottomBarOffset = useBottomBarOffset(20)
|
||||||
|
|
||||||
|
const {data} = useListMembersQuery(listUri)
|
||||||
|
const profiles = data?.pages.flatMap(p => p.items[0].subject)
|
||||||
|
|
||||||
const onScrollToTop = useCallback(() => {
|
const onScrollToTop = useCallback(() => {
|
||||||
scrollElRef.current?.scrollToOffset({
|
scrollElRef.current?.scrollToOffset({
|
||||||
animated: isNative,
|
animated: isNative,
|
||||||
@@ -49,7 +53,6 @@ export const ProfilesList = React.forwardRef<SectionRef, ProfilesListProps>(
|
|||||||
<View style={[{height: initialHeaderHeight + bottomBarOffset}]} />
|
<View style={[{height: initialHeaderHeight + bottomBarOffset}]} />
|
||||||
}
|
}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
// @ts-ignore
|
|
||||||
desktopFixedHeight
|
desktopFixedHeight
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
|
import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||||
|
|
||||||
|
import {makeProfileLink} from 'lib/routes/links'
|
||||||
import {CommonNavigatorParams} from 'lib/routes/types'
|
import {CommonNavigatorParams} from 'lib/routes/types'
|
||||||
import {shareUrl} from 'lib/sharing'
|
import {shareUrl} from 'lib/sharing'
|
||||||
import {isWeb} from 'platform/detection'
|
import {isWeb} from 'platform/detection'
|
||||||
|
import {useResolveDidQuery} from 'state/queries/resolve-uri'
|
||||||
|
import {useStarterPackQuery} from 'state/queries/useStarterPackQuery'
|
||||||
|
import {useSession} from 'state/session'
|
||||||
import {PagerWithHeader} from 'view/com/pager/PagerWithHeader'
|
import {PagerWithHeader} from 'view/com/pager/PagerWithHeader'
|
||||||
import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader'
|
import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader'
|
||||||
import {CenteredView} from 'view/com/util/Views'
|
import {CenteredView} from 'view/com/util/Views'
|
||||||
@@ -17,148 +22,100 @@ import {Button, ButtonText} from '#/components/Button'
|
|||||||
import {useDialogControl} from '#/components/Dialog'
|
import {useDialogControl} from '#/components/Dialog'
|
||||||
import {ArrowOutOfBox_Stroke2_Corner0_Rounded as ArrowOutOfBox} from '#/components/icons/ArrowOutOfBox'
|
import {ArrowOutOfBox_Stroke2_Corner0_Rounded as ArrowOutOfBox} from '#/components/icons/ArrowOutOfBox'
|
||||||
import {QrCode_Stroke2_Corner0_Rounded as QrCode} from '#/components/icons/QrCode'
|
import {QrCode_Stroke2_Corner0_Rounded as QrCode} from '#/components/icons/QrCode'
|
||||||
|
import {ListMaybePlaceholder} from '#/components/Lists'
|
||||||
import * as Menu from '#/components/Menu'
|
import * as Menu from '#/components/Menu'
|
||||||
import {QrCodeDialog} from '#/components/StarterPack/QrCodeDialog'
|
import {QrCodeDialog} from '#/components/StarterPack/QrCodeDialog'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
/**
|
export function StarterPackScreen({
|
||||||
* TEMPORARY CONTENT, DO NOT TRANSLATE
|
route,
|
||||||
*/
|
}: NativeStackScreenProps<CommonNavigatorParams, 'StarterPackLanding'>) {
|
||||||
/**
|
const {name, rkey} = route.params
|
||||||
* TEMPORARY CONTENT, DO NOT TRANSLATE
|
const {
|
||||||
*/
|
data: did,
|
||||||
/**
|
isLoading: isLoadingDid,
|
||||||
* TEMPORARY CONTENT, DO NOT TRANSLATE
|
isError: isErrorDid,
|
||||||
*/
|
} = useResolveDidQuery(name)
|
||||||
|
const {
|
||||||
|
data: starterPack,
|
||||||
|
isLoading: isLoadingStarterPack,
|
||||||
|
isError: isErrorStarterPack,
|
||||||
|
} = useStarterPackQuery({did, rkey})
|
||||||
|
|
||||||
const PLACEHOLDER_USERS = [
|
if (!did || !starterPack) {
|
||||||
{
|
return (
|
||||||
did: 'did:plc:qjeavhlw222ppsre4rscd3n2',
|
<ListMaybePlaceholder
|
||||||
handle: 'test.handle',
|
isLoading={isLoadingDid || isLoadingStarterPack}
|
||||||
displayName: 'Bossett',
|
isError={isErrorDid || isErrorStarterPack}
|
||||||
avatar:
|
/>
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:jfhpnnst6flqway4eaeqzj2a/bafkreid42e2su4sju7hl2nm4ouacw3icvvytf7r6gab3pvc2qxhqhc5ji4@jpeg',
|
)
|
||||||
description: 'he/him\n' + '📍 🇦🇺',
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:qjeavhlw222ppsre4rscd3n2',
|
|
||||||
handle: 'test.handle',
|
|
||||||
displayName: 'hailey',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:oisofpd7lj26yvgiivf3lxsi/bafkreia4lpswywb5yx3gsezqb5io73kt7icw634ks4m4mmbfvp7e62cxku@jpeg',
|
|
||||||
description:
|
|
||||||
'React Native @ Bluesky\n' + 'Tomato hater 🍅 ❌\n' + 'she/her',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:qjeavhlw222ppsre4rscd3n2',
|
|
||||||
handle: 'test.handle',
|
|
||||||
displayName: 'samuel',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:p2cp5gopk7mgjegy6wadk3ep/bafkreias5vktko4jpg4mwp4audptcbdfkb4o3cfyzt4426mj2h7ewwvg7q@jpeg',
|
|
||||||
description: 'formerly mozzius. developer at bluesky\n' + '📍London',
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
const items = [
|
||||||
did: 'did:plc:qjeavhlw222ppsre4rscd3n2',
|
...(starterPack.list ? ['People'] : []),
|
||||||
handle: 'test.handle',
|
...(starterPack.feeds ? ['Feeds'] : []),
|
||||||
displayName: 'Paul “Frazee” 🦋',
|
]
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:ragtjsm2j2vknwkz3zp4oxrd/bafkreihhpqdyntku66himwor5wlhtdo44hllmngj2ofmbqnm25bdm454wq@jpeg',
|
|
||||||
description: 'Developer at Bluesky. Go Mets.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:qjeavhlw222ppsre4rscd3n2',
|
|
||||||
handle: 'test.handle',
|
|
||||||
displayName: 'Jay',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:oky5czdrnfjpqslsw2a5iclo/bafkreihidru2xruxdxlvvcixc7lbgoudzicjbrdgacdhdhxyfw4yut4nfq@jpeg',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:qjeavhlw222ppsre4rscd3n2',
|
|
||||||
handle: 'test.handle',
|
|
||||||
displayName: 'Emily 🦋',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:vjug55kidv6sye7ykr5faxxn/bafkreia63347vwjt4sgfkedgvytodt22ugfck5o36qotwaflsf3qq5xj3y@jpeg',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:qjeavhlw222ppsre4rscd3n2',
|
|
||||||
handle: 'test.handle',
|
|
||||||
displayName: 'Rose 🌹',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:qjeavhlw222ppsre4rscd3n2/bafkreiehdi7v7bmz64anqam72ybtkkeodfe22sh7dcsh7m6wei2cf5liye@jpeg',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:qjeavhlw222ppsre4rscd3n2',
|
|
||||||
handle: 'test.handle',
|
|
||||||
displayName: 'dan',
|
|
||||||
avatar:
|
|
||||||
'https://cdn.bsky.app/img/avatar/plain/did:plc:fpruhuo22xkm5o7ttr2ktxdo/bafkreif65cz6sp4cvwue6dnsy7lhy7o7vdelknwd6hermcbzg2npealz5q@jpeg',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const PLACEHOLDER_FEEDS = [
|
|
||||||
'at://did:plc:jfhpnnst6flqway4eaeqzj2a/app.bsky.feed.generator/for-science',
|
|
||||||
'at://did:plc:upmfcx5muayjhkg5sltj625o/app.bsky.feed.generator/aaachrckxlsh2',
|
|
||||||
]
|
|
||||||
|
|
||||||
export function StarterPackScreen({}: NativeStackScreenProps<
|
|
||||||
CommonNavigatorParams,
|
|
||||||
'StarterPackLanding'
|
|
||||||
>) {
|
|
||||||
// const {id} = route.params
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CenteredView style={[a.h_full_vh]}>
|
<CenteredView style={[a.h_full_vh]}>
|
||||||
<StarterPackScreenInner />
|
<View style={isWeb ? {minHeight: '100%'} : {height: '100%'}}>
|
||||||
|
<PagerWithHeader
|
||||||
|
items={items}
|
||||||
|
isHeaderReady={true}
|
||||||
|
renderHeader={() => <Header starterPack={starterPack} />}>
|
||||||
|
{starterPack.list
|
||||||
|
? ({headerHeight, scrollElRef}) => (
|
||||||
|
<ProfilesList
|
||||||
|
key={0}
|
||||||
|
listUri={starterPack.list.uri}
|
||||||
|
headerHeight={headerHeight}
|
||||||
|
// @ts-expect-error
|
||||||
|
scrollElRef={scrollElRef}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
{starterPack.feeds
|
||||||
|
? ({headerHeight, scrollElRef}) => (
|
||||||
|
<FeedsList
|
||||||
|
key={1}
|
||||||
|
feeds={starterPack.feeds}
|
||||||
|
headerHeight={headerHeight}
|
||||||
|
// @ts-expect-error
|
||||||
|
scrollElRef={scrollElRef}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
</PagerWithHeader>
|
||||||
|
</View>
|
||||||
</CenteredView>
|
</CenteredView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function StarterPackScreenInner() {
|
function Header({
|
||||||
const isOwn = true
|
starterPack,
|
||||||
|
}: {
|
||||||
return (
|
starterPack: AppBskyGraphDefs.StarterPackView
|
||||||
<View style={isWeb ? {minHeight: '100%'} : {height: '100%'}}>
|
}) {
|
||||||
<PagerWithHeader
|
|
||||||
items={['People', 'Feeds']}
|
|
||||||
isHeaderReady={true}
|
|
||||||
renderHeader={() => <Header isOwn={isOwn} />}>
|
|
||||||
{({headerHeight, scrollElRef}) => (
|
|
||||||
<ProfilesList
|
|
||||||
key={0}
|
|
||||||
profiles={PLACEHOLDER_USERS}
|
|
||||||
headerHeight={headerHeight}
|
|
||||||
// @ts-expect-error
|
|
||||||
scrollElRef={scrollElRef}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{({headerHeight, scrollElRef}) => (
|
|
||||||
<FeedsList
|
|
||||||
key={1}
|
|
||||||
feeds={PLACEHOLDER_FEEDS}
|
|
||||||
headerHeight={headerHeight}
|
|
||||||
// @ts-expect-error
|
|
||||||
scrollElRef={scrollElRef}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</PagerWithHeader>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function Header({isOwn}: {isOwn: boolean}) {
|
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const {currentAccount} = useSession()
|
||||||
const qrCodeDialogControl = useDialogControl()
|
const qrCodeDialogControl = useDialogControl()
|
||||||
|
|
||||||
|
const {record, creator} = starterPack
|
||||||
|
const isOwn = creator.did === currentAccount?.did
|
||||||
|
|
||||||
|
if (!AppBskyGraphStarterpack.isRecord(record)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ProfileSubpageHeader
|
<ProfileSubpageHeader
|
||||||
isLoading={false}
|
isLoading={false}
|
||||||
href=""
|
href={makeProfileLink(creator)}
|
||||||
title="Science"
|
title={record.name}
|
||||||
isOwner={false}
|
isOwner={isOwn}
|
||||||
avatar={undefined}
|
avatar={undefined}
|
||||||
creator={undefined}
|
creator={creator}
|
||||||
avatarType="starter-pack">
|
avatarType="starter-pack">
|
||||||
<View style={[a.flex_row, a.gap_sm]}>
|
<View style={[a.flex_row, a.gap_sm]}>
|
||||||
<Menu.Root>
|
<Menu.Root>
|
||||||
@@ -218,10 +175,7 @@ function Header({isOwn}: {isOwn: boolean}) {
|
|||||||
</View>
|
</View>
|
||||||
</ProfileSubpageHeader>
|
</ProfileSubpageHeader>
|
||||||
<View style={[a.px_md, a.py_lg]}>
|
<View style={[a.px_md, a.py_lg]}>
|
||||||
<Text style={[a.text_md]}>
|
<Text style={[a.text_md]}>{record.description}</Text>
|
||||||
(This is the description) A collection of feeds and users to get you
|
|
||||||
started with the science community on Bluesky!
|
|
||||||
</Text>
|
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<QrCodeDialog control={qrCodeDialogControl} url="https://bsky.app" />
|
<QrCodeDialog control={qrCodeDialogControl} url="https://bsky.app" />
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
import {AppBskyGraphGetStarterPack} from '@atproto/api'
|
import {StarterPackView} from '@atproto/api/dist/client/types/app/bsky/graph/defs'
|
||||||
import {useMutation} from '@tanstack/react-query'
|
import {useMutation, useQuery} from '@tanstack/react-query'
|
||||||
import {useQuery} from 'react-query'
|
|
||||||
|
|
||||||
import {STALE} from 'state/queries/index'
|
import {STALE} from 'state/queries/index'
|
||||||
import {useAgent, useSession} from 'state/session'
|
import {useAgent, useSession} from 'state/session'
|
||||||
|
|
||||||
const RQKEY_ROOT = 'starter-pack'
|
const RQKEY_ROOT = 'starter-pack'
|
||||||
|
|
||||||
export function useStarterPackQuery({id}: {id: string}) {
|
export function useStarterPackQuery({did, rkey}: {did?: string; rkey: string}) {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
return useQuery<AppBskyGraphGetStarterPack.OutputSchema>({
|
const uri = `at://${did}/app.bsky.graph.starterpack/${rkey}`
|
||||||
queryKey: [RQKEY_ROOT, id],
|
|
||||||
|
return useQuery<StarterPackView>({
|
||||||
|
queryKey: [RQKEY_ROOT, did, rkey],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await agent.app.bsky.graph.getStarterPack({
|
const res = await agent.app.bsky.graph.getStarterPack({
|
||||||
starterPack: id,
|
starterPack: uri,
|
||||||
})
|
})
|
||||||
return res.data
|
return res.data.starterPack
|
||||||
},
|
},
|
||||||
|
enabled: Boolean(did),
|
||||||
staleTime: STALE.MINUTES.FIVE,
|
staleTime: STALE.MINUTES.FIVE,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user