Files

184 lines
7.7 KiB
TypeScript

import React from 'react'
import { Magnet, Type } from 'lucide-react'
import { PRIMARY_TOOLS, TRIM_TOOLS, ToolType } from './video-editor-utils'
import { getShortcutLabel, type KeyboardLayout } from './video-editor-utils'
import { Tooltip } from '@/components/ui/tooltip'
interface ToolsPanelProps {
activeTool: ToolType
setActiveTool: (t: ToolType) => void
lastTrimTool: ToolType
setLastTrimTool: (t: ToolType) => void
showTrimFlyout: boolean
setShowTrimFlyout: (v: boolean) => void
trimFlyoutOpenedRef: React.MutableRefObject<boolean>
trimLongPressRef: React.MutableRefObject<ReturnType<typeof setTimeout> | null>
snapEnabled: boolean
setSnapEnabled: (v: boolean) => void
showEffectsBrowser: boolean
setShowEffectsBrowser: (v: boolean) => void
addTextClip: () => void
kbLayout: KeyboardLayout
}
export function ToolsPanel({
activeTool, setActiveTool,
lastTrimTool, setLastTrimTool,
showTrimFlyout, setShowTrimFlyout,
trimFlyoutOpenedRef, trimLongPressRef,
snapEnabled, setSnapEnabled,
showEffectsBrowser: _showEffectsBrowser, setShowEffectsBrowser: _setShowEffectsBrowser, // EFFECTS HIDDEN
addTextClip, kbLayout,
}: ToolsPanelProps) {
return (
<div className="w-10 flex-shrink-0 bg-zinc-900 border-r border-zinc-800 flex flex-col items-center py-1 gap-0.5 overflow-y-auto">
{PRIMARY_TOOLS.map(tool => (
<Tooltip
key={tool.id}
side="right"
content={(() => { const s = getShortcutLabel(kbLayout, tool.actionId); return <>{tool.label}{s && <span className="text-zinc-400"> ({s})</span>}</>; })()}
>
<button
onClick={() => setActiveTool(tool.id)}
className={`p-1.5 rounded-lg transition-colors flex-shrink-0 ${
activeTool === tool.id
? 'bg-blue-600 text-white'
: 'text-zinc-400 hover:bg-zinc-800 hover:text-white'
}`}
>
<tool.icon className="h-4 w-4" />
</button>
</Tooltip>
))}
{/* Trim tools group button */}
{(() => {
const trimToolIds = new Set(TRIM_TOOLS.map(t => t.id))
const isTrimActive = trimToolIds.has(activeTool)
const currentTrimTool = TRIM_TOOLS.find(t => t.id === (isTrimActive ? activeTool : lastTrimTool)) || TRIM_TOOLS[0]
return (
<div className="relative flex-shrink-0">
<Tooltip
side="right"
content={(() => { const s = getShortcutLabel(kbLayout, currentTrimTool.actionId); return <>{currentTrimTool.label}<span className="text-zinc-400">{s ? ` (${s}) — ` : ' — '}right-click or hold for more</span></>; })()}
>
<button
onClick={() => {
if (trimFlyoutOpenedRef.current) { trimFlyoutOpenedRef.current = false; return }
setActiveTool(currentTrimTool.id)
setLastTrimTool(currentTrimTool.id)
}}
onContextMenu={(e) => {
e.preventDefault()
e.stopPropagation()
if (trimLongPressRef.current) { clearTimeout(trimLongPressRef.current); trimLongPressRef.current = null }
trimFlyoutOpenedRef.current = true
setShowTrimFlyout(true)
}}
onMouseDown={(e) => {
if (e.button !== 0) return
trimFlyoutOpenedRef.current = false
trimLongPressRef.current = setTimeout(() => {
trimLongPressRef.current = null
trimFlyoutOpenedRef.current = true
setShowTrimFlyout(true)
}, 400)
}}
onMouseUp={() => {
if (trimLongPressRef.current) { clearTimeout(trimLongPressRef.current); trimLongPressRef.current = null }
}}
onMouseLeave={() => {
if (trimLongPressRef.current) { clearTimeout(trimLongPressRef.current); trimLongPressRef.current = null }
}}
data-trim-group-btn=""
className={`p-1.5 rounded-lg transition-colors relative ${
isTrimActive
? 'bg-blue-600 text-white'
: 'text-zinc-400 hover:bg-zinc-800 hover:text-white'
}`}
>
<currentTrimTool.icon className="h-4 w-4" />
<div className="absolute bottom-0 right-0 w-0 h-0 border-l-[4px] border-l-transparent border-b-[4px] border-b-current opacity-60" />
</button>
</Tooltip>
{showTrimFlyout && (() => {
const btnEl = document.querySelector('[data-trim-group-btn]')
const rect = btnEl?.getBoundingClientRect()
return (
<>
<div className="fixed inset-0 z-[9998]" onMouseDown={() => setShowTrimFlyout(false)} onContextMenu={(e) => { e.preventDefault(); setShowTrimFlyout(false) }} />
<div
className="fixed bg-zinc-800 border border-zinc-700 rounded-lg shadow-xl py-1 z-[9999] min-w-[160px]"
style={{ top: rect?.top ?? 0, left: (rect?.right ?? 44) + 4 }}
>
{TRIM_TOOLS.map(t => (
<button
key={t.id}
onClick={() => {
setActiveTool(t.id)
setLastTrimTool(t.id)
setShowTrimFlyout(false)
}}
className={`w-full text-left px-3 py-1.5 text-xs flex items-center gap-2 transition-colors ${
activeTool === t.id ? 'bg-blue-600/30 text-white' : 'text-zinc-300 hover:bg-zinc-700'
}`}
>
<t.icon className="h-3.5 w-3.5" />
<span className="flex-1">{t.label}</span>
<span className="text-zinc-500 text-[10px]">{getShortcutLabel(kbLayout, t.actionId)}</span>
</button>
))}
</div>
</>
)
})()}
</div>
)
})()}
<div className="w-6 h-px bg-zinc-700 my-1 flex-shrink-0" />
<Tooltip side="right" content={snapEnabled ? 'Snapping On' : 'Snapping Off'}>
<button
onClick={() => setSnapEnabled(!snapEnabled)}
className={`p-1.5 rounded-lg transition-colors flex-shrink-0 ${
snapEnabled
? 'bg-blue-600 text-white'
: 'text-zinc-400 hover:bg-zinc-800 hover:text-white'
}`}
>
<Magnet className="h-4 w-4" />
</button>
</Tooltip>
{/* EFFECTS HIDDEN - FX button hidden because effects are not applied during export
<div className="w-6 h-px bg-zinc-700 my-1 flex-shrink-0" />
<Tooltip side="right" content="Effects Browser">
<button
onClick={() => setShowEffectsBrowser(!showEffectsBrowser)}
className={`p-1.5 rounded-lg transition-colors flex-shrink-0 text-[10px] font-bold ${
showEffectsBrowser
? 'bg-blue-600 text-white'
: 'text-zinc-400 hover:bg-zinc-800 hover:text-white'
}`}
>
FX
</button>
</Tooltip>
EFFECTS HIDDEN */}
<div className="w-6 h-px bg-zinc-700 my-1 flex-shrink-0" />
<Tooltip side="right" content="Add Text Overlay">
<button
onClick={() => addTextClip()}
className="p-1.5 rounded-lg transition-colors flex-shrink-0 text-cyan-400 hover:bg-cyan-900/30 hover:text-cyan-300"
>
<Type className="h-4 w-4" />
</button>
</Tooltip>
</div>
)
}