Ship fonts, customer auth menu, contact API, and Meshkee SEO wiring.

Host Iran Yekan/Montserrat locally, link login to customer.havaran.com with a logged-in dropdown, submit contact forms to Meshkee, and publish sitemap-config with canonical id/slug detail URLs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-09-08 22:53:33 +03:30
co-authored by Cursor
parent aaa3078145
commit e4ca605e93
44 changed files with 1405 additions and 330 deletions
+67
View File
@@ -0,0 +1,67 @@
import { notFound, permanentRedirect } from "next/navigation";
import { Footer } from "@/components/Footer";
import { Header } from "@/components/Header";
import { PageHero } from "@/components/PageShared";
import { PortfolioDetailView } from "@/components/PortfolioDetail";
import { getPortfolioById } from "@/lib/meshkee";
import { pageMetadata } from "@/lib/seo";
import { portfolioPath, portfolioTitleSlug } from "@/lib/urls";
type PageProps = {
params: Promise<{ id: string; slug: string }>;
};
export async function generateMetadata({ params }: PageProps) {
const { id } = await params;
const { item } = await getPortfolioById(id);
if (!item) {
return pageMetadata({
title: "پروژه",
description: "پروژه مورد نظر یافت نشد.",
path: `/portfolios/${id}`,
noIndex: true,
});
}
const description =
item.description?.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim() ||
`نمونه کار ${item.title} — شرکت رسام تجارت هواران`;
return pageMetadata({
title: item.title,
description: description.slice(0, 160),
path: portfolioPath(item),
image: item.coverImage || item.image || undefined,
});
}
export default async function PortfolioDetailPage({ params }: PageProps) {
const { id, slug: slugParam } = await params;
const slug = decodeURIComponent(slugParam);
const { item } = await getPortfolioById(id);
if (!item) notFound();
const canonicalSlug = portfolioTitleSlug(item);
if (slug !== canonicalSlug) {
permanentRedirect(portfolioPath(item));
}
return (
<>
<Header />
<main>
<PageHero
title={item.title}
titleEn={item.titleEn || "PROJECT DETAILS"}
breadcrumb={[
{ label: "صفحه اصلی", href: "/" },
{ label: "پروژه ها", href: "/portfolios" },
{ label: item.title, href: portfolioPath(item) },
]}
/>
<PortfolioDetailView item={item} />
</main>
<Footer />
</>
);
}