Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions ab-testing/config/abTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ const ABTests: ABTest[] = [
groups: ["control", "variant"],
shouldForceMetricsCollection: false,
},
{
name: "fronts-and-curation-personalised-container",
description: "Testing the a personalised container component on fronts",
owners: ["fronts.and.curation@guardian.co.uk"],
expirationDate: `2026-02-22`,
type: "server",
status: "ON",
audienceSize: 0 / 100,
audienceSpace: "A",
groups: ["control", "variant"],
shouldForceMetricsCollection: false,
},
];

const activeABtests = ABTests.filter((test) => test.status === "ON");
Expand Down
18 changes: 16 additions & 2 deletions dotcom-rendering/src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ export type Props = {
isInStarRatingVariant?: boolean;
starRatingSize?: RatingSizeType;
isInOnwardsAbTestVariant?: boolean;
isInPersonalisationVariant?: boolean;
};

const starWrapper = (cardHasImage: boolean) => css`
Expand Down Expand Up @@ -201,13 +202,16 @@ const waveformWrapper = (
left: 0;
right: 0;
bottom: 0;

svg {
display: block;
width: 100%;
height: ${mediaPositionOnMobile === 'top' ? 50 : 29}px;

${from.mobileMedium} {
height: ${mediaPositionOnMobile === 'top' ? 50 : 33}px;
}

${from.tablet} {
height: ${mediaPositionOnDesktop === 'top' ? 50 : 33}px;
}
Expand All @@ -221,12 +225,15 @@ const HorizontalDivider = () => (
border-top: 1px solid ${palette('--card-border-top')};
height: 1px;
width: 50%;

${from.tablet} {
width: 100px;
}

${from.desktop} {
width: 140px;
}

margin-top: ${space[3]}px;
}
`}
Expand All @@ -241,6 +248,7 @@ const podcastImageStyles = (
return css`
width: 69px;
height: 69px;

${from.tablet} {
width: 98px;
height: 98px;
Expand All @@ -254,11 +262,14 @@ const podcastImageStyles = (
return css`
width: 98px;
height: 98px;

${from.tablet} {
width: 120px;
height: 120px;
}

/** The image takes the full height on desktop, so that the waveform sticks to the bottom of the card. */

${from.desktop} {
width: ${isHorizontalOnDesktop ? 'unset' : '120px'};
height: ${isHorizontalOnDesktop ? 'unset' : '120px'};
Expand Down Expand Up @@ -429,6 +440,7 @@ export const Card = ({
isInStarRatingVariant,
starRatingSize = 'small',
isInOnwardsAbTestVariant,
isInPersonalisationVariant,
}: Props) => {
const hasSublinks = supportingContent && supportingContent.length > 0;
const sublinkPosition = decideSublinkPosition(
Expand Down Expand Up @@ -612,8 +624,8 @@ export const Card = ({

/**
- * Media cards have contrasting background colours. We add additional
* padding to these cards to keep the text readable.
- */
* padding to these cards to keep the text readable.
- */
const isMediaCardOrNewsletter = isMediaCard(format) || isNewsletter;

const showPill = isMediaCardOrNewsletter && !isGallerySecondaryOnward;
Expand Down Expand Up @@ -910,6 +922,7 @@ export const Card = ({
${until.tablet} {
display: none;
}

${from.desktop} {
display: none;
}
Expand Down Expand Up @@ -946,6 +959,7 @@ export const Card = ({
headlineText={headlineText}
dataLinkName={resolvedDataLinkName}
isExternalLink={isExternalLink}
isInPersonalisationVariant={isInPersonalisationVariant}
/>
{headlinePosition === 'outer' && (
<div
Expand Down
20 changes: 17 additions & 3 deletions dotcom-rendering/src/components/Card/components/CardLink.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { css } from '@emotion/react';
import { focusHalo } from '@guardian/source/foundations';
import { getZIndex } from '../../../lib/getZIndex';
import { trackPersonalisationClick } from '../../../lib/personalisationHistory';

const fauxLinkStyles = css`
position: absolute;
Expand All @@ -21,16 +22,19 @@ type Props = {
headlineText: string;
dataLinkName?: string;
isExternalLink: boolean;
isInPersonalisationVariant?: boolean;
};

const InternalLink = ({
linkTo,
headlineText,
dataLinkName,
trackPersonalisationCardClick,
}: {
linkTo: string;
headlineText: string;
dataLinkName?: string;
trackPersonalisationCardClick?: () => void;
}) => {
return (
// eslint-disable-next-line jsx-a11y/anchor-has-content -- we have an aria-label attribute describing the content
Expand All @@ -39,6 +43,7 @@ const InternalLink = ({
css={fauxLinkStyles}
data-link-name={dataLinkName}
aria-label={headlineText}
onClick={trackPersonalisationCardClick}
/>
);
};
Expand All @@ -47,12 +52,12 @@ const ExternalLink = ({
linkTo,
headlineText,
dataLinkName,
trackCardClick,
trackPersonalisationCardClick,
}: {
linkTo: string;
headlineText: string;
dataLinkName?: string;
trackCardClick?: () => void;
trackPersonalisationCardClick?: () => void;
}) => {
return (
// eslint-disable-next-line jsx-a11y/anchor-has-content -- we have an aria-label attribute describing the content
Expand All @@ -63,7 +68,7 @@ const ExternalLink = ({
aria-label={headlineText + ' (opens in new tab)'}
target="_blank"
rel="noreferrer"
onClick={trackCardClick}
onClick={trackPersonalisationCardClick}
/>
);
};
Expand All @@ -73,6 +78,7 @@ export const CardLink = ({
headlineText,
dataLinkName = 'article', //this makes sense if the link is to an article, but should this say something like "external" if it's an external link? are there any other uses/alternatives?
isExternalLink,
isInPersonalisationVariant,
}: Props) => {
return (
<>
Expand All @@ -81,13 +87,21 @@ export const CardLink = ({
linkTo={linkTo}
headlineText={headlineText}
dataLinkName={dataLinkName}
trackPersonalisationCardClick={() =>
isInPersonalisationVariant &&
trackPersonalisationClick(linkTo)
}
/>
)}
{!isExternalLink && (
<InternalLink
linkTo={linkTo}
headlineText={headlineText}
dataLinkName={dataLinkName}
trackPersonalisationCardClick={() =>
isInPersonalisationVariant &&
trackPersonalisationClick(linkTo)
}
/>
)}
</>
Expand Down
4 changes: 4 additions & 0 deletions dotcom-rendering/src/components/Card/components/LI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ type Props = {
offsetBottomPaddingOnDivider?: boolean;
/** Overrides the vertical divider colour */
verticalDividerColour?: string;

isVisible?: boolean;
};

export const LI = ({
Expand All @@ -114,6 +116,7 @@ export const LI = ({
snapAlignStart = false,
offsetBottomPaddingOnDivider = false,
verticalDividerColour = palette('--section-border'),
isVisible = true,
}: Props) => {
// Decide sizing
const sizeStyles = decideSize(percentage, stretch);
Expand All @@ -133,6 +136,7 @@ export const LI = ({
padSidesOnMobile &&
sidePaddingStylesMobile(padSidesMobileOverride),
snapAlignStart && snapAlignStartStyles,
{ visibility: isVisible ? 'visible' : 'hidden' },
]}
>
{children}
Expand Down
20 changes: 20 additions & 0 deletions dotcom-rendering/src/components/DecideContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
DCRContainerType,
DCRFrontCard,
DCRGroupedTrails,
PillarBucket,
} from '../types/front';
import { DynamicFast } from './DynamicFast';
import { DynamicPackage } from './DynamicPackage';
Expand All @@ -27,6 +28,7 @@ import { FlexibleGeneral } from './FlexibleGeneral';
import { FlexibleSpecial } from './FlexibleSpecial';
import { Island } from './Island';
import { NavList } from './NavList';
import { PersonalisedMediumFour } from './PersonalisedMediumFour.importable';
import { ScrollableFeature } from './ScrollableFeature.importable';
import { ScrollableHighlights } from './ScrollableHighlights.importable';
import { ScrollableMedium } from './ScrollableMedium.importable';
Expand All @@ -48,6 +50,7 @@ type Props = {
collectionId: number;
containerLevel?: DCRContainerLevel;
isInStarRatingVariant?: boolean;
pillarBuckets?: PillarBucket;
};

export const DecideContainer = ({
Expand All @@ -64,6 +67,7 @@ export const DecideContainer = ({
collectionId,
containerLevel,
isInStarRatingVariant,
pillarBuckets,
}: Props) => {
switch (containerType) {
case 'dynamic/fast':
Expand Down Expand Up @@ -298,6 +302,22 @@ export const DecideContainer = ({
</Island>
);
case 'static/medium/4':
if (pillarBuckets) {
return (
<Island priority="critical" defer={{ until: 'visible' }}>
<PersonalisedMediumFour
trails={trails}
containerPalette={containerPalette}
showAge={showAge}
serverTime={serverTime}
imageLoading={imageLoading}
aspectRatio={aspectRatio}
isInStarRatingVariant={isInStarRatingVariant}
pillarBuckets={pillarBuckets}
/>
</Island>
);
}
return (
<StaticMediumFour
trails={trails}
Expand Down
Loading
Loading