File size: 15,373 Bytes
5f07a23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
import { LoaderCircle, ImageIcon, Send, RotateCw, Maximize, Wand2, Sun, Plus, Palette, Image as ImageLucide, Brush, SendToBack, Download, ArrowLeftRight } from 'lucide-react';
import { useEffect, useState, useCallback } from 'react';
import ImageRefiner from './ImageRefiner';
import HeaderButtons from './HeaderButtons';

// Update REFINEMENT_SUGGESTIONS with cleaner labels and full prompts
const REFINEMENT_SUGGESTIONS = [
  { label: 'Rotate', prompt: 'Can you rotate this by ', icon: RotateCw },
  { label: 'Add light', prompt: 'Can you add a light from the ', icon: Sun },
  { label: 'Add object', prompt: 'Can you add a ', icon: Plus },
  { label: 'Background', prompt: 'Can you change the background to ', icon: ImageLucide },
  { label: 'Color', prompt: 'Can you make the color more ', icon: Palette },
  { label: 'Scale', prompt: 'Can you make this ', icon: Maximize },
  { label: 'Lighting', prompt: 'Can you make the lighting more ', icon: Sun },
  { label: 'Style', prompt: 'Can you make it look more ', icon: Wand2 },
  { label: 'Material', prompt: 'Can you change the material to ', icon: Wand2 },
  // Add more suggestions as needed...
];

// Update SURPRISE_REFINEMENTS with more fun, bonkers prompts
const SURPRISE_REFINEMENTS = [
  // Open-ended prompts (higher probability)
  "Do something cool with this. I leave it up to you!",
  "Surprise me! Take this image somewhere unexpected.",
  "Transform this however you want. Be creative!",
  "Do something wild with this image. No limits!",
  "Make this image magical in your own way.",
  "Take creative freedom with this image. Surprise me!",
  "Show me what you can do with this. Go crazy!",
  "Transform this in a way I wouldn't expect.",
  "Have fun with this and do whatever inspires you.",
  "Go wild with this image! Show me something amazing.",
  "Put your own creative spin on this image.",
  "Reimagine this image however you want. Be bold!",
  "Do something unexpected with this. Totally up to you!",
  "Surprise me with your creativity. Anything goes!",
  "Make this extraordinary in whatever way you choose.",
  "Show off your creative abilities with this image!",
  "Take this in any direction that excites you!",
  "Transform this however your imagination guides you.",
  "Make this magical in your own unique way.",
  "Do something fun and unexpected with this!",
  "Surprise me! Show me your creativity.",
  "Make this more beautiful <3",
  "Put your artistic spin on this image!",
  "Let your imagination run wild with this!",
  "Take this image to a whole new level of awesome!",
  "Make this image extraordinary in your own way.",
  "Do something fantastic with this. Full creative freedom!",
  "Surprise me with a totally unexpected transformation!",
  "Go nuts with this! Show me something incredible!",
  "Add your own wild twist to this image!",
  "Make this image come alive however you want!",
  "Transform this in the most creative way possible!",
  "Go crazy with this. I want to be wowed :))",
  "Do whatever magical things you want with this image!",
  "Reinvent this image however inspires you!",
  
  // Specific wild ideas (lower probability)
  "Can you add this to outer space with aliens having a BBQ?",
  "Can you add a giraffe wearing a tuxedo to this?",
  "Can you make tiny vikings invade this image?",
  "Can you turn this into an ice cream sundae being eaten by robots?",
  "Can you make this float in a sea of rainbow soup?",
  "Can you add dancing pickles to this image?",
  "Can you make this the centerpiece of an alien museum?",
  "Can you add this to a cereal bowl being eaten by a giant?",
  "Can you make this the star of a bizarre music video?",
  "Can you add tiny dinosaurs having a tea party?",
  "Can you turn this into something from a fever dream?",
  "Can you make this the main character in a surreal fairytale?",
  "Can you put this in the middle of a candy landscape?",
  "Can you add this to a world where physics works backwards?",
  "Can you make this the prize in a cosmic game show?",
  "Can you add tiny people worshipping this as a deity?",
  "Can you put this in the paws of a giant cosmic cat?",
  "Can you make this wearing sunglasses and surfing?",
  "Can you add this to a world made entirely of cheese?",
  "Can you make this the centerpiece of a goblin birthday party?",
  "Can you transform this into a cloud creature floating in the sky?",
  "Can you add this to a world where everything is made of pasta?",
  "Can you turn this into a piñata at a monster celebration?",
  "Can you add this to outer space?",
  "Can you add this to a landscape made of breakfast foods?",
  "Can you make this the conductor of an orchestra of unusual animals?",
  "Can you turn this into a strange plant growing in an alien garden?",
  "Can you add this to a world inside a snow globe?",
  "Can you make this the secret ingredient in a witch's cauldron?",
  "Can you turn this into a superhero with an unusual power?",
  "Can you make this swimming in a sea of jelly beans?",
  "Can you add this to a planet where everything is upside down?",
  "Can you make this the treasure in a dragon's unusual collection?",
  "Can you transform this into a character in a bizarre cartoon?",
  "Can you add this to a world where shadows come to life?"
];

