Skip to content

Commit

Permalink
Card image/description independent of hero image/description (#1244)
Browse files Browse the repository at this point in the history
**Related Ticket:**
US-GHG-Center/veda-config-ghg#636

### Description of Changes

1. Introduced new `cardDescription` and `cardMedia` props to enable
customizable card content
2. Implemented a fallback background color for cases where no media (e.g
image source) is provided

These updates are applied across various places where the card component
is used (story cards) but also layer cards in the Data Catalog and the
E&A Catalog to better control displayed descriptions and images.

### Notes & Questions About Changes

### Validation / Testing

1. Add `cardDescription` to the 'This is the life of water' story in the
MDX configuration file
2. Verify that `/stories` displays the newly added `cardDescription` on
the card
3. Click on the story -> verify that the hero section retains its
previous description, separate from the card description
4. Try the same with `cardMedia`
5. Also try to remove both the `cardMedia` and the `media` prop ->
verify that there's a fallback background color shown

Verify that the behavior below (copied from the issues' acceptance
criteria) is applied:

1. Story and dataset administrators can define a hero image and a card
image separately from one another, within the mdx file
2. Story and dataset administrators can define a hero description and a
card description separately from one another, within the mdx file
3. If a story or dataset does not have any hero or card images
configured, then we default to a blank space of a solid primary color
(like the blue hero for Data Catalog in GHGC)
4. If a story or dataset has a hero image defined, but no card image
defined, then the card image shows the hero image (like how it currently
functions)
  • Loading branch information
dzole0311 authored Nov 11, 2024
2 parents adb8741 + 842216d commit 2c7561f
Show file tree
Hide file tree
Showing 12 changed files with 706 additions and 320 deletions.
43 changes: 17 additions & 26 deletions app/scripts/components/common/card/horizontal-info-card.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import React from 'react';
import styled, { css } from 'styled-components';
import {
glsp,
themeVal,
} from '@devseed-ui/theme-provider';
import { glsp, themeVal } from '@devseed-ui/theme-provider';
import { CardTitle } from './styles';
import { variableBaseType } from '$styles/variable-utils';
import { Pill } from '$styles/pill';
Expand All @@ -17,6 +14,8 @@ const CardImage = styled.div`
min-width: 10rem;
width: 10rem;
height: 100%;
background: ${themeVal('color.primary-100')};
img {
width: 100%;
height: 100%;
Expand Down Expand Up @@ -48,8 +47,8 @@ export const HorizontalCardStyles = css`
/* stylelint-disable-next-line value-no-vendor-prefix */
display: -webkit-box;
-webkit-line-clamp: 2; /* number of lines to show */
line-clamp: 2;
line-clamp: 2;
/* stylelint-disable-next-line property-no-vendor-prefix */
-webkit-box-orient: vertical;
}
Expand All @@ -70,36 +69,28 @@ interface Props {
}

export default function HorizontalInfoCard(props: Props) {
const {
title,
description,
imgSrc,
imgAlt,
tagLabels,
} = props;
const { title, description, imgSrc, imgAlt, tagLabels } = props;

return (
<HorizontalCard>
<CardImage>
<img src={imgSrc} alt={imgAlt} loading='lazy' />
{imgSrc && <img src={imgSrc} alt={imgAlt} loading='lazy' />}
</CardImage>
<CardContent>
<CardTitle>{title}</CardTitle>
<div id='description'>
<p>{description}</p>
</div>
<div id='tags'>
{
tagLabels && (
tagLabels.map((label) => (
<Pill variation='primary' key={label}>
{label}
</Pill>
))
)
}
</div>
{tagLabels && tagLabels.length > 0 && (
<div id='tags'>
{tagLabels.map((label) => (
<Pill variation='primary' key={label}>
{label}
</Pill>
))}
</div>
)}
</CardContent>
</HorizontalCard>
);
}
}
137 changes: 75 additions & 62 deletions app/scripts/components/common/card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,21 @@ import {
media,
multiply,
themeVal,
listReset,
listReset
} from '@devseed-ui/theme-provider';
const SmartLink = lazy(() => import('../smart-link'));

import { CardBody, CardBlank, CardHeader, CardHeadline, CardTitle, CardOverline } from './styles';
import HorizontalInfoCard, { HorizontalCardStyles } from './horizontal-info-card';
import {
CardBody,
CardBlank,
CardHeader,
CardHeadline,
CardTitle,
CardOverline
} from './styles';
import HorizontalInfoCard, {
HorizontalCardStyles
} from './horizontal-info-card';
import { variableBaseType, variableGlsp } from '$styles/variable-utils';
import { ElementInteractive } from '$components/common/element-interactive';
import { Figure } from '$components/common/figure';
Expand Down Expand Up @@ -175,15 +184,17 @@ const CardLabel = styled.span`
}
`;


