← alle entries

stats-bento

FC-0111Sectiesstatsblockv2.0.0

Vier cijfers in een bento-raster: één groot vlak op --primary (label, groot getal, toelichting, schuine arcering naar de hoek), een groeikaart met staafjes, een klein telvlak en een beoordelingsvlak met glyph. Smal stapelt alles; breed 6 kolommen × 2.

zelfde component — andere tokens
Marktaandeel

64%

Toonaangevend in cloud-infrastructuur voor snelgroeiende start-ups.

Groei

+240%

12

Awards

4,9 / 5,0

Beoordelingen van klanten

blocks/stats/stats-bento.tsx
/**
 * StatsBento — vier cijfers in een bento-raster: één groot vlak op --primary
 * (label, groot getal, toelichting, met een schuine arcering die naar de
 * hoek uitvloeit), een groeikaart met een rij staafjes, een klein telvlak en
 * een beoordelingsvlak met glyph. Smal stapelt alles; breed 6 kolommen × 2.
 *
 * Geoogst uit 21st.dev Stats Bento (uilayout): de repeating-linear-gradient
 * met #808080 → --primary-foreground op lage dekking, vaste teksten
 * ('Market Share 64%', 'G2 Peer Reviews') → props, size-10/★ → glyph-slot.
 * Statisch; de staafjes zijn hoogtes in % (geen animatie).
 */

import type * as React from "react";

export interface StatsBentoProps extends Omit<React.HTMLAttributes<HTMLElement>, "children"> {
  /** Het grote vlak. */
  main: { label: string; value: string; text?: string };
  /** De groeikaart: getal + staafjes (0–100). */
  trend?: { label: string; value: string; bars?: readonly number[] };
  /** Het kleine telvlak. */
  count?: { value: string; label: string };
  /** Het beoordelingsvlak. */
  rating?: { value: string; label: string; glyph?: React.ReactNode };
}

export function StatsBento({ main, trend, count, rating, className, ...rest }: StatsBentoProps) {
  return (
    <section {...rest} className={["fp-bento", className].filter(Boolean).join(" ")}>
      <div className="fp-bento__vlak fp-bento__vlak--hoofd">
        <span className="fp-bento__arcering" aria-hidden="true" />
        <div>
          <span className="fp-bento__label fp-bento__label--pil">{main.label}</span>
          <p className="fp-bento__groot">{main.value}</p>
        </div>
        {main.text && <p className="fp-bento__tekst">{main.text}</p>}
      </div>
      {trend && (
        <div className="fp-bento__vlak fp-bento__vlak--trend">
          <div>
            <p className="fp-bento__label">{trend.label}</p>
            <p className="fp-bento__getal">{trend.value}</p>
          </div>
          {trend.bars && (
            <div className="fp-bento__staafjes" aria-hidden="true">
              {trend.bars.map((h, i) => (
                <i key={i} style={{ ["--h" as string]: `${Math.max(0, Math.min(100, h))}%` } as React.CSSProperties} />
              ))}
            </div>
          )}
        </div>
      )}
      {count && (
        <div className="fp-bento__vlak fp-bento__vlak--tel">
          <p className="fp-bento__getal">{count.value}</p>
          <p className="fp-bento__label">{count.label}</p>
        </div>
      )}
      {rating && (
        <div className="fp-bento__vlak fp-bento__vlak--score">
          <span className="fp-bento__glyph" aria-hidden="true">{rating.glyph ?? "★"}</span>
          <div>
            <p className="fp-bento__score">{rating.value}</p>
            <p className="fp-bento__label fp-bento__label--klein">{rating.label}</p>
          </div>
        </div>
      )}
    </section>
  );
}
blocks/stats/stats.css
/** StatsBento — importeren in de app-root (registry-site: app/globals.css). */

.fp-bento { display: grid; grid-template-columns: 1fr; gap: 1rem; width: 100%; max-width: 72rem; margin: 0 auto; box-sizing: border-box; color: var(--foreground); }
@media (min-width: 48rem) {
  .fp-bento { grid-template-columns: repeat(6, minmax(0, 1fr)); grid-template-rows: repeat(2, minmax(0, 1fr)); }
  .fp-bento__vlak--hoofd { grid-column: span 3; grid-row: span 2; }
  .fp-bento__vlak--trend { grid-column: span 3; }
  .fp-bento__vlak--tel { grid-column: span 1; }
  .fp-bento__vlak--score { grid-column: span 2; }
}
.fp-bento__vlak { position: relative; overflow: hidden; box-sizing: border-box; border-radius: var(--radius-lg); }
.fp-bento__vlak--hoofd { display: flex; flex-direction: column; justify-content: space-between; gap: 2rem; padding: 2.5rem; background: var(--primary); color: var(--primary-foreground); }
/* Schuine arcering die naar de rechterbovenhoek uitvloeit. */
.fp-bento__arcering {
  position: absolute; inset: 0; pointer-events: none; opacity: 0.3;
  background: repeating-linear-gradient(45deg, color-mix(in srgb, var(--primary-foreground) 50%, transparent) 0 1px, transparent 1px 10px);
  -webkit-mask-image: radial-gradient(ellipse 80% 50% at 100% 0%, black 70%, transparent 110%); mask-image: radial-gradient(ellipse 80% 50% at 100% 0%, black 70%, transparent 110%);
}
.fp-bento__label { margin: 0 0 0.25rem; font: inherit; font-size: var(--text-label); font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted-foreground); }
.fp-bento__label--pil { display: inline-block; margin: 0 0 1.5rem; padding: 0.25rem 0.75rem; border-radius: 999px; font-size: var(--text-label); background: color-mix(in srgb, var(--primary-foreground) 10%, transparent); color: color-mix(in srgb, var(--primary-foreground) 60%, transparent); }
.fp-bento__label--klein { margin: 0.25rem 0 0; letter-spacing: 0; text-transform: none; }
.fp-bento__groot { position: relative; margin: 0; font: inherit; font-size: var(--text-display); line-height: 1; letter-spacing: -0.04em; }
.fp-bento__tekst { position: relative; margin: 0; max-width: 20rem; font: inherit; font-size: var(--text-body-sm); line-height: 1.5; color: color-mix(in srgb, var(--primary-foreground) 60%, transparent); }
.fp-bento__vlak--trend { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 2rem; background: var(--muted); border: 1px solid var(--border); }
.fp-bento__getal { margin: 0; font: inherit; font-size: var(--text-data); line-height: 1.1; letter-spacing: -0.02em; }
.fp-bento__staafjes { display: flex; align-items: flex-end; gap: 0.25rem; height: 2rem; }
.fp-bento__staafjes i { display: block; width: 0.375rem; height: var(--h, 50%); border-radius: 999px; background: var(--foreground); }
.fp-bento__vlak--tel { display: flex; flex-direction: column; justify-content: center; text-align: center; padding: 1.5rem; background: var(--card); color: var(--card-foreground, var(--foreground)); border: 1px solid var(--border); }
.fp-bento__vlak--tel .fp-bento__getal { font-size: var(--text-data); }
.fp-bento__vlak--score { display: flex; align-items: center; gap: 1rem; padding: 1.5rem; background: var(--muted); }
.fp-bento__glyph { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; width: 2.5rem; height: 2.5rem; border-radius: 50%; background: var(--background); color: var(--foreground); font-size: var(--text-h3); font-weight: 600; box-shadow: var(--shadow-overlay); }
.fp-bento__score { margin: 0; font: inherit; font-size: var(--text-body-sm); line-height: 1; }