Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2f91961
Rough implementation for mobile view
frederickobrien Feb 25, 2026
1e969fd
Desktop layout
frederickobrien Feb 27, 2026
0662b8c
Add vertical rules to grid module
frederickobrien Feb 27, 2026
cb657c3
Fix not appearing
frederickobrien Mar 3, 2026
d831dba
Roll back RightColumn changes
frederickobrien Mar 4, 2026
8c318c1
Abstract area placement depending on layout
frederickobrien Mar 4, 2026
1707c5d
Human readable furniture row configuration
frederickobrien Mar 5, 2026
c366481
Review polishes and refactors
frederickobrien Mar 6, 2026
21e999b
Adjust media furniture layout
frederickobrien Mar 10, 2026
853ac8d
More consistent row and column grid styling abstraction
frederickobrien Mar 10, 2026
246388f
Dom review polishes
frederickobrien Mar 11, 2026
6e9be6e
Incorporate grid rows into furniture layout config
frederickobrien Mar 11, 2026
c3a7410
Type tidying
frederickobrien Mar 11, 2026
d173fb3
Move all column settings into layout config
frederickobrien Mar 11, 2026
5688891
Remove maxWidth wrapper divs
frederickobrien Mar 11, 2026
be42eb5
Deduplicate config
frederickobrien Mar 12, 2026
29ea7f6
Adjust standard layout to sit properly when there's no featured image
frederickobrien Mar 12, 2026
a55c321
Tidying
frederickobrien Mar 17, 2026
752b086
Reflect existing conditional padding on right-column area
frederickobrien Mar 18, 2026
8002fa6
Rebase tidy
frederickobrien Mar 18, 2026
c5342cd
Rename furnitureLayouts to furnitureArrangements
frederickobrien Apr 15, 2026
22d35eb
Review suggestions
frederickobrien Apr 21, 2026
2c22ac5
Readability improvements
frederickobrien Apr 22, 2026
782b599
Documentation
frederickobrien Apr 22, 2026
0f0d12a
Replace abstraction with vanilla CSS approach
frederickobrien Apr 28, 2026
2e49d44
Update grid.ts
frederickobrien Apr 30, 2026
121d360
Rebase tidying
frederickobrien Apr 30, 2026
4911227
Rough first pass
frederickobrien May 19, 2026
cbefe1f
Refactor grid centre rule, more breakpoints
frederickobrien May 21, 2026
996e900
Rough implementation of portrait/landscape variants
frederickobrien May 26, 2026
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
151 changes: 56 additions & 95 deletions dotcom-rendering/src/components/ArticleHeadline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
ArticleSpecial,
Pillar,
} from '../lib/articleFormat';
import { getZIndex } from '../lib/getZIndex';
import { palette as themePalette } from '../palette';
import type { StarRating as Rating } from '../types/content';
import type { TagType } from '../types/tag';
Expand All @@ -45,6 +44,7 @@ type Props = {
hasAvatar?: boolean;
isMatch?: boolean;
starRating?: Rating;
isInverted?: boolean;
};

const topPadding = css`
Expand Down Expand Up @@ -205,30 +205,20 @@ const invertedStyles = css`
box-decoration-break: clone;
`;

const immersiveStyles = css`
min-height: 112px;
padding-bottom: ${space[6]}px;
padding-left: ${space[1]}px;

${from.mobileLandscape} {
padding-left: ${space[3]}px;
}

${from.tablet} {
padding-left: ${space[1]}px;
}

margin-right: ${space[5]}px;
`;

const darkBackground = css`
background-color: ${themePalette('--headline-background')};
`;

const invertedText = css`
white-space: pre-wrap;
padding-bottom: ${space[1]}px;
padding-right: ${space[1]}px;
${from.desktop} {
color: white;
background-color: black;
white-space: pre-wrap;
padding-bottom: ${space[1]}px;
padding-right: ${space[1]}px;
margin-left: -10px;
padding-left: 10px;
}
`;

const maxWidth = css`
Expand All @@ -246,35 +236,6 @@ const invertedWrapper = css`
margin-left: 6px;
`;

