Skip to content

Commit 75c91f0

Browse files
authored
Merge pull request #13421 from guardian/doml/align-opinion-meta
Align Opinion Card Avatars
2 parents 624eb9e + 056f1a4 commit 75c91f0

File tree

3 files changed

+108
-53
lines changed

3 files changed

+108
-53
lines changed

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

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,11 @@ import { AvatarContainer } from './components/AvatarContainer';
5151
import { CardAge } from './components/CardAge';
5252
import { CardBranding } from './components/CardBranding';
5353
import { CardFooter } from './components/CardFooter';
54-
import { CardLayout, type GapSizes } from './components/CardLayout';
54+
import {
55+
CardLayout,
56+
decideAvatarPosition,
57+
type GapSizes,
58+
} from './components/CardLayout';
5559
import { CardLink } from './components/CardLink';
5660
import { CardWrapper } from './components/CardWrapper';
5761
import { ContentWrapper } from './components/ContentWrapper';
@@ -553,11 +557,22 @@ export const Card = ({
553557
isBetaContainer,
554558
});
555559

556-
// For opinion type cards with avatars (which aren't onwards content)
557-
// we render the footer in a different location
558-
const showCommentFooter =
560+
/**
561+
* For opinion type cards with avatars (which aren't onwards content)
562+
* we render the footer in a different location
563+
*/
564+
const isOpinionCardWithAvatar =
559565
isOpinion && !isOnwardContent && media?.type === 'avatar';
560566

