Add suggested follows experiment to onboarding (#8847)

* add new gated screen to onboarding

* add tab bar, adjust layout

* replace chevron with arrow

* get suggested accounts working on native

* tweaks for web

* add metrics to follow all

* rm non-functional link from card

* ensure selected interests are passed through to interests query

* fix logcontext

* followed all accounts! toast

* rm save interests function

* Update src/screens/Onboarding/StepSuggestedAccounts/index.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* use admonition

* rm comment

* Better interest tabs (#8879)

* make tabs draggable

* move tab component to own file

* rm focused state from tab, improve label

* add focus styles, remove focus when dragging

* rm log

* add arrows to tabs

* rename Tabs -> InterestTabs

* try and simplify approach

* rename ref

* Update InterestTabs.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update src/components/InterestTabs.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update src/components/ProgressGuide/FollowDialog.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update src/components/ProgressGuide/FollowDialog.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* add newline

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* fix flex problem

* Add value proposition screen experiment (#8898)

* add assets

* add value prop experiment

* add alt text

* add metrics

* add transitions

* add skip button

* tweak copy

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* add borderless variant for web

* rm pointer events

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Add slight delay, prevent layout shift

* Handle layout shift, add Let's Go! text

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Eric Bailey <git@esb.lol>
This commit is contained in:
Samuel Newman
2025-08-27 14:17:45 +03:00
committed by GitHub
parent 0617fca5ef
commit eac0290143
30 changed files with 1302 additions and 291 deletions
+76 -50
View File
@@ -1,4 +1,4 @@
import React from 'react'
import React, {useState} from 'react'
import {ScrollView, View} from 'react-native'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {msg} from '@lingui/macro'
@@ -11,20 +11,23 @@ import {
atoms as a,
flatten,
native,
TextStyleProp,
type TextStyleProp,
tokens,
useBreakpoints,
useTheme,
web,
} from '#/alf'
import {leading} from '#/alf/typography'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron'
import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeft} from '#/components/icons/Arrow'
import {HEADER_SLOT_SIZE} from '#/components/Layout'
import {createPortalGroup} from '#/components/Portal'
import {P, Text} from '#/components/Typography'
const COL_WIDTH = 420
const ONBOARDING_COL_WIDTH = 420
export const OnboardingControls = createPortalGroup()
export const OnboardingHeaderSlot = createPortalGroup()
export function Layout({children}: React.PropsWithChildren<{}>) {
const {_} = useLingui()
@@ -46,6 +49,8 @@ export function Layout({children}: React.PropsWithChildren<{}>) {
const paddingTop = gtMobile ? a.py_5xl : a.py_lg
const dialogLabel = _(msg`Set up your account`)
const [footerHeight, setFooterHeight] = useState(0)
return (
<View
aria-modal
@@ -62,45 +67,67 @@ export function Layout({children}: React.PropsWithChildren<{}>) {
t.atoms.bg,
]}>
{__DEV__ && (
<View style={[a.absolute, a.p_xl, a.z_10, {right: 0, top: insets.top}]}>
<Button
variant="ghost"
color="negative"
size="small"
onPress={() => onboardDispatch({type: 'skip'})}
// DEV ONLY
label="Clear onboarding state">
<ButtonText>Clear</ButtonText>
</Button>
</View>
<Button
variant="ghost"
color="negative"
size="tiny"
onPress={() => onboardDispatch({type: 'skip'})}
// DEV ONLY
label="Clear onboarding state"
style={[
a.absolute,
a.z_10,
{
left: '50%',
top: insets.top + 2,
transform: [{translateX: '-50%'}],
},
]}>
<ButtonText>[DEV] Clear</ButtonText>
</Button>
)}
{!gtMobile && state.hasPrev && (
{!gtMobile && (
<View
pointerEvents="box-none"
style={[
web(a.fixed),
native(a.absolute),
a.left_0,
a.right_0,
a.flex_row,
a.w_full,
a.justify_center,
a.z_20,
a.px_xl,
{
top: paddingTop.paddingTop + insets.top - 1,
},
{top: paddingTop.paddingTop + insets.top - 1},
]}>
<View style={[a.w_full, a.align_start, {maxWidth: COL_WIDTH}]}>
<Button
key={state.activeStep} // remove focus state on nav
variant="ghost"
color="secondary"
size="small"
shape="round"
label={_(msg`Go back to previous step`)}
style={[a.absolute]}
onPress={() => dispatch({type: 'prev'})}>
<ButtonIcon icon={ChevronLeft} />
</Button>
<View
pointerEvents="box-none"
style={[
a.w_full,
a.align_start,
a.flex_row,
a.justify_between,
{maxWidth: ONBOARDING_COL_WIDTH},
]}>
{state.hasPrev ? (
<Button
key={state.activeStep} // remove focus state on nav
color="secondary"
variant="ghost"
shape="square"
size="small"
label={_(msg`Go back to previous step`)}
onPress={() => dispatch({type: 'prev'})}
style={[a.bg_transparent]}>
<ButtonIcon icon={ArrowLeft} size="lg" />
</Button>
) : (
<View />
)}
<OnboardingHeaderSlot.Outlet />
</View>
</View>
)}
@@ -109,22 +136,24 @@ export function Layout({children}: React.PropsWithChildren<{}>) {
ref={scrollview}
style={[a.h_full, a.w_full, {paddingTop: insets.top}]}
contentContainerStyle={{borderWidth: 0}}
// @ts-ignore web only --prf
scrollIndicatorInsets={{bottom: footerHeight - insets.bottom}}
// @ts-expect-error web only --prf
dataSet={{'stable-gutters': 1}}>
<View
style={[a.flex_row, a.justify_center, gtMobile ? a.px_5xl : a.px_xl]}>
<View style={[a.flex_1, {maxWidth: COL_WIDTH}]}>
<View style={[a.flex_1, {maxWidth: ONBOARDING_COL_WIDTH}]}>
<View style={[a.w_full, a.align_center, paddingTop]}>
<View
style={[
a.flex_row,
a.gap_sm,
a.w_full,
{paddingTop: 17, maxWidth: '60%'},
a.align_center,
{height: HEADER_SLOT_SIZE, maxWidth: '60%'},
]}>
{Array(state.totalSteps)
.fill(0)
.map((_, i) => (
.map((__, i) => (
<View
key={i}
style={[
@@ -144,19 +173,16 @@ export function Layout({children}: React.PropsWithChildren<{}>) {
</View>
</View>
<View
style={[a.w_full, a.mb_5xl, {paddingTop: gtMobile ? 20 : 40}]}>
{children}
</View>
<View style={[a.w_full, a.mb_5xl, a.pt_md]}>{children}</View>
<View style={{height: 400}} />
<View style={{height: 100 + footerHeight}} />
</View>
</View>
</ScrollView>
<View
onLayout={evt => setFooterHeight(evt.nativeEvent.layout.height)}
style={[
// @ts-ignore web only -prf
isWeb ? a.fixed : a.absolute,
{bottom: 0, left: 0, right: 0},
t.atoms.bg,
@@ -167,30 +193,30 @@ export function Layout({children}: React.PropsWithChildren<{}>) {
isWeb
? a.py_2xl
: {
paddingTop: a.pt_lg.paddingTop,
paddingBottom: insets.bottom + 10,
paddingTop: tokens.space.md,
paddingBottom: insets.bottom + tokens.space.md,
},
]}>
<View
style={[
a.w_full,
{maxWidth: COL_WIDTH},
gtMobile && [a.flex_row, a.justify_between],
{maxWidth: ONBOARDING_COL_WIDTH},
gtMobile && [a.flex_row, a.justify_between, a.align_center],
]}>
{gtMobile &&
(state.hasPrev ? (
<Button
key={state.activeStep} // remove focus state on nav
variant="solid"
color="secondary"
size="large"
shape="round"
variant="ghost"
shape="square"
size="small"
label={_(msg`Go back to previous step`)}
onPress={() => dispatch({type: 'prev'})}>
<ButtonIcon icon={ChevronLeft} />
<ButtonIcon icon={ArrowLeft} size="lg" />
</Button>
) : (
<View style={{height: 54}} />
<View style={{height: 33}} />
))}
<OnboardingControls.Outlet />
</View>