aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/molecules
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-10-09 18:26:23 +0200
committerArmand Philippot <git@armandphilippot.com>2023-11-11 18:14:41 +0100
commit15522ec9146f6f1956620355c44dea2a6a75b67c (patch)
tree7be0c4ca96cb3e59d2ee989785a6b6a286e6169d /src/components/molecules
parent891441a76173c708c6604fa203b175aefa222333 (diff)
refactor(components): replace ResponsiveImage with Figure component
The styles applied to ResponsiveImage are related to the figure and figcaption elements. Those elements could be use with other contents than images. So I extracted them in a Figure component. The ResponsiveImage component is no longer useful: the consumer should use the Image component from `next` and wrap it in a link if needed.
Diffstat (limited to 'src/components/molecules')
-rw-r--r--src/components/molecules/images/index.ts1
-rw-r--r--src/components/molecules/images/responsive-image.module.scss84
-rw-r--r--src/components/molecules/images/responsive-image.stories.tsx212
-rw-r--r--src/components/molecules/images/responsive-image.test.tsx19
-rw-r--r--src/components/molecules/images/responsive-image.tsx91
-rw-r--r--src/components/molecules/layout/card.fixture.ts (renamed from src/components/molecules/layout/card.fixture.tsx)2
-rw-r--r--src/components/molecules/layout/card.module.scss1
-rw-r--r--src/components/molecules/layout/card.tsx11
8 files changed, 8 insertions, 413 deletions
diff --git a/src/components/molecules/images/index.ts b/src/components/molecules/images/index.ts
index 33ec886..318a6af 100644
--- a/src/components/molecules/images/index.ts
+++ b/src/components/molecules/images/index.ts
@@ -1,2 +1 @@
export * from './flipping-logo';
-export * from './responsive-image';
diff --git a/src/components/molecules/images/responsive-image.module.scss b/src/components/molecules/images/responsive-image.module.scss
deleted file mode 100644
index e4ed4aa..0000000
--- a/src/components/molecules/images/responsive-image.module.scss
+++ /dev/null
@@ -1,84 +0,0 @@
-@use "../../../styles/abstracts/functions" as fun;
-
-.caption {
- margin: 0;
- padding: fun.convert-px(4) var(--spacing-2xs);
- background: var(--color-bg-secondary);
- border: fun.convert-px(1) solid var(--color-border-light);
- font-size: var(--font-size-sm);
- font-weight: 500;
-}
-
-.wrapper {
- display: flex;
- flex-flow: column;
- width: fit-content;
- margin: 0 auto;
- position: relative;
- text-align: center;
-
- &--has-borders {
- .caption {
- margin-top: fun.convert-px(4);
- }
- }
-
- &--has-borders#{&}--has-link {
- .link {
- padding: fun.convert-px(4);
- }
- }
-
- &--has-borders#{&}--no-link {
- padding: fun.convert-px(4);
- border: fun.convert-px(1) solid var(--color-border);
- box-shadow: fun.convert-px(1) fun.convert-px(1) fun.convert-px(1) 0
- var(--color-shadow);
- }
-}
-
-.img {
- max-height: 100%;
- object-fit: cover;
-}
-
-.link {
- display: flex;
- flex-flow: column;
- background: none;
- border: fun.convert-px(1) solid var(--color-border);
- box-shadow: fun.convert-px(1) fun.convert-px(1) fun.convert-px(1) 0
- var(--color-shadow);
- text-decoration: none;
-
- .caption {
- color: var(--color-primary-darker);
- }
-
- &:hover,
- &:focus {
- box-shadow: 0 0 fun.convert-px(2) 0 var(--color-shadow-light),
- fun.convert-px(2) fun.convert-px(2) fun.convert-px(4) fun.convert-px(1)
- var(--color-shadow-light),
- fun.convert-px(4) fun.convert-px(4) fun.convert-px(8) fun.convert-px(2)
- var(--color-shadow-light);
- transform: scale(var(--scale-up, 1.05));
- }
-
- &:focus {
- .caption {
- text-decoration: underline solid var(--color-primary-darker)
- fun.convert-px(3);
- }
- }
-
- &:active {
- box-shadow: fun.convert-px(1) fun.convert-px(1) fun.convert-px(1)
- fun.convert-px(1) var(--color-shadow-light);
- transform: scale(var(--scale-down, 0.95));
-
- .caption {
- text-decoration: none;
- }
- }
-}
diff --git a/src/components/molecules/images/responsive-image.stories.tsx b/src/components/molecules/images/responsive-image.stories.tsx
deleted file mode 100644
index cc6b088..0000000
--- a/src/components/molecules/images/responsive-image.stories.tsx
+++ /dev/null
@@ -1,212 +0,0 @@
-import { ComponentMeta, ComponentStory } from '@storybook/react';
-import { ResponsiveImage } from './responsive-image';
-
-/**
- * ResponsiveImage - Storybook Meta
- */
-export default {
- title: 'Molecules/Images/ResponsiveImage',
- component: ResponsiveImage,
- args: {
- withBorders: false,
- },
- argTypes: {
- alt: {
- control: {
- type: 'text',
- },
- description: 'An alternative text.',
- type: {
- name: 'string',
- required: true,
- },
- },
- caption: {
- control: {
- type: 'text',
- },
- description: 'A figure caption.',
- table: {
- category: 'Options',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- className: {
- control: {
- type: 'text',
- },
- description: 'Set additional classnames to the image wrapper.',
- table: {
- category: 'Styles',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- height: {
- control: {
- type: 'number',
- },
- description: 'The image height.',
- type: {
- name: 'string',
- required: true,
- },
- },
- src: {
- control: {
- type: 'text',
- },
- description: 'The image source.',
- type: {
- name: 'string',
- required: true,
- },
- },
- target: {
- control: {
- type: 'text',
- },
- description: 'A link target.',
- table: {
- category: 'Options',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- width: {
- control: {
- type: 'number',
- },
- description: 'The image width.',
- type: {
- name: 'string',
- required: true,
- },
- },
- withBorders: {
- control: {
- type: 'boolean',
- },
- description: 'Add borders around the image.',
- table: {
- category: 'Styles',
- defaultValue: { summary: false },
- },
- type: {
- name: 'boolean',
- required: false,
- },
- },
- },
-} as ComponentMeta<typeof ResponsiveImage>;
-
-const Template: ComponentStory<typeof ResponsiveImage> = (args) => (
- <ResponsiveImage {...args} />
-);
-
-/**
- * Responsive Image Stories - Default
- */
-export const Default = Template.bind({});
-Default.args = {
- alt: 'An example',
- src: 'http://placeimg.com/640/480/transport',
- width: 640,
- height: 480,
-};
-
-/**
- * Responsive Image Stories - With borders
- */
-export const WithBorders = Template.bind({});
-WithBorders.args = {
- alt: 'An example',
- src: 'http://placeimg.com/640/480/transport',
- width: 640,
- height: 480,
- withBorders: true,
-};
-
-/**
- * Responsive Image Stories - With link
- */
-export const WithLink = Template.bind({});
-WithLink.args = {
- alt: 'An example',
- src: 'http://placeimg.com/640/480/transport',
- width: 640,
- height: 480,
- target: '#',
-};
-
-/**
- * Responsive Image Stories - With link and borders
- */
-export const WithLinkAndBorders = Template.bind({});
-WithLinkAndBorders.args = {
- alt: 'An example',
- src: 'http://placeimg.com/640/480/transport',
- width: 640,
- height: 480,
- target: '#',
- withBorders: true,
-};
-
-/**
- * Responsive Image Stories - With caption
- */
-export const WithCaption = Template.bind({});
-WithCaption.args = {
- alt: 'An example',
- src: 'http://placeimg.com/640/480/transport',
- width: 640,
- height: 480,
- caption: 'Omnis nulla labore',
-};
-
-/**
- * Responsive Image Stories - With caption and borders
- */
-export const WithCaptionAndBorders = Template.bind({});
-WithCaptionAndBorders.args = {
- alt: 'An example',
- src: 'http://placeimg.com/640/480/transport',
- width: 640,
- height: 480,
- caption: 'Omnis nulla labore',
- withBorders: true,
-};
-
-/**
- * Responsive Image Stories - With caption and link
- */
-export const WithCaptionAndLink = Template.bind({});
-WithCaptionAndLink.args = {
- alt: 'An example',
- src: 'http://placeimg.com/640/480/transport',
- width: 640,
- height: 480,
- caption: 'Omnis nulla labore',
- target: '#',
-};
-
-/**
- * Responsive Image Stories - With caption, link and borders
- */
-export const WithCaptionLinkAndBorders = Template.bind({});
-WithCaptionLinkAndBorders.args = {
- alt: 'An example',
- src: 'http://placeimg.com/640/480/transport',
- width: 640,
- height: 480,
- caption: 'Omnis nulla labore',
- target: '#',
- withBorders: true,
-};
diff --git a/src/components/molecules/images/responsive-image.test.tsx b/src/components/molecules/images/responsive-image.test.tsx
deleted file mode 100644
index dec36ea..0000000
--- a/src/components/molecules/images/responsive-image.test.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { describe, expect, it } from '@jest/globals';
-import { render, screen } from '../../../../tests/utils';
-import { ResponsiveImage } from './responsive-image';
-
-describe('ResponsiveImage', () => {
- it('renders a responsive image', () => {
- render(
- <ResponsiveImage
- src="http://placeimg.com/640/480"
- alt="An alternative text"
- width={640}
- height={480}
- />
- );
- expect(
- screen.getByRole('img', { name: 'An alternative text' })
- ).toBeInTheDocument();
- });
-});
diff --git a/src/components/molecules/images/responsive-image.tsx b/src/components/molecules/images/responsive-image.tsx
deleted file mode 100644
index 85c0c46..0000000
--- a/src/components/molecules/images/responsive-image.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-import Image, { type ImageProps } from 'next/image';
-import { FC, ReactNode } from 'react';
-import { Link, type LinkProps } from '../../atoms';
-import styles from './responsive-image.module.scss';
-
-export type ResponsiveImageProps = Omit<
- ImageProps,
- 'alt' | 'width' | 'height'
-> & {
- /**
- * An alternative text.
- */
- alt: string;
- /**
- * A figure caption.
- */
- caption?: ReactNode;
- /**
- * Set additional classnames to the figure wrapper.
- */
- className?: string;
- /**
- * The image height.
- */
- height: number | `${number}`;
- /**
- * A link target.
- */
- target?: LinkProps['href'];
- /**
- * The image width.
- */
- width: number | `${number}`;
- /**
- * Wrap the image with borders.
- */
- withBorders?: boolean;
-};
-
-/**
- * ResponsiveImage component
- *
- * Render a responsive image wrapped in a figure element.
- */
-export const ResponsiveImage: FC<ResponsiveImageProps> = ({
- alt,
- caption,
- className = '',
- target,
- title,
- withBorders,
- ...props
-}) => {
- const bordersModifier = withBorders ? styles['wrapper--has-borders'] : '';
- const linkModifier = target
- ? styles['wrapper--has-link']
- : styles['wrapper--no-link'];
- const figureClass = `${styles.wrapper} ${bordersModifier} ${linkModifier} ${className}`;
-
- return (
- <figure aria-label={caption ? undefined : title} className={figureClass}>
- {target ? (
- <Link href={target} className={styles.link}>
- <Image
- {...props}
- alt={alt}
- className={styles.img}
- sizes="100vw"
- title={title}
- />
- {caption && (
- <figcaption className={styles.caption}>{caption}</figcaption>
- )}
- </Link>
- ) : (
- <>
- <Image
- {...props}
- alt={alt}
- className={styles.img}
- sizes="100vw"
- title={title}
- />
- {caption && (
- <figcaption className={styles.caption}>{caption}</figcaption>
- )}
- </>
- )}
- </figure>
- );
-};
diff --git a/src/components/molecules/layout/card.fixture.tsx b/src/components/molecules/layout/card.fixture.ts
index f96cc43..01fe2e9 100644
--- a/src/components/molecules/layout/card.fixture.tsx
+++ b/src/components/molecules/layout/card.fixture.ts
@@ -1,7 +1,7 @@
export const cover = {
alt: 'A picture',
height: 480,
- src: 'http://placeimg.com/640/480',
+ src: 'https://picsum.photos/640/480',
width: 640,
};
diff --git a/src/components/molecules/layout/card.module.scss b/src/components/molecules/layout/card.module.scss
index 31f6a4b..7a06508 100644
--- a/src/components/molecules/layout/card.module.scss
+++ b/src/components/molecules/layout/card.module.scss
@@ -20,6 +20,7 @@
.cover {
place-content: center;
height: fun.convert-px(150);
+ object-fit: scale-down;
margin: auto;
border-bottom: fun.convert-px(1) solid var(--color-border);
}
diff --git a/src/components/molecules/layout/card.tsx b/src/components/molecules/layout/card.tsx
index c9e7a90..c316100 100644
--- a/src/components/molecules/layout/card.tsx
+++ b/src/components/molecules/layout/card.tsx
@@ -1,7 +1,6 @@
+import NextImage, { type ImageProps as NextImageProps } from 'next/image';
import type { FC } from 'react';
-import type { Image as Img } from '../../../types';
-import { ButtonLink, Heading, type HeadingLevel } from '../../atoms';
-import { ResponsiveImage } from '../images';
+import { ButtonLink, Figure, Heading, type HeadingLevel } from '../../atoms';
import styles from './card.module.scss';
import { Meta, type MetaData } from './meta';
@@ -13,7 +12,7 @@ export type CardProps = {
/**
* The card cover.
*/
- cover?: Img;
+ cover?: Pick<NextImageProps, 'alt' | 'src' | 'title' | 'width' | 'height'>;
/**
* The card id.
*/
@@ -63,7 +62,9 @@ export const Card: FC<CardProps> = ({
<article className={styles.article}>
<header className={styles.header}>
{cover ? (
- <ResponsiveImage {...cover} className={styles.cover} />
+ <Figure>
+ <NextImage {...cover} className={styles.cover} />
+ </Figure>
) : null}
<Heading className={styles.title} id={headingId} level={titleLevel}>
{title}