From 4424336e49160917fb75477a7ee74c3752049d8a Mon Sep 17 00:00:00 2001 From: DanielCliftonGuardian <110032454+DanielCliftonGuardian@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:23:21 +0100 Subject: [PATCH 01/16] World cup 2026 Nav --- .../components/DirectoryPageNav.stories.tsx | 12 +++++++ .../src/components/DirectoryPageNav.tsx | 32 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/dotcom-rendering/src/components/DirectoryPageNav.stories.tsx b/dotcom-rendering/src/components/DirectoryPageNav.stories.tsx index 74e0f21aedf..02c208cf193 100644 --- a/dotcom-rendering/src/components/DirectoryPageNav.stories.tsx +++ b/dotcom-rendering/src/components/DirectoryPageNav.stories.tsx @@ -22,6 +22,18 @@ export const WomensEuro2025 = meta.story({ }, }); +export const WorldCup2026 = meta.story({ + args: { + pageId: 'football/world-cup-2026', + }, +}); + +export const WorldCup2026Fixtures = meta.story({ + args: { + pageId: 'football/world-cup-2026/fixtures', + }, +}); + export const OtherCompetition = meta.story({ args: { pageId: 'football/premierleague/table', diff --git a/dotcom-rendering/src/components/DirectoryPageNav.tsx b/dotcom-rendering/src/components/DirectoryPageNav.tsx index f2304e76043..f505971d0c6 100644 --- a/dotcom-rendering/src/components/DirectoryPageNav.tsx +++ b/dotcom-rendering/src/components/DirectoryPageNav.tsx @@ -37,6 +37,38 @@ interface DirectoryPageNavConfig { } const configs = [ + // World Cup 2026 + { + pageIds: [ + 'football/world-cup-2026', + 'football/world-cup-2026/fixtures', + 'football/world-cup-2026/overview', + ], + tagIds: ['football/world-cup-2026'], + textColor: palette.neutral[100], + backgroundColor: palette.sport[400], + title: { + label: 'World Cup 2026', + id: 'football/world-cup-2026', + }, + links: [ + { + label: 'Fixtures', + id: 'football/world-cup-2026/fixtures', + }, + { + label: 'Tables', + id: 'football/world-cup-2026/overview', + }, + // TODO: add golden boot link once interactive page ID is known + // TODO: add team guide link once interactive page ID is known + { + label: 'Full coverage', + id: 'football/world-cup-2026', + }, + ], + // TODO: add backgroundImages once assets are available + }, // Winter Olympics 2026 { pageIds: [ From f65260e3946de0ec210646b4d67a2b0384a5e05e Mon Sep 17 00:00:00 2001 From: DanielCliftonGuardian <110032454+DanielCliftonGuardian@users.noreply.github.com> Date: Wed, 6 May 2026 16:18:08 +0100 Subject: [PATCH 02/16] Add links, update title and background colour --- .../src/components/DirectoryPageNav.tsx | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/dotcom-rendering/src/components/DirectoryPageNav.tsx b/dotcom-rendering/src/components/DirectoryPageNav.tsx index f505971d0c6..6ad181d7262 100644 --- a/dotcom-rendering/src/components/DirectoryPageNav.tsx +++ b/dotcom-rendering/src/components/DirectoryPageNav.tsx @@ -46,28 +46,43 @@ const configs = [ ], tagIds: ['football/world-cup-2026'], textColor: palette.neutral[100], - backgroundColor: palette.sport[400], + backgroundColor: palette.brand[400], title: { - label: 'World Cup 2026', + label: 'World Cup', id: 'football/world-cup-2026', }, links: [ { - label: 'Fixtures', - id: 'football/world-cup-2026/fixtures', + label: 'Match centre', + id: 'football/world-cup-2026/overview', }, { - label: 'Tables', - id: 'football/world-cup-2026/overview', + label: 'Player guide', + id: '', }, - // TODO: add golden boot link once interactive page ID is known - // TODO: add team guide link once interactive page ID is known { - label: 'Full coverage', - id: 'football/world-cup-2026', + label: 'Bracketology', + id: '', + }, + { + label: 'Golden boot', + id: '', + }, + { + label: 'More football', + id: 'football', }, ], - // TODO: add backgroundImages once assets are available + // backgroundImages: { + // mobile: '', + // mobileLandscape: + // '', + // phablet: + // '', + // tablet: '', + // desktop: + // '', + // }, }, // Winter Olympics 2026 { From aeb8670f4df485b72d6f76c62035c2edc9c1b64d Mon Sep 17 00:00:00 2001 From: DanielCliftonGuardian <110032454+DanielCliftonGuardian@users.noreply.github.com> Date: Fri, 15 May 2026 16:36:11 +0100 Subject: [PATCH 03/16] Remove subnav above header --- dotcom-rendering/src/components/DirectoryPageNav.tsx | 2 +- dotcom-rendering/src/layouts/FrontLayout.tsx | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/dotcom-rendering/src/components/DirectoryPageNav.tsx b/dotcom-rendering/src/components/DirectoryPageNav.tsx index 6ad181d7262..3082ad67659 100644 --- a/dotcom-rendering/src/components/DirectoryPageNav.tsx +++ b/dotcom-rendering/src/components/DirectoryPageNav.tsx @@ -44,7 +44,7 @@ const configs = [ 'football/world-cup-2026/fixtures', 'football/world-cup-2026/overview', ], - tagIds: ['football/world-cup-2026'], + tagIds: [], textColor: palette.neutral[100], backgroundColor: palette.brand[400], title: { diff --git a/dotcom-rendering/src/layouts/FrontLayout.tsx b/dotcom-rendering/src/layouts/FrontLayout.tsx index 8ebbbcaed45..2f22162efbe 100644 --- a/dotcom-rendering/src/layouts/FrontLayout.tsx +++ b/dotcom-rendering/src/layouts/FrontLayout.tsx @@ -122,6 +122,12 @@ export const FrontLayout = ({ front, NAV }: Props) => { const hasPageSkin = renderAds && hasPageSkinConfig; + const isWorldCup2026 = [ + 'football/world-cup-2026', + 'football/world-cup-2026/fixtures', + 'football/world-cup-2026/overview', + ].includes(pageId); + const filteredCollections = front.pressedPage.collections.filter( (collection) => !isHighlights(collection), ); @@ -227,7 +233,7 @@ export const FrontLayout = ({ front, NAV }: Props) => { discussionApiUrl={front.config.discussionApiUrl} contributionsServiceUrl={contributionsServiceUrl} idApiUrl={front.config.idApiUrl} - showSubNav={!isPaidContent} + showSubNav={!isPaidContent && !isWorldCup2026} showSlimNav={false} hasPageSkin={hasPageSkin} hasPageSkinContentSelfConstrain={true} From 9371ea1b7e0d8fe449fd6d31ab65ac725e3891f7 Mon Sep 17 00:00:00 2001 From: DanielCliftonGuardian <110032454+DanielCliftonGuardian@users.noreply.github.com> Date: Fri, 15 May 2026 16:45:15 +0100 Subject: [PATCH 04/16] Remove subnav for world cup 2026 fixtures page --- dotcom-rendering/src/layouts/SportDataPageLayout.tsx | 9 ++++++++- dotcom-rendering/src/layouts/TagPageLayout.tsx | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/dotcom-rendering/src/layouts/SportDataPageLayout.tsx b/dotcom-rendering/src/layouts/SportDataPageLayout.tsx index 90f7ddfbe06..c296ca55dec 100644 --- a/dotcom-rendering/src/layouts/SportDataPageLayout.tsx +++ b/dotcom-rendering/src/layouts/SportDataPageLayout.tsx @@ -2,6 +2,7 @@ import { palette } from '@guardian/source/foundations'; import { AdSlot } from '../components/AdSlot.web'; import { AppsFooter } from '../components/AppsFooter.island'; import { CricketScorecardPage } from '../components/CricketScorecardPage'; +import { DirectoryPageNav } from '../components/DirectoryPageNav'; import { FootballMatchesPageWrapper } from '../components/FootballMatchesPageWrapper.island'; import { FootballMatchInfoPage } from '../components/FootballMatchInfoPage'; import { FootballTablesPage } from '../components/FootballTablesPage'; @@ -100,6 +101,12 @@ export const SportDataPageLayout = ( const contributionsServiceUrl = getContributionsServiceUrl(sportData); + const isWorldCup2026 = [ + 'football/world-cup-2026', + 'football/world-cup-2026/fixtures', + 'football/world-cup-2026/overview', + ].includes(sportData.config.pageId); + return ( <> {isWeb && ( @@ -126,7 +133,7 @@ export const SportDataPageLayout = ( discussionApiUrl={sportData.config.discussionApiUrl} idApiUrl={sportData.config.idApiUrl} contributionsServiceUrl={contributionsServiceUrl} - showSubNav={true} + showSubNav={!isWorldCup2026} showSlimNav={false} hasPageSkin={sportData.config.hasPageSkin} pageId={sportData.config.pageId} diff --git a/dotcom-rendering/src/layouts/TagPageLayout.tsx b/dotcom-rendering/src/layouts/TagPageLayout.tsx index d67a815a0c2..ab67cb6ded5 100644 --- a/dotcom-rendering/src/layouts/TagPageLayout.tsx +++ b/dotcom-rendering/src/layouts/TagPageLayout.tsx @@ -66,6 +66,12 @@ export const TagPageLayout = ({ tagPage, NAV }: Props) => { const isAccessibilityPage = tagPage.config.pageId === 'help/accessibility-help'; + const isWorldCup2026 = [ + 'football/world-cup-2026', + 'football/world-cup-2026/fixtures', + 'football/world-cup-2026/overview', + ].includes(pageId); + return ( <>
@@ -91,7 +97,7 @@ export const TagPageLayout = ({ tagPage, NAV }: Props) => { discussionApiUrl={tagPage.config.discussionApiUrl} idApiUrl={tagPage.config.idApiUrl} contributionsServiceUrl={contributionsServiceUrl} - showSubNav={true} + showSubNav={!isWorldCup2026} showSlimNav={false} hasPageSkin={hasPageSkin} pageId={pageId} From 20ccc93643389c415e5546a111d5ce872cbead63 Mon Sep 17 00:00:00 2001 From: DanielCliftonGuardian <110032454+DanielCliftonGuardian@users.noreply.github.com> Date: Fri, 15 May 2026 16:46:29 +0100 Subject: [PATCH 05/16] Update SportDataPageLayout.tsx --- dotcom-rendering/src/layouts/SportDataPageLayout.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dotcom-rendering/src/layouts/SportDataPageLayout.tsx b/dotcom-rendering/src/layouts/SportDataPageLayout.tsx index c296ca55dec..17ca51b8c8f 100644 --- a/dotcom-rendering/src/layouts/SportDataPageLayout.tsx +++ b/dotcom-rendering/src/layouts/SportDataPageLayout.tsx @@ -145,6 +145,8 @@ export const SportDataPageLayout = ( {isWeb && renderAds && hasSurveyAd && } + {isWeb && } + Date: Fri, 15 May 2026 16:52:02 +0100 Subject: [PATCH 06/16] Update SportDataPageLayout.tsx --- dotcom-rendering/src/layouts/SportDataPageLayout.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/dotcom-rendering/src/layouts/SportDataPageLayout.tsx b/dotcom-rendering/src/layouts/SportDataPageLayout.tsx index 17ca51b8c8f..c84d26050f6 100644 --- a/dotcom-rendering/src/layouts/SportDataPageLayout.tsx +++ b/dotcom-rendering/src/layouts/SportDataPageLayout.tsx @@ -2,7 +2,6 @@ import { palette } from '@guardian/source/foundations'; import { AdSlot } from '../components/AdSlot.web'; import { AppsFooter } from '../components/AppsFooter.island'; import { CricketScorecardPage } from '../components/CricketScorecardPage'; -import { DirectoryPageNav } from '../components/DirectoryPageNav'; import { FootballMatchesPageWrapper } from '../components/FootballMatchesPageWrapper.island'; import { FootballMatchInfoPage } from '../components/FootballMatchInfoPage'; import { FootballTablesPage } from '../components/FootballTablesPage'; @@ -145,8 +144,6 @@ export const SportDataPageLayout = ( {isWeb && renderAds && hasSurveyAd && } - {isWeb && } - Date: Mon, 18 May 2026 09:21:13 +0100 Subject: [PATCH 07/16] Hf/tweak world cup nav (#15886) * update style to match new design and add image assets * add wide images to old headers * fix nav style and add mobLandscape and phablet image * remove unused --- .../src/components/DirectoryPageNav.tsx | 161 ++++++++++-------- 1 file changed, 90 insertions(+), 71 deletions(-) diff --git a/dotcom-rendering/src/components/DirectoryPageNav.tsx b/dotcom-rendering/src/components/DirectoryPageNav.tsx index 3082ad67659..88e4a55b270 100644 --- a/dotcom-rendering/src/components/DirectoryPageNav.tsx +++ b/dotcom-rendering/src/components/DirectoryPageNav.tsx @@ -3,13 +3,10 @@ import { type Breakpoint, breakpoints, from, - headlineBold15Object, - headlineBold17Object, headlineBold24Object, headlineBold42Object, - headlineMedium15Object, - headlineMedium17Object, palette, + textSans14Object, } from '@guardian/source/foundations'; import { grid } from '../grid'; import { generateImageURL } from '../lib/image'; @@ -25,6 +22,7 @@ interface DirectoryPageNavConfig { tagIds: string[]; textColor: string; backgroundColor: string; + titleIconImage: string; title: { label: string; id: string }; links: { label: string; id: string }[]; backgroundImages?: { @@ -33,6 +31,7 @@ interface DirectoryPageNavConfig { phablet: string; tablet: string; desktop: string; + wide: string; }; } @@ -51,6 +50,8 @@ const configs = [ label: 'World Cup', id: 'football/world-cup-2026', }, + titleIconImage: + 'data:image/svg+xml,%3Csvg%20width%3D%2240%22%20height%3D%2246%22%20viewBox%3D%220%200%2040%2046%22%20fill%3D%22none%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Crect%20width%3D%2212.3697%22%20height%3D%2232.4706%22%20fill%3D%22%23D71921%22/%3E%3Crect%20x%3D%2213.5294%22%20y%3D%2213.5295%22%20width%3D%2212.3697%22%20height%3D%2232.4706%22%20fill%3D%22white%22/%3E%3Crect%20x%3D%2227.059%22%20width%3D%2212.3697%22%20height%3D%2232.4706%22%20fill%3D%22%23007E46%22/%3E%3Ccircle%20cx%3D%2219.7142%22%20cy%3D%226.18487%22%20r%3D%226.18487%22%20fill%3D%22white%22/%3E%3C/svg%3E', links: [ { label: 'Match centre', @@ -73,16 +74,17 @@ const configs = [ id: 'football', }, ], - // backgroundImages: { - // mobile: '', - // mobileLandscape: - // '', - // phablet: - // '', - // tablet: '', - // desktop: - // '', - // }, + backgroundImages: { + mobile: 'https://media.guim.co.uk/4ba0caac6d18c1fe6a5a3267b270d8c21ae6f940/0_0_750_376/750.jpg', + mobileLandscape: + 'https://media.guim.co.uk/8e1356cc926c6bbfcdb3da5908252ba0b4cbd3bb/0_0_960_376/960.jpg', + phablet: + 'https://media.guim.co.uk/ed4fe540c6a114db35c1f73fc41ee802c3fea7d3/0_0_1320_282/1320.jpg', + tablet: 'https://media.guim.co.uk/861646115875f3f246313036f754b2f5f1480b1a/0_0_1480_276/1480.jpg', + desktop: + 'https://media.guim.co.uk/167bec4a208bfc7fdc6b2127186b9bb183932259/0_0_1960_276/1960.jpg', + wide: 'https://media.guim.co.uk/4e44f9a88fcc9a3b1b5294f7e581644baa75c904/0_0_2600_276/2600.jpg', + }, }, // Winter Olympics 2026 { @@ -99,6 +101,7 @@ const configs = [ label: 'Winter Olympics 2026', id: 'sport/winter-olympics-2026', }, + titleIconImage: '', links: [ { label: 'Schedule', @@ -126,6 +129,7 @@ const configs = [ tablet: 'https://uploads.guim.co.uk/2026/02/03/winter-olympics-740px-thin.jpg', desktop: 'https://uploads.guim.co.uk/2026/02/03/winter-olympics-980px.jpg', + wide: 'https://uploads.guim.co.uk/2026/02/03/winter-olympics-980px.jpg', }, }, // Winter Paralympics 2026 @@ -142,6 +146,7 @@ const configs = [ label: 'Winter Paralympics 2026', id: 'sport/winter-paralympics-2026', }, + titleIconImage: '', links: [ { label: 'Results', @@ -165,6 +170,7 @@ const configs = [ tablet: 'https://uploads.guim.co.uk/2026/03/03/winter-paralympics-740px-thin.jpg', desktop: 'https://uploads.guim.co.uk/2026/03/03/winter-paralympics-980px.jpg', + wide: 'https://uploads.guim.co.uk/2026/03/03/winter-paralympics-980px.jpg', }, }, ] satisfies DirectoryPageNavConfig[]; @@ -188,14 +194,20 @@ export const DirectoryPageNav = ({ pageId, pageTags }: Props) => { backgroundColor, '&': css(grid.paddedContainer), alignContent: 'space-between', + position: 'relative', }); const largeLinkStyles = css({ + position: 'absolute', + top: '4px', + left: 0, ...headlineBold24Object, color: textColor, textDecoration: 'none', '&': css(grid.column.centre), gridRow: 1, + display: 'flex', + alignItems: 'flex-start', [from.tablet]: headlineBold42Object, [from.leftCol]: css( grid.between('left-column-start', 'right-column-end'), @@ -204,35 +216,38 @@ export const DirectoryPageNav = ({ pageId, pageTags }: Props) => { const list = css({ display: 'flex', - flexWrap: 'wrap', '&': css(grid.column.all), - gridRow: 2, alignSelf: 'end', position: 'relative', '--top-border-gap': '1.55rem', + overflowX: 'scroll', + scrollbarWidth: 'none', + padding: '10px 10px', + borderTop: '1px solid', + borderColor: palette.brand[600], + height: '100%', [from.mobileLandscape]: { - paddingLeft: 10, + padding: '10px 20px', }, [from.tablet]: { '--top-border-gap': '3rem', }, - backgroundImage: ` - linear-gradient( - ${textColor} 0, - ${textColor} 1px, - transparent 1px, - transparent var(--top-border-gap), - ${textColor} var(--top-border-gap), - ${textColor} calc(var(--top-border-gap) + 1px), - transparent 1px, - transparent var(--top-border-gap) - ) - `, + '&:after': { + content: '""', + position: 'sticky', + right: '-10px', + top: '-10px', + height: '100%', + minWidth: 40, + background: `linear-gradient(to left, ${backgroundColor}, transparent)`, + [from.mobileLandscape]: { + right: '-20px', + }, + }, }); const selectedStyles = { - '--selected-height': '4px', - '--selected-opacity': '1', + fontWeight: 'bold', }; const listItem = css({ @@ -249,62 +264,40 @@ export const DirectoryPageNav = ({ pageId, pageTags }: Props) => { backgroundColor: textColor, transition: 'height 0.3s ease-in-out, opacity 0.05s 0.1s linear', }, - '&:hover': selectedStyles, - [from.leftCol]: { - flexBasis: 160, + [from.desktop]: { + '&:hover a': { + textDecoration: 'underline', + color: 'var(--masthead-nav-link-text-hover)', + }, }, }); const smallLink = css({ - ...headlineBold15Object, - padding: '4px 10px 6px', + ...textSans14Object, + padding: '4px 12px 6px 0', display: 'block', lineHeight: 1, color: textColor, textDecoration: 'none', - '&::after': { - content: '""', - display: 'block', - position: 'absolute', - top: 0, - right: 0, - width: 1, - height: '1.3rem', - backgroundColor: textColor, - }, - [from.tablet]: headlineBold17Object, - [from.leftCol]: { - padding: '9px 10px 10px', - }, - }); - - const lastSmallLink = css(smallLink, { - ...headlineMedium15Object, - lineHeight: 1, - [from.tablet]: headlineMedium17Object, + whiteSpace: 'nowrap', }); return (