- web/: React + Vite + TypeScript 前端 - backend/: Django + DRF + SimpleJWT 后端 - prototype/: HTML 设计原型 - docs/: PRD 和设计评审文档 - test: 单元测试 + E2E 极限测试
47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
import { useRef, useEffect } from 'react';
|
||
import { Sidebar } from './Sidebar';
|
||
import { InputBar } from './InputBar';
|
||
import { GenerationCard } from './GenerationCard';
|
||
import { Toast } from './Toast';
|
||
import { UserInfoBar } from './UserInfoBar';
|
||
import { useGenerationStore } from '../store/generation';
|
||
import styles from './VideoGenerationPage.module.css';
|
||
|
||
export function VideoGenerationPage() {
|
||
const tasks = useGenerationStore((s) => s.tasks);
|
||
const scrollRef = useRef<HTMLDivElement>(null);
|
||
const prevCountRef = useRef(tasks.length);
|
||
|
||
// Auto-scroll to top when new task is added
|
||
useEffect(() => {
|
||
if (tasks.length > prevCountRef.current && scrollRef.current) {
|
||
scrollRef.current.scrollTo({ top: 0, behavior: 'smooth' });
|
||
}
|
||
prevCountRef.current = tasks.length;
|
||
}, [tasks.length]);
|
||
|
||
return (
|
||
<div className={styles.layout}>
|
||
<Sidebar />
|
||
<main className={styles.main}>
|
||
<UserInfoBar />
|
||
<div className={styles.contentArea} ref={scrollRef}>
|
||
{tasks.length === 0 ? (
|
||
<div className={styles.emptyArea}>
|
||
<p className={styles.emptyHint}>在下方输入提示词,开始创作 AI 视频</p>
|
||
</div>
|
||
) : (
|
||
<div className={styles.taskList}>
|
||
{tasks.map((task) => (
|
||
<GenerationCard key={task.id} task={task} />
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
<InputBar />
|
||
</main>
|
||
<Toast />
|
||
</div>
|
||
);
|
||
}
|