list partially done. UI changes needed, UX is good
This commit is contained in:
@@ -9,12 +9,13 @@ import Footer from "@/components/landing/footer";
|
||||
import SearchBy from "@/components/search-results/search";
|
||||
import Results from "@/components/search-results/results";
|
||||
import Features from "@/components/details/features";
|
||||
import List from "@/components/list-property/list";
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<Navigation />
|
||||
<Features />
|
||||
<List />
|
||||
<Footer />
|
||||
</div>
|
||||
</>
|
||||
|
||||
587
src/components/list-property/list.tsx
Normal file
587
src/components/list-property/list.tsx
Normal file
@@ -0,0 +1,587 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useRef } from "react";
|
||||
import localFont from "next/font/local";
|
||||
import gsap from "gsap";
|
||||
import { useGSAP } from "@gsap/react";
|
||||
import {
|
||||
House,
|
||||
Buildings,
|
||||
Farm,
|
||||
Bed,
|
||||
MapPin,
|
||||
Camera,
|
||||
WifiHigh,
|
||||
Article,
|
||||
CurrencyDollar,
|
||||
CheckCircle,
|
||||
CalendarBlank,
|
||||
ShieldCheck,
|
||||
CaretLeft,
|
||||
CaretRight
|
||||
} from "@phosphor-icons/react";
|
||||
|
||||
const figtree = localFont({
|
||||
src: [
|
||||
{
|
||||
path: '../../../public/Fonts/figtree/figtree.ttf',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// Shared styles
|
||||
const containerStyle = `flex flex-col gap-6 w-full max-w-xl mx-auto`;
|
||||
const titleStyle = `${figtree.className} text-3xl font-bold mb-4`;
|
||||
const inputStyle = `${figtree.className} w-full p-4 border-2 border-black text-lg outline-none focus:bg-gray-50 transition-colors`;
|
||||
const buttonStyle = `${figtree.className} flex items-center justify-center gap-2 px-8 py-3 border-2 border-black bg-[#E7FE78] text-lg font-medium hover:bg-[#dcfc4e] transition-colors disabled:opacity-50 disabled:cursor-not-allowed`;
|
||||
const secondaryButtonStyle = `${figtree.className} flex items-center justify-center gap-2 px-8 py-3 border-2 border-black bg-white text-lg font-medium hover:bg-gray-50 transition-colors`;
|
||||
const optionCardStyle = (selected: boolean) =>
|
||||
`flex flex-col items-center justify-center gap-3 p-6 border-2 border-black cursor-pointer transition-all hover:bg-gray-50 ${selected ? 'bg-[#E7FE78]' : 'bg-white'}`;
|
||||
|
||||
interface FormData {
|
||||
propertyType?: string;
|
||||
placeType?: string;
|
||||
location?: string;
|
||||
guests?: number;
|
||||
bedrooms?: number;
|
||||
beds?: number;
|
||||
bathrooms?: number;
|
||||
amenities?: string[];
|
||||
description?: string;
|
||||
price?: string;
|
||||
instantBook?: boolean;
|
||||
safety?: string[];
|
||||
}
|
||||
|
||||
type FormValue = string | number | boolean | string[] | undefined;
|
||||
|
||||
interface StepProps {
|
||||
onNext: () => void;
|
||||
onBack: () => void;
|
||||
data: FormData;
|
||||
updateData: (key: keyof FormData, value: FormValue) => void;
|
||||
}
|
||||
|
||||
/* Property Type */
|
||||
const PropertyType = ({ onNext, data, updateData }: StepProps) => {
|
||||
const types = [
|
||||
{ id: 'house', label: 'House', icon: House },
|
||||
{ id: 'flat', label: 'Flat', icon: Buildings },
|
||||
{ id: 'farmhouse', label: 'Farmhouse', icon: Farm },
|
||||
{ id: 'guesthouse', label: 'Guesthouse', icon: Bed },
|
||||
];
|
||||
|
||||
const handleSelect = (id: string) => {
|
||||
updateData('propertyType', id);
|
||||
onNext();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<h2 className={titleStyle}>What kind of place will you host?</h2>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{types.map((type) => (
|
||||
<button
|
||||
key={type.id}
|
||||
type="button"
|
||||
onClick={() => handleSelect(type.id)}
|
||||
className={optionCardStyle(data.propertyType === type.id)}
|
||||
>
|
||||
<type.icon size={48} weight="light" />
|
||||
<span className={`${figtree.className} text-xl font-medium`}>{type.label}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/* Property Place Type */
|
||||
const PropertyPlaceType = ({ onNext, onBack, data, updateData }: StepProps) => {
|
||||
const places = [
|
||||
{ id: 'entire', label: 'An entire place', description: 'Guests have the whole place to themselves.' },
|
||||
{ id: 'room', label: 'A room', description: 'Guests have their own room in a home, plus access to shared spaces.' },
|
||||
{ id: 'shared', label: 'A shared room', description: 'Guests sleep in a room or common area that may be shared with others.' },
|
||||
];
|
||||
|
||||
const handleSelect = (id: string) => {
|
||||
updateData('placeType', id);
|
||||
onNext();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<h2 className={titleStyle}>What type of place will guests have?</h2>
|
||||
<div className="flex flex-col gap-4">
|
||||
{places.map((place) => (
|
||||
<button
|
||||
key={place.id}
|
||||
type="button"
|
||||
onClick={() => handleSelect(place.id)}
|
||||
className={`${optionCardStyle(data.placeType === place.id)} flex-row justify-between text-left items-center w-full`}
|
||||
>
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className={`${figtree.className} text-xl font-bold`}>{place.label}</span>
|
||||
<span className={`${figtree.className} text-gray-600`}>{place.description}</span>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-start mt-4">
|
||||
<button type="button" onClick={onBack} className={secondaryButtonStyle}>
|
||||
<CaretLeft size={20} /> Back
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/* Property Location */
|
||||
const PropertyLocation = ({ onNext, onBack, data, updateData }: StepProps) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<h2 className={titleStyle}>Where's your place located?</h2>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="relative">
|
||||
<MapPin size={24} className="absolute left-4 top-1/2 -translate-y-1/2" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter your address"
|
||||
className={`${inputStyle} pl-12`}
|
||||
value={data.location || ''}
|
||||
onChange={(e) => updateData('location', e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
{/* Placeholder for map */}
|
||||
<div className="w-full h-64 bg-gray-100 border-2 border-black flex items-center justify-center">
|
||||
<span className={`${figtree.className} text-gray-500`}>Map Preview</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between mt-4">
|
||||
<button type="button" onClick={onBack} className={secondaryButtonStyle}>
|
||||
<CaretLeft size={20} /> Back
|
||||
</button>
|
||||
<button type="button" onClick={() => onNext()} className={buttonStyle}>
|
||||
Next <CaretRight size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/* Property Capacity */
|
||||
const PropertyCapacity = ({ onNext, onBack, data, updateData }: StepProps) => {
|
||||
const counters: { key: keyof FormData; label: string }[] = [
|
||||
{ key: 'guests', label: 'Guests' },
|
||||
{ key: 'bedrooms', label: 'Bedrooms' },
|
||||
{ key: 'beds', label: 'Beds' },
|
||||
{ key: 'bathrooms', label: 'Bathrooms' },
|
||||
];
|
||||
|
||||
const updateCount = (key: keyof FormData, delta: number) => {
|
||||
const current = (data[key] as number) || 0;
|
||||
updateData(key, Math.max(0, current + delta));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<h2 className={titleStyle}>Share some basics about your place</h2>
|
||||
<div className="flex flex-col gap-6">
|
||||
{counters.map((item) => (
|
||||
<div key={item.key} className="flex items-center justify-between border-b-2 border-gray-100 pb-4">
|
||||
<span className={`${figtree.className} text-xl`}>{item.label}</span>
|
||||
<div className="flex items-center gap-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => updateCount(item.key, -1)}
|
||||
className="w-10 h-10 rounded-full border-2 border-black flex items-center justify-center hover:bg-gray-100"
|
||||
>
|
||||
-
|
||||
</button>
|
||||
<span className={`${figtree.className} text-xl w-8 text-center`}>{data[item.key] || 0}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => updateCount(item.key, 1)}
|
||||
className="w-10 h-10 rounded-full border-2 border-black flex items-center justify-center hover:bg-gray-100"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-between mt-4">
|
||||
<button type="button" onClick={onBack} className={secondaryButtonStyle}>
|
||||
<CaretLeft size={20} /> Back
|
||||
</button>
|
||||
<button type="button" onClick={() => onNext()} className={buttonStyle}>
|
||||
Next <CaretRight size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/* Property Photos */
|
||||
const PropertyPhotos = ({ onNext, onBack }: StepProps) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<h2 className={titleStyle}>Add some photos of your house</h2>
|
||||
<div className="border-2 border-dashed border-black p-12 flex flex-col items-center justify-center gap-4 bg-gray-50 cursor-pointer hover:bg-gray-100 transition-colors">
|
||||
<Camera size={48} />
|
||||
<div className="text-center">
|
||||
<p className={`${figtree.className} text-xl font-bold`}>Drag your photos here</p>
|
||||
<p className={`${figtree.className} text-gray-500`}>Choose at least 5 photos</p>
|
||||
</div>
|
||||
<button type="button" className="underline font-medium">Upload from your device</button>
|
||||
</div>
|
||||
<div className="flex justify-between mt-4">
|
||||
<button type="button" onClick={onBack} className={secondaryButtonStyle}>
|
||||
<CaretLeft size={20} /> Back
|
||||
</button>
|
||||
<button type="button" onClick={() => onNext()} className={buttonStyle}>
|
||||
Next <CaretRight size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/* Property Amenities */
|
||||
const PropertyAmenities = ({ onNext, onBack, data, updateData }: StepProps) => {
|
||||
const amenities = [
|
||||
{ id: 'wifi', label: 'Wi-Fi', icon: WifiHigh },
|
||||
{ id: 'kitchen', label: 'Kitchen', icon: House },
|
||||
{ id: 'parking', label: 'Free parking', icon: Farm },
|
||||
{ id: 'pool', label: 'Pool', icon: Buildings },
|
||||
];
|
||||
|
||||
const toggleAmenity = (id: string) => {
|
||||
const current = data.amenities || [];
|
||||
const updated = current.includes(id)
|
||||
? current.filter((item: string) => item !== id)
|
||||
: [...current, id];
|
||||
updateData('amenities', updated);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<h2 className={titleStyle}>What does your place offer?</h2>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{amenities.map((amenity) => (
|
||||
<button
|
||||
key={amenity.id}
|
||||
type="button"
|
||||
onClick={() => toggleAmenity(amenity.id)}
|
||||
className={`${optionCardStyle((data.amenities || []).includes(amenity.id))} items-start w-full`}
|
||||
>
|
||||
<amenity.icon size={32} />
|
||||
<span className={`${figtree.className} text-lg font-medium`}>{amenity.label}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-between mt-4">
|
||||
<button type="button" onClick={onBack} className={secondaryButtonStyle}>
|
||||
<CaretLeft size={20} /> Back
|
||||
</button>
|
||||
<button type="button" onClick={() => onNext()} className={buttonStyle}>
|
||||
Next <CaretRight size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/* Property Description */
|
||||
const PropertyDescription = ({ onNext, onBack, data, updateData }: StepProps) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<h2 className={titleStyle}>How would you describe your place?</h2>
|
||||
<div className="flex flex-col gap-4">
|
||||
<textarea
|
||||
placeholder="This unique place has a style all its own..."
|
||||
className={`${inputStyle} h-48 resize-none`}
|
||||
value={data.description || ''}
|
||||
onChange={(e) => updateData('description', e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-between mt-4">
|
||||
<button type="button" onClick={onBack} className={secondaryButtonStyle}>
|
||||
<CaretLeft size={20} /> Back
|
||||
</button>
|
||||
<button type="button" onClick={() => onNext()} className={buttonStyle}>
|
||||
Next <CaretRight size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/* Property Price */
|
||||
const PropertyPrice = ({ onNext, onBack, data, updateData }: StepProps) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<h2 className={titleStyle}>Now, set your price</h2>
|
||||
<div className="flex flex-col gap-4 items-center">
|
||||
<div className="relative w-full max-w-xs">
|
||||
<CurrencyDollar size={32} className="absolute left-4 top-1/2 -translate-y-1/2" />
|
||||
<input
|
||||
type="number"
|
||||
placeholder="0"
|
||||
className={`${inputStyle} pl-14 text-4xl font-bold text-center`}
|
||||
value={data.price || ''}
|
||||
onChange={(e) => updateData('price', e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<p className={`${figtree.className} text-gray-500`}>per night</p>
|
||||
</div>
|
||||
<div className="flex justify-between mt-4">
|
||||
<button type="button" onClick={onBack} className={secondaryButtonStyle}>
|
||||
<CaretLeft size={20} /> Back
|
||||
</button>
|
||||
<button type="button" onClick={() => onNext()} className={buttonStyle}>
|
||||
Next <CaretRight size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/* Property Instant Approval */
|
||||
const PropertyInstantApproval = ({ onNext, onBack, data, updateData }: StepProps) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<h2 className={titleStyle}>Decide how you'll confirm reservations</h2>
|
||||
<div className="flex flex-col gap-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => updateData('instantBook', true)}
|
||||
className={`${optionCardStyle(data.instantBook === true)} w-full`}
|
||||
>
|
||||
<div className="flex items-center gap-4 w-full">
|
||||
<CheckCircle size={32} />
|
||||
<div className="flex flex-col text-left">
|
||||
<span className="font-bold text-lg">Use Instant Book</span>
|
||||
<span className="text-gray-600">Guests can book automatically.</span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => updateData('instantBook', false)}
|
||||
className={`${optionCardStyle(data.instantBook === false)} w-full`}
|
||||
>
|
||||
<div className="flex items-center gap-4 w-full">
|
||||
<Article size={32} />
|
||||
<div className="flex flex-col text-left">
|
||||
<span className="font-bold text-lg">Approve manually</span>
|
||||
<span className="text-gray-600">You approve or decline booking requests.</span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex justify-between mt-4">
|
||||
<button type="button" onClick={onBack} className={secondaryButtonStyle}>
|
||||
<CaretLeft size={20} /> Back
|
||||
</button>
|
||||
<button type="button" onClick={() => onNext()} className={buttonStyle}>
|
||||
Next <CaretRight size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/* Availability Calendar */
|
||||
const AvailabilityCalendar = ({ onNext, onBack }: StepProps) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<h2 className={titleStyle}>When is your place available?</h2>
|
||||
<div className="flex flex-col items-center justify-center h-64 border-2 border-black bg-gray-50">
|
||||
<CalendarBlank size={48} className="text-gray-400 mb-2" />
|
||||
<p className={`${figtree.className} text-gray-500`}>Calendar Component Placeholder</p>
|
||||
</div>
|
||||
<div className="flex justify-between mt-4">
|
||||
<button type="button" onClick={onBack} className={secondaryButtonStyle}>
|
||||
<CaretLeft size={20} /> Back
|
||||
</button>
|
||||
<button type="button" onClick={() => onNext()} className={buttonStyle}>
|
||||
Next <CaretRight size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/* Safety Details */
|
||||
const SafetyDetails = ({ onNext, onBack, data, updateData }: StepProps) => {
|
||||
const safetyItems = [
|
||||
{ id: 'camera', label: 'Security camera(s)', icon: Camera },
|
||||
{ id: 'weapons', label: 'Weapons', icon: ShieldCheck },
|
||||
{ id: 'animals', label: 'Dangerous animals', icon: Farm },
|
||||
];
|
||||
|
||||
const toggleSafety = (id: string) => {
|
||||
const current = data.safety || [];
|
||||
const updated = current.includes(id)
|
||||
? current.filter((item: string) => item !== id)
|
||||
: [...current, id];
|
||||
updateData('safety', updated);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<h2 className={titleStyle}>Does your place have any of these?</h2>
|
||||
<div className="flex flex-col gap-4">
|
||||
{safetyItems.map((item) => (
|
||||
<button
|
||||
key={item.id}
|
||||
type="button"
|
||||
onClick={() => toggleSafety(item.id)}
|
||||
className={`${optionCardStyle((data.safety || []).includes(item.id))} flex-row justify-between items-center w-full`}
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<item.icon size={32} />
|
||||
<span className={`${figtree.className} text-lg font-medium`}>{item.label}</span>
|
||||
</div>
|
||||
<div className={`w-6 h-6 rounded-full border-2 border-black ${(data.safety || []).includes(item.id) ? 'bg-black' : 'bg-transparent'}`} />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-between mt-4">
|
||||
<button type="button" onClick={onBack} className={secondaryButtonStyle}>
|
||||
<CaretLeft size={20} /> Back
|
||||
</button>
|
||||
<button type="button" onClick={() => { }} className={buttonStyle}>
|
||||
Finish <CheckCircle size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function List() {
|
||||
const [step, setStep] = useState(0);
|
||||
const [direction, setDirection] = useState(1); // 1 for next, -1 for back
|
||||
const [formData, setFormData] = useState<FormData>({});
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const steps = [
|
||||
PropertyType,
|
||||
PropertyPlaceType,
|
||||
PropertyLocation,
|
||||
PropertyCapacity,
|
||||
PropertyPhotos,
|
||||
PropertyAmenities,
|
||||
PropertyDescription,
|
||||
PropertyPrice,
|
||||
PropertyInstantApproval,
|
||||
AvailabilityCalendar,
|
||||
SafetyDetails
|
||||
];
|
||||
|
||||
const CurrentStepComponent = steps[step];
|
||||
|
||||
const updateData = (key: keyof FormData, value: FormValue) => {
|
||||
setFormData(prev => ({ ...prev, [key]: value }));
|
||||
};
|
||||
|
||||
const handleNext = () => {
|
||||
if (step < steps.length - 1) {
|
||||
setDirection(1);
|
||||
setStep(prev => prev + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
if (step > 0) {
|
||||
setDirection(-1);
|
||||
setStep(prev => prev - 1);
|
||||
}
|
||||
};
|
||||
|
||||
useGSAP(() => {
|
||||
if (!contentRef.current) return;
|
||||
|
||||
// Animate the content sliding in
|
||||
gsap.fromTo(contentRef.current,
|
||||
{
|
||||
x: direction * 50,
|
||||
opacity: 0
|
||||
},
|
||||
{
|
||||
x: 0,
|
||||
opacity: 1,
|
||||
duration: 0.4,
|
||||
ease: "power2.out"
|
||||
}
|
||||
);
|
||||
}, [step]);
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen w-full bg-white overflow-hidden">
|
||||
{/* Left Panel - Form */}
|
||||
<div className="w-full lg:w-1/2 flex flex-col justify-between p-8 md:p-12 overflow-y-auto relative h-screen">
|
||||
{/* Progress Bar - Top */}
|
||||
<div className="w-full max-w-xl mx-auto mb-8">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-8 h-8 bg-black text-white rounded-full flex items-center justify-center font-bold text-sm">
|
||||
{step + 1}
|
||||
</div>
|
||||
<span className={`${figtree.className} font-bold text-sm uppercase tracking-wider`}>Step {step + 1} of {steps.length}</span>
|
||||
</div>
|
||||
<button className="text-sm font-bold underline decoration-2 underline-offset-4 hover:text-gray-600">Exit</button>
|
||||
</div>
|
||||
<div className="h-1 w-full bg-gray-100 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full bg-black transition-all duration-500 ease-out"
|
||||
style={{ width: `${((step + 1) / steps.length) * 100}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex-1 flex flex-col justify-center py-8">
|
||||
<div ref={containerRef} className={containerStyle}>
|
||||
<div ref={contentRef}>
|
||||
<CurrentStepComponent
|
||||
onNext={handleNext}
|
||||
onBack={handleBack}
|
||||
data={formData}
|
||||
updateData={updateData}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Panel - Visual */}
|
||||
<div className="hidden lg:flex w-1/2 bg-[#F7F7F7] items-center justify-center relative overflow-hidden h-screen border-l-2 border-black">
|
||||
{/* Gradient Background */}
|
||||
<div className="absolute inset-0 bg-[#E7FE78]" />
|
||||
<div className="absolute inset-0 opacity-20"
|
||||
style={{
|
||||
backgroundImage: `radial-gradient(circle at 2px 2px, black 1px, transparent 0)`,
|
||||
backgroundSize: '32px 32px'
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Decorative Content */}
|
||||
<div className="relative z-10 p-16 max-w-2xl">
|
||||
<div className="bg-white border-2 border-black p-8 shadow-[8px_8px_0px_0px_rgba(0,0,0,1)] mb-8 rotate-1 hover:rotate-0 transition-transform duration-500">
|
||||
<h1 className={`${figtree.className} text-5xl font-bold mb-6 leading-tight`}>
|
||||
Open your door<br />to hosting
|
||||
</h1>
|
||||
<p className={`${figtree.className} text-xl text-gray-800 leading-relaxed`}>
|
||||
Earn money, reach millions of travelers, and find your freedom. It's easy to get started.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default List;
|
||||
Reference in New Issue
Block a user