Skip to content

Commit 9d74d6f

Browse files
authored
Merge pull request #14298 from guardian/doml/scrollable-highlights-refactor
Update Scrollable Highlights scroll behaviour at large screens
2 parents f91ac7b + c0684f5 commit 9d74d6f

File tree

4 files changed

+111
-118
lines changed

4 files changed

+111
-118
lines changed

dotcom-rendering/src/components/Masthead/HighlightsCard.tsx

Lines changed: 35 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,14 @@ import { palette } from '../../palette';
99
import type { StarRating as Rating } from '../../types/content';
1010
import type { DCRFrontImage } from '../../types/front';
1111
import type { MainMedia } from '../../types/mainMedia';
12-
import { Avatar } from '../Avatar';
1312
import { CardLink } from '../Card/components/CardLink';
1413
import { CardHeadline } from '../CardHeadline';
1514
import type { Loading } from '../CardPicture';
16-
import { CardPicture } from '../CardPicture';
1715
import { FormatBoundary } from '../FormatBoundary';
1816
import { Pill } from '../Pill';
1917
import { StarRating } from '../StarRating/StarRating';
2018
import { SvgMediaControlsPlay } from '../SvgMediaControlsPlay';
19+
import { HighlightsCardImage } from './HighlightsCardImage';
2120

