diff options
Diffstat (limited to 'src/view/com/posts/FeedItem.tsx')
-rw-r--r-- | src/view/com/posts/FeedItem.tsx | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx new file mode 100644 index 000000000..2376686df --- /dev/null +++ b/src/view/com/posts/FeedItem.tsx @@ -0,0 +1,219 @@ +import React, {useMemo} from 'react' +import {observer} from 'mobx-react-lite' +import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native' +import {bsky, AdxUri} from '@adxp/mock-api' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {FeedViewItemModel} from '../../../state/models/feed-view' +import {ComposePostModel, SharePostModel} from '../../../state/models/shell' +import {Link} from '../util/Link' +import {PostDropdownBtn} from '../util/DropdownBtn' +import {s, colors} from '../../lib/styles' +import {ago} from '../../lib/strings' +import {AVIS} from '../../lib/assets' +import {useStores} from '../../../state' + +export const FeedItem = observer(function FeedItem({ + item, +}: { + item: FeedViewItemModel +}) { + const store = useStores() + const record = item.record as unknown as bsky.Post.Record + const itemHref = useMemo(() => { + const urip = new AdxUri(item.uri) + return `/profile/${item.author.name}/post/${urip.recordKey}` + }, [item.uri, item.author.name]) + const itemTitle = `Post by ${item.author.name}` + const authorHref = `/profile/${item.author.name}` + + const onPressReply = () => { + store.shell.openModal(new ComposePostModel(item.uri)) + } + const onPressToggleRepost = () => { + item + .toggleRepost() + .catch(e => console.error('Failed to toggle repost', record, e)) + } + const onPressToggleLike = () => { + item + .toggleLike() + .catch(e => console.error('Failed to toggle like', record, e)) + } + const onPressShare = (uri: string) => { + store.shell.openModal(new SharePostModel(uri)) + } + + return ( + <Link style={styles.outer} href={itemHref} title={itemTitle}> + {item.repostedBy && ( + <View style={styles.repostedBy}> + <FontAwesomeIcon icon="retweet" style={styles.repostedByIcon} /> + <Text style={[s.gray4, s.bold, s.f13]}> + Reposted by {item.repostedBy.displayName} + </Text> + </View> + )} + <View style={styles.layout}> + <Link + style={styles.layoutAvi} + href={authorHref} + title={item.author.name}> + <Image + style={styles.avi} + source={AVIS[item.author.name] || AVIS['alice.com']} + /> + </Link> + <View style={styles.layoutContent}> + <View style={styles.meta}> + <Link + style={styles.metaItem} + href={authorHref} + title={item.author.name}> + <Text style={[s.f15, s.bold]}>{item.author.displayName}</Text> + </Link> + <Link + style={styles.metaItem} + href={authorHref} + title={item.author.name}> + <Text style={[s.f14, s.gray5]}>@{item.author.name}</Text> + </Link> + <Text style={[styles.metaItem, s.f14, s.gray5]}> + · {ago(item.indexedAt)} + </Text> + <View style={s.flex1} /> + <PostDropdownBtn + style={styles.metaItem} + itemHref={itemHref} + itemTitle={itemTitle}> + <FontAwesomeIcon + icon="ellipsis-h" + size={14} + style={[s.mt2, s.mr5]} + /> + </PostDropdownBtn> + </View> + <Text style={[styles.postText, s.f15, s['lh15-1.3']]}> + {record.text} + </Text> + <View style={styles.ctrls}> + <TouchableOpacity style={styles.ctrl} onPress={onPressReply}> + <FontAwesomeIcon + style={styles.ctrlIcon} + icon={['far', 'comment']} + size={14} + /> + <Text style={s.f13}>{item.replyCount}</Text> + </TouchableOpacity> + <TouchableOpacity style={styles.ctrl} onPress={onPressToggleRepost}> + <FontAwesomeIcon + style={ + item.myState.hasReposted + ? styles.ctrlIconReposted + : styles.ctrlIcon + } + icon="retweet" + size={18} + /> + <Text + style={ + item.myState.hasReposted ? [s.bold, s.green3, s.f13] : s.f13 + }> + {item.repostCount} + </Text> + </TouchableOpacity> + <TouchableOpacity style={styles.ctrl} onPress={onPressToggleLike}> + <FontAwesomeIcon + style={ + item.myState.hasLiked ? styles.ctrlIconLiked : styles.ctrlIcon + } + icon={[item.myState.hasLiked ? 'fas' : 'far', 'heart']} + size={14} + /> + <Text + style={item.myState.hasLiked ? [s.bold, s.red3, s.f13] : s.f13}> + {item.likeCount} + </Text> + </TouchableOpacity> + <TouchableOpacity + style={styles.ctrl} + onPress={() => onPressShare(item.uri)}> + <FontAwesomeIcon + style={styles.ctrlIcon} + icon="share-from-square" + size={14} + /> + </TouchableOpacity> + </View> + </View> + </View> + </Link> + ) +}) + +const styles = StyleSheet.create({ + outer: { + borderRadius: 6, + margin: 2, + marginBottom: 0, + backgroundColor: colors.white, + padding: 10, + }, + repostedBy: { + flexDirection: 'row', + paddingLeft: 60, + }, + repostedByIcon: { + marginRight: 2, + color: colors.gray4, + }, + layout: { + flexDirection: 'row', + }, + layoutAvi: { + width: 60, + paddingTop: 5, + }, + avi: { + width: 50, + height: 50, + borderRadius: 25, + resizeMode: 'cover', + }, + layoutContent: { + flex: 1, + }, + meta: { + flexDirection: 'row', + paddingTop: 2, + paddingBottom: 2, + }, + metaItem: { + paddingRight: 5, + }, + postText: { + paddingBottom: 5, + fontFamily: 'Helvetica Neue', + }, + ctrls: { + flexDirection: 'row', + }, + ctrl: { + flexDirection: 'row', + alignItems: 'center', + flex: 1, + paddingLeft: 4, + paddingRight: 4, + }, + ctrlIcon: { + marginRight: 5, + color: colors.gray5, + }, + ctrlIconReposted: { + marginRight: 5, + color: colors.green3, + }, + ctrlIconLiked: { + marginRight: 5, + color: colors.red3, + }, +}) |