Files
marmarislocal/app/[locale]/page.tsx
T

255 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { getTranslations, setRequestLocale } from 'next-intl/server'
import { mockDb } from '@/lib/mockDb'
import ListingCard from '@/components/ListingCard'
import { Link } from '@/i18n/routing'
import { Search, MapPin, CheckCircle, ArrowRight } from 'lucide-react'
import LiveSearchInput from '@/components/LiveSearchInput'
import type { Metadata } from 'next'
import { basicMetadata } from '@/lib/seo'
export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }): Promise<Metadata> {
const { locale } = await params
const title =
locale === 'en'
? 'Marmaris Local — Best Local Spots, Hidden From Plain Sight'
: locale === 'ru'
? 'Marmaris Local — Лучшие места, которые знают местные'
: 'Marmaris Local — Turistin Göremediği Yerel Adresler'
const description =
locale === 'en'
? "Discover Marmaris' best restaurants, apart hotels and local businesses — curated and locally approved, not tourist traps."
: locale === 'ru'
? 'Лучшие рестораны, апарт-отели и заведения Мармариса — подборка, проверенная местными жителями.'
: "Marmaris'in turistin göremediği en iyi restoranları, apart otelleri ve yerel işletmeleri — yerel onaylı, güvenilir rehber."
return basicMetadata(title, description)
}
export default async function HomePage({ params }: { params: Promise<{ locale: string }> }) {
const { locale } = await params
setRequestLocale(locale)
const t = await getTranslations('hero')
const homeT = await getTranslations('home')
const navT = await getTranslations('nav')
// Get active listings and filter for featured (Local Approved)
const allListings = await mockDb.getListings()
const featuredListings = allListings.filter(l => l.isLocalApproved).slice(0, 3)
const categories = await mockDb.getCategories()
const neighborhoods = await mockDb.getNeighborhoods()
// Get localized names
const getLocalizedName = (obj: any) => {
if (!obj) return ''
return locale === 'ru' ? obj.nameRu : locale === 'en' ? obj.nameEn : obj.nameTr
}
// Map category slug to lucide icons or nice visual cues
const categoryImages: Record<string, string> = {
restoran: 'https://images.unsplash.com/photo-1555396273-367ea4eb4db5?w=800&auto=format&fit=crop&q=80',
apart: 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=800&auto=format&fit=crop&q=80',
isletme: 'https://images.unsplash.com/photo-1544551763-46a013bb70d5?w=800&auto=format&fit=crop&q=80'
}
return (
<div className="flex-1 flex flex-col min-h-screen bg-stone text-ink">
{/* Hero Section */}
<section className="bg-pine text-stone pt-20 pb-24 relative overflow-hidden">
{/* Decorative background shapes */}
<div className="absolute inset-0 opacity-5 pointer-events-none">
<div className="absolute -top-40 -right-40 w-96 h-96 rounded-full bg-turquoise blur-3xl" />
<div className="absolute -bottom-45 -left-40 w-96 h-96 rounded-full bg-bougainvillea blur-3xl" />
</div>
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center relative z-10 space-y-8">
{/* Logo stamp effect */}
<div className="flex justify-center">
<div className="w-16 h-16 rounded-full border-2 border-stone/30 flex items-center justify-center relative bg-white/5 backdrop-blur-sm -rotate-6">
<div className="absolute inset-[3.5px] rounded-full border border-dashed border-turquoise/50" />
<span className="font-heading font-extrabold text-stone text-lg tracking-tighter">ML</span>
</div>
</div>
<h1 className="font-heading font-extrabold text-3xl sm:text-5xl lg:text-6xl text-stone leading-tight tracking-tight max-w-3xl mx-auto lowercase">
{locale === 'tr' && (
<>En iyi yerel adresler,<br /><span className="text-turquoise">turistin göremediği yerde.</span></>
)}
{locale === 'en' && (
<>The best local spots,<br /><span className="text-turquoise">hidden from plain sight.</span></>
)}
{locale === 'ru' && (
<>Лучшие места,<br /><span className="text-turquoise">которые знают местные.</span></>
)}
</h1>
<p className="text-sm sm:text-base text-stone/70 max-w-xl mx-auto font-medium">
{t('subtitle')}
</p>
{/* Search Form */}
<form
action={`/${locale}/${categories[0]?.slug || 'restoran'}`}
method="GET"
className="max-w-xl mx-auto bg-paper p-2 rounded-2xl flex items-center shadow-lg border border-white/10"
>
<LiveSearchInput placeholder={t('searchPlaceholder')} />
<button
type="submit"
className="bg-turquoise hover:bg-turquoise/90 text-paper font-medium text-xs px-5 py-3 rounded-xl transition"
>
{t('cta')}
</button>
</form>
{/* Local Approved Banner */}
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-white/5 border border-white/10 text-xs">
<span className="inline-block w-2.5 h-2.5 rounded-full bg-turquoise animate-pulse" />
<span className="font-semibold text-turquoise">{t('approvedBadge')}</span>
<span className="text-stone/60">mührü ile güvenli rehber</span>
</div>
</div>
</section>
{/* Category Grid Section */}
<section className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20">
<div className="text-center mb-12">
<h3 className="text-2xl sm:text-3xl font-heading font-extrabold text-pine lowercase">
{homeT('categories')}
</h3>
<p className="text-sm text-ink/65 mt-2 font-medium">
{homeT('categoriesSubtitle')}
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{categories.map((cat) => {
const imageUrl = categoryImages[cat.slug] || categoryImages.isletme
const path = `/${cat.slug}`
const catName = getLocalizedName(cat)
return (
<Link
key={cat.id}
href={path}
className="group relative h-64 rounded-2xl overflow-hidden shadow-sm hover:shadow-md transition duration-300 border border-pine/5 flex items-end p-6"
>
<div className="absolute inset-0">
<img
src={imageUrl}
alt={catName}
className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105"
/>
<div className="absolute inset-0 bg-gradient-to-t from-pine/90 via-pine/30 to-transparent" />
</div>
<div className="relative z-10 space-y-1">
<h4 className="font-heading font-extrabold text-xl text-stone group-hover:text-turquoise transition-colors lowercase">
{catName}
</h4>
<div className="flex items-center gap-1 text-[11px] font-mono text-turquoise">
<span>{homeT('explore')}</span>
<ArrowRight className="w-3.5 h-3.5 group-hover:translate-x-1 transition-transform" />
</div>
</div>
</Link>
)
})}
</div>
</section>
{/* Local Approved Featured Section */}
<section className="bg-stone-deep py-20 border-t border-b border-pine/5">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex flex-col sm:flex-row sm:items-end justify-between mb-12 gap-4">
<div>
<div className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full border border-turquoise/20 bg-turquoise/5 text-[10px] font-mono text-turquoise font-semibold uppercase tracking-wider mb-3">
{t('approvedBadge')}
</div>
<h3 className="text-2xl sm:text-3xl font-heading font-extrabold text-pine lowercase">
{homeT('featured')}
</h3>
<p className="text-sm text-ink/65 mt-2 font-medium">
{homeT('featuredSubtitle')}
</p>
</div>
<Link
href={`/${categories[0]?.slug || 'restoran'}?approved=true`}
className="flex items-center gap-1 text-xs font-bold text-pine hover:text-turquoise transition-colors border-b border-pine/20 hover:border-turquoise pb-1 w-fit"
>
<span>{locale === 'tr' ? 'tüm onaylı mekanlar' : locale === 'en' ? 'all approved places' : 'все проверенные места'}</span>
<ArrowRight className="w-3.5 h-3.5" />
</Link>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
{featuredListings.map((listing) => (
<ListingCard key={listing.id} listing={listing} />
))}
</div>
</div>
</section>
{/* Neighborhoods Section */}
<section className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20">
<div className="text-center mb-12">
<h3 className="text-2xl sm:text-3xl font-heading font-extrabold text-pine lowercase">
{homeT('neighborhoods')}
</h3>
<p className="text-sm text-ink/65 mt-2 font-medium">
{homeT('neighborhoodsSubtitle')}
</p>
</div>
<div className="grid grid-cols-2 md:grid-cols-5 gap-4">
{neighborhoods.map((neigh) => {
const name = getLocalizedName(neigh)
return (
<Link
key={neigh.id}
href={`/neighborhood/${neigh.slug}`}
className="bg-paper p-5 rounded-xl border border-pine/8 text-center hover:border-turquoise/40 hover:bg-paper/90 transition shadow-sm group flex flex-col items-center gap-2"
>
<MapPin className="w-5 h-5 text-shutter group-hover:text-turquoise transition-colors" />
<span className="font-heading font-bold text-xs text-pine lowercase group-hover:text-turquoise transition-colors">
{name}
</span>
</Link>
)
})}
</div>
</section>
{/* Trust Badge Explainer */}
<section className="bg-pine text-stone py-16 border-t border-white/5">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center space-y-6">
<div className="flex justify-center">
<div className="w-14 h-14 rounded-full border-2 border-turquoise flex items-center justify-center relative bg-paper -rotate-6">
<div className="absolute inset-[2px] rounded-full border border-dashed border-turquoise/60" />
<span className="font-mono text-[8px] text-center font-bold text-turquoise tracking-tight leading-none uppercase">
YEREL<br />ONAYLI
</span>
</div>
</div>
<h3 className="text-xl sm:text-2xl font-heading font-extrabold lowercase">
yerel onay mührü nedir?
</h3>
<p className="text-xs sm:text-sm text-stone/70 max-w-xl mx-auto font-medium leading-relaxed">
{t('approvedExplain')}
</p>
</div>
</section>
</div>
)
}