Skip to content
Merged
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
133 changes: 35 additions & 98 deletions dotcom-rendering/src/components/Masthead/HighlightsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ import { palette } from '../../palette';
import type { StarRating as Rating } from '../../types/content';
import type { DCRFrontImage } from '../../types/front';
import type { MainMedia } from '../../types/mainMedia';
import { Avatar } from '../Avatar';
import { CardLink } from '../Card/components/CardLink';
import { CardHeadline } from '../CardHeadline';
import type { Loading } from '../CardPicture';
import { CardPicture } from '../CardPicture';
import { FormatBoundary } from '../FormatBoundary';
import { Pill } from '../Pill';
import { StarRating } from '../StarRating/StarRating';
import { SvgMediaControlsPlay } from '../SvgMediaControlsPlay';
import { HighlightsCardImage } from './HighlightsCardImage';

export type HighlightsCardProps = {
linkTo: string;
Expand All @@ -35,7 +34,7 @@ export type HighlightsCardProps = {
starRating?: Rating;
};

const gridContainer = css`
const container = css`
display: grid;
background-color: ${palette('--highlights-container-background')};
/** Relative positioning is required to absolutely
Expand Down Expand Up @@ -132,90 +131,6 @@ const starWrapper = css`
align-self: flex-end;
`;

const decideImage = (
imageLoading: Loading,
image?: DCRFrontImage,
avatarUrl?: string,
byline?: string,
mainMedia?: MainMedia,
) => {
if (!image && !avatarUrl) {
return null;
}

if (avatarUrl) {
return (
<Avatar
src={avatarUrl}
alt={byline ?? ''}
shape="cutout"
imageSize="large"
/>
);
}

if (mainMedia?.type === 'Audio' && mainMedia.podcastImage?.src) {
return (
<>
<CardPicture
imageSize="medium"
mainImage={mainMedia.podcastImage.src}
alt={mainMedia.podcastImage.altText}
loading={imageLoading}
isCircular={false}
aspectRatio="1:1"
/>
<div className="image-overlay" />
</>
);
}

if (!image) {
return null;
}

return (
<>
<CardPicture
imageSize="highlights-card"
mainImage={image.src}
alt={image.altText}
loading={imageLoading}
isCircular={true}
aspectRatio="1:1"
/>
{/* This image overlay is styled when the CardLink is hovered */}
<div className="image-overlay circular" />
</>
);
};

const MediaPill = ({ mainMedia }: { mainMedia: MainMedia }) => (
<div css={mediaIcon}>
{mainMedia.type === 'Video' && (
<Pill
content={secondsToDuration(mainMedia.duration)}
prefix="Video"
icon={<SvgMediaControlsPlay width={18} />}
/>
)}
{mainMedia.type === 'Audio' && (
<Pill
content={mainMedia.duration}
prefix="Podcast"
icon={<SvgMediaControlsPlay width={18} />}
/>
)}
{mainMedia.type === 'Gallery' && (
<Pill
content={mainMedia.count}
prefix="Gallery"
icon={<SvgCamera />}
/>
)}
</div>
);

