10 Commits

Author SHA1 Message Date
87aa54d786 Update src/app/page.tsx 2026-03-11 07:02:14 +00:00
bce176f26f Update src/app/page.tsx 2026-03-11 07:01:07 +00:00
275afe7b48 Switch to version 1: remove src/components/virtualTryOn/VirtualTryOnUpload.tsx 2026-03-11 06:58:50 +00:00
b3d4e9c603 Switch to version 1: remove src/components/virtualTryOn/VirtualTryOnPreview.tsx 2026-03-11 06:58:50 +00:00
1aaf017077 Switch to version 1: modified src/app/styles/variables.css 2026-03-11 06:58:49 +00:00
6277f3754b Switch to version 1: modified src/app/page.tsx 2026-03-11 06:58:49 +00:00
7069e73c83 Switch to version 1: modified src/app/favicon.ico 2026-03-11 06:58:49 +00:00
c87f5afa7c Merge version_2 into main
Merge version_2 into main
2026-03-11 06:58:16 +00:00
31c6c49d87 Merge version_2 into main
Merge version_2 into main
2026-03-10 11:38:26 +00:00
091b625404 Merge version_2 into main
Merge version_2 into main
2026-03-10 11:21:30 +00:00
5 changed files with 52 additions and 394 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -9,30 +9,9 @@ import MetricCardOne from "@/components/sections/metrics/MetricCardOne";
import FaqDouble from "@/components/sections/faq/FaqDouble";
import ContactFaq from "@/components/sections/contact/ContactFaq";
import FooterBaseReveal from "@/components/sections/footer/FooterBaseReveal";
import VirtualTryOnUpload from "@/components/virtualTryOn/VirtualTryOnUpload";
import VirtualTryOnPreview from "@/components/virtualTryOn/VirtualTryOnPreview";
import { Clock, Package, Sparkles, Target, Zap } from "lucide-react";
import { useState } from "react";
export default function LandingPage() {
const [userPhoto, setUserPhoto] = useState<string | null>(null);
const [clothesPhoto, setClothesPhoto] = useState<string | null>(null);
const [showPreview, setShowPreview] = useState(false);
const handleUserPhotoUpload = (photo: string) => {
setUserPhoto(photo);
};
const handleClothesPhotoUpload = (photo: string) => {
setClothesPhoto(photo);
};
const handleStartTryOn = () => {
if (userPhoto && clothesPhoto) {
setShowPreview(true);
}
};
return (
<ThemeProvider
defaultButtonVariant="directional-hover"
@@ -63,18 +42,21 @@ export default function LandingPage() {
<div id="hero" data-section="hero">
<HeroCarouselLogo
logoText="VIRTUAL TRY ON"
description="Upload your photo and clothes to instantly see how outfits look on you. No more guessing visualize your style in seconds with AI-powered virtual fitting."
description="Shop with confidence—see exactly how clothes fit on your body before buying. Upload your photo and clothes to instantly visualize outfits with AI-powered virtual fitting."
buttons={[
{ text: "Start Try-On", href: "tryon" },
{ text: "Learn More", href: "about" },
]}
slides={[
{
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/a-modern-clean-interface-showing-a-perso-1773140923936-4fd9a2ad.png", imageAlt: "Virtual try-on demonstration with user wearing tried-on clothes"},
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/a-modern-clean-interface-showing-a-perso-1773140923936-4fd9a2ad.png", imageAlt: "Virtual try-on demonstration with user wearing tried-on clothes"
},
{
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/a-fashion-model-in-professional-studio-s-1773140924846-ede690c0.png", imageAlt: "Fashion model trying on different outfits virtually"},
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/a-fashion-model-in-professional-studio-s-1773140924846-ede690c0.png", imageAlt: "Fashion model trying on different outfits virtually"
},
{
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/user-interface-showing-real-time-virtual-1773140923840-8d6f0322.png", imageAlt: "User interface showing virtual clothing fitting on person"},
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/user-interface-showing-real-time-virtual-1773140923840-8d6f0322.png", imageAlt: "User interface showing virtual clothing fitting on person"
},
]}
autoplayDelay={4000}
showDimOverlay={true}
@@ -87,23 +69,29 @@ export default function LandingPage() {
{
id: 1,
title: "Upload Your Photo", description: "Take a clear full-body photo or upload from your gallery. Our AI analyzes your body measurements and proportions automatically.", phoneOne: {
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/smartphone-screen-showing-photo-upload-i-1773140923728-8a57dab7.png", imageAlt: "Upload Your Photo - Phone 1"},
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/smartphone-screen-showing-photo-upload-i-1773140923728-8a57dab7.png", imageAlt: "Upload Your Photo - Phone 1"
},
phoneTwo: {
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/smartphone-screen-showing-successful-pho-1773140924340-d914f40c.png", imageAlt: "Upload Your Photo - Phone 2"},
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/smartphone-screen-showing-successful-pho-1773140924340-d914f40c.png", imageAlt: "Upload Your Photo - Phone 2"
},
},
{
id: 2,
title: "Select Your Clothes", description: "Browse from our extensive catalog or upload images of clothes you own. Choose sizes and colors to customize your selection.", phoneOne: {
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/smartphone-displaying-clothing-catalog-i-1773140924524-ff3ad0c2.png", imageAlt: "Select Your Clothes - Phone 1"},
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/smartphone-displaying-clothing-catalog-i-1773140924524-ff3ad0c2.png", imageAlt: "Select Your Clothes - Phone 1"
},
phoneTwo: {
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/smartphone-screen-showing-selected-cloth-1773140924624-dbbb7667.png", imageAlt: "Select Your Clothes - Phone 2"},
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/smartphone-screen-showing-selected-cloth-1773140924624-dbbb7667.png", imageAlt: "Select Your Clothes - Phone 2"
},
},
{
id: 3,
title: "See How It Looks", description: "Watch in real-time as our AI technology drapes the clothing onto your body. Get instant visual feedback before making purchase decisions.", phoneOne: {
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/smartphone-showing-real-time-virtual-try-1773140924250-6c935ace.png", imageAlt: "See How It Looks - Phone 1"},
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/smartphone-showing-real-time-virtual-try-1773140924250-6c935ace.png", imageAlt: "See How It Looks - Phone 1"
},
phoneTwo: {
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/smartphone-interface-showing-side-by-sid-1773140924110-0eadfeb0.jpg", imageAlt: "See How It Looks - Phone 2"},
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AkdZCEKcsvSa3zMiBDupiHXQnd/smartphone-interface-showing-side-by-sid-1773140924110-0eadfeb0.jpg", imageAlt: "See How It Looks - Phone 2"
},
},
]}
showStepNumbers={true}
@@ -131,28 +119,18 @@ export default function LandingPage() {
<div id="tryon" data-section="tryon">
<div className="w-full py-20 px-4 md:px-8 bg-gradient-to-b from-transparent to-background/50">
<div className="max-w-6xl mx-auto">
{!showPreview ? (
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<VirtualTryOnUpload
title="Upload Your Photo"
description="Select a clear full-body photo for accurate measurements"
onPhotoUpload={handleUserPhotoUpload}
uploadType="user"
/>
<VirtualTryOnUpload
title="Upload Clothing Photo"
description="Choose the clothes you want to try on"
onPhotoUpload={handleClothesPhotoUpload}
uploadType="clothes"
/>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<div className="flex flex-col items-center justify-center p-8 rounded-lg border border-border/30 bg-card">
<h3 className="text-2xl font-semibold mb-2">Upload Your Photo</h3>
<p className="text-center text-muted-foreground mb-4">Select a clear full-body photo for accurate measurements</p>
<button className="px-6 py-2 bg-primary-cta text-primary-cta-foreground rounded-theme hover:opacity-90 transition-opacity">Upload Photo</button>
</div>
) : (
<VirtualTryOnPreview
userPhoto={userPhoto}
clothesPhoto={clothesPhoto}
onBack={() => setShowPreview(false)}
/>
)}
<div className="flex flex-col items-center justify-center p-8 rounded-lg border border-border/30 bg-card">
<h3 className="text-2xl font-semibold mb-2">Upload Clothing Photo</h3>
<p className="text-center text-muted-foreground mb-4">Choose the clothes you want to try on</p>
<button className="px-6 py-2 bg-primary-cta text-primary-cta-foreground rounded-theme hover:opacity-90 transition-opacity">Upload Clothes</button>
</div>
</div>
</div>
</div>
</div>
@@ -187,17 +165,23 @@ export default function LandingPage() {
<FaqDouble
faqs={[
{
id: "1", title: "How accurate is the virtual try-on?", content: "Our AI technology uses advanced computer vision and machine learning to achieve 94% accuracy in fit prediction. We analyze 50+ body points and fabric properties to ensure realistic visualization. Results vary based on photo quality and clothing specifications."},
id: "1", title: "How accurate is the virtual try-on?", content: "Our AI technology uses advanced computer vision and machine learning to achieve 94% accuracy in fit prediction. We analyze 50+ body points and fabric properties to ensure realistic visualization. Results vary based on photo quality and clothing specifications."
},
{
id: "2", title: "What data do you collect from my photos?", content: "We analyze body measurements and proportions but do not store your original photos permanently. Data is processed securely and deleted after 30 days unless you choose to save your profile. You have full control over your privacy settings."},
id: "2", title: "What data do you collect from my photos?", content: "We analyze body measurements and proportions but do not store your original photos permanently. Data is processed securely and deleted after 30 days unless you choose to save your profile. You have full control over your privacy settings."
},
{
id: "3", title: "Can I use this for online shopping?", content: "Yes! Many retailers integrate with our platform. You can see exactly how clothes will fit before purchasing, significantly reducing return rates and improving shopping confidence."},
id: "3", title: "Can I use this for online shopping?", content: "Yes! Many retailers integrate with our platform. You can see exactly how clothes will fit before purchasing, significantly reducing return rates and improving shopping confidence."
},
{
id: "4", title: "Which devices are supported?", content: "Our platform works on all modern devices including smartphones, tablets, and desktop computers. We recommend good lighting and a clear full-body view for best results."},
id: "4", title: "Which devices are supported?", content: "Our platform works on all modern devices including smartphones, tablets, and desktop computers. We recommend good lighting and a clear full-body view for best results."
},
{
id: "5", title: "Is there a subscription fee?", content: "Basic virtual try-on is completely free. Premium features like advanced body mapping and brand partnerships are available through optional premium tiers starting at $4.99/month."},
id: "5", title: "Is there a subscription fee?", content: "Basic virtual try-on is completely free. Premium features like advanced body mapping and brand partnerships are available through optional premium tiers starting at $4.99/month."
},
{
id: "6", title: "How do I get accurate measurements?", content: "Our AI automatically detects body proportions from your photo. For the most accurate results, wear fitted clothing, stand in good lighting, and ensure your entire body is visible in the frame."},
id: "6", title: "How do I get accurate measurements?", content: "Our AI automatically detects body proportions from your photo. For the most accurate results, wear fitted clothing, stand in good lighting, and ensure your entire body is visible in the frame."
},
]}
title="Frequently Asked Questions"
description="Everything you need to know about virtual try-on technology"
@@ -213,11 +197,14 @@ export default function LandingPage() {
<ContactFaq
faqs={[
{
id: "1", title: "Do I need to create an account?", content: "No account is required for basic try-ons. Create a free account to save your profile, preferences, and try-on history for a personalized experience."},
id: "1", title: "Do I need to create an account?", content: "No account is required for basic try-ons. Create a free account to save your profile, preferences, and try-on history for a personalized experience."
},
{
id: "2", title: "Can I share my virtual try-ons?", content: "Yes! Share try-on results directly with friends via social media, email, or link. Get real-time feedback before making purchase decisions."},
id: "2", title: "Can I share my virtual try-ons?", content: "Yes! Share try-on results directly with friends via social media, email, or link. Get real-time feedback before making purchase decisions."
},
{
id: "3", title: "What about different body types?", content: "Our AI is trained on diverse body types and sizes. We support measurements from XS to XXXL and continuously improve accuracy across all body shapes."},
id: "3", title: "What about different body types?", content: "Our AI is trained on diverse body types and sizes. We support measurements from XS to XXXL and continuously improve accuracy across all body shapes."
},
]}
ctaTitle="Ready to Transform Your Shopping?"
ctaDescription="Start your virtual try-on journey today. Get instant access to our AI-powered fitting technology."

