Яхта, доработки

This commit is contained in:
Sergey Bolshakov 2025-12-12 20:48:52 +03:00
parent d5e466b879
commit ec00216b93
12 changed files with 267 additions and 199 deletions

BIN
public/images/avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -0,0 +1,11 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_0_6016" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="32" height="32">
<path d="M32 0H0V32H32V0Z" fill="white"/>
</mask>
<g mask="url(#mask0_0_6016)">
<path d="M20.3996 6.30371C18.7042 6.30371 17.1601 6.95075 16 8.01102C14.8399 6.95075 13.2958 6.30371 11.6005 6.30371C7.99768 6.30371 5.07715 9.22424 5.07715 12.827C5.07715 14.9028 5.79843 16.6222 7.16376 18.2532C8.5291 19.8841 15.9958 25.697 15.9958 25.697C15.9958 25.697 23.5087 19.9101 24.8438 18.2145C26.1274 16.5842 26.9229 14.9153 26.9229 12.827C26.9229 9.22424 24.0024 6.30371 20.3996 6.30371Z" fill="white"/>
<path d="M20.3996 6.30371C18.7042 6.30371 17.1601 6.95075 16 8.01102C14.8399 6.95075 13.2958 6.30371 11.6005 6.30371C7.99768 6.30371 5.07715 9.22424 5.07715 12.827C5.07715 14.9028 5.79843 16.6222 7.16376 18.2532C8.5291 19.8841 15.9958 25.697 15.9958 25.697C15.9958 25.697 23.5087 19.9101 24.8438 18.2145C26.1274 16.5842 26.9229 14.9153 26.9229 12.827C26.9229 9.22424 24.0024 6.30371 20.3996 6.30371Z" stroke="white" stroke-width="5.12"/>
<path d="M20.3996 6.30371C18.7042 6.30371 17.1601 6.95075 16 8.01102C14.8399 6.95075 13.2958 6.30371 11.6005 6.30371C7.99768 6.30371 5.07715 9.22424 5.07715 12.827C5.07715 14.9028 5.79843 16.6222 7.16376 18.2532C8.5291 19.8841 15.9958 25.697 15.9958 25.697C15.9958 25.697 23.5087 19.9101 24.8438 18.2145C26.1274 16.5842 26.9229 14.9153 26.9229 12.827C26.9229 9.22424 24.0024 6.30371 20.3996 6.30371Z" fill="white"/>
<path d="M20.3996 6.30371C18.7042 6.30371 17.1601 6.95075 16 8.01102C14.8399 6.95075 13.2958 6.30371 11.6005 6.30371C7.99768 6.30371 5.07715 9.22424 5.07715 12.827C5.07715 14.9028 5.79843 16.6222 7.16376 18.2532C8.5291 19.8841 15.9958 25.697 15.9958 25.697C15.9958 25.697 23.5087 19.9101 24.8438 18.2145C26.1274 16.5842 26.9229 14.9153 26.9229 12.827C26.9229 9.22424 24.0024 6.30371 20.3996 6.30371Z" stroke="#0072A8" stroke-width="1.70667"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,4 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 4C14.7743 3.99987 13.5606 4.24118 12.4281 4.71015C11.2957 5.17911 10.2667 5.86656 9.39994 6.73322C8.53319 7.59988 7.84563 8.62879 7.37654 9.76118C6.90745 10.8936 6.66602 12.1073 6.66602 13.333C6.66602 18.667 12.666 24 15.999 27.333C19.333 24 25.333 18.488 25.333 13.333C25.333 12.1073 25.0916 10.8936 24.6225 9.76118C24.1534 8.62879 23.4658 7.59988 22.5991 6.73322C21.7323 5.86656 20.7034 5.17911 19.5709 4.71015C18.4385 4.24118 17.2257 3.99987 16 4Z" stroke="#0072A8" stroke-width="2"/>
<path d="M16.001 16C17.4739 16 18.668 14.806 18.668 13.333C18.668 11.8601 17.4739 10.666 16.001 10.666C14.528 10.666 13.334 11.8601 13.334 13.333C13.334 14.806 14.528 16 16.001 16Z" fill="#0072A8"/>
</svg>

After

Width:  |  Height:  |  Size: 803 B

View File

@ -0,0 +1,10 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_0_5837)">
<path d="M8.00005 0L9.88096 5.41115L15.6085 5.52787L11.0434 8.98885L12.7023 14.4721L8.00005 11.2L3.29777 14.4721L4.95667 8.98885L0.391602 5.52787L6.11915 5.41115L8.00005 0Z" fill="#FFAA2B"/>
</g>
<defs>
<clipPath id="clip0_0_5837">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 434 B

View File

@ -0,0 +1,6 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.5 11C22.8807 11 24 9.88071 24 8.5C24 7.11929 22.8807 6 21.5 6C20.1193 6 19 7.11929 19 8.5C19 9.88071 20.1193 11 21.5 11Z" stroke="#0072A8" stroke-width="2"/>
<path d="M10.5 19C9.11929 19 8 17.8807 8 16.5C8 15.1193 9.11929 14 10.5 14C11.8807 14 13 15.1193 13 16.5C13 17.8807 11.8807 19 10.5 19Z" stroke="#0072A8" stroke-width="2"/>
<path d="M21.5 26C22.8807 26 24 24.8807 24 23.5C24 22.1193 22.8807 21 21.5 21C20.1193 21 19 22.1193 19 23.5C19 24.8807 20.1193 26 21.5 26Z" stroke="#0072A8" stroke-width="2"/>
<path d="M12.5 15L20 10M20 23L12.5 18" stroke="#0072A8" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 698 B

View File

@ -4,15 +4,14 @@ import { useState } from "react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { DatePicker } from "@/components/ui/date-picker"; import { DatePicker } from "@/components/ui/date-picker";
import { GuestPicker } from "@/components/form/guest-picker"; import { GuestPicker } from "@/components/form/guest-picker";
import Icon from "@/components/ui/icon";
interface BookingWidgetProps { interface BookingWidgetProps {
price: string; price: string;
} }
export function BookingWidget({ price }: BookingWidgetProps) { export function BookingWidget({ price }: BookingWidgetProps) {
const [departureDate, setDepartureDate] = useState<Date | undefined>(); const [departureDate] = useState<Date | undefined>();
const [arrivalDate, setArrivalDate] = useState<Date | undefined>(); const [arrivalDate] = useState<Date | undefined>();
const [guests, setGuests] = useState({ adults: 1, children: 0 }); const [guests, setGuests] = useState({ adults: 1, children: 0 });
const [total] = useState(0); const [total] = useState(0);
@ -30,10 +29,13 @@ export function BookingWidget({ price }: BookingWidgetProps) {
}; };
return ( return (
<div className="bg-white border border-gray-200 rounded-lg p-6 sticky top-24"> <div className="bg-white border border-gray-200 rounded-lg p-6">
<div className="mb-6"> <div className="mb-6">
<p className="text-2xl font-bold text-[#333333] mb-2"> <p className="text-2xl font-bold text-[#333333] mb-2">
от {price} р/час от {price} {" "}
<span className="text-base font-normal text-[#999999]">
/час
</span>
</p> </p>
</div> </div>
@ -85,15 +87,12 @@ export function BookingWidget({ price }: BookingWidgetProps) {
<div className="pt-4 border-t border-gray-200"> <div className="pt-4 border-t border-gray-200">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<span className="text-base font-semibold text-[#333333]"> <span className="text-base text-[#333333]">Итого:</span>
Итого: <span className="text-base font-bold text-[#333333]">
</span> {total}
<span className="text-xl font-bold text-[#333333]">
{total} Р
</span> </span>
</div> </div>
</div> </div>
</div> </div>
); );
} }

View File

