1export type Theme = Record<string, string> & {
2 bg: string;
3 fg: string;
4 accent: string;
5 accent2: string;
6};
7
8export const defaultTheme: Theme = {
9 bg: '#11001c',
10 fg: '#f8fafc',
11 accent: '#ec4899',
12 accent2: '#8b5cf6'
13};
14
15export const hashColor = (input: string): string => {
16 let hash: number;
17
18 const id = input.split(':').pop() || input;
19
20 hash = 0;
21 for (let i = 0; i < Math.min(10, id.length); i++) {
22 hash = (hash << 4) + id.charCodeAt(i);
23 }
24 hash = hash >>> 0;
25
26 // magic mixing
27 hash ^= hash >>> 16;
28 hash = Math.imul(hash, 0x21f0aaad);
29 hash ^= hash >>> 15;
30 hash = hash >>> 0;
31
32 const hue = hash % 360;
33 const saturation = 0.8 + ((hash >>> 10) % 20) * 0.01; // 80-100%
34 const lightness = 0.45 + ((hash >>> 20) % 35) * 0.01; // 45-80%
35
36 const rgb = hslToRgb(hue, saturation, lightness);
37 const hex = rgb.map((value) => value.toString(16).padStart(2, '0')).join('');
38
39 return `#${hex}`;
40};
41
42const hslToRgb = (h: number, s: number, l: number): [number, number, number] => {
43 const c = (1 - Math.abs(2 * l - 1)) * s;
44 const hPrime = h / 60;
45 const x = c * (1 - Math.abs((hPrime % 2) - 1));
46 const m = l - c / 2;
47
48 let r: number, g: number, b: number;
49
50 if (hPrime < 1) {
51 r = c;
52 g = x;
53 b = 0;
54 } else if (hPrime < 2) {
55 r = x;
56 g = c;
57 b = 0;
58 } else if (hPrime < 3) {
59 r = 0;
60 g = c;
61 b = x;
62 } else if (hPrime < 4) {
63 r = 0;
64 g = x;
65 b = c;
66 } else if (hPrime < 5) {
67 r = x;
68 g = 0;
69 b = c;
70 } else {
71 r = c;
72 g = 0;
73 b = x;
74 }
75
76 return [Math.round((r + m) * 255), Math.round((g + m) * 255), Math.round((b + m) * 255)];
77};