120 lines
4.2 KiB
TypeScript
120 lines
4.2 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect, useRef, useState } from 'react'
|
|
import TagSelector from '@/components/tags/TagSelector'
|
|
|
|
interface Props {
|
|
url: string
|
|
name: string
|
|
onClose: () => void
|
|
mediaKey?: string
|
|
onTagsChanged?: () => void
|
|
}
|
|
|
|
export default function VideoPlayerModal({ url, name, onClose, mediaKey, onTagsChanged }: Props) {
|
|
const overlayRef = useRef<HTMLDivElement>(null)
|
|
const [showTags, setShowTags] = useState(
|
|
() => !!mediaKey && typeof window !== 'undefined' && window.innerWidth >= 1280
|
|
)
|
|
|
|
useEffect(() => {
|
|
const handleKey = (e: KeyboardEvent) => {
|
|
if (e.key === 'Escape') onClose()
|
|
}
|
|
document.addEventListener('keydown', handleKey)
|
|
document.body.style.overflow = 'hidden'
|
|
return () => {
|
|
document.removeEventListener('keydown', handleKey)
|
|
document.body.style.overflow = ''
|
|
}
|
|
}, [onClose])
|
|
|
|
const handleOverlayClick = (e: React.MouseEvent) => {
|
|
if (e.target === overlayRef.current) onClose()
|
|
}
|
|
|
|
return (
|
|
<div
|
|
ref={overlayRef}
|
|
className="fixed inset-0 z-50 flex flex-col items-center justify-center p-4 gap-3"
|
|
style={{ backgroundColor: 'rgba(0,0,0,0.9)' }}
|
|
onClick={handleOverlayClick}
|
|
>
|
|
{/* Toolbar */}
|
|
<div className={`flex items-center justify-between w-full ${showTags ? '' : 'max-w-4xl'}`}>
|
|
<span className="text-sm truncate max-w-[80%]" style={{ color: 'var(--text-secondary)' }}>
|
|
{name}
|
|
</span>
|
|
<div className="flex items-center gap-2 flex-shrink-0">
|
|
{mediaKey && (
|
|
<button
|
|
onClick={(e) => { e.stopPropagation(); setShowTags((v) => !v) }}
|
|
className="w-8 h-8 rounded-full flex items-center justify-center text-sm transition-colors"
|
|
style={{
|
|
backgroundColor: showTags ? 'var(--accent)' : 'var(--surface)',
|
|
color: showTags ? '#fff' : 'var(--text-primary)',
|
|
}}
|
|
onMouseEnter={(e) => {
|
|
if (!showTags) (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--surface-hover)'
|
|
}}
|
|
onMouseLeave={(e) => {
|
|
if (!showTags) (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--surface)'
|
|
}}
|
|
aria-label={showTags ? 'Hide tags' : 'Show tags'}
|
|
title="Tags"
|
|
>
|
|
🏷
|
|
</button>
|
|
)}
|
|
<button
|
|
onClick={onClose}
|
|
className="w-8 h-8 rounded-full flex items-center justify-center text-sm flex-shrink-0 transition-colors"
|
|
style={{ backgroundColor: 'var(--surface)', color: 'var(--text-primary)' }}
|
|
onMouseEnter={(e) => ((e.currentTarget as HTMLElement).style.backgroundColor = 'var(--surface-hover)')}
|
|
onMouseLeave={(e) => ((e.currentTarget as HTMLElement).style.backgroundColor = 'var(--surface)')}
|
|
aria-label="Close"
|
|
>
|
|
✕
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{showTags ? (
|
|
<div className="flex gap-4 w-full flex-1 min-h-0 items-start">
|
|
{/* Video */}
|
|
<div className="flex-1 min-w-0 flex items-center justify-center">
|
|
<video
|
|
src={url}
|
|
controls
|
|
autoPlay
|
|
className="w-full max-h-full rounded-lg"
|
|
style={{ backgroundColor: '#000' }}
|
|
onClick={(e) => e.stopPropagation()}
|
|
/>
|
|
</div>
|
|
{/* Tag panel */}
|
|
<div
|
|
className="w-80 flex-shrink-0 rounded-xl overflow-y-auto max-h-[80vh] p-4"
|
|
style={{ backgroundColor: 'var(--surface)', border: '1px solid var(--border)' }}
|
|
onClick={(e) => e.stopPropagation()}
|
|
>
|
|
<p className="text-xs font-semibold uppercase tracking-wider mb-3" style={{ color: 'var(--text-secondary)' }}>
|
|
Tags
|
|
</p>
|
|
<TagSelector mediaKey={mediaKey!} onTagsChanged={onTagsChanged} />
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<video
|
|
src={url}
|
|
controls
|
|
autoPlay
|
|
className="w-full max-w-4xl max-h-[80vh] rounded-lg"
|
|
style={{ backgroundColor: '#000' }}
|
|
onClick={(e) => e.stopPropagation()}
|
|
/>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|