const CardFigure = styled(Figure)`
order: -1;
background: ${themeVal('color.primary-100')};
min-height: ${variableGlsp(12)};
img {
height: 100%;
width: 100%;
object-fit: cover;
mix-blend-mode: multiply;
display: ${(props) => (props.src ? 'inline-block' : 'none')};
}
`;

Expand Down Expand Up @@ -259,8 +270,10 @@ export interface CardComponentProps extends CardComponentBaseProps {
type CardComponentPropsType = CardComponentProps | CardComponentPropsDeprecated;

// Type guard to check if props has linkProperties
function hasLinkProperties(props: CardComponentPropsType): props is CardComponentProps {
return !!((props as CardComponentProps).linkProperties);
function hasLinkProperties(
props: CardComponentPropsType
): props is CardComponentProps {
return !!(props as CardComponentProps).linkProperties;
}

function CardComponent(props: CardComponentPropsType) {
Expand All @@ -280,8 +293,8 @@ function CardComponent(props: CardComponentPropsType) {
hideExternalLinkBadge,
onCardClickCapture
} = props;
// @TODO: This process is not necessary once all the instances adapt the linkProperties syntax
// Consolidate them to use LinkProperties only
// @TODO: This process is not necessary once all the instances adapt the linkProperties syntax
// Consolidate them to use LinkProperties only
let linkProperties: LinkWithPathProperties;

if (hasLinkProperties(props)) {
Expand Down Expand Up @@ -313,64 +326,64 @@ function CardComponent(props: CardComponentPropsType) {
linkLabel={linkLabel ?? 'View more'}
onClickCapture={onCardClickCapture}
>
{
cardType !== 'horizontal-info' && (
<>
<CardHeader>
<CardHeadline>
<CardTitle>{title}</CardTitle>
<CardOverline as='div'>
{(hideExternalLinkBadge !== true && isExternalLink) && <ExternalLinkFlag />}
{!isExternalLink && tagLabels && parentTo && (
tagLabels.map((label) => (
<CardLabel as={linkProperties.LinkElement} to={parentTo} key={label}>
{label}
</CardLabel>
))
)}
{date ? (
<>
published on{' '}
<time dateTime={format(date, 'yyyy-MM-dd')}>
{format(date, 'MMM d, yyyy')}
</time>
</>
) : (
overline
)}
</CardOverline>
</CardHeadline>
</CardHeader>
{description && (
<CardBody>
<p>{description}</p>
</CardBody>
)}
{footerContent && <CardFooter>{footerContent}</CardFooter>}
{imgSrc && (
<CardFigure>
<img src={imgSrc} alt={imgAlt} loading='lazy' />
</CardFigure>
)}
</>
)
}
{
cardType === 'horizontal-info' && (
<HorizontalInfoCard
title={title}
description={description}
imgSrc={imgSrc}
imgAlt={imgAlt}
tagLabels={tagLabels}
/>
)
}
{cardType !== 'horizontal-info' && (
<>
<CardHeader>
<CardHeadline>
<CardTitle>{title}</CardTitle>
<CardOverline as='div'>
{hideExternalLinkBadge !== true && isExternalLink && (
<ExternalLinkFlag />
)}
{!isExternalLink &&
tagLabels &&
parentTo &&
tagLabels.map((label) => (
<CardLabel
as={linkProperties.LinkElement}
to={parentTo}
key={label}
>
{label}
</CardLabel>
))}
{date ? (
<>
published on{' '}
<time dateTime={format(date, 'yyyy-MM-dd')}>
{format(date, 'MMM d, yyyy')}
</time>
</>
) : (
overline
)}
</CardOverline>
</CardHeadline>
</CardHeader>
{description && (
<CardBody>
<p>{description}</p>
</CardBody>
)}
{footerContent && <CardFooter>{footerContent}</CardFooter>}
<CardFigure src={imgSrc}>
<img src={imgSrc} alt={imgAlt} loading='lazy' />
</CardFigure>
</>
)}
{cardType === 'horizontal-info' && (
<HorizontalInfoCard
title={title}
description={description}
imgSrc={imgSrc}
imgAlt={imgAlt}
tagLabels={tagLabels}
/>
)}
</ElementInteractive>
);
}

export const Card = styled(CardComponent)`
/* Convert to styled-component: https://styled-components.com/docs/advanced#caveat */
`;

Loading

0 comments on commit 2c7561f

Please sign in to comment.