forked from izu/student-web-if-development-kit
feat(ACAAB): redesign stats section - layout total prestasi & portofolio
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,20 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ACAAB — Dev Preview</title>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ACAAB — Dev Preview</title>
|
||||
<style>
|
||||
#dev-banner {
|
||||
background: #feb401; color: #003150; font-size: 11px; font-weight: 700;
|
||||
text-align: center; padding: 6px; letter-spacing: .05em; position: sticky; top: 0; z-index: 999;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
<script type="module" crossorigin src="../acaab.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="../acaab.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="dev-banner">⚡ DEV MODE — Navbar & footer tidak tampil di sini. Gunakan kit dev server (root) untuk preview lengkap.</div>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
</head>
|
||||
<body>
|
||||
<div id="dev-banner">⚡ DEV MODE — Navbar & footer tidak tampil di sini. Gunakan kit dev server (root) untuk preview lengkap.</div>
|
||||
<div id="root"></div>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -55,47 +55,53 @@ function useCountUp(target: number, duration = 1600) {
|
||||
return { count, elRef };
|
||||
}
|
||||
|
||||
/* ── Big stat ──────────────────────────────────────────────────────────── */
|
||||
function BigStat({ value, label }: { value: number; label: string }) {
|
||||
const { count, elRef } = useCountUp(value);
|
||||
return (
|
||||
<div ref={elRef} className="flex flex-col items-center justify-center gap-1 md:gap-1.5 px-2 h-full">
|
||||
<div className="text-[3.5rem] md:text-[4.5rem] lg:text-[5rem] font-black font-display text-primary-navy leading-none tabular-nums">
|
||||
{count}
|
||||
</div>
|
||||
<div className="text-[10px] md:text-[11px] lg:text-[13px] leading-none font-extrabold uppercase tracking-[0.1em] text-primary-navy text-center">
|
||||
{label}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* ── Level row ──────────────────────────────────────────────────────────── */
|
||||
function LevelRow({ label, value, delay = 0 }: { label: string; value: number; delay?: number }) {
|
||||
/* ── Stat number with label ─────────────────────────────────────────────── */
|
||||
function StatItem({ value, label, delay = 0 }: { value: number; label: string; delay?: number }) {
|
||||
const { count, elRef } = useCountUp(value, 1600 + delay);
|
||||
return (
|
||||
<div ref={elRef} className="flex items-center gap-2 md:gap-3 lg:gap-4">
|
||||
<span className="text-[10px] md:text-[11px] lg:text-[12px] leading-none font-extrabold uppercase tracking-[0.1em] text-primary-navy text-right">
|
||||
{label}
|
||||
</span>
|
||||
<span className="text-lg md:text-xl lg:text-2xl leading-none font-black font-display text-primary-navy tabular-nums text-right w-[1rem] md:w-[1.25rem] lg:w-[1.5rem]">
|
||||
<div ref={elRef} className="flex flex-col items-center gap-1" style={{ minWidth: 'clamp(5rem, 10vw, 8rem)' }}>
|
||||
<div
|
||||
className="font-display font-black text-primary-navy leading-none tabular-nums"
|
||||
style={{ fontSize: 'clamp(2.8rem, 6vw, 5rem)' }}
|
||||
>
|
||||
{count}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="font-display font-bold text-primary-navy text-center leading-tight uppercase tracking-wide"
|
||||
style={{ fontSize: 'clamp(0.6rem, 1.1vw, 0.8rem)' }}
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* ── Dividers ───────────────────────────────────────────────────────────── */
|
||||
function VDivider() {
|
||||
/* ── Section panel ──────────────────────────────────────────────────────── */
|
||||
function StatPanel({
|
||||
title,
|
||||
children,
|
||||
flexClass = 'flex-1',
|
||||
}: {
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
flexClass?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="hidden md:flex items-center justify-center self-stretch">
|
||||
<div className="w-px h-full bg-primary-navy/10 rounded-full" />
|
||||
<div className={`flex flex-col gap-5 ${flexClass}`}>
|
||||
{/* Dark pill header — full width of this panel */}
|
||||
<div
|
||||
className="bg-primary-navy text-white font-display font-bold text-center rounded-xl px-8 py-3 w-full uppercase tracking-wide"
|
||||
style={{ fontSize: 'clamp(0.85rem, 1.5vw, 1.05rem)' }}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
{/* Numbers row — equal spacing */}
|
||||
<div className="flex items-end justify-evenly pb-2">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
function HDivider() {
|
||||
return <div className="block md:hidden h-px w-2/3 mx-auto bg-primary-navy/10 my-2 rounded-full" />;
|
||||
}
|
||||
|
||||
/* ── Main export ────────────────────────────────────────────────────────── */
|
||||
export default function Stats() {
|
||||
@@ -119,34 +125,29 @@ export default function Stats() {
|
||||
<div id="tentang">
|
||||
{/* ── Stats bar ─────────────────────────────────────────────────── */}
|
||||
<section className="relative z-10 mb-2 rounded-xl overflow-hidden shadow-[0_10px_30px_-10px_rgba(253,184,19,0.4)]">
|
||||
<div className="bg-[#FDB813] relative">
|
||||
<div className="bg-[#FDB813] relative px-6 md:px-10 py-7 md:py-9">
|
||||
<div className="absolute inset-0 bg-white/5 mix-blend-overlay pointer-events-none" />
|
||||
<div className="relative grid grid-cols-1 stats-grid items-stretch px-4 md:px-6 lg:px-8 py-5 md:py-6 lg:py-7">
|
||||
|
||||
{/* ① Total Prestasi */}
|
||||
<div className="flex items-center justify-center">
|
||||
<BigStat value={totalPrestasi} label={t.stats.totalPrestasi} />
|
||||
</div>
|
||||
<div className="relative flex flex-col md:flex-row md:items-start gap-8 md:gap-6">
|
||||
|
||||
<VDivider />
|
||||
<HDivider />
|
||||
{/* ① Total Prestasi — 3 kolom → flex-[3] */}
|
||||
<StatPanel
|
||||
title={lang === 'id' ? 'Total Prestasi' : 'Total Achievements'}
|
||||
flexClass="flex-[4]"
|
||||
>
|
||||
<StatItem value={totalPrestasi} label={lang === 'id' ? 'prestasi mahasiswa' : 'student achievements'} delay={0} />
|
||||
<StatItem value={internasional} label={lang === 'id' ? 'internasional' : 'international'} delay={150} />
|
||||
<StatItem value={nasional} label={lang === 'id' ? 'nasional' : 'national'} delay={300} />
|
||||
<StatItem value={regional} label="regional" delay={450} />
|
||||
</StatPanel>
|
||||
|
||||
{/* ② Total Proyek */}
|
||||
<div className="flex items-center justify-center">
|
||||
<BigStat value={totalProyek} label={t.stats.totalProyek} />
|
||||
</div>
|
||||
|
||||
<VDivider />
|
||||
<HDivider />
|
||||
|
||||
{/* ③ Level breakdown */}
|
||||
<div className="flex justify-center items-center px-4 md:px-0">
|
||||
<div className="flex flex-col justify-center items-end gap-2 md:gap-3 lg:gap-3">
|
||||
<LevelRow label="Internasional" value={internasional} delay={0} />
|
||||
<LevelRow label="Nasional" value={nasional} delay={150} />
|
||||
<LevelRow label="Regional" value={regional} delay={300} />
|
||||
</div>
|
||||
</div>
|
||||
{/* ② Total Portofolio — 1 kolom → flex-[1] */}
|
||||
<StatPanel
|
||||
title={lang === 'id' ? 'Total Portofolio' : 'Total Portfolio'}
|
||||
flexClass="flex-[1.5]"
|
||||
>
|
||||
<StatItem value={totalProyek} label={lang === 'id' ? 'proyek mahasiswa' : 'student projects'} delay={200} />
|
||||
</StatPanel>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user