diff --git a/src/Navigation.tsx b/src/Navigation.tsx index df601d0cd0..2422491e2f 100644 --- a/src/Navigation.tsx +++ b/src/Navigation.tsx @@ -260,6 +260,7 @@ function TabsNavigator() { function HomeTabNavigator() { const contentStyle = useColorSchemeStyle(styles.bgLight, styles.bgDark) + return ( { sessionReadySub.remove() - this.rootStore.shell.openModal({name: 'onboarding'}) + this.rootStore.onboarding.start() }) try { diff --git a/src/state/models/ui/shell.ts b/src/state/models/ui/shell.ts index d19de4b96c..33fdd57103 100644 --- a/src/state/models/ui/shell.ts +++ b/src/state/models/ui/shell.ts @@ -136,10 +136,6 @@ export interface PostLanguagesSettingsModal { name: 'post-languages-settings' } -export interface OnboardingModal { - name: 'onboarding' -} - export type Modal = // Account | AddAppPasswordModal @@ -171,9 +167,6 @@ export type Modal = | WaitlistModal | InviteCodesModal - // Onboarding - | OnboardingModal - // Generic | ConfirmModal diff --git a/src/view/com/auth/Onboarding.tsx b/src/view/com/auth/Onboarding.tsx new file mode 100644 index 0000000000..065d4d244a --- /dev/null +++ b/src/view/com/auth/Onboarding.tsx @@ -0,0 +1,34 @@ +import React from 'react' +import {SafeAreaView} from 'react-native' +import {observer} from 'mobx-react-lite' +import {ErrorBoundary} from 'view/com/util/ErrorBoundary' +import {s} from 'lib/styles' +import {usePalette} from 'lib/hooks/usePalette' +import {useStores} from 'state/index' +import {Welcome} from './onboarding/Welcome' +import {RecommendedFeeds} from './onboarding/RecommendedFeeds' + +export const Onboarding = observer(() => { + const pal = usePalette('default') + const store = useStores() + + React.useEffect(() => { + store.shell.setMinimalShellMode(true) + }, [store]) + + const next = () => store.onboarding.next() + const skip = () => store.onboarding.skip() + + return ( + + + {store.onboarding.step === 'Welcome' && ( + + )} + {store.onboarding.step === 'RecommendedFeeds' && ( + + )} + + + ) +}) diff --git a/src/view/com/auth/onboarding/Onboarding.tsx b/src/view/com/auth/onboarding/Onboarding.tsx deleted file mode 100644 index 28e4419d75..0000000000 --- a/src/view/com/auth/onboarding/Onboarding.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import React from 'react' -import {StyleSheet, View} from 'react-native' -import {usePalette} from 'lib/hooks/usePalette' -import {Welcome} from './Welcome' -import {useStores} from 'state/index' -import {track} from 'lib/analytics/analytics' - -enum OnboardingStep { - WELCOME = 'WELCOME', - // SELECT_INTERESTS = 'SELECT_INTERESTS', - COMPLETE = 'COMPLETE', -} -type OnboardingState = { - currentStep: OnboardingStep -} -type Action = {type: 'NEXT_STEP'} -const initialState: OnboardingState = { - currentStep: OnboardingStep.WELCOME, -} -const reducer = (state: OnboardingState, action: Action): OnboardingState => { - switch (action.type) { - case 'NEXT_STEP': - switch (state.currentStep) { - case OnboardingStep.WELCOME: - track('Onboarding:Begin') - return {...state, currentStep: OnboardingStep.COMPLETE} - case OnboardingStep.COMPLETE: - track('Onboarding:Complete') - return state - default: - return state - } - default: - return state - } -} - -export const Onboarding = () => { - const pal = usePalette('default') - const rootStore = useStores() - const [state, dispatch] = React.useReducer(reducer, initialState) - const next = React.useCallback( - () => dispatch({type: 'NEXT_STEP'}), - [dispatch], - ) - - React.useEffect(() => { - if (state.currentStep === OnboardingStep.COMPLETE) { - // navigate to home - rootStore.shell.closeModal() - } - }, [state.currentStep, rootStore.shell]) - - return ( - - {state.currentStep === OnboardingStep.WELCOME && } - - ) -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - paddingHorizontal: 20, - }, -}) diff --git a/src/view/com/auth/onboarding/RecommendedFeeds.tsx b/src/view/com/auth/onboarding/RecommendedFeeds.tsx new file mode 100644 index 0000000000..28dc2cdd02 --- /dev/null +++ b/src/view/com/auth/onboarding/RecommendedFeeds.tsx @@ -0,0 +1,176 @@ +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 {TabletOrDesktop, Mobile} from 'view/com/util/layouts/Breakpoints' +import {Text} from 'view/com/util/text/Text' +import {ViewHeader} from 'view/com/util/ViewHeader' +import {TitleColumnLayout} from 'view/com/util/layouts/TitleColumnLayout' +import {Button} from 'view/com/util/forms/Button' +import {RecommendedFeedsItem} from './RecommendedFeedsItem' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {usePalette} from 'lib/hooks/usePalette' +import {RECOMMENDED_FEEDS} from 'lib/constants' + +type Props = { + next: () => void +} +export const RecommendedFeeds = observer(({next}: Props) => { + const pal = usePalette('default') + const {isTabletOrMobile} = useWebMediaQueries() + + const title = ( + <> + + Choose your + + + Recomended + + + Feeds + + + Feeds are created by users to curate content. Choose some feeds that you + find interesting. + + + + + + ) + + return ( + <> + + + } + keyExtractor={item => item.did + item.rkey} + style={{flex: 1}} + /> + + + + + + + Check out some recommended feeds. Tap + to add them to your list of + pinned feeds. + + + } + keyExtractor={item => item.did + item.rkey} + style={{flex: 1}} + /> + + + + + + + {item.data.likeCount || 0} + + + + + + + ) + }, +) diff --git a/src/view/com/auth/onboarding/Welcome.tsx b/src/view/com/auth/onboarding/Welcome.tsx index 87435c88a6..b44b58f843 100644 --- a/src/view/com/auth/onboarding/Welcome.tsx +++ b/src/view/com/auth/onboarding/Welcome.tsx @@ -1,92 +1,10 @@ -import React from 'react' -import {StyleSheet, View} from 'react-native' -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 {Button} from 'view/com/util/forms/Button' +import 'react' +import {withBreakpoints} from 'view/com/util/layouts/withBreakpoints' +import {WelcomeDesktop} from './WelcomeDesktop' +import {WelcomeMobile} from './WelcomeMobile' -export const Welcome = ({next}: {next: () => void}) => { - const pal = usePalette('default') - return ( - - - Welcome to - Bluesky - - - - - - - - Bluesky is public. - - - Your posts, likes, and blocks are public. Mutes are private. - - - - - - - - Bluesky is open. - - - Never lose access to your followers and data. - - - - - - - - Bluesky is flexible. - - - Choose the algorithms that power your experience with custom - feeds. - - - - - - + + + ) +}) + +const styles = StyleSheet.create({ + row: { + flexDirection: 'row', + columnGap: 20, + alignItems: 'center', + marginVertical: 20, + }, + rowText: { + flex: 1, + }, + spacer: { + height: 20, + }, +}) diff --git a/src/view/com/auth/onboarding/WelcomeMobile.tsx b/src/view/com/auth/onboarding/WelcomeMobile.tsx new file mode 100644 index 0000000000..eb72de836b --- /dev/null +++ b/src/view/com/auth/onboarding/WelcomeMobile.tsx @@ -0,0 +1,123 @@ +import React from 'react' +import {Pressable, StyleSheet, View} from 'react-native' +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 {Button} from 'view/com/util/forms/Button' +import {observer} from 'mobx-react-lite' +import {ViewHeader} from 'view/com/util/ViewHeader' +import {isDesktopWeb} from 'platform/detection' + +type Props = { + next: () => void + skip: () => void +} + +export const WelcomeMobile = observer(({next, skip}: Props) => { + const pal = usePalette('default') + + return ( + + { + return ( + + Skip + + + ) + }} + /> + + + Welcome to{' '} + Bluesky + + + + + + + Bluesky is public. + + + Your posts, likes, and blocks are public. Mutes are private. + + + + + + + + Bluesky is open. + + + Never lose access to your followers and data. + + + + + + + + Bluesky is flexible. + + + Choose the algorithms that power your experience with custom + feeds. + + + + + +