Add replaceable images, category mega menu, and contact pages.

Give every placeholder a real img src, add FAQ and contact sections, and put categories first in the header.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-13 14:18:47 +03:30
co-authored by Cursor
parent 78ef438f9d
commit 39d85512c5
65 changed files with 382 additions and 56 deletions
+5 -2
View File
@@ -9,7 +9,7 @@ Color palette is purple cyan red - light theme
Design only homepage Design only homepage
Use Persian font like iran-yekan or kalameh or iran sans and some cool kids like English font Use Persian font like iran-yekan or kalameh or iran sans and some cool kids like English font
Do not use images - show only placeholders with sizes Do not use images - show only placeholders images - use empty image file so they can be replace easily
Do not use text over the images or banners - even slider Do not use text over the images or banners - even slider
Sections are: Sections are:
@@ -30,4 +30,7 @@ Sections are:
10. Yeganeh brand product carousel 10. Yeganeh brand product carousel
11. About nini Naderi 11. About nini Naderi
12. Latest blog carousel 12. Latest blog carousel
13. footer 13. footer
For header, as first item add a categories, show a mega menu for categories
Other link are: special sale - about us - faq - contact us
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
import struct
import zlib
from pathlib import Path
COLORS = {
"purple": (216, 198, 255),
"cyan": (165, 243, 252),
"rose": (254, 205, 211),
}
IMAGES = [
("slider-1.png", 960, 420, "purple"),
("slider-2.png", 960, 420, "rose"),
("slider-3.png", 960, 420, "cyan"),
("side-banner-1.png", 360, 200, "cyan"),
("side-banner-2.png", 360, 200, "rose"),
("category-1.png", 160, 160, "purple"),
("category-2.png", 160, 160, "rose"),
("category-3.png", 160, 160, "cyan"),
("category-4.png", 160, 160, "purple"),
("category-5.png", 160, 160, "cyan"),
("category-6.png", 160, 160, "rose"),
("category-7.png", 160, 160, "purple"),
("category-8.png", 160, 160, "rose"),
("sale-banner.png", 240, 400, "rose"),
("sale-1.png", 280, 340, "purple"),
("sale-2.png", 280, 340, "rose"),
("sale-3.png", 280, 340, "cyan"),
("sale-4.png", 280, 340, "purple"),
("sale-5.png", 280, 340, "cyan"),
("sale-6.png", 280, 340, "rose"),
("sale-7.png", 280, 340, "purple"),
("sale-8.png", 280, 340, "cyan"),
("banner-dual-1.png", 640, 280, "purple"),
("banner-dual-2.png", 640, 280, "cyan"),
("top-1.png", 280, 340, "purple"),
("top-2.png", 280, 340, "cyan"),
("top-3.png", 280, 340, "rose"),
("top-4.png", 280, 340, "purple"),
("top-5.png", 280, 340, "cyan"),
("top-6.png", 280, 340, "rose"),
("top-7.png", 280, 340, "purple"),
("top-8.png", 280, 340, "cyan"),
("banner-triple-1.png", 420, 240, "rose"),
("banner-triple-2.png", 420, 240, "cyan"),
("banner-triple-3.png", 420, 240, "purple"),
("yeganeh-1.png", 280, 340, "purple"),
("yeganeh-2.png", 280, 340, "rose"),
("yeganeh-3.png", 280, 340, "cyan"),
("yeganeh-4.png", 280, 340, "purple"),
("yeganeh-5.png", 280, 340, "rose"),
("yeganeh-6.png", 280, 340, "cyan"),
("about.png", 560, 400, "purple"),
("blog-1.png", 360, 220, "purple"),
("blog-2.png", 360, 220, "cyan"),
("blog-3.png", 360, 220, "rose"),
("blog-4.png", 360, 220, "purple"),
("enamad.png", 80, 80, "purple"),
("samandehi.png", 80, 80, "cyan"),
]
def chunk(tag: bytes, data: bytes) -> bytes:
return struct.pack(">I", len(data)) + tag + data + struct.pack(">I", zlib.crc32(tag + data) & 0xFFFFFFFF)
def write_png(path: Path, width: int, height: int, rgb: tuple[int, int, int]) -> None:
row = b"\x00" + bytes(rgb) * width
raw = row * height
with path.open("wb") as handle:
handle.write(b"\x89PNG\r\n\x1a\n")
handle.write(chunk(b"IHDR", struct.pack(">IIBBBBB", width, height, 8, 2, 0, 0, 0)))
handle.write(chunk(b"IDAT", zlib.compress(raw, 9)))
handle.write(chunk(b"IEND", b""))
def main() -> None:
out = Path(__file__).resolve().parents[1] / "public" / "images"
out.mkdir(parents=True, exist_ok=True)
for name, width, height, tone in IMAGES:
write_png(out / name, width, height, COLORS[tone])
print(name)
if __name__ == "__main__":
main()
+4
View File
@@ -1,6 +1,8 @@
import { About } from "@/components/About"; import { About } from "@/components/About";
import { DualBanners, TripleBanners } from "@/components/Banners"; import { DualBanners, TripleBanners } from "@/components/Banners";
import { BlogCarousel } from "@/components/BlogCarousel"; import { BlogCarousel } from "@/components/BlogCarousel";
import { Contact } from "@/components/Contact";
import { Faq } from "@/components/Faq";
import { FeaturedCategories } from "@/components/FeaturedCategories"; import { FeaturedCategories } from "@/components/FeaturedCategories";
import { Features } from "@/components/Features"; import { Features } from "@/components/Features";
import { Footer } from "@/components/Footer"; import { Footer } from "@/components/Footer";
@@ -42,6 +44,8 @@ export default function Home() {
/> />
<About /> <About />
<BlogCarousel /> <BlogCarousel />
<Faq />
<Contact />
</main> </main>
<Footer /> <Footer />
</div> </div>
+3 -2
View File
@@ -26,11 +26,12 @@ export function About() {
</div> </div>
<div className="bg-purple-50 p-4 sm:p-6"> <div className="bg-purple-50 p-4 sm:p-6">
<Placeholder <Placeholder
src={about.image}
alt={about.title}
width={560} width={560}
height={400} height={400}
tone="purple"
rounded="rounded-[28px]" rounded="rounded-[28px]"
className="h-full min-h-[280px]" className="h-full min-h-[280px] object-cover"
/> />
</div> </div>
</div> </div>
+14 -2
View File
@@ -7,7 +7,13 @@ export function DualBanners() {
<div className="grid gap-4 md:grid-cols-2"> <div className="grid gap-4 md:grid-cols-2">
{dualBanners.map((banner) => ( {dualBanners.map((banner) => (
<a key={banner.id} href="#" className="overflow-hidden rounded-3xl"> <a key={banner.id} href="#" className="overflow-hidden rounded-3xl">
<Placeholder width={640} height={280} tone={banner.tone} rounded="rounded-3xl" /> <Placeholder
src={banner.image}
alt={banner.title}
width={640}
height={280}
rounded="rounded-3xl"
/>
</a> </a>
))} ))}
</div> </div>
@@ -21,7 +27,13 @@ export function TripleBanners() {
<div className="grid gap-4 md:grid-cols-3"> <div className="grid gap-4 md:grid-cols-3">
{tripleBanners.map((banner) => ( {tripleBanners.map((banner) => (
<a key={banner.id} href="#" className="overflow-hidden rounded-3xl"> <a key={banner.id} href="#" className="overflow-hidden rounded-3xl">
<Placeholder width={420} height={240} tone={banner.tone} rounded="rounded-3xl" /> <Placeholder
src={banner.image}
alt={banner.title}
width={420}
height={240}
rounded="rounded-3xl"
/>
</a> </a>
))} ))}
</div> </div>
+1 -1
View File
@@ -14,7 +14,7 @@ export function BlogCarousel() {
data-card data-card
className="glass-box w-[280px] shrink-0 snap-start overflow-hidden rounded-3xl shadow-soft sm:w-[320px]" className="glass-box w-[280px] shrink-0 snap-start overflow-hidden rounded-3xl shadow-soft sm:w-[320px]"
> >
<Placeholder width={360} height={220} tone={post.tone} rounded="rounded-none" /> <Placeholder src={post.image} alt={post.title} width={360} height={220} rounded="rounded-none" />
<div className="p-4"> <div className="p-4">
<p className="text-xs text-cyan-600">{post.date}</p> <p className="text-xs text-cyan-600">{post.date}</p>
<h3 className="mt-2 line-clamp-2 min-h-12 text-base font-bold leading-6 text-ink"> <h3 className="mt-2 line-clamp-2 min-h-12 text-base font-bold leading-6 text-ink">
+53
View File
@@ -0,0 +1,53 @@
import { footer } from "@/data/content";
import { IconPhone } from "./Icons";
export function Contact() {
return (
<section id="contact" className="container-nn py-10">
<div className="glass-box overflow-hidden rounded-[32px]">
<div className="grid gap-8 p-6 sm:p-10 lg:grid-cols-2">
<div>
<p className="font-display text-sm text-cyan-600">Contact us</p>
<h2 className="mt-1 text-2xl font-black text-ink sm:text-3xl">تماس با ما</h2>
<span className="mt-3 block h-1.5 w-16 rounded-full bg-linear-to-l from-purple-600 via-cyan-500 to-rose-500" />
<p className="mt-5 text-sm leading-8 text-muted">
برای سفارش عمده، سوال سایز یا پیگیری مرسوله، از این راه‌ها به نینی نادری برسید.
</p>
<ul className="mt-6 space-y-3 text-sm text-ink">
<li className="flex items-center gap-2">
<IconPhone className="size-4 text-purple-700" />
{footer.contact.phone}
</li>
<li>{footer.contact.mobile}</li>
<li>{footer.contact.email}</li>
<li className="leading-7 text-muted">{footer.contact.address}</li>
</ul>
</div>
<form className="grid gap-3">
<input
type="text"
placeholder="نام و نام خانوادگی"
className="h-11 rounded-2xl border border-line bg-white/70 px-4 text-sm outline-none focus:border-purple-500"
/>
<input
type="tel"
placeholder="شماره موبایل"
className="h-11 rounded-2xl border border-line bg-white/70 px-4 text-sm outline-none focus:border-purple-500"
/>
<textarea
rows={4}
placeholder="پیام شما"
className="rounded-2xl border border-line bg-white/70 px-4 py-3 text-sm outline-none focus:border-purple-500"
/>
<button
type="button"
className="h-11 rounded-full bg-purple-700 text-sm font-bold text-white hover:bg-purple-800"
>
ارسال پیام
</button>
</form>
</div>
</div>
</section>
);
}
+21
View File
@@ -0,0 +1,21 @@
import { faqs } from "@/data/content";
export function Faq() {
return (
<section id="faq" className="container-nn py-10">
<div className="mb-6">
<p className="font-display text-sm text-cyan-600">FAQ</p>
<h2 className="mt-1 text-2xl font-bold text-ink sm:text-3xl">سوالات متداول</h2>
<span className="mt-2 block h-1.5 w-16 rounded-full bg-linear-to-l from-purple-600 via-cyan-500 to-rose-500" />
</div>
<div className="grid gap-3 md:grid-cols-2">
{faqs.map((item) => (
<article key={item.q} className="glass-box rounded-3xl p-5">
<h3 className="text-base font-bold text-ink">{item.q}</h3>
<p className="mt-2 text-sm leading-7 text-muted">{item.a}</p>
</article>
))}
</div>
</section>
);
}
+2 -1
View File
@@ -15,9 +15,10 @@ export function FeaturedCategories() {
className="glass-box group rounded-3xl p-3 text-center shadow-soft transition hover:-translate-y-1" className="glass-box group rounded-3xl p-3 text-center shadow-soft transition hover:-translate-y-1"
> >
<Placeholder <Placeholder
src={category.image}
alt={category.title}
width={160} width={160}
height={160} height={160}
tone={category.tone}
rounded="rounded-2xl" rounded="rounded-2xl"
/> />
<h3 className="mt-3 text-sm font-bold text-ink">{category.title}</h3> <h3 className="mt-3 text-sm font-bold text-ink">{category.title}</h3>
+2 -2
View File
@@ -38,11 +38,11 @@ export function Footer() {
<p className="mt-2 text-sm text-ink">{footer.contact.email}</p> <p className="mt-2 text-sm text-ink">{footer.contact.email}</p>
<div className="mt-4 flex gap-2"> <div className="mt-4 flex gap-2">
<div> <div>
<Placeholder width={80} height={80} tone="purple" rounded="rounded-xl" /> <Placeholder src="/images/enamad.png" alt="اینماد" width={80} height={80} rounded="rounded-xl" />
<p className="mt-1 text-center text-[11px] text-muted">اینماد</p> <p className="mt-1 text-center text-[11px] text-muted">اینماد</p>
</div> </div>
<div> <div>
<Placeholder width={80} height={80} tone="cyan" rounded="rounded-xl" /> <Placeholder src="/images/samandehi.png" alt="ساماندهی" width={80} height={80} rounded="rounded-xl" />
<p className="mt-1 text-center text-[11px] text-muted">ساماندهی</p> <p className="mt-1 text-center text-[11px] text-muted">ساماندهی</p>
</div> </div>
</div> </div>
+90 -4
View File
@@ -2,11 +2,21 @@
import Link from "next/link"; import Link from "next/link";
import { useState } from "react"; import { useState } from "react";
import { navLinks } from "@/data/content"; import { categories, navLinks } from "@/data/content";
import { IconBag, IconClose, IconHeart, IconMenu, IconSearch, IconUser } from "./Icons"; import { toFaDigits } from "@/lib/format";
import { IconBag, IconChevronDown, IconClose, IconHeart, IconMenu, IconSearch, IconUser } from "./Icons";
import { Placeholder } from "./Placeholder";
export function Header() { export function Header() {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [mega, setMega] = useState(false);
const [mobileCats, setMobileCats] = useState(false);
const closeAll = () => {
setOpen(false);
setMega(false);
setMobileCats(false);
};
return ( return (
<header className="sticky top-0 z-40 border-b border-white/60 bg-white/55 backdrop-blur-xl"> <header className="sticky top-0 z-40 border-b border-white/60 bg-white/55 backdrop-blur-xl">
@@ -75,7 +85,23 @@ export function Header() {
</div> </div>
</form> </form>
<nav className="hidden h-12 items-center gap-6 text-sm font-medium text-ink lg:flex"> <nav className="relative hidden h-12 items-center gap-6 text-sm font-medium text-ink lg:flex">
<div
className="h-full"
onMouseEnter={() => setMega(true)}
onMouseLeave={() => setMega(false)}
>
<button
type="button"
className="relative flex h-full items-center gap-1 py-3 transition hover:text-purple-700"
aria-expanded={mega}
onClick={() => setMega((value) => !value)}
>
دسته‌بندی‌ها
<IconChevronDown className={`size-4 transition ${mega ? "rotate-180" : ""}`} />
</button>
{mega ? <MegaMenu onPick={closeAll} /> : null}
</div>
{navLinks.map((link) => ( {navLinks.map((link) => (
<a <a
key={link.label} key={link.label}
@@ -91,11 +117,33 @@ export function Header() {
{open ? ( {open ? (
<div className="border-t border-line bg-white lg:hidden"> <div className="border-t border-line bg-white lg:hidden">
<nav className="container-nn flex flex-col py-2 text-sm"> <nav className="container-nn flex flex-col py-2 text-sm">
<button
type="button"
className="flex items-center justify-between border-b border-line/70 py-3 text-ink"
onClick={() => setMobileCats((value) => !value)}
>
دسته‌بندی‌ها
<IconChevronDown className={`size-4 transition ${mobileCats ? "rotate-180" : ""}`} />
</button>
{mobileCats ? (
<div className="grid grid-cols-2 gap-2 border-b border-line/70 py-3">
{categories.map((category) => (
<a
key={category.id}
href="#categories"
onClick={closeAll}
className="rounded-2xl bg-purple-50/70 px-3 py-2 text-xs font-bold"
>
{category.title}
</a>
))}
</div>
) : null}
{navLinks.map((link) => ( {navLinks.map((link) => (
<a <a
key={link.label} key={link.label}
href={link.href} href={link.href}
onClick={() => setOpen(false)} onClick={closeAll}
className="border-b border-line/70 py-3 text-ink" className="border-b border-line/70 py-3 text-ink"
> >
{link.label} {link.label}
@@ -107,3 +155,41 @@ export function Header() {
</header> </header>
); );
} }
function MegaMenu({ onPick }: { onPick: () => void }) {
return (
<div className="absolute top-full right-0 z-50 w-[min(56rem,calc(100vw-2rem))] pt-2">
<div className="glass-box rounded-3xl p-5 shadow-card">
<div className="mb-4 flex items-end justify-between">
<div>
<p className="font-display text-xs text-cyan-600">Categories</p>
<p className="text-base font-bold">خرید بر اساس دسته</p>
</div>
<a href="#categories" onClick={onPick} className="text-xs font-medium text-purple-700">
مشاهده همه
</a>
</div>
<div className="grid grid-cols-4 gap-3">
{categories.map((category) => (
<a
key={category.id}
href="#categories"
onClick={onPick}
className="rounded-2xl bg-white/70 p-2 text-center transition hover:-translate-y-0.5 hover:bg-white"
>
<Placeholder
src={category.image}
alt={category.title}
width={160}
height={160}
rounded="rounded-xl"
/>
<p className="mt-2 text-xs font-bold text-ink">{category.title}</p>
<p className="text-[11px] text-muted">{toFaDigits(category.count)} مدل</p>
</a>
))}
</div>
</div>
</div>
);
}
+9 -2
View File
@@ -27,9 +27,10 @@ export function Hero() {
aria-label="اسلاید بعد" aria-label="اسلاید بعد"
> >
<Placeholder <Placeholder
src={slide.image}
alt={slide.title}
width={960} width={960}
height={420} height={420}
tone={slide.tone}
rounded="rounded-3xl" rounded="rounded-3xl"
fill fill
className="aspect-[960/420] h-full w-full lg:aspect-auto" className="aspect-[960/420] h-full w-full lg:aspect-auto"
@@ -53,7 +54,13 @@ export function Hero() {
href="#" href="#"
className="overflow-hidden rounded-3xl lg:col-span-4" className="overflow-hidden rounded-3xl lg:col-span-4"
> >
<Placeholder width={360} height={200} tone={banner.tone} rounded="rounded-3xl" /> <Placeholder
src={banner.image}
alt={banner.title}
width={360}
height={200}
rounded="rounded-3xl"
/>
</a> </a>
))} ))}
</div> </div>
+8
View File
@@ -126,6 +126,14 @@ export function IconPalette({ className = "size-7" }: IconProps) {
); );
} }
export function IconChevronDown({ className = "size-4" }: IconProps) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" aria-hidden>
<path d="m6 9 6 6 6-6" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
</svg>
);
}
export function IconChevron({ className = "size-5" }: IconProps) { export function IconChevron({ className = "size-5" }: IconProps) {
return ( return (
<svg className={className} viewBox="0 0 24 24" fill="none" aria-hidden> <svg className={className} viewBox="0 0 24 24" fill="none" aria-hidden>
+11 -23
View File
@@ -1,41 +1,29 @@
import type { Tone } from "@/data/content";
const tones: Record<Tone, string> = {
purple: "bg-purple-200 from-purple-300 via-purple-200 to-purple-100 text-purple-800",
cyan: "bg-cyan-100 from-cyan-300 via-cyan-200 to-cyan-100 text-cyan-800",
rose: "bg-rose-100 from-rose-300 via-rose-200 to-rose-100 text-rose-700",
};
type Props = { type Props = {
src: string;
alt?: string;
width: number; width: number;
height: number; height: number;
tone?: Tone;
className?: string; className?: string;
rounded?: string; rounded?: string;
fill?: boolean; fill?: boolean;
showSize?: boolean;
}; };
export function Placeholder({ export function Placeholder({
src,
alt = "",
width, width,
height, height,
tone = "purple",
className = "", className = "",
rounded = "rounded-2xl", rounded = "rounded-2xl",
fill = false, fill = false,
showSize = true,
}: Props) { }: Props) {
return ( return (
<div <img
className={`placeholder-grid relative flex flex-col items-center justify-center overflow-hidden bg-linear-to-br ${tones[tone]} ${rounded} ${className}`} src={src}
style={fill ? undefined : { aspectRatio: `${width} / ${height}` }} alt={alt}
aria-hidden width={width}
> height={height}
{showSize ? ( className={`block w-full object-cover ${fill ? "h-full" : "h-auto"} ${rounded} ${className}`}
<span className="font-display text-lg font-semibold tracking-wide sm:text-xl"> />
{width} × {height}
</span>
) : null}
</div>
); );
} }
+2 -1
View File
@@ -13,9 +13,10 @@ export function ProductCard({ product }: Props) {
className="glass-box w-[220px] shrink-0 snap-start rounded-3xl p-2.5 shadow-soft transition hover:-translate-y-1 hover:shadow-card sm:w-[240px]" className="glass-box w-[220px] shrink-0 snap-start rounded-3xl p-2.5 shadow-soft transition hover:-translate-y-1 hover:shadow-card sm:w-[240px]"
> >
<Placeholder <Placeholder
src={product.image}
alt={product.title}
width={280} width={280}
height={340} height={340}
tone={product.tone}
rounded="rounded-2xl" rounded="rounded-2xl"
/> />
<div className="px-1.5 pt-3 pb-1"> <div className="px-1.5 pt-3 pb-1">
+2 -2
View File
@@ -39,12 +39,12 @@ export function ProductCarousel({
aria-label="بنر فروش ویژه" aria-label="بنر فروش ویژه"
> >
<Placeholder <Placeholder
src="/images/sale-banner.png"
alt=""
width={240} width={240}
height={400} height={400}
tone="rose"
rounded="rounded-3xl" rounded="rounded-3xl"
fill fill
showSize={false}
className="h-full w-full" className="h-full w-full"
/> />
</a> </a>
+68 -14
View File
@@ -2,6 +2,7 @@ export type Tone = "purple" | "cyan" | "rose";
export type Product = { export type Product = {
id: string; id: string;
image: string;
title: string; title: string;
brand: string; brand: string;
price: number; price: number;
@@ -12,18 +13,16 @@ export type Product = {
}; };
export const navLinks = [ export const navLinks = [
{ href: "#", label: "صفحه اصلی" },
{ href: "#categories", label: "نوزاد" },
{ href: "#categories", label: "دخترانه" },
{ href: "#categories", label: "پسرانه" },
{ href: "#yeganeh", label: "برند یگانه" },
{ href: "#sale", label: "فروش ویژه" }, { href: "#sale", label: "فروش ویژه" },
{ href: "#blog", label: "وبلاگ" }, { href: "#about", label: "درباره ما" },
{ href: "#faq", label: "سوالات متداول" },
{ href: "#contact", label: "تماس با ما" },
]; ];
export const slides = [ export const slides = [
{ {
id: "s1", id: "s1",
image: "/images/slider-1.png",
tone: "purple" as Tone, tone: "purple" as Tone,
kicker: "Summer 1405", kicker: "Summer 1405",
title: "کالکشن تابستان نینی‌ها", title: "کالکشن تابستان نینی‌ها",
@@ -33,6 +32,7 @@ export const slides = [
}, },
{ {
id: "s2", id: "s2",
image: "/images/slider-2.png",
tone: "rose" as Tone, tone: "rose" as Tone,
kicker: "Newborn Sale", kicker: "Newborn Sale",
title: "تخفیف ویژه نوزادی تا ۴۰٪", title: "تخفیف ویژه نوزادی تا ۴۰٪",
@@ -42,6 +42,7 @@ export const slides = [
}, },
{ {
id: "s3", id: "s3",
image: "/images/slider-3.png",
tone: "cyan" as Tone, tone: "cyan" as Tone,
kicker: "Yeganeh", kicker: "Yeganeh",
title: "برند یگانه حالا در نینی نادری", title: "برند یگانه حالا در نینی نادری",
@@ -54,6 +55,7 @@ export const slides = [
export const sideBanners = [ export const sideBanners = [
{ {
id: "sb1", id: "sb1",
image: "/images/side-banner-1.png",
tone: "cyan" as Tone, tone: "cyan" as Tone,
title: "ست خواهر و برادری", title: "ست خواهر و برادری",
text: "جفت‌های رنگی برای عکس‌های خانوادگی", text: "جفت‌های رنگی برای عکس‌های خانوادگی",
@@ -61,6 +63,7 @@ export const sideBanners = [
}, },
{ {
id: "sb2", id: "sb2",
image: "/images/side-banner-2.png",
tone: "rose" as Tone, tone: "rose" as Tone,
title: "کفش اولین قدم", title: "کفش اولین قدم",
text: "پاپوش نرم برای نوپاهای کنجکاو", text: "پاپوش نرم برای نوپاهای کنجکاو",
@@ -69,14 +72,14 @@ export const sideBanners = [
]; ];
export const categories = [ export const categories = [
{ id: "c1", title: "لباس نوزاد", count: 86, tone: "purple" as Tone, size: "160 × 160" }, { id: "c1", image: "/images/category-1.png", title: "لباس نوزاد", count: 86, tone: "purple" as Tone, size: "160 × 160" },
{ id: "c2", title: "دخترانه", count: 124, tone: "rose" as Tone, size: "160 × 160" }, { id: "c2", image: "/images/category-2.png", title: "دخترانه", count: 124, tone: "rose" as Tone, size: "160 × 160" },
{ id: "c3", title: "پسرانه", count: 118, tone: "cyan" as Tone, size: "160 × 160" }, { id: "c3", image: "/images/category-3.png", title: "پسرانه", count: 118, tone: "cyan" as Tone, size: "160 × 160" },
{ id: "c4", title: "ست و راحتی", count: 64, tone: "purple" as Tone, size: "160 × 160" }, { id: "c4", image: "/images/category-4.png", title: "ست و راحتی", count: 64, tone: "purple" as Tone, size: "160 × 160" },
{ id: "c5", title: "کفش و پاپوش", count: 41, tone: "cyan" as Tone, size: "160 × 160" }, { id: "c5", image: "/images/category-5.png", title: "کفش و پاپوش", count: 41, tone: "cyan" as Tone, size: "160 × 160" },
{ id: "c6", title: "اکسسوری", count: 37, tone: "rose" as Tone, size: "160 × 160" }, { id: "c6", image: "/images/category-6.png", title: "اکسسوری", count: 37, tone: "rose" as Tone, size: "160 × 160" },
{ id: "c7", title: "حمام و حوله", count: 22, tone: "purple" as Tone, size: "160 × 160" }, { id: "c7", image: "/images/category-7.png", title: "حمام و حوله", count: 22, tone: "purple" as Tone, size: "160 × 160" },
{ id: "c8", title: "مهمانی", count: 29, tone: "rose" as Tone, size: "160 × 160" }, { id: "c8", image: "/images/category-8.png", title: "مهمانی", count: 29, tone: "rose" as Tone, size: "160 × 160" },
]; ];
export const features = [ export const features = [
@@ -109,6 +112,7 @@ export const features = [
export const saleProducts: Product[] = [ export const saleProducts: Product[] = [
{ {
id: "p1", id: "p1",
image: "/images/sale-1.png",
title: "سرهمی نخی نوزاد یاسی", title: "سرهمی نخی نوزاد یاسی",
brand: "نینی نادری", brand: "نینی نادری",
price: 890000, price: 890000,
@@ -119,6 +123,7 @@ export const saleProducts: Product[] = [
}, },
{ {
id: "p2", id: "p2",
image: "/images/sale-2.png",
title: "پیراهن چین‌دار دخترانه", title: "پیراهن چین‌دار دخترانه",
brand: "یگانه", brand: "یگانه",
price: 1450000, price: 1450000,
@@ -129,6 +134,7 @@ export const saleProducts: Product[] = [
}, },
{ {
id: "p3", id: "p3",
image: "/images/sale-3.png",
title: "تیشرت طرح دایناسور", title: "تیشرت طرح دایناسور",
brand: "نینی نادری", brand: "نینی نادری",
price: 620000, price: 620000,
@@ -139,6 +145,7 @@ export const saleProducts: Product[] = [
}, },
{ {
id: "p4", id: "p4",
image: "/images/sale-4.png",
title: "بادی آستین بلند ارگانیک", title: "بادی آستین بلند ارگانیک",
brand: "یگانه", brand: "یگانه",
price: 540000, price: 540000,
@@ -149,6 +156,7 @@ export const saleProducts: Product[] = [
}, },
{ {
id: "p5", id: "p5",
image: "/images/sale-5.png",
title: "شلوار اسلش راحتی", title: "شلوار اسلش راحتی",
brand: "نینی نادری", brand: "نینی نادری",
price: 710000, price: 710000,
@@ -159,6 +167,7 @@ export const saleProducts: Product[] = [
}, },
{ {
id: "p6", id: "p6",
image: "/images/sale-6.png",
title: "کت بافت پاییزه خردلی", title: "کت بافت پاییزه خردلی",
brand: "یگانه", brand: "یگانه",
price: 1680000, price: 1680000,
@@ -169,6 +178,7 @@ export const saleProducts: Product[] = [
}, },
{ {
id: "p7", id: "p7",
image: "/images/sale-7.png",
title: "ست بیمارستانی نوزاد", title: "ست بیمارستانی نوزاد",
brand: "نینی نادری", brand: "نینی نادری",
price: 1120000, price: 1120000,
@@ -179,6 +189,7 @@ export const saleProducts: Product[] = [
}, },
{ {
id: "p8", id: "p8",
image: "/images/sale-8.png",
title: "کفش پارچه‌ای نوپا", title: "کفش پارچه‌ای نوپا",
brand: "یگانه", brand: "یگانه",
price: 980000, price: 980000,
@@ -192,6 +203,7 @@ export const saleProducts: Product[] = [
export const dualBanners = [ export const dualBanners = [
{ {
id: "db1", id: "db1",
image: "/images/banner-dual-1.png",
tone: "purple" as Tone, tone: "purple" as Tone,
kicker: "Party Edit", kicker: "Party Edit",
title: "کالکشن مهمانی کوچولوها", title: "کالکشن مهمانی کوچولوها",
@@ -200,6 +212,7 @@ export const dualBanners = [
}, },
{ {
id: "db2", id: "db2",
image: "/images/banner-dual-2.png",
tone: "cyan" as Tone, tone: "cyan" as Tone,
kicker: "Bedtime", kicker: "Bedtime",
title: "لباس خواب نخی", title: "لباس خواب نخی",
@@ -211,6 +224,7 @@ export const dualBanners = [
export const topProducts: Product[] = [ export const topProducts: Product[] = [
{ {
id: "t1", id: "t1",
image: "/images/top-1.png",
title: "ست خواهر برادری راه راه", title: "ست خواهر برادری راه راه",
brand: "یگانه", brand: "یگانه",
price: 1980000, price: 1980000,
@@ -220,6 +234,7 @@ export const topProducts: Product[] = [
}, },
{ {
id: "t2", id: "t2",
image: "/images/top-2.png",
title: "سارافون جین دخترانه", title: "سارافون جین دخترانه",
brand: "نینی نادری", brand: "نینی نادری",
price: 1320000, price: 1320000,
@@ -229,6 +244,7 @@ export const topProducts: Product[] = [
}, },
{ {
id: "t3", id: "t3",
image: "/images/top-3.png",
title: "هودی گوش‌دار خرسی", title: "هودی گوش‌دار خرسی",
brand: "یگانه", brand: "یگانه",
price: 1540000, price: 1540000,
@@ -238,6 +254,7 @@ export const topProducts: Product[] = [
}, },
{ {
id: "t4", id: "t4",
image: "/images/top-4.png",
title: "بادی دکمه فشاری سه‌تایی", title: "بادی دکمه فشاری سه‌تایی",
brand: "نینی نادری", brand: "نینی نادری",
price: 870000, price: 870000,
@@ -247,6 +264,7 @@ export const topProducts: Product[] = [
}, },
{ {
id: "t5", id: "t5",
image: "/images/top-5.png",
title: "شلوارک کتان پسرانه", title: "شلوارک کتان پسرانه",
brand: "یگانه", brand: "یگانه",
price: 760000, price: 760000,
@@ -256,6 +274,7 @@ export const topProducts: Product[] = [
}, },
{ {
id: "t6", id: "t6",
image: "/images/top-6.png",
title: "کلاه و دستکش ست", title: "کلاه و دستکش ست",
brand: "نینی نادری", brand: "نینی نادری",
price: 390000, price: 390000,
@@ -265,6 +284,7 @@ export const topProducts: Product[] = [
}, },
{ {
id: "t7", id: "t7",
image: "/images/top-7.png",
title: "پیراهن لینن تابستانه", title: "پیراهن لینن تابستانه",
brand: "یگانه", brand: "یگانه",
price: 1410000, price: 1410000,
@@ -274,6 +294,7 @@ export const topProducts: Product[] = [
}, },
{ {
id: "t8", id: "t8",
image: "/images/top-8.png",
title: "جوراب ساق‌بلند رنگی", title: "جوراب ساق‌بلند رنگی",
brand: "نینی نادری", brand: "نینی نادری",
price: 210000, price: 210000,
@@ -286,6 +307,7 @@ export const topProducts: Product[] = [
export const tripleBanners = [ export const tripleBanners = [
{ {
id: "tb1", id: "tb1",
image: "/images/banner-triple-1.png",
tone: "rose" as Tone, tone: "rose" as Tone,
title: "دخترانه بهاری", title: "دخترانه بهاری",
text: "گل‌گلی، چین‌دار و روشن", text: "گل‌گلی، چین‌دار و روشن",
@@ -293,6 +315,7 @@ export const tripleBanners = [
}, },
{ {
id: "tb2", id: "tb2",
image: "/images/banner-triple-2.png",
tone: "cyan" as Tone, tone: "cyan" as Tone,
title: "پسرانه اسپرت", title: "پسرانه اسپرت",
text: "هودی، تیشرت و شلوارک بازی", text: "هودی، تیشرت و شلوارک بازی",
@@ -300,6 +323,7 @@ export const tripleBanners = [
}, },
{ {
id: "tb3", id: "tb3",
image: "/images/banner-triple-3.png",
tone: "purple" as Tone, tone: "purple" as Tone,
title: "نوزادی ارگانیک", title: "نوزادی ارگانیک",
text: "پنبه لطیف برای پوست حساس", text: "پنبه لطیف برای پوست حساس",
@@ -310,6 +334,7 @@ export const tripleBanners = [
export const yeganehProducts: Product[] = [ export const yeganehProducts: Product[] = [
{ {
id: "y1", id: "y1",
image: "/images/yeganeh-1.png",
title: "سرهمی یگانه طرح ستاره", title: "سرهمی یگانه طرح ستاره",
brand: "یگانه", brand: "یگانه",
price: 1180000, price: 1180000,
@@ -319,6 +344,7 @@ export const yeganehProducts: Product[] = [
}, },
{ {
id: "y2", id: "y2",
image: "/images/yeganeh-2.png",
title: "ست دوتکه یگانه دخترانه", title: "ست دوتکه یگانه دخترانه",
brand: "یگانه", brand: "یگانه",
price: 1720000, price: 1720000,
@@ -328,6 +354,7 @@ export const yeganehProducts: Product[] = [
}, },
{ {
id: "y3", id: "y3",
image: "/images/yeganeh-3.png",
title: "پولوشرت یگانه پسرانه", title: "پولوشرت یگانه پسرانه",
brand: "یگانه", brand: "یگانه",
price: 990000, price: 990000,
@@ -337,6 +364,7 @@ export const yeganehProducts: Product[] = [
}, },
{ {
id: "y4", id: "y4",
image: "/images/yeganeh-4.png",
title: "بادی یگانه بسته دوتایی", title: "بادی یگانه بسته دوتایی",
brand: "یگانه", brand: "یگانه",
price: 860000, price: 860000,
@@ -346,6 +374,7 @@ export const yeganehProducts: Product[] = [
}, },
{ {
id: "y5", id: "y5",
image: "/images/yeganeh-5.png",
title: "پیراهن یقه ب ب یگانه", title: "پیراهن یقه ب ب یگانه",
brand: "یگانه", brand: "یگانه",
price: 1390000, price: 1390000,
@@ -355,6 +384,7 @@ export const yeganehProducts: Product[] = [
}, },
{ {
id: "y6", id: "y6",
image: "/images/yeganeh-6.png",
title: "شلوار جین نرم یگانه", title: "شلوار جین نرم یگانه",
brand: "یگانه", brand: "یگانه",
price: 1250000, price: 1250000,
@@ -377,12 +407,14 @@ export const about = {
{ value: "+۴۰۰", label: "مدل فعال" }, { value: "+۴۰۰", label: "مدل فعال" },
{ value: "۲۴ ساعته", label: "پاسخگویی سفارش" }, { value: "۲۴ ساعته", label: "پاسخگویی سفارش" },
], ],
image: "/images/about.png",
imageSize: "560 × 400", imageSize: "560 × 400",
}; };
export const posts = [ export const posts = [
{ {
id: "b1", id: "b1",
image: "/images/blog-1.png",
tone: "purple" as Tone, tone: "purple" as Tone,
date: "۲۳ مرداد ۱۴۰۵", date: "۲۳ مرداد ۱۴۰۵",
title: "چطور سایز لباس نوزاد را درست حدس بزنیم؟", title: "چطور سایز لباس نوزاد را درست حدس بزنیم؟",
@@ -391,6 +423,7 @@ export const posts = [
}, },
{ {
id: "b2", id: "b2",
image: "/images/blog-2.png",
tone: "cyan" as Tone, tone: "cyan" as Tone,
date: "۱۸ مرداد ۱۴۰۵", date: "۱۸ مرداد ۱۴۰۵",
title: "پارچه نخی بهتر است یا پنبه ارگانیک؟", title: "پارچه نخی بهتر است یا پنبه ارگانیک؟",
@@ -399,6 +432,7 @@ export const posts = [
}, },
{ {
id: "b3", id: "b3",
image: "/images/blog-3.png",
tone: "rose" as Tone, tone: "rose" as Tone,
date: "۹ مرداد ۱۴۰۵", date: "۹ مرداد ۱۴۰۵",
title: "کفش اولین قدم؛ نرم باشد یا محکم؟", title: "کفش اولین قدم؛ نرم باشد یا محکم؟",
@@ -407,6 +441,7 @@ export const posts = [
}, },
{ {
id: "b4", id: "b4",
image: "/images/blog-4.png",
tone: "purple" as Tone, tone: "purple" as Tone,
date: "۱ مرداد ۱۴۰۵", date: "۱ مرداد ۱۴۰۵",
title: "ست خواهر و برادری برای عکس تولد", title: "ست خواهر و برادری برای عکس تولد",
@@ -415,6 +450,25 @@ export const posts = [
}, },
]; ];
export const faqs = [
{
q: "ارسال رایگان از چه مبلغی است؟",
a: "برای سفارش‌های بالای ۵ میلیون تومان هزینه ارسال رایگان است و سفارش‌های کمتر با نرخ پیک محاسبه می‌شود.",
},
{
q: "چطور سایز مناسب نوزاد را انتخاب کنیم؟",
a: "جدول سایز هر محصول را ببینید. اگر بین دو سایز بودید، معمولاً سایز بزرگ‌تر بهتر است چون بچه‌ها زود رشد می‌کنند.",
},
{
q: "امکان مرجوعی کالا هست؟",
a: "تا ۷ روز بعد از تحویل، اگر کالا استفاده نشده و تگ داشته باشد، می‌توانید آن را برگردانید.",
},
{
q: "ضمانت اصالت یعنی چه؟",
a: "هر محصول قبل از ارسال از نظر تگ، دوخت و برند بررسی می‌شود. برند یگانه و انتخاب‌های نینی نادری اصل هستند.",
},
];
export const footer = { export const footer = {
blurb: blurb:
"فروشگاه پوشاک نوزاد و کودک نینی نادری. لباس نرم، رنگ زنده، ارسال سریع.", "فروشگاه پوشاک نوزاد و کودک نینی نادری. لباس نرم، رنگ زنده، ارسال سریع.",