onboarding: 选项字体与问题一致、底部间距、提醒页文案与移除底部 Skip

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
雷汀岚
2026-02-09 17:11:13 +08:00
parent 66241e5231
commit aa4e1e9947
6 changed files with 35 additions and 40 deletions

View File

@@ -1,8 +1,7 @@
import React from 'react'; import React from 'react';
import { View, StyleSheet, TouchableOpacity } from 'react-native'; import { View, StyleSheet, TouchableOpacity, Text } from 'react-native';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { SerifText } from './SerifText'; import { OnboardingColors, OnboardingFont } from '@/constants/OnboardingTheme';
import { OnboardingColors } from '@/constants/OnboardingTheme';
export const INTENTS = [ export const INTENTS = [
{ id: 'love', labelKey: 'intent.love', icon: '❤️' }, { id: 'love', labelKey: 'intent.love', icon: '❤️' },
@@ -20,7 +19,7 @@ export function IntentSelectionStep({ selectedIds, onToggle }: IntentSelectionSt
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<View style={styles.container}> <View style={styles.container}>
<SerifText style={styles.title}>{t('intent.title')}</SerifText> <Text style={styles.title}>{t('intent.title')}</Text>
<View style={styles.grid}> <View style={styles.grid}>
{INTENTS.map((intent) => { {INTENTS.map((intent) => {
@@ -35,10 +34,10 @@ export function IntentSelectionStep({ selectedIds, onToggle }: IntentSelectionSt
onPress={() => onToggle(intent.id)} onPress={() => onToggle(intent.id)}
activeOpacity={0.7} activeOpacity={0.7}
> >
<SerifText style={styles.icon}>{intent.icon}</SerifText> <Text style={styles.icon}>{intent.icon}</Text>
<SerifText style={[styles.label, isSelected && styles.labelSelected]}> <Text style={[styles.label, isSelected && styles.labelSelected]}>
{t(intent.labelKey)} {t(intent.labelKey)}
</SerifText> </Text>
</TouchableOpacity> </TouchableOpacity>
); );
})} })}
@@ -56,6 +55,8 @@ const styles = StyleSheet.create({
fontSize: 24, fontSize: 24,
marginBottom: 40, marginBottom: 40,
textAlign: 'center', textAlign: 'center',
fontFamily: OnboardingFont.question,
color: OnboardingColors.textPrimary,
}, },
grid: { grid: {
flexDirection: 'row', flexDirection: 'row',
@@ -86,10 +87,12 @@ const styles = StyleSheet.create({
}, },
icon: { icon: {
fontSize: 32, fontSize: 32,
fontFamily: OnboardingFont.question,
}, },
label: { label: {
fontSize: 18, fontSize: 18,
color: OnboardingColors.textPrimary, color: OnboardingColors.textPrimary,
fontFamily: OnboardingFont.question,
}, },
labelSelected: { labelSelected: {
fontWeight: 'bold', fontWeight: 'bold',

View File

@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { View, StyleSheet, SafeAreaView, TouchableOpacity, StatusBar, Text, Image, Platform } from 'react-native'; import { View, StyleSheet, SafeAreaView, TouchableOpacity, StatusBar, Text, Image, Platform } from 'react-native';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { OnboardingColors } from '@/constants/OnboardingTheme'; import { OnboardingColors, OnboardingFont } from '@/constants/OnboardingTheme';
interface OnboardingLayoutProps { interface OnboardingLayoutProps {
children: React.ReactNode; children: React.ReactNode;
@@ -119,13 +119,13 @@ const styles = StyleSheet.create({
questionTitle: { questionTitle: {
fontSize: 22, fontSize: 22,
color: OnboardingColors.questionTitle, color: OnboardingColors.questionTitle,
fontFamily: Platform.OS === 'ios' ? 'PingFang TC' : 'sans-serif', fontFamily: OnboardingFont.question,
flex: 1, flex: 1,
}, },
progressText: { progressText: {
fontSize: 18, fontSize: 18,
color: OnboardingColors.textProgress, color: OnboardingColors.textProgress,
fontFamily: Platform.OS === 'ios' ? 'PingFang TC' : 'sans-serif', fontFamily: OnboardingFont.question,
marginLeft: 10, marginLeft: 10,
}, },
content: { content: {

View File

@@ -11,10 +11,10 @@ interface ReminderStepProps {
value: number; value: number;
onChange: (value: number) => void; onChange: (value: number) => void;
onFinish: () => void; onFinish: () => void;
onSkip: () => void; onSkip?: () => void;
} }
export function ReminderStep({ value, onChange, onFinish, onSkip }: ReminderStepProps) { export function ReminderStep({ value, onChange, onFinish }: ReminderStepProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const insets = useSafeAreaInsets(); const insets = useSafeAreaInsets();
@@ -48,10 +48,6 @@ export function ReminderStep({ value, onChange, onFinish, onSkip }: ReminderStep
<TouchableOpacity onPress={onFinish} activeOpacity={0.8}> <TouchableOpacity onPress={onFinish} activeOpacity={0.8}>
<BtnClicked width={87} height={57} /> <BtnClicked width={87} height={57} />
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity onPress={onSkip} activeOpacity={0.8} style={styles.skipBtn}>
<Text style={styles.skipText}>{t('onboarding.skip')}</Text>
</TouchableOpacity>
</View> </View>
</View> </View>
); );
@@ -93,17 +89,5 @@ const styles = StyleSheet.create({
footer: { footer: {
position: 'absolute', position: 'absolute',
alignItems: 'center', alignItems: 'center',
}
,
skipBtn: {
marginTop: 14,
paddingVertical: 10,
paddingHorizontal: 18,
},
skipText: {
color: OnboardingColors.textPrimary,
fontSize: 15,
fontWeight: '600',
opacity: 0.85,
}, },
}); });

View File

@@ -1,8 +1,7 @@
import React from 'react'; import React from 'react';
import { View, StyleSheet, TouchableOpacity, ScrollView } from 'react-native'; import { View, StyleSheet, TouchableOpacity, ScrollView, Text } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { OnboardingColors } from '@/constants/OnboardingTheme'; import { OnboardingColors, OnboardingFont } from '@/constants/OnboardingTheme';
import { SerifText } from './SerifText';
import SelectedIcon from '@/assets/images/icon/selected_icon.svg'; import SelectedIcon from '@/assets/images/icon/selected_icon.svg';
import BtnNotClicked from '@/assets/images/icon/btn_Notclicked.svg'; import BtnNotClicked from '@/assets/images/icon/btn_Notclicked.svg';
import BtnClicked from '@/assets/images/icon/btn_clicked.svg'; import BtnClicked from '@/assets/images/icon/btn_clicked.svg';
@@ -25,7 +24,8 @@ export function SelectionStep({ options, selectedIds, onToggle, onNext, onSkip }
const insets = useSafeAreaInsets(); const insets = useSafeAreaInsets();
const footerBottom = insets.bottom + 16; const footerBottom = insets.bottom + 16;
const footerButtonHeight = 57; const footerButtonHeight = 57;
const footerPaddingBottom = footerBottom + footerButtonHeight + 24; // 底部留白加大,避免最后一项与按钮边框视觉重叠
const footerPaddingBottom = footerBottom + footerButtonHeight + 40;
return ( return (
<View style={styles.container}> <View style={styles.container}>
@@ -43,7 +43,7 @@ export function SelectionStep({ options, selectedIds, onToggle, onNext, onSkip }
onPress={() => onToggle(option.id)} onPress={() => onToggle(option.id)}
activeOpacity={0.7} activeOpacity={0.7}
> >
<SerifText style={styles.optionText}>{option.label}</SerifText> <Text style={styles.optionText}>{option.label}</Text>
{isSelected && ( {isSelected && (
<View style={styles.iconWrapper}> <View style={styles.iconWrapper}>
<SelectedIcon width={20} height={20} /> <SelectedIcon width={20} height={20} />
@@ -95,6 +95,7 @@ const styles = StyleSheet.create({
fontSize: 18, fontSize: 18,
color: OnboardingColors.textPrimary, color: OnboardingColors.textPrimary,
fontWeight: '500', fontWeight: '500',
fontFamily: OnboardingFont.question,
flex: 1, flex: 1,
}, },
iconWrapper: { iconWrapper: {

View File

@@ -1,3 +1,10 @@
import { Platform } from 'react-native';
/** 与 onboarding 问题标题一致的字体PingFang TC / sans-serif */
export const OnboardingFont = {
question: Platform.OS === 'ios' ? 'PingFang TC' : 'sans-serif',
};
export const OnboardingColors = { export const OnboardingColors = {
background: '#FFF4EA', background: '#FFF4EA',
textPrimary: '#772F00', textPrimary: '#772F00',

View File

@@ -14,7 +14,7 @@
"progress": "{{current}}/{{total}}", "progress": "{{current}}/{{total}}",
"next": "Next", "next": "Next",
"skip": "Skip", "skip": "Skip",
"skipAll": "Skip onboarding", "skipAll": "Skip",
"q1Title": "How are you feeling lately?", "q1Title": "How are you feeling lately?",
"q1Desc": "No right or wrong. You can skip and adjust later.", "q1Desc": "No right or wrong. You can skip and adjust later.",
"q2Title": "What kind of support do you want?", "q2Title": "What kind of support do you want?",
@@ -26,9 +26,9 @@
}, },
"onboardingSurvey": { "onboardingSurvey": {
"steps": { "steps": {
"name": { "title": "What do you want to be called?", "placeholder": "Mama" }, "name": { "title": "What should we call you?", "placeholder": "Mama" },
"status": { "status": {
"title": "Which stage of motherhood are you in?", "title": "Where are you at right now?",
"options": { "options": {
"pregnant": "Pregnant / Preparing", "pregnant": "Pregnant / Preparing",
"has_kids": "Parenting", "has_kids": "Parenting",
@@ -66,7 +66,7 @@
"balance": "Rest & balance" "balance": "Rest & balance"
} }
}, },
"reminder": { "title": "How many reminders do you want per day?" } "reminder": { "title": "How often would you like a gentle reminder?" }
} }
}, },
"intent": { "intent": {
@@ -142,13 +142,13 @@
"widgetDesc": "Put gentle reminders on your home screen: long-press → tap “+” → search “Mindfulness” → add a size you like." "widgetDesc": "Put gentle reminders on your home screen: long-press → tap “+” → search “Mindfulness” → add a size you like."
}, },
"consent": { "consent": {
"title": "You Are Perfect.", "title": "Hey mama.",
"subtitle": "Everything\nWill Be Better.", "subtitle": "Youre doing okay\nright now.",
"agree": "Agree & Continue", "agree": "Agree & Continue",
"privacy": "Privacy Policy", "privacy": "Privacy Policy",
"terms": "Terms of Use", "terms": "Terms of Use",
"notice": "By continuing, you agree to the Privacy Policy and Terms of Use.", "notice": "By continuing, you agree to the Privacy Policy and Terms of Use.",
"noticeRich": "By continuing, you agree to the <privacy>{{privacyLabel}}{{privacySuffix}}</privacy> and <terms>{{termsLabel}}{{termsSuffix}}</terms>.", "noticeRich": "By continuing,\nyou agree to the <privacy>{{privacyLabel}}{{privacySuffix}}</privacy> and <terms>{{termsLabel}}{{termsSuffix}}</terms>.",
"linkUnavailable": "Failed to load the policy link. Please check your network and try again.", "linkUnavailable": "Failed to load the policy link. Please check your network and try again.",
"linkUnavailableDev": "Failed to load the policy link. Please check your network or API_BASE_URL: {{baseUrl}}", "linkUnavailableDev": "Failed to load the policy link. Please check your network or API_BASE_URL: {{baseUrl}}",
"linkLoadingSuffix": " (loading…)" "linkLoadingSuffix": " (loading…)"