Dejband.com clone — Next.js, RTL Persian

- Homepage faithfully matching dejband.com (hero, services, consulting,
  stats, about block, timeline, portfolio, articles) + About/Contact/
  Portfolios/Articles pages under source URLs
- Meshkee API integration: live blog content, favicon, user menu,
  sitemap/robots proxy, canonical /blog/{id}/{slug}
- SEO pass: one H1 per page, unique metadata + canonicals, alt text
- Contact form wired to /api/contact with toast + reset

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
meshkee.ai10
2026-09-04 11:51:32 +03:30
co-authored by Claude Sonnet 5
commit 028a91944c
104 changed files with 4715 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
import { redirect } from "next/navigation";
import { getBlog, blogPath } from "@/lib/api";
export const revalidate = 300;
// Legacy path — 308-redirect to the canonical /blog/{id}/{slug}.
export default async function LegacyArticleRedirect({ params }) {
const { slug } = await params;
const blog = await getBlog(slug);
redirect(blog ? encodeURI(blogPath(blog)) : "/articles");
}
+70
View File
@@ -0,0 +1,70 @@
import Image from "next/image";
import Link from "next/link";
import PageTitle from "@/components/PageTitle";
import { getBlogs, formatFaDate, blogPath, SITE_URL } from "@/lib/api";
import { ARTICLES as FALLBACK } from "@/lib/site";
export const metadata = {
title: "مقالات و مطالب آموزشی",
description:
"مقالات تخصصی مهندسین مشاور دژبند قم درباره طراحی و ساخت سوله صنعتی، سازه‌های فلزی، نقشه‌های برق و مکانیک و استانداردهای ایمنی.",
alternates: { canonical: `${SITE_URL}/articles` },
};
export const revalidate = 300;
export default async function ArticlesPage() {
const blogs = await getBlogs();
const items = blogs.length
? blogs.map((b) => ({
href: blogPath(b),
img: b.image || "/images/articles/a-1.jpg",
category: b.category,
date: formatFaDate(b.date),
title: b.title,
external: false,
}))
: FALLBACK.map((a) => ({ ...a, external: true }));
return (
<>
<PageTitle title="مقالات" en="ARTICLES" />
<section className="art-section" style={{ padding: "60px 0" }}>
<div className="art-grid-wrap" style={{ marginTop: 0 }}>
<ul className="art-grid art-grid-page">
{items.map((a) => {
const Card = (
<>
<div className="art-image">
<Image src={a.img} alt={`تصویر مقاله: ${a.title}`} width={600} height={500} />
<div className="art-image-overlay" />
</div>
<div className="art-details">
<span className="art-category">{a.category}</span>
<div className="art-bottom">
<span className="art-date">{a.date}</span>
<h2>{a.title}</h2>
</div>
</div>
</>
);
return (
<li className="art-item" key={a.title}>
{a.external ? (
<a href={a.href} target="_blank" rel="noopener noreferrer">
{Card}
</a>
) : (
<Link href={a.href}>{Card}</Link>
)}
</li>
);
})}
</ul>
</div>
</section>
</>
);
}