feat(projects): پیمایش پروژهٔ قبلی/بعدی در صفحهٔ هر پروژه (حلقه‌ای، دوزبانه) — کاوش بدون بازگشت به فهرست

This commit is contained in:
aramesh-site deploy
2026-10-09 19:08:41 +00:00
parent 1ceb7cb156
commit b088f68fd7
2 changed files with 57 additions and 0 deletions
+6
View File
@@ -13,6 +13,9 @@ export const fa = {
switchLangAria: 'تغییر زبان به انگلیسی',
understood: 'متوجه شدم',
paginationAria: 'صفحه‌بندی پروژه‌ها',
prevProject: 'پروژهٔ قبلی',
nextProject: 'پروژهٔ بعدی',
projectNavAria: 'پیمایش بین پروژه‌ها',
previousPage: 'صفحهٔ قبل',
nextPage: 'صفحهٔ بعد',
@@ -145,6 +148,9 @@ export const en: Dict = {
switchLangAria: 'Switch language to Persian (Farsi)',
understood: 'Got it',
paginationAria: 'Projects pagination',
prevProject: 'Previous project',
nextProject: 'Next project',
projectNavAria: 'Browse projects',
previousPage: 'Previous page',
nextPage: 'Next page',
+51
View File
@@ -79,6 +79,15 @@ export function ProjectDetail() {
}
const related = projects.filter((p) => p.slug !== project.slug).slice(0, 3)
/**
* پیمایش پروژه‌ها — همان ترتیبی که فهرست پروژه‌ها دارد (position از API).
* در ابتدا/انتهای فهرست، حلقه می‌زند تا کاوش هیچ‌وقت قطع نشود.
*/
const currentIndex = projects.findIndex((p) => p.slug === project.slug)
const total = projects.length
const prevProject = total > 1 ? projects[(currentIndex - 1 + total) % total] : undefined
const nextProject = total > 1 ? projects[(currentIndex + 1) % total] : undefined
// مشخصات هر پروژه — همان فهرستی که تیم داده دارد:
// وضعیت / سال / تعداد طبقات / واحدها / نوع پروژه / زیربنا / کاربری
@@ -219,6 +228,48 @@ export function ProjectDetail() {
</div>
</section>
{/* پیمایش پروژه‌ها — رفتن به پروژهٔ قبلی/بعدی بدون بازگشت به فهرست */}
{(prevProject || nextProject) && (
<nav
className="border-t border-ivory/10 bg-char py-10 lg:py-12"
aria-label={t('projectNavAria')}
>
<div className="mx-auto flex max-w-site items-stretch justify-between gap-3 px-6 lg:px-10">
{prevProject ? (
<Link
to={href(`/projects/${prevProject.slug}`)}
className="group flex min-w-0 flex-1 items-center gap-3 rounded-2xl border border-ivory/12 bg-ink/40 px-4 py-3.5 transition-all duration-300 ease-lux hover:-translate-y-0.5 hover:border-copper/50 hover:bg-ink/70 md:max-w-[46%] md:px-6 md:py-5"
>
<ArrowLeftIcon className="h-4 w-4 shrink-0 text-copper transition-transform duration-300 ltr:-scale-x-100 group-hover:ltr:-translate-x-1 rtl:group-hover:-translate-x-1" aria-hidden="true" />
<span className="flex min-w-0 flex-col text-start">
<span className="text-[11px] font-light text-ivory/50">{t('prevProject')}</span>
<span className="mt-1 truncate text-sm font-bold text-ivory transition-colors duration-300 group-hover:text-copper md:text-base">
{prevProject.title}
</span>
</span>
</Link>
) : (
<span className="flex-1" aria-hidden="true" />
)}
{nextProject && (
<Link
to={href(`/projects/${nextProject.slug}`)}
className="group flex min-w-0 flex-1 items-center justify-end gap-3 rounded-2xl border border-ivory/12 bg-ink/40 px-4 py-3.5 text-end transition-all duration-300 ease-lux hover:-translate-y-0.5 hover:border-copper/50 hover:bg-ink/70 md:max-w-[46%] md:px-6 md:py-5"
>
<span className="flex min-w-0 flex-col text-end">
<span className="text-[11px] font-light text-ivory/50">{t('nextProject')}</span>
<span className="mt-1 truncate text-sm font-bold text-ivory transition-colors duration-300 group-hover:text-copper md:text-base">
{nextProject.title}
</span>
</span>
<ArrowLeftIcon className="h-4 w-4 shrink-0 rotate-180 text-copper transition-transform duration-300 ltr:rotate-0 group-hover:ltr:translate-x-1 rtl:group-hover:translate-x-1" aria-hidden="true" />
</Link>
)}
</div>
</nav>
)}
<section className="bg-ink py-20 lg:py-28" aria-label={t('relatedProjectsAria')}>
<div className="mx-auto max-w-site px-6 lg:px-10">
<h2 className="text-section font-bold text-ivory">{t('otherProjects')}</h2>