Skip to content

Commit 3ad6480

Browse files
authored
Merge pull request #14160 from guardian/football-nav-atom-for-euros
Football nav atom for women's euros 2025
2 parents 5192303 + b85536a commit 3ad6480

15 files changed

+204
-78
lines changed

dotcom-rendering/fixtures/manual/footballData.ts

Lines changed: 7 additions & 0 deletions
Large diffs are not rendered by default.

dotcom-rendering/src/components/FootballMatchesPage.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
until,
77
} from '@guardian/source/foundations';
88
import type { FootballMatches } from '../footballMatches';
9+
import type { FootballNavAtom as FootballNavAtomModel } from '../footballNavAtom';
910
import { grid } from '../grid';
1011
import type { EditionId } from '../lib/edition';
1112
import type { Result } from '../lib/result';
@@ -14,6 +15,7 @@ import type { FootballMatchListPageKind, Region } from '../sportDataPage';
1415
import { AdSlot } from './AdSlot.web';
1516
import { FootballCompetitionSelect } from './FootballCompetitionSelect';
1617
import { FootballMatchList } from './FootballMatchList';
18+
import { FootballNavAtom } from './FootballNavAtom';
1719

1820
type Props = {
1921
regions: Region[];
@@ -27,6 +29,7 @@ type Props = {
2729
renderAds: boolean;
2830
pageId: string;
2931
now: string;
32+
navAtom?: FootballNavAtomModel;
3033
};
3134

3235
const createTitle = (kind: FootballMatchListPageKind, edition: EditionId) => {
@@ -56,6 +59,7 @@ export const FootballMatchesPage = ({
5659
getMoreDays,
5760
renderAds,
5861
pageId,
62+
navAtom,
5963
}: Props) => (
6064
<main
6165
id="maincontent"
@@ -81,12 +85,13 @@ export const FootballMatchesPage = ({
8185
padding-bottom: ${space[9]}px;
8286
`}
8387
>
88+
<FootballNavAtom navAtom={navAtom} />
8489
<h1
8590
css={css`
8691
${headlineBold20}
8792
padding: ${space[2]}px 0 ${space[3]}px;
8893
${grid.column.centre}
89-
grid-row: 1;
94+
grid-row: ${navAtom !== undefined ? 2 : 1};
9095
${from.leftCol} {
9196
${grid.between('left-column-start', 'centre-column-end')}
9297
}
@@ -100,7 +105,7 @@ export const FootballMatchesPage = ({
100105
margin-top: ${space[3]}px;
101106
margin-bottom: ${space[6]}px;
102107
${grid.column.centre}
103-
grid-row: 2;
108+
grid-row: ${navAtom !== undefined ? 3 : 2};
104109
`}
105110
>
106111
<FootballCompetitionSelect
@@ -114,7 +119,7 @@ export const FootballMatchesPage = ({
114119
<div
115120
css={css`
116121
${grid.column.centre}
117-
grid-row: 3;
122+
grid-row: ${navAtom !== undefined ? 4 : 3};
118123
${from.leftCol} {
119124
${grid.between('left-column-start', 'centre-column-end')}
120125
}
@@ -137,6 +142,7 @@ export const FootballMatchesPage = ({
137142
${grid.column.right}
138143
/** This allows the ad to grow beyond the third row content (up to line 5) */
139144
grid-row: 1 / 5;
145+
grid-row: ${navAtom !== undefined ? '2 / 6' : '1 / 5'};
140146
${until.desktop} {
141147
display: none;
142148
}

dotcom-rendering/src/components/FootballMatchesPageWrapper.importable.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
getParserErrorMessage,
77
parse,
88
} from '../footballMatches';
9+
import type { FootballNavAtom as FootballNavAtomModel } from '../footballNavAtom';
910
import type { FEFootballMatchListPage } from '../frontend/feFootballMatchListPage';
1011
import type { EditionId } from '../lib/edition';
1112
import type { Result } from '../lib/result';
@@ -72,6 +73,7 @@ type Props = {
7273
edition: EditionId;
7374
renderAds: boolean;
7475
pageId: string;
76+
navAtom?: FootballNavAtomModel;
7577
};
7678

7779
export const FootballMatchesPageWrapper = ({
@@ -86,6 +88,7 @@ export const FootballMatchesPageWrapper = ({
8688
edition,
8789
renderAds,
8890
pageId,
91+
navAtom,
8992
}: Props) => {
9093
const [nextPage, setNextPage] = useState(secondPage);
9194

@@ -108,6 +111,7 @@ export const FootballMatchesPageWrapper = ({
108111
}
109112
renderAds={renderAds}
110113
pageId={pageId}
114+
navAtom={navAtom}
111115
/>
112116
);
113117
};
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { css } from '@emotion/react';
2+
import type { FootballNavAtom as FootballNavAtomModel } from '../footballNavAtom';
3+
import { grid } from '../grid';
4+
import { unifyPageContent } from '../lib/unifyPageContent';
5+
6+
export const FootballNavAtom = ({
7+
navAtom,
8+
}: {
9+
navAtom: FootballNavAtomModel | undefined;
10+
}) =>
11+
navAtom !== undefined ? (
12+
<iframe
13+
title="Navigation for the current football competition"
14+
css={{
15+
width: '100%',
16+
// ['&'] part refers to the current element being styled.
17+
// It allows to mix stringified styles (like CSS selectors) with object styles
18+
['&']: css(grid.column.all),
19+
gridRow: 1,
20+
}}
21+
srcDoc={unifyPageContent({
22+
elementCss:
23+
navAtom.css +
24+
'body { margin: 0; } .Sports-header { margin-left: 0 !important; border: none !important; }',
25+
elementJs: navAtom.mainJS,
26+
elementHtml: navAtom.html,
27+
renderingTarget: 'Web',
28+
})}
29+
sandbox="allow-scripts"
30+
/>
31+
) : null;

dotcom-rendering/src/components/FootballTablesPage.stories.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Meta, StoryObj } from '@storybook/react/*';
2-
import { regions } from '../../fixtures/manual/footballData';
2+
import { euro2025Atom, regions } from '../../fixtures/manual/footballData';
33
import { FootballTableList as TableListDefault } from './FootballTableList.stories';
44
import { FootballTablesPage as FootballTablesPageComponent } from './FootballTablesPage';
55

@@ -21,3 +21,10 @@ export const FootballTablesPage = {
2121
guardianBaseUrl: 'https://www.theguardian.com',
2222
},
2323
} satisfies Story;
24+
25+
export const FootballTablesPageWithAtom = {
26+
args: {
27+
...FootballTablesPage.args,
28+
navAtom: euro2025Atom,
29+
},
30+
} satisfies Story;
Lines changed: 89 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import { css } from '@emotion/react';
2+
import { isUndefined } from '@guardian/libs';
23
import {
34
from,
45
headlineBold20,
56
space,
67
until,
78
} from '@guardian/source/foundations';
9+
import type { FootballNavAtom as FootballNavAtomModel } from '../footballNavAtom';
810
import type { FootballTableCompetition } from '../footballTables';
911
import { grid } from '../grid';
1012
import { palette } from '../palette';
1113
import type { Region } from '../sportDataPage';
1214
import { AdSlot } from './AdSlot.web';
15+
import { FootballNavAtom } from './FootballNavAtom';
1316
import { FootballTableList } from './FootballTableList';
1417
import { FootballTablesCompetitionSelect } from './FootballTablesCompetitionSelect.importable';
1518
import { Island } from './Island';
@@ -20,6 +23,7 @@ type Props = {
2023
tableCompetitions: FootballTableCompetition[];
2124
renderAds: boolean;
2225
guardianBaseUrl: string;
26+
navAtom?: FootballNavAtomModel;
2327
};
2428

2529
export const FootballTablesPage = ({
@@ -28,88 +32,99 @@ export const FootballTablesPage = ({
2832
tableCompetitions: competitions,
2933
renderAds,
3034
guardianBaseUrl,
31-
}: Props) => (
32-
<main
33-
id="maincontent"
34-
data-layout="FootballDataPageLayout"
35-
css={css`
36-
${grid.paddedContainer}
37-
position: relative;
38-
${from.tablet} {
39-
&::before,
40-
&::after {
41-
content: '';
42-
position: absolute;
43-
border-left: 1px solid ${palette('--article-border')};
44-
top: 0;
45-
bottom: 0;
46-
}
35+
navAtom,
36+
}: Props) => {
37+
const navAtomIsDefined = !isUndefined(navAtom);
38+
return (
39+
<main
40+
id="maincontent"
41+
data-layout="FootballDataPageLayout"
42+
css={css`
43+
${grid.paddedContainer}
44+
position: relative;
45+
${from.tablet} {
46+
&::before,
47+
&::after {
48+
content: '';
49+
position: absolute;
50+
border-left: 1px solid ${palette('--article-border')};
51+
top: 0;
52+
bottom: 0;
53+
}
4754
48-
&::after {
49-
right: 0;
55+
&::after {
56+
right: 0;
57+
}
5058
}
51-
}
5259
53-
padding-bottom: ${space[9]}px;
54-
`}
55-
>
56-
<h1
57-
css={css`
58-
${headlineBold20}
59-
padding: ${space[2]}px 0 ${space[3]}px;
60-
${grid.column.centre}
61-
grid-row: 1;
62-
${from.leftCol} {
63-
${grid.between('left-column-start', 'centre-column-end')}
64-
}
60+
padding-bottom: ${space[9]}px;
6561
`}
6662
>
67-
Football tables
68-
</h1>
69-
<div
70-
css={css`
71-
margin-top: ${space[3]}px;
72-
margin-bottom: ${space[6]}px;
73-
${grid.column.centre}
74-
grid-row: 2;
75-
`}
76-
>
77-
<Island priority="feature" defer={{ until: 'visible' }}>
78-
<FootballTablesCompetitionSelect
79-
regions={regions}
80-
pageId={pageId}
81-
guardianBaseUrl={guardianBaseUrl}
82-
/>
83-
</Island>
84-
</div>
85-
<div
86-
css={css`
87-
${grid.column.centre}
88-
grid-row: 3;
89-
${from.leftCol} {
90-
${grid.between('left-column-start', 'centre-column-end')}
91-
}
92-
position: relative;
93-
`}
94-
>
95-
<FootballTableList
96-
competitions={competitions}
97-
guardianBaseUrl={guardianBaseUrl}
98-
/>
99-
</div>
100-
{renderAds && (
63+
<FootballNavAtom navAtom={navAtom} />
64+
<h1
65+
css={css`
66+
${headlineBold20}
67+
padding: ${space[2]}px 0 ${space[3]}px;
68+
${grid.column.centre}
69+
grid-row: ${navAtomIsDefined ? 2 : 1};
70+
${from.leftCol} {
71+
${grid.between(
72+
'left-column-start',
73+
'centre-column-end',
74+
)}
75+
}
76+
`}
77+
>
78+
Football tables
79+
</h1>
80+
<div
81+
css={css`
82+
margin-top: ${space[3]}px;
83+
margin-bottom: ${space[6]}px;
84+
${grid.column.centre}
85+
grid-row: ${navAtomIsDefined ? 3 : 2};
86+
`}
87+
>
88+
<Island priority="feature" defer={{ until: 'visible' }}>
89+
<FootballTablesCompetitionSelect
90+
regions={regions}
91+
pageId={pageId}
92+
guardianBaseUrl={guardianBaseUrl}
93+
/>
94+
</Island>
95+
</div>
10196
<div
10297
css={css`
103-
${grid.column.right}
104-
/** This allows the ad to grow beyond the third row content (up to line 5) */
105-
grid-row: 1 / 4;
106-
${until.desktop} {
107-
display: none;
98+
${grid.column.centre}
99+
grid-row: ${navAtomIsDefined ? 4 : 3};
100+
${from.leftCol} {
101+
${grid.between(
102+
'left-column-start',
103+
'centre-column-end',
104+
)}
108105
}
106+
position: relative;
109107
`}
110108
>
111-
<AdSlot position="football-right" />
109+
<FootballTableList
110+
competitions={competitions}
111+
guardianBaseUrl={guardianBaseUrl}
112+
/>
112113
</div>
113-
)}
114-
</main>
115-
);
114+
{renderAds && (
115+
<div
116+
css={css`
117+
${grid.column.right}
118+
/** This allows the ad to grow beyond the third row content (up to line 5) */
119+
grid-row: ${navAtomIsDefined ? '2 / 5' : '1 / 4'};
120+
${until.desktop} {
121+
display: none;
122+
}
123+
`}
124+
>
125+
<AdSlot position="football-right" />
126+
</div>
127+
)}
128+
</main>
129+
);
130+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import type { FEFootballNavAtom } from './frontend/feFootballNavAtom';
2+
3+
export type FootballNavAtom = FEFootballNavAtom;

dotcom-rendering/src/frontend/feFootballMatchListPage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
FEFootballDataPage,
55
FERound,
66
} from './feFootballDataPage';
7+
import type { FEFootballNavAtom } from './feFootballNavAtom';
78

89
type FEStage = {
910
stageNumber: string;
@@ -95,4 +96,5 @@ export type FEFootballMatchListPage = FEFootballDataPage & {
9596
nextPage?: string;
9697
nextPageNoJs?: string;
9798
previousPage?: string;
99+
atom?: FEFootballNavAtom;
98100
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export type FEFootballNavAtom = {
2+
html: string;
3+
css: string;
4+
mainJS: string;
5+
};

dotcom-rendering/src/frontend/feFootballTablesPage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
FEFootballDataPage,
55
FERound,
66
} from './feFootballDataPage';
7+
import type { FEFootballNavAtom } from './feFootballNavAtom';
78

89
type FELeagueStats = {
910
played: number;
@@ -64,4 +65,5 @@ export type FEFootballTable = {
6465
export type FEFootballTablesPage = FEFootballDataPage & {
6566
filters: Record<string, FEFootballCompetition[]>;
6667
tables: FEFootballTable[];
68+
atom?: FEFootballNavAtom;
6769
};

0 commit comments

Comments
 (0)