refactor(TimelinePanel): 时间线面板拆分(317→226行, -29%) #1178
@@ -1,22 +1,32 @@
|
||||
/**
|
||||
* 水平轨道时间线 — 支持裁剪手柄、分割、右键菜单
|
||||
* 时间标尺(20px) + 水平片段卡片轨道(100x100) + HTML5拖拽排序
|
||||
* "+" 卡片 → 类型+时长选择器
|
||||
* 时间标尺 + 片段轨道 + HTML5拖拽排序
|
||||
*
|
||||
* 裁剪交互:
|
||||
* - 鼠标悬停片段两端显示拖拽手柄,拖动调整入点/出点
|
||||
* - 拖动时实时显示裁剪预览(入点/出点/时长)
|
||||
* - 右键片段弹出菜单:分割 / 恢复原始长度 / 删除
|
||||
* 子组件(timeline/):
|
||||
* - TimeRuler - 时间标尺
|
||||
* - ClipCard - 片段卡片
|
||||
* - ClipTrack - 片段轨道(播放头+片段列表+添加卡片)
|
||||
* - TimelineHeader - 时间线头部(标题+缩放+操作按钮)
|
||||
* - AddClipPicker - 添加片段选择器
|
||||
* - TrimPreview - 裁剪预览 tooltip
|
||||
* - ContextMenu - 右键菜单
|
||||
*
|
||||
* Hooks:
|
||||
* - useClipDrag - 片段拖拽排序
|
||||
* - useTrimDrag - 裁剪拖拽
|
||||
* - useTimelineMenus - 菜单 & 面板
|
||||
* - usePlayheadDrag - 播放头拖拽
|
||||
*/
|
||||
import React, { useState, useRef, useCallback, useEffect } from "react"
|
||||
import React from "react"
|
||||
import type { ClipData, ClipType, TrimConfig } from "../types"
|
||||
import { DEFAULT_PIXELS_PER_SECOND } from "../constants/timeline"
|
||||
import { formatTime } from "../utils/timeline"
|
||||
import { useClipDrag } from "../hooks/useClipDrag"
|
||||
import { useTrimDrag } from "../hooks/useTrimDrag"
|
||||
import { useTimelineMenus } from "../hooks/useTimelineMenus"
|
||||
import { ClipCard } from "./timeline/ClipCard"
|
||||
import { usePlayheadDrag } from "./timeline/hooks/usePlayheadDrag"
|
||||
import { TimeRuler } from "./timeline/TimeRuler"
|
||||
import { ClipTrack } from "./timeline/ClipTrack"
|
||||
import { TimelineHeader } from "./timeline/TimelineHeader"
|
||||
import { AddClipPicker } from "./timeline/AddClipPicker"
|
||||
import { TrimPreview } from "./timeline/TrimPreview"
|
||||
import { ContextMenu } from "./timeline/ContextMenu"
|
||||
@@ -105,106 +115,32 @@ const TimelinePanel: React.FC<TimelinePanelProps> = ({
|
||||
setHoveredClipId,
|
||||
} = useTimelineMenus(clips, currentMode, onAddClip, onClipSplit, onClipResetTrim, onClipRemove)
|
||||
|
||||
/* ── 播放头拖拽状态 ── */
|
||||
const [playheadDragging, setPlayheadDragging] = useState(false)
|
||||
const trackRef = useRef<HTMLDivElement>(null)
|
||||
/* ── 播放头拖拽 ── */
|
||||
const { trackRef, handlePlayheadMouseDown, handleRulerClick } = usePlayheadDrag({
|
||||
currentTime,
|
||||
pps,
|
||||
totalDuration,
|
||||
onSeek,
|
||||
})
|
||||
|
||||
/* ── 播放头拖拽全局 mousemove/mouseup ── */
|
||||
useEffect(() => {
|
||||
if (!playheadDragging) return
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
const trackEl = trackRef.current
|
||||
if (!trackEl) return
|
||||
const rect = trackEl.getBoundingClientRect()
|
||||
const x = e.clientX - rect.left + trackEl.scrollLeft
|
||||
const time = Math.max(0, Math.min(x / pps, totalDuration))
|
||||
onSeek?.(Math.round(time * 10) / 10)
|
||||
/* ── 撤销最后一个片段 ── */
|
||||
const handleUndoClip = () => {
|
||||
if (clips.length > 1) {
|
||||
const last = clips[clips.length - 1]
|
||||
onClipRemove(last.id)
|
||||
}
|
||||
|
||||
const handleMouseUp = () => {
|
||||
setPlayheadDragging(false)
|
||||
}
|
||||
|
||||
document.addEventListener("mousemove", handleMouseMove)
|
||||
document.addEventListener("mouseup", handleMouseUp)
|
||||
return () => {
|
||||
document.removeEventListener("mousemove", handleMouseMove)
|
||||
document.removeEventListener("mouseup", handleMouseUp)
|
||||
}
|
||||
}, [playheadDragging, pps, totalDuration, onSeek])
|
||||
|
||||
/* ── 标尺点击跳转播放头 ── */
|
||||
const handleRulerClick = useCallback(
|
||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||
const rect = e.currentTarget.getBoundingClientRect()
|
||||
const x = e.clientX - rect.left
|
||||
const time = Math.max(0, Math.min(x / pps, totalDuration))
|
||||
onSeek?.(Math.round(time * 10) / 10)
|
||||
},
|
||||
[pps, totalDuration, onSeek],
|
||||
)
|
||||
|
||||
/* ── 播放头拖拽开始 ── */
|
||||
const handlePlayheadMouseDown = useCallback((e: React.MouseEvent) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
setPlayheadDragging(true)
|
||||
}, [])
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ep-timeline-area">
|
||||
{/* 时间线头部 */}
|
||||
<div className="ep-timeline-header">
|
||||
<div className="ep-timeline-title">
|
||||
<span>🎬 时间线</span>
|
||||
<span className="ep-timeline-duration">总时长: {formatTime(totalDuration)}</span>
|
||||
</div>
|
||||
<div className="ep-timeline-actions">
|
||||
{/* 缩放控件 */}
|
||||
<div className="ep-timeline-zoom">
|
||||
<button
|
||||
className="ep-zoom-btn"
|
||||
onClick={() => onZoomChange?.(Math.max(10, pps - 10))}
|
||||
title="缩小"
|
||||
>
|
||||
−
|
||||
</button>
|
||||
<input
|
||||
type="range"
|
||||
className="ep-zoom-slider"
|
||||
min={10}
|
||||
max={120}
|
||||
step={5}
|
||||
value={pps}
|
||||
onChange={(e) => onZoomChange?.(Number(e.target.value))}
|
||||
/>
|
||||
<button
|
||||
className="ep-zoom-btn"
|
||||
onClick={() => onZoomChange?.(Math.min(120, pps + 10))}
|
||||
title="放大"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
<span className="ep-zoom-label">{pps}px/s</span>
|
||||
</div>
|
||||
<button
|
||||
className="ep-timeline-action-btn"
|
||||
onClick={() => {
|
||||
if (clips.length > 1) {
|
||||
const last = clips[clips.length - 1]
|
||||
onClipRemove(last.id)
|
||||
}
|
||||
}}
|
||||
title="删除最后一个片段"
|
||||
>
|
||||
↩
|
||||
</button>
|
||||
<button className="ep-timeline-action-btn" title="重做">
|
||||
↪
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<TimelineHeader
|
||||
totalDuration={totalDuration}
|
||||
pps={pps}
|
||||
onZoomChange={onZoomChange}
|
||||
onUndoClip={handleUndoClip}
|
||||
clipsCount={clips.length}
|
||||
/>
|
||||
|
||||
{/* 一镜到底提示 */}
|
||||
{currentMode === "one_take" && <div className="ep-one-take-hint">🎥 一镜到底模式无片段</div>}
|
||||
@@ -216,61 +152,33 @@ const TimelinePanel: React.FC<TimelinePanelProps> = ({
|
||||
|
||||
{/* 水平片段轨道 */}
|
||||
{currentMode !== "one_take" && (
|
||||
<div className="ep-clip-track" ref={trackRef} onDragOver={handleEmptyDragOver}>
|
||||
{/* 播放头 */}
|
||||
{currentMode !== "one_take" && totalDuration > 0 && (
|
||||
<div
|
||||
className="ep-playhead"
|
||||
style={{ left: currentTime * pps }}
|
||||
onMouseDown={handlePlayheadMouseDown}
|
||||
>
|
||||
<div className="ep-playhead-handle" />
|
||||
</div>
|
||||
)}
|
||||
{clips.length === 0 ? (
|
||||
<div className="ep-track-empty">
|
||||
<div className="ep-track-empty-icon">🎬</div>
|
||||
<div className="ep-track-empty-text">点击右侧 + 添加片段</div>
|
||||
</div>
|
||||
) : (
|
||||
clips.map((clip, idx) => (
|
||||
<ClipCard
|
||||
key={clip.id}
|
||||
clip={clip}
|
||||
idx={idx}
|
||||
isSelected={selectedClipId === clip.id}
|
||||
isDragging={dragIdx === idx}
|
||||
isDragOver={dragOverIdx === idx}
|
||||
isHovered={hoveredClipId === clip.id}
|
||||
pps={pps}
|
||||
trimDragActive={!!trimDrag}
|
||||
showTrimHandles={!!onClipTrim}
|
||||
onDragStart={handleDragStart}
|
||||
onDragOver={handleDragOver}
|
||||
onDragEnd={handleDragEnd}
|
||||
onDrop={handleDrop}
|
||||
onSelect={onClipSelect}
|
||||
onContextMenu={handleContextMenu}
|
||||
onMouseEnter={() => setHoveredClipId(clip.id)}
|
||||
onMouseLeave={() => setHoveredClipId(null)}
|
||||
onTrimHandleMouseDown={handleTrimHandleMouseDown}
|
||||
onRemove={onClipRemove}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
|
||||
{/* ── 轨道末尾 "+" 添加卡片 ── */}
|
||||
<div className="ep-track-add-card-wrapper">
|
||||
<div
|
||||
ref={addCardRef}
|
||||
className="ep-track-add-card"
|
||||
onClick={handleTogglePicker}
|
||||
title="添加片段"
|
||||
>
|
||||
+
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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={handleTogglePicker}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 裁剪预览 tooltip */}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
import React from "react"
|
||||
import type { ClipData } from "../../types"
|
||||
import { ClipCard } from "./ClipCard"
|
||||
|
||||
interface ClipTrackProps {
|
||||
/** 片段列表 */
|
||||
clips: ClipData[]
|
||||
/** 选中的片段ID */
|
||||
selectedClipId: string | null
|
||||
/** 缩放:每秒像素数 */
|
||||
pps: number
|
||||
/** 当前播放时间(秒) */
|
||||
currentTime: number
|
||||
/** 总时长(秒) */
|
||||
totalDuration: number
|
||||
/** 正在拖拽的片段索引 */
|
||||
dragIdx: number | null
|
||||
/** 拖拽悬停的片段索引 */
|
||||
dragOverIdx: number | null
|
||||
/** 悬停的片段ID */
|
||||
hoveredClipId: string | null
|
||||
/** 是否正在裁剪拖拽 */
|
||||
trimDragActive: boolean
|
||||
/** 是否显示裁剪手柄 */
|
||||
showTrimHandles: boolean
|
||||
/** 轨道ref */
|
||||
trackRef: React.RefObject<HTMLDivElement>
|
||||
/** 添加卡片ref */
|
||||
addCardRef: React.RefObject<HTMLDivElement>
|
||||
/** 播放头拖拽开始 */
|
||||
onPlayheadMouseDown: (e: React.MouseEvent) => void
|
||||
/** 片段选中 */
|
||||
onClipSelect: (clipId: string) => void
|
||||
/** 拖拽开始 */
|
||||
onDragStart: (e: React.DragEvent, idx: number) => void
|
||||
/** 拖拽悬停 */
|
||||
onDragOver: (e: React.DragEvent, idx: number) => void
|
||||
/** 拖拽结束 */
|
||||
onDragEnd: () => void
|
||||
/** 放置 */
|
||||
onDrop: (e: React.DragEvent, idx: number) => void
|
||||
/** 空区域拖拽悬停 */
|
||||
onEmptyDragOver: (e: React.DragEvent) => void
|
||||
/** 右键菜单 */
|
||||
onContextMenu: (e: React.MouseEvent, clipId: string) => void
|
||||
/** 片段悬停进入 */
|
||||
onClipMouseEnter: (clipId: string) => void
|
||||
/** 片段悬停离开 */
|
||||
onClipMouseLeave: () => void
|
||||
/** 裁剪手柄按下 */
|
||||
onTrimHandleMouseDown: (e: React.MouseEvent, clipId: string, direction: "left" | "right") => void
|
||||
/** 删除片段 */
|
||||
onClipRemove: (clipId: string) => void
|
||||
/** 点击添加卡片 */
|
||||
onTogglePicker: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* 片段轨道组件
|
||||
* 包含播放头、片段列表、空状态和添加卡片
|
||||
*/
|
||||
export const ClipTrack: React.FC<ClipTrackProps> = ({
|
||||
clips,
|
||||
selectedClipId,
|
||||
pps,
|
||||
currentTime,
|
||||
totalDuration,
|
||||
dragIdx,
|
||||
dragOverIdx,
|
||||
hoveredClipId,
|
||||
trimDragActive,
|
||||
showTrimHandles,
|
||||
trackRef,
|
||||
addCardRef,
|
||||
onPlayheadMouseDown,
|
||||
onClipSelect,
|
||||
onDragStart,
|
||||
onDragOver,
|
||||
onDragEnd,
|
||||
onDrop,
|
||||
onEmptyDragOver,
|
||||
onContextMenu,
|
||||
onClipMouseEnter,
|
||||
onClipMouseLeave,
|
||||
onTrimHandleMouseDown,
|
||||
onClipRemove,
|
||||
onTogglePicker,
|
||||
}) => {
|
||||
return (
|
||||
<div className="ep-clip-track" ref={trackRef} onDragOver={onEmptyDragOver}>
|
||||
{/* 播放头 */}
|
||||
{totalDuration > 0 && (
|
||||
<div
|
||||
className="ep-playhead"
|
||||
style={{ left: currentTime * pps }}
|
||||
onMouseDown={onPlayheadMouseDown}
|
||||
>
|
||||
<div className="ep-playhead-handle" />
|
||||
</div>
|
||||
)}
|
||||
{clips.length === 0 ? (
|
||||
<div className="ep-track-empty">
|
||||
<div className="ep-track-empty-icon">🎬</div>
|
||||
<div className="ep-track-empty-text">点击右侧 + 添加片段</div>
|
||||
</div>
|
||||
) : (
|
||||
clips.map((clip, idx) => (
|
||||
<ClipCard
|
||||
key={clip.id}
|
||||
clip={clip}
|
||||
idx={idx}
|
||||
isSelected={selectedClipId === clip.id}
|
||||
isDragging={dragIdx === idx}
|
||||
isDragOver={dragOverIdx === idx}
|
||||
isHovered={hoveredClipId === clip.id}
|
||||
pps={pps}
|
||||
trimDragActive={trimDragActive}
|
||||
showTrimHandles={showTrimHandles}
|
||||
onDragStart={onDragStart}
|
||||
onDragOver={onDragOver}
|
||||
onDragEnd={onDragEnd}
|
||||
onDrop={onDrop}
|
||||
onSelect={onClipSelect}
|
||||
onContextMenu={onContextMenu}
|
||||
onMouseEnter={() => onClipMouseEnter(clip.id)}
|
||||
onMouseLeave={onClipMouseLeave}
|
||||
onTrimHandleMouseDown={onTrimHandleMouseDown}
|
||||
onRemove={onClipRemove}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
|
||||
{/* ── 轨道末尾 "+" 添加卡片 ── */}
|
||||
<div className="ep-track-add-card-wrapper">
|
||||
<div
|
||||
ref={addCardRef}
|
||||
className="ep-track-add-card"
|
||||
onClick={onTogglePicker}
|
||||
title="添加片段"
|
||||
>
|
||||
+
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import React from "react"
|
||||
import { formatTime } from "../../utils/timeline"
|
||||
|
||||
interface TimelineHeaderProps {
|
||||
/** 总时长(秒) */
|
||||
totalDuration: number
|
||||
/** 缩放:每秒像素数 */
|
||||
pps: number
|
||||
/** 缩放变更回调 */
|
||||
onZoomChange?: (pps: number) => void
|
||||
/** 撤销最后一个片段 */
|
||||
onUndoClip?: () => void
|
||||
/** 片段数量 */
|
||||
clipsCount: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间线头部组件
|
||||
* 包含标题、总时长、缩放控件和操作按钮
|
||||
*/
|
||||
export const TimelineHeader: React.FC<TimelineHeaderProps> = ({
|
||||
totalDuration,
|
||||
pps,
|
||||
onZoomChange,
|
||||
onUndoClip,
|
||||
clipsCount,
|
||||
}) => {
|
||||
return (
|
||||
<div className="ep-timeline-header">
|
||||
<div className="ep-timeline-title">
|
||||
<span>🎬 时间线</span>
|
||||
<span className="ep-timeline-duration">总时长: {formatTime(totalDuration)}</span>
|
||||
</div>
|
||||
<div className="ep-timeline-actions">
|
||||
{/* 缩放控件 */}
|
||||
<div className="ep-timeline-zoom">
|
||||
<button
|
||||
className="ep-zoom-btn"
|
||||
onClick={() => onZoomChange?.(Math.max(10, pps - 10))}
|
||||
title="缩小"
|
||||
>
|
||||
−
|
||||
</button>
|
||||
<input
|
||||
type="range"
|
||||
className="ep-zoom-slider"
|
||||
min={10}
|
||||
max={120}
|
||||
step={5}
|
||||
value={pps}
|
||||
onChange={(e) => onZoomChange?.(Number(e.target.value))}
|
||||
/>
|
||||
<button
|
||||
className="ep-zoom-btn"
|
||||
onClick={() => onZoomChange?.(Math.min(120, pps + 10))}
|
||||
title="放大"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
<span className="ep-zoom-label">{pps}px/s</span>
|
||||
</div>
|
||||
<button
|
||||
className="ep-timeline-action-btn"
|
||||
onClick={onUndoClip}
|
||||
title="删除最后一个片段"
|
||||
disabled={clipsCount <= 1}
|
||||
>
|
||||
↩
|
||||
</button>
|
||||
<button className="ep-timeline-action-btn" title="重做">
|
||||
↪
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { useState, useCallback, useEffect, useRef } from "react"
|
||||
|
||||
interface UsePlayheadDragOptions {
|
||||
/** 当前播放时间(秒) */
|
||||
currentTime: number
|
||||
/** 缩放:每秒像素数 */
|
||||
pps: number
|
||||
/** 总时长(秒) */
|
||||
totalDuration: number
|
||||
/** 播放头跳转回调 */
|
||||
onSeek?: (time: number) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放头拖拽 Hook
|
||||
* 封装播放头的 mousedown/mousemove/mouseup 拖拽逻辑
|
||||
*/
|
||||
export const usePlayheadDrag = ({ pps, totalDuration, onSeek }: UsePlayheadDragOptions) => {
|
||||
const [playheadDragging, setPlayheadDragging] = useState(false)
|
||||
const trackRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
/* ── 播放头拖拽全局 mousemove/mouseup ── */
|
||||
useEffect(() => {
|
||||
if (!playheadDragging) return
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
const trackEl = trackRef.current
|
||||
if (!trackEl) return
|
||||
const rect = trackEl.getBoundingClientRect()
|
||||
const x = e.clientX - rect.left + trackEl.scrollLeft
|
||||
const time = Math.max(0, Math.min(x / pps, totalDuration))
|
||||
onSeek?.(Math.round(time * 10) / 10)
|
||||
}
|
||||
|
||||
const handleMouseUp = () => {
|
||||
setPlayheadDragging(false)
|
||||
}
|
||||
|
||||
document.addEventListener("mousemove", handleMouseMove)
|
||||
document.addEventListener("mouseup", handleMouseUp)
|
||||
return () => {
|
||||
document.removeEventListener("mousemove", handleMouseMove)
|
||||
document.removeEventListener("mouseup", handleMouseUp)
|
||||
}
|
||||
}, [playheadDragging, pps, totalDuration, onSeek])
|
||||
|
||||
/* ── 播放头拖拽开始 ── */
|
||||
const handlePlayheadMouseDown = useCallback((e: React.MouseEvent) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
setPlayheadDragging(true)
|
||||
}, [])
|
||||
|
||||
/* ── 标尺点击跳转播放头 ── */
|
||||
const handleRulerClick = useCallback(
|
||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||
const rect = e.currentTarget.getBoundingClientRect()
|
||||
const x = e.clientX - rect.left
|
||||
const time = Math.max(0, Math.min(x / pps, totalDuration))
|
||||
onSeek?.(Math.round(time * 10) / 10)
|
||||
},
|
||||
[pps, totalDuration, onSeek],
|
||||
)
|
||||
|
||||
return {
|
||||
trackRef,
|
||||
playheadDragging,
|
||||
handlePlayheadMouseDown,
|
||||
handleRulerClick,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Smoke test for AddClipPicker
|
||||
*/
|
||||
import { describe, it, expect } from "vitest"
|
||||
import "@/pages/editing-planner/components/timeline/AddClipPicker"
|
||||
|
||||
describe("AddClipPicker smoke", () => {
|
||||
it("should load module successfully", () => {
|
||||
expect(true).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Smoke test for ClipCard
|
||||
*/
|
||||
import { describe, it, expect } from "vitest"
|
||||
import "@/pages/editing-planner/components/timeline/ClipCard"
|
||||
|
||||
describe("ClipCard smoke", () => {
|
||||
it("should load module successfully", () => {
|
||||
expect(true).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Smoke test for ClipTrack
|
||||
*/
|
||||
import { describe, it, expect } from "vitest"
|
||||
import "@/pages/editing-planner/components/timeline/ClipTrack"
|
||||
|
||||
describe("ClipTrack smoke", () => {
|
||||
it("should load module successfully", () => {
|
||||
expect(true).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Smoke test for ContextMenu
|
||||
*/
|
||||
import { describe, it, expect } from "vitest"
|
||||
import "@/pages/editing-planner/components/timeline/ContextMenu"
|
||||
|
||||
describe("ContextMenu smoke", () => {
|
||||
it("should load module successfully", () => {
|
||||
expect(true).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Smoke test for TimeRuler
|
||||
*/
|
||||
import { describe, it, expect } from "vitest"
|
||||
import "@/pages/editing-planner/components/timeline/TimeRuler"
|
||||
|
||||
describe("TimeRuler smoke", () => {
|
||||
it("should load module successfully", () => {
|
||||
expect(true).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Smoke test for TimelineHeader
|
||||
*/
|
||||
import { describe, it, expect } from "vitest"
|
||||
import "@/pages/editing-planner/components/timeline/TimelineHeader"
|
||||
|
||||
describe("TimelineHeader smoke", () => {
|
||||
it("should load module successfully", () => {
|
||||
expect(true).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Smoke test for TrimPreview
|
||||
*/
|
||||
import { describe, it, expect } from "vitest"
|
||||
import "@/pages/editing-planner/components/timeline/TrimPreview"
|
||||
|
||||
describe("TrimPreview smoke", () => {
|
||||
it("should load module successfully", () => {
|
||||
expect(true).toBe(true)
|
||||
})
|
||||
})
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Smoke test for usePlayheadDrag
|
||||
*/
|
||||
import { describe, it, expect } from "vitest"
|
||||
import "@/pages/editing-planner/components/timeline/hooks/usePlayheadDrag"
|
||||
|
||||
describe("usePlayheadDrag smoke", () => {
|
||||
it("should load module successfully", () => {
|
||||
expect(true).toBe(true)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user