export const HighlightsCard = ({
linkTo,
format,
Expand All @@ -235,7 +150,7 @@ export const HighlightsCard = ({

return (
<FormatBoundary format={format}>
<div css={[gridContainer, hoverStyles]}>
<div css={[container, hoverStyles]}>
<CardLink
linkTo={linkTo}
headlineText={headlineText}
Expand Down Expand Up @@ -264,24 +179,46 @@ export const HighlightsCard = ({
/>
</div>

{!isUndefined(starRating) ? (
{!isUndefined(starRating) && (
<div css={starWrapper}>
<StarRating rating={starRating} size="small" />
</div>
) : null}
)}

{!!mainMedia && isMediaCard && (
<MediaPill mainMedia={mainMedia} />
<div css={mediaIcon}>
{mainMedia.type === 'Video' && (
<Pill
content={secondsToDuration(mainMedia.duration)}
prefix="Video"
icon={<SvgMediaControlsPlay width={18} />}
/>
)}
{mainMedia.type === 'Audio' && (
<Pill
content={mainMedia.duration}
prefix="Podcast"
icon={<SvgMediaControlsPlay width={18} />}
/>
)}
{mainMedia.type === 'Gallery' && (
<Pill
content={mainMedia.count}
prefix="Gallery"
icon={<SvgCamera />}
/>
)}
</div>
)}

<div css={[imageArea, avatarUrl && avatarAlignmentStyles]}>
{decideImage(
imageLoading,
image,
avatarUrl,
byline,
mainMedia,
)}
<HighlightsCardImage
imageLoading={imageLoading}
image={image}
avatarUrl={avatarUrl}
byline={byline}
mainMedia={mainMedia}
/>
</div>
</div>
</FormatBoundary>
Expand Down
67 changes: 67 additions & 0 deletions dotcom-rendering/src/components/Masthead/HighlightsCardImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import type { DCRFrontImage } from '../../types/front';
import type { MainMedia } from '../../types/mainMedia';
import { Avatar } from '../Avatar';
import type { Loading } from '../CardPicture';
import { CardPicture } from '../CardPicture';

type Props = {
imageLoading: Loading;
image?: DCRFrontImage;
avatarUrl?: string;
byline?: string;
mainMedia?: MainMedia;
};

export const HighlightsCardImage = ({
imageLoading,
image,
avatarUrl,
byline,
mainMedia,
}: Props) => {
if (avatarUrl) {
return (
<Avatar
src={avatarUrl}
alt={byline ?? ''}
shape="cutout"
imageSize="large"
/>
);
}

if (image) {
if (mainMedia?.type === 'Audio' && mainMedia.podcastImage?.src) {
return (
<>
<CardPicture
imageSize="medium"
mainImage={mainMedia.podcastImage.src}
alt={mainMedia.podcastImage.altText}
loading={imageLoading}
isCircular={false}
aspectRatio="1:1"
/>
<div className="image-overlay" />
</>
);
}

return (
<>
<CardPicture
imageSize="highlights-card"
mainImage={image.src}
alt={image.altText}
loading={imageLoading}
isCircular={true}
aspectRatio="1:1"
/>
{/* This image overlay is styled when the CardLink is hovered */}
<div className="image-overlay circular" />
</>
);
}

return null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,15 @@ const carouselStyles = css`
scroll-padding-left: 240px;
}
${from.leftCol} {
scroll-padding-left: 80px;
scroll-padding-left: 160px;
padding-left: 160px;
}

${from.wide} {
scroll-padding-left: 240px;
padding-left: 240px;
}

/**
* Hide scrollbars
* See: https://stackoverflow.com/a/38994837
Expand All @@ -73,22 +76,11 @@ const itemStyles = css`
${from.tablet} {
margin-left: 0;
}

/**
* From left col we add space to the left margin to the first
* child so that the first card in the carousel aligns
* with the start of the pages content in the grid.
*/
${from.leftCol} {
padding-left: 160px; /** 160 === 2 columns and 2 column gaps */
}
${from.wide} {
padding-left: 0;
margin-left: 240px; /** 240 === 3 columns and 3 column gaps */
}
}
:last-child {
margin-right: 0;
${from.tablet} {
margin-right: 0;
}
}
`;

Expand Down Expand Up @@ -196,6 +188,7 @@ export const ScrollableHighlights = ({ trails, frontId }: Props) => {
const cardWidth =
carouselRef.current.querySelector('li')?.offsetWidth ?? 0;
const offset = direction === 'left' ? -cardWidth : cardWidth;

carouselRef.current.scrollBy({
left: offset,
behavior: 'smooth',
Expand Down
6 changes: 1 addition & 5 deletions dotcom-rendering/src/paletteDeclarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4347,15 +4347,11 @@ const linkKickerTextLight: PaletteFunction = ({ design, theme }) => {
const linkKickerTextDark: PaletteFunction = ({ theme }) => {
switch (theme) {
case Pillar.News:
return sourcePalette.news[500];
case Pillar.Opinion:
return sourcePalette.opinion[500];
case Pillar.Sport:
return sourcePalette.sport[500];
case Pillar.Culture:
return sourcePalette.culture[500];
case Pillar.Lifestyle:
return sourcePalette.lifestyle[500];
return pillarPalette(theme, 500);
case ArticleSpecial.SpecialReport:
return sourcePalette.news[500];
case ArticleSpecial.Labs:
Expand Down