seaislee1209 f8358a28c6 feat: 前端UI重构 — Air Spark设计系统对标
- 全局样式对标Air Spark设计系统(背景、glass card、配色、圆角)
- 视频详情弹窗(VideoDetailModal)全屏预览+信息面板
- GenerationCard重构:fixed定位tooltip、9:16视频适配、blob下载
- 个人中心:总额度/今日/本月三卡片布局
- Dashboard图表配色统一为#6c63ff主色调
- Sidebar、InputBar、Toolbar等组件样式优化
- 新增AmbientBackground、AssetsPage组件

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 18:48:07 +08:00

100 lines
2.9 KiB
TypeScript

import { useRef, useCallback, type DragEvent } from 'react';
import { useInputBarStore } from '../store/inputBar';
import { UniversalUpload } from './UniversalUpload';
import { KeyframeUpload } from './KeyframeUpload';
import { PromptInput } from './PromptInput';
import { Toolbar } from './Toolbar';
import { showToast } from './Toast';
import styles from './InputBar.module.css';
export function InputBar() {
const mode = useInputBarStore((s) => s.mode);
const addReferences = useInputBarStore((s) => s.addReferences);
const setFirstFrame = useInputBarStore((s) => s.setFirstFrame);
const barRef = useRef<HTMLDivElement>(null);
const handleDragOver = useCallback((e: DragEvent) => {
e.preventDefault();
if (barRef.current) {
barRef.current.style.borderColor = '#00b8e6';
}
}, []);
const handleDragLeave = useCallback(() => {
if (barRef.current) {
barRef.current.style.borderColor = '#2a2a38';
}
}, []);
const handleDrop = useCallback((e: DragEvent) => {
e.preventDefault();
if (barRef.current) {
barRef.current.style.borderColor = '#2a2a38';
}
const IMAGE_MAX = 30 * 1024 * 1024;
const VIDEO_MAX = 50 * 1024 * 1024;
const AUDIO_MAX = 15 * 1024 * 1024;
const files = Array.from(e.dataTransfer.files).filter(
(f) => f.type.startsWith('image/') || f.type.startsWith('video/') || f.type.startsWith('audio/')
);
if (!files.length) return;
const valid: File[] = [];
for (const f of files) {
let limit: number;
let limitLabel: string;
if (f.type.startsWith('video/')) {
limit = VIDEO_MAX;
limitLabel = '视频文件不能超过50MB';
} else if (f.type.startsWith('audio/')) {
limit = AUDIO_MAX;
limitLabel = '音频文件不能超过15MB';
} else {
limit = IMAGE_MAX;
limitLabel = '图片文件不能超过30MB';
}
if (f.size > limit) {
showToast(limitLabel);
} else {
valid.push(f);
}
}
if (!valid.length) return;
if (mode === 'universal') {
addReferences(valid);
} else {
const imageFiles = valid.filter((f) => f.type.startsWith('image/'));
if (imageFiles.length > 0) {
setFirstFrame(imageFiles[0]);
}
}
}, [mode, addReferences, setFirstFrame]);
return (
<div className={styles.wrapper}>
<div className={styles.container}>
<div
ref={barRef}
className={styles.bar}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
>
{/* Upper area: Upload + Prompt */}
<div className={styles.inputArea}>
{mode === 'universal' ? <UniversalUpload /> : <KeyframeUpload />}
<PromptInput />
</div>
{/* Divider */}
<div className={styles.divider} />
{/* Toolbar */}
<Toolbar />
</div>
</div>
</div>
);
}