feat: 更新 CLAUDE.md 文件及多个组件以优化用户体验和功能
- 更新 CLAUDE.md 文件,重构架构部分,增加认证和数据层的描述 - 在 GoalsScreen 中新增目标模板选择功能,支持用户选择和创建目标 - 在 CreateGoalModal 中添加初始数据支持,优化目标创建体验 - 新增 GoalTemplateModal 组件,提供目标模板选择界面 - 更新 NotificationHelpers,支持构建深度链接以便于导航 - 在 CoachScreen 中处理路由参数,增强用户交互体验 - 更新多个组件的样式和逻辑,提升整体用户体验 - 删除不再使用的中文回复规则文档
This commit is contained in:
295
components/GoalTemplateModal.tsx
Normal file
295
components/GoalTemplateModal.tsx
Normal file
@@ -0,0 +1,295 @@
|
||||
import { Colors } from '@/constants/Colors';
|
||||
import { getTemplatesByCategory, goalCategories, GoalTemplate } from '@/constants/goalTemplates';
|
||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Dimensions,
|
||||
Image,
|
||||
Modal,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
StatusBar,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
const { width: screenWidth } = Dimensions.get('window');
|
||||
|
||||
interface GoalTemplateModalProps {
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
onSelectTemplate: (template: GoalTemplate) => void;
|
||||
onCreateCustom: () => void;
|
||||
}
|
||||
|
||||
export default function GoalTemplateModal({
|
||||
visible,
|
||||
onClose,
|
||||
onSelectTemplate,
|
||||
onCreateCustom
|
||||
}: GoalTemplateModalProps) {
|
||||
const theme = (useColorScheme() ?? 'light') as 'light' | 'dark';
|
||||
const colorTokens = Colors[theme];
|
||||
|
||||
const [selectedCategory, setSelectedCategory] = useState('recommended');
|
||||
const currentTemplates = getTemplatesByCategory(selectedCategory);
|
||||
|
||||
// 渲染分类标签
|
||||
const renderCategoryTab = (category: any) => {
|
||||
const isSelected = selectedCategory === category.id;
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={category.id}
|
||||
style={[
|
||||
styles.categoryTab,
|
||||
isSelected && styles.categoryTabSelected
|
||||
]}
|
||||
onPress={() => setSelectedCategory(category.id)}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
{category.isRecommended && (
|
||||
<Image
|
||||
source={require('@/assets/images/icons/icon-recommend.png')}
|
||||
style={{ width: 24, height: 24 }}
|
||||
/>
|
||||
)}
|
||||
<Text style={[
|
||||
styles.categoryTabText,
|
||||
isSelected && styles.categoryTabTextSelected
|
||||
]}>
|
||||
{category.title}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
// 渲染模板项
|
||||
const renderTemplateItem = (template: GoalTemplate) => (
|
||||
<TouchableOpacity
|
||||
key={template.id}
|
||||
style={[styles.templateItem]}
|
||||
onPress={() => onSelectTemplate(template)}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<View style={[styles.templateIcon]}>
|
||||
<MaterialIcons
|
||||
name={template.icon as any}
|
||||
size={24}
|
||||
color={template.iconColor}
|
||||
/>
|
||||
</View>
|
||||
<Text style={[styles.templateTitle]}>
|
||||
{template.title}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
animationType="slide"
|
||||
presentationStyle="pageSheet"
|
||||
onRequestClose={onClose}
|
||||
>
|
||||
<SafeAreaView style={styles.container}>
|
||||
<StatusBar barStyle="dark-content" backgroundColor="#FFFFFF" />
|
||||
|
||||
{/* 头部 */}
|
||||
<View style={styles.header}>
|
||||
<TouchableOpacity
|
||||
onPress={onClose}
|
||||
style={styles.closeButton}
|
||||
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
||||
>
|
||||
<MaterialIcons name="keyboard-arrow-down" size={24} color="#374151" />
|
||||
</TouchableOpacity>
|
||||
|
||||
<Text style={styles.title}>创建新目标</Text>
|
||||
|
||||
<View style={{ width: 24 }} />
|
||||
</View>
|
||||
|
||||
<ScrollView
|
||||
style={styles.content}
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
{/* 创建自定义目标 */}
|
||||
<TouchableOpacity
|
||||
style={styles.customGoalButton}
|
||||
onPress={onCreateCustom}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<View style={styles.customGoalIcon}>
|
||||
<MaterialIcons name="add" size={24} color="#7C3AED" />
|
||||
</View>
|
||||
<Text style={styles.customGoalText}>创建自定义目标</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* 分类选择器 */}
|
||||
<View style={styles.categorySection}>
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={styles.categoryScrollContent}
|
||||
style={styles.categoryScrollView}
|
||||
>
|
||||
{goalCategories.map(renderCategoryTab)}
|
||||
</ScrollView>
|
||||
</View>
|
||||
|
||||
{/* 当前分类的模板 */}
|
||||
<View style={styles.templatesSection}>
|
||||
<View style={styles.templatesGrid}>
|
||||
{currentTemplates.map(renderTemplateItem)}
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#F9FAFB',
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: 20,
|
||||
paddingVertical: 16,
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#E5E7EB',
|
||||
},
|
||||
closeButton: {
|
||||
padding: 4,
|
||||
},
|
||||
title: {
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
color: '#111827',
|
||||
textAlign: 'center',
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
},
|
||||
scrollContent: {
|
||||
paddingBottom: 40,
|
||||
},
|
||||
customGoalButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginHorizontal: 20,
|
||||
marginTop: 20,
|
||||
padding: 16,
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: 16,
|
||||
borderWidth: 1,
|
||||
borderColor: '#E5E7EB',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.05,
|
||||
shadowRadius: 2,
|
||||
elevation: 1,
|
||||
},
|
||||
customGoalIcon: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: '#F3E8FF',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginRight: 12,
|
||||
},
|
||||
customGoalText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: '#374151',
|
||||
},
|
||||
categorySection: {
|
||||
marginTop: 24,
|
||||
},
|
||||
categoryScrollView: {
|
||||
paddingLeft: 20,
|
||||
},
|
||||
categoryScrollContent: {
|
||||
paddingRight: 20,
|
||||
},
|
||||
categoryTab: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 10,
|
||||
marginRight: 12,
|
||||
borderRadius: 20,
|
||||
backgroundColor: '#F3F4F6',
|
||||
},
|
||||
categoryTabSelected: {
|
||||
backgroundColor: '#7C3AED',
|
||||
},
|
||||
categoryTabText: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: '#374151',
|
||||
},
|
||||
categoryTabTextSelected: {
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
avatarGroup: {
|
||||
flexDirection: 'row',
|
||||
marginRight: 8,
|
||||
},
|
||||
avatar: {
|
||||
width: 16,
|
||||
height: 16,
|
||||
borderRadius: 8,
|
||||
borderWidth: 1,
|
||||
borderColor: '#FFFFFF',
|
||||
},
|
||||
templatesSection: {
|
||||
marginTop: 24,
|
||||
},
|
||||
templatesGrid: {
|
||||
paddingHorizontal: 20,
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: 12,
|
||||
},
|
||||
templateItem: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#FFFFFF',
|
||||
minWidth: (screenWidth - 60) / 2, // 2列布局,考虑间距和padding
|
||||
maxWidth: (screenWidth - 60) / 2,
|
||||
aspectRatio: 2.2,
|
||||
borderRadius: 16,
|
||||
padding: 16,
|
||||
justifyContent: 'center',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 3,
|
||||
elevation: 2,
|
||||
},
|
||||
templateIcon: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
templateTitle: {
|
||||
fontSize: 14,
|
||||
color: '#374151',
|
||||
fontWeight: '600',
|
||||
lineHeight: 20,
|
||||
marginLeft: 12,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user