From 4a79f0d5511d6a6732428687740f8190e000f1b9 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Thu, 31 Mar 2022 22:34:23 +0200 Subject: chore: add a Link component --- src/components/atoms/links/link.tsx | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/components/atoms/links/link.tsx (limited to 'src/components/atoms/links/link.tsx') diff --git a/src/components/atoms/links/link.tsx b/src/components/atoms/links/link.tsx new file mode 100644 index 0000000..0a69c33 --- /dev/null +++ b/src/components/atoms/links/link.tsx @@ -0,0 +1,41 @@ +import NextLink from 'next/link'; +import { FC } from 'react'; +import styles from './link.module.scss'; + +type LinkProps = { + /** + * True if it is an external link. Default: false. + */ + external?: boolean; + /** + * The link target. + */ + href: string; + /** + * The link target code language. + */ + lang?: string; +}; + +/** + * Link Component + * + * Render a link. + */ +const Link: FC = ({ children, href, lang, external = false }) => { + return external ? ( + + {children} + + ) : ( + + {children} + + ); +}; + +export default Link; -- cgit v1.2.3 From dfd816d1891545aa8ead982b57891858f1c82bb4 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Wed, 6 Apr 2022 16:24:05 +0200 Subject: chore: add a ResponsiveImage component --- src/components/atoms/links/link.tsx | 18 ++++- .../molecules/images/responsive-image.module.scss | 52 +++++++++++++ .../molecules/images/responsive-image.stories.tsx | 87 ++++++++++++++++++++++ .../molecules/images/responsive-image.test.tsx | 18 +++++ .../molecules/images/responsive-image.tsx | 68 +++++++++++++++++ 5 files changed, 240 insertions(+), 3 deletions(-) create mode 100644 src/components/molecules/images/responsive-image.module.scss create mode 100644 src/components/molecules/images/responsive-image.stories.tsx create mode 100644 src/components/molecules/images/responsive-image.test.tsx create mode 100644 src/components/molecules/images/responsive-image.tsx (limited to 'src/components/atoms/links/link.tsx') diff --git a/src/components/atoms/links/link.tsx b/src/components/atoms/links/link.tsx index 0a69c33..a61158f 100644 --- a/src/components/atoms/links/link.tsx +++ b/src/components/atoms/links/link.tsx @@ -3,6 +3,10 @@ import { FC } from 'react'; import styles from './link.module.scss'; type LinkProps = { + /** + * Set additional classes to the link. + */ + classes?: string; /** * True if it is an external link. Default: false. */ @@ -22,18 +26,26 @@ type LinkProps = { * * Render a link. */ -const Link: FC = ({ children, href, lang, external = false }) => { +const Link: FC = ({ + children, + classes, + href, + lang, + external = false, +}) => { + const additionalClasses = classes || ''; + return external ? ( {children} ) : ( - {children} + {children} ); }; diff --git a/src/components/molecules/images/responsive-image.module.scss b/src/components/molecules/images/responsive-image.module.scss new file mode 100644 index 0000000..83e8d10 --- /dev/null +++ b/src/components/molecules/images/responsive-image.module.scss @@ -0,0 +1,52 @@ +@use "@styles/abstracts/functions" as fun; + +.wrapper { + display: flex; + flex-flow: column; + width: 100%; + max-width: max-content; + margin: var(--spacing-sm) auto; + position: relative; + text-align: center; +} + +.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); + box-shadow: 0 fun.convert-px(-1) fun.convert-px(1) fun.convert-px(1) + var(--color-shadow-light); + font-weight: 500; +} + +.link { + display: flex; + flex-flow: column; + background: none; + text-decoration: none; + + .caption { + color: var(--color-primary-darker); + } + + &:hover, + &:focus { + transform: scale(1.1); + } + + &:focus { + .caption { + text-decoration: underline solid var(--color-primary-darker) + fun.convert-px(3); + } + } + + &:active { + transform: scale(0.9); + + .caption { + text-decoration: none; + } + } +} diff --git a/src/components/molecules/images/responsive-image.stories.tsx b/src/components/molecules/images/responsive-image.stories.tsx new file mode 100644 index 0000000..f9c1d2b --- /dev/null +++ b/src/components/molecules/images/responsive-image.stories.tsx @@ -0,0 +1,87 @@ +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import ResponsiveImageComponent from './responsive-image'; + +export default { + title: 'Molecules/Images', + component: ResponsiveImageComponent, + 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, + }, + }, + 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, + }, + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +export const ResponsiveImage = Template.bind({}); +ResponsiveImage.args = { + alt: 'An example', + src: 'http://placeimg.com/640/480/transport', + width: 640, + height: 480, +}; diff --git a/src/components/molecules/images/responsive-image.test.tsx b/src/components/molecules/images/responsive-image.test.tsx new file mode 100644 index 0000000..5452d28 --- /dev/null +++ b/src/components/molecules/images/responsive-image.test.tsx @@ -0,0 +1,18 @@ +import { render, screen } from '@test-utils'; +import ResponsiveImage from './responsive-image'; + +describe('ResponsiveImage', () => { + it('renders a responsive image', () => { + render( + + ); + 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 new file mode 100644 index 0000000..db2f5ab --- /dev/null +++ b/src/components/molecules/images/responsive-image.tsx @@ -0,0 +1,68 @@ +import Link from '@components/atoms/links/link'; +import Image, { ImageProps } from 'next/image'; +import { FC } from 'react'; +import styles from './responsive-image.module.scss'; + +type ResponsiveImageProps = Omit & { + /** + * An alternative text. + */ + alt: string; + /** + * A figure caption. + */ + caption?: string; + /** + * The image height. + */ + height: number | string; + /** + * A link target. + */ + target?: string; + /** + * The image width. + */ + width: number | string; +}; + +/** + * ResponsiveImage component + * + * Render a responsive image wrapped in a figure element. + */ +const ResponsiveImage: FC = ({ + alt, + caption, + layout, + objectFit, + target, + ...props +}) => { + return ( +
+ {target ? ( + + {alt} + {caption && ( +
{caption}
+ )} + + ) : ( + <> + {alt} + {caption && ( +
{caption}
+ )} + + )} +
+ ); +}; + +export default ResponsiveImage; -- cgit v1.2.3 From a5df28fad0dae266a857ae110c43b3cb8b23c996 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 8 Apr 2022 19:41:40 +0200 Subject: refactor: use a consistent classname prop and avoid children prop I was using the FunctionComponent type for some component that do not use children. So I change the type to VoidFunctionComponent to avoid mistakes. I also rename all the "classes" or "additionalClasses" props to "className" to keep consistency between each components. --- src/components/atoms/buttons/button-link.tsx | 2 +- src/components/atoms/buttons/button.stories.tsx | 13 +++++++++++ src/components/atoms/buttons/button.tsx | 10 ++++----- src/components/atoms/buttons/buttons.module.scss | 4 ++++ src/components/atoms/forms/toggle.module.scss | 3 ++- src/components/atoms/forms/toggle.stories.tsx | 14 ++++++++++++ src/components/atoms/forms/toggle.tsx | 26 ++++++++++++++++------ src/components/atoms/headings/heading.stories.tsx | 14 ++++++------ src/components/atoms/headings/heading.tsx | 14 +++++++----- src/components/atoms/images/logo.stories.tsx | 15 +++++++++++++ src/components/atoms/images/logo.tsx | 4 ++-- src/components/atoms/links/link.stories.tsx | 13 +++++++++++ src/components/atoms/links/link.tsx | 14 +++++------- src/components/atoms/links/nav-link.tsx | 4 ++-- src/components/atoms/links/sharing-link.tsx | 4 ++-- src/components/atoms/links/social-link.tsx | 10 +++++---- .../atoms/lists/description-list.stories.tsx | 6 ++--- src/components/atoms/lists/description-list.tsx | 13 ++++++----- src/components/atoms/lists/list.stories.tsx | 6 ++--- src/components/atoms/lists/list.tsx | 15 +++++-------- .../atoms/loaders/progress-bar.stories.tsx | 8 ++++++- src/components/atoms/loaders/progress-bar.tsx | 10 ++++----- src/components/atoms/loaders/spinner.stories.tsx | 3 +++ src/components/atoms/loaders/spinner.tsx | 6 ++--- .../molecules/buttons/back-to-top.stories.tsx | 7 ++++-- src/components/molecules/buttons/back-to-top.tsx | 12 +++++----- .../molecules/buttons/help-button.stories.tsx | 4 ++-- src/components/molecules/buttons/help-button.tsx | 10 ++++----- .../molecules/images/responsive-image.tsx | 6 ++--- src/components/molecules/layout/branding.tsx | 10 ++++----- .../molecules/layout/flipping-logo.stories.tsx | 23 ++++++++++++++----- src/components/molecules/layout/flipping-logo.tsx | 12 +++++----- src/components/molecules/modals/modal.stories.tsx | 13 +++++++++++ src/components/molecules/modals/modal.tsx | 22 +++++++++++++----- .../molecules/modals/tooltip.stories.tsx | 23 +++++++++++++++++++ src/components/molecules/modals/tooltip.tsx | 15 ++++++++----- 36 files changed, 270 insertions(+), 118 deletions(-) (limited to 'src/components/atoms/links/link.tsx') diff --git a/src/components/atoms/buttons/button-link.tsx b/src/components/atoms/buttons/button-link.tsx index 47fe4b0..81229c8 100644 --- a/src/components/atoms/buttons/button-link.tsx +++ b/src/components/atoms/buttons/button-link.tsx @@ -2,7 +2,7 @@ import Link from 'next/link'; import { FC } from 'react'; import styles from './buttons.module.scss'; -type ButtonLinkProps = { +export type ButtonLinkProps = { /** * ButtonLink accessible label. */ diff --git a/src/components/atoms/buttons/button.stories.tsx b/src/components/atoms/buttons/button.stories.tsx index 9f4061b..1061d83 100644 --- a/src/components/atoms/buttons/button.stories.tsx +++ b/src/components/atoms/buttons/button.stories.tsx @@ -33,6 +33,19 @@ export default { required: true, }, }, + className: { + control: { + type: 'text', + }, + description: 'Set additional classnames to the button wrapper.', + table: { + category: 'Styles', + }, + type: { + name: 'string', + required: false, + }, + }, disabled: { control: { type: 'boolean', diff --git a/src/components/atoms/buttons/button.tsx b/src/components/atoms/buttons/button.tsx index ae4c894..b223046 100644 --- a/src/components/atoms/buttons/button.tsx +++ b/src/components/atoms/buttons/button.tsx @@ -3,9 +3,9 @@ import styles from './buttons.module.scss'; export type ButtonProps = { /** - * Add additional classes to the button wrapper. + * Set additional classnames to the button wrapper. */ - additionalClasses?: string; + className?: string; /** * Button accessible label. */ @@ -17,7 +17,7 @@ export type ButtonProps = { /** * Button kind. Default: secondary. */ - kind?: 'primary' | 'secondary' | 'tertiary'; + kind?: 'primary' | 'secondary' | 'tertiary' | 'neutral'; /** * A callback function to handle click. */ @@ -38,7 +38,7 @@ export type ButtonProps = { * Use a button as call to action. */ const Button: FC = ({ - additionalClasses, + className = '', ariaLabel, children, disabled = false, @@ -54,7 +54,7 @@ const Button: FC = ({