feat: 应用界面重构 - 从模板中心到AI内容生成平台

- 重构首页:从模板列表展示改为AI功能展示界面
- 更新底部导航:将explore改为content,index改为home
- 新增多个页面:积分、兑换、历史记录、结果展示、设置等
- 优化UI组件:新增通用按钮、分类标签、加载状态等组件
- 清理冗余文件:删除旧的认证文档和积分详情页面
- 更新主题配置:调整配色方案和视觉风格
- 修复导入路径:优化组件导入结构

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
imeepos
2025-10-31 17:53:56 +08:00
parent 668caaa91f
commit b9399bf4cf
38 changed files with 5641 additions and 1663 deletions

295
app/templates/[id].tsx Normal file
View File

@@ -0,0 +1,295 @@
import { router, useLocalSearchParams } from 'expo-router';
import React, { useMemo, useState } from 'react';
import { Image, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
type TemplateFrame = {
id: string;
title: string;
uri: string;
accent: string;
};
const curatedLooks: TemplateFrame[] = [
{
id: 'earth-zoom',
title: 'Earth Zoom Our',
uri: 'https://images.unsplash.com/photo-1490481651871-ab68de25d43d?auto=format&fit=crop&w=1200&q=80',
accent: '#D1FF00',
},
{
id: 'midnight-atelier',
title: 'Midnight Atelier',
uri: 'https://images.unsplash.com/photo-1500336624523-d727130c3328?auto=format&fit=crop&w=1200&q=80',
accent: '#FF7A45',
},
{
id: 'flora-couture',
title: 'Flora Couture',
uri: 'https://images.unsplash.com/photo-1524504388940-b1c1722653e1?auto=format&fit=crop&w=1200&q=80',
accent: '#7A8BFF',
},
{
id: 'noir-silhouette',
title: 'Noir Silhouette',
uri: 'https://images.unsplash.com/photo-1521572163474-6864f9cf17ab?auto=format&fit=crop&w=1200&q=80',
accent: '#FF5F6D',
},
{
id: 'aurora-thread',
title: 'Aurora Thread',
uri: 'https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?auto=format&fit=crop&w=1200&q=80',
accent: '#21D4FD',
},
{
id: 'velvet-echo',
title: 'Velvet Echo',
uri: 'https://images.unsplash.com/photo-1512436991641-6745cdb1723f?auto=format&fit=crop&w=1200&q=80',
accent: '#FFAA00',
},
];
const quickActions = [
{ id: 'upscale', label: 'Upscale' },
{ id: 'collect', label: 'Collect' },
{ id: 'download', label: 'Download' },
];
export default function TemplateDetailScreen() {
const { id } = useLocalSearchParams<{ id: string }>();
const [selectedId, setSelectedId] = useState<string>(curatedLooks[0].id);
const [menuVisible, setMenuVisible] = useState(true);
const current = useMemo(
() => curatedLooks.find(look => look.id === selectedId) ?? curatedLooks[0],
[selectedId],
);
const resolvedTemplateId = typeof id === 'string' && id.length > 0 ? id : current.id;
const handleGenerate = () => {
router.push(`/templates/${resolvedTemplateId}/form`);
};
return (
<View style={styles.canvas}>
<SafeAreaView style={styles.safeArea} edges={['top', 'left', 'right']}>
<ScrollView
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.scrollContent}
>
<View style={styles.topCarousel}>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.carouselContent}
>
{curatedLooks.map(look => {
const isActive = look.id === selectedId;
return (
<TouchableOpacity
key={look.id}
activeOpacity={0.85}
onPress={() => setSelectedId(look.id)}
style={[
styles.previewFrame,
{ borderColor: isActive ? look.accent : 'rgba(255,255,255,0.08)' },
isActive && styles.previewFrameActive,
]}
>
<Image source={{ uri: look.uri }} style={styles.previewImage} />
</TouchableOpacity>
);
})}
</ScrollView>
</View>
<View style={styles.heroStage}>
<Image source={{ uri: current.uri }} style={styles.heroImage} />
</View>
<View style={styles.bottomBar}>
<View style={styles.infoCard}>
<Image source={{ uri: current.uri }} style={styles.infoThumbnail} />
<Text style={styles.infoTitle} numberOfLines={1}>
{current.title}
</Text>
</View>
<TouchableOpacity
style={styles.generateButton}
activeOpacity={0.9}
onPress={handleGenerate}
>
<Text style={styles.generateLabel}>Generate Video</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.menuTrigger}
activeOpacity={0.85}
onPress={() => setMenuVisible(prev => !prev)}
>
<View style={styles.menuDots}>
<View style={styles.dot} />
<View style={[styles.dot, styles.dotMiddle]} />
<View style={styles.dot} />
</View>
</TouchableOpacity>
</View>
</ScrollView>
{menuVisible && (
<View style={styles.menuPanel}>
{quickActions.map(action => (
<TouchableOpacity
key={action.id}
activeOpacity={0.85}
style={styles.menuItem}
onPress={() => setMenuVisible(false)}
>
<Text style={styles.menuLabel}>{action.label}</Text>
</TouchableOpacity>
))}
</View>
)}
</SafeAreaView>
</View>
);
}
const styles = StyleSheet.create({
canvas: {
flex: 1,
backgroundColor: '#040404',
},
safeArea: {
flex: 1,
},
scrollContent: {
paddingHorizontal: 24,
paddingBottom: 120,
},
topCarousel: {
marginTop: 12,
paddingVertical: 8,
borderRadius: 22,
backgroundColor: 'rgba(255, 255, 255, 0.04)',
},
carouselContent: {
paddingHorizontal: 12,
alignItems: 'center',
gap: 12,
},
previewFrame: {
width: 56,
height: 56,
borderRadius: 18,
borderWidth: 1,
overflow: 'hidden',
backgroundColor: 'rgba(255, 255, 255, 0.08)',
},
previewFrameActive: {
transform: [{ scale: 1.05 }],
},
previewImage: {
width: '100%',
height: '100%',
},
heroStage: {
marginTop: 32,
borderRadius: 36,
backgroundColor: '#111111',
overflow: 'hidden',
shadowColor: '#000000',
shadowOpacity: 0.45,
shadowRadius: 32,
shadowOffset: { width: 0, height: 18 },
elevation: 24,
},
heroImage: {
width: '100%',
height: 456,
borderRadius: 36,
},
bottomBar: {
flexDirection: 'row',
alignItems: 'center',
gap: 16,
marginTop: 32,
},
infoCard: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 16,
paddingVertical: 12,
borderRadius: 24,
backgroundColor: 'rgba(255, 255, 255, 0.08)',
},
infoThumbnail: {
width: 32,
height: 32,
borderRadius: 10,
marginRight: 12,
},
infoTitle: {
fontSize: 14,
fontWeight: '600',
color: '#FFFFFF',
maxWidth: 120,
},
generateButton: {
flex: 1,
height: 56,
borderRadius: 28,
backgroundColor: '#D1FF00',
alignItems: 'center',
justifyContent: 'center',
},
generateLabel: {
fontSize: 16,
fontWeight: '700',
color: '#050505',
letterSpacing: 0.3,
},
menuTrigger: {
width: 56,
height: 56,
borderRadius: 28,
backgroundColor: 'rgba(255, 255, 255, 0.08)',
alignItems: 'center',
justifyContent: 'center',
},
menuDots: {
justifyContent: 'space-between',
height: 24,
},
dot: {
width: 6,
height: 6,
borderRadius: 3,
backgroundColor: '#FFFFFF',
},
dotMiddle: {
opacity: 0.7,
},
menuPanel: {
position: 'absolute',
right: 24,
bottom: 160,
paddingVertical: 12,
paddingHorizontal: 16,
borderRadius: 20,
backgroundColor: 'rgba(10, 10, 10, 0.94)',
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.08)',
gap: 12,
},
menuItem: {
paddingVertical: 4,
},
menuLabel: {
fontSize: 15,
fontWeight: '600',
color: '#FFFFFF',
},
});