Add the FarrokhWin Next.js site for Meshkee hosting.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-31 09:18:26 +03:30
co-authored by Cursor
commit 4dec4eb92c
116 changed files with 13456 additions and 0 deletions
+310
View File
@@ -0,0 +1,310 @@
import Link from "next/link";
import AparatVideo from "@/components/AparatVideo";
import GlassReadMore from "@/components/GlassReadMore";
import HeroSlider from "@/components/HeroSlider";
import MediaCarousel from "@/components/MediaCarousel";
import Reveal from "@/components/Reveal";
import SlotImage from "@/components/SlotImage";
import { blogCategory, blogDateLong, blogHref, blogImage, fetchBlogs } from "@/lib/blog";
import {
blogPosts,
brands,
features,
homeProducts,
site,
slides,
whyText,
windowTypes,
} from "@/data/site";
import { productHref, productImage, productTitle, fetchProducts } from "@/lib/products";
import { toFaDigits } from "@/lib/format";
import { pageMetadata } from "@/lib/seo";
import { fetchStaticImageSlots, overlaySlotImages, pickSlot, type SlotMediaItem } from "@/lib/static-images";
function carouselItems(overlaid: SlotMediaItem[], fallbacks: SlotMediaItem[], max = 12) {
const seen = new Set<string>();
return fallbacks.slice(0, max).map((item, index) => {
const slotItem = overlaid[index];
if (!slotItem?.image) return item;
return {
...item,
image: slotItem.image,
href: slotItem.href || item.href,
title: item.title || slotItem.title,
kicker: item.kicker || slotItem.kicker,
};
}).filter((item) => {
if (!item.id || seen.has(item.id)) return false;
seen.add(item.id);
return true;
});
}
export const metadata = pageMetadata({
title: site.name,
description: site.description,
path: "/",
image: "/images/hero/slide-1.jpg",
absolute: true,
});
export default async function HomePage() {
const [slots, apiBlogs, apiProducts] = await Promise.all([
fetchStaticImageSlots("home"),
fetchBlogs({ pageSize: 12 }),
fetchProducts({ pageSize: 12 }),
]);
const slider = overlaySlotImages(
pickSlot(slots, "slider"),
slides.map((slide) => ({
id: slide.id,
image: slide.image,
title: slide.title,
})),
"slider",
);
const windows = overlaySlotImages(
pickSlot(slots, "home-windows"),
windowTypes.map((item) => ({
id: item.id,
image: item.image,
title: item.title,
text: item.text,
href: item.href,
})),
"home-windows",
);
const whyImage = overlaySlotImages(
pickSlot(slots, "home-why-image"),
[{ id: "why", image: "/images/features/01.png", title: "چرا پنجره فرخ" }],
"home-why-image",
);
const blogFallbacks: SlotMediaItem[] = apiBlogs.items.length
? apiBlogs.items.map((post) => ({
id: post.id,
image: blogImage(post),
title: post.title,
kicker: blogCategory(post) || undefined,
text: blogDateLong(post) || undefined,
href: blogHref(post),
}))
: blogPosts.map((post) => ({
id: post.id,
image: post.image,
title: post.title,
kicker: post.category,
href: post.href,
}));
const blogItems = overlaySlotImages(pickSlot(slots, "home-blog"), blogFallbacks, "home-blog");
const productFallbacks: SlotMediaItem[] = apiProducts.items.length
? apiProducts.items.map((product) => ({
id: product.id,
image: productImage(product),
title: productTitle(product),
kicker: product.title && product.nameFa ? product.title : product.categoryNameFa || undefined,
href: productHref(product),
}))
: homeProducts.map((product) => ({
id: product.id,
image: product.image,
title: product.title,
kicker: product.kicker,
href: product.href,
}));
const productItems = overlaySlotImages(pickSlot(slots, "home-products"), productFallbacks, "home-products");
const clientItems = overlaySlotImages(
pickSlot(slots, "home-clients"),
brands.map((brand) => ({
id: brand.id,
image: brand.image,
title: brand.title,
})),
"home-clients",
);
return (
<>
<HeroSlider slides={slider.items} />
<section className="stats-bar">
<div className="container stats-inner">
<div>
<strong>{toFaDigits(site.projects)}</strong>
<span>پروژه انجام شده</span>
</div>
<div>
<strong>{toFaDigits(site.workYears)}</strong>
<span>تجربه کاری</span>
</div>
<div>
<strong>درب و پنجره پنجره فرخ</strong>
<span>{site.slogan}</span>
</div>
</div>
</section>
<section className="section intro-section">
<div className="container intro-grid">
<Reveal>
<div className="years-box">
<span className="years-frame years-frame--left" aria-hidden />
<span className="years-frame years-frame--right" aria-hidden />
<span className="years-num">{toFaDigits(site.experienceYears)}</span>
<span className="years-label">ســــال تجربه در صنعت</span>
</div>
</Reveal>
<Reveal delay={80}>
<div className="intro-brand">
<p className="from-year">از سال {site.foundedYear}</p>
<h1>
شرکــــت درب و پنجــــــــــره
<br />
پنجره فرخ
</h1>
</div>
</Reveal>
<Reveal delay={160}>
<div>
<p className="muted">{site.tagline}</p>
<Link className="text-link" href="/about">
توضیحات بیشتر
</Link>
</div>
</Reveal>
</div>
</section>
<section className="video-heading">
<div className="container">
<h2>فرخ وین تولید کننده انواع پنجره UPVC و شیشه دو جداره</h2>
<AparatVideo />
</div>
</section>
<section className="section glass-section">
<div className="container">
<GlassReadMore />
</div>
</section>
<section className="section windows-section">
<div className="container">
<p className="section-kicker">دسته بندی های ما</p>
<h2>انواع درب و پنجره دوجداره</h2>
</div>
<div className="windows-wrap">
<div className="windows-grid">
{windows.items.map((item) => (
<article key={item.id} className="window-card">
<Link href={item.href || "/products"}>
<div className="window-photo">
<SlotImage src={item.image} alt={item.title || site.shortName} />
<span className="window-dim" aria-hidden />
<div className="window-content">
<h3>{item.title}</h3>
<span className="window-arrow" aria-hidden>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none">
<path d="M15 6l-6 6 6 6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</span>
</div>
<div className="window-hover">
<div className="window-hover-inner">
<p>{item.text}</p>
<span className="window-details">
نمایش جزئیات
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" aria-hidden>
<path d="M15 6l-6 6 6 6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</span>
</div>
</div>
</div>
</Link>
</article>
))}
</div>
</div>
</section>
<section className="section why-section">
<div className="why-watermark" aria-hidden>
Farrokh
</div>
<div className="container why-grid">
<Reveal>
<div className="why-photo">
<SlotImage
src={whyImage.items[0]?.image || "/images/features/01.png"}
alt={whyImage.items[0]?.title || "چرا پنجره فرخ"}
/>
</div>
</Reveal>
<Reveal delay={120} variant="left">
<div className="why-copy">
<h2>چرا پنجره فرخ ؟!</h2>
<p>{whyText}</p>
<Link className="text-link why-link" href="/products">
محصولات ما
</Link>
</div>
</Reveal>
</div>
</section>
<section className="section features-section">
<div className="container">
<p className="section-kicker">فرخ وین، تولید کننده شیشه دو جداره</p>
<div className="features-grid">
{features.map((feature) => (
<article key={feature.id}>
<SlotImage src={feature.image} alt={feature.title} width={72} height={72} />
<h3>{feature.title}</h3>
</article>
))}
</div>
</div>
</section>
<section className="section blog-section">
<div className="container">
<h2>آخرین مقالات</h2>
</div>
<MediaCarousel items={carouselItems(blogItems.items, blogFallbacks)} variant="blog" ariaLabel="آخرین مقالات" />
</section>
<section className="cta-section">
<div className="container">
<h2>
آیا آماده همکاری با ما هستید؟{" "}
<Link href="/contact">شروع یک پروژه</Link>
</h2>
</div>
</section>
<section className="section products-section">
<div className="container">
<p className="section-kicker">انتخاب مردم</p>
<h2>کارهای خاص</h2>
<MediaCarousel items={carouselItems(productItems.items, productFallbacks)} variant="product" ariaLabel="آخرین محصولات" />
</div>
</section>
<section className="section brands-section">
<div className="container">
<h2>برند های ما</h2>
<p className="en">OUR CUSTOMER</p>
<div className="brands-grid">
{clientItems.items.map((brand) => (
<Link key={brand.id} href="/products" className="brand-item" title={brand.title}>
<SlotImage src={brand.image} alt={brand.title || "برند"} />
</Link>
))}
</div>
</div>
</section>
</>
);
}