Repository navigation
Expand file tree
/
Copy pathteams.ts
More file actions
129 lines (111 loc) · 10 KB
/
Copy pathteams.ts
File metadata and controls
129 lines (111 loc) · 10 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Curated World Cup nations. Colors are the real kit / crest colors, used to
// drive the reveal palette at runtime. Keep `id` stable, it is what the model
// and the share URL both key off.
export type Team = {
id: string;
name: string;
code: string; // ISO 3166-1 alpha-2, used for the flag
flag: string; // emoji fallback
confederation: 'UEFA' | 'CONMEBOL' | 'CONCACAF' | 'CAF' | 'AFC' | 'OFC';
primary: string; // hero color, floods the reveal
secondary: string; // accent
ink: string; // text color that stays AA-legible on `primary`
nickname: string;
};
export const TEAMS: Team[] = [
{ id: 'argentina', name: 'Argentina', code: 'AR', flag: '🇦🇷', confederation: 'CONMEBOL', primary: '#75AADB', secondary: '#FFFFFF', ink: '#0B1C2C', nickname: 'La Albiceleste' },
{ id: 'brazil', name: 'Brazil', code: 'BR', flag: '🇧🇷', confederation: 'CONMEBOL', primary: '#FFDF00', secondary: '#009C3B', ink: '#0B2312', nickname: 'A Seleção' },
{ id: 'uruguay', name: 'Uruguay', code: 'UY', flag: '🇺🇾', confederation: 'CONMEBOL', primary: '#5CBFEB', secondary: '#0B1C2C', ink: '#08131F', nickname: 'La Celeste' },
{ id: 'colombia', name: 'Colombia', code: 'CO', flag: '🇨🇴', confederation: 'CONMEBOL', primary: '#FCD116', secondary: '#003893', ink: '#231A00', nickname: 'Los Cafeteros' },
{ id: 'ecuador', name: 'Ecuador', code: 'EC', flag: '🇪🇨', confederation: 'CONMEBOL', primary: '#FFDD00', secondary: '#034EA2', ink: '#241F00', nickname: 'La Tri' },
{ id: 'paraguay', name: 'Paraguay', code: 'PY', flag: '🇵🇾', confederation: 'CONMEBOL', primary: '#D52B1E', secondary: '#0038A8', ink: '#FFFFFF', nickname: 'La Albirroja' },
// The kit is white, but a white flood on a near-black page is no flood at all.
// The St George's cross red is the more iconic colour anyway.
{ id: 'england', name: 'England', code: 'GB-ENG', flag: '🏴', confederation: 'UEFA', primary: '#CE1124', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'The Three Lions' },
{ id: 'france', name: 'France', code: 'FR', flag: '🇫🇷', confederation: 'UEFA', primary: '#1E3A8A', secondary: '#EF4135', ink: '#FFFFFF', nickname: 'Les Bleus' },
{ id: 'germany', name: 'Germany', code: 'DE', flag: '🇩🇪', confederation: 'UEFA', primary: '#111111', secondary: '#DD0000', ink: '#FFFFFF', nickname: 'Die Mannschaft' },
{ id: 'spain', name: 'Spain', code: 'ES', flag: '🇪🇸', confederation: 'UEFA', primary: '#C60B1E', secondary: '#FFC400', ink: '#FFFFFF', nickname: 'La Roja' },
{ id: 'italy', name: 'Italy', code: 'IT', flag: '🇮🇹', confederation: 'UEFA', primary: '#0064AA', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'Gli Azzurri' },
{ id: 'portugal', name: 'Portugal', code: 'PT', flag: '🇵🇹', confederation: 'UEFA', primary: '#046A38', secondary: '#DA291C', ink: '#FFFFFF', nickname: 'A Seleção das Quinas' },
{ id: 'netherlands', name: 'Netherlands', code: 'NL', flag: '🇳🇱', confederation: 'UEFA', primary: '#F36C21', secondary: '#21468B', ink: '#1A0C00', nickname: 'Oranje' },
{ id: 'belgium', name: 'Belgium', code: 'BE', flag: '🇧🇪', confederation: 'UEFA', primary: '#E30613', secondary: '#FDDA24', ink: '#FFFFFF', nickname: 'The Red Devils' },
{ id: 'croatia', name: 'Croatia', code: 'HR', flag: '🇭🇷', confederation: 'UEFA', primary: '#E63329', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'Vatreni' },
{ id: 'scotland', name: 'Scotland', code: 'GB-SCT', flag: '🏴', confederation: 'UEFA', primary: '#0065BD', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'The Tartan Army' },
{ id: 'switzerland', name: 'Switzerland', code: 'CH', flag: '🇨🇭', confederation: 'UEFA', primary: '#DA291C', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'Nati' },
{ id: 'poland', name: 'Poland', code: 'PL', flag: '🇵🇱', confederation: 'UEFA', primary: '#DC143C', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'Biało-czerwoni' },
{ id: 'denmark', name: 'Denmark', code: 'DK', flag: '🇩🇰', confederation: 'UEFA', primary: '#C60C30', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'Danish Dynamite' },
{ id: 'austria', name: 'Austria', code: 'AT', flag: '🇦🇹', confederation: 'UEFA', primary: '#ED2939', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'Das Team' },
{ id: 'norway', name: 'Norway', code: 'NO', flag: '🇳🇴', confederation: 'UEFA', primary: '#BA0C2F', secondary: '#00205B', ink: '#FFFFFF', nickname: 'Løvene' },
{ id: 'turkey', name: 'Türkiye', code: 'TR', flag: '🇹🇷', confederation: 'UEFA', primary: '#E30A17', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'Ay-Yıldızlılar' },
{ id: 'usa', name: 'United States', code: 'US', flag: '🇺🇸', confederation: 'CONCACAF', primary: '#0A3161', secondary: '#B31942', ink: '#FFFFFF', nickname: 'The Stars and Stripes' },
{ id: 'mexico', name: 'Mexico', code: 'MX', flag: '🇲🇽', confederation: 'CONCACAF', primary: '#006847', secondary: '#CE1126', ink: '#FFFFFF', nickname: 'El Tri' },
{ id: 'canada', name: 'Canada', code: 'CA', flag: '🇨🇦', confederation: 'CONCACAF', primary: '#D80621', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'Les Rouges' },
{ id: 'costa-rica', name: 'Costa Rica', code: 'CR', flag: '🇨🇷', confederation: 'CONCACAF', primary: '#002B7F', secondary: '#CE1126', ink: '#FFFFFF', nickname: 'La Sele' },
{ id: 'morocco', name: 'Morocco', code: 'MA', flag: '🇲🇦', confederation: 'CAF', primary: '#C1272D', secondary: '#006233', ink: '#FFFFFF', nickname: 'The Atlas Lions' },
{ id: 'senegal', name: 'Senegal', code: 'SN', flag: '🇸🇳', confederation: 'CAF', primary: '#00853F', secondary: '#FDEF42', ink: '#FFFFFF', nickname: 'The Lions of Teranga' },
{ id: 'nigeria', name: 'Nigeria', code: 'NG', flag: '🇳🇬', confederation: 'CAF', primary: '#008751', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'The Super Eagles' },
{ id: 'ghana', name: 'Ghana', code: 'GH', flag: '🇬🇭', confederation: 'CAF', primary: '#006B3F', secondary: '#FCD116', ink: '#FFFFFF', nickname: 'The Black Stars' },
{ id: 'cameroon', name: 'Cameroon', code: 'CM', flag: '🇨🇲', confederation: 'CAF', primary: '#007A5E', secondary: '#CE1126', ink: '#FFFFFF', nickname: 'The Indomitable Lions' },
{ id: 'egypt', name: 'Egypt', code: 'EG', flag: '🇪🇬', confederation: 'CAF', primary: '#C8102E', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'The Pharaohs' },
{ id: 'ivory-coast', name: "Côte d'Ivoire", code: 'CI', flag: '🇨🇮', confederation: 'CAF', primary: '#F77F00', secondary: '#009E60', ink: '#1A0C00', nickname: 'The Elephants' },
{ id: 'algeria', name: 'Algeria', code: 'DZ', flag: '🇩🇿', confederation: 'CAF', primary: '#007229', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'The Desert Foxes' },
{ id: 'japan', name: 'Japan', code: 'JP', flag: '🇯🇵', confederation: 'AFC', primary: '#0B1C6B', secondary: '#BC002D', ink: '#FFFFFF', nickname: 'The Samurai Blue' },
{ id: 'south-korea', name: 'South Korea', code: 'KR', flag: '🇰🇷', confederation: 'AFC', primary: '#CD2E3A', secondary: '#0047A0', ink: '#FFFFFF', nickname: 'The Taegeuk Warriors' },
{ id: 'saudi-arabia', name: 'Saudi Arabia', code: 'SA', flag: '🇸🇦', confederation: 'AFC', primary: '#006C35', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'The Green Falcons' },
{ id: 'iran', name: 'Iran', code: 'IR', flag: '🇮🇷', confederation: 'AFC', primary: '#239F40', secondary: '#DA0000', ink: '#FFFFFF', nickname: 'Team Melli' },
{ id: 'australia', name: 'Australia', code: 'AU', flag: '🇦🇺', confederation: 'AFC', primary: '#FFCD00', secondary: '#00843D', ink: '#231F00', nickname: 'The Socceroos' },
{ id: 'qatar', name: 'Qatar', code: 'QA', flag: '🇶🇦', confederation: 'AFC', primary: '#8A1538', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'The Maroon' },
{ id: 'new-zealand', name: 'New Zealand', code: 'NZ', flag: '🇳🇿', confederation: 'OFC', primary: '#0A0A0A', secondary: '#FFFFFF', ink: '#FFFFFF', nickname: 'The All Whites' },
];
export const TEAMS_BY_ID = new Map(TEAMS.map((t) => [t.id, t]));
export function getTeam(id: string | null | undefined): Team | undefined {
if (!id) return undefined;
return TEAMS_BY_ID.get(id.toLowerCase());
}
/* -------------------------------------------------------------------------
Colour. The kit colours above are the real ones, and some of them are all
but black: Germany is #111111, New Zealand is #0A0A0A. Flood a near-black
page with those and the nation's name disappears. So the authentic colour
is kept as the source of truth, and the colours actually painted on screen
are derived from it and guaranteed to be legible.
------------------------------------------------------------------------- */
const PAGE = "#040705";
function channels(hex: string) {
const n = parseInt(hex.slice(1), 16);
return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
}
function luminance(hex: string) {
const [r, g, b] = channels(hex).map((v) => {
const c = v / 255;
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
});
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
function contrast(a: string, b: string) {
const [x, y] = [luminance(a), luminance(b)];
return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05);
}
function toHex([r, g, b]: number[]) {
return `#${[r, g, b].map((v) => Math.round(v).toString(16).padStart(2, "0")).join("")}`;
}
function mixWithWhite(hex: string, amount: number) {
return toHex(channels(hex).map((v) => v + (255 - v) * amount));
}
/**
* The colour the nation's name is set in. Lifted toward white only as far as it
* needs to be to clear 4.5:1 against the page, so Brazil's yellow is untouched
* and Germany's black becomes a legible graphite.
*/
export function teamGlow(team: Team): string {
let colour = team.primary;
for (let i = 0; i <= 10 && contrast(colour, PAGE) < 4.5; i++) {
colour = mixWithWhite(team.primary, i / 10);
}
return colour;
}
/** Black or white on the nation's colour, whichever a person can actually read. */
export function teamInk(team: Team): string {
return contrast("#ffffff", team.primary) >= contrast("#0a0a0a", team.primary)
? "#ffffff"
: "#0a0a0a";
}