Rework web onboarding
parent
5d9534ca72
commit
5e765bf1cb
|
@ -148,3 +148,110 @@ export const HITSLOP_10 = createHitslop(10)
|
||||||
export const HITSLOP_20 = createHitslop(20)
|
export const HITSLOP_20 = createHitslop(20)
|
||||||
export const HITSLOP_30 = createHitslop(30)
|
export const HITSLOP_30 = createHitslop(30)
|
||||||
export const BACK_HITSLOP = HITSLOP_30
|
export const BACK_HITSLOP = HITSLOP_30
|
||||||
|
|
||||||
|
export const RECOMMENDED_FEEDS = [
|
||||||
|
{
|
||||||
|
did: 'did:plc:hsqwcidfez66lwm3gxhfv5in',
|
||||||
|
rkey: 'aaaf2pqeodmpy',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:gekdk2nd47gkk3utfz2xf7cn',
|
||||||
|
rkey: 'aaap4tbjcfe5y',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:5rw2on4i56btlcajojaxwcat',
|
||||||
|
rkey: 'aaao6g552b33o',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:jfhpnnst6flqway4eaeqzj2a',
|
||||||
|
rkey: 'for-science',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:7q4nnnxawajbfaq7to5dpbsy',
|
||||||
|
rkey: 'bsky-news',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:jcoy7v3a2t4rcfdh6i4kza25',
|
||||||
|
rkey: 'astro',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:tenurhgjptubkk5zf5qhi3og',
|
||||||
|
rkey: 'h-nba',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:vpkhqolt662uhesyj6nxm7ys',
|
||||||
|
rkey: 'devfeed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:cndfx4udwgvpjaakvxvh7wm5',
|
||||||
|
rkey: 'flipboard-tech',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:w4xbfzo7kqfes5zb7r6qv3rw',
|
||||||
|
rkey: 'blacksky',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:lptjvw6ut224kwrj7ub3sqbe',
|
||||||
|
rkey: 'aaaotfjzjplna',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:gkvpokm7ec5j5yxls6xk4e3z',
|
||||||
|
rkey: 'formula-one',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:q6gjnaw2blty4crticxkmujt',
|
||||||
|
rkey: 'positivifeed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:l72uci4styb4jucsgcrrj5ap',
|
||||||
|
rkey: 'aaao5dzfm36u4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:k3jkadxv5kkjgs6boyon7m6n',
|
||||||
|
rkey: 'aaaavlyvqzst2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:nkahctfdi6bxk72umytfwghw',
|
||||||
|
rkey: 'aaado2uvfsc6w',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:epihigio3d7un7u3gpqiy5gv',
|
||||||
|
rkey: 'aaaekwsc7zsvs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:qiknc4t5rq7yngvz7g4aezq7',
|
||||||
|
rkey: 'aaaejxlobe474',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:mlq4aycufcuolr7ax6sezpc4',
|
||||||
|
rkey: 'aaaoudweck6uy',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:rcez5hcvq3vzlu5x7xrjyccg',
|
||||||
|
rkey: 'aaadzjxbcddzi',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:lnxbuzaenlwjrncx6sc4cfdr',
|
||||||
|
rkey: 'aaab2vesjtszc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:x3cya3wkt4n6u4ihmvpsc5if',
|
||||||
|
rkey: 'aaacynbxwimok',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:abv47bjgzjgoh3yrygwoi36x',
|
||||||
|
rkey: 'aaagt6amuur5e',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:ffkgesg3jsv2j7aagkzrtcvt',
|
||||||
|
rkey: 'aaacjerk7gwek',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:geoqe3qls5mwezckxxsewys2',
|
||||||
|
rkey: 'aaai43yetqshu',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
did: 'did:plc:2wqomm3tjqbgktbrfwgvrw34',
|
||||||
|
rkey: 'authors',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
|
@ -67,6 +67,19 @@ export class CustomFeedModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async pin() {
|
||||||
|
try {
|
||||||
|
await this.rootStore.preferences.addPinnedFeed(this.uri)
|
||||||
|
} catch (error) {
|
||||||
|
this.rootStore.log.error('Failed to pin feed', error)
|
||||||
|
} finally {
|
||||||
|
track('CustomFeed:Pin', {
|
||||||
|
name: this.data.displayName,
|
||||||
|
uri: this.uri,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async unsave() {
|
async unsave() {
|
||||||
try {
|
try {
|
||||||
await this.rootStore.preferences.removeSavedFeed(this.uri)
|
await this.rootStore.preferences.removeSavedFeed(this.uri)
|
||||||
|
|
|
@ -6,7 +6,6 @@ import {s} from 'lib/styles'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {useAnalytics} from 'lib/analytics/analytics'
|
import {useAnalytics} from 'lib/analytics/analytics'
|
||||||
import {CenteredView} from '../util/Views'
|
|
||||||
import {Welcome} from './onboarding/Welcome'
|
import {Welcome} from './onboarding/Welcome'
|
||||||
import {RecommendedFeeds} from './onboarding/RecommendedFeeds'
|
import {RecommendedFeeds} from './onboarding/RecommendedFeeds'
|
||||||
|
|
||||||
|
@ -24,17 +23,15 @@ export const Onboarding = observer(() => {
|
||||||
const skip = () => store.onboarding.skip()
|
const skip = () => store.onboarding.skip()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CenteredView style={[s.hContentRegion, pal.view]}>
|
<SafeAreaView testID="onboardingView" style={[s.hContentRegion, pal.view]}>
|
||||||
<SafeAreaView testID="noSessionView" style={s.hContentRegion}>
|
<ErrorBoundary>
|
||||||
<ErrorBoundary>
|
{store.onboarding.step === 'Welcome' && (
|
||||||
{store.onboarding.step === 'Welcome' && (
|
<Welcome skip={skip} next={next} />
|
||||||
<Welcome skip={skip} next={next} />
|
)}
|
||||||
)}
|
{store.onboarding.step === 'RecommendedFeeds' && (
|
||||||
{store.onboarding.step === 'RecommendedFeeds' && (
|
<RecommendedFeeds next={next} />
|
||||||
<RecommendedFeeds next={next} />
|
)}
|
||||||
)}
|
</ErrorBoundary>
|
||||||
</ErrorBoundary>
|
</SafeAreaView>
|
||||||
</SafeAreaView>
|
|
||||||
</CenteredView>
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -9,113 +9,7 @@ import {useCustomFeed} from 'lib/hooks/useCustomFeed'
|
||||||
import {makeRecordUri} from 'lib/strings/url-helpers'
|
import {makeRecordUri} from 'lib/strings/url-helpers'
|
||||||
import {ViewHeader} from 'view/com/util/ViewHeader'
|
import {ViewHeader} from 'view/com/util/ViewHeader'
|
||||||
import {isDesktopWeb} from 'platform/detection'
|
import {isDesktopWeb} from 'platform/detection'
|
||||||
|
import {RECOMMENDED_FEEDS} from 'lib/constants'
|
||||||
const TEMPORARY_RECOMMENDED_FEEDS = [
|
|
||||||
{
|
|
||||||
did: 'did:plc:hsqwcidfez66lwm3gxhfv5in',
|
|
||||||
rkey: 'aaaf2pqeodmpy',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:gekdk2nd47gkk3utfz2xf7cn',
|
|
||||||
rkey: 'aaap4tbjcfe5y',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:5rw2on4i56btlcajojaxwcat',
|
|
||||||
rkey: 'aaao6g552b33o',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:jfhpnnst6flqway4eaeqzj2a',
|
|
||||||
rkey: 'for-science',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:7q4nnnxawajbfaq7to5dpbsy',
|
|
||||||
rkey: 'bsky-news',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:jcoy7v3a2t4rcfdh6i4kza25',
|
|
||||||
rkey: 'astro',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:tenurhgjptubkk5zf5qhi3og',
|
|
||||||
rkey: 'h-nba',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:vpkhqolt662uhesyj6nxm7ys',
|
|
||||||
rkey: 'devfeed',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:cndfx4udwgvpjaakvxvh7wm5',
|
|
||||||
rkey: 'flipboard-tech',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:w4xbfzo7kqfes5zb7r6qv3rw',
|
|
||||||
rkey: 'blacksky',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:lptjvw6ut224kwrj7ub3sqbe',
|
|
||||||
rkey: 'aaaotfjzjplna',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:gkvpokm7ec5j5yxls6xk4e3z',
|
|
||||||
rkey: 'formula-one',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:q6gjnaw2blty4crticxkmujt',
|
|
||||||
rkey: 'positivifeed',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:l72uci4styb4jucsgcrrj5ap',
|
|
||||||
rkey: 'aaao5dzfm36u4',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:k3jkadxv5kkjgs6boyon7m6n',
|
|
||||||
rkey: 'aaaavlyvqzst2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:nkahctfdi6bxk72umytfwghw',
|
|
||||||
rkey: 'aaado2uvfsc6w',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:epihigio3d7un7u3gpqiy5gv',
|
|
||||||
rkey: 'aaaekwsc7zsvs',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:qiknc4t5rq7yngvz7g4aezq7',
|
|
||||||
rkey: 'aaaejxlobe474',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:mlq4aycufcuolr7ax6sezpc4',
|
|
||||||
rkey: 'aaaoudweck6uy',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:rcez5hcvq3vzlu5x7xrjyccg',
|
|
||||||
rkey: 'aaadzjxbcddzi',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:lnxbuzaenlwjrncx6sc4cfdr',
|
|
||||||
rkey: 'aaab2vesjtszc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:x3cya3wkt4n6u4ihmvpsc5if',
|
|
||||||
rkey: 'aaacynbxwimok',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:abv47bjgzjgoh3yrygwoi36x',
|
|
||||||
rkey: 'aaagt6amuur5e',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:ffkgesg3jsv2j7aagkzrtcvt',
|
|
||||||
rkey: 'aaacjerk7gwek',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:geoqe3qls5mwezckxxsewys2',
|
|
||||||
rkey: 'aaai43yetqshu',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
did: 'did:plc:2wqomm3tjqbgktbrfwgvrw34',
|
|
||||||
rkey: 'authors',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
next: () => void
|
next: () => void
|
||||||
|
@ -132,7 +26,7 @@ export const RecommendedFeeds = observer(({next}: Props) => {
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<FlatList
|
<FlatList
|
||||||
data={TEMPORARY_RECOMMENDED_FEEDS}
|
data={RECOMMENDED_FEEDS}
|
||||||
renderItem={({item}) => <Item item={item} />}
|
renderItem={({item}) => <Item item={item} />}
|
||||||
keyExtractor={item => item.did + item.rkey}
|
keyExtractor={item => item.did + item.rkey}
|
||||||
style={{flex: 1}}
|
style={{flex: 1}}
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
import React from 'react'
|
||||||
|
import {FlatList, StyleSheet, View} from 'react-native'
|
||||||
|
import {observer} from 'mobx-react-lite'
|
||||||
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
|
import {Text} from 'view/com/util/text/Text'
|
||||||
|
import {TitleColumnLayout} from 'view/com/util/layouts/TitleColumnLayout'
|
||||||
|
import {UserAvatar} from 'view/com/util/UserAvatar'
|
||||||
|
import {Button} from 'view/com/util/forms/Button'
|
||||||
|
import * as Toast from 'view/com/util/Toast'
|
||||||
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
|
import {useCustomFeed} from 'lib/hooks/useCustomFeed'
|
||||||
|
import {makeRecordUri} from 'lib/strings/url-helpers'
|
||||||
|
import {sanitizeHandle} from 'lib/strings/handles'
|
||||||
|
import {HeartIcon} from 'lib/icons'
|
||||||
|
import {RECOMMENDED_FEEDS} from 'lib/constants'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
next: () => void
|
||||||
|
}
|
||||||
|
export const RecommendedFeeds = observer(({next}: Props) => {
|
||||||
|
const pal = usePalette('default')
|
||||||
|
|
||||||
|
const title = (
|
||||||
|
<>
|
||||||
|
<Text style={[pal.textLight, styles.title1]}>Choose your</Text>
|
||||||
|
<Text style={[pal.link, styles.title2]}>Recomended</Text>
|
||||||
|
<Text style={[pal.link, styles.title2]}>Feeds</Text>
|
||||||
|
<Text type="2xl-medium" style={[pal.textLight, styles.description]}>
|
||||||
|
Feeds are created by users to curate content. Choose some feeds that you
|
||||||
|
find interesting.
|
||||||
|
</Text>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
marginTop: 20,
|
||||||
|
}}>
|
||||||
|
<Button onPress={next} testID="continueBtn">
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingLeft: 2,
|
||||||
|
gap: 6,
|
||||||
|
}}>
|
||||||
|
<Text
|
||||||
|
type="2xl-medium"
|
||||||
|
style={{color: '#fff', position: 'relative', top: -1}}>
|
||||||
|
Done
|
||||||
|
</Text>
|
||||||
|
<FontAwesomeIcon icon="angle-right" color="#fff" size={14} />
|
||||||
|
</View>
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TitleColumnLayout
|
||||||
|
testID="recommendedFeedsScreen"
|
||||||
|
title={title}
|
||||||
|
horizontal
|
||||||
|
titleStyle={{minWidth: 470}}
|
||||||
|
contentStyle={{paddingHorizontal: 0}}>
|
||||||
|
<FlatList
|
||||||
|
data={RECOMMENDED_FEEDS}
|
||||||
|
renderItem={({item}) => <Item {...item} />}
|
||||||
|
keyExtractor={item => item.did + item.rkey}
|
||||||
|
style={{flex: 1}}
|
||||||
|
/>
|
||||||
|
</TitleColumnLayout>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const Item = observer(({did, rkey}: {did: string; rkey: string}) => {
|
||||||
|
const pal = usePalette('default')
|
||||||
|
const uri = makeRecordUri(did, 'app.bsky.feed.generator', rkey)
|
||||||
|
const item = useCustomFeed(uri)
|
||||||
|
if (!item) return null
|
||||||
|
const onToggle = async () => {
|
||||||
|
if (item.isSaved) {
|
||||||
|
try {
|
||||||
|
await item.unsave()
|
||||||
|
} catch (e) {
|
||||||
|
Toast.show('There was an issue contacting your server')
|
||||||
|
console.error('Failed to unsave feed', {e})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
await item.save()
|
||||||
|
await item.pin()
|
||||||
|
} catch (e) {
|
||||||
|
Toast.show('There was an issue contacting your server')
|
||||||
|
console.error('Failed to pin feed', {e})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<View testID={`feed-${item.displayName}`}>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
pal.border,
|
||||||
|
{
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: 18,
|
||||||
|
maxWidth: 670,
|
||||||
|
borderRightWidth: 1,
|
||||||
|
paddingHorizontal: 24,
|
||||||
|
paddingVertical: 24,
|
||||||
|
borderTopWidth: 1,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<View style={{marginTop: 2}}>
|
||||||
|
<UserAvatar type="algo" size={42} avatar={item.data.avatar} />
|
||||||
|
</View>
|
||||||
|
<View>
|
||||||
|
<Text
|
||||||
|
type="2xl-bold"
|
||||||
|
numberOfLines={1}
|
||||||
|
style={[pal.text, {fontSize: 19}]}>
|
||||||
|
{item.displayName}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text style={[pal.textLight, {marginBottom: 8}]} numberOfLines={1}>
|
||||||
|
by {sanitizeHandle(item.data.creator.handle, '@')}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
{item.data.description ? (
|
||||||
|
<Text
|
||||||
|
type="xl"
|
||||||
|
style={[pal.text, {maxWidth: 550, marginBottom: 18}]}
|
||||||
|
numberOfLines={6}>
|
||||||
|
{item.data.description}
|
||||||
|
</Text>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<View style={{flexDirection: 'row', alignItems: 'center', gap: 12}}>
|
||||||
|
<Button
|
||||||
|
type="inverted"
|
||||||
|
style={{paddingVertical: 6}}
|
||||||
|
onPress={onToggle}>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingRight: 2,
|
||||||
|
gap: 6,
|
||||||
|
}}>
|
||||||
|
{item.isSaved ? (
|
||||||
|
<>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon="check"
|
||||||
|
size={16}
|
||||||
|
color={pal.colors.textInverted}
|
||||||
|
/>
|
||||||
|
<Text type="lg-medium" style={pal.textInverted}>
|
||||||
|
Added
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon="plus"
|
||||||
|
size={16}
|
||||||
|
color={pal.colors.textInverted}
|
||||||
|
/>
|
||||||
|
<Text type="lg-medium" style={pal.textInverted}>
|
||||||
|
Add
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<View style={{flexDirection: 'row', gap: 4}}>
|
||||||
|
<HeartIcon
|
||||||
|
size={16}
|
||||||
|
strokeWidth={2.5}
|
||||||
|
style={[pal.textLight, {position: 'relative', top: 2}]}
|
||||||
|
/>
|
||||||
|
<Text type="lg-medium" style={[pal.text, pal.textLight]}>
|
||||||
|
{item.data.likeCount || 0}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
marginHorizontal: 16,
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
},
|
||||||
|
title1: {
|
||||||
|
fontSize: 36,
|
||||||
|
fontWeight: '800',
|
||||||
|
textAlign: 'right',
|
||||||
|
},
|
||||||
|
title2: {
|
||||||
|
fontSize: 58,
|
||||||
|
fontWeight: '800',
|
||||||
|
textAlign: 'right',
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
maxWidth: 400,
|
||||||
|
marginTop: 10,
|
||||||
|
marginLeft: 'auto',
|
||||||
|
textAlign: 'right',
|
||||||
|
},
|
||||||
|
})
|
|
@ -41,8 +41,10 @@ export const Welcome = observer(({next, skip}: Props) => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<View>
|
<View>
|
||||||
<Text style={[pal.text, styles.title]}>Welcome to </Text>
|
<Text style={[pal.text, styles.title]}>
|
||||||
<Text style={[pal.text, pal.link, styles.title]}>Bluesky</Text>
|
Welcome to{' '}
|
||||||
|
<Text style={[pal.text, pal.link, styles.title]}>Bluesky</Text>
|
||||||
|
</Text>
|
||||||
<View style={styles.spacer} />
|
<View style={styles.spacer} />
|
||||||
<View style={[styles.row]}>
|
<View style={[styles.row]}>
|
||||||
<FontAwesomeIcon icon={'globe'} size={36} color={pal.colors.link} />
|
<FontAwesomeIcon icon={'globe'} size={36} color={pal.colors.link} />
|
||||||
|
@ -98,7 +100,7 @@ const styles = StyleSheet.create({
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 48,
|
fontSize: 42,
|
||||||
fontWeight: '800',
|
fontWeight: '800',
|
||||||
},
|
},
|
||||||
row: {
|
row: {
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
import React from 'react'
|
||||||
|
import {StyleSheet, View} from 'react-native'
|
||||||
|
import {useMediaQuery} from 'react-responsive'
|
||||||
|
import {Text} from 'view/com/util/text/Text'
|
||||||
|
import {s} from 'lib/styles'
|
||||||
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
|
import {TitleColumnLayout} from 'view/com/util/layouts/TitleColumnLayout'
|
||||||
|
import {Button} from 'view/com/util/forms/Button'
|
||||||
|
import {observer} from 'mobx-react-lite'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
next: () => void
|
||||||
|
skip: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Welcome = observer(({next}: Props) => {
|
||||||
|
const pal = usePalette('default')
|
||||||
|
const horizontal = useMediaQuery({
|
||||||
|
query: '(min-width: 1230px)',
|
||||||
|
})
|
||||||
|
const title = (
|
||||||
|
<>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
pal.textLight,
|
||||||
|
{
|
||||||
|
fontSize: 36,
|
||||||
|
fontWeight: '800',
|
||||||
|
textAlign: horizontal ? 'right' : 'left',
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
Welcome to
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
pal.link,
|
||||||
|
{
|
||||||
|
fontSize: 72,
|
||||||
|
fontWeight: '800',
|
||||||
|
textAlign: horizontal ? 'right' : 'left',
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
Bluesky
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
<TitleColumnLayout
|
||||||
|
testID="welcomeOnboarding"
|
||||||
|
title={title}
|
||||||
|
horizontal={horizontal}
|
||||||
|
titleStyle={horizontal ? {paddingBottom: 160} : undefined}>
|
||||||
|
<View style={[styles.row]}>
|
||||||
|
<FontAwesomeIcon icon={'globe'} size={36} color={pal.colors.link} />
|
||||||
|
<View style={[styles.rowText]}>
|
||||||
|
<Text type="xl-bold" style={[pal.text]}>
|
||||||
|
Bluesky is public.
|
||||||
|
</Text>
|
||||||
|
<Text type="xl" style={[pal.text, s.pt2]}>
|
||||||
|
Your posts, likes, and blocks are public. Mutes are private.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={[styles.row]}>
|
||||||
|
<FontAwesomeIcon icon={'at'} size={36} color={pal.colors.link} />
|
||||||
|
<View style={[styles.rowText]}>
|
||||||
|
<Text type="xl-bold" style={[pal.text]}>
|
||||||
|
Bluesky is open.
|
||||||
|
</Text>
|
||||||
|
<Text type="xl" style={[pal.text, s.pt2]}>
|
||||||
|
Never lose access to your followers and data.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={[styles.row]}>
|
||||||
|
<FontAwesomeIcon icon={'gear'} size={36} color={pal.colors.link} />
|
||||||
|
<View style={[styles.rowText]}>
|
||||||
|
<Text type="xl-bold" style={[pal.text]}>
|
||||||
|
Bluesky is flexible.
|
||||||
|
</Text>
|
||||||
|
<Text type="xl" style={[pal.text, s.pt2]}>
|
||||||
|
Choose the algorithms that power your experience with custom feeds.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={styles.spacer} />
|
||||||
|
<View style={{flexDirection: 'row'}}>
|
||||||
|
<Button onPress={next} testID="continueBtn">
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingLeft: 2,
|
||||||
|
gap: 6,
|
||||||
|
}}>
|
||||||
|
<Text
|
||||||
|
type="2xl-medium"
|
||||||
|
style={{color: '#fff', position: 'relative', top: -1}}>
|
||||||
|
Next
|
||||||
|
</Text>
|
||||||
|
<FontAwesomeIcon icon="angle-right" color="#fff" size={14} />
|
||||||
|
</View>
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</TitleColumnLayout>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
columnGap: 20,
|
||||||
|
alignItems: 'center',
|
||||||
|
marginVertical: 20,
|
||||||
|
},
|
||||||
|
rowText: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
spacer: {
|
||||||
|
height: 20,
|
||||||
|
},
|
||||||
|
})
|
|
@ -0,0 +1,62 @@
|
||||||
|
import React from 'react'
|
||||||
|
import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
|
||||||
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
testID?: string
|
||||||
|
title: React.Component
|
||||||
|
horizontal: boolean
|
||||||
|
titleStyle?: StyleProp<ViewStyle>
|
||||||
|
contentStyle?: StyleProp<ViewStyle>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TitleColumnLayout({
|
||||||
|
testID,
|
||||||
|
title,
|
||||||
|
horizontal,
|
||||||
|
children,
|
||||||
|
titleStyle,
|
||||||
|
contentStyle,
|
||||||
|
}: React.PropsWithChildren<Props>) {
|
||||||
|
const pal = usePalette('default')
|
||||||
|
|
||||||
|
const layoutStyles = horizontal ? styles2Column : styles1Column
|
||||||
|
return (
|
||||||
|
<View testID={testID} style={layoutStyles.container}>
|
||||||
|
<View style={[layoutStyles.title, pal.viewLight, titleStyle]}>
|
||||||
|
{title}
|
||||||
|
</View>
|
||||||
|
<View style={[layoutStyles.content, contentStyle]}>{children}</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles2Column = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
height: '100%',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
flex: 1,
|
||||||
|
paddingHorizontal: 40,
|
||||||
|
paddingBottom: 80,
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
flex: 2,
|
||||||
|
paddingHorizontal: 40,
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const styles1Column = StyleSheet.create({
|
||||||
|
container: {},
|
||||||
|
title: {
|
||||||
|
paddingHorizontal: 40,
|
||||||
|
paddingVertical: 40,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
paddingHorizontal: 40,
|
||||||
|
paddingVertical: 40,
|
||||||
|
},
|
||||||
|
})
|
|
@ -20,7 +20,6 @@ import {NavigationProp} from 'lib/routes/types'
|
||||||
const ShellInner = observer(() => {
|
const ShellInner = observer(() => {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const {isDesktop} = useWebMediaQueries()
|
const {isDesktop} = useWebMediaQueries()
|
||||||
|
|
||||||
const navigator = useNavigation<NavigationProp>()
|
const navigator = useNavigation<NavigationProp>()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -29,6 +28,8 @@ const ShellInner = observer(() => {
|
||||||
})
|
})
|
||||||
}, [navigator, store.shell])
|
}, [navigator, store.shell])
|
||||||
|
|
||||||
|
const showSideNavs =
|
||||||
|
isDesktop && store.session.hasSession && !store.onboarding.isActive
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View style={s.hContentRegion}>
|
<View style={s.hContentRegion}>
|
||||||
|
@ -36,7 +37,7 @@ const ShellInner = observer(() => {
|
||||||
<FlatNavigator />
|
<FlatNavigator />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</View>
|
</View>
|
||||||
{isDesktop && store.session.hasSession && (
|
{showSideNavs && (
|
||||||
<>
|
<>
|
||||||
<DesktopLeftNav />
|
<DesktopLeftNav />
|
||||||
<DesktopRightNav />
|
<DesktopRightNav />
|
||||||
|
|
Loading…
Reference in New Issue