feat: refine generation workspace experience
This commit is contained in:
@@ -12,7 +12,7 @@ import {
|
||||
SwapOutlined,
|
||||
VideoCameraOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { useCallback, useEffect, useRef, useState, type CSSProperties } from "react";
|
||||
import { useCallback, useEffect, useRef, useState, type CSSProperties, type DragEvent } from "react";
|
||||
import "../../styles/pages/more-tools.css";
|
||||
import "../../styles/pages/image-workbench.css";
|
||||
import "../../styles/pages/subtitle-removal.css";
|
||||
@@ -76,6 +76,7 @@ function SubtitleRemovalPage({
|
||||
const [isProcessing, setIsProcessing] = useState(false);
|
||||
const [isDownloading, setIsDownloading] = useState(false);
|
||||
const [isSavingAsset, setIsSavingAsset] = useState(false);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const activeTaskIdRef = useRef(activeTaskId);
|
||||
activeTaskIdRef.current = activeTaskId;
|
||||
const keepaliveRestoredRef = useRef(false);
|
||||
@@ -128,10 +129,7 @@ function SubtitleRemovalPage({
|
||||
event.currentTarget.value = "";
|
||||
};
|
||||
|
||||
const handleFileDrop = (event: React.DragEvent) => {
|
||||
event.preventDefault();
|
||||
const file = Array.from(event.dataTransfer.files).find((f) => f.type.startsWith("video/"));
|
||||
if (!file) return;
|
||||
const processDroppedFile = (file: File) => {
|
||||
if (sourcePreview.startsWith("blob:")) URL.revokeObjectURL(sourcePreview);
|
||||
setSourceName(file.name);
|
||||
setSourceFile(file);
|
||||
@@ -143,6 +141,10 @@ function SubtitleRemovalPage({
|
||||
setStatus(`已导入 ${file.name}`);
|
||||
};
|
||||
|
||||
const handleDragOver = (e: DragEvent<HTMLDivElement>) => { e.preventDefault(); e.stopPropagation(); if (e.dataTransfer.types.includes("Files")) setIsDragging(true); };
|
||||
const handleDragLeave = (e: DragEvent<HTMLDivElement>) => { e.preventDefault(); e.stopPropagation(); if (e.currentTarget === e.target || !e.currentTarget.contains(e.relatedTarget as Node)) setIsDragging(false); };
|
||||
const handleFileDrop = (e: DragEvent<HTMLDivElement>) => { e.preventDefault(); e.stopPropagation(); setIsDragging(false); const file = Array.from(e.dataTransfer.files).find((f) => f.type.startsWith("video/")); if (file) processDroppedFile(file); };
|
||||
|
||||
const handleImportUrl = () => {
|
||||
const normalized = sourceUrl.trim();
|
||||
if (!/^https?:\/\//i.test(normalized)) {
|
||||
@@ -344,7 +346,13 @@ function SubtitleRemovalPage({
|
||||
accept="video/mp4"
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
<div className="image-workbench-upload-shell" onDragOver={(e) => e.preventDefault()} onDrop={handleFileDrop}>
|
||||
<div
|
||||
className={`image-workbench-upload-shell${isDragging ? " is-dragging" : ""}`}
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleFileDrop}
|
||||
>
|
||||
{isDragging ? <div className="image-workbench-upload-drop-overlay"><span>释放文件以上传</span></div> : null}
|
||||
<button type="button" className="image-workbench-upload" onClick={() => fileInputRef.current?.click()}>
|
||||
<FileImageOutlined />
|
||||
<strong>{sourceName || "拖拽或选择视频"}</strong>
|
||||
@@ -438,9 +446,17 @@ function SubtitleRemovalPage({
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="image-workbench-empty-canvas">
|
||||
<DeleteOutlined style={{ fontSize: 48, opacity: 0.2 }} />
|
||||
<p>上传视频后在此预览</p>
|
||||
<div
|
||||
className="studio-canvas-ghost"
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleFileDrop}
|
||||
>
|
||||
<div className="studio-canvas-ghost__icon">
|
||||
<VideoCameraOutlined />
|
||||
</div>
|
||||
<div className="studio-canvas-ghost__title">拖拽或选择视频</div>
|
||||
<div className="studio-canvas-ghost__hint">仅支持 MP4,最大 1GB,最高 1080P</div>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user