✨ 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:
295
app/templates/[id].tsx
Normal file
295
app/templates/[id].tsx
Normal 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',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user