Update carousels, card hover, and IranBay branding.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+451
@@ -0,0 +1,451 @@
|
||||
import Header from "@/components/Header";
|
||||
import Footer from "@/components/Footer";
|
||||
import ProducerCard from "@/components/ProducerCard";
|
||||
import {
|
||||
aboutBullets,
|
||||
featuredCategories,
|
||||
featuredProducers,
|
||||
type Producer,
|
||||
} from "@/data/home";
|
||||
import {
|
||||
getWebsiteHomeMedia,
|
||||
type WebsiteMediaItem,
|
||||
} from "@/lib/website-media";
|
||||
import {
|
||||
carouselBusinessToProducer,
|
||||
getWebsiteCarousels,
|
||||
type WebsiteCarousel,
|
||||
} from "@/lib/website-carousels";
|
||||
import styles from "./home.module.css";
|
||||
|
||||
function SectionHeading({
|
||||
title,
|
||||
subtitle,
|
||||
exploreHref,
|
||||
}: {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
exploreHref: string;
|
||||
}) {
|
||||
return (
|
||||
<div className={styles.sectionHead}>
|
||||
<div className={styles.arrows}>
|
||||
<button
|
||||
className={`tile-hover ${styles.arrowBtn}`}
|
||||
type="button"
|
||||
aria-label="Previous"
|
||||
>
|
||||
<img
|
||||
className={styles.arrowPrev}
|
||||
src="/images/icons/chevron.svg"
|
||||
alt=""
|
||||
width={8}
|
||||
height={14}
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
className={`tile-hover ${styles.arrowBtn}`}
|
||||
type="button"
|
||||
aria-label="Next"
|
||||
>
|
||||
<img src="/images/icons/chevron.svg" alt="" width={8} height={14} />
|
||||
</button>
|
||||
</div>
|
||||
<div className={styles.sectionTitles}>
|
||||
<h2 className={styles.sectionTitle}>{title}</h2>
|
||||
<p className={styles.sectionSubtitle}>
|
||||
{subtitle || "some of our most crowded categories"}
|
||||
</p>
|
||||
</div>
|
||||
<a className={`tile-hover ${styles.explore}`} href={exploreHref}>
|
||||
Explore all
|
||||
<img src="/images/icons/menu.svg" alt="" width={22} height={22} />
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function BusinessCarouselSection({
|
||||
carousel,
|
||||
fallbackProducers,
|
||||
}: {
|
||||
carousel?: WebsiteCarousel;
|
||||
fallbackProducers?: Producer[];
|
||||
}) {
|
||||
if (!carousel) return null;
|
||||
|
||||
const producers =
|
||||
carousel.businesses.length > 0
|
||||
? carousel.businesses.map(carouselBusinessToProducer)
|
||||
: (fallbackProducers ?? []);
|
||||
|
||||
if (!producers.length) return null;
|
||||
|
||||
return (
|
||||
<section
|
||||
className={`${styles.section} ${styles.carousel}`}
|
||||
id={carousel.slug || carousel.id}
|
||||
>
|
||||
<SectionHeading
|
||||
title={carousel.title}
|
||||
subtitle={carousel.subtext || undefined}
|
||||
exploreHref="/businesses"
|
||||
/>
|
||||
<div className={styles.producerGrid}>
|
||||
{producers.map((producer) => (
|
||||
<ProducerCard
|
||||
key={`${carousel.id}-${producer.slug}`}
|
||||
producer={producer}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function TitleLines({ text }: { text: string }) {
|
||||
const lines = text.includes("\n")
|
||||
? text.split("\n")
|
||||
: (() => {
|
||||
const parts = text.trim().split(/\s+/);
|
||||
if (parts.length <= 1) return [text];
|
||||
return [parts[0], parts.slice(1).join(" ")];
|
||||
})();
|
||||
|
||||
return (
|
||||
<>
|
||||
{lines.map((line, index) => (
|
||||
<span key={`${line}-${index}`}>
|
||||
{index > 0 ? <br /> : null}
|
||||
{line}
|
||||
</span>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function fallbackMedia() {
|
||||
return {
|
||||
slider: [
|
||||
{
|
||||
id: "slider-1",
|
||||
imageUrl: "/images/hero/furniture.png",
|
||||
linkUrl: "#producers",
|
||||
title: "Iranian modern art",
|
||||
cta: "browse furniture producers",
|
||||
},
|
||||
] satisfies WebsiteMediaItem[],
|
||||
standingBanners: [
|
||||
{
|
||||
id: "standing-1",
|
||||
imageUrl: "/images/hero/ice-cream.png",
|
||||
linkUrl: "#producers",
|
||||
title: "food industry",
|
||||
cta: "browse producers",
|
||||
},
|
||||
{
|
||||
id: "standing-2",
|
||||
imageUrl: "/images/hero/rug.png",
|
||||
linkUrl: "#producers",
|
||||
title: "original & pure art",
|
||||
cta: "browse producers",
|
||||
},
|
||||
] satisfies WebsiteMediaItem[],
|
||||
categories: featuredCategories.map((category, index) => ({
|
||||
id: `cat-${index + 1}`,
|
||||
imageUrl: category.image,
|
||||
linkUrl: "#producers",
|
||||
title: category.title,
|
||||
subtitle: category.description,
|
||||
})),
|
||||
menuImages: [],
|
||||
aboutUs: {
|
||||
id: "about-1",
|
||||
imageUrl: "/images/banners/ship.png",
|
||||
linkUrl: "/about",
|
||||
} satisfies WebsiteMediaItem,
|
||||
banners: [
|
||||
{
|
||||
id: "banner-1",
|
||||
imageUrl: "/images/banners/tv.png",
|
||||
linkUrl: "#producers",
|
||||
title: "Iranian modern art",
|
||||
cta: "browse furniture producers",
|
||||
},
|
||||
{
|
||||
id: "banner-2",
|
||||
imageUrl: "/images/banners/pistachio.png",
|
||||
linkUrl: "#producers",
|
||||
title: "food industry",
|
||||
cta: "browse producers",
|
||||
},
|
||||
{
|
||||
id: "banner-3",
|
||||
imageUrl: "/images/banners/shampoo.png",
|
||||
linkUrl: "#producers",
|
||||
title: "food industry",
|
||||
cta: "browse producers",
|
||||
},
|
||||
{
|
||||
id: "banner-4",
|
||||
imageUrl: "/images/banners/saffron.png",
|
||||
linkUrl: "#producers",
|
||||
title: "original & pure art",
|
||||
cta: "browse producers",
|
||||
},
|
||||
{
|
||||
id: "banner-5",
|
||||
imageUrl: "/images/banners/plane.png",
|
||||
linkUrl: "/register",
|
||||
title: "let's export",
|
||||
cta: "begin",
|
||||
},
|
||||
] satisfies WebsiteMediaItem[],
|
||||
};
|
||||
}
|
||||
|
||||
export default async function Home() {
|
||||
const [mediaResult, carousels] = await Promise.all([
|
||||
getWebsiteHomeMedia(),
|
||||
getWebsiteCarousels(),
|
||||
]);
|
||||
const media = mediaResult ?? fallbackMedia();
|
||||
const slide = media.slider[0];
|
||||
const standing = media.standingBanners;
|
||||
const collectionBanners = media.banners.slice(0, 4);
|
||||
const exportBanner =
|
||||
media.banners[4] ?? media.banners[media.banners.length - 1];
|
||||
|
||||
const [firstCarousel, secondCarousel, ...restCarousels] = carousels;
|
||||
|
||||
return (
|
||||
<div className={styles.page} id="top">
|
||||
<Header />
|
||||
|
||||
<main>
|
||||
<section className={styles.section} aria-label="Featured collections">
|
||||
<div className={styles.hero}>
|
||||
<article className={`tile-hover ${styles.heroCard} ${styles.heroMain}`}>
|
||||
<button
|
||||
className={`${styles.heroNav} ${styles.heroPrev}`}
|
||||
type="button"
|
||||
aria-label="Previous slide"
|
||||
>
|
||||
<img src="/images/icons/chevron.svg" alt="" width={11} height={22} />
|
||||
</button>
|
||||
<div className={styles.heroCopy}>
|
||||
<h1 className={styles.heroTitle}>
|
||||
<TitleLines text={slide?.title || "Iranian modern art"} />
|
||||
</h1>
|
||||
<a
|
||||
className={`outline-btn ${styles.heroBtn}`}
|
||||
href={slide?.linkUrl || "#producers"}
|
||||
>
|
||||
{slide?.cta || "browse furniture producers"}
|
||||
</a>
|
||||
</div>
|
||||
<img
|
||||
className={`${styles.heroImage} ${styles.heroFurniture}`}
|
||||
src={slide?.imageUrl || "/images/hero/furniture.png"}
|
||||
alt={slide?.title || "Iranian modern furniture"}
|
||||
/>
|
||||
<button
|
||||
className={`${styles.heroNav} ${styles.heroNext}`}
|
||||
type="button"
|
||||
aria-label="Next slide"
|
||||
>
|
||||
<img src="/images/icons/chevron.svg" alt="" width={11} height={22} />
|
||||
</button>
|
||||
</article>
|
||||
|
||||
{standing.slice(0, 2).map((banner, index) => (
|
||||
<article key={banner.id} className={`tile-hover ${styles.heroCard}`}>
|
||||
<img
|
||||
className={`${styles.heroImage} ${
|
||||
index === 0 ? styles.heroIceCream : styles.heroRug
|
||||
}`}
|
||||
src={banner.imageUrl}
|
||||
alt={banner.title || ""}
|
||||
/>
|
||||
<h2 className={`${styles.heroTitle} ${styles.heroTitleSmall}`}>
|
||||
<TitleLines text={banner.title || "Browse"} />
|
||||
</h2>
|
||||
<a
|
||||
className={`outline-btn ${styles.heroBtnSmall}`}
|
||||
href={banner.linkUrl || "#producers"}
|
||||
>
|
||||
{banner.cta || "browse producers"}
|
||||
</a>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className={styles.section} id="join">
|
||||
<a href="/register" className={`tile-hover ${styles.join}`}>
|
||||
<img
|
||||
className={styles.joinIcon}
|
||||
src="/images/icons/join-add.svg"
|
||||
alt=""
|
||||
width={62}
|
||||
height={62}
|
||||
/>
|
||||
<span className={styles.joinCopy}>
|
||||
<span className={styles.joinTitle}>Join our club</span>
|
||||
<span className={styles.joinText}>
|
||||
we will show your business to verity
|
||||
<br />
|
||||
of visitor around the world
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<section className={`${styles.section} ${styles.container}`} id="categories">
|
||||
<div className={styles.sectionHeadCentered}>
|
||||
<h2 className={styles.sectionTitle}>Featured categories</h2>
|
||||
<p className={styles.sectionSubtitle}>
|
||||
some of our most crowded categories
|
||||
</p>
|
||||
</div>
|
||||
<div className={styles.categoryGrid}>
|
||||
{media.categories.map((category) => (
|
||||
<a
|
||||
key={category.id}
|
||||
href={category.linkUrl || "#producers"}
|
||||
className={styles.categoryCard}
|
||||
>
|
||||
<div className={`tile-hover ${styles.categoryStage}`}>
|
||||
<img
|
||||
className={styles.categoryImage}
|
||||
src={category.imageUrl}
|
||||
alt=""
|
||||
/>
|
||||
<h3 className={styles.categoryTitle}>
|
||||
{category.title || "Category"}
|
||||
</h3>
|
||||
<p className={styles.categoryCopy}>
|
||||
{category.subtitle || ""}
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<BusinessCarouselSection
|
||||
carousel={firstCarousel}
|
||||
fallbackProducers={featuredProducers}
|
||||
/>
|
||||
|
||||
<section className={`${styles.section} ${styles.container}`} id="about">
|
||||
<div className={styles.about}>
|
||||
<div>
|
||||
<h2 className={styles.aboutKicker}>
|
||||
IranBay<span>,</span>
|
||||
</h2>
|
||||
<p className={styles.aboutLead}>
|
||||
We are a gate to iran’s market place
|
||||
</p>
|
||||
<p className={styles.aboutBody}>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
|
||||
enim ad minim veniam, quis nostrud exercitation ullamco laboris
|
||||
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
|
||||
reprehenderit in voluptate velit esse cillum dolore eu fugiat
|
||||
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
|
||||
sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
<ul className={styles.aboutList}>
|
||||
{aboutBullets.map((item, index) => (
|
||||
<li key={`${item}-${index}`}>
|
||||
<img src="/images/icons/bullet.svg" alt="" width={11} height={11} />
|
||||
<span>{item}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<a
|
||||
className={`outline-btn ${styles.aboutBtn}`}
|
||||
href={media.aboutUs.linkUrl || "/about"}
|
||||
>
|
||||
know more about us
|
||||
</a>
|
||||
</div>
|
||||
<div className={styles.aboutVisual}>
|
||||
<div className={styles.aboutFrame} />
|
||||
<img
|
||||
className={styles.aboutShip}
|
||||
src={media.aboutUs.imageUrl}
|
||||
alt="Cargo ship entering the market"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<BusinessCarouselSection
|
||||
carousel={secondCarousel}
|
||||
fallbackProducers={featuredProducers}
|
||||
/>
|
||||
|
||||
<section className={`${styles.section} ${styles.bannerBlock}`} aria-label="Browse collections">
|
||||
<div className={styles.bannerRow}>
|
||||
{collectionBanners.map((banner, index) => (
|
||||
<article
|
||||
key={banner.id}
|
||||
className={`tile-hover ${styles.bannerCard} ${
|
||||
index === 0 ? styles.bannerWide : ""
|
||||
}`}
|
||||
>
|
||||
<img
|
||||
className={styles.bannerImage}
|
||||
src={banner.imageUrl}
|
||||
alt={banner.title || ""}
|
||||
/>
|
||||
<h2 className={styles.bannerTitle}>
|
||||
<TitleLines text={banner.title || "Browse"} />
|
||||
</h2>
|
||||
<a
|
||||
className={`outline-btn ${styles.bannerBtn} ${
|
||||
index === 0 ? styles.bannerBtnWide : ""
|
||||
}`}
|
||||
href={banner.linkUrl || "#producers"}
|
||||
>
|
||||
{banner.cta || "browse producers"}
|
||||
</a>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
{exportBanner ? (
|
||||
<div className={`tile-hover ${styles.exportCta}`}>
|
||||
<img
|
||||
className={styles.plane}
|
||||
src={exportBanner.imageUrl}
|
||||
alt=""
|
||||
/>
|
||||
<h2 className={styles.exportTitle}>
|
||||
<TitleLines text={exportBanner.title || "let's export"} />
|
||||
</h2>
|
||||
<a
|
||||
className={`outline-btn ${styles.beginBtn}`}
|
||||
href={exportBanner.linkUrl || "/register"}
|
||||
>
|
||||
{exportBanner.cta || "begin"}
|
||||
<img src="/images/icons/chevron.svg" alt="" width={9} height={16} />
|
||||
</a>
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
|
||||
{restCarousels.map((carousel, index) => (
|
||||
<BusinessCarouselSection
|
||||
key={carousel.id}
|
||||
carousel={carousel}
|
||||
fallbackProducers={index === 0 ? featuredProducers : undefined}
|
||||
/>
|
||||
))}
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user