2221
export type HighlightsCardProps = {
2322
linkTo: string;
@@ -35,7 +34,7 @@ export type HighlightsCardProps = {
3534
starRating?: Rating;
3635
};
3736

38-
const gridContainer = css`
37+
const container = css`
3938
display: grid;
4039
background-color: ${palette('--highlights-container-background')};
4140
/** Relative positioning is required to absolutely
@@ -132,90 +131,6 @@ const starWrapper = css`
132131
align-self: flex-end;
133132
`;
134133

135-
const decideImage = (
136-
imageLoading: Loading,
137-
image?: DCRFrontImage,
138-
avatarUrl?: string,
139-
byline?: string,
140-
mainMedia?: MainMedia,
141-
) => {
142-
if (!image && !avatarUrl) {
143-
return null;
144-
}
145-
146-
if (avatarUrl) {
147-
return (
148-
<Avatar
149-
src={avatarUrl}
150-
alt={byline ?? ''}
151-
shape="cutout"
152-
imageSize="large"
153-
/>
154-
);
155-
}
156-
157-
if (mainMedia?.type === 'Audio' && mainMedia.podcastImage?.src) {
158-
return (
159-
<>
160-
<CardPicture
161-
imageSize="medium"
162-
mainImage={mainMedia.podcastImage.src}
163-
alt={mainMedia.podcastImage.altText}
164-
loading={imageLoading}
165-
isCircular={false}
166-
aspectRatio="1:1"
167-
/>
168-
<div className="image-overlay" />
169-
</>
170-
);
171-
}
172-
173-
if (!image) {
174-
return null;
175-
}
176-
177-
return (
178-
<>
179-
<CardPicture
180-
imageSize="highlights-card"
181-
mainImage={image.src}
182-
alt={image.altText}
183-
loading={imageLoading}
184-
isCircular={true}
185-
aspectRatio="1:1"
186-
/>
187-
{/* This image overlay is styled when the CardLink is hovered */}
188-
<div className="image-overlay circular" />
189-
</>
190-
);
191-
};
192-
193-
const MediaPill = ({ mainMedia }: { mainMedia: MainMedia }) => (
194-
<div css={mediaIcon}>
195-
{mainMedia.type === 'Video' && (
196-
<Pill
197-
content={secondsToDuration(mainMedia.duration)}
198-
prefix="Video"
199-
icon={<SvgMediaControlsPlay width={18} />}
200-
/>
201-
)}
202-
{mainMedia.type === 'Audio' && (
203-
<Pill
204-
content={mainMedia.duration}
205-
prefix="Podcast"
206-
icon={<SvgMediaControlsPlay width={18} />}
207-
/>
208-
)}
209-
{mainMedia.type === 'Gallery' && (
210-
<Pill
211-
content={mainMedia.count}
212-
prefix="Gallery"
213-
icon={<SvgCamera />}
214-
/>
215-
)}
216-
</div>
217-
);
218-
219134
export const HighlightsCard = ({
220135
linkTo,
221136
format,
@@ -235,7 +150,7 @@ export const HighlightsCard = ({
235150

236151
return (
237152
<FormatBoundary format={format}>
238-
<div css={[gridContainer, hoverStyles]}>
153+
<div css={[container, hoverStyles]}>
239154
<CardLink
240155
linkTo={linkTo}
241156
headlineText={headlineText}
@@ -264,24 +179,46 @@ export const HighlightsCard = ({
264179
/>
265180
</div>
266181

267-
{!isUndefined(starRating) ? (
182+
{!isUndefined(starRating) && (
268183
<div css={starWrapper}>
269184
<StarRating rating={starRating} size="small" />
270185
</div>
271-
) : null}
186+
)}
272187

273188
{!!mainMedia && isMediaCard && (
274-
<MediaPill mainMedia={mainMedia} />
189+
<div css={mediaIcon}>
190+
{mainMedia.type === 'Video' && (
191+
<Pill
192+
content={secondsToDuration(mainMedia.duration)}
193+
prefix="Video"
194+
icon={<SvgMediaControlsPlay width={18} />}
195+
/>
196+
)}
197+
{mainMedia.type === 'Audio' && (
198+
<Pill
199+
content={mainMedia.duration}
200+
prefix="Podcast"
201+
icon={<SvgMediaControlsPlay width={18} />}
202+
/>
203+
)}
204+
{mainMedia.type === 'Gallery' && (
205+
<Pill
206+
content={mainMedia.count}
207+
prefix="Gallery"
208+
icon={<SvgCamera />}
209+
/>
210+
)}
211+
</div>
275212
)}
276213

277214
<div css={[imageArea, avatarUrl && avatarAlignmentStyles]}>
278-
{decideImage(
279-
imageLoading,
280-
image,
281-
avatarUrl,
282-
byline,
283-
mainMedia,
284-
)}
215+
<HighlightsCardImage
216+
imageLoading={imageLoading}
217+
image={image}
218+
avatarUrl={avatarUrl}
219+
byline={byline}
220+
mainMedia={mainMedia}
221+
/>
285222
</div>
286223
</div>
287224
</FormatBoundary>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import type { DCRFrontImage } from '../../types/front';
2+
import type { MainMedia } from '../../types/mainMedia';
3+
import { Avatar } from '../Avatar';
4+
import type { Loading } from '../CardPicture';
5+
import { CardPicture } from '../CardPicture';
6+
7+
type Props = {
8+
imageLoading: Loading;
9+
image?: DCRFrontImage;
10+
avatarUrl?: string;
11+
byline?: string;
12+
mainMedia?: MainMedia;
13+
};
14+
15+
export const HighlightsCardImage = ({
16+
imageLoading,
17+
image,
18+
avatarUrl,
19+
byline,
20+
mainMedia,
21+
}: Props) => {
22+
if (avatarUrl) {
23+
return (
24+
<Avatar
25+
src={avatarUrl}
26+
alt={byline ?? ''}
27+
shape="cutout"
28+
imageSize="large"
29+
/>
30+
);
31+
}
32+
33+
if (image) {
34+
if (mainMedia?.type === 'Audio' && mainMedia.podcastImage?.src) {
35+
return (
36+
<>
37+
<CardPicture
38+
imageSize="medium"
39+
mainImage={mainMedia.podcastImage.src}
40+
alt={mainMedia.podcastImage.altText}
41+
loading={imageLoading}
42+
isCircular={false}
43+
aspectRatio="1:1"
44+
/>
45+
<div className="image-overlay" />
46+
</>
47+
);
48+
}
49+
50+
return (
51+
<>
52+
<CardPicture
53+
imageSize="highlights-card"
54+
mainImage={image.src}
55+
alt={image.altText}
56+
loading={imageLoading}
57+
isCircular={true}
58+
aspectRatio="1:1"
59+
/>
60+
{/* This image overlay is styled when the CardLink is hovered */}
61+
<div className="image-overlay circular" />
62+
</>
63+
);
64+
}
65+
66+
return null;
67+
};

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

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,15 @@ const carouselStyles = css`
4747
scroll-padding-left: 240px;
4848
}
4949
${from.leftCol} {
50-
scroll-padding-left: 80px;
50+
scroll-padding-left: 160px;
51+
padding-left: 160px;
5152
}
5253
5354
${from.wide} {
5455
scroll-padding-left: 240px;
56+
padding-left: 240px;
5557
}
58+
5659
/**
5760
* Hide scrollbars
5861
* See: https://stackoverflow.com/a/38994837
@@ -73,22 +76,11 @@ const itemStyles = css`
7376
${from.tablet} {
7477
margin-left: 0;
7578
}
76-
77-
/**
78-
* From left col we add space to the left margin to the first
79-
* child so that the first card in the carousel aligns
80-
* with the start of the pages content in the grid.
81-
*/
82-
${from.leftCol} {
83-
padding-left: 160px; /** 160 === 2 columns and 2 column gaps */
84-
}
85-
${from.wide} {
86-
padding-left: 0;
87-
margin-left: 240px; /** 240 === 3 columns and 3 column gaps */
88-
}
8979
}
9080
:last-child {
91-
margin-right: 0;
81+
${from.tablet} {
82+
margin-right: 0;
83+
}
9284
}
9385
`;
9486

@@ -196,6 +188,7 @@ export const ScrollableHighlights = ({ trails, frontId }: Props) => {
196188
const cardWidth =
197189
carouselRef.current.querySelector('li')?.offsetWidth ?? 0;
198190
const offset = direction === 'left' ? -cardWidth : cardWidth;
191+
199192
carouselRef.current.scrollBy({
200193
left: offset,
201194
behavior: 'smooth',

dotcom-rendering/src/paletteDeclarations.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4347,15 +4347,11 @@ const linkKickerTextLight: PaletteFunction = ({ design, theme }) => {
43474347
const linkKickerTextDark: PaletteFunction = ({ theme }) => {
43484348
switch (theme) {
43494349
case Pillar.News:
4350-
return sourcePalette.news[500];
43514350
case Pillar.Opinion:
4352-
return sourcePalette.opinion[500];
43534351
case Pillar.Sport:
4354-
return sourcePalette.sport[500];
43554352
case Pillar.Culture:
4356-
return sourcePalette.culture[500];
43574353
case Pillar.Lifestyle:
4358-
return sourcePalette.lifestyle[500];
4354+
return pillarPalette(theme, 500);
43594355
case ArticleSpecial.SpecialReport:
43604356
return sourcePalette.news[500];
43614357
case ArticleSpecial.Labs:

0 commit comments

Comments
 (0)