Files
havaran/src/components/PageShared.tsx
T
Alireza HassaniandCursor c49347061c Build Havaran storefront with Meshkee-backed blogs and portfolios.
Clone product, solution, and company pages from the original site and wire articles/projects to the Meshkee Website API with pagination and media from the backend CDN.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-09 15:54:40 +03:30

168 lines
4.5 KiB
TypeScript

import Image from "next/image";
type PageHeroProps = {
title: string;
titleEn?: string;
breadcrumb?: { label: string; href: string }[];
};
export function PageHero({ title, titleEn, breadcrumb }: PageHeroProps) {
return (
<section className="border-b border-[#eee] bg-[#f7f7f7]">
<div className="container-page py-10 text-center sm:py-12">
{breadcrumb ? (
<nav className="mb-4 flex flex-wrap items-center justify-center gap-2 text-xs text-[#888]">
{breadcrumb.map((item, i) => (
<span key={item.href} className="inline-flex items-center gap-2">
{i > 0 ? <span>/</span> : null}
<a href={item.href} className="hover:text-brand">
{item.label}
</a>
</span>
))}
</nav>
) : null}
<h1 className="mb-2 text-2xl font-bold text-[#232323] sm:text-[32px]">
{title}
</h1>
{titleEn ? (
<p className="text-sm tracking-[2px] text-[#9a9a9a] uppercase">
{titleEn}
</p>
) : null}
</div>
</section>
);
}
type CatalogCardProps = {
href: string;
image: string;
title: string;
titleEn: string;
description: string;
};
export function CatalogCard({
href,
image,
title,
titleEn,
description,
}: CatalogCardProps) {
return (
<article className="card-shadow flex h-full flex-col bg-white p-5 text-center">
<a href={href} className="mb-4 flex h-[120px] items-center justify-center">
<Image
src={image}
alt={title}
width={160}
height={120}
unoptimized
className="max-h-[120px] w-auto object-contain"
style={{ width: "auto", height: 120 }}
/>
</a>
<h2 className="mb-1 text-[16px] font-bold text-[#232323]">
<a href={href}>{title}</a>
</h2>
<p className="mb-3 text-xs font-semibold tracking-wide text-[#999]">
{titleEn}
</p>
<p className="mb-5 line-clamp-3 flex-1 text-sm leading-7 text-[#666]">
{description}
</p>
<a href={href} className="btn-more mx-auto">
بیشتر بدانید
</a>
</article>
);
}
type ContentSectionProps = {
title: string;
titleEn?: string;
image?: string;
imageAlt?: string;
children: React.ReactNode;
reverse?: boolean;
};
export function ContentSection({
title,
titleEn,
image,
imageAlt,
children,
reverse,
}: ContentSectionProps) {
return (
<section className="section">
<div
className={`container-page grid items-center gap-8 md:grid-cols-2 ${
reverse ? "md:[&>*:first-child]:order-2" : ""
}`}
>
{image ? (
<div
className={`relative aspect-[4/3] overflow-hidden ${
image.endsWith(".png") ? "" : "bg-[#f7f7f7]"
}`}
>
<Image
src={image}
alt={imageAlt || title}
fill
className="object-contain p-4"
sizes="(max-width: 768px) 100vw, 50vw"
/>
</div>
) : null}
<div className={image ? "" : "md:col-span-2"}>
<h2 className="mb-2 text-xl font-bold text-[#232323] sm:text-2xl">
{title}
</h2>
{titleEn ? (
<p className="mb-4 text-sm tracking-wide text-[#999]">{titleEn}</p>
) : null}
<div className="space-y-3 text-sm leading-8 text-[#666]">{children}</div>
</div>
</div>
</section>
);
}
export function SpecList({ items }: { items: string[] }) {
return (
<div className="mt-4">
<h3 className="mb-3 text-base font-bold text-[#232323]">مشخصات فنـــــی</h3>
<ul className="space-y-2">
{items.map((item) => (
<li
key={item}
className="flex gap-2 border-b border-[#f0f0f0] py-2 text-sm leading-7 text-[#555]"
>
<span className="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-green" />
<span>{item}</span>
</li>
))}
</ul>
</div>
);
}
export function UpdatingNotice() {
return (
<div className="container-page py-20 text-center">
<Image
src="/images/pages/shared/updating.png"
alt="در حال بروز رسانی"
width={120}
height={120}
className="mx-auto mb-6 opacity-70"
/>
<p className="text-lg font-bold text-[#666]">در حال بروز رسانی ...</p>
</div>
);
}