Skip to content

Commit 0d17862

Browse files
Merge branch 'main' into ab/admiralScript-to-run-after-cmp-booted
2 parents d214e7c + 262f6ac commit 0d17862

22 files changed

+274
-86
lines changed

ab-testing/config/abTests.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ import type { ABTest } from "./types.ts";
2020
*/
2121

2222
const ABTests: ABTest[] = [
23+
{
24+
name: "webx-dark-mode-web",
25+
description: "Dark mode accessibility feature test on web",
26+
owners: ["[email protected]"],
27+
status: "ON",
28+
expirationDate: "2027-04-09",
29+
type: "server",
30+
audienceSize: 0 / 100,
31+
groups: ["enable"],
32+
shouldForceMetricsCollection: false,
33+
},
2334
{
2435
name: "commercial-prebid-v10",
2536
description: "Testing Prebid.js v10 integration on DCR",
@@ -112,7 +123,7 @@ const ABTests: ABTest[] = [
112123
description:
113124
"Test placing the Most Viewed and Deeply Read components in the right-hand column on the homepage.",
114125
owners: ["[email protected]"],
115-
status: "OFF",
126+
status: "ON",
116127
expirationDate: `2026-04-28`,
117128
type: "server",
118129
audienceSize: 0 / 100,

ab-testing/config/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ type AllSpace = Map<string, FastlyTestParams[]>;
66

77
type Team =
88
| "commercial"
9+
// WebX in the canonical name for the team, when the last test using webex expires we should remove webex from this union type
910
| "webex"
11+
| "webx"
1012
| "thefilter"
1113
| "fronts-and-curation"
1214
| "growth";

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

Lines changed: 26 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { css } from '@emotion/react';
2-
import { isUndefined, removeCookie, setCookie, storage } from '@guardian/libs';
2+
import { isUndefined, storage } from '@guardian/libs';
33
import { article17, palette } from '@guardian/source/foundations';
44
import { type SetStateAction, useEffect, useState } from 'react';
55
import { useConfig } from './ConfigContext';
@@ -19,10 +19,6 @@ const bold = css`
1919
font-weight: bold;
2020
`;
2121

22-
// This is hard coded, and must be changed if the experiment bucket changes
23-
// https://github.com/guardian/frontend/blob/09f49b80/common/app/experiments/Experiments.scala#L57
24-
const darkModeCookieName = 'X-GU-Experiment-0perc-D';
25-
2622
const PreferenceToggle = ({
2723
label,
2824
checked,
@@ -90,30 +86,6 @@ export const Accessibility = () => {
9086
true,
9187
);
9288

93-
const [shouldParticipate, setParticipate] =
94-
useState<boolean>(darkModeAvailable);
95-
96-
useEffect(() => {
97-
if (shouldParticipate) {
98-
setCookie({
99-
name: darkModeCookieName,
100-
value: 'true',
101-
});
102-
} else {
103-
removeCookie({ name: darkModeCookieName });
104-
}
105-
106-
const timeout = setTimeout(() => {
107-
// we must reload the page for the preference to take effect,
108-
// as this relies on a server-side test & cookie combination
109-
if (shouldParticipate !== darkModeAvailable) {
110-
window.location.reload();
111-
}
112-
}, 1200);
113-
114-
return () => clearTimeout(timeout);
115-
}, [shouldParticipate, darkModeAvailable]);
116-
11789
const togglePreference = (
11890
preferenceCallback: (value: SetStateAction<boolean>) => void,
11991
): void => {
@@ -154,29 +126,36 @@ export const Accessibility = () => {
154126

155127
<br />
156128

157-
<fieldset css={formStyle}>
129+
<div css={formStyle}>
158130
<p>
159131
We offer beta support for a dark colour scheme on the
160132
web. The colour scheme preference will follow your
161133
system settings.
162134
</p>
163-
<label>
164-
<input
165-
type="checkbox"
166-
checked={shouldParticipate}
167-
onChange={(e) => {
168-
setParticipate(e.target.checked);
169-
}}
170-
data-link-name="prefers-colour-scheme"
171-
/>
172-
<span css={bold}>
173-
Participate in the dark colour scheme beta{' '}
174-
</span>
175-
{shouldParticipate
176-
? ' Untick this to opt out (browser will refresh)'
177-
: ' Tick this to opt in (browser will refresh)'}
178-
</label>
179-
</fieldset>
135+
{darkModeAvailable ? (
136+
<>
137+
<p css={bold}>
138+
You are currently participating in the dark
139+
colour scheme beta.
140+
</p>
141+
<a href="/ab-tests/opt-out/webx-dark-mode-web:enable">
142+
Click here to opt out (this will redirect you to
143+
the homepage)
144+
</a>
145+
</>
146+
) : (
147+
<>
148+
<p css={bold}>
149+
You are not currently participating in the dark
150+
colour scheme beta.
151+
</p>
152+
<a href="/ab-tests/opt-in/webx-dark-mode-web:enable">
153+
Click here to opt in (this will redirect you to
154+
the homepage)
155+
</a>
156+
</>
157+
)}
158+
</div>
180159
</form>
181160
</FrontSection>
182161
);

dotcom-rendering/src/components/ArticlePage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ export const ArticlePage = (props: WebProps | AppProps) => {
179179
You can{' '}
180180
<a
181181
style={{ color: 'inherit' }}
182-
href="/opt/out/dark-mode-web"
182+
href="/ab-tests/opt-out/webx-dark-mode-web"
183183
>
184184
opt out anytime
185185
</a>{' '}

dotcom-rendering/src/components/FrontPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export const FrontPage = ({ front, NAV }: Props) => {
112112
You can{' '}
113113
<a
114114
style={{ color: 'inherit' }}
115-
href="/opt/out/dark-mode-web"
115+
href="/ab-tests/opt-out/webx-dark-mode-web"
116116
>
117117
opt out anytime
118118
</a>{' '}

dotcom-rendering/src/components/FrontSection.tsx

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@ import type {
1414
} from '../types/front';
1515
import type { TagPagePagination } from '../types/tagPage';
1616
import { isAustralianTerritory, type Territory } from '../types/territory';
17+
import type { TrailType } from '../types/trails';
1718
import { AustralianTerritorySwitcher } from './AustralianTerritorySwitcher.importable';
1819
import { BrandingLabel } from './BrandingLabel';
1920
import { ContainerOverrides } from './ContainerOverrides';
2021
import { ContainerTitle } from './ContainerTitle';
2122
import { FrontPagination } from './FrontPagination';
2223
import { FrontSectionTitle } from './FrontSectionTitle';
24+
import { Hide } from './Hide';
2325
import { Island } from './Island';
2426
import { LabsSectionHeader } from './LabsSectionHeader';
27+
import { MostPopularFrontRight } from './MostPopularFrontRight';
2528
import { ShowHideButton } from './ShowHideButton';
2629
import { ShowMore } from './ShowMore.importable';
2730
import { Treats } from './Treats';
@@ -90,6 +93,11 @@ type Props = {
9093
* the page skin background showing through the containers
9194
*/
9295
hasPageSkin?: boolean;
96+
/**
97+
* The Slim Homepage AB test requires some sections to have reduced width so that
98+
* the Most Popular Front Right component can be placed on the right-hand side.
99+
*/
100+
slimifySectionForAbTest?: boolean;
93101
discussionApiUrl: string;
94102
collectionBranding?: CollectionBranding;
95103
isTagPage?: boolean;
@@ -98,6 +106,8 @@ type Props = {
98106
isAboveMobileAd?: boolean;
99107
/** Indicates whether this is a Guardian Labs container */
100108
isLabs?: boolean;
109+
mostViewed?: TrailType[];
110+
deeplyRead?: TrailType[];
101111
};
102112

103113
const width = (columns: number, columnWidth: number, columnGap: number) =>
@@ -356,12 +366,17 @@ const sectionControls = css`
356366

357367
const sectionContent = css`
358368
margin: 0;
369+
grid-column: content;
359370

360371
.hidden > & {
361372
display: none;
362373
}
374+
`;
363375

364-
grid-column: content;
376+
const slimSectionContent = css`
377+
${from.wide} {
378+
grid-column: 5 / 14;
379+
}
365380
`;
366381

367382
const sectionContentRow = (toggleable: boolean) => css`
@@ -385,7 +400,23 @@ const sectionContentBorderFromLeftCol = css`
385400
bottom: 0;
386401
border-left: 1px solid ${schemePalette('--section-border')};
387402
transform: translateX(-50%);
388-
/** Keeps the vertical divider ontop of carousel item dividers */
403+
/** Keeps the vertical divider on top of carousel item dividers */
404+
z-index: 1;
405+
}
406+
}
407+
`;
408+
409+
const slimHomepageRightBorderStyles = css`
410+
${from.wide} {
411+
::after {
412+
content: '';
413+
position: absolute;
414+
top: ${space[2]}px;
415+
bottom: 0;
416+
right: 0;
417+
border-right: 1px solid ${schemePalette('--section-border')};
418+
transform: translateX(-50%);
419+
/** Keeps the vertical divider on top of carousel item dividers */
389420
z-index: 1;
390421
}
391422
}
@@ -619,13 +650,16 @@ export const FrontSection = ({
619650
isOnPaidContentFront,
620651
targetedTerritory,
621652
hasPageSkin = false,
653+
slimifySectionForAbTest = false,
622654
discussionApiUrl,
623655
collectionBranding,
624656
isTagPage = false,
625657
hasNavigationButtons = false,
626658
isAboveDesktopAd = false,
627659
isAboveMobileAd = false,
628660
isLabs = false,
661+
mostViewed = [],
662+
deeplyRead = [],
629663
}: Props) => {
630664
const isToggleable = toggleable && !!sectionId;
631665
const showVerticalRule = !hasPageSkin;
@@ -690,6 +724,15 @@ export const FrontSection = ({
690724
title,
691725
showSectionColours,
692726
),
727+
// To reduce the width of the border line between Features
728+
// and More features in the Slim Homepage AB test.
729+
slimifySectionForAbTest &&
730+
sectionId === 'more-features' &&
731+
css`
732+
${from.wide} {
733+
grid-column: 2 / 14;
734+
}
735+
`,
693736
]}
694737
/>
695738
)}
@@ -784,18 +827,58 @@ export const FrontSection = ({
784827
<div
785828
css={[
786829
sectionContent,
830+
slimifySectionForAbTest && slimSectionContent,
787831
sectionContentHorizontalMargins,
788832
sectionContentRow(toggleable),
789833
topPadding,
790834
showVerticalRule &&
791835
isBetaContainer &&
792836
sectionContentBorderFromLeftCol,
837+
slimifySectionForAbTest &&
838+
slimHomepageRightBorderStyles,
793839
]}
794840
id={`container-${sectionId}`}
795841
>
796842
{children}
797843
</div>
798844

845+
{slimifySectionForAbTest && sectionId === 'news' && (
846+
<div
847+
css={css`
848+
${from.wide} {
849+
grid-row: content-toggleable;
850+
grid-column: 14 / 18;
851+
}
852+
`}
853+
>
854+
<Hide when="below" breakpoint="wide">
855+
<MostPopularFrontRight
856+
heading="Most viewed"
857+
trails={mostViewed}
858+
/>
859+
</Hide>
860+
</div>
861+
)}
862+
863+
{slimifySectionForAbTest && sectionId === 'features' && (
864+
<div
865+
css={css`
866+
${from.wide} {
867+
grid-row: content-toggleable;
868+
grid-column: 14 / 18;
869+
position: relative;
870+
}
871+
`}
872+
>
873+
<Hide when="below" breakpoint="wide">
874+
<MostPopularFrontRight
875+
heading="Deeply read"
876+
trails={deeplyRead}
877+
/>
878+
</Hide>
879+
</div>
880+
)}
881+
799882
<div
800883
css={[
801884
sectionContentHorizontalMargins,

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

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ import {
99
bypassCoreWebVitalsSampling,
1010
initCoreWebVitals,
1111
} from '@guardian/core-web-vitals';
12-
import { getCookie, isString, isUndefined } from '@guardian/libs';
12+
import { isUndefined } from '@guardian/libs';
1313
import { useCallback, useEffect, useState } from 'react';
1414
import { useAB, useBetaAB } from '../lib/useAB';
1515
import { useAdBlockInUse } from '../lib/useAdBlockInUse';
16+
import { useBrowserId } from '../lib/useBrowserId';
1617
import { useDetectAdBlock } from '../lib/useDetectAdBlock';
1718
import { usePageViewId } from '../lib/usePageViewId';
1819
import type { ServerSideTests } from '../types/config';
@@ -41,20 +42,6 @@ const shouldCollectMetricsForBetaTests = (userTestParticipations: string[]) => {
4142
);
4243
};
4344

44-
const useBrowserId = () => {
45-
const [browserId, setBrowserId] = useState<string>();
46-
47-
useEffect(() => {
48-
const cookie = getCookie({ name: 'bwid', shouldMemoize: true });
49-
50-
const id = isString(cookie) ? cookie : 'no-browser-id-available';
51-
52-
setBrowserId(id);
53-
}, []);
54-
55-
return browserId;
56-
};
57-
5845
const useDev = () => {
5946
const [isDev, setIsDev] = useState<boolean>();
6047

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ const meta = {
77
component: MostPopularFrontRight,
88
title: 'Components/MostPopularFrontRight',
99
decorators: [rightColumnDecorator],
10-
render: (args) => <MostPopularFrontRight {...args} />,
10+
render: (args) => (
11+
<div css={{ position: 'relative' }}>
12+
<MostPopularFrontRight {...args} />
13+
</div>
14+
),
1115
} satisfies Meta<typeof MostPopularFrontRight>;
1216

1317
export default meta;

0 commit comments

Comments
 (0)