Skip to content

Commit 65a586a

Browse files
Add crests to football matches (#13594)
* feat: add crests to football results * blank alt for missing crests * add storybook examples with wide name and badge * use max width and height to avoid default img - flex to centre horizontally * fix flex behaviour at mobileMedium --------- Co-authored-by: James Mockett <[email protected]>
1 parent d6ebd4a commit 65a586a

File tree

3 files changed

+164
-26
lines changed

3 files changed

+164
-26
lines changed

dotcom-rendering/fixtures/manual/footballData.ts

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ export const initialDays: FootballMatches = [
3737
paId: '4482093',
3838
homeTeam: {
3939
name: 'Torino',
40+
id: '27038',
4041
score: 10,
4142
},
4243
awayTeam: {
4344
name: 'Cagliari',
45+
id: '26474',
4446
score: 0,
4547
},
4648
status: '1st',
@@ -53,9 +55,11 @@ export const initialDays: FootballMatches = [
5355
paId: '12345',
5456
homeTeam: {
5557
name: 'Fiorentina',
58+
id: '26366',
5659
},
5760
awayTeam: {
5861
name: 'Bologna',
62+
id: '26371',
5963
},
6064
status: 'S',
6165
comment: 'Awaiting officials decision',
@@ -66,8 +70,82 @@ export const initialDays: FootballMatches = [
6670
'2022-01-01T19:45:00Z',
6771
).toISOString(),
6872
paId: '4482890',
69-
homeTeam: 'Auxerre',
70-
awayTeam: 'St Etienne',
73+
homeTeam: {
74+
name: 'Auxerre',
75+
id: '26348',
76+
},
77+
awayTeam: { name: 'St Etienne', id: '27408' },
78+
},
79+
],
80+
},
81+
{
82+
id: '1',
83+
tag: 'football/bundesligafootball',
84+
name: 'Bundesliga',
85+
nation: 'European',
86+
matches: [
87+
{
88+
kind: 'Live',
89+
dateTimeISOString: new Date(
90+
'2022-01-01T11:11:00Z',
91+
).toISOString(),
92+
paId: '123',
93+
homeTeam: {
94+
name: 'Eintracht Frankfurt',
95+
id: '26460',
96+
score: 1,
97+
},
98+
awayTeam: {
99+
name: 'Bayern Munich',
100+
id: '26247',
101+
score: 0,
102+
},
103+
status: '1st',
104+
},
105+
],
106+
},
107+
108+
{
109+
id: '2',
110+
tag: 'football/uefa-europa-league',
111+
name: 'Europa League',
112+
nation: 'European',
113+
matches: [
114+
{
115+
kind: 'Live',
116+
dateTimeISOString: new Date(
117+
'2022-01-01T11:11:00Z',
118+
).toISOString(),
119+
paId: '123',
120+
homeTeam: {
121+
name: 'AZ',
122+
id: '26464',
123+
score: 1,
124+
},
125+
awayTeam: {
126+
name: 'Sevilla',
127+
id: '27821',
128+
score: 2,
129+
},
130+
status: 'HT',
131+
},
132+
{
133+
kind: 'Live',
134+
dateTimeISOString: new Date(
135+
'2022-01-01T11:11:00Z',
136+
).toISOString(),
137+
paId: '1234',
138+
homeTeam: {
139+
name: 'Jagiellonia Białystok',
140+
id: '9999999',
141+
score: 3,
142+
},
143+
awayTeam: {
144+
name: 'Shakhtar Donetsk',
145+
id: '38299',
146+
score: 2,
147+
},
148+
status: 'HT',
71149
},
72150
],
73151
},
@@ -85,10 +163,12 @@ export const initialDays: FootballMatches = [
85163
paId: '4482835',
86164
homeTeam: {
87165
name: 'Las Palmas',
166+
id: '27804',
88167
score: 2,
89168
},
90169
awayTeam: {
91170
name: 'Osasuna',
171+
id: '27152',
92172
score: 3,
93173
},
94174
comment: 'AET',
@@ -109,10 +189,12 @@ export const initialDays: FootballMatches = [
109189
paId: '4482836',
110190
homeTeam: {
111191
name: 'Brighton & Hove Albion Women',
192+
id: '8450',
112193
score: 1,
113194
},
114195
awayTeam: {
115196
name: 'Crystal Palace Women',
197+
id: '48752',
116198
score: 1,
117199
},
118200
comment:
@@ -140,8 +222,8 @@ export const moreDays: FootballMatches = [
140222
'2022-01-05T19:45:00Z',
141223
).toISOString(),
142224
paId: '4482890',
143-
homeTeam: 'Juventus',
144-
awayTeam: 'Roma',
225+
homeTeam: { name: 'Juventus', id: '26359' },
226+
awayTeam: { name: 'Roma', id: '26357' },
145227
},
146228
],
147229
},

