Add copy to feeds page (#2852)

* move `IconCircle` to `components` for reuse

* add copy to feeds page

* start of a header

* saveit

* add lg size

* add your feeds

* don't show Your Feeds if you don't have any

* Minor ui tweaks

* cleanup

* remove unused activity indicator

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
zio/stable
Hailey 2024-02-13 00:40:39 -08:00 committed by GitHub
parent 36e1da1006
commit d8245e96ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 129 additions and 97 deletions

View File

@ -30,8 +30,8 @@ export function IconCircle({
a.align_center, a.align_center,
a.rounded_full, a.rounded_full,
{ {
width: 64, width: size === 'lg' ? 52 : 64,
height: 64, height: size === 'lg' ? 52 : 64,
backgroundColor: backgroundColor:
t.name === 'light' ? t.palette.primary_50 : t.palette.primary_950, t.name === 'light' ? t.palette.primary_50 : t.palette.primary_950,
}, },

View File

@ -20,7 +20,7 @@ import {
OnboardingControls, OnboardingControls,
} from '#/screens/Onboarding/Layout' } from '#/screens/Onboarding/Layout'
import {FeedCard} from '#/screens/Onboarding/StepAlgoFeeds/FeedCard' import {FeedCard} from '#/screens/Onboarding/StepAlgoFeeds/FeedCard'
import {IconCircle} from '#/screens/Onboarding/IconCircle' import {IconCircle} from '#/components/IconCircle'
export type FeedConfig = { export type FeedConfig = {
default: boolean default: boolean

View File

@ -23,7 +23,7 @@ import {
Description, Description,
OnboardingControls, OnboardingControls,
} from '#/screens/Onboarding/Layout' } from '#/screens/Onboarding/Layout'
import {IconCircle} from '#/screens/Onboarding/IconCircle' import {IconCircle} from '#/components/IconCircle'
import { import {
bulkWriteFollows, bulkWriteFollows,
sortPrimaryAlgorithmFeeds, sortPrimaryAlgorithmFeeds,

View File

@ -22,7 +22,7 @@ import {
usePreferencesQuery, usePreferencesQuery,
useSetFeedViewPreferencesMutation, useSetFeedViewPreferencesMutation,
} from 'state/queries/preferences' } from 'state/queries/preferences'
import {IconCircle} from '#/screens/Onboarding/IconCircle' import {IconCircle} from '#/components/IconCircle'
export function StepFollowingFeed() { export function StepFollowingFeed() {
const {_} = useLingui() const {_} = useLingui()

View File

@ -26,7 +26,7 @@ import {
OnboardingControls, OnboardingControls,
} from '#/screens/Onboarding/Layout' } from '#/screens/Onboarding/Layout'
import {InterestButton} from '#/screens/Onboarding/StepInterests/InterestButton' import {InterestButton} from '#/screens/Onboarding/StepInterests/InterestButton'
import {IconCircle} from '#/screens/Onboarding/IconCircle' import {IconCircle} from '#/components/IconCircle'
export function StepInterests() { export function StepInterests() {
const {_} = useLingui() const {_} = useLingui()

View File

@ -26,7 +26,7 @@ import {
import {ModerationOption} from '#/screens/Onboarding/StepModeration/ModerationOption' import {ModerationOption} from '#/screens/Onboarding/StepModeration/ModerationOption'
import {AdultContentEnabledPref} from '#/screens/Onboarding/StepModeration/AdultContentEnabledPref' import {AdultContentEnabledPref} from '#/screens/Onboarding/StepModeration/AdultContentEnabledPref'
import {Context} from '#/screens/Onboarding/state' import {Context} from '#/screens/Onboarding/state'
import {IconCircle} from '#/screens/Onboarding/IconCircle' import {IconCircle} from '#/components/IconCircle'
function AnimatedDivider() { function AnimatedDivider() {
return ( return (

View File

@ -27,7 +27,7 @@ import {
SuggestedAccountCardPlaceholder, SuggestedAccountCardPlaceholder,
} from '#/screens/Onboarding/StepSuggestedAccounts/SuggestedAccountCard' } from '#/screens/Onboarding/StepSuggestedAccounts/SuggestedAccountCard'
import {aggregateInterestItems} from '#/screens/Onboarding/util' import {aggregateInterestItems} from '#/screens/Onboarding/util'
import {IconCircle} from '#/screens/Onboarding/IconCircle' import {IconCircle} from '#/components/IconCircle'
export function Inner({ export function Inner({
profiles, profiles,

View File

@ -21,7 +21,7 @@ import {
} from '#/screens/Onboarding/Layout' } from '#/screens/Onboarding/Layout'
import {FeedCard} from '#/screens/Onboarding/StepAlgoFeeds/FeedCard' import {FeedCard} from '#/screens/Onboarding/StepAlgoFeeds/FeedCard'
import {aggregateInterestItems} from '#/screens/Onboarding/util' import {aggregateInterestItems} from '#/screens/Onboarding/util'
import {IconCircle} from '#/screens/Onboarding/IconCircle' import {IconCircle} from '#/components/IconCircle'
export function StepTopicalFeeds() { export function StepTopicalFeeds() {
const {_} = useLingui() const {_} = useLingui()

View File

@ -16,6 +16,7 @@ import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {ComposeIcon2, CogIcon, MagnifyingGlassIcon2} from 'lib/icons' import {ComposeIcon2, CogIcon, MagnifyingGlassIcon2} from 'lib/icons'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {atoms as a, useTheme} from '#/alf'
import {SearchInput, SearchInputRef} from 'view/com/util/forms/SearchInput' import {SearchInput, SearchInputRef} from 'view/com/util/forms/SearchInput'
import {UserAvatar} from 'view/com/util/UserAvatar' import {UserAvatar} from 'view/com/util/UserAvatar'
import { import {
@ -41,8 +42,11 @@ import {
import {cleanError} from 'lib/strings/errors' import {cleanError} from 'lib/strings/errors'
import {useComposerControls} from '#/state/shell/composer' import {useComposerControls} from '#/state/shell/composer'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {isNative} from '#/platform/detection' import {isNative, isWeb} from '#/platform/detection'
import {HITSLOP_10} from 'lib/constants' import {HITSLOP_10} from 'lib/constants'
import {IconCircle} from '#/components/IconCircle'
import {ListSparkle_Stroke2_Corner0_Rounded} from '#/components/icons/ListSparkle'
import {ListMagnifyingGlass_Stroke2_Corner0_Rounded} from '#/components/icons/ListMagnifyingGlass'
type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'> type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'>
@ -215,12 +219,7 @@ export function FeedsScreen(_props: Props) {
// pendingItems: this.rootStore.preferences.savedFeeds.length || 3, // pendingItems: this.rootStore.preferences.savedFeeds.length || 3,
}) })
} else { } else {
if (preferences?.feeds?.saved.length === 0) { if (preferences?.feeds?.saved.length !== 0) {
slices.push({
key: 'savedFeedNoResults',
type: 'savedFeedNoResults',
})
} else {
const {saved, pinned} = preferences.feeds const {saved, pinned} = preferences.feeds
slices = slices.concat( slices = slices.concat(
@ -400,12 +399,13 @@ export function FeedsScreen(_props: Props) {
) { ) {
return ( return (
<View style={s.p10}> <View style={s.p10}>
<ActivityIndicator /> <ActivityIndicator size="large" />
</View> </View>
) )
} else if (item.type === 'savedFeedsHeader') { } else if (item.type === 'savedFeedsHeader') {
if (!isMobile) {
return ( return (
<>
{!isMobile && (
<View <View
style={[ style={[
pal.view, pal.view,
@ -416,7 +416,7 @@ export function FeedsScreen(_props: Props) {
}, },
]}> ]}>
<Text type="title-lg" style={[pal.text, s.bold]}> <Text type="title-lg" style={[pal.text, s.bold]}>
<Trans>My Feeds</Trans> <Trans>Feeds</Trans>
</Text> </Text>
<View style={styles.headerBtnGroup}> <View style={styles.headerBtnGroup}>
<Pressable <Pressable
@ -437,9 +437,10 @@ export function FeedsScreen(_props: Props) {
</Link> </Link>
</View> </View>
</View> </View>
)}
{preferences?.feeds?.saved?.length !== 0 && <FeedsSavedHeader />}
</>
) )
}
return <View />
} else if (item.type === 'savedFeedNoResults') { } else if (item.type === 'savedFeedNoResults') {
return ( return (
<View <View
@ -457,37 +458,8 @@ export function FeedsScreen(_props: Props) {
} else if (item.type === 'popularFeedsHeader') { } else if (item.type === 'popularFeedsHeader') {
return ( return (
<> <>
<View <FeedsAboutHeader />
style={[ <View style={{paddingHorizontal: 12, paddingBottom: 12}}>
pal.view,
styles.header,
{
// This is first in the flatlist without a session -esb
marginTop: hasSession ? 16 : 0,
paddingLeft: isMobile ? 12 : undefined,
paddingRight: 10,
paddingBottom: isMobile ? 6 : undefined,
},
]}>
<Text type="title-lg" style={[pal.text, s.bold]}>
<Trans>Discover new feeds</Trans>
</Text>
{!isMobile && (
<SearchInput
ref={searchInputRef}
query={query}
onChangeQuery={onChangeQuery}
onPressCancelSearch={onPressCancelSearch}
onSubmitQuery={onSubmitQuery}
setIsInputFocused={onChangeSearchFocus}
style={{flex: 1, maxWidth: 250}}
/>
)}
</View>
{isMobile && (
<View style={{paddingHorizontal: 8, paddingBottom: 10}}>
<SearchInput <SearchInput
ref={searchInputRef} ref={searchInputRef}
query={query} query={query}
@ -497,7 +469,6 @@ export function FeedsScreen(_props: Props) {
setIsInputFocused={onChangeSearchFocus} setIsInputFocused={onChangeSearchFocus}
/> />
</View> </View>
)}
</> </>
) )
} else if (item.type === 'popularFeedsLoading') { } else if (item.type === 'popularFeedsLoading') {
@ -529,15 +500,20 @@ export function FeedsScreen(_props: Props) {
return null return null
}, },
[ [
_,
hasSession,
isMobile, isMobile,
pal, pal.view,
pal.border,
pal.text,
pal.icon,
pal.textLight,
_,
preferences?.feeds?.saved?.length,
query, query,
onChangeQuery, onChangeQuery,
onPressCancelSearch, onPressCancelSearch,
onSubmitQuery, onSubmitQuery,
onChangeSearchFocus, onChangeSearchFocus,
hasSession,
], ],
) )
@ -552,8 +528,6 @@ export function FeedsScreen(_props: Props) {
/> />
)} )}
{preferences ? <View /> : <ActivityIndicator />}
<List <List
ref={listRef} ref={listRef}
style={[!isTabletOrDesktop && s.flex1, styles.list]} style={[!isTabletOrDesktop && s.flex1, styles.list]}
@ -660,6 +634,64 @@ function SavedFeedLoadingPlaceholder() {
) )
} }
function FeedsSavedHeader() {
const t = useTheme()
return (
<View
style={[
a.flex_row,
a.px_md,
a.pt_2xl,
a.gap_md,
isWeb ? a.pb_2xl : a.pb_xl,
a.border_b,
t.atoms.border_contrast_low,
]}>
<IconCircle icon={ListSparkle_Stroke2_Corner0_Rounded} size="lg" />
<View style={[a.flex_1, a.gap_sm]}>
<Text style={[a.flex_1, a.text_2xl, a.font_bold, t.atoms.text]}>
<Trans>My Feeds</Trans>
</Text>
<Text style={[t.atoms.text_contrast_high]}>
<Trans>All the feeds you've saved, right in one place.</Trans>
</Text>
</View>
</View>
)
}
function FeedsAboutHeader() {
const t = useTheme()
return (
<View
style={[
a.flex_row,
a.px_md,
a.pt_2xl,
a.gap_md,
isWeb ? a.pb_2xl : a.pb_xl,
]}>
<IconCircle
icon={ListMagnifyingGlass_Stroke2_Corner0_Rounded}
size="lg"
/>
<View style={[a.flex_1, a.gap_sm]}>
<Text style={[a.flex_1, a.text_2xl, a.font_bold, t.atoms.text]}>
<Trans>Discover New Feeds</Trans>
</Text>
<Text style={[t.atoms.text_contrast_high]}>
<Trans>
Custom feeds built by the community bring you new experiences and
help you find the content you love.
</Trans>
</Text>
</View>
</View>
)
}
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,