-
Notifications
You must be signed in to change notification settings - Fork 30
Football match header tabs #14997
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Football match header tabs #14997
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| import type { Meta, StoryObj } from '@storybook/react-webpack5'; | ||
| import { gridContainerDecorator } from '../../../.storybook/decorators/gridDecorators'; | ||
| import { palette } from '../../palette'; | ||
| import { Tabs } from './Tabs'; | ||
|
|
||
| const meta = { | ||
| component: Tabs, | ||
| } satisfies Meta<typeof Tabs>; | ||
|
|
||
| export default meta; | ||
|
|
||
| type Story = StoryObj<typeof meta>; | ||
|
|
||
| export const MatchInfoWhenFixture = { | ||
| args: { | ||
| selected: 'info', | ||
| }, | ||
| parameters: { | ||
| colourSchemeBackground: { | ||
| light: palette('--football-match-header-fixture-result-background'), | ||
| dark: palette('--football-match-header-fixture-result-background'), | ||
| }, | ||
| }, | ||
| decorators: [gridContainerDecorator], | ||
| } satisfies Story; | ||
|
|
||
| export const LiveWhenLive = { | ||
| ...MatchInfoWhenFixture, | ||
| args: { | ||
| selected: 'live', | ||
| infoURL: new URL( | ||
| 'https://www.theguardian.com/football/match/2025/nov/26/arsenal-v-bayernmunich', | ||
| ), | ||
| }, | ||
| } satisfies Story; | ||
|
|
||
| export const ReportWhenResult = { | ||
| ...MatchInfoWhenFixture, | ||
| args: { | ||
| selected: 'report', | ||
| liveURL: new URL( | ||
| 'https://www.theguardian.com/football/live/2025/nov/26/arsenal-v-bayern-munich-champions-league-live', | ||
| ), | ||
| infoURL: LiveWhenLive.args.infoURL, | ||
| }, | ||
| } satisfies Story; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| import { css } from '@emotion/react'; | ||
| import { | ||
| from, | ||
| headlineBold15Object, | ||
| headlineBold17Object, | ||
| space, | ||
| } from '@guardian/source/foundations'; | ||
| import type { ReactNode } from 'react'; | ||
| import { grid } from '../../grid'; | ||
| import { palette } from '../../palette'; | ||
|
|
||
| type Props = | ||
| | { | ||
| selected: 'info'; | ||
| reportURL?: URL; | ||
| liveURL?: URL; | ||
| } | ||
| | { | ||
| selected: 'live'; | ||
| reportURL?: URL; | ||
| infoURL: URL; | ||
| } | ||
| | { | ||
| selected: 'report'; | ||
| liveURL?: URL; | ||
| infoURL: URL; | ||
| }; | ||
|
|
||
| export const Tabs = (props: Props) => ( | ||
| <nav css={[grid.column.centre]}> | ||
| <ul | ||
| css={{ | ||
| ...headlineBold15Object, | ||
| paddingTop: space[2], | ||
| display: 'flex', | ||
| width: '100%', | ||
| borderBottomWidth: 1, | ||
| borderStyle: 'solid', | ||
| borderColor: palette( | ||
| '--football-match-header-fixture-result-border', | ||
| ), | ||
| [from.leftCol]: headlineBold17Object, | ||
| }} | ||
| > | ||
| <MatchReport {...props} /> | ||
| <LiveFeed {...props} /> | ||
| <MatchInfo {...props} /> | ||
| </ul> | ||
| </nav> | ||
| ); | ||
|
|
||
| const MatchReport = (props: Props) => { | ||
| if (props.selected === 'report') { | ||
| return <Tab>Match report</Tab>; | ||
| } | ||
|
|
||
| if (props.reportURL !== undefined) { | ||
| return <Tab href={props.reportURL}>Match report</Tab>; | ||
| } | ||
|
|
||
| return null; | ||
| }; | ||
|
|
||
| const LiveFeed = (props: Props) => { | ||
| if (props.selected === 'live') { | ||
| return <Tab>Live feed</Tab>; | ||
| } | ||
|
|
||
| if (props.liveURL !== undefined) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same question as above
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there's no live URL (i.e. there is no liveblog or deadblog) it either means the match hasn't started yet, and therefore there is no liveblog yet but there might be in the future, or it has started but no liveblog has been created for it. |
||
| return <Tab href={props.liveURL}>Live feed</Tab>; | ||
| } | ||
|
|
||
| return null; | ||
| }; | ||
|
|
||
| const MatchInfo = (props: Props) => { | ||
| if (props.selected === 'info') { | ||
| return <Tab>Match info</Tab>; | ||
| } | ||
|
|
||
| return <Tab href={props.infoURL}>Match info</Tab>; | ||
| }; | ||
|
|
||
| const Tab = (props: { children: ReactNode; href?: URL }) => ( | ||
| <li | ||
| css={{ | ||
| // Ensures that if there are only two tabs they take up exactly 50% | ||
| flex: '1 1 50%', | ||
| borderLeftStyle: 'solid', | ||
| borderLeftColor: palette( | ||
| '--football-match-header-fixture-result-border', | ||
| ), | ||
| '&:not(:first-of-type)': { | ||
| paddingLeft: space[2], | ||
| borderLeftWidth: 1, | ||
| }, | ||
| [from.leftCol]: { | ||
| paddingLeft: space[2], | ||
| borderLeftWidth: 1, | ||
| flex: '0 0 auto', | ||
| }, | ||
| }} | ||
| > | ||
| <TabText href={props.href}>{props.children}</TabText> | ||
| </li> | ||
| ); | ||
|
|
||
| const TabText = (props: { children: ReactNode; href?: URL }) => { | ||
| if (props.href !== undefined) { | ||
| return ( | ||
| <a href={props.href.toString()} css={tabTextStyles}> | ||
| {props.children} | ||
| </a> | ||
| ); | ||
| } | ||
|
|
||
| return ( | ||
| <span | ||
| css={tabTextStyles} | ||
| style={{ | ||
| borderBottomColor: palette( | ||
| '--football-match-header-fixture-result-selected', | ||
| ), | ||
| }} | ||
| > | ||
| {props.children} | ||
| </span> | ||
| ); | ||
| }; | ||
|
|
||
| const tabTextStyles = css({ | ||
| display: 'block', | ||
| paddingBottom: space[2], | ||
| borderBottomWidth: space[1], | ||
| borderBottomStyle: 'solid', | ||
| borderBottomColor: 'transparent', | ||
| color: palette('--football-match-header-fixture-result-primary-text'), | ||
| textDecoration: 'none', | ||
| '&:hover': { | ||
| borderBottomColor: palette( | ||
| '--football-match-header-fixture-result-selected', | ||
| ), | ||
| }, | ||
| [from.leftCol]: { | ||
| paddingRight: space[6], | ||
| paddingBottom: space[3], | ||
| }, | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which scenario does this cover?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there's no report URL (i.e. there is no match report) it either means the match hasn't finished yet, and therefore there is no report yet but there might be in the future, or it has finished but no report article has been written for it.