Add initial Nudge component

This commit is contained in:
Paul Frazee
2024-06-11 22:59:08 -07:00
parent 6736384ff4
commit ae7d1a8bc4
3 changed files with 213 additions and 35 deletions
+117
View File
@@ -0,0 +1,117 @@
import React from 'react'
import {Keyboard, StyleProp, View, ViewStyle} from 'react-native'
import {LinearGradient} from 'expo-linear-gradient'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {isWeb} from '#/platform/detection'
import {atoms as a, useTheme} from '#/alf'
import {FullWindowOverlay} from '#/components/FullWindowOverlay'
import {Portal} from '#/components/Portal'
import {Button} from './Button'
import {Text} from './Typography'
type Anchor = 'top_left' | 'top_center' | 'top_right'
interface NudgeProps {
testID?: string
isOpen: boolean
anchor: Anchor
onClose: () => void
style?: StyleProp<ViewStyle>
}
export function Nudge({
children,
testID,
isOpen,
anchor,
onClose,
style,
}: React.PropsWithChildren<NudgeProps>) {
const t = useTheme()
const {_} = useLingui()
const anchorPositioningStyle = useAnchorPositioningStyle(anchor)
return (
isOpen && (
<Portal>
<FullWindowOverlay>
{/* Backdrop overlay */}
<View
style={[
a.fixed,
a.inset_0,
{backgroundColor: '#000', opacity: 0.1},
a.pointer_events_none,
]}
/>
<View
// iOS
accessibilityViewIsModal
// Android
importantForAccessibility="yes"
style={[a.fixed, a.px_lg, a.py_md, style]}
testID={testID}
onTouchMove={() => Keyboard.dismiss()}>
{/* Angle pointer up */}
<View
style={[
a.absolute,
anchorPositioningStyle,
{
width: 16,
height: 16,
backgroundColor: t.palette.primary_500,
transform: [{rotate: '45deg'}],
},
]}
/>
<LinearGradient
colors={[t.palette.primary_500, t.palette.primary_400]}
locations={[0, 1]}
start={{x: 0, y: 0}}
end={{x: 0, y: 1}}
style={[a.absolute, a.inset_0, a.rounded_sm]}
/>
<View>{children}</View>
<Button label={_(msg`Okay`)} onPress={onClose}>
{({hovered}) => (
<View
style={[
a.flex_1,
a.px_lg,
a.py_md,
a.rounded_xs,
a.border,
{borderColor: '#fff'},
hovered && {backgroundColor: t.palette.primary_400},
]}>
<Text
style={[
a.text_md,
a.text_center,
a.font_semibold,
{color: '#fff'},
]}>
<Trans>Okay</Trans>
</Text>
</View>
)}
</Button>
</View>
</FullWindowOverlay>
</Portal>
)
)
}
function useAnchorPositioningStyle(anchor: Anchor): ViewStyle {
if (anchor === 'top_center') {
return {left: isWeb ? '48%' : '52%', top: -8}
}
if (anchor === 'top_right') {
return {right: 20, top: -8}
}
return {left: 20, top: -8}
}
+58
View File
@@ -0,0 +1,58 @@
import React from 'react'
import {View} from 'react-native'
import {isWeb} from '#/platform/detection'
import {Nudge} from '#/components/Nudge'
import {Text} from '#/components/Typography'
export function HomeNewUserNudge() {
const [isOpen, setIsOpen] = React.useState(true)
return (
<Nudge
isOpen={isOpen}
anchor="top_center"
onClose={() => setIsOpen(false)}
style={
isWeb
? {
left: '50%',
top: 105,
maxWidth: 380,
transform: [{translateX: '-50%'}],
}
: {
top: 155,
left: 10,
right: 10,
}
}>
<View
style={{
paddingTop: 10,
paddingBottom: 20,
paddingHorizontal: 10,
gap: 10,
}}>
<Text
style={{
fontWeight: 'bold',
fontSize: 21,
lineHeight: 23,
color: '#fff',
}}>
Welcome to Bluesky!
</Text>
<Text
style={{
fontWeight: '500',
fontSize: 16,
lineHeight: 18,
color: '#fff',
}}>
You're on the Discover algorithm. Swipe right to change your current
feed.
</Text>
</View>
</Nudge>
)
}
+38 -35
View File
@@ -29,6 +29,7 @@ import {FollowingEmptyState} from 'view/com/posts/FollowingEmptyState'
import {FollowingEndOfFeed} from 'view/com/posts/FollowingEndOfFeed'
import {NoFeedsPinned} from '#/screens/Home/NoFeedsPinned'
import {HomeHeader} from '../com/home/HomeHeader'
import {HomeNewUserNudge} from '../com/home/HomeNewUserNudge'
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
export function HomeScreen(props: Props) {
@@ -173,7 +174,6 @@ function HomeScreenReady({
},
[setMinimalShellMode],
)
const renderTabBar = React.useCallback(
(props: RenderTabBarFnProps) => {
return (
@@ -209,47 +209,50 @@ function HomeScreenReady({
}, [preferences])
return hasSession ? (
<Pager
key={allFeeds.join(',')}
ref={pagerRef}
testID="homeScreen"
initialPage={selectedIndex}
onPageSelecting={onPageSelecting}
onPageSelected={onPageSelected}
onPageScrollStateChanged={onPageScrollStateChanged}
renderTabBar={renderTabBar}>
{pinnedFeedInfos.length ? (
pinnedFeedInfos.map(feedInfo => {
const feed = feedInfo.feedDescriptor
if (feed === 'following') {
<>
<HomeNewUserNudge />
<Pager
key={allFeeds.join(',')}
ref={pagerRef}
testID="homeScreen"
initialPage={selectedIndex}
onPageSelecting={onPageSelecting}
onPageSelected={onPageSelected}
onPageScrollStateChanged={onPageScrollStateChanged}
renderTabBar={renderTabBar}>
{pinnedFeedInfos.length ? (
pinnedFeedInfos.map(feedInfo => {
const feed = feedInfo.feedDescriptor
if (feed === 'following') {
return (
<FeedPage
key={feed}
testID="followingFeedPage"
isPageFocused={selectedFeed === feed}
feed={feed}
feedParams={homeFeedParams}
renderEmptyState={renderFollowingEmptyState}
renderEndOfFeed={FollowingEndOfFeed}
/>
)
}
const savedFeedConfig = feedInfo.savedFeed
return (
<FeedPage
key={feed}
testID="followingFeedPage"
testID="customFeedPage"
isPageFocused={selectedFeed === feed}
feed={feed}
feedParams={homeFeedParams}
renderEmptyState={renderFollowingEmptyState}
renderEndOfFeed={FollowingEndOfFeed}
renderEmptyState={renderCustomFeedEmptyState}
savedFeedConfig={savedFeedConfig}
/>
)
}
const savedFeedConfig = feedInfo.savedFeed
return (
<FeedPage
key={feed}
testID="customFeedPage"
isPageFocused={selectedFeed === feed}
feed={feed}
renderEmptyState={renderCustomFeedEmptyState}
savedFeedConfig={savedFeedConfig}
/>
)
})
) : (
<NoFeedsPinned preferences={preferences} />
)}
</Pager>
})
) : (
<NoFeedsPinned preferences={preferences} />
)}
</Pager>
</>
) : (
<Pager
testID="homeScreen"