Skip to content

Commit 665cc96

Browse files
Merge branch 'main' of https://github.com/guardian/dotcom-rendering into 14890-show-or-hide-the-sign-up-newsletter-component
2 parents 87287b7 + f1c2b54 commit 665cc96

File tree

17 files changed

+705
-23
lines changed

17 files changed

+705
-23
lines changed

ab-testing/config/abTests.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ const ABTests: ABTest[] = [
2424
name: "commercial-prebid-v10",
2525
description: "Testing Prebid.js v10 integration on DCR",
2626
owners: ["[email protected]"],
27-
status: "OFF",
28-
expirationDate: "2025-12-10",
27+
status: "ON",
28+
expirationDate: "2026-01-10",
2929
type: "client",
3030
audienceSize: 10 / 100,
3131
audienceSpace: "A",

dotcom-rendering/docs/development/ab-testing-in-dcr.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,3 +255,20 @@ These links are also in the [frontend admin](https://frontend.gutools.co.uk/anal
255255
- Opt-out on PROD: `https://theguardian.com/ab-tests/opt/out`
256256

257257
You can use the same routes on CODE.
258+
259+
### 6. Forcing yourself into a test locally
260+
261+
Use the opt-in and opt-out URL fragments to force yourself into or out of a test using a query parameter.
262+
263+
When opted-in, the test will override any mvt based assignment and you'll only be in the opted-in test group.
264+
265+
**Opt-in Example**
266+
267+
- Articles: `http://localhost:3030/Article/?ab-commercial-test-example=variant`
268+
- Fronts: `http://localhost:3030/Front/https://www.theguardian.com/international?ab-commercial-test-example=variant`
269+
- Interactives: `http://localhost:3030/Interactive/https://www.theguardian.com/global-development/ng-interactive/2022/jun/09/the-black-sea-blockade-mapping-the-impact-of-war-in-ukraine-on-the-worlds-food-supply-interactive?ab--commercial-test-example=variant`
270+
271+
You can verify that you're in the test by checking:
272+
273+
- Server-side tests: `window.guardian.config.serverSideABTests` in the browser console
274+
- Client-side tests: `window.guardian.modules.abTests.getParticipations()` in the browser console

dotcom-rendering/src/components/Caption.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ export const Caption = ({
315315
]}
316316
data-spacefinder-role="inline"
317317
>
318-
{mediaType === 'YoutubeVideo' ? (
318+
{mediaType === 'YoutubeVideo' || mediaType === 'SelfHostedVideo' ? (
319319
<VideoIcon format={format} />
320320
) : (
321321
<CameraIcon format={format} />
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { css } from '@emotion/react';
2+
import { space } from '@guardian/source/foundations';
3+
import type { Meta, StoryObj } from '@storybook/react-webpack5';
4+
import { palette } from '../palette';
5+
import { FootballMatchStat } from './FootballMatchStat';
6+
7+
const meta = {
8+
title: 'Components/Football Match Stat',
9+
component: FootballMatchStat,
10+
decorators: [
11+
(Story) => (
12+
<div
13+
css={css`
14+
padding: ${space[4]}px;
15+
background-color: ${palette(
16+
'--football-live-blog-background',
17+
)};
18+
`}
19+
>
20+
<Story />
21+
</div>
22+
),
23+
],
24+
parameters: {
25+
viewport: {
26+
defaultViewport: 'mobileMedium',
27+
},
28+
},
29+
} satisfies Meta<typeof FootballMatchStat>;
30+
31+
export default meta;
32+
type Story = StoryObj<typeof meta>;
33+
34+
export const Default = {
35+
args: {
36+
label: 'Goal Attempts',
37+
home: {
38+
teamName: 'Manchester United',
39+
teamColour: '#da020e',
40+
value: 7,
41+
},
42+
away: {
43+
teamName: 'Arsenal',
44+
teamColour: '#023474',
45+
value: 4,
46+
},
47+
},
48+
} satisfies Story;
49+
50+
export const ShownAsPercentage = {
51+
args: {
52+
label: 'Possession',
53+
home: {
54+
teamName: 'West Ham',
55+
teamColour: '#722642',
56+
value: 39,
57+
},
58+
away: {
59+
teamName: 'Newcastle',
60+
teamColour: '#383838',
61+
value: 61,
62+
},
63+
showPercentage: true,
64+
},
65+
} satisfies Story;
66+
67+
export const RaisedLabelOnDesktop = {
68+
args: {
69+
...Default.args,
70+
raiseLabelOnDesktop: true,
71+
},
72+
} satisfies Story;
73+
74+
export const LargeNumbersOnDesktop = {
75+
args: {
76+
...Default.args,
77+
largeNumbersOnDesktop: true,
78+
},
79+
} satisfies Story;
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import { css } from '@emotion/react';
2+
import {
3+
from,
4+
space,
5+
textSansBold14,
6+
textSansBold15,
7+
textSansBold20,
8+
textSansBold28,
9+
visuallyHidden,
10+
} from '@guardian/source/foundations';
11+
import { palette } from '../palette';
12+
13+
const containerCss = css`
14+
position: relative;
15+
padding: 5px 10px 10px;
16+
border: 1px solid ${palette('--football-match-stat-border')};
17+
border-radius: 6px;
18+
&::before {
19+
position: absolute;
20+
content: '';
21+
left: 50%;
22+
bottom: 0;
23+
width: 1px;
24+
height: ${space[6]}px;
25+
background-color: ${palette('--football-match-stat-border')};
26+
}
27+
`;
28+
29+
const headerCss = css`
30+
display: grid;
31+
grid-template-columns: auto 1fr auto;
32+
grid-template-areas: 'home-stat label away-stat';
33+
`;
34+
35+
const raiseLabelCss = css`
36+
${from.desktop} {
37+
grid-template-areas:
38+
'label label label'
39+
'home-stat . away-stat';
40+
}
41+
`;
42+
43+
const labelCss = css`
44+
${textSansBold14};
45+
grid-area: label;
46+
justify-self: center;
47+
color: ${palette('--football-match-stat-name')};
48+
${from.desktop} {
49+
${textSansBold15};
50+
}
51+
`;
52+
53+
const numberCss = css`
54+
${textSansBold20};
55+
grid-area: home-stat;
56+
color: var(--match-stat-team-colour);
57+
`;
58+
59+
const largeNumberCss = css`
60+
${from.desktop} {
61+
${textSansBold28}
62+
}
63+
`;
64+
65+
const awayStatCss = css`
66+
grid-area: away-stat;
67+
justify-self: end;
68+
`;
69+
70+
const chartCss = css`
71+
position: relative;
72+
display: flex;
73+
gap: 10px;
74+
`;
75+
76+
const barCss = css`
77+
height: ${space[2]}px;
78+
width: var(--match-stat-percentage);
79+
background-color: var(--match-stat-team-colour);
80+
border-radius: 8px;
81+
`;
82+
83+
type MatchStatistic = {
84+
teamName: string;
85+
teamColour: string;
86+
value: number;
87+
};
88+
89+
type Props = {
90+
label: string;
91+
home: MatchStatistic;
92+
away: MatchStatistic;
93+
showPercentage?: boolean;
94+
raiseLabelOnDesktop?: boolean;
95+
largeNumbersOnDesktop?: boolean;
96+
};
97+
98+
const formatValue = (value: number, showPercentage: boolean) =>
99+
`${value}${showPercentage ? '%' : ''}`;
100+
101+
export const FootballMatchStat = ({
102+
label,
103+
home,
104+
away,
105+
showPercentage = false,
106+
raiseLabelOnDesktop = false,
107+
largeNumbersOnDesktop = false,
108+
}: Props) => {
109+
const homePercentage = (home.value / (home.value + away.value)) * 100;
110+
const awayPercentage = (away.value / (home.value + away.value)) * 100;
111+
112+
return (
113+
<div css={containerCss}>
114+
<div css={[headerCss, raiseLabelOnDesktop && raiseLabelCss]}>
115+
<span css={labelCss}>{label}</span>
116+
<span
117+
css={[numberCss, largeNumbersOnDesktop && largeNumberCss]}
118+
style={{ '--match-stat-team-colour': home.teamColour }}
119+
>
120+
<span
121+
css={css`
122+
${visuallyHidden}
123+
`}
124+
>
125+
{home.teamName}
126+
</span>
127+
{formatValue(home.value, showPercentage)}
128+
</span>
129+
<span
130+
css={[
131+
numberCss,
132+
awayStatCss,
133+
largeNumbersOnDesktop && largeNumberCss,
134+
]}
135+
style={{ '--match-stat-team-colour': away.teamColour }}
136+
>
137+
<span
138+
css={css`
139+
${visuallyHidden}
140+
`}
141+
>
142+
{away.teamName}
143+
</span>
144+
{formatValue(away.value, showPercentage)}
145+
</span>
146+
</div>
147+
<div aria-hidden="true" css={chartCss}>
148+
<div
149+
css={barCss}
150+
style={{
151+
'--match-stat-percentage': `${homePercentage}%`,
152+
'--match-stat-team-colour': home.teamColour,
153+
}}
154+
></div>
155+
<div
156+
css={barCss}
157+
style={{
158+
'--match-stat-percentage': `${awayPercentage}%`,
159+
'--match-stat-team-colour': away.teamColour,
160+
}}
161+
></div>
162+
</div>
163+
</div>
164+
);
165+
};
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { css } from '@emotion/react';
2+
import { breakpoints, from } from '@guardian/source/foundations';
3+
import type { Meta, StoryObj } from '@storybook/react-webpack5';
4+
import { palette } from '../palette';
5+
import { FootballMiniMatchStats as FootballMiniMatchStatsComponent } from './FootballMiniMatchStats';
6+
7+
const gridCss = css`
8+
background-color: ${palette('--football-live-blog-background')};
9+
/**
10+
* Extremely simplified live blog grid layout as we're only interested in
11+
* the 240px wide left column added at the desktop breakpoint.
12+
* dotcom-rendering/src/layouts/LiveLayout.tsx
13+
*/
14+
${from.desktop} {
15+
display: grid;
16+
grid-column-gap: 20px;
17+
grid-template-columns: 240px 1fr;
18+
}
19+
`;
20+
21+
const containerCss = css`
22+
padding: 10px;
23+
${from.desktop} {
24+
padding-left: 20px;
25+
padding-right: 0;
26+
}
27+
`;
28+
29+
const meta = {
30+
title: 'Components/Football Mini Match Stats',
31+
component: FootballMiniMatchStatsComponent,
32+
decorators: [
33+
(Story) => (
34+
<div css={gridCss}>
35+
<div css={containerCss}>
36+
<Story />
37+
</div>
38+
</div>
39+
),
40+
],
41+
parameters: {
42+
chromatic: {
43+
viewports: [
44+
breakpoints.mobileMedium,
45+
breakpoints.tablet,
46+
breakpoints.wide,
47+
],
48+
},
49+
},
50+
} satisfies Meta<typeof FootballMiniMatchStatsComponent>;
51+
52+
export default meta;
53+
type Story = StoryObj<typeof meta>;
54+
55+
export const FootballMiniMatchStats = {
56+
args: {
57+
homeTeam: {
58+
name: 'Manchester United',
59+
colour: '#da020e',
60+
},
61+
awayTeam: {
62+
name: 'Arsenal',
63+
colour: '#023474',
64+
},
65+
stats: [
66+
{
67+
label: 'Possession',
68+
homeValue: 39,
69+
awayValue: 61,
70+
showPercentage: true,
71+
},
72+
{ label: 'Goal Attempts', homeValue: 7, awayValue: 4 },
73+
],
74+
},
75+
} satisfies Story;

0 commit comments

Comments
 (0)