Skip to content

剪影 #16

@01du

Description

@01du

import React, { useState } from 'react';
import {
Play, Pause, SkipBack, SkipForward, Scissors, Trash2,
Undo, Redo, Download, Settings, ZoomIn, ZoomOut,
Image as ImageIcon, Type, Music, Smile, Sparkles,
Layout, SplitSquareHorizontal, Sliders, MousePointer2,
ChevronRight, ChevronDown, Plus
} from 'lucide-react';

// 模拟素材数据
const MEDIA_ASSETS = [
{ id: 1, type: 'video', name: 'Travel_Vlog_01.mp4', duration: '00:15', color: 'bg-blue-500' },
{ id: 2, type: 'video', name: 'Drone_Shot_City.mov', duration: '00:08', color: 'bg-teal-500' },
{ id: 3, type: 'image', name: 'Thumbnail.jpg', duration: '00:05', color: 'bg-purple-500' },
{ id: 4, type: 'audio', name: 'LoFi_Chill_Beat.mp3', duration: '02:30', color: 'bg-yellow-500' },
];

const SIDEBAR_TABS = [
{ id: 'media', icon: ImageIcon, label: '媒体' },
{ id: 'audio', icon: Music, label: '音频' },
{ id: 'text', icon: Type, label: '文字' },
{ id: 'stickers', icon: Smile, label: '贴纸' },
{ id: 'effects', icon: Sparkles, label: '特效' },
{ id: 'transitions', icon: SplitSquareHorizontal, label: '转场' },
{ id: 'filters', icon: Sliders, label: '滤镜' },
];

