From bdc68bf733ad2048e8e51c262c5f8ac82791d55c Mon Sep 17 00:00:00 2001 From: root Date: Fri, 11 Jul 2025 01:49:27 +0800 Subject: [PATCH] fix --- src/components/FeaturesHighlight.tsx | 44 ++++ src/components/ProjectCard.tsx | 35 ++++ src/components/ProjectImage.tsx | 56 +++++ src/components/QuickActions.tsx | 50 +++++ src/components/RecentProjects.tsx | 113 ++++++++++ src/components/WelcomeSection.tsx | 33 +++ src/pages/HomePage.tsx | 296 --------------------------- 7 files changed, 331 insertions(+), 296 deletions(-) create mode 100644 src/components/FeaturesHighlight.tsx create mode 100644 src/components/ProjectCard.tsx create mode 100644 src/components/ProjectImage.tsx create mode 100644 src/components/QuickActions.tsx create mode 100644 src/components/RecentProjects.tsx create mode 100644 src/components/WelcomeSection.tsx delete mode 100644 src/pages/HomePage.tsx diff --git a/src/components/FeaturesHighlight.tsx b/src/components/FeaturesHighlight.tsx new file mode 100644 index 0000000..54a4ef1 --- /dev/null +++ b/src/components/FeaturesHighlight.tsx @@ -0,0 +1,44 @@ +import React from 'react' +import { Sparkles, Zap, Video } from 'lucide-react' + +const FeaturesHighlight: React.FC = () => { + const features = [ + { + icon: Sparkles, + title: 'AI 智能剪辑', + description: '使用先进的 AI 技术,自动识别精彩片段,智能生成视频剪辑' + }, + { + icon: Zap, + title: '高效处理', + description: '优化的渲染引擎,支持多种格式,快速导出高质量视频' + }, + { + icon: Video, + title: '专业工具', + description: '丰富的编辑工具和特效,满足从入门到专业的各种需求' + } + ] + + return ( +
+

强大的功能特性

+
+ {features.map((feature, index) => { + const IconComponent = feature.icon + return ( +
+
+ +
+

{feature.title}

+

{feature.description}

+
+ ) + })} +
+
+ ) +} + +export default FeaturesHighlight diff --git a/src/components/ProjectCard.tsx b/src/components/ProjectCard.tsx new file mode 100644 index 0000000..76aa5a9 --- /dev/null +++ b/src/components/ProjectCard.tsx @@ -0,0 +1,35 @@ +import React from 'react' +import { Link } from 'react-router-dom' +import { Project } from '../services/projectService' +import ProjectImage from './ProjectImage' + +interface ProjectCardProps { + project: Project + formatTimeAgo: (dateString: string) => string +} + +const ProjectCard: React.FC = ({ project, formatTimeAgo }) => { + return ( + +
+ +
+
+

{project.name}

+

{formatTimeAgo(project.updated_at)}

+ {project.product_name && ( +

{project.product_name}

+ )} +
+ + ) +} + +export default ProjectCard diff --git a/src/components/ProjectImage.tsx b/src/components/ProjectImage.tsx new file mode 100644 index 0000000..e0e218b --- /dev/null +++ b/src/components/ProjectImage.tsx @@ -0,0 +1,56 @@ +import React, { useState, useEffect } from 'react' +import { invoke } from '@tauri-apps/api/core' +import { Video } from 'lucide-react' + +interface ProjectImageProps { + imagePath: string + alt: string + className: string +} + +const ProjectImage: React.FC = ({ imagePath, alt, className }) => { + const [imageSrc, setImageSrc] = useState('') + const [imageLoading, setImageLoading] = useState(true) + + useEffect(() => { + const loadImage = async () => { + if (!imagePath) { + setImageLoading(false) + return + } + + if (imagePath.startsWith('http') || imagePath.startsWith('data:')) { + setImageSrc(imagePath) + setImageLoading(false) + return + } + + try { + const dataUrl = await invoke('read_image_as_data_url', { filePath: imagePath }) + setImageSrc(dataUrl) + } catch (error) { + console.error('Failed to read image:', error) + } finally { + setImageLoading(false) + } + } + + loadImage() + }, [imagePath]) + + if (imageLoading) { + return
+ } + + if (!imageSrc) { + return ( +
+
+ ) + } + + return {alt} +} + +export default ProjectImage diff --git a/src/components/QuickActions.tsx b/src/components/QuickActions.tsx new file mode 100644 index 0000000..8ce4f91 --- /dev/null +++ b/src/components/QuickActions.tsx @@ -0,0 +1,50 @@ +import React from 'react' +import { Link } from 'react-router-dom' +import { FolderOpen, Music, Zap, Sparkles, Database, LucideIcon } from 'lucide-react' + +interface QuickAction { + icon: LucideIcon + label: string + description: string + path: string +} + +const QuickActions: React.FC = () => { + const quickActions: QuickAction[] = [ + { icon: Sparkles, label: 'AI 视频生成', description: '使用 AI 将图片转换为动态视频', path: '/ai-video' }, + { icon: Music, label: '音频处理', description: '处理音频文件,添加效果', path: '/audio' }, + { icon: Zap, label: 'AI 自动剪辑', description: '使用 AI 自动生成视频剪辑', path: '/editor' }, + { icon: FolderOpen, label: '导入媒体', description: '导入视频、音频和图片文件', path: '/media' }, + { icon: Database, label: 'KV 存储测试', description: '测试 Cloudflare KV 键值存储功能', path: '/kv-test' }, + ] + + return ( +
+

快速操作

+
+ {quickActions.map((action, index) => { + const IconComponent = action.icon + return ( + +
+
+ +
+
+

{action.label}

+

{action.description}

+
+
+ + ) + })} +
+
+ ) +} + +export default QuickActions diff --git a/src/components/RecentProjects.tsx b/src/components/RecentProjects.tsx new file mode 100644 index 0000000..d4f4030 --- /dev/null +++ b/src/components/RecentProjects.tsx @@ -0,0 +1,113 @@ +import React, { useState, useEffect } from 'react' +import { Link } from 'react-router-dom' +import { Plus, Video } from 'lucide-react' +import { ProjectService, Project } from '../services/projectService' +import ProjectCard from './ProjectCard' + +const RecentProjects: React.FC = () => { + const [recentProjects, setRecentProjects] = useState([]) + const [loading, setLoading] = useState(true) + + // 加载最近的项目 + useEffect(() => { + const loadRecentProjects = async () => { + try { + const response = await ProjectService.getAllProjects() + if (response.status && response.data) { + // 按更新时间排序,取最近的3个项目 + const sortedProjects = response.data + .sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()) + .slice(0, 3) + setRecentProjects(sortedProjects) + } + } catch (error) { + console.error('Failed to load recent projects:', error) + } finally { + setLoading(false) + } + } + + loadRecentProjects() + }, []) + + // 格式化时间显示 + const formatTimeAgo = (dateString: string): string => { + const now = new Date() + const date = new Date(dateString) + const diffInMs = now.getTime() - date.getTime() + const diffInHours = Math.floor(diffInMs / (1000 * 60 * 60)) + const diffInDays = Math.floor(diffInHours / 24) + + if (diffInHours < 1) { + return '刚刚' + } else if (diffInHours < 24) { + return `${diffInHours} 小时前` + } else if (diffInDays < 7) { + return `${diffInDays} 天前` + } else { + return date.toLocaleDateString('zh-CN') + } + } + + // 加载状态骨架屏 + const LoadingSkeleton = () => ( + <> + {Array.from({ length: 3 }).map((_, index) => ( +
+
+
+
+
+
+
+ ))} + + ) + + // 空状态 + const EmptyState = () => ( +
+
+ ) + + return ( +
+
+

最近项目

+ + 查看全部 + +
+ +
+ {loading ? ( + + ) : recentProjects.length > 0 ? ( + recentProjects.map((project) => ( + + )) + ) : ( + + )} +
+
+ ) +} + +export default RecentProjects diff --git a/src/components/WelcomeSection.tsx b/src/components/WelcomeSection.tsx new file mode 100644 index 0000000..a53c6a5 --- /dev/null +++ b/src/components/WelcomeSection.tsx @@ -0,0 +1,33 @@ +import React from 'react' +import { Link } from 'react-router-dom' +import { Plus } from 'lucide-react' + +const WelcomeSection: React.FC = () => { + return ( +
+

+ 欢迎使用 MixVideo V2 +

+

+ 专业的视频混剪软件,让创作更简单 +

+
+ + + 创建新项目 + + + 浏览模板 + +
+
+ ) +} + +export default WelcomeSection diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx deleted file mode 100644 index c1482ac..0000000 --- a/src/pages/HomePage.tsx +++ /dev/null @@ -1,296 +0,0 @@ -import React, { useState, useEffect } from 'react' -import { Link } from 'react-router-dom' -import { Plus, FolderOpen, Video, Music, Zap, Sparkles, Database } from 'lucide-react' -import { invoke } from '@tauri-apps/api/core' -import { ProjectService, Project } from '../services/projectService' - -const HomePage: React.FC = () => { - const [recentProjects, setRecentProjects] = useState([]) - const [loading, setLoading] = useState(true) - - // 加载最近的项目 - useEffect(() => { - const loadRecentProjects = async () => { - try { - const response = await ProjectService.getAllProjects() - if (response.status && response.data) { - // 按更新时间排序,取最近的3个项目 - const sortedProjects = response.data - .sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()) - .slice(0, 3) - setRecentProjects(sortedProjects) - } - } catch (error) { - console.error('Failed to load recent projects:', error) - } finally { - setLoading(false) - } - } - - loadRecentProjects() - }, []) - - // 简化的图片组件 - const ProjectImage: React.FC<{ imagePath: string; alt: string; className: string }> = ({ - imagePath, alt, className - }) => { - const [imageSrc, setImageSrc] = useState('') - const [imageLoading, setImageLoading] = useState(true) - - useEffect(() => { - const loadImage = async () => { - if (!imagePath) { - setImageLoading(false) - return - } - - if (imagePath.startsWith('http') || imagePath.startsWith('data:')) { - setImageSrc(imagePath) - setImageLoading(false) - return - } - - try { - const dataUrl = await invoke('read_image_as_data_url', { filePath: imagePath }) - setImageSrc(dataUrl) - } catch (error) { - console.error('Failed to read image:', error) - } finally { - setImageLoading(false) - } - } - - loadImage() - }, [imagePath]) - - if (imageLoading) { - return
- } - - if (!imageSrc) { - return ( -
-
- ) - } - - return {alt} - } - - // 格式化时间显示 - const formatTimeAgo = (dateString: string): string => { - const now = new Date() - const date = new Date(dateString) - const diffInMs = now.getTime() - date.getTime() - const diffInHours = Math.floor(diffInMs / (1000 * 60 * 60)) - const diffInDays = Math.floor(diffInHours / 24) - - if (diffInHours < 1) { - return '刚刚' - } else if (diffInHours < 24) { - return `${diffInHours} 小时前` - } else if (diffInDays < 7) { - return `${diffInDays} 天前` - } else { - return date.toLocaleDateString('zh-CN') - } - } - - const quickActions = [ - { icon: Sparkles, label: 'AI 视频生成', description: '使用 AI 将图片转换为动态视频', path: '/ai-video' }, - { icon: Music, label: '音频处理', description: '处理音频文件,添加效果', path: '/audio' }, - { icon: Zap, label: 'AI 自动剪辑', description: '使用 AI 自动生成视频剪辑', path: '/editor' }, - { icon: FolderOpen, label: '导入媒体', description: '导入视频、音频和图片文件', path: '/media' }, - { icon: Database, label: 'KV 存储测试', description: '测试 Cloudflare KV 键值存储功能', path: '/kv-test' }, - ] - - - return ( -
- {/* Welcome Section */} -
-

