Add the FarrokhWin Next.js site for Meshkee hosting.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user