refactor: delete TimelinePanel.tsx (#1899 #1900)

This commit is contained in:
2026-09-14 20:44:04 +08:00
parent c8fa0e0f19
commit bee15fd6f9
@@ -1,200 +0,0 @@
/**
* 水平轨道时间线 — 支持裁剪手柄、分割、右键菜单
* 时间标尺 + 片段轨道 + HTML5拖拽排序
*
* 子组件(timeline/):
* - TimeRuler - 时间标尺
* - ClipCard - 片段卡片
* - ClipTrack - 片段轨道(播放头+片段列表+添加卡片)
* - TimelineHeader - 时间线头部(标题+缩放+操作按钮)
* - TrimPreview - 裁剪预览 tooltip
* - ContextMenu - 右键菜单
*
* Hooks:
* - useClipDrag - 片段拖拽排序
* - useTrimDrag - 裁剪拖拽
* - useTimelineMenus - 菜单 & 面板
* - usePlayheadDrag - 播放头拖拽
*/
import React from "react"
import type { ClipData, ClipType, TrimConfig } from "../types"
import { DEFAULT_PIXELS_PER_SECOND } from "../constants/timeline"
import { useClipDrag } from "../hooks/useClipDrag"
import { useTrimDrag } from "../hooks/useTrimDrag"
import { useTimelineMenus } from "../hooks/useTimelineMenus"
import { usePlayheadDrag } from "./timeline/hooks/usePlayheadDrag"
import { TimeRuler } from "./timeline/TimeRuler"
import { ClipTrack } from "./timeline/ClipTrack"
import { TimelineHeader } from "./timeline/TimelineHeader"
import { TrimPreview } from "./timeline/TrimPreview"
import { ContextMenu } from "./timeline/ContextMenu"
interface TimelinePanelProps {
clips: ClipData[]
selectedClipId: string | null
currentMode: string
onClipSelect: (clipId: string) => void
onClipReorder: (fromIdx: number, toIdx: number) => void
onClipRemove: (clipId: string) => void
onAddClip: (type: ClipType, duration: number) => void
/** 裁剪更新:调整片段的 trim_config 和 duration */
onClipTrim?: (clipId: string, trimConfig: TrimConfig, newDuration: number) => void
/** 在指定位置分割片段 */
onClipSplit?: (clipId: string, splitRatio: number) => void
/** 恢复片段原始长度 */
onClipResetTrim?: (clipId: string) => void
/** 当前播放时间(秒) */
currentTime?: number
/** 缩放:每秒像素数 */
pixelsPerSecond?: number
/** 缩放变更回调 */
onZoomChange?: (pps: number) => void
/** 播放头跳转回调 */
onSeek?: (time: number) => void
/** 总时长(秒),可选(默认由 clips 计算) */
totalDuration?: number
}
const TimelinePanel: React.FC<TimelinePanelProps> = ({
clips,
selectedClipId,
currentMode,
onClipSelect,
onClipReorder,
onClipRemove,
onAddClip,
onClipTrim,
onClipSplit,
onClipResetTrim,
currentTime = 0,
pixelsPerSecond = 40,
onZoomChange,
onSeek,
totalDuration: totalDurationProp,
}) => {
/* ── 缩放 & 时长 ── */
const pps = pixelsPerSecond ?? DEFAULT_PIXELS_PER_SECOND
const totalDuration = totalDurationProp ?? clips.reduce((s, c) => s + c.duration, 0)
/* ── 裁剪拖拽 ── */
const { trimDrag, trimPreview, handleTrimHandleMouseDown } = useTrimDrag(clips, pps, onClipTrim)
/* ── 片段拖拽排序 ── */
const {
dragIdx,
dragOverIdx,
handleDragStart,
handleDragOver,
handleDragEnd,
handleDrop,
handleEmptyDragOver,
} = useClipDrag(onClipReorder, !!trimDrag)
/* ── 菜单 & 面板 ── */
const {
contextMenu,
contextMenuRef,
handleContextMenu,
handleContextSplit,
handleContextResetTrim,
handleContextDelete,
addCardRef,
handleConfirmAdd,
hoveredClipId,
setHoveredClipId,
} = useTimelineMenus(clips, currentMode, onAddClip, onClipSplit, onClipResetTrim, onClipRemove)
/* ── 播放头拖拽 ── */
const { trackRef, handlePlayheadMouseDown, handleRulerClick } = usePlayheadDrag({
currentTime,
pps,
totalDuration,
onSeek,
})
/* ── 撤销最后一个片段 ── */
const handleUndoClip = () => {
if (clips.length > 1) {
const last = clips[clips.length - 1]
onClipRemove(last.id)
}
}
return (
<div className="ep-timeline-area">
{/* 时间线头部 */}
<TimelineHeader
totalDuration={totalDuration}
pps={pps}
onZoomChange={onZoomChange}
onUndoClip={handleUndoClip}
clipsCount={clips.length}
/>
{/* 一镜到底提示 */}
{currentMode === "one_take" && <div className="ep-one-take-hint">🎥 一镜到底模式无片段</div>}
{/* 时间标尺 */}
{currentMode !== "one_take" && (
<TimeRuler totalDuration={totalDuration} pps={pps} onClick={handleRulerClick} />
)}
{/* 水平片段轨道 */}
{currentMode !== "one_take" && (
<ClipTrack
clips={clips}
selectedClipId={selectedClipId}
pps={pps}
currentTime={currentTime}
totalDuration={totalDuration}
dragIdx={dragIdx}
dragOverIdx={dragOverIdx}
hoveredClipId={hoveredClipId}
trimDragActive={!!trimDrag}
showTrimHandles={!!onClipTrim}
trackRef={trackRef}
addCardRef={addCardRef}
onPlayheadMouseDown={handlePlayheadMouseDown}
onClipSelect={onClipSelect}
onDragStart={handleDragStart}
onDragOver={handleDragOver}
onDragEnd={handleDragEnd}
onDrop={handleDrop}
onEmptyDragOver={handleEmptyDragOver}
onContextMenu={handleContextMenu}
onClipMouseEnter={setHoveredClipId}
onClipMouseLeave={() => setHoveredClipId(null)}
onTrimHandleMouseDown={handleTrimHandleMouseDown}
onClipRemove={onClipRemove}
onTogglePicker={handleConfirmAdd}
/>
)}
{/* 裁剪预览 tooltip */}
{trimPreview && (
<TrimPreview
startTime={trimPreview.startTime}
endTime={trimPreview.endTime}
duration={trimPreview.duration}
x={trimPreview.x}
y={trimPreview.y}
/>
)}
{/* 右键菜单 */}
{contextMenu && (
<ContextMenu
x={contextMenu.x}
y={contextMenu.y}
menuRef={contextMenuRef}
hasTrim={!!clips.find((c) => c.id === contextMenu.clipId)?.trim_config}
onSplit={handleContextSplit}
onResetTrim={handleContextResetTrim}
onDelete={handleContextDelete}
/>
)}
</div>
)
}
export default TimelinePanel