const immersiveWrapper = css`
/*
Make sure we vertically align the headline font with the body font
*/
margin-left: 6px;

${from.tablet} {
margin-left: 16px;
}

${from.leftCol} {
margin-left: 25px;
}

/*
We need this grow to ensure the headline fills the main content column
*/
flex-grow: 1;
/*
This z-index is what ensures the headline text shows above the pseudo black
box that extends the black background to the right
*/
z-index: ${getZIndex('articleHeadline')};

${until.mobileLandscape} {
margin-right: 40px;
}
`;

// Due to MainMedia using position: relative, this seems to effect the rendering order
// To mitigate we use z-index
// TODO: find a cleaner solution
Expand All @@ -283,59 +244,58 @@ const zIndex = css`
`;

const ageWarningMargins = (format: ArticleFormat) => {
if (format.design === ArticleDesign.Gallery) {
if (
format.design === ArticleDesign.Gallery ||
format.display === ArticleDisplay.Immersive
) {
return '';
}
return format.display === ArticleDisplay.Immersive
? css`
margin-left: 0px;
margin-bottom: 0px;

${from.tablet} {
margin-left: 10px;
}
return css`
margin-top: 12px;
margin-left: -10px;
margin-bottom: 6px;

${from.leftCol} {
margin-left: 20px;
}
`
: css`
margin-top: 12px;
margin-left: -10px;
margin-bottom: 6px;

${from.tablet} {
margin-left: -20px;
}
${from.tablet} {
margin-left: -20px;
}

${from.leftCol} {
margin-left: -10px;
margin-top: 0;
}
`;
${from.leftCol} {
margin-left: -10px;
margin-top: 0;
}
`;
};

const backgroundStyles = css`
background-color: ${themePalette('--age-warning-wrapper-background')};
`;

const WithAgeWarning = ({
tags,
webPublicationDateDeprecated,
format,
children,
snapToInverted = false,
}: {
tags: TagType[];
webPublicationDateDeprecated: string;
format: ArticleFormat;
children: React.ReactNode;
snapToInverted?: boolean;
}) => {
const age = getAgeWarning(tags, webPublicationDateDeprecated);

if (age) {
return (
<>
<div css={[backgroundStyles, ageWarningMargins(format)]}>
<div
css={[
ageWarningMargins(format),
snapToInverted
? css`
${from.desktop} {
margin-left: -10px;
}
`
: '',
]}
>
<AgeWarning age={age} />
</div>
{children}
Expand Down Expand Up @@ -430,6 +390,7 @@ export const ArticleHeadline = ({
hasAvatar,
isMatch,
starRating,
isInverted = false,
}: Props) => {
switch (format.display) {
case ArticleDisplay.Immersive: {
Expand All @@ -456,12 +417,13 @@ export const ArticleHeadline = ({
format.theme === ArticleSpecial.Labs
? labsFont
: headlineFont(format),
invertedText,
css`
color: ${themePalette(
'--headline-colour',
)};
`,
isInverted
? [invertedText, darkBackground]
: css`
color: ${themePalette(
'--headline-colour',
)};
`,
]}
>
{headlineString}
Expand All @@ -487,16 +449,17 @@ export const ArticleHeadline = ({
webPublicationDateDeprecated
}
format={format}
snapToInverted={true}
>
<h1
css={[
immersiveWrapper,
darkBackground,
css`
color: ${themePalette(
'--headline-colour',
)};
`,
isInverted
? [invertedText, darkBackground]
: css`
color: ${themePalette(
'--headline-colour',
)};
`,
]}
>
<span
Expand All @@ -505,8 +468,6 @@ export const ArticleHeadline = ({
? jumboLabsFont
: headlineFont(format),
maxWidth,
invertedStyles,
immersiveStyles,
displayBlock,
]}
>
Expand Down
1 change: 0 additions & 1 deletion dotcom-rendering/src/components/Standfirst.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,6 @@ const standfirstStyles = ({ display, design, theme }: ArticleFormat) => {
`;
default:
return css`
max-width: 280px;
${from.tablet} {
max-width: 460px;
}
Expand Down
53 changes: 39 additions & 14 deletions dotcom-rendering/src/grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,35 +88,55 @@ const paddedContainer = `
// ----- Vertical Rules ----- //

type VerticalRuleOptions = {
centre?: boolean;
plusChild?: number;
};

/**
* Render Guardian grid vertical rules.
*
* Left and right rules are always present.
* A centre rule can optionally be enabled.
* A centre rule can optionally be enabled, anchored to the top of the first
* child by default, or to the nth child if a number is passed.
*
* Usage:
* css([grid.container, grid.verticalRules()])
* css([grid.container, grid.verticalRules({ centre: true })])
* css([grid.container, grid.verticalRules({ centre: 3 })])
*/
const optionalCentreRule = `/* CENTRE RULE */
& > *:first-child::before {
grid-column: centre-column-start;
transform: translateX(-${columnGap});
${fromBreakpoint.leftCol} {
transform: translateX(calc(-${columnGap} / 2));
}

// The centre rule is self-contained on the nth child element rather than on
// the grid container, so that `top: 0` aligns to that element's top edge.
// `bottom` uses a large negative value to extend the rule down to the
// container's bottom; ensure `overflow: hidden` is set on the container
const optionalCentreRule = (nth: number): string => `/* CENTRE RULE */
& > *:nth-child(${nth}) {
position: relative;

&::before {
position: absolute;
top: 0;
bottom: -9999px;
width: 1px;
background-color: ${palette('--article-border')};
content: '';
grid-column: centre-column-start;
transform: translateX(-${columnGap});

${fromBreakpoint.leftCol} {
transform: translateX(calc(-${columnGap} / 2));
}
}
}`;

const verticalRules = (options: VerticalRuleOptions = {}): string => `
const verticalRules = (options: VerticalRuleOptions = {}): string => {
const { plusChild: centreChild } = options;

return `
${fromBreakpoint.tablet} {
position: relative;

&::before,
&::after
${options.centre ? ', & > *:first-child::before' : ''} {
&::after {
position: absolute;
top: 0;
bottom: 0;
Expand Down Expand Up @@ -145,8 +165,9 @@ const verticalRules = (options: VerticalRuleOptions = {}): string => `
}
}

${options.centre ? optionalCentreRule : ''}
`;
${centreChild !== undefined ? optionalCentreRule(centreChild) : ''}
}`;
};

// ----- API ----- //

Expand Down Expand Up @@ -251,6 +272,10 @@ const grid = {
verticalRules,
} as const;

// ----- Types ----- //
type ColumnPreset = keyof typeof grid.column;

// ----- Exports ----- //

export type { Line, ColumnPreset };
export { grid };
5 changes: 2 additions & 3 deletions dotcom-rendering/src/layouts/DecideLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { GalleryLayout } from './GalleryLayout';
import { HostedArticleLayout } from './HostedArticleLayout';
import { HostedGalleryLayout } from './HostedGalleryLayout';
import { HostedVideoLayout } from './HostedVideoLayout';
import { ImmersiveLayout } from './ImmersiveLayout';
import { InteractiveLayout } from './InteractiveLayout';
import { LiveLayout } from './LiveLayout';
import { NewsletterSignupLayout } from './NewsletterSignupLayout';
Expand Down Expand Up @@ -58,7 +57,7 @@ const DecideLayoutApps = ({ article, renderingTarget }: AppProps) => {
}
default: {
return (
<ImmersiveLayout
<StandardLayout
article={article.frontendData}
format={format}
renderingTarget={renderingTarget}
Expand Down Expand Up @@ -237,7 +236,7 @@ const DecideLayoutWeb = ({ article, NAV, renderingTarget }: WebProps) => {
}
default: {
return (
<ImmersiveLayout
<StandardLayout
article={article.frontendData}
format={format}
NAV={NAV}
Expand Down
Loading
Loading