Skip to content

Commit

Permalink
OPHJOD-1198: Update MediaCard
Browse files Browse the repository at this point in the history
  • Loading branch information
ketsappi committed Jan 16, 2025
1 parent 9ced7fd commit 2680767
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 77 deletions.
56 changes: 26 additions & 30 deletions lib/components/MediaCard/MediaCard.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react';

import { useState } from '@storybook/preview-api';
import { fn } from '@storybook/test';
import { MediaCard } from './MediaCard';

const meta = {
Expand All @@ -12,15 +14,19 @@ export default meta;

type Story = StoryObj<typeof meta>;

export const Vertical: Story = {
export const Default: Story = {
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/design/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=2217-8529',
},
docs: {
description: {
story: 'MediaCard where there is no favorite-button available',
},
},
},
args: {
variant: 'vertical',
imageSrc: 'https://images.unsplash.com/photo-1523464862212-d6631d073194?q=80&w=260?q=80&w=260',
imageAlt: 'Woman standing in front of a colourful wall',
label: 'Tulevaisuusmatka',
Expand All @@ -29,47 +35,37 @@ export const Vertical: Story = {
},
};

export const Horizontal: Story = {
export const AbleToBeFavorited: Story = {
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/design/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=2217-8529',
docs: {
description: {
story: 'MediaCard where the favorite status can be toggled.',
},
},
},
args: {
variant: 'horizontal',
imageSrc: 'https://images.unsplash.com/photo-1523464862212-d6631d073194?q=80&w=260',
imageAlt: 'Woman standing in front of a colourful wall',
label: 'Tulevaisuusmatka',
description: 'Tulevaisuusmatka on koulutus, joka auttaa sinua löytämään oman polkusi ja tavoitteesi.',
tags: ['Taglorem', 'Loremtag', 'Nonutag'],
},
};

export const VerticalWithRating: Story = {
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/design/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=2217-8529',
},
},
argTypes: {
rating: {
control: {
type: 'range',
min: 0,
max: 5,
step: 1,
},
},
render: (args) => {
const [isFavorite, setFavorite] = useState(true);
return (
<MediaCard
{...args}
favoriteLabel={isFavorite ? 'Poista suosikeista' : 'Lisää suosikkeihin'}
isFavorite={isFavorite}
onFavoriteClick={() => setFavorite(!isFavorite)}
/>
);
},
args: {
rating: 3,
variant: 'vertical',
imageSrc: 'https://images.unsplash.com/photo-1523464862212-d6631d073194?q=80&w=260?q=80&w=260',
imageAlt: 'Woman standing in front of a colourful wall',
label: 'Tulevaisuusmatka',
description: 'Tulevaisuusmatka on koulutus, joka auttaa sinua löytämään oman polkusi ja tavoitteesi.',
tags: ['Taglorem', 'Loremtag', 'Nonutag'],
isFavorite: true,
onFavoriteClick: fn(),
favoriteLabel: 'Poista suosikeista',
},
};
2 changes: 0 additions & 2 deletions lib/components/MediaCard/MediaCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ describe('MediaCard', () => {
it('renders the MediaCard component with vertical variant', () => {
render(
<MediaCard
variant="vertical"
imageSrc="vertical.jpg"
imageAlt="Image for the vertical"
label="Vertical"
Expand All @@ -25,7 +24,6 @@ describe('MediaCard', () => {
it('renders the MediaCard component with horizontal variant', () => {
render(
<MediaCard
variant="horizontal"
imageSrc="horizontal.jpg"
imageAlt="Image for horizontal"
label="Horizontal"
Expand Down
80 changes: 36 additions & 44 deletions lib/components/MediaCard/MediaCard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import { MdOutlineStar } from 'react-icons/md';
import { cx } from '../../cva';

type Variant = 'vertical' | 'horizontal';
import { MdFavorite, MdFavoriteBorder } from 'react-icons/md';

type LinkComponent =
| {
Expand All @@ -17,31 +14,26 @@ type LinkComponent =
linkComponent?: never;
};

type FavoriteButtonProps =
| {
isFavorite?: never;
onFavoriteClick?: never;
favoriteLabel?: never;
}
| {
isFavorite: boolean;
onFavoriteClick: () => void;
favoriteLabel: string;
};

export type MediaCardProps = {
variant?: Variant;
imageSrc: string;
imageAlt: string;
label: string;
description: string;
tags: string[];
/** Rating between 0-5*/
rating?: number;
ratingAriaLabel?: string;
} & LinkComponent;

const getVariantContainerClassNames = ({ variant }: { variant: Variant }) => {
return cx({
'ds-flex ds-flex-col ds-w-[260px] ds-h-[329px]': variant === 'vertical',
'ds-flex ds-flex-row ds-w-full ds-h-[147px]': variant === 'horizontal',
});
};

const getVariantImageClassNames = ({ variant }: { variant: Variant }) => {
return cx('ds-object-cover', {
'ds-min-h-[147px]': variant === 'vertical',
'ds-h-full ds-min-w-[265px]': variant === 'horizontal',
});
};
} & LinkComponent &
FavoriteButtonProps;

const Tag = ({ label }: { label: string }) => {
return <li className="ds-px-2 first:ds-pl-0 last:ds-pr-0">{label}</li>;
Expand Down Expand Up @@ -71,51 +63,51 @@ const LinkOrDiv = ({
);
};

interface RatingElementProps {
/** Amount of the rating, possible values between 0-5 */
amount: number;
ariaLabel: string;
}

const RatingElement = ({ amount, ariaLabel }: RatingElementProps) => {
const FavoriteButton = ({ isFavorite, favoriteLabel, onFavoriteClick }: FavoriteButtonProps) => {
return (
<div role="figure" className="ds-flex ds-flex-row ds-gap-2" aria-label={ariaLabel}>
{Array.from({ length: 5 }).map((_, idx) => (
// eslint-disable-next-line react/no-array-index-key
<MdOutlineStar key={idx} className={idx < amount ? 'ds-text-black' : 'ds-text-accent-25'} />
))}
</div>
<button
className="ds-absolute ds-top-0 ds-right-0 ds-p-[12px] ds-bg-white ds-rounded-bl"
aria-label={favoriteLabel}
onClick={onFavoriteClick}
>
{isFavorite ? (
<MdFavorite size={24} aria-hidden className="ds-text-accent" />
) : (
<MdFavoriteBorder aria-hidden size={24} />
)}
</button>
);
};

export const MediaCard = ({
variant = 'vertical',
imageSrc,
imageAlt,
label,
description,
tags,
linkComponent: Link,
to,
rating,
ratingAriaLabel,
isFavorite,
onFavoriteClick,
favoriteLabel,
}: MediaCardProps) => {
const variantContainerClassNames = getVariantContainerClassNames({ variant });
const variantImageClassNames = getVariantImageClassNames({ variant });
const variantImageClassNames = 'ds-object-cover ds-min-h-[147px]';

return (
<LinkOrDiv to={to} linkComponent={Link} className={variantContainerClassNames}>
<LinkOrDiv to={to} linkComponent={Link} className="ds-relative ds-flex ds-flex-col ds-w-[261px] ds-h-[299px]">
{imageSrc ? (
<img className={`${variantImageClassNames}`} src={imageSrc} alt={imageAlt} />
) : (
<span className="ds-w-full ds-h-full ds-bg-secondary-5"></span>
<span className={`ds-w-full ds-h-full ds-bg-secondary-5 ds-max-w-[265px] ${variantImageClassNames}`}></span>
)}
<div className="ds-px-5 ds-pt-4 ds-pb-5 ds-text-black ds-flex ds-flex-col ds-justify-between ds-h-full ds-flex-nowrap">
<div className="ds-gap-3 ds-flex ds-flex-col">
<div className="ds-text-heading-3-mobile sm:ds-text-heading-3">{label}</div>
<div className="ds-text-body-sm-mobile sm:ds-text-body-sm ds-line-clamp-3">{description}</div>
</div>
{rating !== undefined && <RatingElement amount={rating} ariaLabel={ratingAriaLabel ?? ''} />}
{isFavorite !== undefined && (
<FavoriteButton isFavorite={isFavorite} favoriteLabel={favoriteLabel} onFavoriteClick={onFavoriteClick} />
)}
<ul className="ds-text-attrib-value ds-flex ds-flex-row ds-divide-x ds-flex-wrap ds-text-accent ds-pt-3">
{tags.map((tag) => (
<Tag key={tag} label={tag} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

exports[`MediaCard > renders the MediaCard component with default vertical variant 1`] = `
<div
class="ds-overflow-clip ds-rounded ds-shadow-border ds-bg-white ds-flex ds-flex-col ds-w-[260px] ds-h-[329px]"
class="ds-overflow-clip ds-rounded ds-shadow-border ds-bg-white ds-relative ds-flex ds-flex-col ds-w-[261px] ds-h-[299px]"
>
<img
alt="Image for default"
Expand Down

0 comments on commit 2680767

Please sign in to comment.