File size: 5,919 Bytes
bf849d3 eceac5b bf849d3 9048ee6 eceac5b bf849d3 eceac5b bf849d3 eceac5b bf849d3 eceac5b bf849d3 eceac5b bf849d3 eceac5b bf849d3 eceac5b bf849d3 eceac5b bf849d3 eceac5b bf849d3 eceac5b bf849d3 eceac5b bf849d3 eceac5b bf849d3 e1a68dd bf849d3 e1a68dd bf849d3 eceac5b bf849d3 | 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 | import React, { useState } from 'react';
import { motion } from 'framer-motion';
import { Upload, Image as ImageIcon, Loader } from 'lucide-react';
import axios from 'axios';
const InteriorStyleTransformer = () => {
const [selectedImage, setSelectedImage] = useState(null);
const [styleInput, setStyleInput] = useState('');
const [generatedImage, setGeneratedImage] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
// Handle image upload
const handleImageUpload = (event) => {
const file = event.target.files[0];
if (file) {
setSelectedImage(URL.createObjectURL(file));
setGeneratedImage(null);
setError(null);
}
};
// Handle style input change
const handleStyleInput = (event) => {
setStyleInput(event.target.value);
};
// Handle form submission to process the image
const handleSubmit = async () => {
if (!selectedImage || !styleInput) {
setError('Please upload an image and specify a design style.');
return;
}
setIsLoading(true);
setError(null);
try {
// Prepare form data
const formData = new FormData();
const fileInput = document.querySelector('input[type="file"]');
formData.append('image', fileInput.files[0]);
formData.append('style', styleInput);
// Hypothetical API call to an AI image processing service
const response = await axios.post('https://api.example.com/transform-interior', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
// Assuming the API returns a URL to the generated image
setGeneratedImage(response.data.imageUrl);
} catch (err) {
setError('Failed to process the image. Please try again.');
console.error(err);
} finally {
setIsLoading(false);
}
};
return (
<section className="py-20 bg-[#0B1118]">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
className="text-center mb-12"
>
<h2 className="text-3xl md:text-4xl font-bold mb-4 text-white">
Transform Your Interior Design
</h2>
<p className="text-xl text-gray-400">
Upload a photo of your space and specify your desired interior design style.
</p>
</motion.div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{/* Image Upload Section */}
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
whileInView={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.5 }}
className="bg-gray-800/30 rounded-lg p-6 border border-gray-700 hover:border-blue-500/50"
>
<h3 className="text-xl font-semibold mb-4 text-white">Upload Your Room Photo</h3>
<div className="flex flex-col items-center">
<label className="w-full flex flex-col items-center px-4 py-6 bg-gray-900/50 rounded-lg border-2 border-dashed border-gray-600 cursor-pointer hover:border-blue-500">
<Upload className="h-12 w-12 text-blue-500 mb-4" />
<span className="text-gray-400">
{selectedImage ? 'Change Image' : 'Upload an Image'}
</span>
<input
type="file"
accept="image/*"
className="hidden"
onChange={handleImageUpload}
/>
</label>
{selectedImage && (
<img
src={selectedImage}
alt="Uploaded room"
className="mt-4 max-h-64 w-full object-contain rounded-lg"
/>
)}
</div>
</motion.div>
{/* Style Input and Generated Image Section */}
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
whileInView={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.5 }}
className="bg-gray-800/30 rounded-lg p-6 border border-gray-700 hover:border-blue-500/50"
>
<h3 className="text-xl font-semibold mb-4 text-white">Specify Design Style</h3>
<input
type="text"
placeholder="e.g., Modern, Scandinavian, Minimalist"
value={styleInput}
onChange={handleStyleInput}
className="w-full px-4 py-2 bg-gray-900 text-white rounded-lg border border-gray-600 focus:outline-none focus:border-blue-500 mb-4"
/>
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={handleSubmit}
disabled={isLoading}
className="w-full px-4 py-2 bg-blue-600 text-white rounded-lg font-semibold hover:bg-blue-700 disabled:bg-gray-600"
>
{isLoading ? (
<div className="flex items-center justify-center">
<Loader className="h-6 w-6 animate-spin mr-2" />
Processing...
</div>
) : (
'Generate Design'
)}
</motion.button>
{error && <p className="text-red-500 mt-4">{error}</p>}
{generatedImage && (
<div className="mt-4">
<h3 className="text-lg font-semibold text-white mb-2">Generated Design</h3>
<img
src={generatedImage}
alt="Generated interior design"
className="max-h-64 w-full object-contain rounded-lg"
/>
</div>
)}
</motion.div>
</div>
</div>
</section>
);
};
export default InteriorStyleTransformer; |