diff options
author | Paul Frazee <pfrazee@gmail.com> | 2023-08-29 22:56:13 -0700 |
---|---|---|
committer | Paul Frazee <pfrazee@gmail.com> | 2023-08-29 22:56:13 -0700 |
commit | 5e765bf1cb29d30d627552da84d02594f506af1f (patch) | |
tree | 4620266dbd31e9ec525e173bb07652ff0b804ba7 | |
parent | 5d9534ca7258e6165e537b89d999a8c494501dc0 (diff) | |
download | voidsky-5e765bf1cb29d30d627552da84d02594f506af1f.tar.zst |
Rework web onboarding
-rw-r--r-- | src/lib/constants.ts | 107 | ||||
-rw-r--r-- | src/state/models/feeds/custom-feed.ts | 13 | ||||
-rw-r--r-- | src/view/com/auth/Onboarding.tsx | 23 | ||||
-rw-r--r-- | src/view/com/auth/onboarding/RecommendedFeeds.tsx | 110 | ||||
-rw-r--r-- | src/view/com/auth/onboarding/RecommendedFeeds.web.tsx | 214 | ||||
-rw-r--r-- | src/view/com/auth/onboarding/Welcome.tsx | 8 | ||||
-rw-r--r-- | src/view/com/auth/onboarding/Welcome.web.tsx | 123 | ||||
-rw-r--r-- | src/view/com/util/layouts/TitleColumnLayout.tsx | 62 | ||||
-rw-r--r-- | src/view/shell/index.web.tsx | 5 |
9 files changed, 539 insertions, 126 deletions
diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 001cdf8c3..94551e6ef 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -148,3 +148,110 @@ export const HITSLOP_10 = createHitslop(10) export const HITSLOP_20 = createHitslop(20) export const HITSLOP_30 = createHitslop(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', + }, +] diff --git a/src/state/models/feeds/custom-feed.ts b/src/state/models/feeds/custom-feed.ts index 3c6d52755..2de4534e7 100644 --- a/src/state/models/feeds/custom-feed.ts +++ b/src/state/models/feeds/custom-feed.ts @@ -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() { try { await this.rootStore.preferences.removeSavedFeed(this.uri) diff --git a/src/view/com/auth/Onboarding.tsx b/src/view/com/auth/Onboarding.tsx index f43d5d93a..2f0acfc47 100644 --- a/src/view/com/auth/Onboarding.tsx +++ b/src/view/com/auth/Onboarding.tsx @@ -6,7 +6,6 @@ import {s} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' import {useStores} from 'state/index' import {useAnalytics} from 'lib/analytics/analytics' -import {CenteredView} from '../util/Views' import {Welcome} from './onboarding/Welcome' import {RecommendedFeeds} from './onboarding/RecommendedFeeds' @@ -24,17 +23,15 @@ export const Onboarding = observer(() => { const skip = () => store.onboarding.skip() return ( - <CenteredView style={[s.hContentRegion, pal.view]}> - <SafeAreaView testID="noSessionView" style={s.hContentRegion}> - <ErrorBoundary> - {store.onboarding.step === 'Welcome' && ( - <Welcome skip={skip} next={next} /> - )} - {store.onboarding.step === 'RecommendedFeeds' && ( - <RecommendedFeeds next={next} /> - )} - </ErrorBoundary> - </SafeAreaView> - </CenteredView> + <SafeAreaView testID="onboardingView" style={[s.hContentRegion, pal.view]}> + <ErrorBoundary> + {store.onboarding.step === 'Welcome' && ( + <Welcome skip={skip} next={next} /> + )} + {store.onboarding.step === 'RecommendedFeeds' && ( + <RecommendedFeeds next={next} /> + )} + </ErrorBoundary> + </SafeAreaView> ) }) diff --git a/src/view/com/auth/onboarding/RecommendedFeeds.tsx b/src/view/com/auth/onboarding/RecommendedFeeds.tsx index fa9d69f98..f6b40b88d 100644 --- a/src/view/com/auth/onboarding/RecommendedFeeds.tsx +++ b/src/view/com/auth/onboarding/RecommendedFeeds.tsx @@ -9,113 +9,7 @@ import {useCustomFeed} from 'lib/hooks/useCustomFeed' import {makeRecordUri} from 'lib/strings/url-helpers' import {ViewHeader} from 'view/com/util/ViewHeader' import {isDesktopWeb} from 'platform/detection' - -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', - }, -] +import {RECOMMENDED_FEEDS} from 'lib/constants' type Props = { next: () => void @@ -132,7 +26,7 @@ export const RecommendedFeeds = observer(({next}: Props) => { </Text> <FlatList - data={TEMPORARY_RECOMMENDED_FEEDS} + data={RECOMMENDED_FEEDS} renderItem={({item}) => <Item item={item} />} keyExtractor={item => item.did + item.rkey} style={{flex: 1}} diff --git a/src/view/com/auth/onboarding/RecommendedFeeds.web.tsx b/src/view/com/auth/onboarding/RecommendedFeeds.web.tsx new file mode 100644 index 000000000..9038c7a5a --- /dev/null +++ b/src/view/com/auth/onboarding/RecommendedFeeds.web.tsx @@ -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', + }, +}) diff --git a/src/view/com/auth/onboarding/Welcome.tsx b/src/view/com/auth/onboarding/Welcome.tsx index a322e4d4f..6f95c0853 100644 --- a/src/view/com/auth/onboarding/Welcome.tsx +++ b/src/view/com/auth/onboarding/Welcome.tsx @@ -41,8 +41,10 @@ export const Welcome = observer(({next, skip}: Props) => { }} /> <View> - <Text style={[pal.text, styles.title]}>Welcome to </Text> - <Text style={[pal.text, pal.link, styles.title]}>Bluesky</Text> + <Text style={[pal.text, styles.title]}> + Welcome to{' '} + <Text style={[pal.text, pal.link, styles.title]}>Bluesky</Text> + </Text> <View style={styles.spacer} /> <View style={[styles.row]}> <FontAwesomeIcon icon={'globe'} size={36} color={pal.colors.link} /> @@ -98,7 +100,7 @@ const styles = StyleSheet.create({ justifyContent: 'space-between', }, title: { - fontSize: 48, + fontSize: 42, fontWeight: '800', }, row: { diff --git a/src/view/com/auth/onboarding/Welcome.web.tsx b/src/view/com/auth/onboarding/Welcome.web.tsx new file mode 100644 index 000000000..af3ca7074 --- /dev/null +++ b/src/view/com/auth/onboarding/Welcome.web.tsx @@ -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, + }, +}) diff --git a/src/view/com/util/layouts/TitleColumnLayout.tsx b/src/view/com/util/layouts/TitleColumnLayout.tsx new file mode 100644 index 000000000..3ca10868e --- /dev/null +++ b/src/view/com/util/layouts/TitleColumnLayout.tsx @@ -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, + }, +}) diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx index 16ed17a5b..9ad8007f6 100644 --- a/src/view/shell/index.web.tsx +++ b/src/view/shell/index.web.tsx @@ -20,7 +20,6 @@ import {NavigationProp} from 'lib/routes/types' const ShellInner = observer(() => { const store = useStores() const {isDesktop} = useWebMediaQueries() - const navigator = useNavigation<NavigationProp>() useEffect(() => { @@ -29,6 +28,8 @@ const ShellInner = observer(() => { }) }, [navigator, store.shell]) + const showSideNavs = + isDesktop && store.session.hasSession && !store.onboarding.isActive return ( <> <View style={s.hContentRegion}> @@ -36,7 +37,7 @@ const ShellInner = observer(() => { <FlatNavigator /> </ErrorBoundary> </View> - {isDesktop && store.session.hasSession && ( + {showSideNavs && ( <> <DesktopLeftNav /> <DesktopRightNav /> |