121 lines · 4.1 KB
import type { LanguageShare } from "./languages";

const CARD_LANGUAGES = 6;

/** The card's language strip: the largest languages as whole percents (at least 1), the rest as "Other". */
export function cardLanguages(languages: readonly LanguageShare[]): Array<{ name: string; percent: number }> {
  const total = languages.reduce((sum, language) => sum + language.bytes, 0);
  if (total === 0) return [];
  const shares = languages.map((language) => ({ name: language.name, bytes: language.bytes }));
  const kept = shares.filter((language) => language.name !== "Other").slice(0, CARD_LANGUAGES);
  const rest = total - kept.reduce((sum, language) => sum + language.bytes, 0);
  if (rest > 0) kept.push({ name: "Other", bytes: rest });
  return kept.map((language) => ({
    name: language.name,
    percent: Math.max(1, Math.round((language.bytes / total) * 100)),
  }));
}

/** Social card URLs and their version hashes; shared by page heads (client and server) and the /og handler. */

/** Bump when a card layout changes so every cached card URL changes with it. */
export const OG_RENDERER_VERSION = "2";
export const OG_WIDTH = 1200;
export const OG_HEIGHT = 630;
export const OG_PREFIX = "/og/";
export const SITE_OG_PATH = "/og/site.png";
export const SITE_DESCRIPTION =
  "gitfor hosts Git repositories with pull requests, Actions-style CI, issues, security scanning and sites. Open source under 0BSD, and you can run your own instance.";
export const SITE_OG_ALT = "gitfor: open-source Git hosting, code review and CI";

/** FNV-1a 32-bit over the joined fields: cheap, sync and stable on both sides; it only needs to change, not resist collisions. */
export function ogVersion(fields: ReadonlyArray<string | number | null | undefined>): string {
  const input = [
    OG_RENDERER_VERSION,
    ...fields.map((field) => (field === null || field === undefined ? "" : String(field))),
  ].join("\u0000");
  let hash = 0x811c9dc5;
  for (let index = 0; index < input.length; index++) {
    hash ^= input.charCodeAt(index);
    hash = Math.imul(hash, 0x01000193);