50 lines · 1.8 KB
import { languageColor } from "~/lib/languages";
import type { LanguageShare } from "~/lib/languages";
import { cn } from "~/utils/cn";

const ONE_DECIMAL_BELOW = 10;

function percent(bytes: number, total: number): string {
  const share = (bytes / total) * 100;
  return `${share < ONE_DECIMAL_BELOW ? share.toFixed(1) : share.toFixed(0)}%`;
}

/** The default branch's languages as one proportional bar with a legend, like GitHub's sidebar. */
export function LanguageBar({ languages, className }: { languages: readonly LanguageShare[]; className?: string }) {
  const total = languages.reduce((sum, language) => sum + language.bytes, 0);
  if (total === 0) return null;
  return (
    <section className={cn("space-y-2", className)} aria-label="Languages">
      <div className="flex h-2 overflow-hidden rounded-full bg-kumo-hairline">
        {languages.map((language) => (
          <span
            key={language.name}
            className="h-full"
            style={{ width: `${(language.bytes / total) * 100}%`, backgroundColor: languageColor(language.name) }}
            title={`${language.name} ${percent(language.bytes, total)}`}
          />
        ))}
      </div>
      <ul className="flex flex-wrap gap-x-4 gap-y-1 text-xs text-kumo-subtle">
        {languages.map((language) => (
          <li key={language.name} className="flex items-center gap-1.5">
            <LanguageDot name={language.name} />
            <span className="font-medium text-kumo-default">{language.name}</span>
            <span>{percent(language.bytes, total)}</span>
          </li>
        ))}
      </ul>
    </section>
  );
}