feat(hero): نشان «پروژه فعال الیسیان» به صفحهٔ همان پروژه وصل شد (تطبیق دوزبانهٔ نام با نگاشت Elysian→الیسیان)
This commit is contained in:
@@ -10,9 +10,46 @@ import { InlineEdit } from '../admin/InlineEdit'
|
||||
import { HeroProjectBadge } from './HeroProjectBadge'
|
||||
import { SingletonPill } from '../../admin/Editable'
|
||||
|
||||
/** واژههای عمومی برچسب نشان که در تطبیق نام پروژه نادیده گرفته میشوند */
|
||||
const NOISE_WORDS = ['پروژه', 'فعال', 'آرامش', 'گروه', 'ساختمانی', 'Active', 'Project', 'Aramesh']
|
||||
/** نام لاتین برچسب انگلیسی → معادل فارسی در عنوان پروژه (پروژههای بدون title_en) */
|
||||
const LATIN_ALIAS: Record<string, string> = { elysian: 'الیسیان' }
|
||||
|
||||
export function Hero() {
|
||||
const { brand, hero } = useSite()
|
||||
const { t, href } = useLang()
|
||||
const { brand, hero, projects } = useSite()
|
||||
const { t, href, lang } = useLang()
|
||||
|
||||
/**
|
||||
* پروژهٔ فعال هیرو → صفحهٔ همان پروژه.
|
||||
* برچسب نشان مثل «پروژه فعال آرامش الیسیان» یا «Elysian Aramesh Active Project»
|
||||
* است؛ واژههای عمومی حذف و نام باقیمانده با عنوان پروژهها تطبیق داده میشود.
|
||||
*/
|
||||
const activeProjectHref = (() => {
|
||||
const label = hero.badge_label.trim()
|
||||
if (!label) return undefined
|
||||
|
||||
const strip = (text: string) => {
|
||||
let out = text
|
||||
NOISE_WORDS.forEach((w) => {
|
||||
out = out.split(w).join(' ')
|
||||
})
|
||||
return out.replace(/[\s\-—_]+/g, '').trim().toLowerCase()
|
||||
}
|
||||
|
||||
let key = strip(label)
|
||||
// برچسب انگلیسی ممکن است نام لاتین داشته باشد و پروژه فقط عنوان فارسی (Elysian → الیسیان)
|
||||
if (key.length < 3 || LATIN_ALIAS[key]) key = LATIN_ALIAS[key] ?? key
|
||||
if (key.length < 3) return undefined
|
||||
|
||||
const hit = projects.find((p) => {
|
||||
const candidates = [p.title, p.title_en ?? ''].filter(Boolean)
|
||||
return candidates.some((title) => {
|
||||
const k = strip(title)
|
||||
return k.length >= 3 && (k.includes(key) || key.includes(k))
|
||||
})
|
||||
})
|
||||
return hit ? `/projects/${hit.slug}` : undefined
|
||||
})()
|
||||
const save = useFieldSaver()
|
||||
const { scrollY } = useScroll()
|
||||
const imageY = useTransform(scrollY, [0, 700], [0, 110])
|
||||
@@ -141,7 +178,11 @@ export function Hero() {
|
||||
<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">
|
||||
<HeroProjectBadge value={String(hero.badge_value ?? '').trim()} label={hero.badge_label} />
|
||||
<HeroProjectBadge
|
||||
value={String(hero.badge_value ?? '').trim()}
|
||||
label={hero.badge_label}
|
||||
href={activeProjectHref ? href(activeProjectHref) : undefined}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
import { Building2Icon } from 'lucide-react'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
/**
|
||||
* نشان «پروژه فعال» هیرو — آیکون و متن کنار هم، با فاصلهٔ یکنواخت و
|
||||
* چیدمان وسطچین. فلکسباکس ستون را از بین میبرد تا فاصلهٔ آیکون و متن
|
||||
* یکدست بماند و آیکون درست با متن همتراز شود.
|
||||
*/
|
||||
export function HeroProjectBadge({ value, label }: { value: string; label: string }) {
|
||||
return (
|
||||
export function HeroProjectBadge({
|
||||
value,
|
||||
label,
|
||||
href,
|
||||
}: {
|
||||
value: string
|
||||
label: string
|
||||
/** نشانی صفحهٔ پروژهٔ فعال — نشان کلیکپذیر میشود و به همان پروژه میرود */
|
||||
href?: string
|
||||
}) {
|
||||
const body = (
|
||||
<div className="flex items-center gap-3.5 text-center">
|
||||
{/* آیکون در کادر مربعی با نشان زندهٔ مسی */}
|
||||
<span className="relative flex h-14 w-14 shrink-0 items-center justify-center rounded-xl border border-copper/40 bg-copper/10">
|
||||
@@ -23,4 +33,16 @@ export function HeroProjectBadge({ value, label }: { value: string; label: strin
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
// بدون نشانی همان ظرف ساده میماند؛ با نشانی، کل نشان یک پیوند به پروژه است
|
||||
if (!href) return body
|
||||
return (
|
||||
<Link
|
||||
to={href}
|
||||
className="block rounded-2xl transition-transform duration-300 ease-lux hover:-translate-y-0.5 focus:outline-none focus-visible:ring-2 focus-visible:ring-copper"
|
||||
aria-label={label}
|
||||
>
|
||||
{body}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user