Skip to content

Commit 24ff0a5

Browse files
authored
Merge pull request #15437 from guardian/doml/slim-homepage-abtest
Slim Homepage AB test: implement logic
2 parents a9dc3ec + 3acc60d commit 24ff0a5

6 files changed

Lines changed: 155 additions & 8 deletions

File tree

ab-testing/config/abTests.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ const ABTests: ABTest[] = [
112112
description:
113113
"Test placing the Most Viewed and Deeply Read components in the right-hand column on the homepage.",
114114
owners: ["fronts.and.curation@guardian.co.uk"],
115-
status: "OFF",
115+
status: "ON",
116116
expirationDate: `2026-04-28`,
117117
type: "server",
118118
audienceSize: 0 / 100,

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/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;

dotcom-rendering/src/components/MostPopularFrontRight.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,19 @@ import { LinkHeadline } from './LinkHeadline';
1414

1515
const containerStyles = css`
1616
padding-top: ${space[2]}px;
17+
padding-bottom: ${space[10]}px;
1718
display: flex;
1819
flex-direction: column;
1920
gap: ${space[8]}px;
2021
`;
2122

23+
const absolutePositionStyles = css`
24+
position: absolute;
25+
top: 0;
26+
left: 0;
27+
width: 300px;
28+
`;
29+
2230
const headingStyles = css`
2331
padding-left: 80px;
2432
${headlineBold24};
@@ -84,7 +92,10 @@ export const MostPopularFrontRight = ({ heading, trails }: Props) => {
8492
return (
8593
<section
8694
data-component="most-popular-front-right"
87-
css={containerStyles}
95+
css={[
96+
containerStyles,
97+
heading === 'Deeply read' && absolutePositionStyles,
98+
]}
8899
>
89100
<h3 css={headingStyles}>{heading}</h3>
90101
<ol>

dotcom-rendering/src/components/MostViewedFooterItem.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export const MostViewedFooterItem = ({
8484
<span css={bigNumber}>
8585
<BigNumber index={position} />
8686
</span>
87-
<div css={[headlineHeader]}>
87+
<div css={headlineHeader}>
8888
<FormatBoundary format={format}>
8989
{format.design === ArticleDesign.LiveBlog ? (
9090
<LinkHeadline

dotcom-rendering/src/layouts/FrontLayout.tsx

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {
4040
} from '../lib/getFrontsAdPositions';
4141
import { hideAge } from '../lib/hideAge';
4242
import { ophanComponentId } from '../lib/ophan-helpers';
43+
import { useBetaAB } from '../lib/useAB';
4344
import type { NavType } from '../model/extract-nav';
4445
import { palette as schemePalette } from '../palette';
4546
import type {
@@ -67,20 +68,35 @@ const isNavList = (collection: DCRCollectionType) => {
6768
const isHighlights = ({ collectionType }: DCRCollectionType) =>
6869
collectionType === 'scrollable/highlights';
6970

71+
const isMostPopular = ({ collectionType }: DCRCollectionType) =>
72+
collectionType === 'news/most-popular';
73+
7074
const isLabs = ({ containerPalette }: DCRCollectionType) =>
7175
containerPalette === 'Branded';
7276

7377
const isToggleable = (
7478
index: number,
7579
collection: DCRCollectionType,
7680
isNetworkFront: boolean,
81+
isInSlimHomepageAbTestVariant: boolean,
7782
) => {
7883
if (isNetworkFront) {
84+
/**
85+
* The show/hide button would be covered by the MostPopularFrontRight component
86+
* in the variant of the Slim Homepage AB test.
87+
*/
88+
const hideForSlimHomepageAbTest =
89+
isInSlimHomepageAbTestVariant &&
90+
(collection.displayName === 'News' ||
91+
collection.displayName === 'Features' ||
92+
collection.displayName === 'More features');
93+
7994
return (
8095
collection.displayName.toLowerCase() !== 'headlines' &&
8196
!isNavList(collection) &&
8297
!isHighlights(collection) &&
83-
!isLabs(collection)
98+
!isLabs(collection) &&
99+
!hideForSlimHomepageAbTest
84100
);
85101
}
86102

@@ -138,6 +154,23 @@ export const FrontLayout = ({ front, NAV }: Props) => {
138154

139155
const contributionsServiceUrl = getContributionsServiceUrl(front);
140156

157+
const abTests = useBetaAB();
158+
159+
/**
160+
* The Slim Homepage AB test only runs on /uk and on screen widths >=1300px.
161+
* In the variant of this test a Most Popular component is added to the right-hand side of the page.
162+
* Page skins require slim content and is incompatible with this test. We do not run this test
163+
* on pages where there is a page skin (a page skin takes precedence).
164+
*/
165+
const isInSlimHomepageAbTestVariant =
166+
(pageId === 'uk' &&
167+
!hasPageSkin &&
168+
abTests?.isUserInTestGroup(
169+
'fronts-and-curation-slim-homepage',
170+
'variant',
171+
)) ??
172+
false;
173+
141174
const fallbackAspectRatio = (collectionType: DCRContainerType) => {
142175
switch (collectionType) {
143176
case 'scrollable/feature':
@@ -278,6 +311,15 @@ export const FrontLayout = ({ front, NAV }: Props) => {
278311
} | ${ophanName}`;
279312
const mostPopularTitle = 'Most popular';
280313

314+
/**
315+
* We only shrink the content of certain sections to place the Most Popular
316+
* content on the right-hand side. Other sections remain full-width.
317+
*/
318+
const isTargetedContainerInSlimHomepageAbTest =
319+
collection.displayName === 'News' ||
320+
collection.displayName === 'Features' ||
321+
collection.displayName === 'More features';
322+
281323
if (collection.collectionType === 'scrollable/highlights') {
282324
// Highlights are rendered in the Masthead component
283325
return null;
@@ -352,7 +394,7 @@ export const FrontLayout = ({ front, NAV }: Props) => {
352394
}
353395

354396
if (
355-
collection.collectionType === 'news/most-popular' &&
397+
isMostPopular(collection) &&
356398
!isPaidContent &&
357399
switches.mostViewedFronts
358400
) {
@@ -457,6 +499,7 @@ export const FrontLayout = ({ front, NAV }: Props) => {
457499
index,
458500
collection,
459501
front.isNetworkFront,
502+
isInSlimHomepageAbTestVariant,
460503
)}
461504
leftContent={decideLeftContent(
462505
front,
@@ -496,6 +539,12 @@ export const FrontLayout = ({ front, NAV }: Props) => {
496539
index,
497540
)}
498541
isLabs={isLabs(collection)}
542+
slimifySectionForAbTest={
543+
isInSlimHomepageAbTestVariant &&
544+
isTargetedContainerInSlimHomepageAbTest
545+
}
546+
mostViewed={front.mostViewed}
547+
deeplyRead={front.deeplyRead}
499548
>
500549
<DecideContainer
501550
trails={trails}

0 commit comments

Comments
 (0)