View File

@@ -12,13 +12,13 @@
--background: #ffffff;
--card: #f9f9f9;
--foreground: #120a00e6;
--primary-cta: #E34400;
--foreground: #000f06e6;
--primary-cta: #0a7039;
--primary-cta-text: #ffffff;
--secondary-cta: #f9f9f9;
--secondary-cta-text: #120a00e6;
--secondary-cta-text: #000f06e6;
--accent: #e2e2e2;
--background-accent: #E34400;
--background-accent: #c4c4c4;
/* text sizing - set by ThemeProvider */
/* --text-2xs: clamp(0.465rem, 0.62vw, 0.62rem);

View File

@@ -1,193 +0,0 @@
"use client";
import { useState, useEffect } from "react";
import { ArrowLeft, Download, Share2, RotateCcw } from "lucide-react";
interface VirtualTryOnPreviewProps {
userPhoto: string | null;
clothesPhoto: string | null;
onBack: () => void;
}
export default function VirtualTryOnPreview({
userPhoto,
clothesPhoto,
onBack,
}: VirtualTryOnPreviewProps) {
const [previewImage, setPreviewImage] = useState<string | null>(null);
const [isProcessing, setIsProcessing] = useState(true);
const [selectedFit, setSelectedFit] = useState<"tight" | "normal" | "loose">("normal");
useEffect(() => {
// Simulate AI processing time
const timer = setTimeout(() => {
setIsProcessing(false);
// Create a simple composite preview
if (userPhoto && clothesPhoto) {
// In a real implementation, this would use server-side image processing
setPreviewImage(userPhoto);
}
}, 2000);
return () => clearTimeout(timer);
}, [userPhoto, clothesPhoto]);
const handleDownload = () => {
if (previewImage) {
const link = document.createElement("a");
link.href = previewImage;
link.download = "virtual-tryon-result.png";
link.click();
}
};
const handleShare = () => {
if (navigator.share && previewImage) {
navigator.share({
title: "My Virtual Try-On", text: "Check out how I look in these clothes!"});
} else {
// Fallback: copy to clipboard
const url = window.location.href;
navigator.clipboard.writeText(url);
alert("Link copied to clipboard!");
}
};
const handleFitChange = (fit: "tight" | "normal" | "loose") => {
setSelectedFit(fit);
setIsProcessing(true);
setTimeout(() => setIsProcessing(false), 1500);
};
return (
<div className="w-full">
{/* Header */}
<div className="mb-8 flex items-center justify-between">
<h2 className="text-2xl md:text-3xl font-semibold text-foreground">Your Virtual Try-On</h2>
<button
onClick={onBack}
className="flex items-center gap-2 px-4 py-2 rounded-lg border border-foreground/20 hover:border-foreground/40 hover:bg-foreground/5 transition-all text-foreground text-sm"
aria-label="Go back"
>
<ArrowLeft className="w-4 h-4" />
<span>Back</span>
</button>
</div>
{/* Main Preview Container */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Preview Image */}
<div className="lg:col-span-2">
<div className="relative w-full aspect-video rounded-xl overflow-hidden border-2 border-foreground/20 bg-gradient-to-br from-foreground/5 to-background/20">
{isProcessing ? (
<div className="absolute inset-0 flex flex-col items-center justify-center gap-4 bg-background/40 backdrop-blur-sm">
<div className="w-16 h-16 rounded-full border-4 border-foreground/20 border-t-primary-cta animate-spin"></div>
<p className="text-foreground text-center text-sm md:text-base">
Processing your virtual try-on with AI technology...
</p>
</div>
) : previewImage ? (
<>
<img
src={previewImage}
alt="Virtual try-on preview"
className="w-full h-full object-cover"
/>
<div className="absolute inset-0 bg-gradient-to-b from-transparent via-transparent to-background/10"></div>
</>
) : null}
</div>
{/* Details Below Preview */}
<div className="mt-6 grid grid-cols-2 gap-4">
<div className="p-4 rounded-lg bg-foreground/5 border border-foreground/10">
<p className="text-xs text-foreground/60 uppercase tracking-wide mb-2">Your Photo</p>
<div className="w-full aspect-square rounded-lg overflow-hidden border border-foreground/20 bg-foreground/5">
{userPhoto && (
<img
src={userPhoto}
alt="Your photo"
className="w-full h-full object-cover"
/>
)}
</div>
</div>
<div className="p-4 rounded-lg bg-foreground/5 border border-foreground/10">
<p className="text-xs text-foreground/60 uppercase tracking-wide mb-2">Clothes</p>
<div className="w-full aspect-square rounded-lg overflow-hidden border border-foreground/20 bg-foreground/5">
{clothesPhoto && (
<img
src={clothesPhoto}
alt="Clothes photo"
className="w-full h-full object-cover"
/>
)}
</div>
</div>
</div>
</div>
{/* Controls Panel */}
<div className="flex flex-col gap-6">
{/* Fit Selector */}
<div className="p-6 rounded-xl bg-foreground/5 border border-foreground/10">
<h3 className="text-sm font-semibold text-foreground mb-4 uppercase tracking-wide">
Fit Preference
</h3>
<div className="flex flex-col gap-3">
{(["tight", "normal", "loose"] as const).map((fit) => (
<button
key={fit}
onClick={() => handleFitChange(fit)}
className={`px-4 py-3 rounded-lg transition-all text-sm font-medium capitalize border-2 ${
selectedFit === fit
? "border-primary-cta bg-primary-cta/10 text-foreground"
: "border-foreground/20 bg-background text-foreground/70 hover:border-foreground/40"
}`}
>
{fit}
</button>
))}
</div>
</div>
{/* Action Buttons */}
<div className="space-y-3">
<button
onClick={handleDownload}
className="w-full px-4 py-3 rounded-lg bg-primary-cta text-background font-medium flex items-center justify-center gap-2 hover:opacity-90 transition-opacity"
aria-label="Download result"
>
<Download className="w-4 h-4" />
<span>Download</span>
</button>
<button
onClick={handleShare}
className="w-full px-4 py-3 rounded-lg bg-foreground/10 border border-foreground/20 text-foreground font-medium flex items-center justify-center gap-2 hover:border-foreground/40 hover:bg-foreground/15 transition-all"
aria-label="Share result"
>
<Share2 className="w-4 h-4" />
<span>Share</span>
</button>
<button
onClick={onBack}
className="w-full px-4 py-3 rounded-lg bg-foreground/10 border border-foreground/20 text-foreground font-medium flex items-center justify-center gap-2 hover:border-foreground/40 hover:bg-foreground/15 transition-all"
aria-label="Try again"
>
<RotateCcw className="w-4 h-4" />
<span>Try Again</span>
</button>
</div>
{/* Info Box */}
<div className="p-4 rounded-lg bg-background-accent/40 border border-foreground/10">
<p className="text-xs text-foreground/70 leading-relaxed">
<span className="font-semibold text-foreground block mb-2">Accuracy:</span>
This preview is powered by advanced AI. The actual fit may vary based on fabric properties and your exact measurements.
</p>
</div>
</div>
</div>
</div>
);
}

