summaryrefslogtreecommitdiff
path: root/apps/web/src/components/editor/preview-panel.tsx
blob: 16c808f40e4e2e485fc2d9a9ca77c58ff9cb0ec9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
"use client";

import { useTimelineStore } from "@/stores/timeline-store";
import { useMediaStore } from "@/stores/media-store";
import { ImageTimelineTreatment } from "@/components/ui/image-timeline-treatment";
import { Button } from "@/components/ui/button";
import { Play, Pause } from "lucide-react";
import { useState } from "react";

export function PreviewPanel() {
  const { tracks } = useTimelineStore();
  const { mediaItems } = useMediaStore();
  const [isPlaying, setIsPlaying] = useState(false);

  // Get the first clip from the first track for preview (simplified for now)
  const firstClip = tracks[0]?.clips[0];
  const firstMediaItem = firstClip
    ? mediaItems.find((item) => item.id === firstClip.mediaId)
    : null;

  // Calculate dynamic aspect ratio - default to 16:9 if no media
  const aspectRatio = firstMediaItem?.aspectRatio || 16 / 9;

  const renderPreviewContent = () => {
    if (!firstMediaItem) {
      return (
        <div className="absolute inset-0 flex items-center justify-center text-muted-foreground/50 group-hover:text-muted-foreground/80 transition-colors">
          Drop media here or click to import
        </div>
      );
    }

    if (firstMediaItem.type === "image") {
      return (
        <ImageTimelineTreatment
          src={firstMediaItem.url}
          alt={firstMediaItem.name}
          targetAspectRatio={aspectRatio}
          className="w-full h-full rounded-lg"
          backgroundType="blur"
        />
      );
    }

    if (firstMediaItem.type === "video") {
      return firstMediaItem.thumbnailUrl ? (
        <img
          src={firstMediaItem.thumbnailUrl}
          alt={firstMediaItem.name}
          className="w-full h-full object-cover rounded-lg"
        />
      ) : (
        <div className="absolute inset-0 flex items-center justify-center text-muted-foreground/50">
          Video Preview
        </div>
      );
    }

    if (firstMediaItem.type === "audio") {
      return (
        <div className="absolute inset-0 flex items-center justify-center bg-gradient-to-br from-green-500/20 to-emerald-500/20">
          <div className="text-center">
            <div className="text-6xl mb-4">🎵</div>
            <p className="text-muted-foreground">{firstMediaItem.name}</p>
          </div>
        </div>
      );
    }

    return null;
  };

  return (
    <div className="h-full flex flex-col items-center justify-center p-4 overflow-hidden">
      <div
        className="bg-black/90 rounded-lg shadow-lg relative group overflow-hidden flex-shrink"
        style={{
          aspectRatio: aspectRatio.toString(),
          width: aspectRatio > 1 ? "100%" : "auto",
          height: aspectRatio <= 1 ? "100%" : "auto",
          maxWidth: "100%",
          maxHeight: "100%",
        }}
      >
        {renderPreviewContent()}

        {/* Playback Controls Overlay */}
        {firstMediaItem && (
          <div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity">
            <div className="flex items-center gap-2 bg-black/80 rounded-lg px-4 py-2">
              <Button
                variant="ghost"
                size="icon"
                className="text-white hover:bg-white/20"
                onClick={() => setIsPlaying(!isPlaying)}
              >
                {isPlaying ? (
                  <Pause className="h-5 w-5" />
                ) : (
                  <Play className="h-5 w-5" />
                )}
              </Button>
              <span className="text-white text-sm">
                {firstClip?.name || "No clip selected"}
              </span>
            </div>
          </div>
        )}
      </div>

      {/* Preview Info */}
      {firstMediaItem && (
        <div className="mt-4 text-center">
          <p className="text-sm text-muted-foreground">
            Preview: {firstMediaItem.name}
            {firstMediaItem.type === "image" &&
              " (with CapCut-style treatment)"}
            <br />
            <span className="text-xs text-muted-foreground/70">
              Aspect Ratio: {aspectRatio.toFixed(2)} (
              {aspectRatio > 1
                ? "Landscape"
                : aspectRatio < 1
                  ? "Portrait"
                  : "Square"}
              )
            </span>
          </p>
        </div>
      )}
    </div>
  );
}