File size: 5,220 Bytes
23b413b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
134
135
import React from 'react'
import { Loader2, ImageIcon, RefreshCw } from 'lucide-react'
import { resolveFileUrl } from '../../resolveFileUrl'

// -----------------------------------------------------------------------------
// Types
// -----------------------------------------------------------------------------

type StudioPreviewPanelProps = {
  imageUrl?: string | null
  isGenerating?: boolean
  narration?: string
  prompt?: string
  onRegenerateImage?: () => void
  className?: string
}

// -----------------------------------------------------------------------------
// Component
// -----------------------------------------------------------------------------

/**
 * Preview panel for the current scene, styled like Imagine's lightbox.
 * Shows the scene image with narration overlay and generation status.
 */
export function StudioPreviewPanel({
  imageUrl,
  isGenerating = false,
  narration,
  prompt,
  onRegenerateImage,
  className = '',
}: StudioPreviewPanelProps) {
  const hasImage = Boolean(imageUrl)

  return (
    <div className={`relative flex-1 overflow-hidden ${className}`}>
      {/* Background gradient */}
      <div className="absolute inset-0 bg-gradient-to-b from-black via-[#0a0a0f] to-[#121218]" />

      {/* Main content area */}
      <div className="absolute inset-0 flex items-center justify-center p-4">
        {hasImage ? (
          <div className="relative w-full h-full flex items-center justify-center">
            {/* Image container with subtle shadow */}
            <div className="relative max-w-full max-h-full">
              <img
                src={resolveFileUrl(imageUrl!)}
                alt="Scene preview"
                className="max-h-[calc(100vh-320px)] max-w-full object-contain rounded-lg shadow-2xl transition-opacity duration-700"
              />

              {/* Regenerate overlay on hover */}
              {onRegenerateImage && (
                <div className="absolute inset-0 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity duration-300 bg-black/40 rounded-lg">
                  <button
                    onClick={onRegenerateImage}
                    disabled={isGenerating}
                    className="flex items-center gap-2 px-4 py-2 bg-white/10 backdrop-blur-md border border-white/20 rounded-full text-white text-sm font-medium hover:bg-white/20 transition-colors disabled:opacity-50"
                    type="button"
                  >
                    <RefreshCw size={14} className={isGenerating ? 'animate-spin' : ''} />
                    Regenerate Image
                  </button>
                </div>
              )}
            </div>

            {/* Generating overlay */}
            {isGenerating && (
              <div className="absolute inset-0 flex items-center justify-center bg-black/60 rounded-lg">
                <div className="flex flex-col items-center gap-3">
                  <Loader2 size={32} className="text-purple-400 animate-spin" />
                  <span className="text-white/70 text-sm">Generating image...</span>
                </div>
              </div>
            )}
          </div>
        ) : (
          /* Empty state when no image */
          <div className="flex flex-col items-center justify-center text-center p-8">
            {isGenerating ? (
              <>
                <Loader2 size={48} className="text-purple-400 animate-spin mb-4" />
                <p className="text-white/70 text-sm">Generating image...</p>
                {prompt && (
                  <p className="text-white/40 text-xs mt-2 max-w-md line-clamp-2">{prompt}</p>
                )}
              </>
            ) : (
              <>
                <div className="w-16 h-16 rounded-2xl bg-white/5 border border-white/10 flex items-center justify-center mb-4">
                  <ImageIcon size={24} className="text-white/30" />
                </div>
                <p className="text-white/50 text-sm">No image for this scene</p>
                {onRegenerateImage && (
                  <button
                    onClick={onRegenerateImage}
                    className="mt-4 flex items-center gap-2 px-4 py-2 bg-purple-500 hover:bg-purple-600 rounded-full text-white text-sm font-medium transition-colors"
                    type="button"
                  >
                    Generate Image
                  </button>
                )}
              </>
            )}
          </div>
        )}
      </div>

      {/* Narration subtitle overlay */}
      {narration && (
        <div className="absolute bottom-6 left-0 right-0 flex justify-center px-8 pointer-events-none">
          <div className="bg-black/80 backdrop-blur-sm px-6 py-4 rounded-xl max-w-3xl shadow-lg border border-white/5">
            <p className="text-base md:text-lg text-white leading-relaxed text-center">
              {narration}
            </p>
          </div>
        </div>
      )}

      <style>{`
        .line-clamp-2 {
          display: -webkit-box;
          -webkit-line-clamp: 2;
          -webkit-box-orient: vertical;
          overflow: hidden;
        }
      `}</style>
    </div>
  )
}

export default StudioPreviewPanel