311 lines
11 KiB
TypeScript
311 lines
11 KiB
TypeScript
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>
|
|
</>
|
|
);
|
|
}
|