← back to My Childhood Pics

components/ui/spacex-photo-recreator.tsx

430 lines

"use client"

import type React from "react"
import { useState, useCallback } from "react"
import Image from "next/image"
import {
  Sparkles,
  Upload,
  User,
  Users,
  MapPin,
  Download,
  ArrowRight,
  X,
} from "lucide-react"
import { motion } from "framer-motion"

import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils"

type UploadMode = "person1" | "person2" | "environment"

interface GenerationSettings {
  person1Image: string | null
  person2Image: string | null
  environmentImage: string | null
  selectedEnvironment: string
}

interface SuggestedEnvironment {
  id: string
  name: string
  image: string
}

const suggestedEnvironments: SuggestedEnvironment[] = [
  {
    id: "mars",
    name: "MARS SURFACE",
    image: "https://images.unsplash.com/photo-1614728894747-a83421e2b9c9?w=400",
  },
  {
    id: "moon",
    name: "LUNAR BASE",
    image: "https://images.unsplash.com/photo-1446941103752-6d3a49ebe962?w=400",
  },
  {
    id: "station",
    name: "SPACE STATION",
    image: "https://images.unsplash.com/photo-1454391304352-2bf4678b1a7a?w=400",
  },
  {
    id: "earth",
    name: "EARTH ORBIT",
    image: "https://images.unsplash.com/photo-1611918126831-0a8352d6196f?w=400",
  },
  {
    id: "nebula",
    name: "NEBULA",
    image: "https://images.unsplash.com/photo-1502134249126-9f3755a50d78?w=400",
  },
  {
    id: "galaxy",
    name: "GALAXY",
    image: "https://images.unsplash.com/photo-1543722530-d2c3201371e7?w=400",
  },
]

