1import { PROJECT_ICON_COLORS } from "./projectIconColors";
2import type { ProjectIconColor } from "@t3tools/contracts";
3
4/** Visual identity tokens for a generated project badge. */
5export interface ProjectIdentity {
6 readonly monogram: string;
7 readonly color: ProjectIconColor;
8}
9
10function normalizeProjectName(projectName: string): string {
11 return projectName.normalize("NFKC").trim();
12}
13
14function projectMonogram(projectName: string): string {
15 const words = normalizeProjectName(projectName).match(/[\p{L}\p{N}]+/gu) ?? [];
16 const firstWord = words[0];
17 if (!firstWord) return "PR";
18
19 const glyphs = Array.from(firstWord);
20 const first = glyphs[0] ?? "P";
21 const second =
22 glyphs.slice(1).find((glyph) => /\p{N}/u.test(glyph)) ??
23 (words.length > 1 ? Array.from(words.at(-1) ?? "")[0] : glyphs.at(-1)) ??
24 first;
25 return Array.from(`${first}${second}`.toUpperCase()).slice(0, 2).join("");
26}
27
28function projectColor(projectName: string): ProjectIconColor {
29 const seed = normalizeProjectName(projectName).toLocaleLowerCase("en-US") || "project";
30 let index = 0;
31 for (const glyph of seed) {
32 index = (index * 31 + (glyph.codePointAt(0) ?? 0)) % PROJECT_ICON_COLORS.length;
33 }
34 return PROJECT_ICON_COLORS[index]?.value ?? "blue";
35}
36
37/** Derives the stable monogram and generated colors used when a project has no icon. */
38export function deriveProjectIdentity(projectName: string): ProjectIdentity {
39 return {
40 monogram: projectMonogram(projectName),
41 color: projectColor(projectName),
42 };
43}