feat(projects): پیمایش پروژهٔ قبلی/بعدی در صفحهٔ هر پروژه (حلقهای، دوزبانه) — کاوش بدون بازگشت به فهرست
This commit is contained in:
@@ -13,6 +13,9 @@ export const fa = {
|
|||||||
switchLangAria: 'تغییر زبان به انگلیسی',
|
switchLangAria: 'تغییر زبان به انگلیسی',
|
||||||
understood: 'متوجه شدم',
|
understood: 'متوجه شدم',
|
||||||
paginationAria: 'صفحهبندی پروژهها',
|
paginationAria: 'صفحهبندی پروژهها',
|
||||||
|
prevProject: 'پروژهٔ قبلی',
|
||||||
|
nextProject: 'پروژهٔ بعدی',
|
||||||
|
projectNavAria: 'پیمایش بین پروژهها',
|
||||||
previousPage: 'صفحهٔ قبل',
|
previousPage: 'صفحهٔ قبل',
|
||||||
nextPage: 'صفحهٔ بعد',
|
nextPage: 'صفحهٔ بعد',
|
||||||
|
|
||||||
@@ -145,6 +148,9 @@ export const en: Dict = {
|
|||||||
switchLangAria: 'Switch language to Persian (Farsi)',
|
switchLangAria: 'Switch language to Persian (Farsi)',
|
||||||
understood: 'Got it',
|
understood: 'Got it',
|
||||||
paginationAria: 'Projects pagination',
|
paginationAria: 'Projects pagination',
|
||||||
|
prevProject: 'Previous project',
|
||||||
|
nextProject: 'Next project',
|
||||||
|
projectNavAria: 'Browse projects',
|
||||||
previousPage: 'Previous page',
|
previousPage: 'Previous page',
|
||||||
nextPage: 'Next page',
|
nextPage: 'Next page',
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,15 @@ export function ProjectDetail() {
|
|||||||
|
|
||||||
const related = projects.filter((p) => p.slug !== project.slug).slice(0, 3)
|
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>
|
</div>
|
||||||
</section>
|
</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')}>
|
<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">
|
<div className="mx-auto max-w-site px-6 lg:px-10">
|
||||||
<h2 className="text-section font-bold text-ivory">{t('otherProjects')}</h2>
|
<h2 className="text-section font-bold text-ivory">{t('otherProjects')}</h2>
|
||||||
|
|||||||
Reference in New Issue
Block a user