dotcom-rendering/src/components/FootballMatchList.tsx

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import type {
1818
FootballMatch,
1919
FootballMatches,
2020
FootballMatchKind,
21+
Team,
2122
} from '../footballMatches';
2223
import {
2324
type EditionId,
@@ -72,6 +73,10 @@ const footballMatchesGridStyles = css`
7273
}
7374
`;
7475

76+
function getFootballCrestImageUrl(teamId: string) {
77+
return `https://sport.guim.co.uk/football/crests/60/${teamId}.png`;
78+
}
79+
7580
const getTimeFormatter = (edition: EditionId): Intl.DateTimeFormat =>
7681
new Intl.DateTimeFormat(getLocaleFromEdition(edition), {
7782
hour: '2-digit',
@@ -141,7 +146,7 @@ const matchStatusStyles = css`
141146
width: 5rem;
142147
color: ${palette('--football-sub-text')};
143148
144-
${until.mobileMedium} {
149+
${until.mobileLandscape} {
145150
flex-basis: 100%;
146151
}
147152
`;
@@ -203,6 +208,7 @@ const matchStyles = (matchKind: FootballMatchKind) => css`
203208
${matchKind === 'Live' ? 'font-weight: bold;' : undefined}
204209
205210
display: flex;
211+
align-items: center;
206212
flex-wrap: wrap;
207213
padding: ${space[2]}px;
208214
`;
@@ -260,28 +266,26 @@ const Match = ({
260266
<MatchStatus match={match} timeFormatter={timeFormatter} />
261267
{match.kind === 'Fixture' ? (
262268
<>
263-
<HomeTeam>{match.homeTeam}</HomeTeam>
264-
269+
<HomeTeam team={match.homeTeam} />
265270
<Versus />
266-
<AwayTeam>{match.awayTeam}</AwayTeam>
271+
<AwayTeam team={match.awayTeam} />
267272
</>
268273
) : (
269274
<>
270-
<HomeTeam>{match.homeTeam.name}</HomeTeam>
271-
275+
<HomeTeam team={match.homeTeam} />
272276
<Scores
273277
homeScore={match.homeTeam.score}
274278
awayScore={match.awayTeam.score}
275279
/>
276-
<AwayTeam>{match.awayTeam.name}</AwayTeam>
280+
<AwayTeam team={match.awayTeam} />
277281
{isUndefined(match.comment) ? null : (
278282
<small
279283
css={css`
280284
color: ${palette('--football-sub-text')};
281285
flex-basis: 100%;
282286
text-align: center;
283287
padding-top: ${space[2]}px;
284-
${from.mobileMedium} {
288+
${from.mobileLandscape} {
285289
padding-left: 5rem;
286290
}
287291
`}
@@ -294,25 +298,63 @@ const Match = ({
294298
</MatchWrapper>
295299
);
296300

297-
const HomeTeam = (props: { children: ReactNode }) => (
298-
<span
299-
{...props}
301+
const FootballCrest = ({ teamId }: { teamId: string }) => (
302+
<div
303+
css={css`
304+
width: 1.25rem;
305+
height: 1.25rem;
306+
flex-shrink: 0;
307+
display: flex;
308+
justify-content: center;
309+
`}
310+
>
311+
<img
312+
css={css`
313+
max-width: 100%;
314+
max-height: 100%;
315+
object-fit: contain;
316+
`}
317+
src={getFootballCrestImageUrl(teamId)}
318+
alt=""
319+
/>
320+
</div>
321+
);
322+
323+
const HomeTeam = ({ team }: { team: Team }) => (
324+
<div
300325
css={css`
301-
text-align: right;
326+
justify-content: flex-end;
302327
flex: 1 0 0;
303328
padding-right: 1rem;
329+
display: flex;
330+
align-items: center;
331+
gap: 0.325rem;
304332
`}
305-
/>
333+
>
334+
<span
335+
css={css`
336+
text-align: right;
337+
`}
338+
>
339+
{team.name}
340+
</span>
341+
<FootballCrest teamId={team.id} />
342+
</div>
306343
);
307344

308-
const AwayTeam = (props: { children: ReactNode }) => (
309-
<span
310-
{...props}
345+
const AwayTeam = ({ team }: { team: Team }) => (
346+
<div
311347
css={css`
312348
flex: 1 0 0;
313349
padding-left: 1rem;
350+
display: flex;
351+
align-items: center;
352+
gap: 0.325rem;
314353
`}
315-
/>
354+
>
355+
<FootballCrest teamId={team.id} />
356+
{team.name}
357+
</div>
316358
);
317359

318360
const Battleline = () => (

dotcom-rendering/src/footballMatches.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ import { error, ok, type Result } from './lib/result';
1313
import type { NavType } from './model/extract-nav';
1414
import type { FooterType } from './types/footer';
1515

16-
export type TeamScore = {
16+
export type Team = {
1717
name: string;
18+
id: string;
19+
};
20+
21+
export type TeamScore = Team & {
1822
score?: number;
1923
};
2024

@@ -32,8 +36,8 @@ export type MatchResult = MatchData & {
3236

3337
export type MatchFixture = MatchData & {
3438
kind: 'Fixture';
35-
homeTeam: string;
36-
awayTeam: string;
39+
homeTeam: Team;
40+
awayTeam: Team;
3741
};
3842

3943
export type LiveMatch = MatchData & {
@@ -205,8 +209,14 @@ const parseFixture = (
205209

206210
return ok({
207211
kind: 'Fixture',
208-
homeTeam: cleanTeamName(feFixture.homeTeam.name),
209-
awayTeam: cleanTeamName(feFixture.awayTeam.name),
212+
homeTeam: {
213+
name: cleanTeamName(feFixture.homeTeam.name),
214+
id: feFixture.homeTeam.id,
215+
},
216+
awayTeam: {
217+
name: cleanTeamName(feFixture.awayTeam.name),
218+
id: feFixture.awayTeam.id,
219+
},
210220
dateTimeISOString: date.value,
211221
paId: feFixture.id,
212222
});
@@ -233,10 +243,12 @@ const parseMatchResult = (
233243
homeTeam: {
234244
name: cleanTeamName(feResult.homeTeam.name),
235245
score: feResult.homeTeam.score,
246+
id: feResult.homeTeam.id,
236247
},
237248
awayTeam: {
238249
name: cleanTeamName(feResult.awayTeam.name),
239250
score: feResult.awayTeam.score,
251+
id: feResult.awayTeam.id,
240252
},
241253
dateTimeISOString: date.value,
242254
paId: feResult.id,
@@ -265,10 +277,12 @@ const parseLiveMatch = (
265277
homeTeam: {
266278
name: cleanTeamName(feMatchDay.homeTeam.name),
267279
score: feMatchDay.homeTeam.score,
280+
id: feMatchDay.homeTeam.id,
268281
},
269282
awayTeam: {
270283
name: cleanTeamName(feMatchDay.awayTeam.name),
271284
score: feMatchDay.awayTeam.score,
285+
id: feMatchDay.awayTeam.id,
272286
},
273287
dateTimeISOString: date.value,
274288
paId: feMatchDay.id,

0 commit comments

Comments
 (0)