Add right column of web shell and tweak left column
parent
c24d0254bc
commit
f51ad28025
|
@ -0,0 +1,194 @@
|
||||||
|
import React, {useEffect, useState} from 'react'
|
||||||
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
StyleSheet,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from 'react-native'
|
||||||
|
import LinearGradient from 'react-native-linear-gradient'
|
||||||
|
import {observer} from 'mobx-react-lite'
|
||||||
|
import _omit from 'lodash.omit'
|
||||||
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
|
import {Link} from '../util/Link'
|
||||||
|
import {Text} from '../util/text/Text'
|
||||||
|
import {UserAvatar} from '../util/UserAvatar'
|
||||||
|
import * as Toast from '../util/Toast'
|
||||||
|
import {useStores} from '../../../state'
|
||||||
|
import * as apilib from '../../../state/lib/api'
|
||||||
|
import {
|
||||||
|
SuggestedActorsViewModel,
|
||||||
|
SuggestedActor,
|
||||||
|
} from '../../../state/models/suggested-actors-view'
|
||||||
|
import {s, gradients} from '../../lib/styles'
|
||||||
|
import {usePalette} from '../../lib/hooks/usePalette'
|
||||||
|
|
||||||
|
export const LiteSuggestedFollows = observer(() => {
|
||||||
|
const store = useStores()
|
||||||
|
const [suggestions, setSuggestions] = useState<SuggestedActor[] | undefined>(
|
||||||
|
undefined,
|
||||||
|
)
|
||||||
|
const [follows, setFollows] = useState<Record<string, string>>({})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const view = new SuggestedActorsViewModel(store)
|
||||||
|
view.loadMore().then(
|
||||||
|
() => {
|
||||||
|
setSuggestions(view.suggestions.slice().sort(randomize).slice(0, 3))
|
||||||
|
},
|
||||||
|
(err: any) => {
|
||||||
|
setSuggestions([])
|
||||||
|
store.log.error('Failed to fetch suggestions', err)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}, [store, store.log])
|
||||||
|
|
||||||
|
const onPressFollow = async (item: SuggestedActor) => {
|
||||||
|
try {
|
||||||
|
const res = await apilib.follow(store, item.did, item.declaration.cid)
|
||||||
|
setFollows({[item.did]: res.uri, ...follows})
|
||||||
|
} catch (e: any) {
|
||||||
|
store.log.error('Failed fo create follow', e)
|
||||||
|
Toast.show('An issue occurred, please try again.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onPressUnfollow = async (item: SuggestedActor) => {
|
||||||
|
try {
|
||||||
|
await apilib.unfollow(store, follows[item.did])
|
||||||
|
setFollows(_omit(follows, [item.did]))
|
||||||
|
} catch (e: any) {
|
||||||
|
store.log.error('Failed fo delete follow', e)
|
||||||
|
Toast.show('An issue occurred, please try again.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
{!suggestions ? (
|
||||||
|
<View>
|
||||||
|
<ActivityIndicator />
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View>
|
||||||
|
{suggestions.map(item => (
|
||||||
|
<Link
|
||||||
|
key={item.did}
|
||||||
|
href={`/profile/${item.handle}`}
|
||||||
|
title={item.displayName || item.handle}>
|
||||||
|
<User
|
||||||
|
item={item}
|
||||||
|
follow={follows[item.did]}
|
||||||
|
onPressFollow={onPressFollow}
|
||||||
|
onPressUnfollow={onPressUnfollow}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const User = ({
|
||||||
|
item,
|
||||||
|
follow,
|
||||||
|
onPressFollow,
|
||||||
|
onPressUnfollow,
|
||||||
|
}: {
|
||||||
|
item: SuggestedActor
|
||||||
|
follow: string | undefined
|
||||||
|
onPressFollow: (item: SuggestedActor) => void
|
||||||
|
onPressUnfollow: (item: SuggestedActor) => void
|
||||||
|
}) => {
|
||||||
|
const pal = usePalette('default')
|
||||||
|
return (
|
||||||
|
<View style={[styles.actor]}>
|
||||||
|
<View style={styles.actorMeta}>
|
||||||
|
<View style={styles.actorAvi}>
|
||||||
|
<UserAvatar
|
||||||
|
size={40}
|
||||||
|
displayName={item.displayName}
|
||||||
|
handle={item.handle}
|
||||||
|
avatar={item.avatar}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.actorContent}>
|
||||||
|
<Text type="lg-medium" style={pal.text} numberOfLines={1}>
|
||||||
|
{item.displayName || item.handle}
|
||||||
|
</Text>
|
||||||
|
<Text type="sm" style={pal.textLight} numberOfLines={1}>
|
||||||
|
@{item.handle}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.actorBtn}>
|
||||||
|
{follow ? (
|
||||||
|
<TouchableOpacity onPress={() => onPressUnfollow(item)}>
|
||||||
|
<View style={[styles.btn, styles.secondaryBtn, pal.btn]}>
|
||||||
|
<Text type="button" style={pal.text}>
|
||||||
|
Unfollow
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
) : (
|
||||||
|
<TouchableOpacity onPress={() => onPressFollow(item)}>
|
||||||
|
<LinearGradient
|
||||||
|
colors={[gradients.blueLight.start, gradients.blueLight.end]}
|
||||||
|
start={{x: 0, y: 0}}
|
||||||
|
end={{x: 1, y: 1}}
|
||||||
|
style={[styles.btn, styles.gradientBtn]}>
|
||||||
|
<Text type="sm-medium" style={s.white}>
|
||||||
|
Follow
|
||||||
|
</Text>
|
||||||
|
</LinearGradient>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function randomize() {
|
||||||
|
return Math.random() > 0.5 ? 1 : -1
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
footer: {
|
||||||
|
height: 200,
|
||||||
|
paddingTop: 20,
|
||||||
|
},
|
||||||
|
|
||||||
|
actor: {},
|
||||||
|
actorMeta: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
},
|
||||||
|
actorAvi: {
|
||||||
|
width: 50,
|
||||||
|
paddingTop: 10,
|
||||||
|
paddingBottom: 10,
|
||||||
|
},
|
||||||
|
actorContent: {
|
||||||
|
flex: 1,
|
||||||
|
paddingRight: 10,
|
||||||
|
paddingTop: 10,
|
||||||
|
},
|
||||||
|
actorBtn: {
|
||||||
|
paddingRight: 10,
|
||||||
|
paddingTop: 10,
|
||||||
|
},
|
||||||
|
|
||||||
|
gradientBtn: {
|
||||||
|
paddingHorizontal: 14,
|
||||||
|
paddingVertical: 6,
|
||||||
|
},
|
||||||
|
secondaryBtn: {
|
||||||
|
paddingHorizontal: 8,
|
||||||
|
},
|
||||||
|
btn: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
paddingVertical: 7,
|
||||||
|
borderRadius: 50,
|
||||||
|
marginLeft: 6,
|
||||||
|
},
|
||||||
|
})
|
|
@ -1,10 +1,10 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {View, StyleSheet, Text} from 'react-native'
|
import {View, StyleSheet} from 'react-native'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {match, MatchResult} from '../../routes'
|
import {match, MatchResult} from '../../routes'
|
||||||
import {DesktopLeftColumn} from './left-column'
|
import {DesktopLeftColumn} from './left-column'
|
||||||
// import {DesktopRightColumn} from './right-column'
|
import {DesktopRightColumn} from './right-column'
|
||||||
import {Login} from '../../screens/Login'
|
import {Login} from '../../screens/Login'
|
||||||
import {ErrorBoundary} from '../../com/util/ErrorBoundary'
|
import {ErrorBoundary} from '../../com/util/ErrorBoundary'
|
||||||
import {usePalette} from '../../lib/hooks/usePalette'
|
import {usePalette} from '../../lib/hooks/usePalette'
|
||||||
|
@ -35,6 +35,7 @@ export const WebShell: React.FC = observer(() => {
|
||||||
</View>
|
</View>
|
||||||
))}
|
))}
|
||||||
<DesktopLeftColumn />
|
<DesktopLeftColumn />
|
||||||
|
<DesktopRightColumn />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -48,25 +49,6 @@ export const WebShell: React.FC = observer(() => {
|
||||||
// imagesOpen={store.shell.composerOpts?.imagesOpen}
|
// imagesOpen={store.shell.composerOpts?.imagesOpen}
|
||||||
// onPost={store.shell.composerOpts?.onPost}
|
// onPost={store.shell.composerOpts?.onPost}
|
||||||
// />
|
// />
|
||||||
// return (
|
|
||||||
// <View style={styles.outerContainer}>
|
|
||||||
// {store.session.hasSession ? (
|
|
||||||
// <>
|
|
||||||
// <DesktopLeftColumn />
|
|
||||||
// <View style={styles.innerContainer}>
|
|
||||||
// <Text>Hello, world! (Logged in)</Text>
|
|
||||||
// {children}
|
|
||||||
// </View>
|
|
||||||
// <DesktopRightColumn />
|
|
||||||
// </>
|
|
||||||
// ) : (
|
|
||||||
// <View style={styles.innerContainer}>
|
|
||||||
// <Text>Hello, world! (Logged out)</Text>
|
|
||||||
// {children}
|
|
||||||
// </View>
|
|
||||||
// )}
|
|
||||||
// </View>
|
|
||||||
// )
|
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -42,7 +42,9 @@ export const NavItem = observer(
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
<Text type={isCurrent ? 'xl-bold' : 'xl-medium'}>{label}</Text>
|
<Text type={isCurrent ? 'xl-bold' : 'xl'} style={styles.navItemLabel}>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
</Link>
|
</Link>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
)
|
)
|
||||||
|
@ -86,10 +88,11 @@ export const DesktopLeftColumn = observer(() => {
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: 'calc(50vw - 500px)',
|
left: 'calc(50vw - 530px)',
|
||||||
width: '200px',
|
width: '230px',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
borderRightWidth: 1,
|
borderRightWidth: 1,
|
||||||
|
paddingTop: 20,
|
||||||
},
|
},
|
||||||
navItem: {
|
navItem: {
|
||||||
padding: '1rem',
|
padding: '1rem',
|
||||||
|
@ -109,7 +112,11 @@ const styles = StyleSheet.create({
|
||||||
backgroundColor: colors.red3,
|
backgroundColor: colors.red3,
|
||||||
color: colors.white,
|
color: colors.white,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
|
fontWeight: 'bold',
|
||||||
paddingHorizontal: 4,
|
paddingHorizontal: 4,
|
||||||
borderRadius: 4,
|
borderRadius: 6,
|
||||||
|
},
|
||||||
|
navItemLabel: {
|
||||||
|
fontSize: 19,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,10 +1,28 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {Text, View, StyleSheet} from 'react-native'
|
import {View, StyleSheet} from 'react-native'
|
||||||
|
import {Link} from '../../com/util/Link'
|
||||||
|
import {Text} from '../../com/util/text/Text'
|
||||||
|
import {usePalette} from '../../lib/hooks/usePalette'
|
||||||
|
import {MagnifyingGlassIcon} from '../../lib/icons'
|
||||||
|
import {LiteSuggestedFollows} from '../../com/discover/LiteSuggestedFollows'
|
||||||
|
import {s} from '../../lib/styles'
|
||||||
|
|
||||||
export const DesktopRightColumn: React.FC = () => {
|
export const DesktopRightColumn: React.FC = () => {
|
||||||
|
const pal = usePalette('default')
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={[styles.container, pal.border]}>
|
||||||
<Text>Right Column</Text>
|
<Link href="/search" style={[pal.btn, styles.searchContainer]}>
|
||||||
|
<View style={styles.searchIcon}>
|
||||||
|
<MagnifyingGlassIcon style={pal.textLight} />
|
||||||
|
</View>
|
||||||
|
<Text type="lg" style={pal.textLight}>
|
||||||
|
Search
|
||||||
|
</Text>
|
||||||
|
</Link>
|
||||||
|
<Text type="xl-bold" style={s.mb10}>
|
||||||
|
Suggested Follows
|
||||||
|
</Text>
|
||||||
|
<LiteSuggestedFollows />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -12,8 +30,23 @@ export const DesktopRightColumn: React.FC = () => {
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
right: 'calc(50vw - 500px)',
|
right: 'calc(50vw - 650px)',
|
||||||
width: '200px',
|
width: '350px',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
borderLeftWidth: 1,
|
||||||
|
overscrollBehavior: 'auto',
|
||||||
|
paddingLeft: 30,
|
||||||
|
paddingTop: 10,
|
||||||
|
},
|
||||||
|
searchContainer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingHorizontal: 14,
|
||||||
|
paddingVertical: 10,
|
||||||
|
borderRadius: 20,
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
searchIcon: {
|
||||||
|
marginRight: 5,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue