first commit

This commit is contained in:
amirhosein.ashourloo
2026-09-15 20:37:49 +03:30
commit dee487ad73
91 changed files with 7365 additions and 0 deletions
@@ -0,0 +1,12 @@
import { notFound } from 'next/navigation';
import Link from 'next/link';
import MediaGallery from '../../../../components/media-gallery';
import { faSlug, galleryOf, getPortfolioById, getPortfolios, imageUrlOf, plainText, titleOf } from '../../../../lib/meshkee-api';
export const dynamicParams = false;
export async function generateStaticParams() { const params=(await getPortfolios()).map((item)=>({slug:String(item.id),titleFaSlug:faSlug(titleOf(item))})); return params.length?params:[{slug:'__placeholder__',titleFaSlug:'بدون-عنوان'}]; }
export async function generateMetadata({params}) { const {slug}=await params; const item=await getPortfolioById(slug); if(!item)return{robots:{index:false,follow:false}}; const title=titleOf(item,'نمونه‌کار'); const description=item.seoMetaDescription||plainText(item.abstract||item.mainTextHtml||'').slice(0,160)||`معرفی پروژهٔ ${title} از گروه معماری ساناز گودرزی.`; const canonical=`/portfolios/${item.id}/${faSlug(title)}/`; return {title:item.seoMetaTitle||title,description,alternates:{canonical},openGraph:{title,description,url:canonical,type:'article',images:imageUrlOf(item)?[{url:imageUrlOf(item),alt:title}]:[]}}; }
export default async function PortfolioPage({params}) { const {slug}=await params; const item=await getPortfolioById(slug); if(!item)notFound(); const all=await getPortfolios(); const title=titleOf(item); const cover=imageUrlOf(item); const gallery=galleryOf(item); const images=[...(cover?[{id:'cover',url:cover,alt:`تصویر اصلی پروژهٔ ${title}`}]:[]),...gallery.filter(image=>image.url!==cover)]; const related=all.filter(candidate=>candidate.id!==item.id&&(candidate.categoryId===item.categoryId||candidate.categoryName===item.categoryName)).slice(0,3); return <>
<article className="portfolio-api-detail container"><Link className="text-link" href="/portfolios/">بازگشت به نمونه‌کارها ←</Link><header><span className="eyebrow">{item.categoryName||'نمونه‌کار معماری'}</span><h1>{title}</h1>{item.abstract&&<p>{plainText(item.abstract)}</p>}</header><MediaGallery images={images} title={title}/>{item.mainTextHtml&&<div className="rich-content" dangerouslySetInnerHTML={{__html:item.mainTextHtml}}/>}{item.projectUrl&&<a className="button button-dark" href={item.projectUrl} target="_blank" rel="noopener noreferrer">مشاهده وب‌سایت پروژه</a>}</article>
{related.length>0&&<section className="related-work container"><h2>نمونه‌کارهای مشابه</h2><div className="editorial-grid">{related.map(candidate=>{const candidateTitle=titleOf(candidate);return <article key={candidate.id}><Link href={`/portfolios/${candidate.id}/${faSlug(candidateTitle)}/`}><div className="editorial-image"><img src={imageUrlOf(candidate)||'/img/subheader/bg.jpg'} alt={`تصویر پروژهٔ ${candidateTitle}`} loading="lazy"/></div><h3>{candidateTitle}</h3></Link></article>})}</div></section>}
</>; }
+8
View File
@@ -0,0 +1,8 @@
import { notFound } from 'next/navigation';
import Link from 'next/link';
import { portfolioItems } from '../../../lib/portfolio';
import { services } from '../../../lib/content';
import { PageHeading, ContactCTA } from '../../../components/common';
export function generateStaticParams(){return portfolioItems.map(item=>({slug:item.slug}))}
export async function generateMetadata({params}){const {slug}=await params;const item=portfolioItems.find(i=>i.slug===slug);return {title:item?.title??'نمونه‌کار',robots:{index:false,follow:true}}}
export default async function PortfolioDetail({params}){const {slug}=await params;const item=portfolioItems.find(i=>i.slug===slug);if(!item)notFound();const service=services.find(s=>s.id===slug);return <><PageHeading title={item.title} en={service.en}/><article className="container portfolio-detail"><img src={item.image} alt={`تصویر نمایشی ${item.title}`}/><div><span className="eyebrow">پیش‌نمایش حوزهٔ طراحی</span><h2>{item.title}</h2><p>{service.description}</p><div className="placeholder-notice"><strong>اطلاعات پروژه‌ها به‌زودی</strong><p>{item.description} این تصویر معرفی حوزهٔ طراحی است و به پروژهٔ مشخصی نسبت داده نشده است.</p></div><Link className="text-link" href="/portfolios/">بازگشت به نمونه‌کارها ←</Link></div></article><ContactCTA/></>}