feat: complete UI/UX improvements and localization

This commit is contained in:
AyrisAI
2026-07-15 14:42:51 +03:00
parent 2d149f1178
commit a36b833e00
32 changed files with 3667 additions and 348 deletions
+14
View File
@@ -0,0 +1,14 @@
export default function BougainvilleaMotif({ className = "" }: { className?: string }) {
return (
<svg
className={`text-accent opacity-80 ${className}`}
viewBox="0 0 100 100"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M49.9 22.8c-2.3-5.5-8.5-12.7-16-11.2-13.8 2.8-15.5 19.3-7.5 28.5C32.1 46.5 45 47.9 50 51.5c4.9-3.6 17.9-5 23.6-11.4 8-9.2 6.3-25.7-7.5-28.5-7.5-1.5-13.7 5.7-16 11.2zM49.9 77.2c2.3 5.5 8.5 12.7 16 11.2 13.8-2.8 15.5-19.3 7.5-28.5-5.7-6.4-18.7-7.8-23.6-11.4-4.9 3.6-17.9 5-23.6 11.4-8 9.2-6.3 25.7 7.5 28.5 7.5 1.5 13.7-5.7 16-11.2z" />
<path d="M22.8 50.1c-5.5 2.3-12.7 8.5-11.2 16 2.8 13.8 19.3 15.5 28.5 7.5 6.4-5.7 7.8-18.7 11.4-23.6-3.6-4.9-5-17.9-11.4-23.6-9.2-8-25.7-6.3-28.5 7.5-1.5 7.5 5.7 13.7 11.2 16zM77.2 50.1c5.5-2.3 12.7-8.5 11.2-16-2.8-13.8-19.3-15.5-28.5-7.5-6.4 5.7-7.8 18.7-11.4 23.6 3.6 4.9 5 17.9 11.4 23.6 9.2 8 25.7 6.3 28.5-7.5 1.5-7.5-5.7-13.7-11.2-16z" />
<circle cx="50" cy="50" r="4" fill="#FFC107" />
</svg>
)
}
+39
View File
@@ -0,0 +1,39 @@
import { useTranslations } from 'next-intl';
import { Link } from '@/i18n/routing';
export default function Footer() {
const t = useTranslations('footer');
return (
<footer className="border-t bg-gray-50 mt-auto">
<div className="container mx-auto px-4 py-8">
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<div>
<h3 className="font-bold text-lg mb-4 text-[#2FB6C4]">Sitar Apart & Otel</h3>
<p className="text-gray-600 text-sm">
{t('about')}
</p>
</div>
<div>
<h3 className="font-bold text-lg mb-4">{t('contact')}</h3>
<p className="text-gray-600 text-sm mb-2">{t('address_1')}</p>
<p className="text-gray-600 text-sm mb-2">{t('address_2')}</p>
<p className="text-gray-600 text-sm">0 530 510 98 42</p>
</div>
<div>
<h3 className="font-bold text-lg mb-4">{t('quick_links')}</h3>
<ul className="text-gray-600 text-sm space-y-2">
<li><Link href="/dairelerimiz" className="hover:text-[#2FB6C4] transition-colors duration-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#2FB6C4] rounded-sm px-1 cursor-pointer inline-block">{t('quick_links_rooms', { defaultMessage: 'Dairelerimiz' })}</Link></li>
<li><Link href="/galeri" className="hover:text-[#2FB6C4] transition-colors duration-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#2FB6C4] rounded-sm px-1 cursor-pointer inline-block">{t('quick_links_gallery', { defaultMessage: 'Galeri' })}</Link></li>
<li><Link href="/iletisim" className="hover:text-[#2FB6C4] transition-colors duration-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#2FB6C4] rounded-sm px-1 cursor-pointer inline-block">{t('quick_links_contact', { defaultMessage: 'İletişim' })}</Link></li>
</ul>
</div>
</div>
<div className="border-t mt-8 pt-8 flex flex-col md:flex-row justify-between items-center text-sm text-gray-500">
<p>{t('rights')}</p>
<p>Created by <a href="https://ayris.tech" className="text-[#2FB6C4] hover:underline transition-all duration-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#2FB6C4] rounded-sm px-1 cursor-pointer inline-block" target="_blank" rel="noreferrer">ayris.tech</a></p>
</div>
</div>
</footer>
);
}
+172
View File
@@ -0,0 +1,172 @@
'use client'
import { motion } from 'framer-motion'
import { useState, useEffect } from 'react'
import { Link, usePathname } from '@/i18n/routing'
import { useTranslations } from 'next-intl'
import LocaleSwitcher from './LocaleSwitcher'
import { cn } from '@/lib/utils'
import { Menu, X } from 'lucide-react'
export default function Header() {
const [scrolled, setScrolled] = useState(false)
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
const t = useTranslations('nav')
const pathname = usePathname()
const isHome = pathname === '/'
// If we are not on the home page, the header should always look "scrolled"
// so the text is visible against the light background.
const isScrolledOrInner = scrolled || !isHome
useEffect(() => {
const handler = () => setScrolled(window.scrollY > 50)
window.addEventListener('scroll', handler, { passive: true })
// Initialize
handler()
return () => window.removeEventListener('scroll', handler)
}, [])
return (
<motion.header
initial={{ y: -20, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
className={cn(
'fixed top-0 inset-x-0 z-50 transition-all duration-300',
isScrolledOrInner
? 'bg-surface/85 backdrop-blur-md border-b border-outline-variant/20 shadow-sm py-4'
: 'bg-transparent py-6'
)}
>
<div className="max-w-container-max mx-auto px-margin-mobile md:px-gutter">
<div className="flex items-center justify-between">
{/* Logo */}
<Link href="/" className="flex items-center z-50">
<span className={cn(
"font-serif text-2xl md:text-[32px] font-bold tracking-tight italic transition-colors duration-300",
isScrolledOrInner ? "text-secondary" : "text-white"
)}>
Sitar Apart
</span>
</Link>
{/* Desktop Navigation */}
<nav className="hidden md:flex items-center gap-8">
<Link
href="/"
className={cn(
"text-[14px] font-bold tracking-wider uppercase transition-colors duration-300 hover:text-tertiary cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-primary rounded-sm px-1",
isScrolledOrInner ? "text-secondary" : "text-white/90"
)}
>
{t('home')}
</Link>
<Link
href="/dairelerimiz"
className={cn(
"text-[14px] font-bold tracking-wider uppercase transition-colors duration-300 hover:text-tertiary cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-primary rounded-sm px-1",
isScrolledOrInner ? "text-secondary" : "text-white/90"
)}
>
{t('rooms')}
</Link>
<Link
href="/galeri"
className={cn(
"text-[14px] font-bold tracking-wider uppercase transition-colors duration-300 hover:text-tertiary cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-primary rounded-sm px-1",
isScrolledOrInner ? "text-secondary" : "text-white/90"
)}
>
{t('gallery')}
</Link>
<Link
href="/iletisim"
className={cn(
"text-[14px] font-bold tracking-wider uppercase transition-colors duration-300 hover:text-tertiary cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-primary rounded-sm px-1",
isScrolledOrInner ? "text-secondary" : "text-white/90"
)}
>
{t('contact')}
</Link>
</nav>
{/* Desktop Actions */}
<div className="hidden md:flex items-center gap-4">
<LocaleSwitcher scrolled={isScrolledOrInner} />
<Link
href="/iletisim"
className={cn(
"px-6 py-3 rounded-full text-[14px] font-bold tracking-wider uppercase transition-all duration-300 hover:opacity-80 cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2",
isScrolledOrInner
? "bg-accent-pink text-white shadow-md"
: "bg-accent-pink text-white backdrop-blur-md"
)}
>
{t('book_now')}
</Link>
</div>
{/* Mobile Menu Button */}
<button
aria-label="Toggle menu"
className="md:hidden z-50 p-2 cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-primary rounded-md transition-all duration-300"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
>
{mobileMenuOpen ? (
<X className={cn("w-6 h-6", isScrolledOrInner ? "text-secondary" : "text-white")} />
) : (
<Menu className={cn("w-6 h-6", isScrolledOrInner ? "text-secondary" : "text-white")} />
)}
</button>
</div>
</div>
{/* Mobile Menu */}
{mobileMenuOpen && (
<div className="md:hidden absolute top-full left-0 right-0 bg-surface border-b border-outline-variant/20 shadow-lg p-6">
<nav className="flex flex-col gap-6">
<Link
href="/"
onClick={() => setMobileMenuOpen(false)}
className="text-secondary hover:text-tertiary font-bold tracking-wider uppercase text-[14px]"
>
{t('home')}
</Link>
<Link
href="/dairelerimiz"
onClick={() => setMobileMenuOpen(false)}
className="text-secondary hover:text-tertiary font-bold tracking-wider uppercase text-[14px]"
>
{t('rooms')}
</Link>
<Link
href="/galeri"
onClick={() => setMobileMenuOpen(false)}
className="text-secondary hover:text-tertiary font-bold tracking-wider uppercase text-[14px]"
>
{t('gallery')}
</Link>
<Link
href="/iletisim"
onClick={() => setMobileMenuOpen(false)}
className="text-secondary hover:text-tertiary font-bold tracking-wider uppercase text-[14px]"
>
{t('contact')}
</Link>
<div className="pt-6 border-t border-outline-variant/20 flex flex-col gap-4">
<div className="self-end"><LocaleSwitcher scrolled={true} /></div>
<Link
href="/iletisim"
onClick={() => setMobileMenuOpen(false)}
className="bg-accent-pink text-white px-6 py-3 rounded-full text-[14px] font-bold tracking-wider uppercase text-center"
>
{t('book_now')}
</Link>
</div>
</nav>
</div>
)}
</motion.header>
)
}
+39
View File
@@ -0,0 +1,39 @@
'use client'
import { useLocale } from 'next-intl'
import { useRouter, usePathname } from '@/i18n/routing'
import { ChangeEvent } from 'react'
import { cn } from '@/lib/utils'
import { Globe } from 'lucide-react'
export default function LocaleSwitcher({ scrolled }: { scrolled: boolean }) {
const locale = useLocale()
const router = useRouter()
const pathname = usePathname()
const onSelectChange = (e: ChangeEvent<HTMLSelectElement>) => {
const nextLocale = e.target.value
router.replace({ pathname }, { locale: nextLocale as any })
}
return (
<div className="relative flex items-center">
<Globe className={cn(
"w-4 h-4 absolute left-2 pointer-events-none transition-colors",
scrolled ? "text-foreground" : "text-white"
)} />
<select
value={locale}
onChange={onSelectChange}
className={cn(
"appearance-none bg-transparent border-none py-1 pl-8 pr-4 text-sm font-medium focus:ring-0 focus:outline-none cursor-pointer uppercase transition-colors",
scrolled ? "text-foreground" : "text-white"
)}
>
<option value="tr" className="text-foreground">TR</option>
<option value="en" className="text-foreground">EN</option>
<option value="de" className="text-foreground">DE</option>
</select>
</div>
)
}