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>
@@ -9,7 +9,7 @@ Color palette is purple cyan red - light theme
|
||||
|
||||
Design only homepage
|
||||
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
|
||||
|
||||
Sections are:
|
||||
@@ -30,4 +30,7 @@ Sections are:
|
||||
10. Yeganeh brand product carousel
|
||||
11. About nini Naderi
|
||||
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
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 963 B |
|
After Width: | Height: | Size: 963 B |
|
After Width: | Height: | Size: 684 B |
|
After Width: | Height: | Size: 684 B |
|
After Width: | Height: | Size: 684 B |
|
After Width: | Height: | Size: 597 B |
|
After Width: | Height: | Size: 597 B |
|
After Width: | Height: | Size: 597 B |
|
After Width: | Height: | Size: 597 B |
|
After Width: | Height: | Size: 322 B |
|
After Width: | Height: | Size: 323 B |
|
After Width: | Height: | Size: 323 B |
|
After Width: | Height: | Size: 322 B |
|
After Width: | Height: | Size: 323 B |
|
After Width: | Height: | Size: 323 B |
|
After Width: | Height: | Size: 322 B |
|
After Width: | Height: | Size: 323 B |
|
After Width: | Height: | Size: 161 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 753 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 753 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 753 B |
|
After Width: | Height: | Size: 822 B |
|
After Width: | Height: | Size: 161 B |
|
After Width: | Height: | Size: 551 B |
|
After Width: | Height: | Size: 550 B |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 753 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 753 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 753 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 753 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 753 B |
@@ -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()
|
||||
@@ -1,6 +1,8 @@
|
||||
import { About } from "@/components/About";
|
||||
import { DualBanners, TripleBanners } from "@/components/Banners";
|
||||
import { BlogCarousel } from "@/components/BlogCarousel";
|
||||
import { Contact } from "@/components/Contact";
|
||||
import { Faq } from "@/components/Faq";
|
||||
import { FeaturedCategories } from "@/components/FeaturedCategories";
|
||||
import { Features } from "@/components/Features";
|
||||
import { Footer } from "@/components/Footer";
|
||||
@@ -42,6 +44,8 @@ export default function Home() {
|
||||
/>
|
||||
<About />
|
||||
<BlogCarousel />
|
||||
<Faq />
|
||||
<Contact />
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
@@ -26,11 +26,12 @@ export function About() {
|
||||
</div>
|
||||
<div className="bg-purple-50 p-4 sm:p-6">
|
||||
<Placeholder
|
||||
src={about.image}
|
||||
alt={about.title}
|
||||
width={560}
|
||||
height={400}
|
||||
tone="purple"
|
||||
rounded="rounded-[28px]"
|
||||
className="h-full min-h-[280px]"
|
||||
className="h-full min-h-[280px] object-cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,13 @@ export function DualBanners() {
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
{dualBanners.map((banner) => (
|
||||
<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>
|
||||
))}
|
||||
</div>
|
||||
@@ -21,7 +27,13 @@ export function TripleBanners() {
|
||||
<div className="grid gap-4 md:grid-cols-3">
|
||||
{tripleBanners.map((banner) => (
|
||||
<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>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,7 @@ export function BlogCarousel() {
|
||||
data-card
|
||||
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">
|
||||
<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">
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -15,9 +15,10 @@ export function FeaturedCategories() {
|
||||
className="glass-box group rounded-3xl p-3 text-center shadow-soft transition hover:-translate-y-1"
|
||||
>
|
||||
<Placeholder
|
||||
src={category.image}
|
||||
alt={category.title}
|
||||
width={160}
|
||||
height={160}
|
||||
tone={category.tone}
|
||||
rounded="rounded-2xl"
|
||||
/>
|
||||
<h3 className="mt-3 text-sm font-bold text-ink">{category.title}</h3>
|
||||
|
||||
@@ -38,11 +38,11 @@ export function Footer() {
|
||||
<p className="mt-2 text-sm text-ink">{footer.contact.email}</p>
|
||||
<div className="mt-4 flex gap-2">
|
||||
<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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,11 +2,21 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { navLinks } from "@/data/content";
|
||||
import { IconBag, IconClose, IconHeart, IconMenu, IconSearch, IconUser } from "./Icons";
|
||||
import { categories, navLinks } from "@/data/content";
|
||||
import { toFaDigits } from "@/lib/format";
|
||||
import { IconBag, IconChevronDown, IconClose, IconHeart, IconMenu, IconSearch, IconUser } from "./Icons";
|
||||
import { Placeholder } from "./Placeholder";
|
||||
|
||||
export function Header() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [mega, setMega] = useState(false);
|
||||
const [mobileCats, setMobileCats] = useState(false);
|
||||
|
||||
const closeAll = () => {
|
||||
setOpen(false);
|
||||
setMega(false);
|
||||
setMobileCats(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<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>
|
||||
</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) => (
|
||||
<a
|
||||
key={link.label}
|
||||
@@ -91,11 +117,33 @@ export function Header() {
|
||||
{open ? (
|
||||
<div className="border-t border-line bg-white lg:hidden">
|
||||
<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) => (
|
||||
<a
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
onClick={() => setOpen(false)}
|
||||
onClick={closeAll}
|
||||
className="border-b border-line/70 py-3 text-ink"
|
||||
>
|
||||
{link.label}
|
||||
@@ -107,3 +155,41 @@ export function 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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,9 +27,10 @@ export function Hero() {
|
||||
aria-label="اسلاید بعد"
|
||||
>
|
||||
<Placeholder
|
||||
src={slide.image}
|
||||
alt={slide.title}
|
||||
width={960}
|
||||
height={420}
|
||||
tone={slide.tone}
|
||||
rounded="rounded-3xl"
|
||||
fill
|
||||
className="aspect-[960/420] h-full w-full lg:aspect-auto"
|
||||
@@ -53,7 +54,13 @@ export function Hero() {
|
||||
href="#"
|
||||
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>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -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) {
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 24 24" fill="none" aria-hidden>
|
||||
|
||||
@@ -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 = {
|
||||
src: string;
|
||||
alt?: string;
|
||||
width: number;
|
||||
height: number;
|
||||
tone?: Tone;
|
||||
className?: string;
|
||||
rounded?: string;
|
||||
fill?: boolean;
|
||||
showSize?: boolean;
|
||||
};
|
||||
|
||||
export function Placeholder({
|
||||
src,
|
||||
alt = "",
|
||||
width,
|
||||
height,
|
||||
tone = "purple",
|
||||
className = "",
|
||||
rounded = "rounded-2xl",
|
||||
fill = false,
|
||||
showSize = true,
|
||||
}: Props) {
|
||||
return (
|
||||
<div
|
||||
className={`placeholder-grid relative flex flex-col items-center justify-center overflow-hidden bg-linear-to-br ${tones[tone]} ${rounded} ${className}`}
|
||||
style={fill ? undefined : { aspectRatio: `${width} / ${height}` }}
|
||||
aria-hidden
|
||||
>
|
||||
{showSize ? (
|
||||
<span className="font-display text-lg font-semibold tracking-wide sm:text-xl">
|
||||
{width} × {height}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
<img
|
||||
src={src}
|
||||
alt={alt}
|
||||
width={width}
|
||||
height={height}
|
||||
className={`block w-full object-cover ${fill ? "h-full" : "h-auto"} ${rounded} ${className}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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]"
|
||||
>
|
||||
<Placeholder
|
||||
src={product.image}
|
||||
alt={product.title}
|
||||
width={280}
|
||||
height={340}
|
||||
tone={product.tone}
|
||||
rounded="rounded-2xl"
|
||||
/>
|
||||
<div className="px-1.5 pt-3 pb-1">
|
||||
|
||||
@@ -39,12 +39,12 @@ export function ProductCarousel({
|
||||
aria-label="بنر فروش ویژه"
|
||||
>
|
||||
<Placeholder
|
||||
src="/images/sale-banner.png"
|
||||
alt=""
|
||||
width={240}
|
||||
height={400}
|
||||
tone="rose"
|
||||
rounded="rounded-3xl"
|
||||
fill
|
||||
showSize={false}
|
||||
className="h-full w-full"
|
||||
/>
|
||||
</a>
|
||||
|
||||
@@ -2,6 +2,7 @@ export type Tone = "purple" | "cyan" | "rose";
|
||||
|
||||
export type Product = {
|
||||
id: string;
|
||||
image: string;
|
||||
title: string;
|
||||
brand: string;
|
||||
price: number;
|
||||
@@ -12,18 +13,16 @@ export type Product = {
|
||||
};
|
||||
|
||||
export const navLinks = [
|
||||
{ href: "#", label: "صفحه اصلی" },
|
||||
{ href: "#categories", label: "نوزاد" },
|
||||
{ href: "#categories", label: "دخترانه" },
|
||||
{ href: "#categories", label: "پسرانه" },
|
||||
{ href: "#yeganeh", label: "برند یگانه" },
|
||||
{ href: "#sale", label: "فروش ویژه" },
|
||||
{ href: "#blog", label: "وبلاگ" },
|
||||
{ href: "#about", label: "درباره ما" },
|
||||
{ href: "#faq", label: "سوالات متداول" },
|
||||
{ href: "#contact", label: "تماس با ما" },
|
||||
];
|
||||
|
||||
export const slides = [
|
||||
{
|
||||
id: "s1",
|
||||
image: "/images/slider-1.png",
|
||||
tone: "purple" as Tone,
|
||||
kicker: "Summer 1405",
|
||||
title: "کالکشن تابستان نینیها",
|
||||
@@ -33,6 +32,7 @@ export const slides = [
|
||||
},
|
||||
{
|
||||
id: "s2",
|
||||
image: "/images/slider-2.png",
|
||||
tone: "rose" as Tone,
|
||||
kicker: "Newborn Sale",
|
||||
title: "تخفیف ویژه نوزادی تا ۴۰٪",
|
||||
@@ -42,6 +42,7 @@ export const slides = [
|
||||
},
|
||||
{
|
||||
id: "s3",
|
||||
image: "/images/slider-3.png",
|
||||
tone: "cyan" as Tone,
|
||||
kicker: "Yeganeh",
|
||||
title: "برند یگانه حالا در نینی نادری",
|
||||
@@ -54,6 +55,7 @@ export const slides = [
|
||||
export const sideBanners = [
|
||||
{
|
||||
id: "sb1",
|
||||
image: "/images/side-banner-1.png",
|
||||
tone: "cyan" as Tone,
|
||||
title: "ست خواهر و برادری",
|
||||
text: "جفتهای رنگی برای عکسهای خانوادگی",
|
||||
@@ -61,6 +63,7 @@ export const sideBanners = [
|
||||
},
|
||||
{
|
||||
id: "sb2",
|
||||
image: "/images/side-banner-2.png",
|
||||
tone: "rose" as Tone,
|
||||
title: "کفش اولین قدم",
|
||||
text: "پاپوش نرم برای نوپاهای کنجکاو",
|
||||
@@ -69,14 +72,14 @@ export const sideBanners = [
|
||||
];
|
||||
|
||||
export const categories = [
|
||||
{ id: "c1", title: "لباس نوزاد", count: 86, tone: "purple" as Tone, size: "160 × 160" },
|
||||
{ id: "c2", title: "دخترانه", count: 124, tone: "rose" as Tone, size: "160 × 160" },
|
||||
{ id: "c3", title: "پسرانه", count: 118, tone: "cyan" as Tone, size: "160 × 160" },
|
||||
{ id: "c4", title: "ست و راحتی", count: 64, tone: "purple" as Tone, size: "160 × 160" },
|
||||
{ id: "c5", title: "کفش و پاپوش", count: 41, tone: "cyan" as Tone, size: "160 × 160" },
|
||||
{ id: "c6", title: "اکسسوری", count: 37, tone: "rose" as Tone, size: "160 × 160" },
|
||||
{ id: "c7", title: "حمام و حوله", count: 22, tone: "purple" as Tone, size: "160 × 160" },
|
||||
{ id: "c8", title: "مهمانی", count: 29, tone: "rose" as Tone, size: "160 × 160" },
|
||||
{ id: "c1", image: "/images/category-1.png", title: "لباس نوزاد", count: 86, tone: "purple" as Tone, size: "160 × 160" },
|
||||
{ id: "c2", image: "/images/category-2.png", title: "دخترانه", count: 124, tone: "rose" as Tone, size: "160 × 160" },
|
||||
{ id: "c3", image: "/images/category-3.png", title: "پسرانه", count: 118, tone: "cyan" as Tone, size: "160 × 160" },
|
||||
{ id: "c4", image: "/images/category-4.png", title: "ست و راحتی", count: 64, tone: "purple" as Tone, size: "160 × 160" },
|
||||
{ id: "c5", image: "/images/category-5.png", title: "کفش و پاپوش", count: 41, tone: "cyan" as Tone, size: "160 × 160" },
|
||||
{ id: "c6", image: "/images/category-6.png", title: "اکسسوری", count: 37, tone: "rose" as Tone, size: "160 × 160" },
|
||||
{ id: "c7", image: "/images/category-7.png", title: "حمام و حوله", count: 22, tone: "purple" 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 = [
|
||||
@@ -109,6 +112,7 @@ export const features = [
|
||||
export const saleProducts: Product[] = [
|
||||
{
|
||||
id: "p1",
|
||||
image: "/images/sale-1.png",
|
||||
title: "سرهمی نخی نوزاد یاسی",
|
||||
brand: "نینی نادری",
|
||||
price: 890000,
|
||||
@@ -119,6 +123,7 @@ export const saleProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "p2",
|
||||
image: "/images/sale-2.png",
|
||||
title: "پیراهن چیندار دخترانه",
|
||||
brand: "یگانه",
|
||||
price: 1450000,
|
||||
@@ -129,6 +134,7 @@ export const saleProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "p3",
|
||||
image: "/images/sale-3.png",
|
||||
title: "تیشرت طرح دایناسور",
|
||||
brand: "نینی نادری",
|
||||
price: 620000,
|
||||
@@ -139,6 +145,7 @@ export const saleProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "p4",
|
||||
image: "/images/sale-4.png",
|
||||
title: "بادی آستین بلند ارگانیک",
|
||||
brand: "یگانه",
|
||||
price: 540000,
|
||||
@@ -149,6 +156,7 @@ export const saleProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "p5",
|
||||
image: "/images/sale-5.png",
|
||||
title: "شلوار اسلش راحتی",
|
||||
brand: "نینی نادری",
|
||||
price: 710000,
|
||||
@@ -159,6 +167,7 @@ export const saleProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "p6",
|
||||
image: "/images/sale-6.png",
|
||||
title: "کت بافت پاییزه خردلی",
|
||||
brand: "یگانه",
|
||||
price: 1680000,
|
||||
@@ -169,6 +178,7 @@ export const saleProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "p7",
|
||||
image: "/images/sale-7.png",
|
||||
title: "ست بیمارستانی نوزاد",
|
||||
brand: "نینی نادری",
|
||||
price: 1120000,
|
||||
@@ -179,6 +189,7 @@ export const saleProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "p8",
|
||||
image: "/images/sale-8.png",
|
||||
title: "کفش پارچهای نوپا",
|
||||
brand: "یگانه",
|
||||
price: 980000,
|
||||
@@ -192,6 +203,7 @@ export const saleProducts: Product[] = [
|
||||
export const dualBanners = [
|
||||
{
|
||||
id: "db1",
|
||||
image: "/images/banner-dual-1.png",
|
||||
tone: "purple" as Tone,
|
||||
kicker: "Party Edit",
|
||||
title: "کالکشن مهمانی کوچولوها",
|
||||
@@ -200,6 +212,7 @@ export const dualBanners = [
|
||||
},
|
||||
{
|
||||
id: "db2",
|
||||
image: "/images/banner-dual-2.png",
|
||||
tone: "cyan" as Tone,
|
||||
kicker: "Bedtime",
|
||||
title: "لباس خواب نخی",
|
||||
@@ -211,6 +224,7 @@ export const dualBanners = [
|
||||
export const topProducts: Product[] = [
|
||||
{
|
||||
id: "t1",
|
||||
image: "/images/top-1.png",
|
||||
title: "ست خواهر برادری راه راه",
|
||||
brand: "یگانه",
|
||||
price: 1980000,
|
||||
@@ -220,6 +234,7 @@ export const topProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "t2",
|
||||
image: "/images/top-2.png",
|
||||
title: "سارافون جین دخترانه",
|
||||
brand: "نینی نادری",
|
||||
price: 1320000,
|
||||
@@ -229,6 +244,7 @@ export const topProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "t3",
|
||||
image: "/images/top-3.png",
|
||||
title: "هودی گوشدار خرسی",
|
||||
brand: "یگانه",
|
||||
price: 1540000,
|
||||
@@ -238,6 +254,7 @@ export const topProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "t4",
|
||||
image: "/images/top-4.png",
|
||||
title: "بادی دکمه فشاری سهتایی",
|
||||
brand: "نینی نادری",
|
||||
price: 870000,
|
||||
@@ -247,6 +264,7 @@ export const topProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "t5",
|
||||
image: "/images/top-5.png",
|
||||
title: "شلوارک کتان پسرانه",
|
||||
brand: "یگانه",
|
||||
price: 760000,
|
||||
@@ -256,6 +274,7 @@ export const topProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "t6",
|
||||
image: "/images/top-6.png",
|
||||
title: "کلاه و دستکش ست",
|
||||
brand: "نینی نادری",
|
||||
price: 390000,
|
||||
@@ -265,6 +284,7 @@ export const topProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "t7",
|
||||
image: "/images/top-7.png",
|
||||
title: "پیراهن لینن تابستانه",
|
||||
brand: "یگانه",
|
||||
price: 1410000,
|
||||
@@ -274,6 +294,7 @@ export const topProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "t8",
|
||||
image: "/images/top-8.png",
|
||||
title: "جوراب ساقبلند رنگی",
|
||||
brand: "نینی نادری",
|
||||
price: 210000,
|
||||
@@ -286,6 +307,7 @@ export const topProducts: Product[] = [
|
||||
export const tripleBanners = [
|
||||
{
|
||||
id: "tb1",
|
||||
image: "/images/banner-triple-1.png",
|
||||
tone: "rose" as Tone,
|
||||
title: "دخترانه بهاری",
|
||||
text: "گلگلی، چیندار و روشن",
|
||||
@@ -293,6 +315,7 @@ export const tripleBanners = [
|
||||
},
|
||||
{
|
||||
id: "tb2",
|
||||
image: "/images/banner-triple-2.png",
|
||||
tone: "cyan" as Tone,
|
||||
title: "پسرانه اسپرت",
|
||||
text: "هودی، تیشرت و شلوارک بازی",
|
||||
@@ -300,6 +323,7 @@ export const tripleBanners = [
|
||||
},
|
||||
{
|
||||
id: "tb3",
|
||||
image: "/images/banner-triple-3.png",
|
||||
tone: "purple" as Tone,
|
||||
title: "نوزادی ارگانیک",
|
||||
text: "پنبه لطیف برای پوست حساس",
|
||||
@@ -310,6 +334,7 @@ export const tripleBanners = [
|
||||
export const yeganehProducts: Product[] = [
|
||||
{
|
||||
id: "y1",
|
||||
image: "/images/yeganeh-1.png",
|
||||
title: "سرهمی یگانه طرح ستاره",
|
||||
brand: "یگانه",
|
||||
price: 1180000,
|
||||
@@ -319,6 +344,7 @@ export const yeganehProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "y2",
|
||||
image: "/images/yeganeh-2.png",
|
||||
title: "ست دوتکه یگانه دخترانه",
|
||||
brand: "یگانه",
|
||||
price: 1720000,
|
||||
@@ -328,6 +354,7 @@ export const yeganehProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "y3",
|
||||
image: "/images/yeganeh-3.png",
|
||||
title: "پولوشرت یگانه پسرانه",
|
||||
brand: "یگانه",
|
||||
price: 990000,
|
||||
@@ -337,6 +364,7 @@ export const yeganehProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "y4",
|
||||
image: "/images/yeganeh-4.png",
|
||||
title: "بادی یگانه بسته دوتایی",
|
||||
brand: "یگانه",
|
||||
price: 860000,
|
||||
@@ -346,6 +374,7 @@ export const yeganehProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "y5",
|
||||
image: "/images/yeganeh-5.png",
|
||||
title: "پیراهن یقه ب ب یگانه",
|
||||
brand: "یگانه",
|
||||
price: 1390000,
|
||||
@@ -355,6 +384,7 @@ export const yeganehProducts: Product[] = [
|
||||
},
|
||||
{
|
||||
id: "y6",
|
||||
image: "/images/yeganeh-6.png",
|
||||
title: "شلوار جین نرم یگانه",
|
||||
brand: "یگانه",
|
||||
price: 1250000,
|
||||
@@ -377,12 +407,14 @@ export const about = {
|
||||
{ value: "+۴۰۰", label: "مدل فعال" },
|
||||
{ value: "۲۴ ساعته", label: "پاسخگویی سفارش" },
|
||||
],
|
||||
image: "/images/about.png",
|
||||
imageSize: "560 × 400",
|
||||
};
|
||||
|
||||
export const posts = [
|
||||
{
|
||||
id: "b1",
|
||||
image: "/images/blog-1.png",
|
||||
tone: "purple" as Tone,
|
||||
date: "۲۳ مرداد ۱۴۰۵",
|
||||
title: "چطور سایز لباس نوزاد را درست حدس بزنیم؟",
|
||||
@@ -391,6 +423,7 @@ export const posts = [
|
||||
},
|
||||
{
|
||||
id: "b2",
|
||||
image: "/images/blog-2.png",
|
||||
tone: "cyan" as Tone,
|
||||
date: "۱۸ مرداد ۱۴۰۵",
|
||||
title: "پارچه نخی بهتر است یا پنبه ارگانیک؟",
|
||||
@@ -399,6 +432,7 @@ export const posts = [
|
||||
},
|
||||
{
|
||||
id: "b3",
|
||||
image: "/images/blog-3.png",
|
||||
tone: "rose" as Tone,
|
||||
date: "۹ مرداد ۱۴۰۵",
|
||||
title: "کفش اولین قدم؛ نرم باشد یا محکم؟",
|
||||
@@ -407,6 +441,7 @@ export const posts = [
|
||||
},
|
||||
{
|
||||
id: "b4",
|
||||
image: "/images/blog-4.png",
|
||||
tone: "purple" as Tone,
|
||||
date: "۱ مرداد ۱۴۰۵",
|
||||
title: "ست خواهر و برادری برای عکس تولد",
|
||||
@@ -415,6 +450,25 @@ export const posts = [
|
||||
},
|
||||
];
|
||||
|
||||
export const faqs = [
|
||||
{
|
||||
q: "ارسال رایگان از چه مبلغی است؟",
|
||||
a: "برای سفارشهای بالای ۵ میلیون تومان هزینه ارسال رایگان است و سفارشهای کمتر با نرخ پیک محاسبه میشود.",
|
||||
},
|
||||
{
|
||||
q: "چطور سایز مناسب نوزاد را انتخاب کنیم؟",
|
||||
a: "جدول سایز هر محصول را ببینید. اگر بین دو سایز بودید، معمولاً سایز بزرگتر بهتر است چون بچهها زود رشد میکنند.",
|
||||
},
|
||||
{
|
||||
q: "امکان مرجوعی کالا هست؟",
|
||||
a: "تا ۷ روز بعد از تحویل، اگر کالا استفاده نشده و تگ داشته باشد، میتوانید آن را برگردانید.",
|
||||
},
|
||||
{
|
||||
q: "ضمانت اصالت یعنی چه؟",
|
||||
a: "هر محصول قبل از ارسال از نظر تگ، دوخت و برند بررسی میشود. برند یگانه و انتخابهای نینی نادری اصل هستند.",
|
||||
},
|
||||
];
|
||||
|
||||
export const footer = {
|
||||
blurb:
|
||||
"فروشگاه پوشاک نوزاد و کودک نینی نادری. لباس نرم، رنگ زنده، ارسال سریع.",
|
||||
|
||||