Files

447 lines
31 KiB
TypeScript

'use client'
import Link from 'next/link'
import Image from 'next/image'
import { usePathname } from 'next/navigation'
import { BadgeCheck, BriefcaseBusiness, Gauge, Info, Menu, PhoneCall, ShieldCheck, Sparkles, Store, X } from 'lucide-react'
import { Button } from '@/components/ui/button'
import React from 'react'
import { cn } from '@/lib/utils'
import { useScroll } from 'motion/react'
import { useContent } from '@/components/layout/content-provider'
import { AnimatePresence, motion } from 'framer-motion'
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
} from '@/components/ui/navigation-menu'
function isRouteActive(pathname: string, href: string): boolean {
if (href === '/') return pathname === '/'
return pathname === href || pathname.startsWith(`${href}/`)
}
const HOME_HREF = '/'
export const HeroHeaderTailark = () => {
const [menuState, setMenuState] = React.useState(false)
const [scrolled, setScrolled] = React.useState(false)
const pathname = usePathname() ?? ''
const content = useContent()
const { header } = content.navigation
const { images } = content
const menuItems = header.menuItems
const productItems = header.productItems
const wordmark = header.wordmark ?? content.meta.siteName
const homeItem = menuItems.find((i) => i.href === HOME_HREF)
const trailItems = menuItems.filter((i) => i.href !== HOME_HREF)
const productMenuItems = productItems.map((item, index) => ({
...item,
icon: [Sparkles, Gauge, ShieldCheck][index] ?? BadgeCheck,
}))
const solutionMenuItems = [
{
name: 'درباره ما',
href: '/about',
description: 'آشنایی با چشم انداز، تجربه و مسیر توسعه مستر دکور',
icon: Info,
},
{
name: 'تماس با ما',
href: '/contact',
description: 'ارتباط مستقیم با تیم برای دریافت پاسخ سریع',
icon: PhoneCall,
},
{
name: 'مشاوره و قیمت',
href: '/consultation',
description: 'بررسی دقیق نیاز شما و پیشنهاد مسیر اجرایی مناسب',
icon: BriefcaseBusiness,
},
]
const { scrollYProgress } = useScroll()
React.useEffect(() => {
const unsubscribe = scrollYProgress.on('change', (latest) => {
setScrolled(latest > 0.05)
})
return () => unsubscribe()
}, [scrollYProgress])
return (
<header className="pt-[env(safe-area-inset-top)]">
<nav
data-state={menuState && 'active'}
className={cn(
'fixed z-[100] w-full border-b transition-[background-color,box-shadow] duration-200',
scrolled
? 'border-border/80 bg-background/90 shadow-sm shadow-black/5 backdrop-blur-xl'
: 'border-transparent bg-background/70 backdrop-blur-md'
)}>
<div className="mx-auto max-w-7xl px-4 sm:px-6">
<div className="relative flex min-h-[3.5rem] flex-wrap items-center justify-between gap-3 py-2.5 lg:min-h-0 lg:flex-nowrap lg:py-3">
<div className="flex w-full min-w-0 flex-1 items-center gap-2 lg:w-auto lg:flex-initial">
<button
type="button"
onClick={() => setMenuState(!menuState)}
aria-label={menuState ? 'بستن منو' : 'باز کردن منو'}
className="relative z-20 -m-1.5 flex size-10 shrink-0 items-center justify-center rounded-full border border-transparent hover:bg-accent/60 lg:hidden">
<AnimatePresence mode="wait">
{menuState ? (
<motion.span
key="close"
initial={{ rotate: -90, opacity: 0 }}
animate={{ rotate: 0, opacity: 1 }}
exit={{ rotate: 90, opacity: 0 }}
transition={{ duration: 0.2 }}
className="inline-flex">
<X className="size-5" />
</motion.span>
) : (
<motion.span
key="menu"
initial={{ rotate: 90, opacity: 0 }}
animate={{ rotate: 0, opacity: 1 }}
exit={{ rotate: -90, opacity: 0 }}
transition={{ duration: 0.2 }}
className="inline-flex">
<Menu className="size-5" />
</motion.span>
)}
</AnimatePresence>
</button>
<Link
href="/"
className="flex min-w-0 shrink items-center gap-2.5 rounded-xl py-1 pe-1 ps-0 transition-opacity hover:opacity-90"
aria-label={wordmark}>
<Image
src={images.logo}
alt={header.logoAlt}
width={180}
height={60}
className="mx-auto h-9 w-auto object-contain object-center sm:h-10"
priority
/>
<span className="hidden truncate text-start text-base font-semibold tracking-tight text-foreground sm:inline md:text-lg">
{wordmark}
</span>
</Link>
</div>
<div className="order-last hidden w-full justify-center lg:order-none lg:flex lg:w-auto lg:flex-1 lg:justify-center">
<NavigationMenu
dir="rtl"
className="mx-auto"
>
<NavigationMenuList className="gap-3">
{homeItem ? (
<NavigationMenuItem>
<NavigationMenuLink
asChild
className={cn(
'inline-flex h-8 w-max items-center justify-center rounded-md px-4 py-1 text-body-sm font-medium transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1',
isRouteActive(pathname, homeItem.href)
? 'bg-foreground/5 text-foreground'
: 'text-muted-foreground hover:bg-foreground/5 hover:text-foreground'
)}
>
<Link href={homeItem.href}>{homeItem.name}</Link>
</NavigationMenuLink>
</NavigationMenuItem>
) : null}
<NavigationMenuItem >
<NavigationMenuTrigger
className={cn(
'inline-flex h-8 w-max items-center justify-center rounded-md px-4 py-1 text-body-sm font-medium transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1',
pathname.startsWith('/product')
? 'bg-foreground/5 text-foreground'
: 'text-muted-foreground hover:bg-foreground/5 hover:text-foreground',
)}
>
{header.productsLabel}
</NavigationMenuTrigger>
<NavigationMenuContent className="p-3" dir="rtl">
<div className="grid gap-3 lg:grid-cols-3 w-[75rem] max-w-[calc(100vw-2rem)]">
<div className="space-y-2 lg:col-span-2">
<div className="px-2">
<p className="text-caption font-medium text-muted-foreground">محصولات</p>
</div>
<ul className="grid gap-1 sm:grid-cols-2">
{productMenuItems.map((product) => {
const Icon = product.icon
return (
<li key={`${product.name}-${product.href}`}>
<NavigationMenuLink asChild>
<Link
href={product.href}
className="flex items-start gap-3 rounded-xl border border-transparent px-3 py-3 text-start transition-colors hover:border-border/80 hover:bg-accent/60"
>
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-muted">
<Icon className="h-4 w-4 text-muted-foreground" />
</span>
<span className="space-y-0.5">
<span className="block text-body-sm font-medium text-foreground">{product.name}</span>
<span className="block text-caption leading-snug text-muted-foreground">{product.description}</span>
</span>
</Link>
</NavigationMenuLink>
</li>
)
})}
</ul>
</div>
<Link
href="/product"
className="group relative hidden overflow-hidden rounded-2xl border border-border bg-card lg:block"
>
<Image
src="/assets/main-pic/product/sampleghaleb.png"
alt="نمای کلی محصولات"
width={600}
height={760}
className="h-full w-full object-cover transition-transform duration-300 group-hover:scale-[1.02]"
/>
<div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-background/90 to-transparent p-4">
<p className="text-body-sm font-medium text-foreground">اکوسیستم یکپارچه محصولات</p>
<p className="mt-1 text-caption text-muted-foreground">برای مشاهده جزئیات کامل همه محصولات کلیک کنید</p>
</div>
<span className="absolute start-3 top-3 inline-flex items-center rounded-full bg-background/90 px-2 py-1 text-caption font-medium text-foreground">
<Store className="me-1 h-3.5 w-3.5" />
{productMenuItems.length} محصول
</span>
</Link>
</div>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink
asChild
className={cn(
'inline-flex h-8 w-max items-center justify-center rounded-md px-4 py-1 text-body-sm font-medium transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1',
isRouteActive(pathname, '/after-sales')
? 'bg-foreground/5 text-foreground'
: 'text-muted-foreground hover:bg-foreground/5 hover:text-foreground'
)}
>
<Link href="/after-sales">خدمات پس از فروش</Link>
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink
asChild
className={cn(
'inline-flex h-8 w-max items-center justify-center rounded-md px-4 py-1 text-body-sm font-medium transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1',
isRouteActive(pathname, '/warranty')
? 'bg-foreground/5 text-foreground'
: 'text-muted-foreground hover:bg-foreground/5 hover:text-foreground'
)}
>
<Link href="/warranty">گارانتی</Link>
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink
asChild
className={cn(
'inline-flex h-8 w-max items-center justify-center rounded-md px-4 py-1 text-body-sm font-medium transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1',
isRouteActive(pathname, '/faq')
? 'bg-foreground/5 text-foreground'
: 'text-muted-foreground hover:bg-foreground/5 hover:text-foreground'
)}
>
<Link href="/faq">سوالات متداول</Link>
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem >
<NavigationMenuTrigger className="inline-flex h-8 w-max items-center justify-center rounded-md px-4 py-1 text-body-sm font-medium text-muted-foreground transition-[color,box-shadow] hover:bg-foreground/5 hover:text-foreground focus-visible:ring-[3px] focus-visible:outline-1">
پیوند ها
</NavigationMenuTrigger>
<NavigationMenuContent className="p-3" dir="rtl">
<div className="grid gap-3 lg:grid-cols-3 w-[75rem] max-w-[calc(100vw-2rem)]">
<div className="space-y-2 lg:col-span-2">
<div className="px-2">
<p className="text-caption font-medium text-muted-foreground">منوی اصلی</p>
</div>
<ul className="grid gap-1 sm:grid-cols-2">
{solutionMenuItems.map((item) => {
const Icon = item.icon
const active = isRouteActive(pathname, item.href)
return (
<li key={item.href}>
<NavigationMenuLink asChild>
<Link
href={item.href}
className={cn(
'flex items-start gap-3 rounded-xl border border-transparent px-3 py-3 text-start transition-colors hover:border-border/80 hover:bg-accent/60',
active && 'border-border/80 bg-accent/60'
)}
>
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-muted">
<Icon className="h-4 w-4 text-muted-foreground" />
</span>
<span className="space-y-0.5">
<span className="block text-body-sm font-medium text-foreground">{item.name}</span>
<span className="block text-caption leading-snug text-muted-foreground">{item.description}</span>
</span>
</Link>
</NavigationMenuLink>
</li>
)
})}
</ul>
</div>
<Link
href="/consultation"
className="group relative hidden overflow-hidden rounded-2xl border border-border bg-card lg:block"
>
<Image
src="/assets/main-pic/feature/feature1.webp"
alt="راهکارهای مشاوره و پیاده سازی"
width={600}
height={760}
className="h-full max-h-[22rem] w-full object-cover transition-transform duration-300 group-hover:scale-[1.02]"
/>
<div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-background/90 to-transparent p-4">
<p className="text-body-sm font-medium text-foreground">همراهی تا استقرار نهایی</p>
<p className="mt-1 text-caption text-muted-foreground">از مشاوره اولیه تا اجرای عملیاتی کنار شما هستیم</p>
</div>
</Link>
</div>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</div>
<div className="flex shrink-0 items-center gap-2 sm:gap-3">
<Button asChild size="sm" variant="primary" className="hidden sm:inline-flex">
<Link href="/consultation">{header.demoButton}</Link>
</Button>
</div>
</div>
<div className="lg:hidden">
<AnimatePresence>
{menuState && (
<>
<motion.div
aria-hidden
onClick={() => setMenuState(false)}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2 }}
className="fixed inset-0 z-[99] bg-background/50 backdrop-blur-[2px]"
/>
<motion.div
initial={{ opacity: 0, y: -8 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -8 }}
transition={{ duration: 0.22, ease: [0.32, 0.72, 0, 1] }}
className="relative z-[100] -mx-1 mb-3 overflow-hidden rounded-2xl border border-border/60 bg-card/95 shadow-lg shadow-black/10 backdrop-blur-xl">
<nav className="max-h-[min(70vh,28rem)] overflow-y-auto overscroll-contain px-3 py-3" aria-label="منوی موبایل">
{homeItem ? (
<>
<p className="text-caption mb-2 px-2 font-medium uppercase tracking-wider text-muted-foreground">
منو
</p>
<ul className="space-y-1">
<li>
<Link
href={homeItem.href}
onClick={() => setMenuState(false)}
className={cn(
'flex items-center rounded-xl px-3 py-2.5 text-body-sm transition-colors',
isRouteActive(pathname, homeItem.href)
? 'bg-primary/12 font-medium text-foreground'
: 'text-muted-foreground hover:bg-accent/50 hover:text-foreground'
)}>
{homeItem.name}
</Link>
</li>
</ul>
<div className="my-3 border-t border-border/60" />
</>
) : null}
<p className="text-caption mb-2 px-2 font-medium uppercase tracking-wider text-muted-foreground">
{header.productsLabel}
</p>
<ul className="grid gap-2 sm:grid-cols-2">
{productMenuItems.map((product) => {
const Icon = product.icon
return (
<li key={`${product.name}-${product.href}`}>
<Link
href={product.href}
onClick={() => setMenuState(false)}
className="flex items-start gap-3 rounded-xl border border-border/60 bg-card/40 px-3 py-3 transition-colors hover:bg-muted/40">
<span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-muted">
<Icon className="h-4 w-4 text-muted-foreground" />
</span>
<span className="space-y-0.5">
<span className="block text-body-sm font-medium text-foreground">{product.name}</span>
<span className="block text-caption leading-snug text-muted-foreground">{product.description}</span>
</span>
</Link>
</li>
)})}
</ul>
{trailItems.length > 0 ? (
<>
<div className="my-3 border-t border-border/60" />
<ul className="space-y-1">
{trailItems.map((item, index) => {
const active = isRouteActive(pathname, item.href)
return (
<li key={index}>
<Link
href={item.href}
onClick={() => setMenuState(false)}
className={cn(
'flex items-center rounded-xl px-3 py-2.5 text-body-sm transition-colors',
active
? 'bg-primary/12 font-medium text-foreground'
: 'text-muted-foreground hover:bg-accent/50 hover:text-foreground'
)}>
{item.name}
</Link>
</li>
)
})}
</ul>
</>
) : null}
<div className="mt-4 flex flex-col gap-2 border-t border-border/60 pt-3 sm:flex-row sm:items-center sm:justify-between">
<Button asChild variant="primary" className="w-full sm:w-auto">
<Link href="/consultation" onClick={() => setMenuState(false)}>
{header.demoButton}
</Link>
</Button>
</div>
</nav>
</motion.div>
</>
)}
</AnimatePresence>
</div>
</div>
</nav>
</header>
)
}