onboarding: 选项字体与问题一致、底部间距、提醒页文案与移除底部 Skip
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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',
|
||||||
|
|||||||
@@ -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: {
|
||||||
|
|||||||
@@ -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,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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: {
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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": "You’re 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…)"
|
||||||
|
|||||||
Reference in New Issue
Block a user