280 lines · 9.3 KB
import type { ReactNode } from "react";
import type { AccountCardData, RepoCardData } from "~/lib/og";
import { OG_HEIGHT, OG_WIDTH } from "~/lib/og";
import { LOGO_SVG } from "./logo";
import { languageColor } from "~/lib/languages";

/** Mirrors src/styles/app.css: gray-950 page, gray-800 rules, the orange brand accent. */
const COLORS = {
  page: "#030712",
  rule: "#1f2937",
  text: "#f9fafb",
  body: "#d1d5db",
  muted: "#9ca3af",
  accent: "#f6821f",
  accentDeep: "#2a1404",
  accentSoft: "#ffb27a",
} as const;

const LOGO_URI = `data:image/svg+xml;base64,${btoa(LOGO_SVG)}`;

const DESCRIPTION_CHARS = 170;
/** Topics take a row, so the description gives up about one line. */
const DESCRIPTION_WITH_TOPICS_CHARS = 90;

export function truncate(text: string, max: number): string {
  const clean = text.replace(/\s+/g, " ").trim();
  if (clean.length <= max) return clean;
  const cut = clean.slice(0, max - 1);
  const space = cut.lastIndexOf(" ");
  return `${(space > max * 0.6 ? cut.slice(0, space) : cut).replace(/[\s.,;:]+$/, "")}…`;
}

const THOUSAND = 1000;
const TEN_THOUSAND = 10_000;
const MILLION = 1_000_000;

export function compactCount(value: number): string {
  if (value < THOUSAND) return String(value);
  if (value < MILLION) return `${(value / THOUSAND).toFixed(value < TEN_THOUSAND ? 1 : 0).replace(/\.0$/, "")}k`;
  return `${(value / MILLION).toFixed(1).replace(/\.0$/, "")}m`;