567+
/**
568+
* The avatar position is not always the same as the image position.
569+
*/
570+
const avatarPosition = decideAvatarPosition(
571+
imagePositionOnMobile,
572+
imagePositionOnDesktop,
573+
isBetaContainer,
574+
);
575+
561576
/**
562577
- * Media cards have contrasting background colours. We add additional
563578
* padding to these cards to keep the text readable.
@@ -1107,7 +1122,7 @@ export const Card = ({
11071122
/>
11081123
)}
11091124

1110-
{!showCommentFooter && (
1125+
{!isOpinionCardWithAvatar && (
11111126
<>
11121127
{showPill ? (
11131128
<>
@@ -1231,7 +1246,7 @@ export const Card = ({
12311246
)}
12321247
{decideOuterSublinks()}
12331248

1234-
{showCommentFooter && (
1249+
{isOpinionCardWithAvatar && (
12351250
<CardFooter
12361251
format={format}
12371252
age={decideAge()}
@@ -1245,6 +1260,10 @@ export const Card = ({
12451260
) : undefined
12461261
}
12471262
showLivePlayable={showLivePlayable}
1263+
shouldReserveSpace={{
1264+
mobile: avatarPosition.mobile === 'bottom',
1265+
desktop: avatarPosition.desktop === 'bottom',
1266+
}}
12481267
/>
12491268
)}
12501269
</div>

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

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { css } from '@emotion/react';
2-
import { palette, space, textSansBold12 } from '@guardian/source/foundations';
2+
import {
3+
from,
4+
palette,
5+
space,
6+
textSansBold12,
7+
} from '@guardian/source/foundations';
38
import { SvgCamera } from '@guardian/source/react-components';
49
import { Pill } from '../../../components/Pill';
510
import { SvgMediaControlsPlay } from '../../../components/SvgMediaControlsPlay';
@@ -35,6 +40,14 @@ const contentStyles = css`
3540
}
3641
`;
3742

43+
const reserveSpaceStyles = (mobile: boolean, desktop: boolean) => css`
44+
min-height: ${mobile ? '14px' : 0};
45+
46+
${from.tablet} {
47+
min-height: ${desktop ? '14px' : 0};
48+
}
49+
`;
50+
3851
const labStyles = css`
3952
margin-top: ${space[1]}px;
4053
`;
@@ -51,6 +64,7 @@ type Props = {
5164
commentCount?: JSX.Element;
5265
cardBranding?: JSX.Element;
5366
mainMedia?: MainMedia;
67+
shouldReserveSpace?: { mobile: boolean; desktop: boolean };
5468
};
5569

5670
export const CardFooter = ({
@@ -60,6 +74,7 @@ export const CardFooter = ({
6074
commentCount,
6175
cardBranding,
6276
mainMedia,
77+
shouldReserveSpace,
6378
}: Props) => {
6479
if (showLivePlayable) return null;
6580

@@ -104,12 +119,17 @@ export const CardFooter = ({
104119
);
105120
}
106121

107-
if (age === undefined && commentCount === undefined) {
108-
return null;
109-
}
110-
111122
return (
112-
<footer css={contentStyles}>
123+
<footer
124+
css={[
125+
contentStyles,
126+
shouldReserveSpace &&
127+
reserveSpaceStyles(
128+
shouldReserveSpace.mobile,
129+
shouldReserveSpace.desktop,
130+
),
131+
]}
132+
>
113133
{age}
114134
{commentCount}
115135
</footer>

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

Lines changed: 57 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -65,70 +65,86 @@ const minWidth = (minWidthInPixels?: number) => {
6565
* position for desktop and mobile are both set to `bottom` to avoid affecting
6666
* existing layouts where the default position values are relied upon.
6767
*/
68-
const decideDirection = (
68+
export const decideAvatarPosition = (
6969
imagePositionOnMobile: ImagePositionType,
7070
imagePositionOnDesktop: ImagePositionType,
7171
isBetaContainer: boolean,
72-
hasAvatar?: boolean,
73-
) => {
74-
const imagePosition = {
75-
top: 'column',
76-
bottom: 'column-reverse',
77-
left: 'row',
78-
right: 'row-reverse',
79-
none: 'column',
80-
};
81-
if (hasAvatar) {
82-
if (
83-
imagePositionOnMobile === 'bottom' &&
84-
imagePositionOnDesktop === 'bottom'
85-
) {
86-
return {
87-
mobile: imagePosition['bottom'],
88-
desktop: imagePosition['bottom'],
89-
};
90-
}
72+
): { mobile: ImagePositionType; desktop: ImagePositionType } => {
73+
if (
74+
imagePositionOnMobile === 'bottom' &&
75+
imagePositionOnDesktop === 'bottom'
76+
) {
77+
return {
78+
mobile: 'bottom',
79+
desktop: 'bottom',
80+
};
81+
}
9182

92-
if (
93-
imagePositionOnDesktop === 'left' ||
94-
imagePositionOnDesktop === 'right'
95-
) {
96-
if (isBetaContainer && imagePositionOnMobile === 'bottom') {
97-
return {
98-
mobile: imagePosition['bottom'],
99-
desktop: imagePosition['right'],
100-
};
101-
}
83+
if (
84+
imagePositionOnDesktop === 'left' ||
85+
imagePositionOnDesktop === 'right'
86+
) {
87+
if (isBetaContainer && imagePositionOnMobile === 'bottom') {
10288
return {
103-
mobile: imagePosition['right'],
104-
desktop: imagePosition['right'],
89+
mobile: 'bottom',
90+
desktop: 'right',
10591
};
10692
}
93+
return {
94+
mobile: 'right',
95+
desktop: 'right',
96+
};
97+
}
98+
99+
return {
100+
mobile: 'right',
101+
desktop: 'bottom',
102+
};
103+
};
104+
105+
const imagePositionMap = {
106+
top: 'column',
107+
bottom: 'column-reverse',
108+
left: 'row',
109+
right: 'row-reverse',
110+
none: 'column',
111+
};
107112

108-
// Default case for avatar: Mobile right, Desktop bottom
113+
const decideFlexDirection = (
114+
imagePositionOnMobile: ImagePositionType,
115+
imagePositionOnDesktop: ImagePositionType,
116+
isBetaContainer: boolean,
117+
hasAvatar?: boolean,
118+
) => {
119+
if (!hasAvatar) {
109120
return {
110-
mobile: imagePosition['right'],
111-
desktop: imagePosition['bottom'],
121+
mobile: imagePositionMap[imagePositionOnMobile],
122+
desktop: imagePositionMap[imagePositionOnDesktop],
112123
};
113124
}
114125

115-
// Handle cases without an avatar
126+
const { mobile, desktop } = decideAvatarPosition(
127+
imagePositionOnMobile,
128+
imagePositionOnDesktop,
129+
isBetaContainer,
130+
);
131+
116132
return {
117-
mobile: imagePosition[imagePositionOnMobile],
118-
desktop: imagePosition[imagePositionOnDesktop],
133+
mobile: imagePositionMap[mobile],
134+
desktop: imagePositionMap[desktop],
119135
};
120136
};
121137

122138
const decidePosition = (
123139
imagePositionOnMobile: ImagePositionType,
124140
imagePositionOnDesktop: ImagePositionType,
125-
isFairgroundContainer: boolean,
141+
isBetaContainer: boolean,
126142
hasAvatar?: boolean,
127143
) => {
128-
const { mobile, desktop } = decideDirection(
144+
const { mobile, desktop } = decideFlexDirection(
129145
imagePositionOnMobile,
130146
imagePositionOnDesktop,
131-
isFairgroundContainer,
147+
isBetaContainer,
132148
hasAvatar,
133149
);
134150

0 commit comments

Comments
 (0)