Skip to content

Commit

Permalink
Added ghost icon
Browse files Browse the repository at this point in the history
  • Loading branch information
Kwasow committed Jan 25, 2025
1 parent 57c4161 commit a8c1cf5
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 37 deletions.
6 changes: 6 additions & 0 deletions assets/ghost.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"react-native-safe-area-context": "4.8.2",
"react-native-screens": "~3.29.0",
"react-native-static-safe-area-insets": "^2.2.0",
"react-native-svg": "^15.4.0",
"react-native-svg": "14.1.0",
"react-native-video": "^6.2.0",
"react-native-vision-camera": "4.6.1",
"react-native-web": "~0.19.6",
Expand Down
47 changes: 27 additions & 20 deletions src/app/(auth)/(tabs)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useState, useRef, useMemo } from 'react'
import { FlatList, StyleSheet, ActivityIndicator, Platform, ListRenderItemInfo } from 'react-native'
import { Text, View, XStack, Spinner } from 'tamagui'
import { Text, View, XStack, Spinner, YStack } from 'tamagui'
import FeedPost from 'src/components/post/FeedPost'
import { StatusBar } from 'expo-status-bar'
import { SafeAreaView } from 'react-native-safe-area-context'
Expand All @@ -27,6 +27,7 @@ import {
} from 'src/lib/api'
import FeedHeader from 'src/components/common/FeedHeader'
import EmptyFeed from 'src/components/common/EmptyFeed'
import ErrorFeed from 'src/components/common/ErrorFeed'
import { BottomSheetModal, BottomSheetBackdrop } from '@gorhom/bottom-sheet'
import CommentFeed from 'src/components/post/CommentFeed'
import { useShareIntentContext } from 'expo-share-intent'
Expand Down Expand Up @@ -282,6 +283,27 @@ export default function HomeScreen() {
)
}

const renderFeed = (data: Array<Status>) => {
return <FlatList
ref={flatListRef}
data={data}
keyExtractor={keyExtractor}
renderItem={renderItem}
maxToRenderPerBatch={3}
refreshing={isRefetching}
onRefresh={refetch}
showsVerticalScrollIndicator={false}
ListEmptyComponent={status === 'success' ? <EmptyFeed /> : <ErrorFeed />}
onViewableItemsChanged={onViewRef}
viewabilityConfig={viewConfigRef.current}
onEndReached={() => {
if (hasNextPage && !isFetching && !isFetchingNextPage) fetchNextPage()
}}
onEndReachedThreshold={0.5}
ListFooterComponent={() => (isFetchingNextPage ? <ActivityIndicator /> : null)}
/>
}

return (
<SafeAreaView style={styles.container} edges={['top']}>
<StatusBar style="dark" />
Expand Down Expand Up @@ -316,24 +338,9 @@ export default function HomeScreen() {
handleReport={handleCommentReport}
/>
</BottomSheetModal>
<FlatList
ref={flatListRef}
data={data?.pages.flatMap((page) => page.data)}
keyExtractor={keyExtractor}
renderItem={renderItem}
maxToRenderPerBatch={3}
refreshing={isRefetching}
onRefresh={refetch}
showsVerticalScrollIndicator={false}
ListEmptyComponent={status === 'success' ? <EmptyFeed /> : null}
onViewableItemsChanged={onViewRef}
viewabilityConfig={viewConfigRef.current}
onEndReached={() => {
if (hasNextPage && !isFetching && !isFetchingNextPage) fetchNextPage()
}}
onEndReachedThreshold={0.5}
ListFooterComponent={() => (isFetchingNextPage ? <ActivityIndicator /> : null)}
/>

{renderFeed(data?.pages.flatMap((page) => page.data))}

</SafeAreaView>
)
}
Expand Down Expand Up @@ -363,5 +370,5 @@ const styles = StyleSheet.create({
textAlign: 'center',
color: 'white',
fontWeight: '800',
},
}
})
45 changes: 35 additions & 10 deletions src/components/common/EmptyFeed.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,40 @@
import { Text, View, YStack } from 'tamagui'
import { Feather } from '@expo/vector-icons'
import { Text, YStack } from 'tamagui'
import { StyleSheet } from 'react-native'
import GhostIcon from '../icons/GhostIcon'