export function SpaceXPhotoRecreator() {
  const [mode, setMode] = useState<UploadMode>("person1")
  const [isGenerating, setIsGenerating] = useState(false)
  const [generatedImage, setGeneratedImage] = useState<string | null>(null)
  const [showResult, setShowResult] = useState(false)

  const [settings, setSettings] = useState<GenerationSettings>({
    person1Image: null,
    person2Image: null,
    environmentImage: null,
    selectedEnvironment: "",
  })

  const handleFileUpload = useCallback((files: FileList | null, uploadMode: UploadMode) => {
    if (files && files[0]) {
      const file = files[0]
      const reader = new FileReader()

      reader.onload = (e) => {
        const result = e.target?.result as string
        if (uploadMode === "person1") {
          setSettings(prev => ({ ...prev, person1Image: result }))
        } else if (uploadMode === "person2") {
          setSettings(prev => ({ ...prev, person2Image: result }))
        } else {
          setSettings(prev => ({ ...prev, environmentImage: result, selectedEnvironment: "custom" }))
        }
      }

      reader.readAsDataURL(file)
    }
  }, [])

  const handleGenerate = async () => {
    if (!settings.person1Image) return
    if (!settings.selectedEnvironment && !settings.environmentImage) return

    setIsGenerating(true)

    // Simulate generation
    await new Promise(resolve => setTimeout(resolve, 3000))

    setGeneratedImage("https://images.unsplash.com/photo-1516849677043-ef67c9557e16?w=800")
    setShowResult(true)
    setIsGenerating(false)
  }

  const clearImage = (type: 'person1' | 'person2' | 'environment') => {
    if (type === 'person1') {
      setSettings(prev => ({ ...prev, person1Image: null }))
    } else if (type === 'person2') {
      setSettings(prev => ({ ...prev, person2Image: null }))
    } else {
      setSettings(prev => ({ ...prev, environmentImage: null, selectedEnvironment: '' }))
    }
  }

  const isReady = settings.person1Image && (settings.selectedEnvironment || settings.environmentImage)

  return (
    <div className="w-full">
      <div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
        {/* Upload Section */}
        <div className="space-y-8">
          <div>
            <h3 className="text-xs font-bold uppercase tracking-[0.3em] text-white/60 mb-6">
              Upload Photos
            </h3>

            {/* Upload Cards */}
            <div className="space-y-4">
              {/* Person 1 */}
              <motion.div
                initial={{ opacity: 0, x: -20 }}
                animate={{ opacity: 1, x: 0 }}
                transition={{ delay: 0.1 }}
                className={cn(
                  "relative border border-white/10 bg-black/40 backdrop-blur-sm p-6 hover:border-white/30 transition-all cursor-pointer",
                  settings.person1Image && "border-white/30 bg-white/5"
                )}
              >
                <input
                  type="file"
                  accept="image/*"
                  onChange={(e) => handleFileUpload(e.target.files, "person1")}
                  className="absolute inset-0 w-full h-full opacity-0 cursor-pointer z-10"
                />

                <div className="flex items-center justify-between relative z-0">
                  <div className="flex items-center gap-4">
                    {settings.person1Image ? (
                      <div className="w-16 h-16 relative">
                        <Image
                          src={settings.person1Image}
                          alt="Person 1"
                          fill
                          className="object-cover"
                        />
                      </div>
                    ) : (
                      <div className="w-16 h-16 border border-white/20 flex items-center justify-center">
                        <User className="w-6 h-6 text-white/40" />
                      </div>
                    )}
                    <div>
                      <div className="text-sm font-medium text-white">PERSON 1</div>
                      <div className="text-xs text-white/40 mt-1">
                        {settings.person1Image ? "Image uploaded" : "Required"}
                      </div>
                    </div>
                  </div>
                  {settings.person1Image && (
                    <button
                      onClick={(e) => {
                        e.stopPropagation()
                        clearImage('person1')
                      }}
                      className="relative z-20 p-2 hover:bg-white/10 transition-colors"
                    >
                      <X className="w-4 h-4 text-white/60" />
                    </button>
                  )}
                </div>
              </motion.div>

              {/* Person 2 */}
              <motion.div
                initial={{ opacity: 0, x: -20 }}
                animate={{ opacity: 1, x: 0 }}
                transition={{ delay: 0.2 }}
                className={cn(
                  "relative border border-white/10 bg-black/40 backdrop-blur-sm p-6 hover:border-white/30 transition-all cursor-pointer",
                  settings.person2Image && "border-white/30 bg-white/5"
                )}
              >
                <input
                  type="file"
                  accept="image/*"
                  onChange={(e) => handleFileUpload(e.target.files, "person2")}
                  className="absolute inset-0 w-full h-full opacity-0 cursor-pointer z-10"
                />

                <div className="flex items-center justify-between relative z-0">
                  <div className="flex items-center gap-4">
                    {settings.person2Image ? (
                      <div className="w-16 h-16 relative">
                        <Image
                          src={settings.person2Image}
                          alt="Person 2"
                          fill
                          className="object-cover"
                        />
                      </div>
                    ) : (
                      <div className="w-16 h-16 border border-white/20 flex items-center justify-center">
                        <Users className="w-6 h-6 text-white/40" />
                      </div>
                    )}
                    <div>
                      <div className="text-sm font-medium text-white">PERSON 2</div>
                      <div className="text-xs text-white/40 mt-1">Optional</div>
                    </div>
                  </div>
                  {settings.person2Image && (
                    <button
                      onClick={(e) => {
                        e.stopPropagation()
                        clearImage('person2')
                      }}
                      className="relative z-20 p-2 hover:bg-white/10 transition-colors"
                    >
                      <X className="w-4 h-4 text-white/60" />
                    </button>
                  )}
                </div>
              </motion.div>

              {/* Custom Environment */}
              <motion.div
                initial={{ opacity: 0, x: -20 }}
                animate={{ opacity: 1, x: 0 }}
                transition={{ delay: 0.3 }}
                className={cn(
                  "relative border border-white/10 bg-black/40 backdrop-blur-sm p-6 hover:border-white/30 transition-all cursor-pointer",
                  settings.environmentImage && "border-white/30 bg-white/5"
                )}
              >
                <input
                  type="file"
                  accept="image/*"
                  onChange={(e) => handleFileUpload(e.target.files, "environment")}
                  className="absolute inset-0 w-full h-full opacity-0 cursor-pointer z-10"
                />

                <div className="flex items-center justify-between relative z-0">
                  <div className="flex items-center gap-4">
                    {settings.environmentImage ? (
                      <div className="w-16 h-16 relative">
                        <Image
                          src={settings.environmentImage}
                          alt="Environment"
                          fill
                          className="object-cover"
                        />
                      </div>
                    ) : (
                      <div className="w-16 h-16 border border-white/20 flex items-center justify-center">
                        <MapPin className="w-6 h-6 text-white/40" />
                      </div>
                    )}
                    <div>
                      <div className="text-sm font-medium text-white">CUSTOM ENVIRONMENT</div>
                      <div className="text-xs text-white/40 mt-1">Upload your own</div>
                    </div>
                  </div>
                  {settings.environmentImage && (
                    <button
                      onClick={(e) => {
                        e.stopPropagation()
                        clearImage('environment')
                      }}
                      className="relative z-20 p-2 hover:bg-white/10 transition-colors"
                    >
                      <X className="w-4 h-4 text-white/60" />
                    </button>
                  )}
                </div>
              </motion.div>
            </div>
          </div>

          {/* Environment Selection */}
          <div>
            <h3 className="text-xs font-bold uppercase tracking-[0.3em] text-white/60 mb-6">
              Or Select Environment
            </h3>
            <div className="grid grid-cols-3 gap-2">
              {suggestedEnvironments.map((env, index) => (
                <motion.button
                  key={env.id}
                  initial={{ opacity: 0, scale: 0.9 }}
                  animate={{ opacity: 1, scale: 1 }}
                  transition={{ delay: index * 0.05 }}
                  onClick={() => setSettings(prev => ({
                    ...prev,
                    selectedEnvironment: env.id,
                    environmentImage: null
                  }))}
                  className={cn(
                    "relative aspect-video overflow-hidden border transition-all",
                    settings.selectedEnvironment === env.id
                      ? "border-white scale-95"
                      : "border-white/10 hover:border-white/30"
                  )}
                >
                  <Image
                    src={env.image}
                    alt={env.name}
                    fill
                    className="object-cover"
                  />
                  <div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent" />
                  <div className="absolute bottom-2 left-2 right-2">
                    <p className="text-[10px] font-bold uppercase tracking-wider text-white">
                      {env.name}
                    </p>
                  </div>
                </motion.button>
              ))}
            </div>
          </div>

          {/* Generate Button */}
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            transition={{ delay: 0.5 }}
          >
            <Button
              onClick={handleGenerate}
              disabled={!isReady || isGenerating}
              className={cn(
                "w-full h-14 text-xs font-bold uppercase tracking-[0.3em] border transition-all",
                isReady
                  ? "bg-white text-black hover:bg-white/90 border-white"
                  : "bg-transparent text-white/40 border-white/20 cursor-not-allowed"
              )}
            >
              {isGenerating ? (
                <span className="flex items-center gap-3">
                  <motion.div
                    animate={{ rotate: 360 }}
                    transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
                  >
                    <Sparkles className="w-4 h-4" />
                  </motion.div>
                  Processing...
                </span>
              ) : (
                <span className="flex items-center gap-3">
                  Generate
                  <ArrowRight className="w-4 h-4" />
                </span>
              )}
            </Button>
          </motion.div>
        </div>

        {/* Result Section */}
        <div className="relative">
          <h3 className="text-xs font-bold uppercase tracking-[0.3em] text-white/60 mb-6">
            Recreation Result
          </h3>

          {showResult && generatedImage ? (
            <motion.div
              initial={{ opacity: 0, scale: 0.95 }}
              animate={{ opacity: 1, scale: 1 }}
              className="space-y-6"
            >
              <div className="relative aspect-square overflow-hidden border border-white/10">
                <Image
                  src={generatedImage}
                  alt="Generated result"
                  fill
                  className="object-cover"
                />
              </div>

              <div className="flex gap-3">
                <Button
                  variant="outline"
                  className="flex-1 h-12 text-xs font-bold uppercase tracking-wider border-white/20 text-white hover:bg-white/10"
                  onClick={handleGenerate}
                >
                  Regenerate
                </Button>
                <Button
                  className="flex-1 h-12 text-xs font-bold uppercase tracking-wider bg-white text-black hover:bg-white/90"
                >
                  <Download className="w-4 h-4 mr-2" />
                  Download
                </Button>
              </div>
            </motion.div>
          ) : (
            <div className="aspect-square border border-white/10 bg-black/40 backdrop-blur-sm flex items-center justify-center">
              <div className="text-center">
                <div className="w-20 h-20 border border-white/20 rounded-full flex items-center justify-center mx-auto mb-4">
                  <Sparkles className="w-8 h-8 text-white/20" />
                </div>
                <p className="text-xs font-medium uppercase tracking-wider text-white/40">
                  Your recreation will appear here
                </p>
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  )
}