export default function CapCutClone() {
const [activeTab, setActiveTab] = useState('media');
const [isPlaying, setIsPlaying] = useState(false);
const [currentTime, setCurrentTime] = useState('00:00:04');
const [zoomLevel, setZoomLevel] = useState(50);

return (

  {/* 1. 顶部标题栏 (Header) */}
  <header className="h-12 border-b border-gray-800 bg-[#181818] flex items-center justify-between px-4 z-20">
    <div className="flex items-center gap-4">
      <div className="w-8 h-8 bg-gradient-to-br from-cyan-400 to-blue-600 rounded-lg flex items-center justify-center text-white font-bold italic">
        C
      </div>
      <div className="flex items-center gap-2 text-xs text-gray-400">
        <span className="hover:text-white cursor-pointer">Menu</span>
        <span>/</span>
        <span className="text-white font-medium truncate max-w-[150px]">Untitled Project *</span>
      </div>
    </div>

    <div className="flex items-center gap-4">
       <div className="text-xs bg-gray-800 px-3 py-1.5 rounded hover:bg-gray-700 cursor-pointer transition-colors">
         1080p
       </div>
       <button className="bg-cyan-500 hover:bg-cyan-400 text-black font-semibold text-xs px-4 py-1.5 rounded-full flex items-center gap-2 transition-colors">
         <Download size={14} />
         Export
       </button>
    </div>
  </header>

  {/* 中间主要工作区 (Main Workspace) */}
  <div className="flex-1 flex min-h-0">
    
    {/* 2. 左侧资源区 (Sidebar & Assets) */}
    <div className="flex w-[360px] border-r border-gray-800 bg-[#181818]">
      {/* 一级导航图标栏 */}
      <div className="w-16 flex flex-col items-center py-4 gap-6 border-r border-gray-800">
        {SIDEBAR_TABS.map((tab) => (
          <div 
            key={tab.id}
            onClick={() => setActiveTab(tab.id)}
            className={`flex flex-col items-center gap-1 cursor-pointer transition-colors ${activeTab === tab.id ? 'text-cyan-400' : 'text-gray-500 hover:text-gray-300'}`}
          >
            <tab.icon size={20} strokeWidth={1.5} />
            <span className="text-[10px]">{tab.label}</span>
          </div>
        ))}
      </div>

      {/* 二级资源面板 */}
      <div className="flex-1 flex flex-col min-w-0">
         <div className="h-10 border-b border-gray-800 flex items-center px-4 font-medium text-sm text-white">
           本地素材
         </div>
         <div className="flex-1 overflow-y-auto p-3">
           <div className="grid grid-cols-2 gap-3">
             <div className="aspect-square border-2 border-dashed border-gray-700 rounded-md flex flex-col items-center justify-center text-gray-500 hover:border-gray-500 cursor-pointer transition-colors">
                <Plus size={24} />
                <span className="text-xs mt-1">导入</span>
             </div>
             {MEDIA_ASSETS.map(item => (
               <div key={item.id} className="group relative aspect-square bg-gray-800 rounded-md overflow-hidden cursor-grab active:cursor-grabbing border border-transparent hover:border-cyan-500/50">
                  <div className={`w-full h-full ${item.color} opacity-50`}></div>
                  <div className="absolute bottom-0 w-full bg-black/60 p-1.5">
                    <div className="text-[10px] text-white truncate">{item.name}</div>
                    <div className="text-[9px] text-gray-400">{item.duration}</div>
                  </div>
                  <div className="absolute top-1 right-1 opacity-0 group-hover:opacity-100 transition-opacity">
                    <div className="bg-cyan-500 p-1 rounded cursor-pointer hover:bg-cyan-400">
                      <Plus size={12} className="text-black" />
                    </div>
                  </div>
               </div>
             ))}
           </div>
         </div>
      </div>
    </div>

    {/* 3. 中间播放器 (Player) */}
    <div className="flex-1 flex flex-col bg-[#0d0d0d] relative min-w-[400px]">
       {/* 播放器工具栏 */}
       <div className="h-10 flex items-center justify-between px-4">
          <div className="text-xs text-gray-500">{currentTime}</div>
          <div className="text-xs text-gray-500 flex gap-2">
            <span>100%</span>
          </div>
       </div>

       {/* 视频画面 */}
       <div className="flex-1 flex items-center justify-center p-4">
          <div className="aspect-video h-full max-h-[60%] bg-black shadow-2xl relative group border border-gray-800">
             {/* 模拟视频内容 */}
             <img 
                src="https://images.unsplash.com/photo-1492691527719-9d1e07e534b4?w=800&q=80" 
                alt="Preview" 
                className="w-full h-full object-cover opacity-80"
             />
             {/* 变换控件覆盖层 */}
             <div className="absolute inset-0 border-2 border-cyan-500/50 opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none">
                <div className="absolute top-0 left-0 w-2 h-2 bg-cyan-500 -translate-x-1 -translate-y-1"></div>
                <div className="absolute top-0 right-0 w-2 h-2 bg-cyan-500 translate-x-1 -translate-y-1"></div>
                <div className="absolute bottom-0 left-0 w-2 h-2 bg-cyan-500 -translate-x-1 translate-y-1"></div>
                <div className="absolute bottom-0 right-0 w-2 h-2 bg-cyan-500 translate-x-1 translate-y-1"></div>
             </div>
          </div>
       </div>

       {/* 播放控制栏 */}
       <div className="h-12 flex items-center justify-center gap-6 text-gray-400 mb-2">
          <SkipBack size={20} className="hover:text-white cursor-pointer" />
          <div 
            className="w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center text-black hover:scale-110 transition-transform cursor-pointer"
            onClick={() => setIsPlaying(!isPlaying)}
          >
             {isPlaying ? <Pause size={16} fill="black" /> : <Play size={16} fill="black" className="ml-0.5" />}
          </div>
          <SkipForward size={20} className="hover:text-white cursor-pointer" />
       </div>
    </div>

    {/* 4. 右侧属性面板 (Properties) */}
    <div className="w-[280px] bg-[#181818] border-l border-gray-800 flex flex-col">
       <div className="flex h-10 border-b border-gray-800">
          <div className="flex-1 flex items-center justify-center text-xs font-medium text-cyan-400 border-b-2 border-cyan-400 bg-gray-800/50 cursor-pointer">
            画面
          </div>
          <div className="flex-1 flex items-center justify-center text-xs font-medium text-gray-500 hover:text-gray-300 cursor-pointer">
            音频
          </div>
          <div className="flex-1 flex items-center justify-center text-xs font-medium text-gray-500 hover:text-gray-300 cursor-pointer">
            变速
          </div>
          <div className="flex-1 flex items-center justify-center text-xs font-medium text-gray-500 hover:text-gray-300 cursor-pointer">
            动画
          </div>
       </div>
       
       <div className="flex-1 overflow-y-auto p-4 text-xs">
          {/* 基础属性组 */}
          <div className="mb-6">
             <div className="flex items-center gap-2 mb-4 font-bold text-gray-300">
               <ChevronDown size={12} /> 基础
             </div>
             
             <div className="space-y-4 pl-2">
                <div className="flex items-center justify-between">
                   <span className="text-gray-400">缩放</span>
                   <div className="flex items-center gap-2">
                      <input type="range" className="w-20 h-1 bg-gray-600 rounded-lg appearance-none cursor-pointer" />
                      <span className="w-8 text-right text-gray-300">100%</span>
                   </div>
                </div>
                <div className="flex items-center justify-between">
                   <span className="text-gray-400">位置 X</span>
                   <span className="bg-[#0a0a0a] px-2 py-1 rounded border border-gray-700 w-16 text-center text-gray-300">0</span>
                </div>
                <div className="flex items-center justify-between">
                   <span className="text-gray-400">位置 Y</span>
                   <span className="bg-[#0a0a0a] px-2 py-1 rounded border border-gray-700 w-16 text-center text-gray-300">0</span>
                </div>
                <div className="flex items-center justify-between">
                   <span className="text-gray-400">旋转</span>
                   <div className="flex items-center gap-2">
                      <div className="w-5 h-5 rounded-full border border-gray-500 flex items-center justify-center">
                        <div className="w-0.5 h-2 bg-gray-400"></div>
                      </div>
                      <span className="w-8 text-right text-gray-300">0°</span>
                   </div>
                </div>
             </div>
          </div>

           {/* 不透明度组 */}
           <div className="mb-6">
             <div className="flex items-center gap-2 mb-4 font-bold text-gray-300">
               <ChevronRight size={12} /> 不透明度
             </div>
           </div>
       </div>
    </div>

  </div>

  {/* 5. 底部时间轴 (Timeline) */}
  <div className="h-[300px] bg-[#121212] border-t border-gray-800 flex flex-col relative z-10">
     {/* 时间轴工具栏 */}
     <div className="h-10 border-b border-gray-800 flex items-center justify-between px-4 bg-[#181818]">
        <div className="flex items-center gap-4">
           <div className="flex gap-2 text-gray-400">
              <Undo size={16} className="hover:text-white cursor-pointer" />
              <Redo size={16} className="hover:text-white cursor-pointer" />
           </div>
           <div className="w-px h-4 bg-gray-700"></div>
           <div className="flex gap-2 text-gray-400">
              <SplitSquareHorizontal size={16} className="hover:text-white cursor-pointer" />
              <Trash2 size={16} className="hover:text-white cursor-pointer" />
           </div>
        </div>
        
        <div className="flex items-center gap-2">
           <ZoomOut size={14} className="text-gray-500 cursor-pointer" onClick={() => setZoomLevel(Math.max(10, zoomLevel - 10))} />
           <input 
             type="range" 
             value={zoomLevel} 
             onChange={(e) => setZoomLevel(e.target.value)}
             className="w-24 h-1 bg-gray-600 rounded-lg appearance-none cursor-pointer" 
           />
           <ZoomIn size={14} className="text-gray-500 cursor-pointer" onClick={() => setZoomLevel(Math.min(100, zoomLevel + 10))} />
        </div>
     </div>

     {/* 时间轴内容区 */}
     <div className="flex-1 overflow-x-scroll overflow-y-hidden relative scrollbar-thin scrollbar-thumb-gray-700 scrollbar-track-transparent">
        {/* 时间刻度尺 */}
        <div className="h-6 border-b border-gray-800 flex items-end sticky top-0 bg-[#121212] z-10 min-w-[1000px]">
           {[...Array(20)].map((_, i) => (
             <div key={i} className="flex-1 border-l border-gray-700 h-2 text-[9px] text-gray-500 pl-1 select-none">
                00:0{i}
             </div>
           ))}
        </div>

        {/* 轨道区域 */}
        <div className="py-4 min-w-[1000px] relative">
           {/* 播放头 (Playhead) */}
           <div className="absolute top-0 left-[300px] bottom-0 w-px bg-white z-30 flex flex-col items-center pointer-events-none">
              <div className="w-3 h-3 bg-cyan-500 rotate-45 -translate-y-1.5 shadow-sm"></div>
           </div>

           {/* 主视频轨 */}
           <div className="h-16 bg-[#1a1a1a] mb-1 relative flex items-center border-y border-gray-800/50 group">
              <div className="absolute left-2 text-[10px] text-gray-500 z-10 bg-[#1a1a1a] px-1">Main Track</div>
              
              {/* 片段 1 */}
              <div className="absolute left-[50px] w-[250px] h-14 bg-blue-900/40 border border-blue-500/50 rounded overflow-hidden cursor-pointer hover:bg-blue-800/50 flex items-center justify-center">
                  <div className="flex w-full h-full opacity-30 gap-0.5">
                     {[...Array(10)].map((_,i) => <div key={i} className="flex-1 bg-blue-400"></div>)}
                  </div>
                  <span className="absolute text-xs text-blue-100 drop-shadow-md">Travel_Vlog_01.mp4</span>
              </div>

               {/* 片段 2 */}
               <div className="absolute left-[305px] w-[180px] h-14 bg-teal-900/40 border border-teal-500/50 rounded overflow-hidden cursor-pointer hover:bg-teal-800/50 flex items-center justify-center">
                  <span className="absolute text-xs text-teal-100 drop-shadow-md">Drone_Shot.mov</span>
              </div>
           </div>

           {/* 音频轨 */}
           <div className="h-10 bg-[#1a1a1a] relative flex items-center border-b border-gray-800/50">
              <div className="absolute left-[50px] w-[435px] h-8 bg-yellow-900/30 border border-yellow-500/30 rounded-full overflow-hidden cursor-pointer flex items-center px-2">
                 {/* 模拟波形 */}
                 <div className="flex items-center gap-0.5 w-full h-4 opacity-60">
                    {[...Array(60)].map((_, i) => (
                      <div key={i} className="w-1 bg-yellow-500 rounded-full" style={{height: `${Math.random() * 100}%`}}></div>
                    ))}
                 </div>
                 <span className="absolute left-2 text-[9px] text-yellow-200">LoFi_Chill_Beat.mp3</span>
              </div>
           </div>
           
           {/* 文本轨 */}
           <div className="h-8 mt-1 bg-[#1a1a1a] relative flex items-center">
               <div className="absolute left-[150px] w-[100px] h-6 bg-purple-900/40 border border-purple-500/50 rounded text-[10px] flex items-center justify-center text-purple-200 cursor-pointer">
                  Text: TRAVEL
               </div>
           </div>

        </div>
     </div>
  </div>
</div>

);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions