мобильные версии страниц
This commit is contained in:
parent
2383f75fe2
commit
bc31770c51
|
|
@ -2,19 +2,33 @@
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Calendar } from "@/components/ui/calendar";
|
import { Calendar } from "@/components/ui/calendar";
|
||||||
import { isSameMonth, isBefore, startOfDay, format } from "date-fns";
|
import {
|
||||||
|
isSameMonth,
|
||||||
|
isBefore,
|
||||||
|
startOfDay,
|
||||||
|
format,
|
||||||
|
eachDayOfInterval,
|
||||||
|
startOfMonth,
|
||||||
|
endOfMonth,
|
||||||
|
} from "date-fns";
|
||||||
import { ru } from "date-fns/locale";
|
import { ru } from "date-fns/locale";
|
||||||
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
import { ChevronLeftIcon, ChevronRightIcon, Clock } from "lucide-react";
|
||||||
|
|
||||||
interface YachtAvailabilityProps {
|
interface YachtAvailabilityProps {
|
||||||
price: string;
|
price: string;
|
||||||
|
mobile?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function YachtAvailability({ price }: YachtAvailabilityProps) {
|
export function YachtAvailability({
|
||||||
|
price,
|
||||||
|
mobile = false,
|
||||||
|
}: YachtAvailabilityProps) {
|
||||||
const today = startOfDay(new Date());
|
const today = startOfDay(new Date());
|
||||||
const [currentMonth, setCurrentMonth] = useState(
|
const [currentMonth, setCurrentMonth] = useState(
|
||||||
new Date(today.getFullYear(), today.getMonth(), 1)
|
new Date(today.getFullYear(), today.getMonth(), 1)
|
||||||
);
|
);
|
||||||
|
const [startTime, setStartTime] = useState<string>("");
|
||||||
|
const [endTime, setEndTime] = useState<string>("");
|
||||||
|
|
||||||
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);
|
||||||
|
|
@ -38,26 +52,182 @@ export function YachtAvailability({ price }: YachtAvailabilityProps) {
|
||||||
return isDateUnavailable(date) || isDateInPast(date);
|
return isDateUnavailable(date) || isDateInPast(date);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isDateAvailable = (date: Date) => {
|
||||||
|
return !shouldBeCrossedOut(date) && isSameMonth(date, currentMonth);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAvailableDaysCount = () => {
|
||||||
|
const monthStart = startOfMonth(currentMonth);
|
||||||
|
const monthEnd = endOfMonth(currentMonth);
|
||||||
|
const daysInMonth = eachDayOfInterval({
|
||||||
|
start: monthStart,
|
||||||
|
end: monthEnd,
|
||||||
|
});
|
||||||
|
return daysInMonth.filter((day) => isDateAvailable(day)).length;
|
||||||
|
};
|
||||||
|
|
||||||
const goToPreviousMonth = () => {
|
const goToPreviousMonth = () => {
|
||||||
setCurrentMonth(
|
setCurrentMonth(
|
||||||
new Date(
|
new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1)
|
||||||
currentMonth.getFullYear(),
|
|
||||||
currentMonth.getMonth() - 1,
|
|
||||||
1
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const goToNextMonth = () => {
|
const goToNextMonth = () => {
|
||||||
setCurrentMonth(
|
setCurrentMonth(
|
||||||
new Date(
|
new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1)
|
||||||
currentMonth.getFullYear(),
|
|
||||||
currentMonth.getMonth() + 1,
|
|
||||||
1
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Генерация времени для селекта
|
||||||
|
const timeOptions = Array.from({ length: 24 * 2 }, (_, i) => {
|
||||||
|
const hours = Math.floor(i / 2);
|
||||||
|
const minutes = (i % 2) * 30;
|
||||||
|
const timeString = `${String(hours).padStart(2, "0")}:${String(
|
||||||
|
minutes
|
||||||
|
).padStart(2, "0")}`;
|
||||||
|
return { value: timeString, label: timeString };
|
||||||
|
});
|
||||||
|
|
||||||
|
if (mobile) {
|
||||||
|
return (
|
||||||
|
<div className="w-full">
|
||||||
|
{/* Навигация по месяцам */}
|
||||||
|
<div className="flex items-center justify-between mb-4">
|
||||||
|
<button
|
||||||
|
onClick={goToPreviousMonth}
|
||||||
|
className="w-10 h-10 rounded-full border border-[#dfdfdf] flex items-center justify-center hover:bg-gray-50 transition-colors"
|
||||||
|
>
|
||||||
|
<ChevronLeftIcon className="size-4 text-[#333333]" />
|
||||||
|
</button>
|
||||||
|
<div className="flex flex-col items-center">
|
||||||
|
<span className="text-lg font-medium text-[#333333] capitalize">
|
||||||
|
{format(currentMonth, "LLLL", { locale: ru })}
|
||||||
|
</span>
|
||||||
|
<span className="text-sm text-[#999999]">
|
||||||
|
Свободных дней: {getAvailableDaysCount()}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={goToNextMonth}
|
||||||
|
className="w-10 h-10 rounded-full border border-[#dfdfdf] flex items-center justify-center hover:bg-gray-50 transition-colors"
|
||||||
|
>
|
||||||
|
<ChevronRightIcon className="size-4 text-[#333333]" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Календарь */}
|
||||||
|
<div style={{ flexShrink: 0 }}>
|
||||||
|
<Calendar
|
||||||
|
mode="single"
|
||||||
|
month={currentMonth}
|
||||||
|
onMonthChange={setCurrentMonth}
|
||||||
|
showOutsideDays={false}
|
||||||
|
className="w-full p-0"
|
||||||
|
locale={ru}
|
||||||
|
formatters={{
|
||||||
|
formatWeekdayName: (date) => {
|
||||||
|
const weekdays = [
|
||||||
|
"ВС",
|
||||||
|
"ПН",
|
||||||
|
"ВТ",
|
||||||
|
"СР",
|
||||||
|
"ЧТ",
|
||||||
|
"ПТ",
|
||||||
|
"СБ",
|
||||||
|
];
|
||||||
|
return weekdays[date.getDay()];
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
classNames={{
|
||||||
|
root: "w-full",
|
||||||
|
month: "flex w-full flex-col gap-2",
|
||||||
|
nav: "hidden",
|
||||||
|
month_caption: "hidden",
|
||||||
|
caption_label: "hidden",
|
||||||
|
button_previous: "hidden",
|
||||||
|
button_next: "hidden",
|
||||||
|
table: "w-full border-collapse table-fixed",
|
||||||
|
weekdays: "flex w-full mb-2",
|
||||||
|
weekday:
|
||||||
|
"flex-1 text-[#999999] text-xs font-normal p-2 text-center",
|
||||||
|
week: "flex w-full min-h-[50px]",
|
||||||
|
day: "relative flex-1 min-w-0 flex-shrink-0",
|
||||||
|
}}
|
||||||
|
components={{
|
||||||
|
DayButton: ({ day, ...props }) => {
|
||||||
|
if (!isSameMonth(day.date, currentMonth)) {
|
||||||
|
return <div className="hidden" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isCrossedOut = shouldBeCrossedOut(
|
||||||
|
day.date
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
{...props}
|
||||||
|
className={`relative w-full flex items-center justify-center text-sm font-medium transition-colors ${
|
||||||
|
isCrossedOut
|
||||||
|
? "text-[#CCCCCC] line-through"
|
||||||
|
: "text-[#333333] hover:bg-gray-100"
|
||||||
|
}`}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
aspectRatio: "1 / 1",
|
||||||
|
minHeight: "44px",
|
||||||
|
} as React.CSSProperties
|
||||||
|
}
|
||||||
|
disabled={isCrossedOut}
|
||||||
|
>
|
||||||
|
{day.date.getDate()}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Выбор времени */}
|
||||||
|
<div className="space-y-4 mb-4" style={{ marginTop: "24px" }}>
|
||||||
|
<div className="flex gap-3">
|
||||||
|
<div className="flex-1">
|
||||||
|
<select
|
||||||
|
value={startTime}
|
||||||
|
onChange={(e) => setStartTime(e.target.value)}
|
||||||
|
className="w-full px-4 py-3 border border-[#DFDFDF] rounded-lg text-base text-[#333333] bg-white appearance-none"
|
||||||
|
>
|
||||||
|
<option value="">--:--</option>
|
||||||
|
{timeOptions.map((time) => (
|
||||||
|
<option key={time.value} value={time.value}>
|
||||||
|
{time.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<select
|
||||||
|
value={endTime}
|
||||||
|
onChange={(e) => setEndTime(e.target.value)}
|
||||||
|
className="w-full px-4 py-3 border border-[#DFDFDF] rounded-lg text-base text-[#333333] bg-white appearance-none"
|
||||||
|
>
|
||||||
|
<option value="">--:--</option>
|
||||||
|
{timeOptions.map((time) => (
|
||||||
|
<option key={time.value} value={time.value}>
|
||||||
|
{time.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 text-sm text-[#999999]">
|
||||||
|
<Clock size={16} />
|
||||||
|
<span>По местному времени яхты</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4 w-full">
|
<div className="space-y-4 w-full">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
|
|
|
||||||
|
|
@ -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-[592px] rounded-lg overflow-hidden">
|
<div className="relative w-full h-[60vh] lg:h-[592px] rounded-0 lg:rounded-[24px] overflow-hidden">
|
||||||
<Image
|
<Image
|
||||||
src={img}
|
src={img}
|
||||||
alt={`Yacht image ${index + 1}`}
|
alt={`Yacht image ${index + 1}`}
|
||||||
|
|
@ -64,12 +64,12 @@ export function YachtGallery({ images, badge }: YachtGalleryProps) {
|
||||||
</CarouselItem>
|
</CarouselItem>
|
||||||
))}
|
))}
|
||||||
</CarouselContent>
|
</CarouselContent>
|
||||||
<CarouselPrevious className="left-4 bg-white/80 hover:bg-white border-gray-300" />
|
<CarouselPrevious className="left-2 lg:left-4 bg-white/80 hover:bg-white border-gray-300 w-10 h-10 lg:w-12 lg:h-12 rounded-full" />
|
||||||
<CarouselNext className="right-4 bg-white/80 hover:bg-white border-gray-300" />
|
<CarouselNext className="right-2 lg:right-4 bg-white/80 hover:bg-white border-gray-300 w-10 h-10 lg:w-12 lg:h-12 rounded-full" />
|
||||||
</Carousel>
|
</Carousel>
|
||||||
{/* Badge - поверх слайдера, не скроллится */}
|
{/* Badge - поверх слайдера, не скроллится */}
|
||||||
{badge && (
|
{badge && (
|
||||||
<div className="absolute top-4 left-4 z-20 pointer-events-none">
|
<div className="absolute bottom-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">
|
<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" />
|
<Icon size={16} name="restart" />
|
||||||
<span>{badge}</span>
|
<span>{badge}</span>
|
||||||
|
|
@ -84,8 +84,8 @@ export function YachtGallery({ images, badge }: YachtGalleryProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Thumbnails */}
|
{/* Thumbnails - скрыты на мобильных */}
|
||||||
<div className="flex gap-2 overflow-x-auto pb-2">
|
<div className="hidden lg:flex gap-2 overflow-x-auto pb-2">
|
||||||
{images.map((img, index) => (
|
{images.map((img, index) => (
|
||||||
<button
|
<button
|
||||||
key={index}
|
key={index}
|
||||||
|
|
@ -108,4 +108,3 @@ export function YachtGallery({ images, badge }: YachtGalleryProps) {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
export const YACHT = {
|
||||||
|
id: 1,
|
||||||
|
name: "Яхта Название",
|
||||||
|
location: "7 Футов",
|
||||||
|
price: "18 000",
|
||||||
|
images: [
|
||||||
|
"/images/yachts/yacht1.jpg",
|
||||||
|
"/images/yachts/yacht2.jpg",
|
||||||
|
"/images/yachts/yacht3.jpg",
|
||||||
|
"/images/yachts/yacht4.jpg",
|
||||||
|
"/images/yachts/yacht5.jpg",
|
||||||
|
"/images/yachts/yacht6.jpg",
|
||||||
|
],
|
||||||
|
badge: "По запросу",
|
||||||
|
year: 2000,
|
||||||
|
maxCapacity: 11,
|
||||||
|
comfortableCapacity: 11,
|
||||||
|
length: 13,
|
||||||
|
width: 4,
|
||||||
|
cabins: 2,
|
||||||
|
material: "Стеклопластик",
|
||||||
|
power: 740,
|
||||||
|
description: `Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта
|
||||||
|
Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта
|
||||||
|
Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта
|
||||||
|
Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта
|
||||||
|
Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта`,
|
||||||
|
contactPerson: {
|
||||||
|
name: "Денис",
|
||||||
|
avatar: "/images/logo.svg",
|
||||||
|
},
|
||||||
|
requisites: {
|
||||||
|
ip: "Иванов Иван Иванович",
|
||||||
|
inn: "23000000000",
|
||||||
|
ogrn: "310000000000001",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -1,62 +1,52 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useParams } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { ArrowLeft, Heart } from "lucide-react";
|
||||||
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";
|
||||||
import { BookingWidget } from "./components/BookingWidget";
|
import { BookingWidget } from "./components/BookingWidget";
|
||||||
import { YachtCharacteristics } from "./components/YachtCharacteristics";
|
import { YachtCharacteristics } from "./components/YachtCharacteristics";
|
||||||
import { ContactInfo } from "./components/ContactInfo";
|
import { ContactInfo } from "./components/ContactInfo";
|
||||||
|
import { YACHT } from "./const";
|
||||||
|
|
||||||
export default function YachtDetailPage() {
|
export default function YachtDetailPage() {
|
||||||
const params = useParams();
|
// const params = useParams();
|
||||||
const id = params.id as string;
|
const router = useRouter();
|
||||||
|
const [activeTab, setActiveTab] = useState<
|
||||||
// Данные яхты (в реальном приложении будут загружаться из API)
|
| "availability"
|
||||||
const yacht = {
|
| "description"
|
||||||
id: id,
|
| "characteristics"
|
||||||
name: "Яхта Название",
|
| "contact"
|
||||||
location: "7 Футов",
|
| "requisites"
|
||||||
price: "18 000",
|
| "reviews"
|
||||||
images: [
|
>("availability");
|
||||||
"/images/yachts/yacht1.jpg",
|
|
||||||
"/images/yachts/yacht2.jpg",
|
|
||||||
"/images/yachts/yacht3.jpg",
|
|
||||||
"/images/yachts/yacht4.jpg",
|
|
||||||
"/images/yachts/yacht5.jpg",
|
|
||||||
"/images/yachts/yacht6.jpg",
|
|
||||||
],
|
|
||||||
badge: "По запросу",
|
|
||||||
year: 2000,
|
|
||||||
maxCapacity: 11,
|
|
||||||
comfortableCapacity: 11,
|
|
||||||
length: 13,
|
|
||||||
width: 4,
|
|
||||||
cabins: 2,
|
|
||||||
material: "Стеклопластик",
|
|
||||||
power: 740,
|
|
||||||
description: `Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта
|
|
||||||
Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта
|
|
||||||
Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта
|
|
||||||
Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта
|
|
||||||
Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта Яхта`,
|
|
||||||
contactPerson: {
|
|
||||||
name: "Денис",
|
|
||||||
avatar: "/images/logo.svg",
|
|
||||||
},
|
|
||||||
requisites: {
|
|
||||||
ip: "Иванов Иван Иванович",
|
|
||||||
inn: "23000000000",
|
|
||||||
ogrn: "310000000000001",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="bg-[#f4f4f4] min-h-screen">
|
<main className="bg-[#f4f4f4] min-h-screen ">
|
||||||
<div className="container max-w-6xl mx-auto px-4 py-6">
|
{/* Мобильная фиксированная верхняя панель навигации */}
|
||||||
{/* Breadcrumbs */}
|
<div className="lg:hidden fixed top-[73px] left-0 right-0 z-[50] bg-white border-b border-gray-200">
|
||||||
<div className="mb-6 text-sm text-[#999999] flex items-center gap-4">
|
<div className="flex items-center justify-between px-4 h-14">
|
||||||
|
<button
|
||||||
|
onClick={() => router.back()}
|
||||||
|
className="flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<ArrowLeft size={24} className="text-[#333333]" />
|
||||||
|
</button>
|
||||||
|
<h2 className="text-base font-medium text-[#333333]">
|
||||||
|
Яхта
|
||||||
|
</h2>
|
||||||
|
<button className="flex items-center justify-center">
|
||||||
|
<Heart size={24} className="text-[#333333]" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Десктопная версия - Breadcrumbs */}
|
||||||
|
<div className="hidden lg:block container max-w-6xl mx-auto px-4 py-4">
|
||||||
|
<div className="text-sm text-[#999999] flex items-center gap-4">
|
||||||
<Link href="/">
|
<Link href="/">
|
||||||
<span className="cursor-pointer hover:text-[#333333] transition-colors">
|
<span className="cursor-pointer hover:text-[#333333] transition-colors">
|
||||||
Аренда яхты
|
Аренда яхты
|
||||||
|
|
@ -69,69 +59,111 @@ export default function YachtDetailPage() {
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
<span>></span>
|
<span>></span>
|
||||||
<span className="text-[#333333]">{yacht.name}</span>
|
<span className="text-[#333333]">{YACHT.name}</span>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Main Content Container */}
|
{/* Main Content Container */}
|
||||||
<div className="bg-white rounded-[16px] p-6">
|
<div className="lg:container lg:max-w-6xl lg:mx-auto lg:px-4 lg:pb-6">
|
||||||
{/* Yacht Title and Actions */}
|
<div className="bg-white lg:rounded-[16px] lg:p-6">
|
||||||
<div className="mb-6 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
|
{/* Мобильная версия - без отступов сверху, с отступом для фиксированной панели */}
|
||||||
<h1 className="text-xl md:text-2 xl font-bold text-[#333333]">
|
<div className="lg:hidden pt-[50px]">
|
||||||
{yacht.name}
|
|
||||||
</h1>
|
|
||||||
<div className="flex items-center gap-6">
|
|
||||||
<div className="flex items-center gap-2 text-[#333333]">
|
|
||||||
<Icon name="pin" size={32} />
|
|
||||||
<span className="text-base">
|
|
||||||
{yacht.location}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<button className="flex items-center gap-2 cursor-pointer text-[#333333] hover:text-[#008299] transition-colors">
|
|
||||||
<Icon name="share" size={32} />
|
|
||||||
<span className="text-base">Поделиться</span>
|
|
||||||
</button>
|
|
||||||
<button className="flex items-center gap-2 cursor-pointer text-[#333333] hover:text-[#008299] transition-colors">
|
|
||||||
<Icon name="heart" size={32} />
|
|
||||||
<span className="text-base">Избранное</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Main Content */}
|
|
||||||
<div className="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 */}
|
{/* Yacht Title */}
|
||||||
<div className="flex flex-col lg:flex-row gap-6 items-start">
|
<div className="px-4 pt-4">
|
||||||
{/* Left column - all content below gallery */}
|
<h1 className="text-xl font-bold text-[#333333] mb-4">
|
||||||
<div className="flex-1 space-y-6">
|
{YACHT.name}
|
||||||
{/* Availability */}
|
</h1>
|
||||||
<YachtAvailability price={yacht.price} />
|
</div>
|
||||||
|
|
||||||
{/* Characteristics */}
|
{/* Tabs */}
|
||||||
<YachtCharacteristics yacht={yacht} />
|
<div className="px-4 border-b border-gray-200 overflow-x-auto">
|
||||||
|
<div className="flex gap-6 min-w-max">
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveTab("availability")}
|
||||||
|
className={`pb-3 text-base font-medium transition-colors whitespace-nowrap ${
|
||||||
|
activeTab === "availability"
|
||||||
|
? "text-[#008299] border-b-2 border-[#008299]"
|
||||||
|
: "text-[#999999]"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Свободные даты
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveTab("description")}
|
||||||
|
className={`pb-3 text-base font-medium transition-colors whitespace-nowrap ${
|
||||||
|
activeTab === "description"
|
||||||
|
? "text-[#008299] border-b-2 border-[#008299]"
|
||||||
|
: "text-[#999999]"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Описание
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
setActiveTab("characteristics")
|
||||||
|
}
|
||||||
|
className={`pb-3 text-base font-medium transition-colors whitespace-nowrap ${
|
||||||
|
activeTab === "characteristics"
|
||||||
|
? "text-[#008299] border-b-2 border-[#008299]"
|
||||||
|
: "text-[#999999]"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Характеристики
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveTab("contact")}
|
||||||
|
className={`pb-3 text-base font-medium transition-colors whitespace-nowrap ${
|
||||||
|
activeTab === "contact"
|
||||||
|
? "text-[#008299] border-b-2 border-[#008299]"
|
||||||
|
: "text-[#999999]"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Контактное лицо и реквизиты
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveTab("reviews")}
|
||||||
|
className={`pb-3 text-base font-medium transition-colors whitespace-nowrap ${
|
||||||
|
activeTab === "reviews"
|
||||||
|
? "text-[#008299] border-b-2 border-[#008299]"
|
||||||
|
: "text-[#999999]"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Отзывы
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Description */}
|
{/* Tab Content */}
|
||||||
|
<div className="px-4 py-6">
|
||||||
|
{activeTab === "availability" && (
|
||||||
|
<YachtAvailability
|
||||||
|
price={YACHT.price}
|
||||||
|
mobile={true}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{activeTab === "description" && (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-base font-bold text-[#333333] mb-4">
|
|
||||||
Описание
|
|
||||||
</h2>
|
|
||||||
<p className="text-base text-[#666666] leading-relaxed">
|
<p className="text-base text-[#666666] leading-relaxed">
|
||||||
{yacht.description}
|
{YACHT.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
{/* Contact and Requisites */}
|
{activeTab === "characteristics" && (
|
||||||
|
<YachtCharacteristics yacht={YACHT} />
|
||||||
|
)}
|
||||||
|
{activeTab === "contact" && (
|
||||||
<ContactInfo
|
<ContactInfo
|
||||||
contactPerson={yacht.contactPerson}
|
contactPerson={YACHT.contactPerson}
|
||||||
requisites={yacht.requisites}
|
requisites={YACHT.requisites}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
{/* Reviews */}
|
{activeTab === "reviews" && (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-2 mb-4">
|
<div className="flex items-center gap-2 mb-4">
|
||||||
<Icon name="reviewStar" size={16} />
|
<Icon name="reviewStar" size={16} />
|
||||||
|
|
@ -145,16 +177,116 @@ export default function YachtDetailPage() {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Right column - Booking Widget (sticky) */}
|
{/* Десктопная версия */}
|
||||||
<div className="lg:w-74 flex-shrink-0 lg:sticky lg:top-24 self-start">
|
<div className="hidden lg:block">
|
||||||
<BookingWidget price={yacht.price} />
|
{/* Yacht Title and Actions */}
|
||||||
|
<div className="mb-6 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
|
||||||
|
<h1 className="text-xl md:text-2xl font-bold text-[#333333]">
|
||||||
|
{YACHT.name}
|
||||||
|
</h1>
|
||||||
|
<div className="flex items-center gap-6">
|
||||||
|
<div className="flex items-center gap-2 text-[#333333]">
|
||||||
|
<Icon name="pin" size={32} />
|
||||||
|
<span className="text-base">
|
||||||
|
{YACHT.location}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<button className="flex items-center gap-2 cursor-pointer text-[#333333] hover:text-[#008299] transition-colors">
|
||||||
|
<Icon name="share" size={32} />
|
||||||
|
<span className="text-base">
|
||||||
|
Поделиться
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button className="flex items-center gap-2 cursor-pointer text-[#333333] hover:text-[#008299] transition-colors">
|
||||||
|
<Icon name="heart" size={32} />
|
||||||
|
<span className="text-base">Избранное</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Main Content */}
|
||||||
|
<div className="space-y-6">
|
||||||
|
{/* Gallery */}
|
||||||
|
<YachtGallery
|
||||||
|
images={YACHT.images}
|
||||||
|
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 */}
|
||||||
|
<YachtAvailability price={YACHT.price} />
|
||||||
|
|
||||||
|
{/* Characteristics */}
|
||||||
|
<YachtCharacteristics yacht={YACHT} />
|
||||||
|
|
||||||
|
{/* Description */}
|
||||||
|
<div>
|
||||||
|
<h2 className="text-base font-bold text-[#333333] mb-4">
|
||||||
|
Описание
|
||||||
|
</h2>
|
||||||
|
<p className="text-base text-[#666666] leading-relaxed">
|
||||||
|
{YACHT.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Contact and Requisites */}
|
||||||
|
<ContactInfo
|
||||||
|
contactPerson={YACHT.contactPerson}
|
||||||
|
requisites={YACHT.requisites}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Reviews */}
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center gap-2 mb-4">
|
||||||
|
<Icon name="reviewStar" size={16} />
|
||||||
|
<h2 className="text-base font-bold text-[#333333]">
|
||||||
|
Отзывы
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div className="border border-[#DFDFDF] rounded-[12px] flex items-center justify-center py-18">
|
||||||
|
<p className="text-lg text-[#999999]">
|
||||||
|
У этой яхты пока нет отзывов
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Right column - Booking Widget (sticky) */}
|
||||||
|
<div className="lg:w-74 flex-shrink-0 lg:sticky lg:top-24 self-start">
|
||||||
|
<BookingWidget price={YACHT.price} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Мобильная фиксированная нижняя панель бронирования */}
|
||||||
|
<div className="lg:hidden sticky bottom-0 left-0 right-0 z-[10] bg-white border-t border-gray-200 px-4 py-3">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<span className="text-lg font-bold text-[#333333]">
|
||||||
|
{YACHT.price} ₽
|
||||||
|
</span>
|
||||||
|
<span className="text-sm text-[#999999] ml-1">
|
||||||
|
/ час
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => router.push("/confirm")}
|
||||||
|
className="bg-[#008299] text-white px-6 py-3 rounded-lg font-bold text-base hover:bg-[#006d7a] transition-colors"
|
||||||
|
>
|
||||||
|
Забронировать
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,11 @@ 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";
|
import Icon from "@/components/ui/icon";
|
||||||
|
|
||||||
export default function CatalogSidebar() {
|
interface CatalogSidebarProps {
|
||||||
|
onApply?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CatalogSidebar({ onApply }: CatalogSidebarProps) {
|
||||||
const [lengthRange, setLengthRange] = useState([7, 50]);
|
const [lengthRange, setLengthRange] = useState([7, 50]);
|
||||||
const [priceRange, setPriceRange] = useState([3000, 200000]);
|
const [priceRange, setPriceRange] = useState([3000, 200000]);
|
||||||
const [yearRange, setYearRange] = useState([1991, 2025]);
|
const [yearRange, setYearRange] = useState([1991, 2025]);
|
||||||
|
|
@ -254,7 +258,10 @@ export default function CatalogSidebar() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Кнопка Применить */}
|
{/* Кнопка Применить */}
|
||||||
<Button className="w-full bg-[#008299] hover:bg-[#006d7f] text-white font-bold h-12 mt-2">
|
<Button
|
||||||
|
onClick={onApply}
|
||||||
|
className="w-full bg-[#008299] hover:bg-[#006d7f] text-white font-bold h-12 mt-2"
|
||||||
|
>
|
||||||
Применить
|
Применить
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Icon from "@/components/ui/icon";
|
import Icon from "@/components/ui/icon";
|
||||||
|
|
@ -12,6 +13,8 @@ import {
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
|
import { Sliders, X, ArrowLeft } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
const yachts = [
|
const yachts = [
|
||||||
{
|
{
|
||||||
|
|
@ -113,11 +116,13 @@ const yachts = [
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function CatalogPage() {
|
export default function CatalogPage() {
|
||||||
|
const [isFiltersOpen, setIsFiltersOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="bg-[#f4f4f4] min-h-screen">
|
<main className="bg-[#f4f4f4] min-h-screen">
|
||||||
<div className="container max-w-6xl mx-auto px-4 py-6">
|
<div className="container max-w-6xl mx-auto px-4 py-6">
|
||||||
{/* Breadcrumbs */}
|
{/* Breadcrumbs - скрыты на мобильных */}
|
||||||
<div className="mb-4 text-sm text-[#999999] flex items-center gap-[16px]">
|
<div className="hidden lg:flex mb-4 text-sm text-[#999999] items-center gap-[16px]">
|
||||||
<Link href="/">
|
<Link href="/">
|
||||||
<span className="cursor-pointer hover:text-[#333333] transition-colors">
|
<span className="cursor-pointer hover:text-[#333333] transition-colors">
|
||||||
Аренда яхты
|
Аренда яхты
|
||||||
|
|
@ -127,21 +132,86 @@ export default function CatalogPage() {
|
||||||
<span className="text-[#333333]">Каталог яхт</span>
|
<span className="text-[#333333]">Каталог яхт</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Мобильная навигационная панель */}
|
||||||
|
<div className="lg:hidden mb-4">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
{/* Кнопка "Назад" */}
|
||||||
|
<Link href="/">
|
||||||
|
<button className="flex-shrink-0 w-8 h-8 flex items-center justify-center">
|
||||||
|
<ArrowLeft
|
||||||
|
size={32}
|
||||||
|
className="text-[#333333] font-bold"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Текстовый блок */}
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<div className="font-bold text-[#333333] text-base truncate">
|
||||||
|
Балаклава
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-[#999999] truncate">
|
||||||
|
Когда? · С кем?
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Кнопка "Фильтры" */}
|
||||||
|
<Button
|
||||||
|
onClick={() => setIsFiltersOpen(true)}
|
||||||
|
className="flex-shrink-0 w-[56px] h-[56px] rounded-full bg-white hover:bg-gray-50 text-black p-0"
|
||||||
|
>
|
||||||
|
<Sliders size={20} className="text-[#333333]" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col lg:flex-row gap-[74px]">
|
<div className="flex flex-col lg:flex-row gap-[74px]">
|
||||||
{/* Sidebar */}
|
{/* Sidebar - скрыт на мобильных, виден на десктопе */}
|
||||||
<div className="w-full lg:w-[260px] flex-shrink-0">
|
<div className="hidden lg:block w-full lg:w-[260px] flex-shrink-0">
|
||||||
<CatalogSidebar />
|
<CatalogSidebar />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Мобильное модальное окно фильтров */}
|
||||||
|
{isFiltersOpen && (
|
||||||
|
<div className="fixed inset-0 z-50 lg:hidden">
|
||||||
|
{/* Overlay */}
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 bg-black/50"
|
||||||
|
onClick={() => setIsFiltersOpen(false)}
|
||||||
|
/>
|
||||||
|
{/* Модальное окно */}
|
||||||
|
<div className="absolute inset-0 bg-white overflow-y-auto">
|
||||||
|
<div className="sticky top-0 bg-white border-b border-gray-200 p-4 flex items-center justify-between z-10">
|
||||||
|
<h2 className="text-lg font-bold text-[#333333]">
|
||||||
|
Фильтры
|
||||||
|
</h2>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
onClick={() => setIsFiltersOpen(false)}
|
||||||
|
className="h-8 w-8"
|
||||||
|
>
|
||||||
|
<X size={20} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="p-4">
|
||||||
|
<CatalogSidebar
|
||||||
|
onApply={() => setIsFiltersOpen(false)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Main Content */}
|
{/* Main Content */}
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-end mb-6 gap-4">
|
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-end mb-6">
|
||||||
<div>
|
<div className="w-full lg:w-auto">
|
||||||
<h1 className="text-2xl md:text-3xl font-bold text-[#333333] mb-4">
|
<h1 className="text-2xl md:text-3xl font-bold text-[#333333] mb-4">
|
||||||
Аренда яхт
|
Аренда яхт
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-lg text-[#333333]">
|
<p className="hidden lg:block text-lg text-[#333333]">
|
||||||
Доступно яхт:{" "}
|
Доступно яхт:{" "}
|
||||||
<span className="text-[#b2b2b2]">
|
<span className="text-[#b2b2b2]">
|
||||||
{yachts.length}
|
{yachts.length}
|
||||||
|
|
|
||||||
|
|
@ -3,126 +3,303 @@
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { User, ArrowUpRight, Map } from "lucide-react";
|
import { User, ArrowUpRight, Map, ArrowLeft, Heart } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
export default function ConfirmPage() {
|
export default function ConfirmPage() {
|
||||||
const [promocode, setPromocode] = useState("");
|
const [promocode, setPromocode] = useState("");
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="bg-[#f4f4f4] grow">
|
<main className="bg-[#f4f4f4] grow">
|
||||||
<div className="container max-w-6xl mx-auto px-4 py-6">
|
{/* Мобильная версия */}
|
||||||
{/* Breadcrumbs */}
|
<div className="lg:hidden">
|
||||||
<div className="mb-6 text-sm text-[#999999] flex items-center gap-[16px]">
|
{/* Верхний блок с навигацией */}
|
||||||
<Link href="/">
|
<div className="bg-white border-b border-[#DFDFDF]">
|
||||||
<span className="cursor-pointer hover:text-[#333333] transition-colors">
|
<div className="container max-w-6xl mx-auto px-4 py-3">
|
||||||
Аренда яхты
|
<div className="flex items-center justify-between gap-4">
|
||||||
</span>
|
{/* Кнопка назад */}
|
||||||
</Link>
|
<button
|
||||||
<span>></span>
|
onClick={() => router.back()}
|
||||||
<span className="text-[#333333]">Ваше бронирование</span>
|
className="flex-shrink-0 w-10 h-10 rounded-full border border-[#DFDFDF] flex items-center justify-center hover:bg-[#f4f4f4] transition-colors"
|
||||||
|
>
|
||||||
|
<ArrowLeft
|
||||||
|
size={20}
|
||||||
|
className="text-[#333333]"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Центральный блок с информацией */}
|
||||||
|
<div className="flex-1 min-w-0 text-center">
|
||||||
|
<h2 className="text-base font-bold text-[#333333] mb-1">
|
||||||
|
Яхта Сеньорита
|
||||||
|
</h2>
|
||||||
|
<div className="flex justify-center gap-10 text-xs text-[#666666]">
|
||||||
|
<span>09 авг.</span>
|
||||||
|
<span>Гостей: 1</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Кнопка избранного */}
|
||||||
|
<button className="flex-shrink-0 w-10 h-10 flex items-center justify-center hover:opacity-70 transition-opacity">
|
||||||
|
<Heart
|
||||||
|
size={20}
|
||||||
|
className="text-[#333333] stroke-2"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col lg:flex-row gap-6">
|
<div className="container max-w-6xl mx-auto">
|
||||||
{/* Левая колонка - Информация о яхте и ценах */}
|
<div className="bg-white p-4">
|
||||||
<div className="w-full lg:w-[336px] flex-shrink-0 flex flex-col gap-6">
|
{/* Заголовок с иконкой */}
|
||||||
<div className="bg-white rounded-[16px]">
|
<div className="flex items-center gap-2 mb-6">
|
||||||
<div className="p-4">
|
<h1 className="text-xl text-[#333333]">
|
||||||
{/* Изображение яхты */}
|
Ваше бронирование 🛥️
|
||||||
<div className="relative mb-5">
|
</h1>
|
||||||
<Image
|
</div>
|
||||||
src="/images/yachts/yacht1.jpg"
|
|
||||||
alt="Яхта"
|
{/* Поля Выход и Заход */}
|
||||||
width={400}
|
<div className="grid grid-cols-2 gap-3 mb-3">
|
||||||
height={250}
|
<div className="relative">
|
||||||
className="w-full h-48 object-cover rounded-[8px]"
|
<label className="absolute -top-2 left-8 px-1 bg-white text-xs text-[#999999]">
|
||||||
/>
|
Выход
|
||||||
{/* Плашка владельца */}
|
</label>
|
||||||
<div className="absolute top-2 left-2">
|
<div className="bg-white rounded-full px-8 py-4 border border-[#DFDFDF]">
|
||||||
<div className="bg-white backdrop-blur-sm px-4 py-2 rounded-[8px] flex items-center gap-2">
|
<div className="text-[#333333]">
|
||||||
<User
|
9 Авг 00:00
|
||||||
size={22}
|
</div>
|
||||||
className="text-[#999999]"
|
</div>
|
||||||
/>
|
</div>
|
||||||
<div className="flex flex-col gap-[4px]">
|
<div className="relative">
|
||||||
<span className="text-[#999999]">
|
<label className="absolute -top-2 left-8 px-1 bg-white text-xs text-[#999999]">
|
||||||
Владелец
|
Заход
|
||||||
|
</label>
|
||||||
|
<div className="bg-white rounded-full px-8 py-4 border border-[#DFDFDF]">
|
||||||
|
<div className="text-[#333333]">
|
||||||
|
9 Авг 02:00
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* По местному времени яхты */}
|
||||||
|
<div className="flex items-center gap-2 text-sm text-[#333333] mb-4">
|
||||||
|
<Map size={16} className="text-[#333333]" />
|
||||||
|
<span>По местному времени яхты</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Гости */}
|
||||||
|
<div className="mb-6">
|
||||||
|
<div className="relative">
|
||||||
|
<label className="absolute -top-2 left-8 px-1 bg-white text-xs text-[#999999]">
|
||||||
|
Гостей
|
||||||
|
</label>
|
||||||
|
<div className="bg-white rounded-full px-8 py-4 border border-[#DFDFDF] flex items-center justify-between">
|
||||||
|
<span className="text-[#333333]">
|
||||||
|
1 гость
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Правила отмены */}
|
||||||
|
<div className="mb-8">
|
||||||
|
<h3 className="text-base font-bold text-[#333333] mb-4">
|
||||||
|
Правила отмены
|
||||||
|
</h3>
|
||||||
|
<p className="text-base text-[#333333]">
|
||||||
|
При отмене до 10 мая вы получите частичный
|
||||||
|
возврат.{" "}
|
||||||
|
<Link
|
||||||
|
href="#"
|
||||||
|
className="text-sm text-[#2D908D] hover:text-[#007088] font-bold transition-colors"
|
||||||
|
>
|
||||||
|
Подробнее
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Детализация цены */}
|
||||||
|
<div className="mb-8">
|
||||||
|
<h3 className="text-base font-bold text-[#333333] mb-4">
|
||||||
|
Детализация цены
|
||||||
|
</h3>
|
||||||
|
<div>
|
||||||
|
<div className="flex justify-between items-center mb-4">
|
||||||
|
<span className="text-[#333333]">
|
||||||
|
26 400₽ x 2ч
|
||||||
|
</span>
|
||||||
|
<span className="text-[#333333]">
|
||||||
|
52 800 ₽
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between items-center mb-4 pb-4 border-b border-[#DFDFDF]">
|
||||||
|
<span className="text-[#333333]">
|
||||||
|
Услуги
|
||||||
|
</span>
|
||||||
|
<span className="text-[#333333]">0 Р</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="text-[#333333]">
|
||||||
|
Итого:
|
||||||
|
</span>
|
||||||
|
<span className="font-bold text-[#333333]">
|
||||||
|
52 800 Р
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Промокод */}
|
||||||
|
<div className="mb-4 pb-6 border-b border-[#DFDFDF]">
|
||||||
|
<div className="w-full flex gap-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Промокод"
|
||||||
|
value={promocode}
|
||||||
|
onChange={(e) =>
|
||||||
|
setPromocode(e.target.value)
|
||||||
|
}
|
||||||
|
className="flex-1 min-w-0 px-4 py-3 h-[64px] border border-[#DFDFDF] rounded-full text-sm text-[#757575] focus:outline-none focus:ring-2 focus:ring-[#008299] focus:border-transparent"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="default"
|
||||||
|
className="flex-shrink-0 h-[64px] w-[64px] bg-[#2D908D] hover:bg-[#007088] text-white rounded-full p-0 transition-colors duration-200"
|
||||||
|
>
|
||||||
|
<ArrowUpRight size={14} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Кнопка отправки заявки */}
|
||||||
|
<Button
|
||||||
|
variant="default"
|
||||||
|
className="w-full h-[56px] bg-[#2D908D] hover:bg-[#007088] text-white font-bold rounded-full transition-colors duration-200"
|
||||||
|
>
|
||||||
|
Отправить заявку
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Десктопная версия */}
|
||||||
|
<div className="hidden lg:block">
|
||||||
|
<div className="container max-w-6xl mx-auto px-4 py-6">
|
||||||
|
{/* Breadcrumbs - скрыты на мобильных */}
|
||||||
|
<div className="hidden lg:flex mb-6 text-sm text-[#999999] items-center gap-[16px]">
|
||||||
|
<Link href="/">
|
||||||
|
<span className="cursor-pointer hover:text-[#333333] transition-colors">
|
||||||
|
Аренда яхты
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
<span>></span>
|
||||||
|
<span className="text-[#333333]">
|
||||||
|
Ваше бронирование
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col lg:flex-row gap-6">
|
||||||
|
{/* Левая колонка - Информация о яхте и ценах - скрыта на мобильных */}
|
||||||
|
<div className="hidden lg:flex w-full lg:w-[336px] flex-shrink-0 flex-col gap-6">
|
||||||
|
<div className="bg-white rounded-[16px]">
|
||||||
|
<div className="p-4">
|
||||||
|
{/* Изображение яхты */}
|
||||||
|
<div className="relative mb-5">
|
||||||
|
<Image
|
||||||
|
src="/images/yachts/yacht1.jpg"
|
||||||
|
alt="Яхта"
|
||||||
|
width={400}
|
||||||
|
height={250}
|
||||||
|
className="w-full h-48 object-cover rounded-[8px]"
|
||||||
|
/>
|
||||||
|
{/* Плашка владельца */}
|
||||||
|
<div className="absolute top-2 left-2">
|
||||||
|
<div className="bg-white backdrop-blur-sm px-4 py-2 rounded-[8px] flex items-center gap-2">
|
||||||
|
<User
|
||||||
|
size={22}
|
||||||
|
className="text-[#999999]"
|
||||||
|
/>
|
||||||
|
<div className="flex flex-col gap-[4px]">
|
||||||
|
<span className="text-[#999999]">
|
||||||
|
Владелец
|
||||||
|
</span>
|
||||||
|
<span className="text-[#333333] font-bold">
|
||||||
|
Денис
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Название яхты */}
|
||||||
|
<h3 className="text-base text-[#333333] pb-3 border-b border-[#DFDFDF] mb-4">
|
||||||
|
Яхта
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
{/* Детализация цены */}
|
||||||
|
<div>
|
||||||
|
<h4 className="text-base font-bold text-[#333333] mb-4">
|
||||||
|
Детализация цены
|
||||||
|
</h4>
|
||||||
|
<div>
|
||||||
|
<div className="flex justify-between items-center mb-4">
|
||||||
|
<span className="text-[#333333]">
|
||||||
|
26 400₽ x 2ч
|
||||||
|
</span>
|
||||||
|
<span className="text-[#333333]">
|
||||||
|
52 800 ₽
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between items-center border-b border-[#DFDFDF] pb-4 mb-4">
|
||||||
|
<span className="text-[#333333]">
|
||||||
|
Услуги
|
||||||
|
</span>
|
||||||
|
<span className="text-[#333333]">
|
||||||
|
0 Р
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="text-[#333333]">
|
||||||
|
Итого:
|
||||||
</span>
|
</span>
|
||||||
<span className="text-[#333333] font-bold">
|
<span className="text-[#333333] font-bold">
|
||||||
Денис
|
52 800 Р
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Название яхты */}
|
</div>
|
||||||
<h3 className="text-base text-[#333333] pb-3 border-b border-[#DFDFDF] mb-4">
|
|
||||||
Яхта
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
{/* Детализация цены */}
|
<div className="bg-white rounded-[16px]">
|
||||||
<div>
|
<div className="p-6">
|
||||||
<h4 className="text-base font-bold text-[#333333] mb-4">
|
{/* Промокод */}
|
||||||
Детализация цены
|
<div className="w-full flex gap-2">
|
||||||
</h4>
|
<input
|
||||||
<div>
|
type="text"
|
||||||
<div className="flex justify-between items-center mb-4">
|
placeholder="Промокод"
|
||||||
<span className="text-[#333333]">
|
value={promocode}
|
||||||
26 400₽ x 2ч
|
onChange={(e) =>
|
||||||
</span>
|
setPromocode(e.target.value)
|
||||||
<span className="text-[#333333]">
|
}
|
||||||
52 800 ₽
|
className="flex-1 min-w-0 px-4 sm:px-8 py-5 h-[64px] border border-[#DFDFDF] rounded-full text-base text-[#757575] focus:outline-none focus:ring-2 focus:ring-[#008299] focus:border-transparent"
|
||||||
</span>
|
/>
|
||||||
</div>
|
<Button
|
||||||
<div className="flex justify-between items-center border-b border-[#DFDFDF] pb-4 mb-4">
|
variant="default"
|
||||||
<span className="text-[#333333]">
|
className="flex-shrink-0 h-[64px] w-[64px] bg-[#2D908D] hover:bg-[#007088] text-white rounded-full p-0 transition-colors duration-200"
|
||||||
Услуги
|
>
|
||||||
</span>
|
<ArrowUpRight size={12} />
|
||||||
<span className="text-[#333333]">
|
</Button>
|
||||||
0 Р
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-between items-center">
|
|
||||||
<span className="text-[#333333]">
|
|
||||||
Итого:
|
|
||||||
</span>
|
|
||||||
<span className="text-[#333333] font-bold">
|
|
||||||
52 800 Р
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-white rounded-[16px]">
|
{/* Правая колонка - Подтверждение бронирования */}
|
||||||
<div className="p-6">
|
<div className="flex-1">
|
||||||
{/* Промокод */}
|
<div className="bg-white rounded-[16px] p-8">
|
||||||
<div className="w-full flex gap-2">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="Промокод"
|
|
||||||
value={promocode}
|
|
||||||
onChange={(e) =>
|
|
||||||
setPromocode(e.target.value)
|
|
||||||
}
|
|
||||||
className="flex-1 min-w-0 px-4 sm:px-8 py-5 h-[64px] border border-[#DFDFDF] rounded-full text-base text-[#757575] focus:outline-none focus:ring-2 focus:ring-[#008299] focus:border-transparent"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
variant="default"
|
|
||||||
className="flex-shrink-0 h-[64px] w-[64px] bg-[#2D908D] hover:bg-[#007088] text-white rounded-full p-0 transition-colors duration-200"
|
|
||||||
>
|
|
||||||
<ArrowUpRight size={12} />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Правая колонка - Подтверждение бронирования */}
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="bg-white rounded-[16px]">
|
|
||||||
<div className="p-8">
|
|
||||||
{/* Заголовок */}
|
{/* Заголовок */}
|
||||||
<h1 className="text-2xl text-[#333333] mb-4">
|
<h1 className="text-2xl text-[#333333] mb-4">
|
||||||
Проверьте данные
|
Проверьте данные
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ export default function Header() {
|
||||||
const [isAuthDialogOpen, setIsAuthDialogOpen] = useState(false);
|
const [isAuthDialogOpen, setIsAuthDialogOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="sticky top-0 z-50 bg-white/95 backdrop-blur-sm border-b border-gray-100">
|
<header className="sticky top-0 z-50 bg-white backdrop-blur-sm border-b border-gray-100">
|
||||||
<div className="w-full max-w-6xl mx-auto">
|
<div className="w-full max-w-6xl mx-auto">
|
||||||
<div className="flex justify-between items-center px-4 sm:px-6 lg:px-8 py-4">
|
<div className="flex justify-between items-center px-4 sm:px-6 lg:px-8 py-4">
|
||||||
{/* Логотип */}
|
{/* Логотип */}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue