feat: 更新标签页和新增探索页面

- 将标签页中的“首页”改为“探索”,并更新相关逻辑
- 新增探索页面,展示推荐文章和训练计划
- 优化教练页面的导航,确保用户体验一致性
- 移除不再使用的代码,简化项目结构
- 更新路由常量,确保路径管理集中化
This commit is contained in:
richarjiang
2025-08-18 19:08:22 +08:00
parent d52981ab29
commit c7d7255312
5 changed files with 20 additions and 65 deletions

View File

@@ -19,7 +19,7 @@ export default function TabLayout() {
initialRouteName="coach" initialRouteName="coach"
screenOptions={({ route }) => { screenOptions={({ route }) => {
const routeName = route.name; const routeName = route.name;
const isSelected = (routeName === 'index' && pathname === ROUTES.TAB_HOME) || const isSelected = (routeName === 'explore' && pathname === ROUTES.TAB_EXPLORE) ||
(routeName === 'coach' && pathname === ROUTES.TAB_COACH) || (routeName === 'coach' && pathname === ROUTES.TAB_COACH) ||
(routeName === 'statistics' && pathname === ROUTES.TAB_STATISTICS) || (routeName === 'statistics' && pathname === ROUTES.TAB_STATISTICS) ||
pathname.includes(routeName); pathname.includes(routeName);
@@ -40,7 +40,7 @@ export default function TabLayout() {
// 基于 routeName 设置图标与标题,避免 tabBarIcon 的包装导致文字裁剪 // 基于 routeName 设置图标与标题,避免 tabBarIcon 的包装导致文字裁剪
const getIconAndTitle = () => { const getIconAndTitle = () => {
switch (routeName) { switch (routeName) {
case 'index': case 'explore':
return { icon: 'magnifyingglass.circle.fill', title: '发现' } as const; return { icon: 'magnifyingglass.circle.fill', title: '发现' } as const;
case 'coach': case 'coach':
return { icon: 'person.3.fill', title: 'Bot' } as const; return { icon: 'person.3.fill', title: 'Bot' } as const;
@@ -157,7 +157,7 @@ export default function TabLayout() {
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="index" name="explore"
options={{ options={{
title: '发现', title: '发现',
tabBarIcon: ({ color }) => { tabBarIcon: ({ color }) => {

View File

@@ -1,5 +1,6 @@
import { ThemedText } from '@/components/ThemedText'; import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView'; import { ThemedView } from '@/components/ThemedView';
import { ROUTES } from '@/constants/Routes';
import { useColorScheme } from '@/hooks/useColorScheme'; import { useColorScheme } from '@/hooks/useColorScheme';
import { useThemeColor } from '@/hooks/useThemeColor'; import { useThemeColor } from '@/hooks/useThemeColor';
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
@@ -13,7 +14,6 @@ import {
TouchableOpacity, TouchableOpacity,
View View
} from 'react-native'; } from 'react-native';
import { ROUTES } from '@/constants/Routes';
const { width, height } = Dimensions.get('window'); const { width, height } = Dimensions.get('window');
@@ -30,10 +30,10 @@ export default function WelcomeScreen() {
const handleSkip = async () => { const handleSkip = async () => {
try { try {
await AsyncStorage.setItem('@onboarding_completed', 'true'); await AsyncStorage.setItem('@onboarding_completed', 'true');
router.replace(ROUTES.TAB_HOME); router.replace(ROUTES.TAB_COACH);
} catch (error) { } catch (error) {
console.error('保存引导状态失败:', error); console.error('保存引导状态失败:', error);
router.replace(ROUTES.TAB_HOME); router.replace(ROUTES.TAB_COACH);
} }
}; };

View File

@@ -1,7 +1,6 @@
import { HeaderBar } from '@/components/ui/HeaderBar'; import { HeaderBar } from '@/components/ui/HeaderBar';
import { Colors } from '@/constants/Colors'; import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme'; import { useColorScheme } from '@/hooks/useColorScheme';
import { Ionicons } from '@expo/vector-icons';
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
import * as Haptics from 'expo-haptics'; import * as Haptics from 'expo-haptics';
import { useRouter } from 'expo-router'; import { useRouter } from 'expo-router';
@@ -305,50 +304,6 @@ export default function GoalsScreen() {
<Text style={[styles.rangeHint, { color: colors.textMuted }]}> {STEPS_RANGE.min.toLocaleString()}-{STEPS_RANGE.max.toLocaleString()} {STEPS_RANGE.step}</Text> <Text style={[styles.rangeHint, { color: colors.textMuted }]}> {STEPS_RANGE.min.toLocaleString()}-{STEPS_RANGE.max.toLocaleString()} {STEPS_RANGE.step}</Text>
</SectionCard> </SectionCard>
<SectionCard
title="练习普拉提是为了什么"
subtitle="可多选"
>
<View style={styles.grid}>
{PURPOSE_OPTIONS.map((opt) => {
const active = purposes.includes(opt.id);
return (
<TouchableOpacity
key={opt.id}
style={[
styles.optionCard,
{
backgroundColor: active ? colors.primary : colors.card,
borderColor: active ? colors.primary : colors.border,
},
]}
activeOpacity={0.9}
onPress={() => togglePurpose(opt.id)}
>
<View style={styles.optionIconWrap}>
<Ionicons
name={opt.icon}
size={20}
color={active ? colors.onPrimary : colors.text}
/>
</View>
<Text
numberOfLines={2}
style={[
styles.optionLabel,
{ color: active ? colors.onPrimary : colors.text },
]}
>
{opt.label}
</Text>
</TouchableOpacity>
);
})}
</View>
{purposes.length > 0 && (
<Text style={[styles.selectedHint, { color: colors.textSecondary }]}> {purposes.length} </Text>
)}
</SectionCard>
</ScrollView> </ScrollView>
</SafeAreaView> </SafeAreaView>
</View> </View>

View File

@@ -1,7 +1,7 @@
// 应用路由常量定义 // 应用路由常量定义
export const ROUTES = { export const ROUTES = {
// Tab路由 // Tab路由
TAB_HOME: '/', TAB_EXPLORE: '/explore',
TAB_COACH: '/coach', TAB_COACH: '/coach',
TAB_STATISTICS: '/statistics', TAB_STATISTICS: '/statistics',
TAB_PERSONAL: '/personal', TAB_PERSONAL: '/personal',