Code — how this page is built

Under the hood

The actual source of the components on this page, read straight from the repo. Copy it, read it, or open it on GitHub.


Fetches the current season's driver standings from the keyless Jolpica/Ergast API and renders the top of the table (position, driver, team, points).

'use client';

import * as React from 'react';

interface Standing {
  pos: string;
  name: string;
  team: string;
  points: string;
  wins: string;
}

export function F1Game() {
  const [rows, setRows] = React.useState<Standing[] | null>(null);
  const [season, setSeason] = React.useState('');
  const [round, setRound] = React.useState('');
  const [error, setError] = React.useState(false);

  React.useEffect(() => {
    fetch('https://api.jolpi.ca/ergast/f1/current/driverStandings.json', {
      headers: { Accept: 'application/json' },
    })
      .then((r) => r.json())
      .then((d) => {
        const list = d?.MRData?.StandingsTable?.StandingsLists?.[0];
        if (!list) throw new Error('no data');
        setSeason(list.season);
        setRound(list.round);
        setRows(
          list.DriverStandings.slice(0, 12).map(
            (s: {
              position: string;
              points: string;
              wins: string;
              Driver: { givenName: string; familyName: string };
              Constructors: { name: string }[];
            }) => ({
              pos: s.position,
              name: `${s.Driver.givenName} ${s.Driver.familyName}`,
              team: s.Constructors[s.Constructors.length - 1]?.name ?? '',
              points: s.points,
              wins: s.wins,
            }),
          ),
        );
      })
      .catch(() => setError(true));
  }, []);

  if (error) return <div className="font-mono text-sm opacity-60">F1 standings unavailable — try again later</div>;
  if (!rows) return <div className="font-mono text-sm opacity-50">loading the grid…</div>;

  return (
    <div className="flex w-full max-w-lg flex-col items-center gap-4">
      <div className="font-mono text-[11px] uppercase tracking-[0.12em] opacity-55">
        {season} drivers&apos; championship · after round {round}
      </div>
      <table className="w-full border-collapse text-sm">
        <tbody>
          {rows.map((r) => (
            <tr key={r.pos} className="border-b border-foreground/10">
              <td className="w-8 py-2 font-mono opacity-50">{r.pos}</td>
              <td className="py-2 font-medium">{r.name}</td>
              <td className="py-2 text-sm opacity-60">{r.team}</td>
              <td className="py-2 text-right font-mono font-bold">{r.points}</td>
            </tr>
          ))}
        </tbody>
      </table>
      <div className="font-mono text-[11px] uppercase tracking-[0.12em] opacity-45">points · live from the season</div>
    </div>
  );
}
↖ kaspirius