Files
studio-hom/src/app/page.tsx
T

300 lines
11 KiB
TypeScript

import type { Metadata } from "next";
import Link from "next/link";
import { DetailsFrame } from "@/components/DetailsFrame";
import { HeroSlider } from "@/components/HeroSlider";
import { InstagramFollow } from "@/components/InstagramFollow";
import { OpeningFrame } from "@/components/OpeningFrame";
import { SectionTitle } from "@/components/SectionTitle";
import { SlotImage } from "@/components/SlotImage";
import { gallery, processSteps, projects, services, site, stats } from "@/data/site";
import { resolveAbout, resolveInstagram, resolveLogo, resolveName } from "@/lib/content";
import { getBusinessInfo } from "@/lib/meshkee";
import { getPageSlots, slotImages, slotRatio } from "@/lib/static-images";
export const metadata: Metadata = {
description:
"استودیو معماری هوم؛ طراحی معماری، طراحی داخلی، طراحی نما و اجرای پروژه‌های مسکونی و تجاری با نگاهی مینیمال و دقیق.",
};
const ArrowIcon = () => (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden="true">
<path d="M4 12h16M13 5l7 7-7 7" />
</svg>
);
export default async function HomePage() {
const [info, slots] = await Promise.all([getBusinessInfo(), getPageSlots("home")]);
const name = resolveName(info);
const about = resolveAbout(info);
const logo = resolveLogo(info);
const instagram = resolveInstagram(info);
const heroSlides = slotImages("slider", slots, gallery.heroSlides);
const categoryImages = slotImages(
"four-category",
slots,
services.map((service) => ({
url: service.image,
titleFa: service.titleFa,
titleEn: service.titleEn,
subtext: service.text,
linkUrl: `/services/${service.slug}`,
})),
);
const projectSlots = slotImages(
"project-images",
slots,
projects.map((project) => ({
url: project.image,
titleFa: project.titleFa,
titleEn: project.titleEn,
subtext: `${project.category} · ${project.year}`,
linkUrl: `/portfolio/${project.slug}`,
})),
);
const sticky = slotImages("sticky-frame-bg", slots, [
{ url: gallery.studio, titleFa: "ورودی سبز", titleEn: "Studio", subtext: about[2] ?? site.about[2] },
])[0];
const openingImage = sticky.url || gallery.studio;
const instagramImage = slotImages("instagram-row", slots, [
{
url: gallery.instagram,
titleFa: "ما را در اینستاگرام دنبال کنید",
titleEn: "Follow us",
subtext: "پروژه‌های تازه و جزئیات اجرا را در صفحه اینستاگرام ببینید.",
linkUrl: instagram.href,
},
])[0];
const instagramRatio = slotRatio("instagram-row", slots);
const brandLogos = slotImages("brands", slots, gallery.brands);
const brandRatio = slotRatio("brands", slots);
return (
<>
<HeroSlider
slides={heroSlides}
title="معماری ساده،"
titleLine2="زندگی روشن"
lead={`${name} یک گروه معماری و طراحی داخلی است؛ از طراحی نما و پلان تا جزئیات داخلی و اجرای نهایی.`}
ctaLabel="شروع یک پروژه"
ctaHref="/contact"
/>
{/* Intro — RTL: logo (rightmost) · copy · focus (left) */}
<section className="section">
<div className="container intro">
<div className="intro__brand">
<img src={logo} alt={name} className="intro__logo" width={480} height={186} />
</div>
<div className="intro__copy">
<SectionTitle en="studio" title={about[0]} className="section-title--compact section-title--story" />
</div>
<div className="intro__meta">
<p>{about[1] ?? site.about[1]}</p>
<div>
<strong>تمرکز ما</strong>
<span>معماری مسکونی، طراحی داخلی، طراحی نما</span>
</div>
<Link href="/about" className="text-link">
بیشتر بدانید
</Link>
</div>
</div>
</section>
{/* four-category — 4 service panels */}
<section className="section section--tight">
<div className="container">
<SectionTitle en="services" title="ما در هوم." titleMuted="چه کارهایی انجام می‌دهیم" />
</div>
<div className="service-panels" role="list">
{Array.from({ length: 4 }, (_, index) => {
const service = services[index];
const cms = categoryImages[index];
const image = cms?.url || service?.image || gallery.heroSlides[0].url;
const titleFa = cms?.titleFa || service?.titleFa || `خدمت ${index + 1}`;
const titleEn = cms?.titleEn || service?.titleEn || "";
const desc = cms?.subtext || service?.text || "";
const href = cms?.linkUrl || (service ? `/services/${service.slug}` : "/services");
const external = /^https?:\/\//.test(href);
return (
<Link
key={service?.index ?? index}
href={href}
className="service-panel"
role="listitem"
aria-label={`${titleFa}${titleEn ? ` — ${titleEn}` : ""}`}
target={external ? "_blank" : undefined}
rel={external ? "noreferrer" : undefined}
>
<img
src={image!}
alt={`${titleFa}${titleEn ? ` / ${titleEn}` : ""}`}
className="service-panel__image"
loading="lazy"
decoding="async"
/>
<div className="service-panel__shade" aria-hidden="true" />
<div className="service-panel__body">
<span className="service-panel__index">{service?.index ?? String(index + 1).padStart(2, "0")}</span>
<h3>{titleFa}</h3>
{titleEn ? <span className="latin">{titleEn}</span> : null}
{desc ? <p className="service-panel__desc">{desc}</p> : null}
</div>
</Link>
);
})}
</div>
</section>
{/* project-images — masonry */}
<section className="section">
<div className="container">
<SectionTitle
en="projects"
title="پروژه‌های"
titleMuted="منتخب"
aside={<p className="lead">گزیده‌ای از کارهای اخیر در معماری، طراحی داخلی و نما.</p>}
/>
<div className="projects">
{projectSlots.map((image, index) => {
const title = image.titleFa || image.titleEn || `پروژه ${index + 1}`;
const media = { ...image, linkUrl: null };
const card = (
<>
<SlotImage image={media} alt={title} />
<div className="project__meta">
<h3>{title}</h3>
{image.subtext ? <span>{image.subtext}</span> : null}
</div>
{image.titleEn ? <p className="project__sub latin">{image.titleEn}</p> : null}
</>
);
if (image.linkUrl) {
const external = /^https?:\/\//.test(image.linkUrl);
return (
<Link
key={`${image.url}-${index}`}
href={image.linkUrl}
className="project"
target={external ? "_blank" : undefined}
rel={external ? "noreferrer" : undefined}
>
{card}
</Link>
);
}
return (
<div key={`${image.url}-${index}`} className="project">
{card}
</div>
);
})}
</div>
</div>
</section>
<DetailsFrame />
{/* sticky-frame-bg */}
<OpeningFrame
image={openingImage}
imageAlt={sticky.titleFa || sticky.titleEn || "نگاه استودیو هوم"}
eyebrow={sticky.titleEn || "نگاه ما"}
headline="معماری ساده،"
headlineMuted="زندگی روشن"
headlineEn="SIMPLE ARCHITECTURE, BRIGHT LIVING"
body={sticky.subtext || about[2] || site.about[2]}
ctaLabel="درباره استودیو"
ctaHref="/about"
/>
{/* Process */}
<section className="section section--dark">
<div className="container">
<SectionTitle en="process" title="از ایده تا تحویل،" titleMuted="در چهار گام" light />
<div className="process">
{processSteps.map((item) => (
<div key={item.step} className="process__item">
<span className="process__num latin" lang="en" dir="ltr" aria-hidden="true">
{String(item.step).padStart(2, "0")}
</span>
<h3>{item.titleFa}</h3>
<p>{item.text}</p>
</div>
))}
</div>
</div>
</section>
{/* Stats */}
<section className="stats-band" aria-label="آمار استودیو">
<div className="stats">
{stats.map((stat) => (
<div key={stat.label} className="stat">
<strong className="latin" lang="en" dir="ltr">
{stat.value}
</strong>
<span>{stat.label}</span>
</div>
))}
</div>
</section>
{/* brands */}
{brandLogos.length ? (
<section className="section section--tight brands" aria-label="همکاران">
<div className="container">
<SectionTitle en="partners" title="برندها و" titleMuted="همکاران" />
<ul className="brands__grid">
{brandLogos.map((brand, index) => {
const alt = brand.titleFa || brand.titleEn || `برند ${index + 1}`;
return (
<li key={`${brand.url}-${index}`}>
<SlotImage image={brand} alt={alt} ratio={brandRatio} className="brands__logo" />
{brand.titleFa || brand.titleEn ? (
<p className="brands__caption">
{brand.titleFa ? <span>{brand.titleFa}</span> : null}
{brand.titleEn ? <span className="latin">{brand.titleEn}</span> : null}
</p>
) : null}
</li>
);
})}
</ul>
</div>
</section>
) : null}
{/* instagram-row */}
<InstagramFollow
handle={instagram.handle}
href={instagram.href}
image={instagramImage}
ratio={instagramRatio}
/>
{/* CTA */}
<section className="cta-band">
<div className="cta-band__glow" aria-hidden="true" />
<div className="container cta">
<SectionTitle
en="collaborate"
title="پروژه‌ای در ذهن دارید؟"
titleMuted="درباره‌اش صحبت کنیم."
className="section-title--inline section-title--light"
aside={
<Link href="/contact" className="btn btn--light">
تماس با ما
<ArrowIcon />
</Link>
}
/>
</div>
</section>
</>
);
}