Integrate composer into design system
parent
5eddbcea16
commit
53267d755b
|
@ -8,6 +8,7 @@ import {
|
||||||
import {useAnimatedValue} from '../../lib/hooks/useAnimatedValue'
|
import {useAnimatedValue} from '../../lib/hooks/useAnimatedValue'
|
||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
import {colors} from '../../lib/styles'
|
import {colors} from '../../lib/styles'
|
||||||
|
import {usePalette} from '../../lib/hooks/usePalette'
|
||||||
|
|
||||||
interface AutocompleteItem {
|
interface AutocompleteItem {
|
||||||
handle: string
|
handle: string
|
||||||
|
@ -23,6 +24,7 @@ export function Autocomplete({
|
||||||
items: AutocompleteItem[]
|
items: AutocompleteItem[]
|
||||||
onSelect: (item: string) => void
|
onSelect: (item: string) => void
|
||||||
}) {
|
}) {
|
||||||
|
const pal = usePalette('default')
|
||||||
const winDim = useWindowDimensions()
|
const winDim = useWindowDimensions()
|
||||||
const positionInterp = useAnimatedValue(0)
|
const positionInterp = useAnimatedValue(0)
|
||||||
|
|
||||||
|
@ -41,13 +43,18 @@ export function Autocomplete({
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Animated.View style={[styles.outer, topAnimStyle]}>
|
<Animated.View style={[styles.outer, pal.view, pal.border, topAnimStyle]}>
|
||||||
{items.map((item, i) => (
|
{items.map((item, i) => (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
key={i}
|
key={i}
|
||||||
style={styles.item}
|
style={[pal.border, styles.item]}
|
||||||
onPress={() => onSelect(item.handle)}>
|
onPress={() => onSelect(item.handle)}>
|
||||||
<Text style={styles.itemText}>@{item.handle}</Text>
|
<Text style={pal.text}>
|
||||||
|
{item.displayName || item.handle}
|
||||||
|
<Text type="body2" style={pal.textLight}>
|
||||||
|
@{item.handle}
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
))}
|
))}
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
@ -60,17 +67,11 @@ const styles = StyleSheet.create({
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
backgroundColor: colors.white,
|
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
borderTopColor: colors.gray2,
|
|
||||||
},
|
},
|
||||||
item: {
|
item: {
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderBottomColor: colors.gray1,
|
|
||||||
paddingVertical: 16,
|
paddingVertical: 16,
|
||||||
paddingHorizontal: 16,
|
paddingHorizontal: 16,
|
||||||
},
|
},
|
||||||
itemText: {
|
|
||||||
fontSize: 16,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -31,6 +31,7 @@ import {detectLinkables} from '../../../lib/strings'
|
||||||
import {UserLocalPhotosModel} from '../../../state/models/user-local-photos'
|
import {UserLocalPhotosModel} from '../../../state/models/user-local-photos'
|
||||||
import {PhotoCarouselPicker} from './PhotoCarouselPicker'
|
import {PhotoCarouselPicker} from './PhotoCarouselPicker'
|
||||||
import {SelectedPhoto} from './SelectedPhoto'
|
import {SelectedPhoto} from './SelectedPhoto'
|
||||||
|
import {usePalette} from '../../lib/hooks/usePalette'
|
||||||
|
|
||||||
const MAX_TEXT_LENGTH = 256
|
const MAX_TEXT_LENGTH = 256
|
||||||
const DANGER_TEXT_LENGTH = MAX_TEXT_LENGTH
|
const DANGER_TEXT_LENGTH = MAX_TEXT_LENGTH
|
||||||
|
@ -45,6 +46,7 @@ export const ComposePost = observer(function ComposePost({
|
||||||
onPost?: ComposerOpts['onPost']
|
onPost?: ComposerOpts['onPost']
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
}) {
|
}) {
|
||||||
|
const pal = usePalette('default')
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const textInput = useRef<TextInput>(null)
|
const textInput = useRef<TextInput>(null)
|
||||||
const [isProcessing, setIsProcessing] = useState(false)
|
const [isProcessing, setIsProcessing] = useState(false)
|
||||||
|
@ -167,7 +169,7 @@ export const ComposePost = observer(function ComposePost({
|
||||||
return v
|
return v
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Text key={i++} style={{color: colors.blue3}}>
|
<Text key={i++} style={pal.link}>
|
||||||
{v.link}
|
{v.link}
|
||||||
</Text>
|
</Text>
|
||||||
)
|
)
|
||||||
|
@ -178,11 +180,11 @@ export const ComposePost = observer(function ComposePost({
|
||||||
return (
|
return (
|
||||||
<KeyboardAvoidingView
|
<KeyboardAvoidingView
|
||||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||||
style={styles.outer}>
|
style={[pal.view, styles.outer]}>
|
||||||
<SafeAreaView style={s.flex1}>
|
<SafeAreaView style={s.flex1}>
|
||||||
<View style={styles.topbar}>
|
<View style={styles.topbar}>
|
||||||
<TouchableOpacity onPress={onPressCancel}>
|
<TouchableOpacity onPress={onPressCancel}>
|
||||||
<Text style={[s.blue3, s.f18]}>Cancel</Text>
|
<Text style={[pal.link, s.f18]}>Cancel</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<View style={s.flex1} />
|
<View style={s.flex1} />
|
||||||
{isProcessing ? (
|
{isProcessing ? (
|
||||||
|
@ -202,13 +204,13 @@ export const ComposePost = observer(function ComposePost({
|
||||||
</LinearGradient>
|
</LinearGradient>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
) : (
|
) : (
|
||||||
<View style={[styles.postBtn, {backgroundColor: colors.gray1}]}>
|
<View style={[styles.postBtn, pal.btn]}>
|
||||||
<Text style={[s.gray5, s.f16, s.bold]}>Post</Text>
|
<Text style={[pal.textLight, s.f16, s.bold]}>Post</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
{isProcessing ? (
|
{isProcessing ? (
|
||||||
<View style={styles.processingLine}>
|
<View style={[pal.btn, styles.processingLine]}>
|
||||||
<Text style={s.black}>{processingState}</Text>
|
<Text style={s.black}>{processingState}</Text>
|
||||||
</View>
|
</View>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
|
@ -226,7 +228,7 @@ export const ComposePost = observer(function ComposePost({
|
||||||
)}
|
)}
|
||||||
<ScrollView style={s.flex1}>
|
<ScrollView style={s.flex1}>
|
||||||
{replyTo ? (
|
{replyTo ? (
|
||||||
<View style={styles.replyToLayout}>
|
<View style={[pal.border, styles.replyToLayout]}>
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
handle={replyTo.author.handle}
|
handle={replyTo.author.handle}
|
||||||
displayName={replyTo.author.displayName}
|
displayName={replyTo.author.displayName}
|
||||||
|
@ -235,17 +237,19 @@ export const ComposePost = observer(function ComposePost({
|
||||||
/>
|
/>
|
||||||
<View style={styles.replyToPost}>
|
<View style={styles.replyToPost}>
|
||||||
<TextLink
|
<TextLink
|
||||||
|
type="h5"
|
||||||
href={`/profile/${replyTo.author.handle}`}
|
href={`/profile/${replyTo.author.handle}`}
|
||||||
text={replyTo.author.displayName || replyTo.author.handle}
|
text={replyTo.author.displayName || replyTo.author.handle}
|
||||||
style={[s.f16, s.bold, s.black]}
|
style={[pal.text]}
|
||||||
/>
|
/>
|
||||||
<Text style={[s.f16, s['lh16-1.3'], s.black]} numberOfLines={6}>
|
<Text style={pal.text} numberOfLines={6}>
|
||||||
{replyTo.text}
|
{replyTo.text}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<View style={[styles.textInputLayout, selectTextInputLayout]}>
|
<View
|
||||||
|
style={[pal.border, styles.textInputLayout, selectTextInputLayout]}>
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
handle={store.me.handle || ''}
|
handle={store.me.handle || ''}
|
||||||
displayName={store.me.displayName}
|
displayName={store.me.displayName}
|
||||||
|
@ -258,8 +262,8 @@ export const ComposePost = observer(function ComposePost({
|
||||||
scrollEnabled
|
scrollEnabled
|
||||||
onChangeText={(text: string) => onChangeText(text)}
|
onChangeText={(text: string) => onChangeText(text)}
|
||||||
placeholder={selectTextInputPlaceholder}
|
placeholder={selectTextInputPlaceholder}
|
||||||
placeholderTextColor={colors.gray4}
|
placeholderTextColor={pal.colors.textLight}
|
||||||
style={styles.textInput}>
|
style={[pal.text, styles.textInput]}>
|
||||||
{textDecorated}
|
{textDecorated}
|
||||||
</TextInput>
|
</TextInput>
|
||||||
</View>
|
</View>
|
||||||
|
@ -277,16 +281,14 @@ export const ComposePost = observer(function ComposePost({
|
||||||
localPhotos={localPhotos}
|
localPhotos={localPhotos}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<View style={styles.bottomBar}>
|
<View style={[pal.border, styles.bottomBar]}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={onPressSelectPhotos}
|
onPress={onPressSelectPhotos}
|
||||||
style={[s.pl5]}
|
style={[s.pl5]}
|
||||||
hitSlop={HITSLOP}>
|
hitSlop={HITSLOP}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={['far', 'image']}
|
icon={['far', 'image']}
|
||||||
style={{
|
style={selectedPhotos.length < 4 ? pal.link : pal.textLight}
|
||||||
color: selectedPhotos.length < 4 ? colors.blue3 : colors.gray3,
|
|
||||||
}}
|
|
||||||
size={24}
|
size={24}
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
@ -343,7 +345,6 @@ const styles = StyleSheet.create({
|
||||||
outer: {
|
outer: {
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
flex: 1,
|
flex: 1,
|
||||||
backgroundColor: '#fff',
|
|
||||||
padding: 15,
|
padding: 15,
|
||||||
paddingBottom: Platform.OS === 'ios' ? 0 : 50,
|
paddingBottom: Platform.OS === 'ios' ? 0 : 50,
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
@ -361,7 +362,6 @@ const styles = StyleSheet.create({
|
||||||
paddingVertical: 6,
|
paddingVertical: 6,
|
||||||
},
|
},
|
||||||
processingLine: {
|
processingLine: {
|
||||||
backgroundColor: colors.gray1,
|
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
paddingHorizontal: 8,
|
paddingHorizontal: 8,
|
||||||
paddingVertical: 6,
|
paddingVertical: 6,
|
||||||
|
@ -395,7 +395,6 @@ const styles = StyleSheet.create({
|
||||||
textInputLayout: {
|
textInputLayout: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
borderTopColor: colors.gray2,
|
|
||||||
paddingTop: 16,
|
paddingTop: 16,
|
||||||
},
|
},
|
||||||
textInput: {
|
textInput: {
|
||||||
|
@ -404,12 +403,10 @@ const styles = StyleSheet.create({
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
marginLeft: 8,
|
marginLeft: 8,
|
||||||
alignSelf: 'flex-start',
|
alignSelf: 'flex-start',
|
||||||
color: colors.black,
|
|
||||||
},
|
},
|
||||||
replyToLayout: {
|
replyToLayout: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
borderTopColor: colors.gray2,
|
|
||||||
paddingTop: 16,
|
paddingTop: 16,
|
||||||
paddingBottom: 16,
|
paddingBottom: 16,
|
||||||
},
|
},
|
||||||
|
@ -424,7 +421,5 @@ const styles = StyleSheet.create({
|
||||||
paddingRight: 5,
|
paddingRight: 5,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
borderTopColor: colors.gray2,
|
|
||||||
backgroundColor: colors.white,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
openCropper,
|
openCropper,
|
||||||
} from 'react-native-image-crop-picker'
|
} from 'react-native-image-crop-picker'
|
||||||
import {compressIfNeeded} from '../../../lib/images'
|
import {compressIfNeeded} from '../../../lib/images'
|
||||||
|
import {usePalette} from '../../lib/hooks/usePalette'
|
||||||
|
|
||||||
const IMAGE_PARAMS = {
|
const IMAGE_PARAMS = {
|
||||||
width: 1000,
|
width: 1000,
|
||||||
|
@ -26,6 +27,7 @@ export const PhotoCarouselPicker = ({
|
||||||
onSelectPhotos: (v: string[]) => void
|
onSelectPhotos: (v: string[]) => void
|
||||||
localPhotos: any
|
localPhotos: any
|
||||||
}) => {
|
}) => {
|
||||||
|
const pal = usePalette('default')
|
||||||
const handleOpenCamera = useCallback(async () => {
|
const handleOpenCamera = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const cameraRes = await openCamera({
|
const cameraRes = await openCamera({
|
||||||
|
@ -83,26 +85,22 @@ export const PhotoCarouselPicker = ({
|
||||||
return (
|
return (
|
||||||
<ScrollView
|
<ScrollView
|
||||||
horizontal
|
horizontal
|
||||||
style={styles.photosContainer}
|
style={[pal.view, styles.photosContainer]}
|
||||||
showsHorizontalScrollIndicator={false}>
|
showsHorizontalScrollIndicator={false}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.galleryButton, styles.photo]}
|
style={[styles.galleryButton, pal.border, styles.photo]}
|
||||||
onPress={handleOpenCamera}>
|
onPress={handleOpenCamera}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon icon="camera" size={24} style={pal.link} />
|
||||||
icon="camera"
|
|
||||||
size={24}
|
|
||||||
style={{color: colors.blue3}}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.galleryButton, styles.photo]}
|
style={[styles.galleryButton, pal.border, styles.photo]}
|
||||||
onPress={handleOpenGallery}>
|
onPress={handleOpenGallery}>
|
||||||
<FontAwesomeIcon icon="image" style={{color: colors.blue3}} size={24} />
|
<FontAwesomeIcon icon="image" style={pal.link} size={24} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
{localPhotos.photos.map((item: any, index: number) => (
|
{localPhotos.photos.map((item: any, index: number) => (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
key={`local-image-${index}`}
|
key={`local-image-${index}`}
|
||||||
style={styles.photoButton}
|
style={[pal.border, styles.photoButton]}
|
||||||
onPress={() => handleSelectPhoto(item.node.image.uri)}>
|
onPress={() => handleSelectPhoto(item.node.image.uri)}>
|
||||||
<Image style={styles.photo} source={{uri: item.node.image.uri}} />
|
<Image style={styles.photo} source={{uri: item.node.image.uri}} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
@ -117,11 +115,9 @@ const styles = StyleSheet.create({
|
||||||
maxHeight: 96,
|
maxHeight: 96,
|
||||||
padding: 8,
|
padding: 8,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
backgroundColor: colors.white,
|
|
||||||
},
|
},
|
||||||
galleryButton: {
|
galleryButton: {
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: colors.gray3,
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
|
@ -131,7 +127,6 @@ const styles = StyleSheet.create({
|
||||||
marginRight: 8,
|
marginRight: 8,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: 16,
|
borderRadius: 16,
|
||||||
borderColor: colors.gray3,
|
|
||||||
},
|
},
|
||||||
photo: {
|
photo: {
|
||||||
width: 75,
|
width: 75,
|
||||||
|
|
Loading…
Reference in New Issue