- 欢迎使用 MixVideo V2 -

-

- 专业的视频混剪软件,让创作更简单 -

-
- - - 开始新项目 - -
-
- - {/* Quick Actions */} -
-

快速操作

-
- {quickActions.map((action, index) => { - const Icon = action.icon - return ( - -
-
- -
-

{action.label}

-

{action.description}

-
- - ) - })} -
-
- - {/* Recent Projects */} -
-
-

最近项目

- - 查看全部 - -
-
- {loading ? ( - // 加载状态 - Array.from({ length: 3 }).map((_, index) => ( -
-
-
-
-
-
-
- )) - ) : recentProjects.length > 0 ? ( - // 显示真实项目 - recentProjects.map((project) => ( - -
- -
-
-

{project.name}

-

{formatTimeAgo(project.updated_at)}

- {project.product_name && ( -

{project.product_name}

- )} -
- - )) - ) : ( - // 空状态 -
-
- )} -
-
- - {/* Features Highlight */} -
-

强大的功能特性

-
-
-

🎬 专业剪辑

-

支持多轨道编辑、特效添加、字幕制作

-
-
-

🎵 音频处理

-

节拍检测、音频分离、智能混音

-
-
-

🤖 AI 辅助

-

自动剪辑、场景检测、内容理解

-
-
-
- - {/* Additional Content for Testing Scroll */} -
-

更多功能

- -
-
-

视频效果

-
    -
  • • 滤镜和颜色调整
  • -
  • • 转场效果
  • -
  • • 动画和运动图形
  • -
  • • 绿幕抠像
  • -
  • • 画中画效果
  • -
-
- -
-

音频功能

-
    -
  • • 降噪和音频修复
  • -
  • • 音频均衡器
  • -
  • • 音频同步
  • -
  • • 语音识别
  • -
  • • 音频可视化
  • -
-
- -
-

导出选项

-
    -
  • • 多种格式支持
  • -
  • • 自定义分辨率
  • -
  • • 批量导出
  • -
  • • 云端渲染
  • -
  • • 直播推流
  • -
-
- -
-

协作功能

-
    -
  • • 团队协作
  • -
  • • 版本控制
  • -
  • • 评论和反馈
  • -
  • • 云端同步
  • -
  • • 权限管理
  • -
-
-
-
- - {/* Footer */} -
-

- © 2025 MixVideo V2. 专业视频编辑软件,让创作更简单。 -

-
-
- ) -} - -export default HomePage