Files
website/src/pages/LandingModelPage.tsx
T

371 lines
14 KiB
TypeScript

import { useEffect, useRef, useState } from 'react'
import { useParams } from 'react-router-dom'
import PrimaryButton from '../components/PrimaryButton'
import {
resolveLandingModel,
type LandingModel,
} from '../data/landingModels'
import { listPublicBlogs, type PublicBlog } from '../lib/api'
import { toFaDigits } from '../lib/faDigits'
import SeoHead from '../components/SeoHead'
import watermarkBg from '../assets/images/mado-230-bg.png'
import BlogCarousel from '../components/BlogCarousel'
import NotFoundPage from './NotFoundPage'
import './LandingModelPage.css'
function ColorCarousel({ images }: { images: string[] }) {
const [index, setIndex] = useState(0)
if (images.length === 0) return null
return (
<div className="landing-carousel">
<div className="landing-carousel__frame">
<img src={images[index]} alt="" />
</div>
<div className="landing-carousel__dots">
{images.map((_, i) => (
<button
key={i}
type="button"
className={i === index ? 'is-active' : ''}
aria-label={`رنگ ${i + 1}`}
onClick={() => setIndex(i)}
/>
))}
</div>
</div>
)
}
function LandingContent({ model }: { model: LandingModel }) {
const [blogs, setBlogs] = useState<PublicBlog[]>([])
const rootRef = useRef<HTMLDivElement>(null)
const modelCode = model.label.replace('مادو ', '')
useEffect(() => {
void listPublicBlogs()
.then((data) => setBlogs(data))
.catch(() => setBlogs([]))
}, [model])
useEffect(() => {
const root = rootRef.current
if (!root) return
const nodes = [...root.querySelectorAll('.js-reveal')]
const io = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
if (!entry.isIntersecting) continue
entry.target.classList.add('is-in')
io.unobserve(entry.target)
}
},
{ threshold: 0.16, rootMargin: '0px 0px -8% 0px' },
)
nodes.forEach((node) => io.observe(node))
return () => io.disconnect()
}, [model.id, blogs.length])
return (
<div className="landing" key={model.id} ref={rootRef}>
<SeoHead
title={`${model.titleFa} - موتور سکلیت برقی`}
description={model.description}
path={`/landing/${model.id}/${model.slug}`}
/>
<section className="landing__slider">
<div
className="landing__slider-bg"
style={{ backgroundImage: `url(${watermarkBg})` }}
aria-hidden="true"
/>
<div className="container landing__slider-inner">
<div className="landing__hero-title">
<h1>
<span className="landing__chip landing__chip--muted landing__chip--lg">
موتورسیکلت
</span>
<strong className="landing__chip landing__chip--xl text-gradient-1 text-shadow">
{model.label}
</strong>
</h1>
<PrimaryButton to="#learn-more" title="بــــــــــرو بریــــــــــــــــم" />
</div>
<div
className={`landing__hero-row ${model.heroExtras ? 'landing__hero-row--extras' : ''}`}
>
<div className="landing__stat landing__stat--speed">
<span className="landing__chip landing__chip--lg text-gradient-2">
حداکثر سرعت
</span>
<div className="landing__stat-line">
<strong className="landing__chip landing__chip--xl">
{toFaDigits(model.maxSpeed)}
</strong>
<span className="landing__chip landing__chip--lg">کیلومتــــر</span>
</div>
{model.heroExtras?.[0] ? (
<div className="landing__extra">
<img src={model.heroExtras[0].image} alt="" width={90} />
<strong className="landing__chip landing__chip--lg">
{model.heroExtras[0].title}
</strong>
<span className="landing__chip landing__chip--md en text-muted">
{model.heroExtras[0].subtitle}
</span>
</div>
) : null}
</div>
<div className="landing__stat landing__stat--range landing__stat--mobile">
<span className="landing__chip landing__chip--lg text-gradient-2">پیمایش تا</span>
<div className="landing__stat-line">
<strong className="landing__chip landing__chip--xl">
{toFaDigits(model.rangeValue)}
</strong>
<span className="landing__chip landing__chip--lg">کیلومتر</span>
</div>
<span className="landing__chip landing__chip--md">{model.rangeNote}</span>
</div>
<div className="landing__hero-image">
<img src={model.heroImage} alt={model.titleFa} />
</div>
<div className="landing__stat landing__stat--range landing__stat--desktop">
<span className="landing__chip landing__chip--lg text-gradient-2">پیمایش تا</span>
<div className="landing__stat-stack">
<div className="landing__stat-line">
<strong className="landing__chip landing__chip--xl">
{toFaDigits(model.rangeValue)}
</strong>
<span className="landing__chip landing__chip--lg">کیلومتر</span>
</div>
<span className="landing__chip landing__chip--md">{model.rangeNote}</span>
</div>
{model.heroExtras?.[1] ? (
<div className="landing__extra">
<img src={model.heroExtras[1].image} alt="" width={80} />
<strong className="landing__chip landing__chip--lg">
{model.heroExtras[1].title}
</strong>
<span className="landing__chip landing__chip--md en text-muted">
{model.heroExtras[1].subtitle}
</span>
</div>
) : null}
</div>
</div>
<div className="landing__scroll">
<img src={model.scrollIcon} alt="" width={25} height={25} />
</div>
</div>
</section>
<section id="learn-more" className="landing__section js-reveal reveal">
<div className="container landing__intro">
<img src={model.introImage} alt="" />
<div>
<div className="landing__kicker">
<span className="landing__chip landing__chip--sm text-muted">مـــــــــادو</span>
<strong className="landing__chip landing__chip--md text-gradient-1 text-shadow">
{modelCode}
</strong>
</div>
<p className="landing__copy">{model.introText}</p>
</div>
</div>
</section>
<section
className="landing__band js-reveal reveal"
style={{ backgroundImage: `url(${model.bg1})` }}
>
<div className="container landing__band-inner">
<img className="landing__band-media" src={model.dashImage} alt="" />
<div className="landing__band-copy">
{model.featureBlocks?.length ? (
model.featureBlocks.map((block) => (
<div key={block.title} className="landing__feature">
<div className="landing__kicker">
<span className="landing__chip landing__chip--sm">{block.eyebrow}</span>
<strong className="landing__chip landing__chip--md text-gradient-2 text-shadow">
{block.title}
</strong>
</div>
<p className="landing__copy">{block.body}</p>
</div>
))
) : (
<>
<div className="landing__kicker">
<span className="landing__chip landing__chip--sm">کیلومتر</span>
<strong className="landing__chip landing__chip--md text-gradient-2 text-shadow">
دیجیتالی
</strong>
</div>
<p className="landing__copy">{model.dashText}</p>
</>
)}
</div>
</div>
</section>
<section
className="landing__highlight js-reveal reveal"
style={{ backgroundImage: `url(${model.bg2})` }}
>
<div className="landing__highlight-inner">
<img
src={model.highlight.icon}
alt=""
width={model.highlight.iconWidth}
height={model.highlight.iconWidth}
/>
{model.id === 'mado-230' ? (
<>
<span className="landing__chip landing__chip--sm text-muted">قابلیت</span>
<strong className="landing__chip landing__chip--xl text-gradient-3 text-shadow">
فست شارژ
</strong>
<span className="landing__chip landing__chip--sm text-muted">به زودی...</span>
</>
) : (
<>
<strong className="landing__chip landing__chip--xl text-gradient-3 text-shadow">
{model.highlight.title}
</strong>
{model.highlight.body ? (
<p className="landing__copy landing__copy--center">{model.highlight.body}</p>
) : null}
</>
)}
</div>
</section>
<section className="landing__section js-reveal reveal">
<div className="container landing__colors">
<strong className="landing__chip landing__chip--md text-gradient-4 text-shadow">
{model.colorTitle}
</strong>
{model.colorSubtitles.map((line) => (
<p key={line} className="landing__copy landing__copy--center">
{line}
</p>
))}
<ColorCarousel images={model.colors} />
</div>
</section>
<section className="landing__split js-reveal reveal reveal--split">
<img src={model.batteryImage} alt="" />
<div>
<div className="landing__kicker column">
<span className="landing__chip landing__chip--sm text-muted">باطری</span>
<strong className="landing__chip landing__chip--md text-gradient-1 text-shadow">
لیتیومی نسل جدید
</strong>
</div>
<ul>
{model.batteryItems.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</div>
</section>
<section
className="landing__band js-reveal reveal"
style={{ backgroundImage: `url(${model.bg1})` }}
>
<div className="container landing__band-inner landing__band-inner--wide">
<img src={model.partsImage} alt="" />
<p className="landing__copy">
دسترسی آسان به تمامی قطعات بواسطه تولید 80 قطعه از 100 قطعه اصلی در داخل کشور قیمت مناسب
خدمات و قطعات موتور سیکلت
</p>
</div>
</section>
<section className="landing__split js-reveal reveal reveal--split">
<img src={model.ecoImage} alt="" />
<div>
<div className="landing__kicker column">
<span className="landing__chip landing__chip--sm text-muted">مادوموتور</span>
<strong className="landing__chip landing__chip--md text-gradient-5">
دوست دار محیط زیست
</strong>
</div>
<p className="landing__copy">
با موتور سیکت های برقی مادو موتور با کاهش آلایندگی هوا به سلامت یکدیگر کمک کنیم
</p>
</div>
</section>
<section
className="landing__guarantee js-reveal reveal"
style={{ backgroundImage: `url(${model.guaranteeTypo})` }}
>
<div className="container landing__guarantee-inner">
<img src={model.guaranteeImage} alt="گارانتی" />
<div>
<div className="landing__kicker column">
<span className="landing__chip landing__chip--sm text-muted">گارانتی</span>
<strong className="landing__chip landing__chip--md text-gradient-1 text-shadow">
بلند مدت و خدمات پس از فروش
</strong>
</div>
<ul>
{model.guaranteeItems.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</div>
</div>
</section>
<section
className="landing__band landing__band--price js-reveal reveal"
style={{ backgroundImage: `url(${model.bg1})` }}
>
<div className="container landing__band-inner">
<img src={model.priceImage} alt="" />
<div>
<div className="landing__kicker column">
<span className="landing__chip landing__chip--sm text-muted">قیمت</span>
<strong className="landing__chip landing__chip--md text-gradient-1">
و شرایط مناسب
</strong>
</div>
<ul>
{model.priceItems.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</div>
</div>
</section>
{blogs.length > 0 ? (
<section className="landing__section js-reveal reveal">
<div className="container landing__blogs">
<strong className="landing__chip landing__chip--lg text-gradient-2">
آخرین مقالات
</strong>
<BlogCarousel blogs={blogs} />
</div>
</section>
) : null}
</div>
)
}
export default function LandingModelPage() {
const { model } = useParams()
const landing = resolveLandingModel(model)
if (!landing) return <NotFoundPage />
return <LandingContent model={landing} />
}