190 lines
9.8 KiB
TypeScript
190 lines
9.8 KiB
TypeScript
import React from 'react'
|
|
import { motion, useScroll, useTransform } from 'framer-motion'
|
|
import { Link } from 'react-router-dom'
|
|
import { ArrowLeftIcon, Building2Icon, ChevronDownIcon } from 'lucide-react'
|
|
import { ButtonLink } from '../Button'
|
|
import { useSite } from '../../api'
|
|
import { useLang } from '../../i18n/lang'
|
|
import { useFieldSaver } from '../../admin/AdminContext'
|
|
import { InlineEdit } from '../admin/InlineEdit'
|
|
import { SingletonPill } from '../../admin/Editable'
|
|
|
|
export function Hero() {
|
|
const { brand, hero } = useSite()
|
|
const { t, href } = useLang()
|
|
const save = useFieldSaver()
|
|
const { scrollY } = useScroll()
|
|
const imageY = useTransform(scrollY, [0, 700], [0, 110])
|
|
const contentY = useTransform(scrollY, [0, 700], [0, -55])
|
|
const overlay = useTransform(scrollY, [0, 600], [0.5, 0.78])
|
|
|
|
const saveHero = (field: string, value: unknown) =>
|
|
save('hero', hero.id, { [field]: value }, (d) => {
|
|
;(d.hero as unknown as Record<string, unknown>)[field] = value
|
|
})
|
|
|
|
return (
|
|
<section className="relative h-screen min-h-[640px] w-full overflow-hidden" aria-label={t('heroAria')}>
|
|
{/* تصویر پسزمینه */}
|
|
<motion.img
|
|
src={brand.hero}
|
|
alt={t('heroImageAlt')}
|
|
style={{ y: imageY }}
|
|
className="absolute inset-0 h-[114%] w-full object-cover"
|
|
/>
|
|
<motion.div className="absolute inset-0 bg-ink" style={{ opacity: overlay }} aria-hidden="true" />
|
|
<div
|
|
className="absolute inset-0"
|
|
style={{
|
|
background:
|
|
'linear-gradient(to top, #27221c 5%, rgba(39,34,28,0.2) 60%, rgba(39,34,28,0.6) 100%)',
|
|
}}
|
|
aria-hidden="true"
|
|
/>
|
|
|
|
{/* محتوای اصلی هیرو */}
|
|
<motion.div
|
|
style={{ y: contentY }}
|
|
className="relative mx-auto flex h-full max-w-site flex-col justify-center px-6 lg:px-10"
|
|
>
|
|
<div className="w-full max-w-[700px] lg:max-w-[58%]">
|
|
{/* کیکر بالای تیتر */}
|
|
<motion.p
|
|
initial={{ opacity: 0, y: 18 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.6, delay: 0.05, ease: [0.23, 1, 0.32, 1] }}
|
|
className="text-sm font-light text-copper tracking-wide"
|
|
>
|
|
<InlineEdit value={hero.kicker} onSave={(v) => saveHero('kicker', v)} />
|
|
</motion.p>
|
|
|
|
{/* تیتر اصلی */}
|
|
<motion.h1
|
|
initial={{ opacity: 0, y: 28 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.6, delay: 0.12, ease: [0.23, 1, 0.32, 1] }}
|
|
className="mt-6 text-hero font-bold text-ivory leading-[1.3]"
|
|
>
|
|
<InlineEdit value={hero.title} onSave={(v) => saveHero('title', v)} aria-label={t('heroTitleAria')} />
|
|
</motion.h1>
|
|
|
|
{/* زیرتیتر */}
|
|
<motion.p
|
|
initial={{ opacity: 0, y: 22 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.6, delay: 0.2, ease: [0.23, 1, 0.32, 1] }}
|
|
className="mt-7 max-w-xl text-base font-light leading-9 text-ivory/75"
|
|
>
|
|
<InlineEdit multiline value={hero.subtitle} onSave={(v) => saveHero('subtitle', v)} />
|
|
</motion.p>
|
|
|
|
{/* پیوند درباره ما — زیر تیتر، در هر دو زبان */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 18 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.6, delay: 0.24, ease: [0.23, 1, 0.32, 1] }}
|
|
className="mt-4"
|
|
>
|
|
<Link
|
|
to={href('/about')}
|
|
className="inline-flex items-center gap-1.5 border-b border-ivory/25 pb-0.5 text-sm font-light text-ivory/70 transition-colors duration-200 hover:border-copper hover:text-copper"
|
|
>
|
|
{t('aboutUs')}
|
|
<ArrowLeftIcon className="h-3.5 w-3.5 ltr:rotate-180" aria-hidden="true" />
|
|
</Link>
|
|
</motion.div>
|
|
|
|
{/* داک دکمهها: استایل کپسولی، شیشهای و دایرهای */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 22 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.6, delay: 0.28, ease: [0.23, 1, 0.32, 1] }}
|
|
className="mt-10 flex flex-wrap items-center gap-4"
|
|
>
|
|
{/* دکمه اصلی: کپسولی شیشهای دودی با دایره کهربایی اختصاصی برای آیکون */}
|
|
<ButtonLink
|
|
to={href(hero.cta_primary_href)}
|
|
variant="copper"
|
|
className="!p-1.5 !ps-7 !rounded-full shadow-lg shadow-black/40 hover:shadow-copper/25 transition-all duration-300"
|
|
>
|
|
<span className="text-sm font-medium tracking-wide text-ivory">
|
|
<InlineEdit value={hero.cta_primary_label} onSave={(v) => saveHero('cta_primary_label', v)} />
|
|
</span>
|
|
<span className="flex h-9 w-9 items-center justify-center rounded-full bg-copper text-char shadow-md transition-all duration-300 group-hover:scale-110 rtl:group-hover:-translate-x-1 ltr:group-hover:translate-x-1">
|
|
<ArrowLeftIcon className="h-4 w-4 stroke-[2.5] ltr:-scale-x-100" />
|
|
</span>
|
|
</ButtonLink>
|
|
|
|
{/* دکمه ثانویه: شیشه دودی مات (Smoked Glass) با کادر ظریف */}
|
|
<ButtonLink
|
|
to={href(hero.cta_secondary_href)}
|
|
variant="outline"
|
|
className="!rounded-full !px-8 !py-3.5 bg-char/40 backdrop-blur-md border border-ivory/20 text-ivory hover:border-copper/70 hover:text-copper transition-all duration-300 shadow-sm"
|
|
>
|
|
<InlineEdit value={hero.cta_secondary_label} onSave={(v) => saveHero('cta_secondary_label', v)} />
|
|
</ButtonLink>
|
|
</motion.div>
|
|
</div>
|
|
|
|
{/* کادر آمار شناور (گوشه پایین چپ) — شیشهٔ چندلایه، خط مویی مسی، هالهٔ نرم و نشان زنده */}
|
|
<motion.div
|
|
initial={{ opacity: 0, x: -24 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
transition={{ duration: 0.6, delay: 0.36, ease: [0.23, 1, 0.32, 1] }}
|
|
className="group absolute bottom-28 ltr:right-6 rtl:left-6 hidden w-72 lg:block lg:ltr:right-10 lg:rtl:left-10"
|
|
>
|
|
<div className="relative overflow-hidden rounded-2xl border border-white/10 bg-ink/55 p-6 shadow-2xl shadow-black/50 backdrop-blur-2xl transition-colors duration-500 group-hover:border-copper/40">
|
|
{/* خط مویی مسی روی لبهٔ شروع */}
|
|
<span aria-hidden="true" className="absolute inset-y-0 start-0 w-[3px] bg-gradient-to-b from-copper/90 via-copper/30 to-transparent" />
|
|
{/* هالهٔ مسی نرم گوشهٔ مقابل — با هاور پررنگتر */}
|
|
<span aria-hidden="true" className="absolute -top-20 -end-20 h-44 w-44 rounded-full bg-copper/10 blur-3xl transition-colors duration-700 group-hover:bg-copper/20" />
|
|
|
|
<div className="relative flex items-start gap-4">
|
|
<span className="relative mt-0.5 flex h-11 w-11 shrink-0 items-center justify-center rounded-xl border border-copper/40 bg-copper/10">
|
|
<Building2Icon className="h-5 w-5 text-copper" aria-hidden="true" />
|
|
<span className="absolute -end-1 -top-1 flex h-2.5 w-2.5" aria-hidden="true">
|
|
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-copper opacity-60" />
|
|
<span className="relative inline-flex h-2.5 w-2.5 rounded-full border border-ink bg-copper" />
|
|
</span>
|
|
</span>
|
|
<div className="min-w-0">
|
|
{String(hero.badge_value ?? '').trim() !== '' && (
|
|
<p className="font-mono text-[2rem] font-bold leading-none tracking-tight text-copper">
|
|
<InlineEdit value={hero.badge_value} onSave={(v) => saveHero('badge_value', v)} />
|
|
</p>
|
|
)}
|
|
<p className={`text-[13px] font-light leading-6 text-ivory/75 ${String(hero.badge_value ?? '').trim() !== '' ? 'mt-2.5' : ''}`}>
|
|
<InlineEdit multiline value={hero.badge_label} onSave={(v) => saveHero('badge_label', v)} />
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
</motion.div>
|
|
|
|
{/* دکمه اسکرول پایین: تبدیلشده به یک گوی شیشهای دایرهای */}
|
|
<a
|
|
href="#story"
|
|
aria-label={t('scrollDown')}
|
|
className="group absolute bottom-7 right-1/2 z-10 flex translate-x-1/2 flex-col items-center gap-2 text-ivory/60 transition-colors duration-300 hover:text-copper"
|
|
>
|
|
<span className="text-[11px] font-light tracking-widest opacity-80 group-hover:opacity-100">
|
|
<InlineEdit value={hero.scroll_label} onSave={(v) => saveHero('scroll_label', v)} />
|
|
</span>
|
|
<div className="flex h-10 w-10 items-center justify-center rounded-full border border-ivory/20 bg-char/40 backdrop-blur-md transition-all duration-300 group-hover:border-copper group-hover:bg-char/70 group-hover:shadow-lg group-hover:shadow-copper/20">
|
|
<ChevronDownIcon className="h-4 w-4 animate-bounce text-ivory group-hover:text-copper" />
|
|
</div>
|
|
</a>
|
|
|
|
{/* کنترلهای ادمین */}
|
|
<div className="absolute left-6 top-24 z-20 flex flex-col gap-2 lg:left-10">
|
|
<SingletonPill resource="hero" label="تنظیمات هیرو (واژه مسی، دکمهها)" />
|
|
<SingletonPill
|
|
resource="seo-meta"
|
|
label="عنوان و توضیح سئوی صفحه اصلی"
|
|
select={(d) => d.seo_meta.find((s) => s.page_key === 'home')}
|
|
/>
|
|
</div>
|
|
</section>
|
|
)
|
|
} |