WIP scene UIs

zio/stable
Paul Frazee 2022-10-31 12:17:58 -05:00
parent 1ab8285ad3
commit eceef67d46
9 changed files with 144 additions and 31 deletions

View File

@ -15,7 +15,7 @@ export interface ProfileUiParams {
export class ProfileUiModel { export class ProfileUiModel {
// constants // constants
static SELECTOR_ITEMS = ['Posts', 'Badges'] static SELECTOR_ITEMS = ['Posts', 'Scenes']
// data // data
profile: ProfileViewModel profile: ProfileViewModel

View File

@ -86,14 +86,16 @@ export const ProfileHeader = observer(function ProfileHeader({
<View style={[styles.displayNameLine]}> <View style={[styles.displayNameLine]}>
<Text style={styles.displayName}>{view.displayName}</Text> <Text style={styles.displayName}>{view.displayName}</Text>
</View> </View>
<View style={styles.badgesLine}> {
undefined /*<View style={styles.badgesLine}>
<FontAwesomeIcon icon="shield" style={s.mr5} size={12} /> <FontAwesomeIcon icon="shield" style={s.mr5} size={12} />
<Link href="/" title="Badge TODO"> <Link href="/" title="Badge TODO">
<Text style={[s.f12, s.bold]}> <Text style={[s.f12, s.bold]}>
Employee <Text style={[s.blue3]}>@blueskyweb.xyz</Text> Employee <Text style={[s.blue3]}>@blueskyweb.xyz</Text>
</Text> </Text>
</Link> </Link>
</View> </View>*/
}
<View style={[styles.buttonsLine]}> <View style={[styles.buttonsLine]}>
{isMe ? ( {isMe ? (
<TouchableOpacity <TouchableOpacity

View File

@ -12,6 +12,8 @@ interface Layout {
width: number width: number
} }
const DEFAULT_SWIPE_GESTURE_INTERP = {value: 0}
export function Selector({ export function Selector({
selectedIndex, selectedIndex,
items, items,
@ -20,7 +22,7 @@ export function Selector({
}: { }: {
selectedIndex: number selectedIndex: number
items: string[] items: string[]
swipeGestureInterp: SharedValue<number> swipeGestureInterp?: SharedValue<number>
onSelect?: (index: number) => void onSelect?: (index: number) => void
}) { }) {
const [itemLayouts, setItemLayouts] = useState<undefined | Layout[]>( const [itemLayouts, setItemLayouts] = useState<undefined | Layout[]>(
@ -41,26 +43,27 @@ export function Selector({
return [left, middle, right] return [left, middle, right]
}, [selectedIndex, itemLayouts]) }, [selectedIndex, itemLayouts])
const interp = swipeGestureInterp || DEFAULT_SWIPE_GESTURE_INTERP
const underlinePos = useAnimatedStyle(() => { const underlinePos = useAnimatedStyle(() => {
const other = const other =
swipeGestureInterp.value === 0 interp.value === 0
? currentLayouts[1] ? currentLayouts[1]
: swipeGestureInterp.value < 0 : interp.value < 0
? currentLayouts[0] ? currentLayouts[0]
: currentLayouts[2] : currentLayouts[2]
return { return {
left: interpolate( left: interpolate(
Math.abs(swipeGestureInterp.value), Math.abs(interp.value),
[0, 1], [0, 1],
[currentLayouts[1].x, other.x], [currentLayouts[1].x, other.x],
), ),
width: interpolate( width: interpolate(
Math.abs(swipeGestureInterp.value), Math.abs(interp.value),
[0, 1], [0, 1],
[currentLayouts[1].width, other.width], [currentLayouts[1].width, other.width],
), ),
} }
}, [currentLayouts, swipeGestureInterp]) }, [currentLayouts, interp])
const onLayout = () => { const onLayout = () => {
const promises = [] const promises = []
@ -112,7 +115,7 @@ const styles = StyleSheet.create({
backgroundColor: colors.white, backgroundColor: colors.white,
}, },
item: { item: {
marginRight: 20, marginRight: 14,
paddingHorizontal: 10, paddingHorizontal: 10,
}, },
itemLabel: { itemLabel: {

View File

@ -19,6 +19,7 @@ import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck'
import {faCircleUser} from '@fortawesome/free-regular-svg-icons/faCircleUser' import {faCircleUser} from '@fortawesome/free-regular-svg-icons/faCircleUser'
import {faClone} from '@fortawesome/free-regular-svg-icons/faClone' import {faClone} from '@fortawesome/free-regular-svg-icons/faClone'
import {faComment} from '@fortawesome/free-regular-svg-icons/faComment' import {faComment} from '@fortawesome/free-regular-svg-icons/faComment'
import {faCompass} from '@fortawesome/free-regular-svg-icons/faCompass'
import {faEllipsis} from '@fortawesome/free-solid-svg-icons/faEllipsis' import {faEllipsis} from '@fortawesome/free-solid-svg-icons/faEllipsis'
import {faEnvelope} from '@fortawesome/free-solid-svg-icons/faEnvelope' import {faEnvelope} from '@fortawesome/free-solid-svg-icons/faEnvelope'
import {faExclamation} from '@fortawesome/free-solid-svg-icons/faExclamation' import {faExclamation} from '@fortawesome/free-solid-svg-icons/faExclamation'
@ -69,6 +70,7 @@ export function setup() {
faCircleUser, faCircleUser,
faClone, faClone,
faComment, faComment,
faCompass,
faEllipsis, faEllipsis,
faEnvelope, faEnvelope,
faExclamation, faExclamation,

View File

@ -33,12 +33,37 @@ export function GridIcon({style}: {style?: StyleProp<ViewStyle>}) {
export function HomeIcon({style}: {style?: StyleProp<ViewStyle>}) { export function HomeIcon({style}: {style?: StyleProp<ViewStyle>}) {
return ( return (
<Svg viewBox="0 0 48 48" width="24" height="24" style={style}> <Svg
viewBox="0 0 48 48"
width="24"
height="24"
stroke="currentColor"
style={style}>
<Path <Path
strokeWidth={4} strokeWidth={4}
stroke="#000"
d="M 23.951 2 C 23.631 2.011 23.323 2.124 23.072 2.322 L 8.859 13.52 C 7.055 14.941 6 17.114 6 19.41 L 6 38.5 C 6 39.864 7.136 41 8.5 41 L 18.5 41 C 19.864 41 21 39.864 21 38.5 L 21 28.5 C 21 28.205 21.205 28 21.5 28 L 26.5 28 C 26.795 28 27 28.205 27 28.5 L 27 38.5 C 27 39.864 28.136 41 29.5 41 L 39.5 41 C 40.864 41 42 39.864 42 38.5 L 42 19.41 C 42 17.114 40.945 14.941 39.141 13.52 L 24.928 2.322 C 24.65 2.103 24.304 1.989 23.951 2 Z" d="M 23.951 2 C 23.631 2.011 23.323 2.124 23.072 2.322 L 8.859 13.52 C 7.055 14.941 6 17.114 6 19.41 L 6 38.5 C 6 39.864 7.136 41 8.5 41 L 18.5 41 C 19.864 41 21 39.864 21 38.5 L 21 28.5 C 21 28.205 21.205 28 21.5 28 L 26.5 28 C 26.795 28 27 28.205 27 28.5 L 27 38.5 C 27 39.864 28.136 41 29.5 41 L 39.5 41 C 40.864 41 42 39.864 42 38.5 L 42 19.41 C 42 17.114 40.945 14.941 39.141 13.52 L 24.928 2.322 C 24.65 2.103 24.304 1.989 23.951 2 Z"
/> />
</Svg> </Svg>
) )
} }
// Copyright (c) 2020 Refactoring UI Inc.
// https://github.com/tailwindlabs/heroicons/blob/master/LICENSE
export function UserGroupIcon({style}: {style?: StyleProp<ViewStyle>}) {
return (
<Svg
fill="none"
viewBox="0 0 24 24"
width="32"
height="32"
strokeWidth={1.5}
stroke="currentColor"
style={style}>
<Path
strokeLinecap="round"
strokeLinejoin="round"
d="M18 18.72a9.094 9.094 0 003.741-.479 3 3 0 00-4.682-2.72m.94 3.198l.001.031c0 .225-.012.447-.037.666A11.944 11.944 0 0112 21c-2.17 0-4.207-.576-5.963-1.584A6.062 6.062 0 016 18.719m12 0a5.971 5.971 0 00-.941-3.197m0 0A5.995 5.995 0 0012 12.75a5.995 5.995 0 00-5.058 2.772m0 0a3 3 0 00-4.681 2.72 8.986 8.986 0 003.74.477m.94-3.197a5.971 5.971 0 00-.94 3.197M15 6.75a3 3 0 11-6 0 3 3 0 016 0zm6 3a2.25 2.25 0 11-4.5 0 2.25 2.25 0 014.5 0zm-13.5 0a2.25 2.25 0 11-4.5 0 2.25 2.25 0 014.5 0z"
/>
</Svg>
)
}

View File

@ -43,7 +43,7 @@ export const Contacts = ({visible, params}: ScreenParams) => {
</View> </View>
</View> </View>
<Selector <Selector
items={['All', 'Following']} items={['All', 'Following', 'Scenes']}
selectedIndex={0} selectedIndex={0}
swipeGestureInterp={selectorInterp} swipeGestureInterp={selectorInterp}
/> />

View File

@ -1,6 +1,7 @@
import React, {useState, useEffect} from 'react' import React, {useState, useEffect} from 'react'
import {View} from 'react-native' import {StyleSheet, Text, View} from 'react-native'
import {Feed} from '../com/notifications/Feed' import {Feed} from '../com/notifications/Feed'
import {colors} from '../lib/styles'
import {useStores} from '../../state' import {useStores} from '../../state'
import {NotificationsViewModel} from '../../state/models/notifications-view' import {NotificationsViewModel} from '../../state/models/notifications-view'
import {ScreenParams} from '../routes' import {ScreenParams} from '../routes'
@ -35,5 +36,24 @@ export const Notifications = ({visible}: ScreenParams) => {
} }
}, [visible, store]) }, [visible, store])
return <View>{notesView && <Feed view={notesView} />}</View> return (
<View>
<View style={styles.header}>
<Text style={styles.title}>Notifications</Text>
</View>
{notesView && <Feed view={notesView} />}
</View>
)
} }
const styles = StyleSheet.create({
header: {
backgroundColor: colors.white,
},
title: {
fontSize: 30,
fontWeight: 'bold',
paddingHorizontal: 12,
paddingVertical: 6,
},
})

View File

@ -2,6 +2,7 @@ import React, {useEffect} from 'react'
import {observer} from 'mobx-react-lite' import {observer} from 'mobx-react-lite'
import { import {
Image, Image,
ImageSourcePropType,
StyleSheet, StyleSheet,
SafeAreaView, SafeAreaView,
Text, Text,
@ -17,7 +18,7 @@ import Animated, {
} from 'react-native-reanimated' } from 'react-native-reanimated'
import {IconProp} from '@fortawesome/fontawesome-svg-core' import {IconProp} from '@fortawesome/fontawesome-svg-core'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {HomeIcon} from '../../lib/icons' import {HomeIcon, UserGroupIcon} from '../../lib/icons'
import {useStores} from '../../../state' import {useStores} from '../../../state'
import {s, colors} from '../../lib/styles' import {s, colors} from '../../lib/styles'
import {DEF_AVATER} from '../../lib/assets' import {DEF_AVATER} from '../../lib/assets'
@ -68,7 +69,9 @@ export const MainMenu = observer(
onPress={() => onNavigate(url)}> onPress={() => onNavigate(url)}>
<View style={[styles.menuItemIconWrapper]}> <View style={[styles.menuItemIconWrapper]}>
{icon === 'home' ? ( {icon === 'home' ? (
<HomeIcon style={styles.menuItemIcon} size={24} /> <HomeIcon style={styles.menuItemIcon} />
) : icon === 'user-group' ? (
<UserGroupIcon style={styles.menuItemIcon} />
) : ( ) : (
<FontAwesomeIcon <FontAwesomeIcon
icon={icon} icon={icon}
@ -87,6 +90,32 @@ export const MainMenu = observer(
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
) )
const MenuItemImage = ({
img,
label,
url,
count,
}: {
img: ImageSourcePropType
label: string
url: string
count?: number
}) => (
<TouchableOpacity
style={[styles.menuItem, styles.menuItemMargin]}
onPress={() => onNavigate(url)}>
<Image style={styles.menuItemImg} source={img} />
{count ? (
<View style={styles.menuItemCount}>
<Text style={styles.menuItemCountLabel}>{count}</Text>
</View>
) : undefined}
<Text style={styles.menuItemLabel} numberOfLines={1}>
{label}
</Text>
</TouchableOpacity>
)
if (!active) { if (!active) {
return <View /> return <View />
} }
@ -118,22 +147,41 @@ export const MainMenu = observer(
/> />
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<View style={[styles.section]}> <Animated.View style={[styles.section, menuItemsAnimStyle]}>
<Animated.View style={[styles.menuItems, menuItemsAnimStyle]}> <View style={[styles.menuItems]}>
<MenuItem icon="home" label="Home" url="/" /> <MenuItem icon="home" label="Home" url="/" />
<MenuItem
icon={['far', 'circle-user']}
label="Contacts"
url="/contacts"
/>
<MenuItem <MenuItem
icon={['far', 'bell']} icon={['far', 'bell']}
label="Notifications" label="Notifications"
url="/notifications" url="/notifications"
count={store.me.notificationCount} count={store.me.notificationCount}
/> />
</Animated.View>
</View> </View>
<Text style={styles.heading}>Scenes</Text>
<View style={[styles.menuItems]}>
<MenuItem icon={['far', 'compass']} label="Discover" url="/" />
<MenuItem
icon={'user-group'}
label="Create Scene"
url="/contacts"
/>
<MenuItemImage img={DEF_AVATER} label="Galaxy Brain" url="/" />
<MenuItemImage
img={DEF_AVATER}
label="Paul's Friends"
url="/"
/>
</View>
<View style={[styles.menuItems]}>
<MenuItemImage
img={DEF_AVATER}
label="Cool People Only"
url="/"
/>
<MenuItemImage img={DEF_AVATER} label="Techsky" url="/" />
</View>
</Animated.View>
</SafeAreaView> </SafeAreaView>
</Animated.View> </Animated.View>
</> </>
@ -168,6 +216,13 @@ const styles = StyleSheet.create({
section: { section: {
paddingHorizontal: 10, paddingHorizontal: 10,
}, },
heading: {
fontSize: 21,
fontWeight: 'bold',
paddingHorizontal: 10,
paddingTop: 6,
paddingBottom: 12,
},
profile: { profile: {
paddingVertical: 10, paddingVertical: 10,
@ -194,16 +249,20 @@ const styles = StyleSheet.create({
menuItems: { menuItems: {
flexDirection: 'row', flexDirection: 'row',
marginTop: 10, marginBottom: 20,
marginBottom: 10,
}, },
menuItem: { menuItem: {
width: 80, width: 82,
alignItems: 'center', alignItems: 'center',
marginRight: 6,
}, },
menuItemMargin: { menuItemMargin: {
marginRight: 14, marginRight: 10,
},
menuItemImg: {
borderRadius: 30,
width: 60,
height: 60,
marginBottom: 5,
}, },
menuItemIconWrapper: { menuItemIconWrapper: {
borderRadius: 6, borderRadius: 6,
@ -219,6 +278,7 @@ const styles = StyleSheet.create({
}, },
menuItemLabel: { menuItemLabel: {
fontSize: 13, fontSize: 13,
textAlign: 'center',
}, },
menuItemCount: { menuItemCount: {
position: 'absolute', position: 'absolute',

View File

@ -388,6 +388,7 @@ const styles = StyleSheet.create({
color: colors.white, color: colors.white,
}, },
ctrlIcon: { ctrlIcon: {
color: colors.black,
marginLeft: 'auto', marginLeft: 'auto',
marginRight: 'auto', marginRight: 'auto',
}, },