const DisplayCanvas = ({ 
  displayCanvasRef, 
  isLoading,
  handleSaveImage,
  handleRegenerate,
  hasGeneratedContent = false,
  currentDimension,
  onOpenHistory,
  onRefineImage,
  onSendToDoodle,
  hasHistory,
  openHistoryModal,
  toggleLibrary
}) => {
  const [showPlaceholder, setShowPlaceholder] = useState(true);
  const [inputValue, setInputValue] = useState('');
  const [showDoodleTooltip, setShowDoodleTooltip] = useState(false);
  const [showSaveTooltip, setShowSaveTooltip] = useState(false);
  const [isHoveringCanvas, setIsHoveringCanvas] = useState(false);
  
  // Update placeholder visibility when loading or content prop changes
  useEffect(() => {
    if (hasGeneratedContent) {
      setShowPlaceholder(false);
    } else if (isLoading) {
      setShowPlaceholder(true);
    }
  }, [isLoading, hasGeneratedContent]);

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!inputValue.trim()) return;
    onRefineImage(inputValue);
    setInputValue('');
  };

  const handleSuggestionClick = (suggestion) => {
    setInputValue(suggestion.prompt);
    document.querySelector('input[name="refiner"]').focus();
  };

  const handleSurpriseMe = () => {
    const randomPrompt = SURPRISE_REFINEMENTS[Math.floor(Math.random() * SURPRISE_REFINEMENTS.length)];
    setInputValue(randomPrompt);
    document.querySelector('input[name="refiner"]').focus();
  };

  const handleSendToDoodle = useCallback(() => {
    if (displayCanvasRef.current && onSendToDoodle) {
      const imageDataUrl = displayCanvasRef.current.toDataURL('image/png');
      onSendToDoodle(imageDataUrl);
    }
  }, [displayCanvasRef, onSendToDoodle]);

  // Function to handle clicking the canvas for regeneration
  const handleCanvasClickForRegenerate = () => {
    if (hasGeneratedContent && !isLoading) {
      handleRegenerate();
    }
  };

  // Placeholder function for fullscreen action
  const handleFullscreen = (e) => {
    e.stopPropagation(); // Prevent triggering the refresh
    alert('Fullscreen action triggered!'); 
    // TODO: Implement actual fullscreen logic (e.g., using Fullscreen API or opening image in new tab)
  };

  return (
    <div className="flex flex-col">
      {/* Canvas container with fixed aspect ratio */}
      <div 
        className="relative w-full"
        style={{ aspectRatio: `${currentDimension.width} / ${currentDimension.height}` }}
      >
        <button
          type="button"
          className="w-full h-full absolute inset-0 z-10 cursor-pointer appearance-none bg-transparent border-0 group" 
          onMouseEnter={() => setIsHoveringCanvas(true)}
          onMouseLeave={() => setIsHoveringCanvas(false)}
          onClick={handleCanvasClickForRegenerate}
          disabled={!hasGeneratedContent || isLoading}
          aria-label="Regenerate image"
        />
        <canvas
          ref={displayCanvasRef}
          width={currentDimension.width}
          height={currentDimension.height}
          className="absolute inset-0 w-full h-full border border-gray-300 bg-white rounded-xl shadow-soft"
          aria-label="Generated image canvas"
        />
        
        {/* Loading overlay */}
        {isLoading && (
          <div className="absolute inset-0 flex items-center justify-center bg-black/5 rounded-xl">
            <div className="bg-white/90 rounded-full p-3 shadow-medium">
              <LoaderCircle className="w-8 h-8 animate-spin text-gray-700" />
            </div>
          </div>
        )}
        
        {/* Placeholder overlay */}
        {showPlaceholder && !isLoading && !hasGeneratedContent && (
          <div className="absolute inset-0 flex flex-col items-center justify-center pointer-events-none">
            <ImageIcon className="w-7 h-7 text-gray-400 mb-2" />
            <p className="text-gray-400 text-lg font-medium">Generation will appear here</p>
          </div>
        )}

        {/* Hover-to-Refresh Overlay */}        
        {isHoveringCanvas && hasGeneratedContent && !isLoading && (
          // Added transition classes for smoother appearance
          // Changed bg-black/20 to bg-black/10 for a gentler overlay
          <div className="absolute inset-0 flex items-center justify-center bg-black/0 rounded-xl pointer-events-none transition-opacity duration-300 ease-in-out">
            {/* Container for icon - allows separate click handling */}
            {/* Removed Maximize icon */}
            <div className="flex items-center gap-4 bg-white/90 rounded-full p-3 shadow-medium pointer-events-auto"> 
              {/* Refresh Icon (clickable via parent div onClick) */}
              <RotateCw className="w-8 h-8 text-gray-700" title="Click canvas to regenerate"/> 
            </div>
          </div>
        )}
      </div>

      {/* Action bar and refiner section - Combined layout */}
      <div className="mt-4 flex items-stretch justify-between gap-2 max-w-full">
        {/* Left side wrapper for Refiner and action buttons */}
        <div className="flex items-stretch gap-2 flex-1 min-w-0">
          {/* Refiner input - only shown when there's generated content */}
          {hasGeneratedContent ? (
            <>
              <form onSubmit={handleSubmit} className="flex-1 min-w-0">
                <div className="group flex items-center bg-gray-50 focus-within:bg-white rounded-xl shadow-soft p-2 border border-gray-200 focus-within:border-gray-300 h-14 transition-colors">
                  <input
                    name="refiner"
                    type="text"
                    value={inputValue}
                    onChange={(e) => setInputValue(e.target.value)}
                    placeholder="Type to refine the image..."
                    disabled={isLoading}
                    className="flex-1 px-2 bg-transparent border-none text-sm text-gray-400 placeholder-gray-300 group-focus-within:text-gray-600 group-focus-within:placeholder-gray-400 focus:outline-none transition-colors"
                  />
                  <button
                    type="submit"
                    disabled={isLoading || !inputValue.trim()}
                    className="p-2 rounded-lg text-gray-400 group-focus-within:text-gray-700 hover:bg-gray-100 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                    aria-label="Send refinement"
                  >
                    <Send className="w-5 h-5" />
                  </button>
                </div>
              </form>
              {/* Action buttons wrapper */}
              <div className="flex gap-2">
                {/* "Send to Doodle" button with tooltip */}
                <div className="relative">
                  <button
                    type="button"
                    onClick={handleSendToDoodle}
                    disabled={isLoading}
                    onMouseEnter={() => setShowDoodleTooltip(true)}
                    onMouseLeave={() => setShowDoodleTooltip(false)}
                    className="group w-14 h-14 p-2 rounded-lg bg-gray-50 border border-gray-200 shadow-soft hover:bg-white hover:border-gray-300 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center"
                    aria-label="Send image back to doodle canvas"
                  >
                    <ArrowLeftRight className="w-5 h-5 text-gray-400 group-hover:text-gray-700 transition-colors" />
                  </button>
                  {/* Custom Tooltip - Right aligned */}
                  {showDoodleTooltip && (
                    <div className="absolute bottom-full right-0 mb-2 px-3 py-1.5 bg-white border border-gray-200 text-gray-700 text-xs rounded-lg shadow-soft whitespace-nowrap pointer-events-none">
                      Send Back to Doodle Canvas
                    </div>
                  )}
                </div>
              </div>
            </>
          ) : (
            // Placeholder div to maintain layout when no content
            <div className="flex-1 h-0" />
          )}
        </div>
      </div>

      {/* Refined suggestion chips */}
      {hasGeneratedContent && (
        <div className="mt-4 flex flex-wrap gap-2 text-xs mb-4">
          {/* Surprise Me button with updated styling */}
          <button
            type="button"
            onClick={handleSurpriseMe}
            className="group flex items-center gap-2 px-3 py-1  bg-gray-50 hover:bg-white rounded-full border border-gray-200 text-gray-400 hover:border-gray-300 transition-all focus:outline-none focus:ring-2 focus:ring-gray-200"
          >
            <Wand2 className="w-4 h-4 group-hover:text-gray-600" />
            <span className="group-hover:text-gray-600">Surprise Me</span>
          </button>

          {/* Regular suggestion buttons with updated styling */}
          {REFINEMENT_SUGGESTIONS.map((suggestion) => (
            <button
              key={`suggestion-${suggestion.label}`}
              type="button"
              onClick={() => handleSuggestionClick(suggestion)}
              className="group flex items-center gap-2 px-3 py-1 bg-gray-50 hover:bg-white rounded-full border border-gray-200 text-gray-400 hover:border-gray-300 transition-all focus:outline-none focus:ring-2 focus:ring-gray-200"
            >
              <suggestion.icon className="w-4 h-4 group-hover:text-gray-600" />
              <span className="group-hover:text-gray-600">{suggestion.label}</span>
            </button>
          ))}
        </div>
      )}
      
      {/* Header buttons - Mobile only, appearing below refinement options */}
      <div className="md:hidden flex flex-wrap justify-between items-center gap-2 mt-6 mb-2 w-full">
        <div className="grid grid-cols-3 w-full gap-2">
          <HeaderButtons 
            hasHistory={hasHistory}
            openHistoryModal={openHistoryModal}
            toggleLibrary={toggleLibrary}
            handleSaveImage={handleSaveImage}
            isLoading={isLoading}
            hasGeneratedContent={hasGeneratedContent}
          />
        </div>
      </div>
    </div>
  );
};

export default DisplayCanvas;