feat: add product section components and integrate them into the homepage landing page
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
'use client';
|
||||
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export function Ecosystem() {
|
||||
const t = useTranslations();
|
||||
|
||||
useEffect(() => {
|
||||
const grid = document.getElementById('bentoGrid');
|
||||
let obs: IntersectionObserver;
|
||||
|
||||
if (grid) {
|
||||
const bars = grid.querySelectorAll<HTMLElement>('.report-bar');
|
||||
const ring = grid.querySelector<SVGElement>('.ring-progress');
|
||||
let done = false;
|
||||
|
||||
obs = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting && !done) {
|
||||
done = true;
|
||||
bars.forEach((bar, i) => {
|
||||
setTimeout(() => {
|
||||
if (bar.dataset.w) bar.style.width = bar.dataset.w;
|
||||
}, i * 150);
|
||||
});
|
||||
if (ring && ring.dataset.dash) {
|
||||
setTimeout(() => {
|
||||
ring.style.strokeDasharray = ring.dataset.dash!;
|
||||
}, 200);
|
||||
}
|
||||
obs.disconnect();
|
||||
}
|
||||
});
|
||||
},
|
||||
{ threshold: 0.35 },
|
||||
);
|
||||
obs.observe(grid);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (obs) obs.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<section className="ecosystem" id="ecosystem">
|
||||
<div className="container">
|
||||
<div className="ecosystem-head">
|
||||
<h2>{t('Ecosystem.title')}</h2>
|
||||
<p>{t('Ecosystem.desc')}</p>
|
||||
</div>
|
||||
|
||||
<div className="bento" id="bentoGrid">
|
||||
{/* Ticketing */}
|
||||
<div className="bento-card bento-r1">
|
||||
<h3>{t('Ecosystem.ticketing.title')}</h3>
|
||||
<p>{t('Ecosystem.ticketing.desc')}</p>
|
||||
<div className="bento-illustration">
|
||||
<div className="ticket-rows">
|
||||
<div className="ticket-row">
|
||||
<div className="ticket-track drift-a" style={{ marginLeft: '-14px' }}>
|
||||
<span className="pill pill-outline">TX24409198-8798</span>
|
||||
<span className="pill pill-orange">TX24409198-8797</span>
|
||||
<span className="pill pill-lime">TX24409198-8798</span>
|
||||
<span className="pill pill-outline">TX24409198-8901</span>
|
||||
<span className="pill pill-navy">TX24409198-8811</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ticket-row">
|
||||
<div className="ticket-track drift-b" style={{ marginLeft: '-32px' }}>
|
||||
<span className="pill pill-lime">TX24409198-8801</span>
|
||||
<span className="pill pill-outline">TX24409198-8787</span>
|
||||
<span className="pill pill-navy">TX24409198-8786</span>
|
||||
<span className="pill pill-outline">TX24409198-8901</span>
|
||||
<span className="pill pill-outline">TX24409198-8881</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ticket-row">
|
||||
<div className="ticket-track drift-a" style={{ marginLeft: '-22px', animationDelay: '-1.4s' }}>
|
||||
<span className="pill pill-outline">TX24409198-8902</span>
|
||||
<span className="pill pill-lime">TX24409198-8788</span>
|
||||
<span className="pill pill-outline">TX24409198-8790</span>
|
||||
<span className="pill pill-orange">TX24409198-8905</span>
|
||||
<span className="pill pill-outline">TX24409198-8812</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Access Management */}
|
||||
<div className="bento-card bento-r2">
|
||||
<div className="bento-illustration access-illustration">
|
||||
<div className="chip-row">
|
||||
<div className="chip active">
|
||||
<span>{t('Ecosystem.stats.qr')}</span>
|
||||
<i className="uil uil-qrcode-scan"></i>
|
||||
</div>
|
||||
<div className="chip">
|
||||
<span>{t('Ecosystem.stats.gate')}</span>
|
||||
<i className="uil uil-monitor-heart-rate"></i>
|
||||
</div>
|
||||
<div className="chip">
|
||||
<span>{t('Ecosystem.stats.rfid')}</span>
|
||||
<i className="uil uil-rss-interface"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ring-wrap">
|
||||
<svg width="140" height="140" viewBox="0 0 100 100">
|
||||
<defs>
|
||||
<linearGradient id="rainbowGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stopColor="#f66b0e" />
|
||||
<stop offset="70%" stopColor="#112b3c" />
|
||||
<stop offset="100%" stopColor="#205375" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<circle cx="50" cy="50" r="34" fill="none" stroke="#E1E5E3" strokeWidth="9" />
|
||||
<circle
|
||||
className="ring-progress"
|
||||
cx="50"
|
||||
cy="50"
|
||||
r="34"
|
||||
fill="none"
|
||||
stroke="url(#rainbowGrad)"
|
||||
strokeWidth="9"
|
||||
strokeLinecap="round"
|
||||
data-dash="166 213.6"
|
||||
transform="rotate(-90 50 50)"
|
||||
/>
|
||||
</svg>
|
||||
<div className="ring-text">
|
||||
<b>0.4s</b>
|
||||
<small>{t('Ecosystem.stats.avg')}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3>{t('Ecosystem.access.title')}</h3>
|
||||
<p>{t('Ecosystem.access.desc')}</p>
|
||||
</div>
|
||||
|
||||
{/* Visitor Operations */}
|
||||
<div className="bento-card bento-r3">
|
||||
<div className="bento-illustration visitor-illustration">
|
||||
<div className="avatar-row">
|
||||
<div className="avatar-stack">
|
||||
<div className="avatar" style={{ background: '#b9f001' }}></div>
|
||||
<div className="avatar" style={{ background: '#f66b0e' }}></div>
|
||||
<div className="avatar" style={{ background: '#112b3c' }}></div>
|
||||
<div className="avatar" style={{ background: '#e1e5e3' }}></div>
|
||||
</div>
|
||||
<span>{t('Ecosystem.stats.queue')}</span>
|
||||
</div>
|
||||
<div className="zone-grid">
|
||||
<div className="zone-cell" style={{ background: '#e1e5e3' }}></div>
|
||||
<div className="zone-cell" style={{ background: '#e1e5e3' }}></div>
|
||||
<div className="zone-cell" style={{ background: '#205375' }}></div>
|
||||
<div className="zone-cell" style={{ background: '#e1e5e3' }}></div>
|
||||
<div className="zone-cell" style={{ background: '#e1e5e3' }}></div>
|
||||
<div className="zone-cell" style={{ background: '#b9f001' }}></div>
|
||||
<div className="zone-cell" style={{ background: '#e1e5e3' }}></div>
|
||||
<div className="zone-cell" style={{ background: 'linear-gradient(135deg, #205375, #112b3c)' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
<h3>{t('Ecosystem.visitor.title')}</h3>
|
||||
<p>{t('Ecosystem.visitor.desc')}</p>
|
||||
</div>
|
||||
|
||||
{/* Report */}
|
||||
<div className="bento-card bento-r4">
|
||||
<h3 style={{ marginBottom: '8px' }}>{t('Ecosystem.report.title')}</h3>
|
||||
<p style={{ marginBottom: '26px' }}>{t('Ecosystem.report.desc')}</p>
|
||||
<div className="report-bars">
|
||||
{[
|
||||
{ w: '150px', bg: '#b9f001', val: 'Rp32.5M', key: 'Ecosystem.stats.revenue' },
|
||||
{ w: '220px', bg: '#f66b0e', val: '1,284', key: 'Ecosystem.stats.visitors' },
|
||||
{ w: '300px', bg: '#112b3c', val: '1,120,240', key: 'Ecosystem.stats.checkin' },
|
||||
].map((item, idx) => (
|
||||
<div className="report-bar-row" key={idx}>
|
||||
<div className="report-bar" data-w={item.w} style={{ background: item.bg }}></div>
|
||||
<div className="report-bar-value">
|
||||
<b>{item.val}</b>
|
||||
<small>{(t as any)(item.key)}</small>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user