Compare commits

..
5 Commits
153 changed files with 2315 additions and 1153 deletions
+4 -4
View File
@@ -110,12 +110,12 @@ src/
## صفحه «درباره ما» ## صفحه «درباره ما»
ظاهر این صفحه الهام‌گرفته از [omniyat.com/omniyat-atelier](https://www.omniyat.com/omniyat-atelier) ظاهر این صفحه بر پایه زبان بصری جدید وب‌سایت رئوفی طراحی شده است.
است، اما **تمام محتوا از صفحه درباره ما سایت رئوفی** برداشته شده است. است، اما **تمام محتوا از صفحه درباره ما سایت رئوفی** برداشته شده است.
سیستم چیدمانِ برگرفته از مرجع: سیستم چیدمانِ برگرفته از مرجع:
| ویژگی | مرجع (Omniyat) | پیاده‌سازی | | ویژگی | طراحی هدف | پیاده‌سازی |
| --- | --- | --- | | --- | --- | --- |
| ریتم عمودی بلوک متن | `192px 48px` | `192px 48px` (موبایل: `96px 24px`) | | ریتم عمودی بلوک متن | `192px 48px` | `192px 48px` (موبایل: `96px 24px`) |
| کپشن بالای تیتر | ۱۴px، `letter-spacing: 1.4px` | همان — فقط روی بخش لاتین | | کپشن بالای تیتر | ۱۴px، `letter-spacing: 1.4px` | همان — فقط روی بخش لاتین |
@@ -137,7 +137,7 @@ src/
## صفحه «خدمات ما» ## صفحه «خدمات ما»
همان سیستم چیدمان صفحه درباره ما (الهام‌گرفته از Omniyat Atelier). همان سیستم چیدمان صفحه درباره ما و زبان بصری جدید وب‌سایت.
**نکته‌ی مهم درباره‌ی محتوا:** صفحه‌ی خدمات سایت فعلی فقط شامل شش عنوان خدمت و تیتر **نکته‌ی مهم درباره‌ی محتوا:** صفحه‌ی خدمات سایت فعلی فقط شامل شش عنوان خدمت و تیتر
«با خدمات ما بیشتر آشنا شوید...» است — هیچ توضیحی برای خدمات ندارد و لینک همه‌ی «با خدمات ما بیشتر آشنا شوید...» است — هیچ توضیحی برای خدمات ندارد و لینک همه‌ی
@@ -159,7 +159,7 @@ src/
## نکات ## نکات
- لینک‌های ناوبری به مسیرهای واقعی سایت (`/portfolios`، `/news`، …) اشاره می‌کنند - لینک‌های ناوبری به مسیرهای واقعی سایت (`/projects`، `/news`، …) اشاره می‌کنند
ولی تاکنون فقط صفحه اصلی و درباره ما طراحی شده‌اند. ولی تاکنون فقط صفحه اصلی و درباره ما طراحی شده‌اند.
- انیمیشن‌ها به `prefers-reduced-motion` احترام می‌گذارند. - انیمیشن‌ها به `prefers-reduced-motion` احترام می‌گذارند.
- کروسل پروژه‌ها برای RTL نوشته شده (`scrollLeft` منفی) و با کیبورد و لمس کار می‌کند. - کروسل پروژه‌ها برای RTL نوشته شده (`scrollLeft` منفی) و با کیبورد و لمس کار می‌کند.
+15 -1
View File
@@ -7,7 +7,7 @@ const nextConfig: NextConfig = {
formats: ["image/avif", "image/webp"], formats: ["image/avif", "image/webp"],
// Every quality value used across the page. Required from Next.js 16 on. // Every quality value used across the page. Required from Next.js 16 on.
qualities: [70, 72, 75, 80, 82, 88, 90], qualities: [70, 72, 75, 80, 82, 88, 90],
// Portfolio media served live from the meshkee API. The storage host has // Project media served live from the meshkee API. The storage host has
// already changed once mid-project (parminstorage.ir -> parspack.net) — // already changed once mid-project (parminstorage.ir -> parspack.net) —
// keep both around since either could be what a given item still points to. // keep both around since either could be what a given item still points to.
remotePatterns: [ remotePatterns: [
@@ -16,6 +16,20 @@ const nextConfig: NextConfig = {
{ protocol: "https", hostname: "c804387.parspack.net" }, { protocol: "https", hostname: "c804387.parspack.net" },
], ],
}, },
async redirects() {
return [
{
source: "/our-services",
destination: "/atelier",
permanent: true,
},
{
source: "/portfolios/:path*",
destination: "/projects/:path*",
permanent: true,
},
];
},
}; };
export default nextConfig; export default nextConfig;
+87 -1
View File
@@ -10,7 +10,8 @@
"dependencies": { "dependencies": {
"next": "15.5.25", "next": "15.5.25",
"react": "^19.2.8", "react": "^19.2.8",
"react-dom": "^19.2.8" "react-dom": "^19.2.8",
"swiper": "^14.2.0"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/postcss": "^4.1.13", "@tailwindcss/postcss": "^4.1.13",
@@ -1266,6 +1267,72 @@
"node": ">=14.0.0" "node": ">=14.0.0"
} }
}, },
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": {
"version": "1.11.1",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.2.2",
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": {
"version": "1.11.1",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
"version": "1.2.2",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
"version": "1.1.4",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@tybys/wasm-util": "^0.10.1"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
},
"peerDependencies": {
"@emnapi/core": "^1.7.1",
"@emnapi/runtime": "^1.7.1"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": {
"version": "0.10.2",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": {
"version": "2.8.1",
"dev": true,
"inBundle": true,
"license": "0BSD",
"optional": true
},
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
"version": "4.3.3", "version": "4.3.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz",
@@ -5863,6 +5930,25 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/swiper": {
"version": "14.2.0",
"resolved": "https://registry.npmjs.org/swiper/-/swiper-14.2.0.tgz",
"integrity": "sha512-GsL4M9Fq7Sg22OyL3SjdNj/0bxTfIxPJJHHW394Li0u5vYtExi0a09iBUc8CuLafJi5pAlH2AHUe1PocxHl45g==",
"funding": [
{
"type": "custom",
"url": "https://sponsors.nolimits4web.com"
},
{
"type": "github",
"url": "https://github.com/sponsors/nolimits4web"
}
],
"license": "MIT",
"engines": {
"node": ">= 4.7.0"
}
},
"node_modules/tailwindcss": { "node_modules/tailwindcss": {
"version": "4.3.3", "version": "4.3.3",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz",
+3 -2
View File
@@ -3,14 +3,15 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "node scripts/dev.cjs",
"build": "next build", "build": "next build",
"start": "next start" "start": "next start"
}, },
"dependencies": { "dependencies": {
"next": "15.5.25", "next": "15.5.25",
"react": "^19.2.8", "react": "^19.2.8",
"react-dom": "^19.2.8" "react-dom": "^19.2.8",
"swiper": "^14.2.0"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/postcss": "^4.1.13", "@tailwindcss/postcss": "^4.1.13",
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

+48
View File
@@ -0,0 +1,48 @@
const { execFileSync, spawn } = require("node:child_process");
const path = require("node:path");
function supportsNext(nodePath) {
try {
const version = execFileSync(nodePath, ["--version"], {
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"],
}).trim();
const [major, minor] = version.replace(/^v/, "").split(".").map(Number);
return major >= 20 || (major === 18 && minor >= 18) || (major === 19 && minor >= 8);
} catch {
return false;
}
}
function installedNodes() {
const command = process.platform === "win32" ? "where.exe" : "which";
const args = process.platform === "win32" ? ["node"] : ["-a", "node"];
try {
return execFileSync(command, args, { encoding: "utf8" })
.split(/\r?\n/)
.map((item) => item.trim())
.filter(Boolean);
} catch {
return [];
}
}
const nodePath = [process.execPath, ...installedNodes()].find(supportsNext);
if (!nodePath) {
console.error("Next.js به Node.js 18.18 یا جدیدتر نیاز دارد. لطفاً Node.js LTS را نصب کنید.");
process.exit(1);
}
const nextCli = require.resolve("next/dist/bin/next");
const child = spawn(nodePath, [nextCli, "dev", ...process.argv.slice(2)], {
cwd: path.resolve(__dirname, ".."),
stdio: "inherit",
env: process.env,
});
child.on("exit", (code, signal) => {
if (signal) process.kill(process.pid, signal);
process.exit(code ?? 1);
});
+7 -97
View File
@@ -1,115 +1,25 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import atelier from "@/assets/images/about/atelier.jpg"; import { RaoofiAbout } from "@/components/about/RaoofiAbout";
import about from "@/assets/images/about/about.jpg";
import heroImage from "@/assets/images/hero/hero-2.jpg";
import heroImageMobile from "@/assets/images/hero/hero-2-mobile.jpg";
import { Pillars } from "@/components/about/Pillars";
import { Editorial } from "@/components/shared/Editorial";
import { FullBleed } from "@/components/shared/FullBleed";
import { PageCta } from "@/components/shared/PageCta";
import { PageHero } from "@/components/shared/PageHero";
import { ProjectGallery } from "@/components/shared/ProjectGallery";
import { Reveal } from "@/components/Reveal";
import { SiteFooter } from "@/components/SiteFooter"; import { SiteFooter } from "@/components/SiteFooter";
import { SiteHeader } from "@/components/SiteHeader"; import { SiteHeader } from "@/components/SiteHeader";
import { aboutPage } from "@/data/site"; import { getRecentProjects, toDisplayProject } from "@/lib/api";
import { getRecentPortfolios, toDisplayProject } from "@/lib/api";
export const revalidate = 300; // keep in sync with api.ts PAGE_REVALIDATE_SECONDS export const revalidate = 300;
export const metadata: Metadata = { export const metadata: Metadata = {
title: "درباره ما", title: "درباره ما",
description: description: "روایت شکل‌گیری، ارزش‌ها و مسیر گروه ساختمانی رئوفی از سال ۱۳۷۹ تا امروز.",
"از سال ۱۳۷۹، دیدگاه مهندس قاسم رئوفی‌منش مسیر گروه رئوفی را تعریف کرده است؛ دیدگاهی که هر پروژه را به تجربه‌ای اصیل و ماندگار از سبک زندگی ارتقاء می‌دهد.",
}; };
export default async function AboutPage() { export default async function AboutPage() {
const portfolios = await getRecentPortfolios(12); const projects = await getRecentProjects(8);
const displayProjects = portfolios.map(toDisplayProject); const displayProjects = projects.map(toDisplayProject);
return ( return (
<> <>
<SiteHeader /> <SiteHeader />
<RaoofiAbout projects={displayProjects} />
<main>
<PageHero
image={heroImage}
imageMobile={heroImageMobile}
title={aboutPage.hero.title}
breadcrumb={aboutPage.hero.breadcrumb}
/>
{/* Overview */}
<section className="bg-paper">
<Editorial
caption={aboutPage.overview.caption}
captionLatin={aboutPage.overview.captionLatin}
title={aboutPage.overview.title}
body={aboutPage.overview.body}
/>
<FullBleed image={atelier} alt="معماری پروژه‌های گروه ساختمانی رئوفی" />
</section>
{/* Philosophy */}
<section className="bg-sand">
<Editorial
caption={aboutPage.philosophy.caption}
captionLatin={aboutPage.philosophy.captionLatin}
title={aboutPage.philosophy.title}
body={aboutPage.philosophy.body}
/>
</section>
{/* Foundations */}
<section className="bg-paper">
<Editorial
caption={aboutPage.pillars.caption}
captionLatin={aboutPage.pillars.captionLatin}
title={aboutPage.pillars.title}
body={aboutPage.pillars.body}
/>
<Pillars />
</section>
{/* Portfolio */}
<section className="bg-sand">
<Editorial
caption={aboutPage.portfolio.caption}
captionLatin={aboutPage.portfolio.captionLatin}
title={aboutPage.portfolio.title}
body={aboutPage.portfolio.body}
/>
<ProjectGallery projects={displayProjects} />
</section>
{/* Closing statement */}
<section className="bg-paper">
<div className="mx-auto max-w-[1400px] px-6 py-24 text-center lg:px-12 lg:py-48">
<Reveal>
<p className="mx-auto max-w-[860px] text-[1.35rem] leading-[2.1] font-light text-ink lg:text-[1.75rem] lg:leading-[2]">
{aboutPage.closing.body}
</p>
</Reveal>
<Reveal delay={140}>
<span
aria-hidden="true"
className="mx-auto mt-14 block h-px w-24 bg-gold"
/>
</Reveal>
</div>
<FullBleed image={about} alt="نمای پروژه‌های گروه ساختمانی رئوفی" />
</section>
<PageCta
caption={aboutPage.cta.caption}
title={aboutPage.cta.title}
action={aboutPage.cta.action}
/>
</main>
<SiteFooter /> <SiteFooter />
</> </>
); );
+72
View File
@@ -0,0 +1,72 @@
import { NextResponse } from "next/server";
const CONTACT_ENDPOINT =
"https://api.meshkee.com/api/v1/tenants/raoofigroup.com/contact-submissions";
const REQUEST_TIMEOUT_MS = 10_000;
type ContactRequest = {
name?: unknown;
phone?: unknown;
email?: unknown;
message?: unknown;
};
function clean(value: unknown, maxLength: number) {
return typeof value === "string" ? value.trim().slice(0, maxLength) : "";
}
export async function POST(request: Request) {
let body: ContactRequest;
try {
body = (await request.json()) as ContactRequest;
} catch {
return NextResponse.json({ message: "اطلاعات فرم معتبر نیست." }, { status: 400 });
}
const name = clean(body.name, 120);
const cellNumber = clean(body.phone, 16);
const email = clean(body.email, 254);
const text = clean(body.message, 4_000);
if (!name || !text || !/^\+989\d{9}$/.test(cellNumber)) {
return NextResponse.json({ message: "لطفاً اطلاعات فرم را به‌درستی وارد کنید." }, { status: 400 });
}
if (email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
return NextResponse.json({ message: "نشانی ایمیل معتبر نیست." }, { status: 400 });
}
try {
const response = await fetch(CONTACT_ENDPOINT, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "درخواست تماس از وب‌سایت رئوفی",
name,
cellNumber,
text,
...(email ? { email } : {}),
}),
cache: "no-store",
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
});
if (!response.ok) {
return NextResponse.json(
{ message: "ارسال پیام با خطا روبه‌رو شد. لطفاً دوباره تلاش کنید." },
{ status: response.status >= 500 ? 502 : 400 },
);
}
return NextResponse.json({ message: "پیام شما با موفقیت ارسال شد." }, { status: 201 });
} catch {
return NextResponse.json(
{ message: "در حال حاضر ارتباط با سرویس پیام برقرار نیست. لطفاً کمی بعد دوباره تلاش کنید." },
{ status: 503 },
);
}
}
+5 -4
View File
@@ -4,7 +4,7 @@ import { NextRequest, NextResponse } from "next/server";
type RevalidateBody = { type RevalidateBody = {
/** Revalidate a fetch cache tag (portfolios, blogs, portfolio:slug, blog:slug, …). */ /** Revalidate a fetch cache tag (portfolios, blogs, portfolio:slug, blog:slug, …). */
tag?: string; tag?: string;
/** Revalidate a path (/portfolios/foo, /, …). */ /** Revalidate a path (/projects/foo, /, …). */
path?: string; path?: string;
/** Shorthand: portfolios | blogs | all */ /** Shorthand: portfolios | blogs | all */
scope?: "portfolios" | "blogs" | "all"; scope?: "portfolios" | "blogs" | "all";
@@ -15,7 +15,7 @@ type RevalidateBody = {
* *
* POST /api/revalidate * POST /api/revalidate
* Header: x-revalidate-secret: <REVALIDATE_SECRET> * Header: x-revalidate-secret: <REVALIDATE_SECRET>
* Body (JSON, optional): { "scope": "all" } | { "tag": "portfolios" } | { "path": "/portfolios/item" } * Body (JSON, optional): { "scope": "all" } | { "tag": "portfolios" } | { "path": "/projects/item" }
* *
* nginx may still serve cached HTML for up to its TTL (5m) unless purged separately. * nginx may still serve cached HTML for up to its TTL (5m) unless purged separately.
*/ */
@@ -50,9 +50,10 @@ export async function POST(req: NextRequest) {
} else if (scope === "portfolios" || scope === "all") { } else if (scope === "portfolios" || scope === "all") {
revalidateTag("portfolios"); revalidateTag("portfolios");
revalidatePath("/"); revalidatePath("/");
revalidatePath("/portfolios"); revalidatePath("/projects");
revalidatePath("/aboutus"); revalidatePath("/aboutus");
revalidatePath("/our-services"); revalidatePath("/atelier");
revalidatePath("/raoofi-home");
revalidated.push("scope:portfolios"); revalidated.push("scope:portfolios");
} }

Some files were not shown because too many files have changed in this diff Show More