Add scene creator
parent
93b64cf474
commit
e7536289cb
|
@ -9,14 +9,14 @@ import {createContext, useContext} from 'react'
|
||||||
import {isObj, hasProp} from '../lib/type-guards'
|
import {isObj, hasProp} from '../lib/type-guards'
|
||||||
import {SessionModel} from './session'
|
import {SessionModel} from './session'
|
||||||
import {NavigationModel} from './navigation'
|
import {NavigationModel} from './navigation'
|
||||||
import {ShellModel} from './shell'
|
import {ShellUiModel} from './shell-ui'
|
||||||
import {MeModel} from './me'
|
import {MeModel} from './me'
|
||||||
import {OnboardModel} from './onboard'
|
import {OnboardModel} from './onboard'
|
||||||
|
|
||||||
export class RootStoreModel {
|
export class RootStoreModel {
|
||||||
session = new SessionModel(this)
|
session = new SessionModel(this)
|
||||||
nav = new NavigationModel()
|
nav = new NavigationModel()
|
||||||
shell = new ShellModel()
|
shell = new ShellUiModel()
|
||||||
me = new MeModel(this)
|
me = new MeModel(this)
|
||||||
onboard = new OnboardModel()
|
onboard = new OnboardModel()
|
||||||
|
|
||||||
|
|
|
@ -35,14 +35,27 @@ export class EditProfileModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class CreateSceneModel {
|
||||||
|
name = 'create-scene'
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
makeAutoObservable(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface ComposerOpts {
|
export interface ComposerOpts {
|
||||||
replyTo?: Post.PostRef
|
replyTo?: Post.PostRef
|
||||||
onPost?: () => void
|
onPost?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ShellModel {
|
export class ShellUiModel {
|
||||||
isModalActive = false
|
isModalActive = false
|
||||||
activeModal: LinkActionsModel | SharePostModel | EditProfileModel | undefined
|
activeModal:
|
||||||
|
| LinkActionsModel
|
||||||
|
| SharePostModel
|
||||||
|
| EditProfileModel
|
||||||
|
| CreateSceneModel
|
||||||
|
| undefined
|
||||||
isComposerActive = false
|
isComposerActive = false
|
||||||
composerOpts: ComposerOpts | undefined
|
composerOpts: ComposerOpts | undefined
|
||||||
|
|
||||||
|
@ -50,7 +63,13 @@ export class ShellModel {
|
||||||
makeAutoObservable(this)
|
makeAutoObservable(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
openModal(modal: LinkActionsModel | SharePostModel | EditProfileModel) {
|
openModal(
|
||||||
|
modal:
|
||||||
|
| LinkActionsModel
|
||||||
|
| SharePostModel
|
||||||
|
| EditProfileModel
|
||||||
|
| CreateSceneModel,
|
||||||
|
) {
|
||||||
this.isModalActive = true
|
this.isModalActive = true
|
||||||
this.activeModal = modal
|
this.activeModal = modal
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@ import Toast from '../util/Toast'
|
||||||
import ProgressCircle from '../util/ProgressCircle'
|
import ProgressCircle from '../util/ProgressCircle'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import * as apilib from '../../../state/lib/api'
|
import * as apilib from '../../../state/lib/api'
|
||||||
import {ComposerOpts} from '../../../state/models/shell'
|
import {ComposerOpts} from '../../../state/models/shell-ui'
|
||||||
import {s, colors, gradients} from '../../lib/styles'
|
import {s, colors, gradients} from '../../lib/styles'
|
||||||
|
|
||||||
const MAX_TEXT_LENGTH = 256
|
const MAX_TEXT_LENGTH = 256
|
||||||
|
|
|
@ -0,0 +1,210 @@
|
||||||
|
import React, {useState} from 'react'
|
||||||
|
import Toast from '../util/Toast'
|
||||||
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from 'react-native'
|
||||||
|
import LinearGradient from 'react-native-linear-gradient'
|
||||||
|
import {ErrorMessage} from '../util/ErrorMessage'
|
||||||
|
import {useStores} from '../../../state'
|
||||||
|
import {s, colors, gradients} from '../../lib/styles'
|
||||||
|
import {makeValidHandle, createFullHandle} from '../../lib/strings'
|
||||||
|
import {AppBskyActorCreateScene} from '../../../third-party/api/index'
|
||||||
|
|
||||||
|
export const snapPoints = ['70%']
|
||||||
|
|
||||||
|
export function Component({}: {}) {
|
||||||
|
const store = useStores()
|
||||||
|
const [error, setError] = useState<string>('')
|
||||||
|
const [isProcessing, setIsProcessing] = useState<boolean>(false)
|
||||||
|
const [handle, setHandle] = useState<string>('')
|
||||||
|
const [displayName, setDisplayName] = useState<string>('')
|
||||||
|
const [description, setDescription] = useState<string>('')
|
||||||
|
const onPressSave = async () => {
|
||||||
|
setIsProcessing(true)
|
||||||
|
if (error) {
|
||||||
|
setError('')
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (!store.me.did) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const desc = await store.api.com.atproto.server.getAccountsConfig()
|
||||||
|
const fullHandle = createFullHandle(
|
||||||
|
handle,
|
||||||
|
desc.data.availableUserDomains[0],
|
||||||
|
)
|
||||||
|
// create scene actor
|
||||||
|
const createSceneRes = await store.api.app.bsky.actor.createScene({
|
||||||
|
handle: fullHandle,
|
||||||
|
})
|
||||||
|
// set the scene profile
|
||||||
|
// TODO
|
||||||
|
// follow the scene
|
||||||
|
await store.api.app.bsky.graph.follow
|
||||||
|
.create(
|
||||||
|
{
|
||||||
|
did: store.me.did,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
subject: {
|
||||||
|
did: createSceneRes.data.did,
|
||||||
|
declarationCid: createSceneRes.data.declarationCid,
|
||||||
|
},
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.catch(e => console.error(e)) // an error here is not critical
|
||||||
|
Toast.show('Scene created', {
|
||||||
|
position: Toast.positions.TOP,
|
||||||
|
})
|
||||||
|
store.shell.closeModal()
|
||||||
|
store.nav.navigate(`/profile/${fullHandle}`)
|
||||||
|
} catch (e: any) {
|
||||||
|
if (e instanceof AppBskyActorCreateScene.InvalidHandleError) {
|
||||||
|
setError(
|
||||||
|
'The handle can only contain letters, numbers, and dashes, and must start with a letter.',
|
||||||
|
)
|
||||||
|
} else if (e instanceof AppBskyActorCreateScene.HandleNotAvailableError) {
|
||||||
|
setError(`The handle "${handle}" is not available.`)
|
||||||
|
} else {
|
||||||
|
console.error(e)
|
||||||
|
setError(
|
||||||
|
'Failed to create the scene. Check your internet connection and try again.',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
setIsProcessing(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={s.flex1}>
|
||||||
|
<Text style={styles.title}>Create a scene</Text>
|
||||||
|
<Text style={styles.description}>
|
||||||
|
Scenes are invite-only groups which aggregate what's popular with
|
||||||
|
members.
|
||||||
|
</Text>
|
||||||
|
<View style={styles.inner}>
|
||||||
|
<View style={styles.group}>
|
||||||
|
<Text style={styles.label}>Scene Handle</Text>
|
||||||
|
<TextInput
|
||||||
|
style={styles.textInput}
|
||||||
|
placeholder="e.g. alices-friends"
|
||||||
|
value={handle}
|
||||||
|
onChangeText={str => setHandle(makeValidHandle(str))}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.group}>
|
||||||
|
<Text style={styles.label}>Scene Display Name</Text>
|
||||||
|
<TextInput
|
||||||
|
style={styles.textInput}
|
||||||
|
placeholder="e.g. Alice's Friends"
|
||||||
|
value={displayName}
|
||||||
|
onChangeText={setDisplayName}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.group}>
|
||||||
|
<Text style={styles.label}>Scene Description</Text>
|
||||||
|
<TextInput
|
||||||
|
style={[styles.textArea]}
|
||||||
|
placeholder="e.g. Artists, dog-lovers, and memelords."
|
||||||
|
multiline
|
||||||
|
value={description}
|
||||||
|
onChangeText={setDescription}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.errorContainer}>
|
||||||
|
{error !== '' && (
|
||||||
|
<View style={s.mb10}>
|
||||||
|
<ErrorMessage message={error} numberOfLines={3} />
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
{handle.length >= 2 && !isProcessing ? (
|
||||||
|
<TouchableOpacity style={s.mt10} onPress={onPressSave}>
|
||||||
|
<LinearGradient
|
||||||
|
colors={[gradients.primary.start, gradients.primary.end]}
|
||||||
|
start={{x: 0, y: 0}}
|
||||||
|
end={{x: 1, y: 1}}
|
||||||
|
style={[styles.btn]}>
|
||||||
|
<Text style={[s.white, s.bold, s.f18]}>Create Scene</Text>
|
||||||
|
</LinearGradient>
|
||||||
|
</TouchableOpacity>
|
||||||
|
) : (
|
||||||
|
<View style={s.mt10}>
|
||||||
|
<View style={[styles.btn]}>
|
||||||
|
{isProcessing ? (
|
||||||
|
<ActivityIndicator />
|
||||||
|
) : (
|
||||||
|
<Text style={[s.gray4, s.bold, s.f18]}>Create Scene</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
title: {
|
||||||
|
textAlign: 'center',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
fontSize: 24,
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: 17,
|
||||||
|
paddingHorizontal: 22,
|
||||||
|
color: colors.gray5,
|
||||||
|
marginBottom: 10,
|
||||||
|
},
|
||||||
|
inner: {
|
||||||
|
padding: 14,
|
||||||
|
},
|
||||||
|
group: {
|
||||||
|
marginBottom: 10,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
paddingHorizontal: 4,
|
||||||
|
paddingBottom: 4,
|
||||||
|
},
|
||||||
|
textInput: {
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: colors.gray3,
|
||||||
|
borderRadius: 6,
|
||||||
|
paddingHorizontal: 14,
|
||||||
|
paddingVertical: 10,
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
textArea: {
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: colors.gray3,
|
||||||
|
borderRadius: 6,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingTop: 10,
|
||||||
|
fontSize: 16,
|
||||||
|
height: 100,
|
||||||
|
textAlignVertical: 'top',
|
||||||
|
},
|
||||||
|
errorContainer: {
|
||||||
|
height: 80,
|
||||||
|
},
|
||||||
|
btn: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
width: '100%',
|
||||||
|
borderRadius: 32,
|
||||||
|
padding: 14,
|
||||||
|
marginBottom: 10,
|
||||||
|
backgroundColor: colors.gray1,
|
||||||
|
},
|
||||||
|
})
|
|
@ -68,7 +68,7 @@ export function Component({profileView}: {profileView: ProfileViewModel}) {
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.group}>
|
<View style={styles.group}>
|
||||||
<Text style={styles.label}>Biography</Text>
|
<Text style={styles.label}>Description</Text>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={[styles.textArea]}
|
style={[styles.textArea]}
|
||||||
placeholder="e.g. Artist, dog-lover, and memelord."
|
placeholder="e.g. Artist, dog-lover, and memelord."
|
||||||
|
|
|
@ -5,11 +5,12 @@ import BottomSheet from '@gorhom/bottom-sheet'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop'
|
import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop'
|
||||||
|
|
||||||
import * as models from '../../../state/models/shell'
|
import * as models from '../../../state/models/shell-ui'
|
||||||
|
|
||||||
import * as LinkActionsModal from './LinkActions'
|
import * as LinkActionsModal from './LinkActions'
|
||||||
import * as SharePostModal from './SharePost.native'
|
import * as SharePostModal from './SharePost.native'
|
||||||
import * as EditProfile from './EditProfile'
|
import * as EditProfile from './EditProfile'
|
||||||
|
import * as CreateScene from './CreateScene'
|
||||||
|
|
||||||
const CLOSED_SNAPPOINTS = ['10%']
|
const CLOSED_SNAPPOINTS = ['10%']
|
||||||
|
|
||||||
|
@ -57,6 +58,9 @@ export const Modal = observer(function Modal() {
|
||||||
{...(store.shell.activeModal as models.EditProfileModel)}
|
{...(store.shell.activeModal as models.EditProfileModel)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
} else if (store.shell.activeModal?.name === 'create-scene') {
|
||||||
|
snapPoints = CreateScene.snapPoints
|
||||||
|
element = <CreateScene.Component />
|
||||||
} else {
|
} else {
|
||||||
element = <View />
|
element = <View />
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
PostThreadViewPostModel,
|
PostThreadViewPostModel,
|
||||||
} from '../../../state/models/post-thread-view'
|
} from '../../../state/models/post-thread-view'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {SharePostModel} from '../../../state/models/shell'
|
import {SharePostModel} from '../../../state/models/shell-ui'
|
||||||
import {PostThreadItem} from './PostThreadItem'
|
import {PostThreadItem} from './PostThreadItem'
|
||||||
|
|
||||||
export const PostThread = observer(function PostThread({uri}: {uri: string}) {
|
export const PostThread = observer(function PostThread({uri}: {uri: string}) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {AtUri} from '../../../third-party/uri'
|
||||||
import * as PostType from '../../../third-party/api/src/client/types/app/bsky/feed/post'
|
import * as PostType from '../../../third-party/api/src/client/types/app/bsky/feed/post'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {FeedItemModel} from '../../../state/models/feed-view'
|
import {FeedItemModel} from '../../../state/models/feed-view'
|
||||||
import {SharePostModel} from '../../../state/models/shell'
|
import {SharePostModel} from '../../../state/models/shell-ui'
|
||||||
import {Link} from '../util/Link'
|
import {Link} from '../util/Link'
|
||||||
import {PostDropdownBtn} from '../util/DropdownBtn'
|
import {PostDropdownBtn} from '../util/DropdownBtn'
|
||||||
import {UserInfoText} from '../util/UserInfoText'
|
import {UserInfoText} from '../util/UserInfoText'
|
||||||
|
|
|
@ -11,7 +11,7 @@ import LinearGradient from 'react-native-linear-gradient'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {ProfileViewModel} from '../../../state/models/profile-view'
|
import {ProfileViewModel} from '../../../state/models/profile-view'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {EditProfileModel} from '../../../state/models/shell'
|
import {EditProfileModel} from '../../../state/models/shell-ui'
|
||||||
import {pluralize} from '../../lib/strings'
|
import {pluralize} from '../../lib/strings'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {getGradient} from '../../lib/asset-gen'
|
import {getGradient} from '../../lib/asset-gen'
|
||||||
|
|
|
@ -13,7 +13,7 @@ import RootSiblings from 'react-native-root-siblings'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {colors} from '../../lib/styles'
|
import {colors} from '../../lib/styles'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {SharePostModel} from '../../../state/models/shell'
|
import {SharePostModel} from '../../../state/models/shell-ui'
|
||||||
|
|
||||||
export interface DropdownItem {
|
export interface DropdownItem {
|
||||||
icon?: IconProp
|
icon?: IconProp
|
||||||
|
|
|
@ -5,9 +5,11 @@ import {colors} from '../../lib/styles'
|
||||||
|
|
||||||
export function ErrorMessage({
|
export function ErrorMessage({
|
||||||
message,
|
message,
|
||||||
|
numberOfLines,
|
||||||
onPressTryAgain,
|
onPressTryAgain,
|
||||||
}: {
|
}: {
|
||||||
message: string
|
message: string
|
||||||
|
numberOfLines?: number
|
||||||
onPressTryAgain?: () => void
|
onPressTryAgain?: () => void
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
|
@ -19,7 +21,9 @@ export function ErrorMessage({
|
||||||
size={16}
|
size={16}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<Text style={styles.message}>{message}</Text>
|
<Text style={styles.message} numberOfLines={numberOfLines}>
|
||||||
|
{message}
|
||||||
|
</Text>
|
||||||
{onPressTryAgain && (
|
{onPressTryAgain && (
|
||||||
<TouchableOpacity style={styles.btn} onPress={onPressTryAgain}>
|
<TouchableOpacity style={styles.btn} onPress={onPressTryAgain}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {StyleProp, Text, TouchableOpacity, ViewStyle} from 'react-native'
|
import {StyleProp, Text, TouchableOpacity, ViewStyle} from 'react-native'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {LinkActionsModel} from '../../../state/models/shell'
|
import {LinkActionsModel} from '../../../state/models/shell-ui'
|
||||||
|
|
||||||
export const Link = observer(function Link({
|
export const Link = observer(function Link({
|
||||||
style,
|
style,
|
||||||
|
|
|
@ -71,3 +71,17 @@ export function extractEntities(text: string): Entity[] | undefined {
|
||||||
}
|
}
|
||||||
return ents.length > 0 ? ents : undefined
|
return ents.length > 0 ? ents : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function makeValidHandle(str: string): string {
|
||||||
|
if (str.length > 20) {
|
||||||
|
str = str.slice(0, 20)
|
||||||
|
}
|
||||||
|
str = str.toLowerCase()
|
||||||
|
return str.replace(/^[^a-z]+/g, '').replace(/[^a-z0-9-]/g, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createFullHandle(name: string, domain: string): string {
|
||||||
|
name = name.replace(/[\.]+$/, '')
|
||||||
|
domain = domain.replace(/^[\.]+/, '')
|
||||||
|
return `${name}.${domain}`
|
||||||
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {HomeIcon, UserGroupIcon, BellIcon} from '../../lib/icons'
|
import {HomeIcon, UserGroupIcon, BellIcon} from '../../lib/icons'
|
||||||
import {ComposePost} from '../../com/composer/ComposePost'
|
import {ComposePost} from '../../com/composer/ComposePost'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {ComposerOpts} from '../../../state/models/shell'
|
import {ComposerOpts} from '../../../state/models/shell-ui'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
|
|
||||||
export const Composer = observer(
|
export const Composer = observer(
|
||||||
|
|
|
@ -20,6 +20,7 @@ import _chunk from 'lodash.chunk'
|
||||||
import {HomeIcon, UserGroupIcon, BellIcon} from '../../lib/icons'
|
import {HomeIcon, UserGroupIcon, BellIcon} from '../../lib/icons'
|
||||||
import {UserAvatar} from '../../com/util/UserAvatar'
|
import {UserAvatar} from '../../com/util/UserAvatar'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
|
import {CreateSceneModel} from '../../../state/models/shell-ui'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
|
|
||||||
export const MainMenu = observer(
|
export const MainMenu = observer(
|
||||||
|
@ -54,6 +55,10 @@ export const MainMenu = observer(
|
||||||
store.nav.navigate(url)
|
store.nav.navigate(url)
|
||||||
onClose()
|
onClose()
|
||||||
}
|
}
|
||||||
|
const onPressCreateScene = () => {
|
||||||
|
store.shell.openModal(new CreateSceneModel())
|
||||||
|
onClose()
|
||||||
|
}
|
||||||
|
|
||||||
// rendering
|
// rendering
|
||||||
// =
|
// =
|
||||||
|
@ -65,17 +70,19 @@ export const MainMenu = observer(
|
||||||
const MenuItem = ({
|
const MenuItem = ({
|
||||||
icon,
|
icon,
|
||||||
label,
|
label,
|
||||||
url,
|
|
||||||
count,
|
count,
|
||||||
|
url,
|
||||||
|
onPress,
|
||||||
}: {
|
}: {
|
||||||
icon: IconProp
|
icon: IconProp
|
||||||
label: string
|
label: string
|
||||||
url: string
|
|
||||||
count?: number
|
count?: number
|
||||||
|
url?: string
|
||||||
|
onPress?: () => void
|
||||||
}) => (
|
}) => (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.menuItem, styles.menuItemMargin]}
|
style={[styles.menuItem, styles.menuItemMargin]}
|
||||||
onPress={() => onNavigate(url)}>
|
onPress={onPress ? onPress : () => onNavigate(url || '/')}>
|
||||||
<View style={[styles.menuItemIconWrapper]}>
|
<View style={[styles.menuItemIconWrapper]}>
|
||||||
{icon === 'home' ? (
|
{icon === 'home' ? (
|
||||||
<HomeIcon style={styles.menuItemIcon} size="32" />
|
<HomeIcon style={styles.menuItemIcon} size="32" />
|
||||||
|
@ -209,7 +216,7 @@ export const MainMenu = observer(
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon={'user-group'}
|
icon={'user-group'}
|
||||||
label="Create Scene"
|
label="Create Scene"
|
||||||
url="/contacts"
|
onPress={onPressCreateScene}
|
||||||
/>
|
/>
|
||||||
{store.me.memberships ? (
|
{store.me.memberships ? (
|
||||||
store.me.memberships.memberships.map((membership, i) => (
|
store.me.memberships.memberships.map((membership, i) => (
|
||||||
|
|
|
@ -19,7 +19,7 @@ import Swipeable from 'react-native-gesture-handler/Swipeable'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {match} from '../../routes'
|
import {match} from '../../routes'
|
||||||
import {LinkActionsModel} from '../../../state/models/shell'
|
import {LinkActionsModel} from '../../../state/models/shell-ui'
|
||||||
|
|
||||||
const TAB_HEIGHT = 42
|
const TAB_HEIGHT = 42
|
||||||
|
|
||||||
|
|
|
@ -230,11 +230,11 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
/>
|
/>
|
||||||
<Btn icon={['far', 'clone']} onPress={onPressTabs} />
|
<Btn icon={['far', 'clone']} onPress={onPressTabs} />
|
||||||
</View>
|
</View>
|
||||||
<Modal />
|
|
||||||
<MainMenu
|
<MainMenu
|
||||||
active={isMainMenuActive}
|
active={isMainMenuActive}
|
||||||
onClose={() => setMainMenuActive(false)}
|
onClose={() => setMainMenuActive(false)}
|
||||||
/>
|
/>
|
||||||
|
<Modal />
|
||||||
<TabsSelector
|
<TabsSelector
|
||||||
active={isTabsSelectorActive}
|
active={isTabsSelectorActive}
|
||||||
onClose={() => setTabsSelectorActive(false)}
|
onClose={() => setTabsSelectorActive(false)}
|
||||||
|
|
Loading…
Reference in New Issue