View File

@@ -1,136 +0,0 @@
"use client";
import { useState, useRef } from "react";
import { Upload, X } from "lucide-react";
interface VirtualTryOnUploadProps {
title: string;
description: string;
onPhotoUpload: (photo: string) => void;
uploadType: "user" | "clothes";
}
export default function VirtualTryOnUpload({
title,
description,
onPhotoUpload,
uploadType,
}: VirtualTryOnUploadProps) {
const [preview, setPreview] = useState<string | null>(null);
const [isDragging, setIsDragging] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
const handleFileSelect = (file: File) => {
if (file && file.type.startsWith("image/")) {
const reader = new FileReader();
reader.onload = (e) => {
const result = e.target?.result as string;
setPreview(result);
onPhotoUpload(result);
};
reader.readAsDataURL(file);
}
};
const handleDragOver = (e: React.DragEvent) => {
e.preventDefault();
setIsDragging(true);
};
const handleDragLeave = () => {
setIsDragging(false);
};
const handleDrop = (e: React.DragEvent) => {
e.preventDefault();
setIsDragging(false);
const files = e.dataTransfer.files;
if (files && files[0]) {
handleFileSelect(files[0]);
}
};
const handleFileInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
if (files && files[0]) {
handleFileSelect(files[0]);
}
};
const handleRemovePhoto = () => {
setPreview(null);
};
const handleClick = () => {
fileInputRef.current?.click();
};
return (
<div className="w-full">
<div className="mb-6">
<h3 className="text-xl md:text-2xl font-semibold mb-2 text-foreground">
{title}
</h3>
<p className="text-sm md:text-base text-foreground/70">{description}</p>
</div>
{!preview ? (
<div
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
onClick={handleClick}
className={`relative w-full aspect-video rounded-xl border-2 border-dashed transition-all cursor-pointer flex flex-col items-center justify-center gap-4 p-8 ${
isDragging
? "border-primary-cta bg-primary-cta/10"
: "border-foreground/20 bg-foreground/5 hover:border-foreground/40 hover:bg-foreground/10"
}`}
>
<input
ref={fileInputRef}
type="file"
accept="image/*"
onChange={handleFileInputChange}
className="hidden"
aria-label={`Upload ${uploadType} photo`}
/>
<div className="text-center">
<Upload className="w-12 h-12 md:w-16 md:h-16 mx-auto mb-4 text-primary-cta opacity-70" />
<p className="text-base md:text-lg font-medium text-foreground mb-2">
{isDragging ? "Drop your photo here" : "Drag & drop or click to upload"}
</p>
<p className="text-sm text-foreground/60">PNG, JPG, GIF up to 10MB</p>
</div>
</div>
) : (
<div className="relative w-full aspect-video rounded-xl overflow-hidden border-2 border-foreground/20 bg-foreground/5">
<img
src={preview}
alt={`${uploadType} photo preview`}
className="w-full h-full object-cover"
/>
<button
onClick={handleRemovePhoto}
className="absolute top-3 right-3 p-2 bg-background/80 hover:bg-background rounded-lg transition-colors border border-foreground/20 flex items-center justify-center"
aria-label="Remove photo"
>
<X className="w-5 h-5 text-foreground" />
</button>
<div className="absolute bottom-3 left-3 right-3 flex items-center gap-2">
<div className="flex-1 h-1 bg-foreground/20 rounded-full overflow-hidden">
<div className="h-full w-1/2 bg-primary-cta rounded-full"></div>
</div>
<span className="text-xs font-medium text-foreground/70">Processing...</span>
</div>
</div>
)}
<div className="mt-4 p-4 bg-background-accent/40 rounded-lg border border-foreground/10">
<p className="text-xs md:text-sm text-foreground/70">
<span className="font-semibold text-foreground">Pro tip:</span> For best results, ensure good
lighting, wear fitted clothes, and stand in a neutral pose.
</p>
</div>
</div>
);
}