first commit
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
"use client";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
import { motion } from "framer-motion";
|
||||
import { mockData } from "@/lib/mock-data";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
|
||||
export function Hero() {
|
||||
const t = useTranslations("hero");
|
||||
|
||||
return (
|
||||
<>
|
||||
<section
|
||||
className="relative h-[921px] min-h-[600px] w-full overflow-hidden"
|
||||
aria-label="Hero Section"
|
||||
>
|
||||
{/* Background Image - Using Next.js Image for optimization */}
|
||||
<div className="absolute inset-0 z-0">
|
||||
<motion.div
|
||||
initial={{ scale: 1.05 }}
|
||||
animate={{ scale: 1 }}
|
||||
transition={{ duration: 15, ease: "easeOut" }}
|
||||
style={{ willChange: "transform" }}
|
||||
className="relative w-full h-full motion-reduce:!transform-none"
|
||||
>
|
||||
<Image
|
||||
src={mockData.heroSlides[1]}
|
||||
alt="Kordon Apart - Fethiye Marina manzarası"
|
||||
fill
|
||||
className="object-cover object-[center_top]"
|
||||
priority
|
||||
sizes="100vw"
|
||||
/>
|
||||
</motion.div>
|
||||
{/* Gradient Overlay */}
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-[#002045]/80 via-[#002045]/50 to-[#002045]/90" />
|
||||
</div>
|
||||
|
||||
{/* Hero Content */}
|
||||
<div className="relative z-10 h-full max-w-7xl mx-auto px-4 md:px-12 flex flex-col justify-center items-start pt-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8, delay: 0.2 }}
|
||||
className="max-w-2xl motion-reduce:!transform-none motion-reduce:!opacity-100"
|
||||
>
|
||||
<span className="font-label-sm text-[12px] text-white/80 uppercase tracking-widest mb-4 block font-bold">
|
||||
{t("subtitle")}
|
||||
</span>
|
||||
<h1 className="font-heading text-5xl md:text-6xl lg:text-7xl text-white mb-6 leading-tight font-extrabold tracking-tight">
|
||||
{t("title")}
|
||||
</h1>
|
||||
<p className="font-body-lg text-lg text-white/90 mb-8 max-w-lg leading-relaxed" style={{ maxWidth: "65ch" }}>
|
||||
{t("desc")}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<Link
|
||||
href="#"
|
||||
className="bg-[#CA8A04] text-white px-8 py-4 rounded-lg font-label-sm uppercase tracking-widest text-[12px] hover:bg-[#CA8A04]/90 transition-colors duration-200 shadow-lg cursor-pointer focus:ring-2 focus:ring-[#CA8A04]/50 focus:outline-none min-h-[48px] flex items-center"
|
||||
role="button"
|
||||
>
|
||||
{t("explore")}
|
||||
</Link>
|
||||
<Link
|
||||
href="#"
|
||||
className="bg-white/10 backdrop-blur-md border border-white/20 text-white px-8 py-4 rounded-lg font-label-sm uppercase tracking-widest text-[12px] hover:bg-white/20 transition-colors duration-200 cursor-pointer focus:ring-2 focus:ring-white/50 focus:outline-none min-h-[48px] flex items-center"
|
||||
role="button"
|
||||
>
|
||||
{t("virtualTour")}
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Search Bar Utility (Floating over Hero bottom) */}
|
||||
<div className="relative z-20 max-w-5xl mx-auto px-4 -mt-24 hidden md:block">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 40 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.5 }}
|
||||
className="bg-white p-8 rounded-xl shadow-2xl shadow-black/10 grid grid-cols-4 gap-6 items-end border border-gray-100 motion-reduce:!transform-none motion-reduce:!opacity-100"
|
||||
>
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="check-in" className="block font-label-sm text-[12px] text-gray-500 uppercase tracking-widest">{t("checkIn")}</label>
|
||||
<input id="check-in" className="w-full bg-transparent border-0 border-b border-gray-200 py-2 focus:ring-0 focus:border-gray-900 transition-colors duration-200 text-gray-900 cursor-pointer min-h-[44px]" type="date" />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="check-out" className="block font-label-sm text-[12px] text-gray-500 uppercase tracking-widest">{t("checkOut")}</label>
|
||||
<input id="check-out" className="w-full bg-transparent border-0 border-b border-gray-200 py-2 focus:ring-0 focus:border-gray-900 transition-colors duration-200 text-gray-900 cursor-pointer min-h-[44px]" type="date" />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="guests" className="block font-label-sm text-[12px] text-gray-500 uppercase tracking-widest">{t("guests")}</label>
|
||||
<select id="guests" className="w-full bg-transparent border-0 border-b border-gray-200 py-2 focus:ring-0 focus:border-gray-900 transition-colors duration-200 text-gray-900 cursor-pointer min-h-[44px]">
|
||||
<option value="1">{t("adult1")}</option>
|
||||
<option value="2">{t("adult2")}</option>
|
||||
<option value="3+">{t("adult3")}</option>
|
||||
</select>
|
||||
</div>
|
||||
<button className="bg-[#CA8A04] text-white min-h-[48px] rounded-lg font-label-sm uppercase tracking-widest text-[12px] hover:bg-[#CA8A04]/90 transition-colors duration-200 font-bold cursor-pointer shadow-lg focus:ring-2 focus:ring-[#CA8A04]/50 focus:outline-none">
|
||||
{t("checkAvailability")}
|
||||
</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
"use client";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
export function Newsletter() {
|
||||
const t = useTranslations("newsletter");
|
||||
|
||||
return (
|
||||
<section className="py-24 bg-[#002045] text-white overflow-hidden relative" aria-label={t("title")}>
|
||||
{/* Decorative Background Elements */}
|
||||
<div className="absolute top-0 left-0 w-full h-full overflow-hidden z-0" aria-hidden="true">
|
||||
<div className="absolute -top-[20%] -left-[10%] w-[50%] h-[150%] bg-white/5 blur-3xl transform rotate-12 rounded-full" />
|
||||
<div className="absolute -bottom-[20%] -right-[10%] w-[50%] h-[150%] bg-[#CA8A04]/10 blur-3xl transform -rotate-12 rounded-full" />
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-50px" }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="max-w-7xl mx-auto px-4 md:px-12 relative z-10 text-center motion-reduce:!transform-none motion-reduce:!opacity-100"
|
||||
>
|
||||
<h2 className="font-heading text-4xl md:text-5xl text-white mb-6 font-bold tracking-tight">
|
||||
{t("title")}
|
||||
</h2>
|
||||
<p className="font-body-lg text-lg text-white/70 mb-10 max-w-xl mx-auto" style={{ maxWidth: "65ch" }}>
|
||||
{t("desc")}
|
||||
</p>
|
||||
|
||||
<form className="max-w-md mx-auto flex flex-col md:flex-row gap-4" onSubmit={(e) => e.preventDefault()}>
|
||||
<label htmlFor="newsletter-email" className="sr-only">{t("label")}</label>
|
||||
<input
|
||||
id="newsletter-email"
|
||||
className="flex-1 bg-white/10 border border-white/20 text-white placeholder-white/40 rounded-lg px-6 py-4 focus:ring-2 focus:ring-[#CA8A04]/50 focus:border-[#CA8A04] outline-none transition-colors duration-200 min-h-[48px]"
|
||||
placeholder={t("placeholder")}
|
||||
type="email"
|
||||
required
|
||||
autoComplete="email"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-[#CA8A04] text-white px-8 py-4 rounded-lg font-label-sm text-[12px] uppercase tracking-widest font-bold hover:bg-[#CA8A04]/90 transition-colors duration-200 shadow-lg cursor-pointer focus:ring-2 focus:ring-[#CA8A04]/50 focus:outline-none min-h-[48px]"
|
||||
>
|
||||
{t("subscribe")}
|
||||
</button>
|
||||
</form>
|
||||
</motion.div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
"use client";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
import { mockData } from "@/lib/mock-data";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { motion } from "framer-motion";
|
||||
import { ArrowRight } from "lucide-react";
|
||||
|
||||
export function RoomList() {
|
||||
const t = useTranslations("accommodations");
|
||||
|
||||
// We take the first 3 rooms for the bento grid
|
||||
const featuredRoom = mockData.accommodations[0];
|
||||
const sideRooms = mockData.accommodations.slice(1, 3);
|
||||
|
||||
return (
|
||||
<section className="py-24 max-w-7xl mx-auto px-4 md:px-12" aria-label="Odalarımız">
|
||||
<div className="flex justify-between items-end mb-12">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="space-y-2 motion-reduce:!transform-none motion-reduce:!opacity-100"
|
||||
>
|
||||
<h2 className="font-heading text-3xl md:text-4xl font-bold text-primary dark:text-primary-fixed-dim">{t("title")}</h2>
|
||||
<p className="font-body-md text-on-surface-variant dark:text-outline text-lg" style={{ maxWidth: "65ch" }}>{t("desc")}</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="motion-reduce:!transform-none motion-reduce:!opacity-100"
|
||||
>
|
||||
<Link href="/odalar" className="font-label-sm text-[12px] uppercase tracking-widest text-primary dark:text-primary-fixed-dim flex items-center gap-2 group font-bold cursor-pointer focus:ring-2 focus:ring-primary/30 focus:outline-none rounded-md px-2 py-1 min-h-[44px]">
|
||||
{t("viewAll")}
|
||||
<ArrowRight className="w-4 h-4 group-hover:translate-x-1 transition-transform duration-200" />
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Bento-style Grid */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="grid grid-cols-1 md:grid-cols-12 gap-6 h-auto md:h-[600px] motion-reduce:!transform-none motion-reduce:!opacity-100"
|
||||
>
|
||||
<Link
|
||||
href={`/odalar/${featuredRoom.slug}`}
|
||||
className="md:col-span-8 group relative overflow-hidden rounded-xl cursor-pointer focus:ring-2 focus:ring-primary/50 focus:outline-none"
|
||||
aria-label={`${featuredRoom.name} - ${featuredRoom.type}`}
|
||||
>
|
||||
<div className="relative w-full h-full min-h-[300px]">
|
||||
<Image
|
||||
src={featuredRoom.image}
|
||||
alt={`${featuredRoom.name} - ${featuredRoom.type} oda görseli`}
|
||||
fill
|
||||
className="object-cover transition-transform duration-500 group-hover:scale-105"
|
||||
sizes="(max-width: 768px) 100vw, 66vw"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-[#002045]/90 via-[#002045]/20 to-transparent opacity-80" />
|
||||
|
||||
<div className="absolute bottom-0 left-0 p-8 text-white w-full">
|
||||
<div className="flex gap-2 mb-3">
|
||||
<span className="bg-[#CA8A04] text-white px-3 py-1 rounded-full font-label-sm text-[10px] uppercase font-bold tracking-wider">
|
||||
{t("bestseller")}
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="font-heading text-3xl md:text-4xl font-bold mb-2">{featuredRoom.name}</h3>
|
||||
<p className="font-body-md text-white/80 text-lg">
|
||||
{featuredRoom.type} • {t("bedrooms", { count: featuredRoom.bedrooms })} • {t("persons", { count: featuredRoom.capacity })}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
{/* Side Stacked Items */}
|
||||
<div className="md:col-span-4 grid grid-rows-2 gap-6">
|
||||
{sideRooms.map((room) => (
|
||||
<Link
|
||||
href={`/odalar/${room.slug}`}
|
||||
key={room.id}
|
||||
className="group relative overflow-hidden rounded-xl cursor-pointer focus:ring-2 focus:ring-primary/50 focus:outline-none"
|
||||
aria-label={`${room.name} - ${room.type}`}
|
||||
>
|
||||
<div className="relative w-full h-full min-h-[150px]">
|
||||
<Image
|
||||
src={room.image}
|
||||
alt={`${room.name} - ${room.type} oda görseli`}
|
||||
fill
|
||||
className="object-cover transition-transform duration-500 group-hover:scale-105"
|
||||
sizes="(max-width: 768px) 100vw, 33vw"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-[#002045]/80 to-transparent opacity-90" />
|
||||
<div className="absolute bottom-0 left-0 p-6 text-white w-full">
|
||||
<h4 className="font-label-sm text-[12px] uppercase tracking-wider font-bold text-[#CA8A04] mb-1">{room.type}</h4>
|
||||
<h3 className="font-heading text-xl font-semibold mb-1">{room.name}</h3>
|
||||
<p className="font-body-md text-white/80 text-sm">
|
||||
{t("persons", { count: room.capacity })}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
"use client";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
import { motion } from "framer-motion";
|
||||
import { Waves, UtensilsCrossed, ConciergeBell } from "lucide-react";
|
||||
|
||||
export function Services() {
|
||||
const t = useTranslations("services");
|
||||
|
||||
const container = {
|
||||
hidden: { opacity: 0 },
|
||||
show: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
staggerChildren: 0.15,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const item = {
|
||||
hidden: { opacity: 0, y: 20 },
|
||||
show: { opacity: 1, y: 0, transition: { duration: 0.5, ease: "easeOut" } }
|
||||
};
|
||||
|
||||
const services = [
|
||||
{
|
||||
icon: Waves,
|
||||
title: t("service1_title"),
|
||||
desc: t("service1_desc"),
|
||||
},
|
||||
{
|
||||
icon: UtensilsCrossed,
|
||||
title: t("service2_title"),
|
||||
desc: t("service2_desc"),
|
||||
},
|
||||
{
|
||||
icon: ConciergeBell,
|
||||
title: t("service3_title"),
|
||||
desc: t("service3_desc"),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="bg-surface-container-low dark:bg-inverse-surface/50 py-24" aria-label="Hizmetlerimiz">
|
||||
<div className="max-w-7xl mx-auto px-4 md:px-12">
|
||||
<div className="text-center max-w-2xl mx-auto mb-16">
|
||||
<motion.span
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className="font-label-sm text-[12px] text-[#CA8A04] dark:text-[#F8BC4B] uppercase tracking-widest mb-4 block font-bold motion-reduce:!transform-none motion-reduce:!opacity-100"
|
||||
>
|
||||
{t("subtitle")}
|
||||
</motion.span>
|
||||
<motion.h2
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: 0.1 }}
|
||||
className="font-heading text-4xl text-primary dark:text-primary-fixed-dim mb-4 font-bold motion-reduce:!transform-none motion-reduce:!opacity-100"
|
||||
>
|
||||
{t("title")}
|
||||
</motion.h2>
|
||||
<motion.p
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: 0.2 }}
|
||||
className="font-body-md text-on-surface-variant dark:text-outline text-lg motion-reduce:!transform-none motion-reduce:!opacity-100"
|
||||
style={{ maxWidth: "65ch", margin: "0 auto" }}
|
||||
>
|
||||
{t("desc")}
|
||||
</motion.p>
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
variants={container}
|
||||
initial="hidden"
|
||||
whileInView="show"
|
||||
viewport={{ once: true, margin: "-50px" }}
|
||||
className="grid grid-cols-1 md:grid-cols-3 gap-12"
|
||||
role="list"
|
||||
>
|
||||
{services.map((service) => (
|
||||
<motion.div
|
||||
variants={item}
|
||||
key={service.title}
|
||||
className="text-center space-y-6 px-4 motion-reduce:!transform-none motion-reduce:!opacity-100"
|
||||
role="listitem"
|
||||
>
|
||||
<div className="w-20 h-20 bg-white dark:bg-primary-container rounded-full flex items-center justify-center mx-auto shadow-md text-primary dark:text-primary-fixed-dim" aria-hidden="true">
|
||||
<service.icon className="w-8 h-8" strokeWidth={1.5} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-heading text-2xl text-primary dark:text-primary-fixed-dim mb-3 font-semibold">{service.title}</h3>
|
||||
<p className="font-body-md text-on-surface-variant dark:text-outline leading-relaxed" style={{ maxWidth: "45ch", margin: "0 auto" }}>
|
||||
{service.desc}
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user