Menu docs

Komponen · · 3 menit baca

Komponen UI: BrowserFrame, SystemFlow & Stat — dengan contoh live

Tiga komponen server-first yang dipakai di seluruh situs ini — mockup browser, diagram arsitektur dari tag, dan angka count-up — dirender live di halaman ini, lengkap dengan source code-nya.

Hono JSXTailwind CSSVanilla JSA11y
Contoh liveDirender langsung oleh komponennya — bukan gambar.
alifnugraha.my.id/preview
0/7

AI coverage

<0s

Load on 4G

Tiga komponen kecil ini muncul di hampir setiap halaman situs ini: BrowserFrame (bingkai browser untuk mockup), SystemFlow (diagram alur sistem), dan Stat (angka yang menghitung naik saat terlihat). Contoh live-nya dirender langsung di atas ↑ — bukan gambar. Ini source code dan keputusan desain di baliknya.

BrowserFrame — mockup tanpa screenshot

Masalahnya: butuh menampilkan “produk” sebelum screenshot asli tersedia. Solusinya bingkai chrome browser minimal — tiga titik, address bar, lalu slot children untuk isi apa pun:

export const BrowserFrame = ({ url, children }: { url: string; children?: Child }) => (
  <div class="card overflow-hidden">
    <div class="flex items-center gap-3 border-b border-line bg-surface px-4 py-2.5">
      <div class="flex gap-1.5" aria-hidden="true">
        <span class="h-2 w-2 rounded-full border border-line bg-base"></span>
        <span class="h-2 w-2 rounded-full border border-line bg-base"></span>
        <span class="h-2 w-2 rounded-full border border-line bg-base"></span>
      </div>
      <div class="min-w-0 flex-1 truncate rounded-sm border border-line bg-base px-3 py-1
                  font-mono text-[10px] tracking-[0.06em] text-muted">{url}</div>
    </div>
    <div class="bg-base">{children}</div>
  </div>
);

Detail yang penting: min-w-0 + truncate di address bar. Tanpa itu, URL panjang memaksa lebar minimum konten melebihi viewport HP — halaman “mengecil” ke kiri (bug nyata yang pernah terjadi di situs ini).

SystemFlow — diagram arsitektur dari tag

Diagram alur (Storefront → Checkout → AI chat → RAG → Ops) tanpa library diagram: hanya deretan tag dengan “beam” animasi di antaranya. Di mobile, beam disembunyikan dan tag dibiarkan wrap:

export const SystemFlow = ({ nodes }: { nodes: string[] }) => (
  <div class="flex flex-wrap items-center justify-center gap-2 py-1 md:flex-nowrap md:gap-0"
       role="img" aria-label="System flow diagram">
    {nodes.map((node, i) => (
      <>
        {i > 0 && <span class="beam hidden w-10 shrink-0 md:block" aria-hidden="true"></span>}
        <span class="tag shrink-0 bg-base">{node}</span>
      </>
    ))}
  </div>
);

role="img" + aria-label membuat screen reader membacanya sebagai satu diagram, bukan lima tag acak.

Stat — angka yang menghitung naik

Server merender nilai akhir di atribut data-count (SEO dan pengguna tanpa JS tetap dapat angkanya — teks awal prefix + 0 + suffix diganti CSS/JS hanya saat JS aktif). Vanilla JS di site.js menganimasikannya saat elemen masuk viewport lewat IntersectionObserver:

export const Stat = ({ prefix, count, suffix, label, delay }: StatProps) => (
  <div class="text-center" data-reveal style={"--d: " + delay}>
    <div class="font-display text-4xl font-semibold tracking-tight md:text-5xl">
      <span data-count={count} data-prefix={prefix} data-suffix={suffix}>{prefix}0{suffix}</span>
    </div>
    <p class="mt-2 font-mono text-[11px] uppercase tracking-[0.18em] text-muted">{label}</p>
  </div>
);

Prinsip di balik ketiganya

  • Server-first: semua konten ada di HTML awal; JavaScript hanya menambah gerak.
  • Nol dependensi: tidak ada library carousel/diagram/count-up — total JS situs tetap di bawah 20KB.
  • Mobile ditegakkan dengan kelas, bukan JS: flex-wrap, hidden md:block, min-w-0 — layout tidak pernah bergantung pada perhitungan runtime.

Mau fitur seperti ini dibangun untuk bisnismu?