feat(challenges): 新增挑战模块与详情页,优化标签栏布局

- 新增挑战列表页 `app/(tabs)/challenges.tsx`,展示热门挑战卡片
- 新增挑战详情页 `app/challenges/[id].tsx`,支持排行榜、分享与参与
- 在标签栏中新增“挑战”入口,替换原有“发现”与“AI”页
- 调整标签栏间距与圆角,适配新布局
- 新增挑战相关路由常量 `TAB_CHALLENGES`
- 迁移 `coach.tsx` 与 `explore.tsx` 至根目录,保持结构清晰
This commit is contained in:
richarjiang
2025-09-26 17:29:00 +08:00
parent a014998848
commit e2597c1bc4
7 changed files with 1033 additions and 16 deletions

View File

@@ -21,8 +21,8 @@ type TabConfig = {
const TAB_CONFIGS: Record<string, TabConfig> = {
statistics: { icon: 'chart.pie.fill', title: '健康' },
// explore: { icon: 'magnifyingglass.circle.fill', title: '发现' },
goals: { icon: 'flag.fill', title: '习惯' },
challenges: { icon: 'trophy.fill', title: '挑战' },
personal: { icon: 'person.fill', title: '个人' },
};
@@ -35,9 +35,10 @@ export default function TabLayout() {
// Helper function to determine if a tab is selected
const isTabSelected = (routeName: string): boolean => {
const routeMap: Record<string, string> = {
explore: ROUTES.TAB_EXPLORE,
goals: ROUTES.TAB_GOALS,
statistics: ROUTES.TAB_STATISTICS,
goals: ROUTES.TAB_GOALS,
challenges: ROUTES.TAB_CHALLENGES,
personal: ROUTES.TAB_PERSONAL,
};
return routeMap[routeName] === pathname || pathname.includes(routeName);
@@ -69,11 +70,11 @@ export default function TabLayout() {
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
marginHorizontal: 6,
marginHorizontal: 2,
marginVertical: 10,
borderRadius: 25,
backgroundColor: isSelected ? colorTokens.tabBarActiveBackground : 'transparent',
paddingHorizontal: isSelected ? 16 : 10,
paddingHorizontal: isSelected ? 8 : 4,
paddingVertical: 8,
}}
>
@@ -91,7 +92,7 @@ export default function TabLayout() {
fontWeight: '600',
marginLeft: 6,
}}
numberOfLines={0 as any}
numberOfLines={1}
>
{tabConfig.title}
</Text>
@@ -148,12 +149,12 @@ export default function TabLayout() {
shadowOpacity: glassEffectAvailable ? 0.1 : 0.2,
shadowRadius: 10,
elevation: 5,
paddingHorizontal: 10,
paddingHorizontal: 6,
paddingTop: 0,
paddingBottom: 0,
marginHorizontal: 20,
left: 20,
right: 20,
marginHorizontal: 16,
left: 16,
right: 16,
alignSelf: 'center',
borderWidth: glassEffectAvailable ? 1 : 0,
borderColor: glassEffectAvailable ? (theme === 'dark' ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)') : 'transparent',
@@ -177,7 +178,11 @@ export default function TabLayout() {
</NativeTabs.Trigger>
<NativeTabs.Trigger name="goals">
<Icon sf="flag.fill" drawable="custom_settings_drawable" />
<Label></Label>
<Label></Label>
</NativeTabs.Trigger>
<NativeTabs.Trigger name="challenges">
<Icon sf="trophy.fill" drawable="custom_android_drawable" />
<Label></Label>
</NativeTabs.Trigger>
<NativeTabs.Trigger name="personal">
<Icon sf="person.fill" drawable="custom_settings_drawable" />
@@ -193,9 +198,8 @@ export default function TabLayout() {
>
<Tabs.Screen name="statistics" options={{ title: '健康' }} />
<Tabs.Screen name="explore" options={{ title: '发现', href: null }} />
<Tabs.Screen name="coach" options={{ title: 'AI', href: null }} />
<Tabs.Screen name="goals" options={{ title: '习惯' }} />
<Tabs.Screen name="challenges" options={{ title: '挑战' }} />
<Tabs.Screen name="personal" options={{ title: '个人' }} />
</Tabs>
);