Skip to content

Commit b3c1cba

Browse files
committed
Merge branch 'main' into rjr-fix-video-main-media-poster-images
2 parents 77b7876 + 3fbb586 commit b3c1cba

37 files changed

+627
-223
lines changed

.prettierignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ dotcom-rendering/stories/generated
1010

1111
# specific files
1212
/**/*/curl-with-js-and-domReady.js
13+
14+
# MDX - prettier breaks SVGs
15+
*.mdx

dotcom-rendering/.storybook/main.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const config: StorybookConfig = {
1515
'../src/**/*.stories.@(tsx)',
1616
'../stories/**/*.stories.@(tsx)',
1717
'../stories/**/*.stories.@(jsx)',
18+
'../src/**/*.mdx',
1819
],
1920

2021
staticDirs: [
@@ -29,7 +30,7 @@ const config: StorybookConfig = {
2930
actions: true,
3031
backgrounds: true,
3132
controls: true,
32-
docs: false,
33+
docs: true,
3334
viewport: true,
3435
toolbars: true,
3536
},
@@ -142,6 +143,8 @@ const webpackConfig = (config: Configuration) => {
142143
config.resolve.alias = {
143144
...config.resolve.alias,
144145
Buffer: 'buffer',
146+
react: 'react',
147+
'react-dom': 'react-dom',
145148
};
146149
return config;
147150
};

dotcom-rendering/README.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,17 @@ $ cd dotcom-rendering
3030

3131
### Install Node.js
3232

33-
To install and manage Node versions, we highly recommend installing a Node version manager such as [fnm](https://github.com/Schniz/fnm) (preferred), [nvm](https://github.com/nvm-sh/nvm) or [asdf](https://asdf-vm.com/guide/getting-started.html).
33+
We highly recommend installing a Node version manager such as [fnm](https://github.com/Schniz/fnm) (preferred), [nvm](https://github.com/nvm-sh/nvm) or [asdf](https://asdf-vm.com/guide/getting-started.html).
3434

35-
Ensure you're at the root directory of this project, then follow the instructions for your version manager to install Node.
35+
Install the Node version manager of your choice.
36+
37+
Ensure you're at the root directory of the project:
38+
39+
```
40+
cd ~/code/dotcom-rendering
41+
```
42+
43+
Run the command for your version manager to use the Node version as specified in [.nvmrc](../.nvmrc).
3644

3745
For `fnm` this will be:
3846

@@ -94,22 +102,20 @@ $ make install
94102

95103
If you get an Node version error then check the setup for your version manager.
96104

97-
### Running locally
105+
### Run
98106

99107
```sh
100108
$ make dev
101109
```
102110

103-
The development server will start on [http://localhost:3030](http://localhost:3030).
111+
The development server will start on [http://localhost:3030](http://localhost:3030)
104112

105-
A list of content types with example URLs are available on the [root path](http://localhost:3030).
113+
The development server home page lists examples of the various page and content types.
106114

107115
You can render a specific article by appending the production URL to the `Article` endpoint, for example:
108-
109116
http://localhost:3030/Article/https://www.theguardian.com/sport/2019/jul/28/tour-de-france-key-moments-egan-bernal-yellow-jersey
110117

111-
You can view the JSON representation of an article as sent to DCR by [Frontend](https://github.com/guardian/frontend), by appending `.json?dcr=true` to the production URL, for example:
112-
118+
You can view the JSON data model of a page as sent by [Frontend](https://github.com/guardian/frontend) to DCR by appending `.json?dcr=true` to the production URL, for example:
113119
https://www.theguardian.com/sport/2019/jul/28/tour-de-france-key-moments-egan-bernal-yellow-jersey.json?dcr=true
114120

115121
### Detailed setup

dotcom-rendering/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"@emotion/server": "11.11.0",
2929
"@guardian/ab-core": "8.0.0",
3030
"@guardian/braze-components": "22.2.0",
31-
"@guardian/bridget": "8.5.1",
31+
"@guardian/bridget": "8.6.0",
3232
"@guardian/browserslist-config": "6.1.0",
3333
"@guardian/cdk": "61.4.0",
3434
"@guardian/commercial-core": "27.1.0",

dotcom-rendering/src/Grid.mdx

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
import { Source } from '@storybook/addon-docs/blocks';
2+
3+
# Grid
4+
5+
The `grid` module implements the [Guardian Grid](https://theguardian.design/2a1e5182b/p/41be19-grids) using [CSS grid](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Basic_concepts_of_grid_layout). The columns described in the Guardian grid definition are implemented as <CSSGridColumn />s. In some Guardian designs we also have a concept of three layout columns: <LeftColumn />, <CentreColumn />, and <RightColumn />. As these are often used in designs on dotcom and apps, this module provides an API for positioning content in these columns as well.
6+
7+
<Diagram>
8+
<text x="45" y="265" fill="red" style={textStyles}>Left column</text>
9+
<text x="460" y="265" fill="green" style={textStyles}>Centre column</text>
10+
<text x="1035" y="265" fill="blue" style={textStyles}>Right column</text>
11+
</Diagram>
12+
13+
export const textStyles = {
14+
fontSize: 30,
15+
fontFamily: 'sans-serif',
16+
fontWeight: 'bold',
17+
};
18+
19+
Note that some of these layout columns only exist at certain breakpoints. All breakpoints have the <CentreColumn />, but the <RightColumn /> only appears from the "desktop" breakpoint (980px), and the <LeftColumn /> only appears from the "leftCol" breakpoint (1140px). You can use the [media queries API](https://guardian.github.io/storybooks/?path=/docs/source_foundations-media-queries--docs) from `@guardian/source` to specify which columns to use at different breakpoints.
20+
21+
The following code provides an example of the API in use, while later sections on this page will give more details about the features demonstrated here. Note that a mixture of different Emotion patterns, such as [object styles](https://emotion.sh/docs/css-prop#object-styles) and [string styles](https://emotion.sh/docs/css-prop#string-styles), are included for demonstration purposes.
22+
23+
<Source language="tsx" code={`
24+
import { css } from '@emotion/react';
25+
import { from } from '@guardian/source/foundations';
26+
import { grid } from '../grid';
27+
28+
const MyComponent = () => (
29+
<article css={css(grid.container)}>
30+
<h1 css={css(grid.column.centre)}>
31+
Headline
32+
</h1>
33+
<p css={{
34+
'&': css(grid.column.centre),
35+
[from.leftCol]: css(grid.column.left),
36+
}}>
37+
Byline
38+
</p>
39+
<ol css={css\`
40+
\${grid.column.right}
41+
display: none;
42+
43+
\${from.desktop} {
44+
display: block;
45+
}
46+
\`}>
47+
Most viewed
48+
</ol>
49+
</article>
50+
);
51+
`} />
52+
53+
## Grid Container
54+
55+
A CSS grid layout consists of an element that's designated as a grid container, and grid items, which are its direct children in the DOM. The `grid` module provides two variants of a grid container, both of which set up the Guardian grid layout.
56+
57+
The first is `grid.container`, which defines a grid that covers the entire viewport, and allows you to position content all the way from the left edge to the right. This is useful for elements like the [immersive main media](https://www.theguardian.com/society/2025/jul/08/the-life-swap-dream-or-a-marketing-gimmick-the-italian-towns-selling-houses-for-1), which needs to span the entire viewport.
58+
59+
The second is `grid.paddedContainer`, which works similarly to `grid.container`, except that it only allows you to position content within the main Guardian grid area, and automatically generates margins on either side. There are many designs where nothing appears in those margins, and it's therefore convenient to be able to position content without having to worry about them.
60+
61+
In practice, which one of these two containers you choose will affect `grid.column.all` in the [Column API](#column-api), and usages of the `'grid-start'` and `'grid-end'` lines in the [Line API](#line-api).
62+
63+
## Column API
64+
65+
The column API is used to interact with the three layout columns. `grid.column.left` will position an element in the <LeftColumn />, `grid.column.centre` will position an element in the <CentreColumn />, and `grid.column.right` will position an element in the <RightColumn />.
66+
67+
There's also `grid.column.all`, which will position an item such that it spans all the way from the start of the grid to the end. As discussed in [Grid Container](#grid-container), if you're within a `grid.container` then this item will always span the entire width of the viewport, whereas with `grid.paddedContainer` it will only span the area inside the margins.
68+
69+
<Source language="tsx" code={`
70+
import { css } from '@emotion/react';
71+
import { grid } from '../grid';
72+
73+
const ImmersiveHeader = () => (
74+
<header css={css(grid.container)}>
75+
<figure css={css(grid.column.all)}>
76+
Main media
77+
</figure>
78+
</header>
79+
);
80+
81+
const FrontContainer = () => (
82+
<section css={css(grid.paddedContainer)}>
83+
<article css={css(grid.column.all)}>
84+
First card
85+
</article>
86+
</section>
87+
);
88+
`} />
89+
90+
## Line API
91+
92+
While the [Column API](#column-api) covers many use cases, it is intentionally limited. In cases where designs call for more flexibility, such as crossing multiple layout columns, or ignoring them completely, a lower-level API is available for positioning elements across an arbitrary number of <CSSGridColumn />s.
93+
94+
A CSS grid layout automatically generates [lines](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Grid_layout_using_line-based_placement) with numerical indices between each grid column. The [grid containers](#grid-container) in this module also define a set of named grid lines based around the layout columns mentioned above. These are, from left to right: `grid-start`, `left-column-start`, `left-column-end`, `centre-column-start`, `centre-column-end`, `right-column-start`, `right-column-end`, and `grid-end`.
95+
96+
<Diagram viewBox="0 -100 1300 700">
97+
<text x="0" y="-70" fill="#d97700" style={lineTextStyles}>grid-start</text>
98+
<line x1="2" y1="-50" x2="2" y2="550" stroke-width="4" stroke="#d97700" />
99+
<text x="30" y="-20" fill="red" style={lineTextStyles}>left-column-start</text>
100+
<line x1="20" y1="-50" x2="20" y2="550" stroke-width="4" stroke="red" />
101+
<text x="65" y="535" fill="red" style={lineTextStyles}>left-column-end</text>
102+
<line x1="240" y1="-50" x2="240" y2="550" stroke-width="4" stroke="red" />
103+
<text x="270" y="-20" fill="green" style={lineTextStyles}>centre-column-start</text>
104+
<line x1="260" y1="-50" x2="260" y2="550" stroke-width="4" stroke="green" />
105+
<text x="670" y="535" fill="green" style={lineTextStyles}>centre-column-end</text>
106+
<line x1="880" y1="-50" x2="880" y2="550" stroke-width="4" stroke="green" />
107+
<text x="990" y="-20" fill="blue" style={lineTextStyles}>right-column-start</text>
108+
<line x1="980" y1="-50" x2="980" y2="550" stroke-width="4" stroke="blue" />
109+
<text x="1090" y="535" fill="blue" style={lineTextStyles}>right-column-end</text>
110+
<line x1="1280" y1="-50" x2="1280" y2="550" stroke-width="4" stroke="blue" />
111+
<line x1="1298" y1="-50" x2="1298" y2="550" stroke-width="4" stroke="#d97700" />
112+
<text x="1210" y="580" fill="#d97700" style={lineTextStyles}>grid-end</text>
113+
</Diagram>
114+
115+
export const lineTextStyles = {
116+
fontSize: 24,
117+
fontFamily: 'sans-serif',
118+
};
119+
120+
Note that, as mentioned above, not all of the layout columns exist at all breakpoints, and therefore not all of these named lines do either. You can use the [media queries API](https://guardian.github.io/storybooks/?path=/docs/source_foundations-media-queries--docs) from `@guardian/source` to specify which lines to use at different breakpoints.
121+
122+
To position an element between two grid lines, the `grid.between` function is available. It takes the line name or number at which the element should start, and the line name or number at which it should end. Alternatively, to have an element start at a particular line and span a certain number of <CSSGridColumn />s, the `grid.span` function is available. It takes the line name or number at which the element should start, and a number of columns to span.
123+
124+
<Source language="tsx" code={`
125+
import { css } from '@emotion/react';
126+
import { grid } from '../grid';
127+
128+
const ShowcaseHeader = () => (
129+
<header css={css(grid.paddedContainer)}>
130+
<figure css={css(
131+
grid.between('centre-column-start', 'right-column-end')
132+
)}>
133+
Main media
134+
</figure>
135+
</header>
136+
);
137+
138+
const GalleryHeader = () => (
139+
<header css={css(grid.container)}>
140+
<p css={css(grid.span('centre-column-start', 6))}>
141+
Standfirst
142+
</p>
143+
</header>
144+
);
145+
`} />
146+
147+
The functions in this part of the API correspond to features of the [`grid-column` CSS property](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column). While that property could be used directly, these functions allow for type-safety and auto-completion of the named grid lines.
148+
149+
{ /* Components used throughout this file */ }
150+
151+
export const CSSGridColumn = () => (
152+
<span style={{ backgroundColor: '#ddd', paddingLeft: 4, paddingRight: 4 }}>
153+
CSS grid column
154+
</span>
155+
);
156+
157+
export const LeftColumn = () => (
158+
<span style={{ color: 'red' }}>left column</span>
159+
);
160+
161+
export const CentreColumn = () => (
162+
<span style={{ color: 'green' }}>centre column</span>
163+
);
164+
165+
export const RightColumn = () => (
166+
<span style={{ color: 'blue' }}>right column</span>
167+
);
168+
169+
export const Diagram = ({ children, viewBox }) => (
170+
<svg viewBox={viewBox ?? "0 0 1300 500"} xmlns="http://www.w3.org/2000/svg">
171+
<defs>
172+
<rect id="grid-column" x="0" y="0" width="60" height="500" fill="#ddd" />
173+
</defs>
174+
<use href="#grid-column" x="20" />
175+
<use href="#grid-column" x="100" />
176+
<use href="#grid-column" x="180" />
177+
<use href="#grid-column" x="260" />
178+
<use href="#grid-column" x="340" />
179+
<use href="#grid-column" x="420" />
180+
<use href="#grid-column" x="500" />
181+
<use href="#grid-column" x="580" />
182+
<use href="#grid-column" x="660" />
183+
<use href="#grid-column" x="740" />
184+
<use href="#grid-column" x="820" />
185+
<use href="#grid-column" x="900" />
186+
<use href="#grid-column" x="980" />
187+
<use href="#grid-column" x="1060" />
188+
<use href="#grid-column" x="1140" />
189+
<use href="#grid-column" x="1220" />
190+
<rect x="20" y="2" width="220" height="496" stroke="red" stroke-width="4" fill="none" />
191+
<rect x="260" y="2" width="620" height="496" stroke="green" stroke-width="4" fill="none" />
192+
<rect x="980" y="2" width="300" height="496" stroke="blue" stroke-width="4" fill="none" />
193+
{children}
194+
</svg>
195+
);

dotcom-rendering/src/components/ArticleMeta.apps.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ export const ArticleMetaApps = ({
244244
const isAnalysis = format.design === ArticleDesign.Analysis;
245245
const isLiveBlog = format.design === ArticleDesign.LiveBlog;
246246
const isGallery = format.design === ArticleDesign.Gallery;
247+
const isVideo = format.design === ArticleDesign.Video;
247248

248249
const shouldShowFollowButtons = (layoutOrDesignType: boolean) =>
249250
layoutOrDesignType && !!byline && !isUndefined(soleContributor);
@@ -254,6 +255,9 @@ export const ArticleMetaApps = ({
254255
const isImmersiveOrAnalysisWithMultipleAuthors =
255256
(isAnalysis || isImmersive) && !!byline && isUndefined(soleContributor);
256257

258+
const shouldShowListenToArticleButton =
259+
!!pageId && !(isLiveBlog || isPicture || isGallery || isVideo);
260+
257261
return (
258262
<div
259263
className={
@@ -365,7 +369,7 @@ export const ArticleMetaApps = ({
365369
</MetaGridBranding>
366370
)}
367371
</div>
368-
{pageId !== undefined && (
372+
{shouldShowListenToArticleButton && (
369373
<Island priority="feature" defer={{ until: 'visible' }}>
370374
<ListenToArticle articleId={pageId} />
371375
</Island>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Meta, StoryObj } from '@storybook/react/*';
1+
import type { Meta, StoryObj } from '@storybook/react';
22
import { leftColumnDecorator } from '../../.storybook/decorators/gridDecorators';
33
import { defaultFormats } from '../../.storybook/decorators/splitThemeDecorator';
44
import { allModes } from '../../.storybook/modes';

dotcom-rendering/src/components/AuthProviderButtons/AuthProviderButtons.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ export const AuthProviderButtons = ({
173173
cssOverrides={secondaryButtonStyles()}
174174
priority="tertiary"
175175
href={buildUrlWithQueryParams(
176-
'https://profile.theguardian.com/register/email',
176+
'https://profile.theguardian.com/signin',
177177
{},
178178
queryParams,
179179
)}

dotcom-rendering/src/components/Card/Card.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -891,11 +891,11 @@ export const Card = ({
891891
>
892892
<LoopVideo
893893
src={media.mainMedia.videoId}
894+
atomId={media.mainMedia.atomId}
895+
uniqueId={uniqueId}
894896
height={media.mainMedia.height}
895897
width={media.mainMedia.width}
896-
image={media.mainMedia.image ?? ''}
897-
uniqueId={uniqueId}
898-
atomId={media.mainMedia.atomId}
898+
posterImage={media.mainMedia.image ?? ''}
899899
fallbackImage={media.mainMedia.image ?? ''}
900900
fallbackImageSize={imageSize}
901901
fallbackImageLoading={imageLoading}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Meta, StoryObj } from '@storybook/react/*';
1+
import type { Meta, StoryObj } from '@storybook/react';
22
import { allModes } from '../../.storybook/modes';
33
import { FootballTable as FootballTableComponent } from './FootballTable';
44

0 commit comments

Comments
 (0)