const almostBlack = 'rgb(64, 64, 64)'

export default function EmptyFeed() {
return (
<View my="$6" justifyContent="center" alignItems="center">
<YStack justifyContent="center" alignItems="center" gap="$3">
<Feather name="alert-circle" size={80} color="red" />
<Text fontSize="$9">No posts found!</Text>
<Text fontSize="$7">The service may be temporarily unavailable.</Text>
<Text fontSize="$5">Pull to refresh</Text>
</YStack>
</View>
<YStack
p='$4'
pt='$12'
alignContent='center'
justifyContent='center'
alignItems='center'
>
<GhostIcon width={200} height={200} color={almostBlack}/>

<Text style={styles.noPostsHeader}>
Ghosts have taken over this timeline!
</Text>
<Text style={styles.noPostsText}>
Try following some accounts to get rid of them!
</Text>
</YStack>
)
}

const styles = StyleSheet.create({
noPostsHeader: {
textAlign: 'center',
fontWeight: 'bold',
fontSize: 24,
color: 'darkgray',
paddingTop: 24
},
noPostsText: {
textAlign: 'center',
color: 'darkgray'
}
})
13 changes: 13 additions & 0 deletions src/components/common/ErrorFeed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Text, View, YStack } from 'tamagui'
import { Feather } from '@expo/vector-icons'

export default function ErrorFeed() {
return (
<YStack my="$6" justifyContent="center" alignItems="center" gap="$3">
<Feather name="alert-circle" size={80} color="red" />
<Text fontSize="$9">No posts found!</Text>
<Text fontSize="$7">The service may be temporarily unavailable.</Text>
<Text fontSize="$5">Pull to refresh</Text>
</YStack>
)
}
24 changes: 24 additions & 0 deletions src/components/icons/GhostIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from "react"
import { ColorValue } from "react-native"
import Svg, { Path } from 'react-native-svg'

// Source: https://free-icons.github.io/free-icons/

interface GhostIconProps {
width: number
height: number
color: ColorValue
}

const GhostIcon = (props: GhostIconProps) => (
<Svg
fill={props.color}
viewBox="0 0 512 512"
width={props.width}
height={props.height}
>
<Path d="M307 506q5 6 13 6t13-6l30-33q9-10 22-11 12 0 22 9l2 2q7 7 16 7 21-2 23-23V192q-2-82-56-136T256 0q-82 2-136 56T64 192v265q2 21 23 23 9 0 16-7l2-2q10-9 22-9 13 1 22 11l30 33q5 6 13 6t13-6l27-30q10-11 24-11t24 11l27 30ZM91 462q-2 2-4 2-6-1-7-7V192q2-75 52-124 49-50 124-52 75 2 124 52 50 49 52 124v265q-1 6-7 7-2 0-4-2l-3-2q-15-14-34-14-19 1-33 16l-30 34h-2l-27-31q-15-16-36-16t-36 16l-27 31h-2l-29-34q-15-15-34-16t-34 14l-3 2Zm101-246q-22-2-24-24 2-22 24-24 22 2 24 24-2 22-24 24Zm-40-24q1 23 20 35 20 10 40 0 19-12 20-35-1-23-20-35-20-10-40 0-19 12-20 35Zm192 0q-2 22-24 24-22-2-24-24 2-22 24-24 22 2 24 24Zm-24-40q-23 1-35 20-10 20 0 40 12 19 35 20 23-1 35-20 10-20 0-40-12-19-35-20Z" />
</Svg>
)

export default GhostIcon

0 comments on commit a8c1cf5

Please sign in to comment.