@ -14,64 +14,57 @@ interface ContactInfoProps {
}; };
} }
export function ContactInfo({ export function ContactInfo({ contactPerson, requisites }: ContactInfoProps) {
contactPerson,
requisites,
}: ContactInfoProps) {
return ( return (
<div className="space-y-6"> <div className="flex flex-col sm:flex-row gap-5">
<div className="flex flex-col sm:flex-row gap-6"> <div className="flex-1 rounded-[24px] px-6 py-5 bg-[#f4f4f4]">
<div className="flex items-start gap-4"> <div className="flex items-center gap-4 h-full">
<div className="relative w-16 h-16 rounded-full overflow-hidden bg-gray-200 flex items-center justify-center"> <div className="relative rounded-full overflow-hidden bg-gray-200 flex items-center justify-center">
<Image <Image
src={contactPerson.avatar} src="/images/avatar.png"
alt={contactPerson.name} alt={contactPerson.name}
width={64} width={124}
height={64} height={124}
className="object-cover"
/> />
</div> </div>
<div> <div className="flex flex-col justify-between h-full">
<h3 className="text-base font-semibold text-[#333333] mb-1"> <h3 className="text-base font-bold text-[#333333]">
Контактное лицо {contactPerson.name}
</h3> </h3>
<p className="text-base text-[#333333]"> <p className="text-base text-[#333333]">
{contactPerson.name} Контактное лицо
</p> </p>
</div> </div>
</div> </div>
</div>
<div className="flex-1"> <div className="flex-1 rounded-[24px] px-6 py-5 bg-[#f4f4f4]">
<h3 className="text-base font-semibold text-[#333333] mb-3"> <h3 className="text-base font-bold text-[#333333] mb-3">
Реквизиты Реквизиты
</h3> </h3>
<div className="space-y-2"> <div className="space-y-2">
<div className="flex flex-col sm:flex-row sm:justify-between gap-1"> <div className="flex flex-col sm:flex-row sm:justify-between gap-1">
<span className="text-sm text-[#999999]">ИП:</span> <span className="text-base text-[#333333]">ИП</span>
<span className="text-sm text-[#333333]"> <span className="text-base text-[#999999]">
{requisites.ip} {requisites.ip}
</span> </span>
</div> </div>
<div className="flex flex-col sm:flex-row sm:justify-between gap-1"> <div className="flex flex-col sm:flex-row sm:justify-between gap-1">
<span className="text-sm text-[#999999]">ИНН:</span> <span className="text-base text-[#333333]">ИНН</span>
<span className="text-sm text-[#333333]"> <span className="text-base text-[#999999]">
{requisites.inn} {requisites.inn}
</span> </span>
</div> </div>
<div className="flex flex-col sm:flex-row sm:justify-between gap-1"> <div className="flex flex-col sm:flex-row sm:justify-between gap-1">
<span className="text-sm text-[#999999]"> <span className="text-base text-[#333333]">
ОГРН/ОГРНИП: ОГРН/ОГРНИП
</span> </span>
<span className="text-sm text-[#333333]"> <span className="text-base text-[#999999]">
{requisites.ogrn} {requisites.ogrn}
</span> </span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
); );
} }

View File

