Add placeholder feeds dropdown to home

This commit is contained in:
Paul Frazee
2024-04-22 16:28:42 -07:00
parent 4ec5669d21
commit 54ca855851
3 changed files with 159 additions and 6 deletions
+131
View File
@@ -0,0 +1,131 @@
import React, {useCallback} from 'react'
import {View} from 'react-native'
import {AtUri} from '@atproto/api'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useNavigation} from '@react-navigation/native'
import {cleanError} from '#/lib/strings/errors'
import {useFeedSourceInfoQuery} from '#/state/queries/feed'
import {usePreferencesQuery} from '#/state/queries/preferences'
import {NavigationProp} from 'lib/routes/types'
import {LoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
import {atoms as a, useTheme} from '#/alf'
import * as Dialog from '#/components/Dialog'
import {router} from '#/routes'
import {Button} from '../Button'
import {Text} from '../Typography'
export function MyFeedsDialog({control}: {control: Dialog.DialogControlProps}) {
const {_} = useLingui()
const t = useTheme()
const {data: preferences} = usePreferencesQuery()
const navigation = useNavigation<NavigationProp>()
const onPressFeed = useCallback(
(uri: string) => {
control.close()
const urip = new AtUri(uri)
const collection =
urip.collection === 'app.bsky.feed.generator' ? 'feed' : 'lists'
const href = `/profile/${urip.hostname}/${collection}/${urip.rkey}`
const route = router.matchPath(href)
// @ts-ignore This is correct -prf
navigation.navigate(route[0], route[1])
},
[control, navigation],
)
const onPressEditFeeds = useCallback(() => {
control.close()
navigation.navigate('SavedFeeds')
}, [control, navigation])
let feeds: string[] = []
if (preferences && preferences?.feeds?.saved.length !== 0) {
const {saved, pinned} = preferences.feeds
feeds = feeds.concat(pinned)
feeds = feeds.concat(saved.filter(uri => !pinned.includes(uri)))
}
return (
<Dialog.Outer control={control}>
<Dialog.Handle />
<Dialog.ScrollableInner label={_(msg`Switch Account`)}>
{feeds.map(feedUri => (
<SavedFeed key={feedUri} feedUri={feedUri} onPress={onPressFeed} />
))}
<Button label="Edit feeds" onPress={onPressEditFeeds}>
{() => (
<View
style={[
a.border_b,
t.atoms.border_contrast_low,
a.px_md,
a.py_md,
a.flex_1,
]}>
<Text numberOfLines={1} style={[t.atoms.text, a.text_md]}>
Edit my feeds
</Text>
</View>
)}
</Button>
</Dialog.ScrollableInner>
</Dialog.Outer>
)
}
function SavedFeed({
feedUri,
onPress,
}: {
feedUri: string
onPress: (uri: string) => void
}) {
const t = useTheme()
const {data: info, error} = useFeedSourceInfoQuery({uri: feedUri})
if (!info && !error) {
return <SavedFeedLoadingPlaceholder />
}
return (
<Button
testID={`saved-feed-${info?.displayName}`}
label={info ? info.displayName : 'Feed offline'}
onPress={() => onPress(feedUri)}>
{() => (
<View
style={[
a.border_b,
t.atoms.border_contrast_low,
a.px_md,
a.py_md,
a.flex_1,
]}>
<Text numberOfLines={1} style={[t.atoms.text, a.text_md]}>
{info ? info.displayName : cleanError(error)}
</Text>
</View>
)}
</Button>
)
}
function SavedFeedLoadingPlaceholder() {
const t = useTheme()
return (
<View
style={[
a.flex_1,
a.border_b,
t.atoms.border_contrast_low,
a.px_md,
a.py_sm,
]}>
<LoadingPlaceholder width={140} height={12} />
</View>
)
}
+27 -5
View File
@@ -1,11 +1,16 @@
import React, {useRef, useMemo, useEffect, useState, useCallback} from 'react'
import {StyleSheet, View, ScrollView, LayoutChangeEvent} from 'react-native'
import {Text} from '../util/text/Text'
import {PressableWithHover} from '../util/PressableWithHover'
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'
import {LayoutChangeEvent, ScrollView, StyleSheet, View} from 'react-native'
import {isNative} from '#/platform/detection'
import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {useDialogControl} from '#/components/Dialog'
import {MyFeedsDialog} from '#/components/dialogs/MyFeeds'
// import {ArrowTriangleBottom_Stroke2_Corner1_Rounded as ArrowTriangleBottom} from '#/components/icons/ArrowTriangle'
import {ChevronBottom_Stroke2_Corner0_Rounded as ArrowTriangleBottom} from '#/components/icons/Chevron'
import {PressableWithHover} from '../util/PressableWithHover'
import {Text} from '../util/text/Text'
import {DraggableScrollView} from './DraggableScrollView'
import {isNative} from '#/platform/detection'
export interface TabBarProps {
testID?: string
@@ -36,6 +41,7 @@ export function TabBar({
() => ({borderBottomColor: indicatorColor || pal.colors.link}),
[indicatorColor, pal],
)
const myFeedsControl = useDialogControl()
const {isDesktop, isTablet} = useWebMediaQueries()
const styles = isDesktop || isTablet ? desktopStyles : mobileStyles
@@ -147,6 +153,14 @@ export function TabBar({
)
})}
</DraggableScrollView>
<PressableWithHover
testID="feedsDropdownBtn"
style={styles.dropdownBtn}
hoverStyle={pal.viewLight}
onPress={() => myFeedsControl.open()}>
<ArrowTriangleBottom fill={pal.textLight.color} size="sm" />
</PressableWithHover>
<MyFeedsDialog control={myFeedsControl} />
<View style={[pal.border, styles.outerBottomBorder]} />
</View>
)
@@ -178,6 +192,10 @@ const desktopStyles = StyleSheet.create({
bottom: -1,
borderBottomWidth: 1,
},
dropdownBtn: {
paddingTop: 14,
paddingHorizontal: 14,
},
})
const mobileStyles = StyleSheet.create({
@@ -205,4 +223,8 @@ const mobileStyles = StyleSheet.create({
bottom: -1,
borderBottomWidth: 1,
},
dropdownBtn: {
paddingTop: 12,
paddingHorizontal: 14,
},
})
+1 -1
View File
@@ -93,7 +93,7 @@ export function ProfileMenuDialog({
<Dialog.Outer control={control}>
<Dialog.Handle />
<Dialog.ScrollableInner label={_(msg`Switch Account`)}>
<Dialog.ScrollableInner label={_(msg`App Menu`)}>
<View style={[a.gap_sm]}>
<ProfileCard onPress={onPressProfile} />