@ -2,38 +2,24 @@
import { useState } from "react"; import { useState } from "react";
import { Calendar } from "@/components/ui/calendar"; import { Calendar } from "@/components/ui/calendar";
import { format } from "date-fns"; import { isSameMonth, isBefore, startOfDay, format } from "date-fns";
import { ru } from "date-fns/locale"; import { ru } from "date-fns/locale";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
import Icon from "@/components/ui/icon";
interface YachtAvailabilityProps { interface YachtAvailabilityProps {
price: string; price: string;
} }
export function YachtAvailability({ price }: YachtAvailabilityProps) { export function YachtAvailability({ price }: YachtAvailabilityProps) {
const [currentMonth, setCurrentMonth] = useState(new Date(2025, 3, 1)); // Апрель 2025 const today = startOfDay(new Date());
const [currentMonth, setCurrentMonth] = useState(
// Генерируем доступные даты (27, 28, 29 апреля доступны) new Date(today.getFullYear(), today.getMonth(), 1)
const availableDates = [ );
new Date(2025, 3, 27),
new Date(2025, 3, 28),
new Date(2025, 3, 29),
];
const unavailableDates = Array.from({ length: 26 }, (_, i) => { const unavailableDates = Array.from({ length: 26 }, (_, i) => {
return new Date(2025, 3, i + 1); return new Date(2025, 3, i + 1);
}); });
const isDateAvailable = (date: Date) => {
return availableDates.some(
(d) =>
d.getDate() === date.getDate() &&
d.getMonth() === date.getMonth() &&
d.getFullYear() === date.getFullYear()
);
};
const isDateUnavailable = (date: Date) => { const isDateUnavailable = (date: Date) => {
return unavailableDates.some( return unavailableDates.some(
(d) => (d) =>
@ -43,101 +29,135 @@ export function YachtAvailability({ price }: YachtAvailabilityProps) {
); );
}; };
const handlePreviousMonth = () => { const isDateInPast = (date: Date) => {
return isBefore(startOfDay(date), today);
};
const shouldBeCrossedOut = (date: Date) => {
// Перечеркиваем если день занят или находится до текущего дня
return isDateUnavailable(date) || isDateInPast(date);
};
const goToPreviousMonth = () => {
setCurrentMonth( setCurrentMonth(
new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1) new Date(
currentMonth.getFullYear(),
currentMonth.getMonth() - 1,
1
)
); );
}; };
const handleNextMonth = () => { const goToNextMonth = () => {
setCurrentMonth( setCurrentMonth(
new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1) new Date(
currentMonth.getFullYear(),
currentMonth.getMonth() + 1,
1
)
); );
}; };
return ( return (
<div className="space-y-4"> <div className="space-y-4 w-full">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<h2 className="text-xl font-bold text-[#333333]"> <h2 className="text-base font-bold text-[#333333]">
Доступность яхты Доступность яхты
</h2> </h2>
<div className="flex items-center gap-2 text-sm text-[#999999]">
<Icon name="calendar" size={16} />
<span>По местному времени яхты</span>
</div>
</div> </div>
<div className="bg-white border border-gray-200 rounded-lg p-4"> <div className="bg-white w-full">
<div className="flex items-center justify-between mb-4"> <div className="w-full flex justify-end mb-8">
<div className="flex items-center gap-5">
<button <button
onClick={handlePreviousMonth} onClick={goToPreviousMonth}
className="p-2 hover:bg-gray-100 rounded-md transition-colors" className="cursor-pointer rounded-full border border-[#dfdfdf] h-12 w-12 flex items-center justify-center"
> >
<ChevronLeft className="w-5 h-5 text-gray-600" /> <ChevronLeftIcon className="size-4" />
</button> </button>
<h3 className="text-lg font-semibold text-[#333333] capitalize"> <span className="text-2xl text-[#333333]">
{format(currentMonth, "LLLL yyyy", { locale: ru })} {format(currentMonth, "LLLL yyyy", { locale: ru })}
</h3> </span>
<button <button
onClick={handleNextMonth} onClick={goToNextMonth}
className="p-2 hover:bg-gray-100 rounded-md transition-colors" className="cursor-pointer rounded-full border border-[#dfdfdf] h-12 w-12 flex items-center justify-center"
> >
<ChevronRight className="w-5 h-5 text-gray-600" /> <ChevronRightIcon className="size-4" />
</button> </button>
</div> </div>
</div>
<Calendar <Calendar
mode="single" mode="single"
month={currentMonth} month={currentMonth}
onMonthChange={setCurrentMonth} onMonthChange={setCurrentMonth}
className="w-full" showOutsideDays={false}
className="w-full p-0"
locale={ru} locale={ru}
classNames={{ classNames={{
root: "w-full", root: "w-full",
month: "flex w-full flex-col gap-4", month: "flex w-full flex-col gap-4",
month_caption: nav: "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-2",
"flex h-8 w-full items-center justify-center px-8 text-gray-700 font-semibold", month_caption: "hidden",
caption_label: "text-2xl",
button_previous: "hidden",
button_next: "hidden",
table: "w-full border-collapse", table: "w-full border-collapse",
weekdays: "flex", weekdays: "hidden",
weekday: weekday:
"flex-1 text-gray-500 text-xs font-normal p-2 text-center", "flex-1 text-gray-500 text-xs font-normal p-2 text-center",
week: "mt-2 flex w-full", week: "flex w-full",
day: "relative", day: "relative flex-1",
}} }}
components={{ components={{
DayButton: ({ day, ...props }) => { DayButton: ({ day, ...props }) => {
const isAvailable = isDateAvailable(day.date); // Показываем только дни текущего месяца
const isUnavailable = isDateUnavailable(day.date); if (!isSameMonth(day.date, currentMonth)) {
const isDay30 = day.date.getDate() === 30; return <div className="hidden" />;
}
const isCrossedOut = shouldBeCrossedOut(day.date);
return ( return (
<button <button
{...props} {...props}
className={`relative w-full h-16 flex flex-col items-center justify-center rounded-md transition-colors ${ className="relative w-full h-20 flex flex-col items-start justify-start px-2 py-[2px] border border-gray-200"
isAvailable disabled={isCrossedOut}
? "bg-[#008299] text-white hover:bg-[#008299]"
: isUnavailable || isDay30
? "text-gray-400 cursor-not-allowed bg-gray-100"
: "hover:bg-gray-100"
}`}
disabled={isUnavailable || isDay30}
> >
<span className="text-sm font-medium"> {isCrossedOut ? (
// Перечеркнутая ячейка для недоступных дней
<>
<span className="text-sm font-medium text-[#333333] self-end">
{day.date.getDate()} {day.date.getDate()}
</span> </span>
{isAvailable && ( <div className="absolute inset-0 flex items-center justify-center">
<> <span className="text-gray-300 text-4xl font-light leading-none">
<span className="text-[10px] mt-1 text-center leading-tight">
Доступно: 08:00-20:00
</span> </span>
<span className="text-[10px] mt-0.5 text-center leading-tight"> </div>
{price} р/час </>
) : (
// Доступный день с информацией
<>
{/* Дата и "Доступно:" в одной строке */}
<div className="flex items-center justify-between w-full">
<span className="text-xs text-gray-400">
Доступно:
</span>
<span className="text-sm font-medium text-[#333333]">
{day.date.getDate()}
</span>
</div>
<div className="flex flex-col gap-1.5 w-full mt-1">
<div className="w-fit bg-[#F6BD4D] text-white text-[10px] font-medium px-1 py-0 rounded-full inline-block">
08:0020:00
</div>
</div>
{/* Цена в нижнем правом углу */}
<span className="absolute bottom-[2px] right-[4px] text-xs text-[#333333] font-medium">
{price} / час
</span> </span>
</> </>
)} )}
{(isUnavailable || isDay30) && (
<span className="text-lg mt-1"></span>
)}
</button> </button>
); );
}, },
@ -147,4 +167,3 @@ export function YachtAvailability({ price }: YachtAvailabilityProps) {
</div> </div>
); );
} }

View File

@ -33,19 +33,19 @@ export function YachtCharacteristics({ yacht }: YachtCharacteristicsProps) {
return ( return (
<div> <div>
<h2 className="text-xl font-bold text-[#333333] mb-4"> <h2 className="text-base font-bold text-[#333333] mb-4">
Характеристики Характеристики
</h2> </h2>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-x-6">
{characteristics.map((char, index) => ( {characteristics.map((char, index) => (
<div <div
key={index} key={index}
className="flex justify-between items-center py-2 border-b border-gray-200" className="flex justify-between items-center py-4 border-b border-gray-200"
> >
<span className="text-base text-[#999999]"> <span className="text-base text-[#999999]">
{char.label}: {char.label}
</span> </span>
<span className="text-base font-medium text-[#333333]"> <span className="text-base font-regular text-[#333333]">
{char.value} {char.value}
</span> </span>
</div> </div>
@ -54,6 +54,3 @@ export function YachtCharacteristics({ yacht }: YachtCharacteristicsProps) {
</div> </div>
); );
} }

View File

@ -52,7 +52,7 @@ export function YachtGallery({ images, badge }: YachtGalleryProps) {
<CarouselContent> <CarouselContent>
{images.map((img, index) => ( {images.map((img, index) => (
<CarouselItem key={index}> <CarouselItem key={index}>
<div className="relative w-full h-[500px] rounded-lg overflow-hidden"> <div className="relative w-full h-[592px] rounded-lg overflow-hidden">
<Image <Image
src={img} src={img}
alt={`Yacht image ${index + 1}`} alt={`Yacht image ${index + 1}`}
@ -60,17 +60,6 @@ export function YachtGallery({ images, badge }: YachtGalleryProps) {
className="object-cover" className="object-cover"
priority={index === 0} priority={index === 0}
/> />
{badge && (
<div className="absolute top-4 left-4 z-10">
<div className="flex items-center justify-center bg-black/40 text-white px-3 py-1 rounded-lg text-sm gap-1">
<Icon size={16} name="restart" />
<span>{badge}</span>
</div>
</div>
)}
<div className="absolute bottom-4 right-4 bg-black/40 text-white px-3 py-1 rounded-lg text-sm">
{index + 1}/{images.length}
</div>
</div> </div>
</CarouselItem> </CarouselItem>
))} ))}
@ -78,6 +67,21 @@ export function YachtGallery({ images, badge }: YachtGalleryProps) {
<CarouselPrevious className="left-4 bg-white/80 hover:bg-white border-gray-300" /> <CarouselPrevious className="left-4 bg-white/80 hover:bg-white border-gray-300" />
<CarouselNext className="right-4 bg-white/80 hover:bg-white border-gray-300" /> <CarouselNext className="right-4 bg-white/80 hover:bg-white border-gray-300" />
</Carousel> </Carousel>
{/* Badge - поверх слайдера, не скроллится */}
{badge && (
<div className="absolute top-4 left-4 z-20 pointer-events-none">
<div className="flex items-center justify-center bg-black/40 text-white px-3 py-1 rounded-lg text-sm gap-1">
<Icon size={16} name="restart" />
<span>{badge}</span>
</div>
</div>
)}
{/* Photo counter - поверх слайдера, не скроллится */}
<div className="absolute bottom-4 right-4 z-20 pointer-events-none">
<div className="bg-black/40 text-white px-3 py-1 rounded-lg text-sm">
{current + 1}/{images.length}
</div>
</div>
</div> </div>
{/* Thumbnails */} {/* Thumbnails */}
@ -86,7 +90,7 @@ export function YachtGallery({ images, badge }: YachtGalleryProps) {
<button <button
key={index} key={index}
onClick={() => scrollTo(index)} onClick={() => scrollTo(index)}
className={`relative flex-shrink-0 w-24 h-24 rounded-lg overflow-hidden border-2 transition-all ${ className={`relative flex-shrink-0 w-17 h-14 rounded-lg overflow-hidden border-2 transition-all ${
current === index current === index
? "border-[#008299] opacity-100" ? "border-[#008299] opacity-100"
: "border-transparent opacity-60 hover:opacity-100" : "border-transparent opacity-60 hover:opacity-100"

View File

@ -2,7 +2,6 @@
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";
import Link from "next/link"; import Link from "next/link";
import Image from "next/image";
import Icon from "@/components/ui/icon"; import Icon from "@/components/ui/icon";
import { YachtGallery } from "./components/YachtGallery"; import { YachtGallery } from "./components/YachtGallery";
import { YachtAvailability } from "./components/YachtAvailability"; import { YachtAvailability } from "./components/YachtAvailability";
@ -37,7 +36,11 @@ export default function YachtDetailPage() {
cabins: 2, cabins: 2,
material: "Стеклопластик", material: "Стеклопластик",
power: 740, power: 740,
description: "Яхта", description: `Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта
Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта
Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта
Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта
Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта`,
contactPerson: { contactPerson: {
name: "Денис", name: "Денис",
avatar: "/images/logo.svg", avatar: "/images/logo.svg",
@ -73,35 +76,39 @@ export default function YachtDetailPage() {
<div className="bg-white rounded-[16px] p-6"> <div className="bg-white rounded-[16px] p-6">
{/* Yacht Title and Actions */} {/* Yacht Title and Actions */}
<div className="mb-6 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4"> <div className="mb-6 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
<h1 className="text-2xl md:text-3xl font-bold text-[#333333]"> <h1 className="text-xl md:text-2 xl font-bold text-[#333333]">
{yacht.name} {yacht.name}
</h1> </h1>
<div className="flex items-center gap-6"> <div className="flex items-center gap-6">
<div className="flex items-center gap-2 text-[#333333]"> <div className="flex items-center gap-2 text-[#333333]">
<Icon name="map" size={20} /> <Icon name="pin" size={32} />
<span className="text-base">{yacht.location}</span> <span className="text-base">
{yacht.location}
</span>
</div> </div>
<button className="flex items-center gap-2 text-[#333333] hover:text-[#008299] transition-colors"> <button className="flex items-center gap-2 cursor-pointer text-[#333333] hover:text-[#008299] transition-colors">
<Icon name="ad" size={20} /> <Icon name="share" size={32} />
<span className="text-base">Поделиться</span> <span className="text-base">Поделиться</span>
</button> </button>
<button className="flex items-center gap-2 text-[#333333] hover:text-[#008299] transition-colors"> <button className="flex items-center gap-2 cursor-pointer text-[#333333] hover:text-[#008299] transition-colors">
<Icon name="like" size={20} /> <Icon name="heart" size={32} />
<span className="text-base">Избранное</span> <span className="text-base">Избранное</span>
</button> </button>
</div> </div>
</div> </div>
{/* Main Content Grid */} {/* Main Content */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6"> <div className="space-y-6">
{/* Left Column - Gallery and Availability */}
<div className="lg:col-span-2 space-y-6">
{/* Gallery */} {/* Gallery */}
<YachtGallery <YachtGallery
images={yacht.images} images={yacht.images}
badge={yacht.badge} badge={yacht.badge}
/> />
{/* Content with Booking Widget on the right */}
<div className="flex flex-col lg:flex-row gap-6 items-start">
{/* Left column - all content below gallery */}
<div className="flex-1 space-y-6">
{/* Availability */} {/* Availability */}
<YachtAvailability price={yacht.price} /> <YachtAvailability price={yacht.price} />
@ -110,10 +117,10 @@ export default function YachtDetailPage() {
{/* Description */} {/* Description */}
<div> <div>
<h2 className="text-xl font-bold text-[#333333] mb-4"> <h2 className="text-base font-bold text-[#333333] mb-4">
Описание Описание
</h2> </h2>
<p className="text-base text-[#333333] leading-relaxed"> <p className="text-base text-[#666666] leading-relaxed">
{yacht.description} {yacht.description}
</p> </p>
</div> </div>
@ -126,22 +133,28 @@ export default function YachtDetailPage() {
{/* Reviews */} {/* Reviews */}
<div> <div>
<h2 className="text-xl font-bold text-[#333333] mb-4"> <div className="flex items-center gap-2 mb-4">
<Icon name="reviewStar" size={16} />
<h2 className="text-base font-bold text-[#333333]">
Отзывы Отзывы
</h2> </h2>
<p className="text-base text-[#999999]"> </div>
<div className="border border-[#DFDFDF] rounded-[12px] flex items-center justify-center py-18">
<p className="text-lg text-[#999999]">
У этой яхты пока нет отзывов У этой яхты пока нет отзывов
</p> </p>
</div> </div>
</div> </div>
</div>
{/* Right Column - Booking Widget */} {/* Right column - Booking Widget (sticky) */}
<div className="lg:col-span-1"> <div className="lg:w-74 flex-shrink-0 lg:sticky lg:top-24 self-start">
<BookingWidget price={yacht.price} /> <BookingWidget price={yacht.price} />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
</main> </main>
); );
} }

View File

@ -22,6 +22,10 @@ import PriceMinIcon from "../../../public/images/icons/price-min.svg";
import PriceMaxIcon from "../../../public/images/icons/price-max.svg"; import PriceMaxIcon from "../../../public/images/icons/price-max.svg";
import BoatYearMinIcon from "../../../public/images/icons/boat-year-min.svg"; import BoatYearMinIcon from "../../../public/images/icons/boat-year-min.svg";
import BoatYearMaxIcon from "../../../public/images/icons/boat-year-max.svg"; import BoatYearMaxIcon from "../../../public/images/icons/boat-year-max.svg";
import PinIcon from "../../../public/images/icons/pin.svg";
import HeartIcon from "../../../public/images/icons/heart.svg";
import ShareIcon from "../../../public/images/icons/share.svg";
import ReviewStarIcon from "../../../public/images/icons/review-star.svg";
// Объект с иконками для удобного доступа // Объект с иконками для удобного доступа
const icons = { const icons = {
@ -45,6 +49,10 @@ const icons = {
priceMax: PriceMaxIcon, priceMax: PriceMaxIcon,
boatYearMin: BoatYearMinIcon, boatYearMin: BoatYearMinIcon,
boatYearMax: BoatYearMaxIcon, boatYearMax: BoatYearMaxIcon,
pin: PinIcon,
heart: HeartIcon,
share: ShareIcon,
reviewStar: ReviewStarIcon,
}; };
export type IconName = export type IconName =
@ -67,7 +75,11 @@ export type IconName =
| "priceMin" | "priceMin"
| "priceMax" | "priceMax"
| "boatYearMin" | "boatYearMin"
| "boatYearMax"; | "boatYearMax"
| "pin"
| "heart"
| "share"
| "reviewStar";
export interface IconProps export interface IconProps
extends Omit<SVGProps<SVGSVGElement>, "name" | "preserveAspectRatio"> { extends Omit<SVGProps<SVGSVGElement>, "name" | "preserveAspectRatio"> {