From 4a79f0d5511d6a6732428687740f8190e000f1b9 Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
Date: Thu, 31 Mar 2022 22:34:23 +0200
Subject: chore: add a Link component

---
 src/components/atoms/links/link.stories.tsx | 66 +++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 src/components/atoms/links/link.stories.tsx

(limited to 'src/components/atoms/links/link.stories.tsx')

diff --git a/src/components/atoms/links/link.stories.tsx b/src/components/atoms/links/link.stories.tsx
new file mode 100644
index 0000000..e5a8b0a
--- /dev/null
+++ b/src/components/atoms/links/link.stories.tsx
@@ -0,0 +1,66 @@
+import { ComponentMeta, ComponentStory } from '@storybook/react';
+import LinkComponent from './link';
+
+export default {
+  title: 'Atoms/Links',
+  component: LinkComponent,
+  argTypes: {
+    children: {
+      control: {
+        type: 'text',
+      },
+      description: 'The link body.',
+      type: {
+        name: 'string',
+        required: true,
+      },
+    },
+    external: {
+      control: {
+        type: 'boolean',
+      },
+      table: {
+        category: 'Options',
+      },
+      description: 'Determine if the link is external of the current website.',
+      type: {
+        name: 'boolean',
+        required: false,
+      },
+    },
+    href: {
+      control: {
+        type: 'text',
+      },
+      description: 'The link target.',
+      type: {
+        name: 'string',
+        required: true,
+      },
+    },
+    lang: {
+      control: {
+        type: 'text',
+      },
+      table: {
+        category: 'Options',
+      },
+      description: 'The target language as code language.',
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
+  },
+} as ComponentMeta<typeof LinkComponent>;
+
+const Template: ComponentStory<typeof LinkComponent> = (args) => (
+  <LinkComponent {...args} />
+);
+
+export const Link = Template.bind({});
+Link.args = {
+  children: 'A link',
+  href: '#',
+  external: false,
+};
-- 
cgit v1.2.3


From a5df28fad0dae266a857ae110c43b3cb8b23c996 Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
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.stories.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<ButtonProps> = ({
-  additionalClasses,
+  className = '',
   ariaLabel,
   children,
   disabled = false,
@@ -54,7 +54,7 @@ const Button: FC<ButtonProps> = ({
     <button
       type={type}
       disabled={disabled}
-      className={`${styles.btn} ${kindClass} ${shapeClass} ${additionalClasses}`}
+      className={`${styles.btn} ${kindClass} ${shapeClass} ${className}`}
       aria-label={ariaLabel}
       {...props}
     >
diff --git a/src/components/atoms/buttons/buttons.module.scss b/src/components/atoms/buttons/buttons.module.scss
index a1c3dba..87c92db 100644
--- a/src/components/atoms/buttons/buttons.module.scss
+++ b/src/components/atoms/buttons/buttons.module.scss
@@ -28,6 +28,10 @@
     cursor: wait;
   }
 
+  &--neutral {
+    background: inherit;
+  }
+
   &--primary {
     background: var(--color-primary);
     border: fun.convert-px(2) solid var(--color-bg);
diff --git a/src/components/atoms/forms/toggle.module.scss b/src/components/atoms/forms/toggle.module.scss
index 00e87a2..24b867e 100644
--- a/src/components/atoms/forms/toggle.module.scss
+++ b/src/components/atoms/forms/toggle.module.scss
@@ -6,10 +6,11 @@
 
   display: inline-flex;
   align-items: center;
+  width: 100%;
 }
 
 .title {
-  margin-right: var(--spacing-xs);
+  margin-right: auto;
 }
 
 .toggle {
diff --git a/src/components/atoms/forms/toggle.stories.tsx b/src/components/atoms/forms/toggle.stories.tsx
index 6e7323b..ea08694 100644
--- a/src/components/atoms/forms/toggle.stories.tsx
+++ b/src/components/atoms/forms/toggle.stories.tsx
@@ -34,6 +34,20 @@ export default {
         required: true,
       },
     },
+    labelSize: {
+      control: {
+        type: 'select',
+      },
+      description: 'The label size.',
+      options: ['medium', 'small'],
+      table: {
+        category: 'Options',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
     name: {
       control: {
         type: 'text',
diff --git a/src/components/atoms/forms/toggle.tsx b/src/components/atoms/forms/toggle.tsx
index e8e8c0f..7ef40ed 100644
--- a/src/components/atoms/forms/toggle.tsx
+++ b/src/components/atoms/forms/toggle.tsx
@@ -1,9 +1,16 @@
-import { FC, ReactElement } from 'react';
+import { ReactNode, VFC } from 'react';
+import Label, { LabelProps } from './label';
 import styles from './toggle.module.scss';
 
 export type ToggleChoices = {
-  left: ReactElement | string;
-  right: ReactElement | string;
+  /**
+   * The left part of the toggle field (unchecked).
+   */
+  left: ReactNode;
+  /**
+   * The right part of the toggle field (checked).
+   */
+  right: ReactNode;
 };
 
 export type ToggleProps = {
@@ -19,6 +26,10 @@ export type ToggleProps = {
    * The toggle label.
    */
   label: string;
+  /**
+   * The label size.
+   */
+  labelSize?: LabelProps['size'];
   /**
    * The input name.
    */
@@ -38,13 +49,14 @@ export type ToggleProps = {
  *
  * Render a toggle with a label and two choices.
  */
-const Toggle: FC<ToggleProps> = ({
+const Toggle: VFC<ToggleProps> = ({
   choices,
   id,
   label,
+  labelSize,
   name,
-  value,
   setValue,
+  value,
 }) => {
   return (
     <>
@@ -56,12 +68,12 @@ const Toggle: FC<ToggleProps> = ({
         onChange={() => setValue(!value)}
         className={styles.checkbox}
       />
-      <label htmlFor={id} className={styles.label}>
+      <Label size={labelSize} htmlFor={id} className={styles.label}>
         <span className={styles.title}>{label}</span>
         {choices.left}
         <span className={styles.toggle}></span>
         {choices.right}
-      </label>
+      </Label>
     </>
   );
 };
diff --git a/src/components/atoms/headings/heading.stories.tsx b/src/components/atoms/headings/heading.stories.tsx
index cea3532..66a84dc 100644
--- a/src/components/atoms/headings/heading.stories.tsx
+++ b/src/components/atoms/headings/heading.stories.tsx
@@ -9,13 +9,13 @@ export default {
     withMargin: true,
   },
   argTypes: {
-    additionalClasses: {
+    className: {
       control: {
         type: 'text',
       },
-      description: 'Set additional classes.',
+      description: 'Set additional classnames.',
       table: {
-        category: 'Options',
+        category: 'Styles',
       },
       type: {
         name: 'string',
@@ -71,12 +71,12 @@ export default {
   },
 } as ComponentMeta<typeof HeadingComponent>;
 
-const Template: ComponentStory<typeof HeadingComponent> = (args) => {
-  const { level, ...props } = args;
-  return <HeadingComponent level={level || 1} {...props} />;
-};
+const Template: ComponentStory<typeof HeadingComponent> = (args) => (
+  <HeadingComponent {...args} />
+);
 
 export const Heading = Template.bind({});
 Heading.args = {
   children: 'Your title',
+  level: 1,
 };
diff --git a/src/components/atoms/headings/heading.tsx b/src/components/atoms/headings/heading.tsx
index 136571d..3048534 100644
--- a/src/components/atoms/headings/heading.tsx
+++ b/src/components/atoms/headings/heading.tsx
@@ -1,19 +1,21 @@
 import { FC } from 'react';
 import styles from './heading.module.scss';
 
+export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
+
 export type HeadingProps = {
   /**
-   * Adds additional classes.
+   * Set additional classnames.
    */
-  additionalClasses?: string;
+  className?: string;
   /**
    * Use an heading element or only its styles. Default: false.
    */
   isFake?: boolean;
   /**
-   * HTML heading level: 'h1', 'h2', 'h3', 'h4', 'h5' or 'h6'.
+   * HTML heading level.
    */
-  level: 1 | 2 | 3 | 4 | 5 | 6;
+  level: HeadingLevel;
   /**
    * Adds margin. Default: true.
    */
@@ -27,7 +29,7 @@ export type HeadingProps = {
  */
 const Heading: FC<HeadingProps> = ({
   children,
-  additionalClasses,
+  className,
   isFake = false,
   level,
   withMargin = true,
@@ -38,7 +40,7 @@ const Heading: FC<HeadingProps> = ({
 
   return (
     <TitleTag
-      className={`${styles.heading} ${styles[levelClass]} ${styles[marginClass]} ${additionalClasses}`}
+      className={`${styles.heading} ${styles[levelClass]} ${styles[marginClass]} ${className}`}
     >
       {children}
     </TitleTag>
diff --git a/src/components/atoms/images/logo.stories.tsx b/src/components/atoms/images/logo.stories.tsx
index afb5317..fbc7501 100644
--- a/src/components/atoms/images/logo.stories.tsx
+++ b/src/components/atoms/images/logo.stories.tsx
@@ -4,6 +4,21 @@ import LogoComponent from './logo';
 export default {
   title: 'Atoms/Images',
   component: LogoComponent,
+  argTypes: {
+    title: {
+      control: {
+        type: 'text',
+      },
+      description: 'The SVG title.',
+      table: {
+        category: 'Accessibility',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
+  },
 } as ComponentMeta<typeof LogoComponent>;
 
 const Template: ComponentStory<typeof LogoComponent> = (args) => (
diff --git a/src/components/atoms/images/logo.tsx b/src/components/atoms/images/logo.tsx
index 9ce2518..2e52110 100644
--- a/src/components/atoms/images/logo.tsx
+++ b/src/components/atoms/images/logo.tsx
@@ -1,4 +1,4 @@
-import { FC } from 'react';
+import { VFC } from 'react';
 import styles from './logo.module.scss';
 
 type LogoProps = {
@@ -13,7 +13,7 @@ type LogoProps = {
  *
  * Render a SVG logo.
  */
-const Logo: FC<LogoProps> = ({ title }) => {
+const Logo: VFC<LogoProps> = ({ title }) => {
   return (
     <svg
       viewBox="0 0 512 512"
diff --git a/src/components/atoms/links/link.stories.tsx b/src/components/atoms/links/link.stories.tsx
index e5a8b0a..569c874 100644
--- a/src/components/atoms/links/link.stories.tsx
+++ b/src/components/atoms/links/link.stories.tsx
@@ -15,6 +15,19 @@ export default {
         required: true,
       },
     },
+    className: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames.',
+      table: {
+        category: 'Styles',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
     external: {
       control: {
         type: 'boolean',
diff --git a/src/components/atoms/links/link.tsx b/src/components/atoms/links/link.tsx
index a61158f..87f11fc 100644
--- a/src/components/atoms/links/link.tsx
+++ b/src/components/atoms/links/link.tsx
@@ -2,11 +2,11 @@ import NextLink from 'next/link';
 import { FC } from 'react';
 import styles from './link.module.scss';
 
-type LinkProps = {
+export type LinkProps = {
   /**
-   * Set additional classes to the link.
+   * Set additional classnames to the link.
    */
-  classes?: string;
+  className?: string;
   /**
    * True if it is an external link. Default: false.
    */
@@ -28,24 +28,22 @@ type LinkProps = {
  */
 const Link: FC<LinkProps> = ({
   children,
-  classes,
+  className = '',
   href,
   lang,
   external = false,
 }) => {
-  const additionalClasses = classes || '';
-
   return external ? (
     <a
       href={href}
       hrefLang={lang}
-      className={`${styles.link} ${styles['link--external']} ${additionalClasses}`}
+      className={`${styles.link} ${styles['link--external']} ${className}`}
     >
       {children}
     </a>
   ) : (
     <NextLink href={href}>
-      <a className={`${styles.link} ${additionalClasses}`}>{children}</a>
+      <a className={`${styles.link} ${className}`}>{children}</a>
     </NextLink>
   );
 };
diff --git a/src/components/atoms/links/nav-link.tsx b/src/components/atoms/links/nav-link.tsx
index 7c6fede..25c0e7d 100644
--- a/src/components/atoms/links/nav-link.tsx
+++ b/src/components/atoms/links/nav-link.tsx
@@ -1,5 +1,5 @@
 import Link from 'next/link';
-import { FC, ReactNode } from 'react';
+import { VFC, ReactNode } from 'react';
 import styles from './nav-link.module.scss';
 
 export type NavLinkProps = {
@@ -22,7 +22,7 @@ export type NavLinkProps = {
  *
  * Render a navigation link.
  */
-const NavLink: FC<NavLinkProps> = ({ href, label, logo }) => {
+const NavLink: VFC<NavLinkProps> = ({ href, label, logo }) => {
   return (
     <Link href={href}>
       <a className={styles.link}>
diff --git a/src/components/atoms/links/sharing-link.tsx b/src/components/atoms/links/sharing-link.tsx
index ca53ef9..3cd2dd1 100644
--- a/src/components/atoms/links/sharing-link.tsx
+++ b/src/components/atoms/links/sharing-link.tsx
@@ -1,4 +1,4 @@
-import { FC } from 'react';
+import { VFC } from 'react';
 import { useIntl } from 'react-intl';
 import styles from './sharing-link.module.scss';
 
@@ -26,7 +26,7 @@ export type SharingLinkProps = {
  *
  * Render a sharing link.
  */
-const SharingLink: FC<SharingLinkProps> = ({ medium, url }) => {
+const SharingLink: VFC<SharingLinkProps> = ({ medium, url }) => {
   const intl = useIntl();
   const text = intl.formatMessage(
     {
diff --git a/src/components/atoms/links/social-link.tsx b/src/components/atoms/links/social-link.tsx
index 489c8b4..8c7c790 100644
--- a/src/components/atoms/links/social-link.tsx
+++ b/src/components/atoms/links/social-link.tsx
@@ -2,14 +2,16 @@ import GithubIcon from '@assets/images/social-media/github.svg';
 import GitlabIcon from '@assets/images/social-media/gitlab.svg';
 import LinkedInIcon from '@assets/images/social-media/linkedin.svg';
 import TwitterIcon from '@assets/images/social-media/twitter.svg';
-import { FC } from 'react';
+import { VFC } from 'react';
 import styles from './social-link.module.scss';
 
-type SocialLinkProps = {
+export type SocialWebsite = 'Github' | 'Gitlab' | 'LinkedIn' | 'Twitter';
+
+export type SocialLinkProps = {
   /**
    * The social website name.
    */
-  name: 'Github' | 'Gitlab' | 'LinkedIn' | 'Twitter';
+  name: SocialWebsite;
   /**
    * The social profile url.
    */
@@ -21,7 +23,7 @@ type SocialLinkProps = {
  *
  * Render a social icon link.
  */
-const SocialLink: FC<SocialLinkProps> = ({ name, url }) => {
+const SocialLink: VFC<SocialLinkProps> = ({ name, url }) => {
   /**
    * Retrieve a social link icon by id.
    * @param {string} id - The social website id.
diff --git a/src/components/atoms/lists/description-list.stories.tsx b/src/components/atoms/lists/description-list.stories.tsx
index e9a60cf..c65241d 100644
--- a/src/components/atoms/lists/description-list.stories.tsx
+++ b/src/components/atoms/lists/description-list.stories.tsx
@@ -7,13 +7,13 @@ export default {
   title: 'Atoms/Lists',
   component: DescriptionListComponent,
   argTypes: {
-    classes: {
+    className: {
       control: {
         type: 'text',
       },
-      description: 'Set additional classes to the list wrapper.',
+      description: 'Set additional classnames to the list wrapper',
       table: {
-        category: 'Options',
+        category: 'Styles',
       },
       type: {
         name: 'string',
diff --git a/src/components/atoms/lists/description-list.tsx b/src/components/atoms/lists/description-list.tsx
index df2880f..a5ab1d5 100644
--- a/src/components/atoms/lists/description-list.tsx
+++ b/src/components/atoms/lists/description-list.tsx
@@ -1,4 +1,4 @@
-import { FC } from 'react';
+import { VFC } from 'react';
 import styles from './description-list.module.scss';
 
 export type DescriptionListItem = {
@@ -18,9 +18,9 @@ export type DescriptionListItem = {
 
 export type DescriptionListProps = {
   /**
-   * Set additional classes to the list wrapper.
+   * Set additional classnames to the list wrapper.
    */
-  classes?: string;
+  className?: string;
   /**
    * The list items.
    */
@@ -32,7 +32,10 @@ export type DescriptionListProps = {
  *
  * Render a description list.
  */
-const DescriptionList: FC<DescriptionListProps> = ({ classes = '', items }) => {
+const DescriptionList: VFC<DescriptionListProps> = ({
+  className = '',
+  items,
+}) => {
   /**
    * Retrieve the description list items wrapped in a div element.
    *
@@ -54,7 +57,7 @@ const DescriptionList: FC<DescriptionListProps> = ({ classes = '', items }) => {
     });
   };
 
-  return <dl className={`${styles.list} ${classes}`}>{getItems(items)}</dl>;
+  return <dl className={`${styles.list} ${className}`}>{getItems(items)}</dl>;
 };
 
 export default DescriptionList;
diff --git a/src/components/atoms/lists/list.stories.tsx b/src/components/atoms/lists/list.stories.tsx
index 6256e81..30079cb 100644
--- a/src/components/atoms/lists/list.stories.tsx
+++ b/src/components/atoms/lists/list.stories.tsx
@@ -8,13 +8,13 @@ export default {
     kind: 'unordered',
   },
   argTypes: {
-    classes: {
+    className: {
       control: {
         type: 'text',
       },
-      description: 'Add additional classes to the list element.',
+      description: 'Set additional classnames to the list wrapper',
       table: {
-        category: 'Options',
+        category: 'Styles',
       },
       type: {
         name: 'string',
diff --git a/src/components/atoms/lists/list.tsx b/src/components/atoms/lists/list.tsx
index 8ce8437..7197c34 100644
--- a/src/components/atoms/lists/list.tsx
+++ b/src/components/atoms/lists/list.tsx
@@ -1,4 +1,4 @@
-import { FC } from 'react';
+import { VFC } from 'react';
 import styles from './list.module.scss';
 
 export type ListItem = {
@@ -18,9 +18,9 @@ export type ListItem = {
 
 export type ListProps = {
   /**
-   * Add additional classes to the list element.
+   * Set additional classnames to the list wrapper
    */
-  classes?: string;
+  className?: string;
   /**
    * An array of list items.
    */
@@ -36,9 +36,8 @@ export type ListProps = {
  *
  * Render either an ordered or an unordered list.
  */
-const List: FC<ListProps> = ({ classes, items, kind = 'unordered' }) => {
+const List: VFC<ListProps> = ({ className, items, kind = 'unordered' }) => {
   const ListTag = kind === 'ordered' ? 'ol' : 'ul';
-  const additionalClasses = classes || '';
   const kindClass = `list--${kind}`;
 
   /**
@@ -52,7 +51,7 @@ const List: FC<ListProps> = ({ classes, items, kind = 'unordered' }) => {
         {value}
         {child && (
           <ListTag
-            className={`${styles.list} ${styles[kindClass]} ${additionalClasses}`}
+            className={`${styles.list} ${styles[kindClass]} ${className}`}
           >
             {getItems(child)}
           </ListTag>
@@ -62,9 +61,7 @@ const List: FC<ListProps> = ({ classes, items, kind = 'unordered' }) => {
   };
 
   return (
-    <ListTag
-      className={`${styles.list} ${styles[kindClass]} ${additionalClasses}`}
-    >
+    <ListTag className={`${styles.list} ${styles[kindClass]} ${className}`}>
       {getItems(items)}
     </ListTag>
   );
diff --git a/src/components/atoms/loaders/progress-bar.stories.tsx b/src/components/atoms/loaders/progress-bar.stories.tsx
index 837a696..4fde5a7 100644
--- a/src/components/atoms/loaders/progress-bar.stories.tsx
+++ b/src/components/atoms/loaders/progress-bar.stories.tsx
@@ -5,11 +5,14 @@ export default {
   title: 'Atoms/Loaders',
   component: ProgressBarComponent,
   argTypes: {
-    ariaLabel: {
+    'aria-label': {
       control: {
         type: 'string',
       },
       description: 'An accessible name.',
+      table: {
+        category: 'Accessibility',
+      },
       type: {
         name: 'string',
         required: false,
@@ -30,6 +33,9 @@ export default {
         type: 'text',
       },
       description: 'An additional information to display.',
+      table: {
+        category: 'Options',
+      },
       type: {
         name: 'string',
         required: false,
diff --git a/src/components/atoms/loaders/progress-bar.tsx b/src/components/atoms/loaders/progress-bar.tsx
index fa4e09d..1b1ff06 100644
--- a/src/components/atoms/loaders/progress-bar.tsx
+++ b/src/components/atoms/loaders/progress-bar.tsx
@@ -1,11 +1,11 @@
-import { FC } from 'react';
+import { VFC } from 'react';
 import styles from './progress-bar.module.scss';
 
 export type ProgressBarProps = {
   /**
    * Accessible progress bar name.
    */
-  ariaLabel?: string;
+  'aria-label'?: string;
   /**
    * Current value.
    */
@@ -29,12 +29,12 @@ export type ProgressBarProps = {
  *
  * Render a progress bar.
  */
-const ProgressBar: FC<ProgressBarProps> = ({
-  ariaLabel,
+const ProgressBar: VFC<ProgressBarProps> = ({
   current,
   info,
   min,
   max,
+  ...props
 }) => {
   return (
     <div className={styles.progress}>
@@ -46,7 +46,7 @@ const ProgressBar: FC<ProgressBarProps> = ({
         aria-valuemin={min}
         aria-valuemax={max}
         aria-valuenow={current}
-        aria-label={ariaLabel}
+        {...props}
       ></progress>
     </div>
   );
diff --git a/src/components/atoms/loaders/spinner.stories.tsx b/src/components/atoms/loaders/spinner.stories.tsx
index 86c316e..5006ce4 100644
--- a/src/components/atoms/loaders/spinner.stories.tsx
+++ b/src/components/atoms/loaders/spinner.stories.tsx
@@ -11,6 +11,9 @@ export default {
         type: 'text',
       },
       description: 'Loading message.',
+      table: {
+        category: 'Options',
+      },
       type: {
         name: 'string',
         required: false,
diff --git a/src/components/atoms/loaders/spinner.tsx b/src/components/atoms/loaders/spinner.tsx
index 57b0a43..bff0f25 100644
--- a/src/components/atoms/loaders/spinner.tsx
+++ b/src/components/atoms/loaders/spinner.tsx
@@ -1,8 +1,8 @@
-import { FC } from 'react';
+import { VFC } from 'react';
 import { useIntl } from 'react-intl';
 import styles from './spinner.module.scss';
 
-type SpinnerProps = {
+export type SpinnerProps = {
   /**
    * The loading message. Default: "Loading...".
    */
@@ -14,7 +14,7 @@ type SpinnerProps = {
  *
  * Render a loading message with animation.
  */
-const Spinner: FC<SpinnerProps> = ({ message }) => {
+const Spinner: VFC<SpinnerProps> = ({ message }) => {
   const intl = useIntl();
 
   return (
diff --git a/src/components/molecules/buttons/back-to-top.stories.tsx b/src/components/molecules/buttons/back-to-top.stories.tsx
index f1a36e5..fe58293 100644
--- a/src/components/molecules/buttons/back-to-top.stories.tsx
+++ b/src/components/molecules/buttons/back-to-top.stories.tsx
@@ -6,11 +6,14 @@ export default {
   title: 'Molecules/Buttons',
   component: BackToTopComponent,
   argTypes: {
-    additionalClasses: {
+    className: {
       control: {
         type: 'text',
       },
-      description: 'Add additional classes to the button wrapper.',
+      description: 'Set additional classnames to the button wrapper.',
+      table: {
+        category: 'Styles',
+      },
       type: {
         name: 'string',
         required: false,
diff --git a/src/components/molecules/buttons/back-to-top.tsx b/src/components/molecules/buttons/back-to-top.tsx
index f25d3e9..56c5247 100644
--- a/src/components/molecules/buttons/back-to-top.tsx
+++ b/src/components/molecules/buttons/back-to-top.tsx
@@ -1,14 +1,14 @@
 import ButtonLink from '@components/atoms/buttons/button-link';
 import Arrow from '@components/atoms/icons/arrow';
-import { FC } from 'react';
+import { VFC } from 'react';
 import { useIntl } from 'react-intl';
 import styles from './back-to-top.module.scss';
 
-type BackToTopProps = {
+export type BackToTopProps = {
   /**
-   * Add additional classes to the button wrapper.
+   * Set additional classnames to the button wrapper.
    */
-  additionalClasses?: string;
+  className?: string;
   /**
    * An element id (without hashtag) to use as anchor.
    */
@@ -20,7 +20,7 @@ type BackToTopProps = {
  *
  * Render a back to top link.
  */
-const BackToTop: FC<BackToTopProps> = ({ additionalClasses, target }) => {
+const BackToTop: VFC<BackToTopProps> = ({ className = '', target }) => {
   const intl = useIntl();
   const linkName = intl.formatMessage({
     defaultMessage: 'Back to top',
@@ -29,7 +29,7 @@ const BackToTop: FC<BackToTopProps> = ({ additionalClasses, target }) => {
   });
 
   return (
-    <div className={`${styles.wrapper} ${additionalClasses}`}>
+    <div className={`${styles.wrapper} ${className}`}>
       <ButtonLink shape="square" target={`#${target}`} aria-label={linkName}>
         <Arrow direction="top" />
       </ButtonLink>
diff --git a/src/components/molecules/buttons/help-button.stories.tsx b/src/components/molecules/buttons/help-button.stories.tsx
index 7ed953e..cfc1b0b 100644
--- a/src/components/molecules/buttons/help-button.stories.tsx
+++ b/src/components/molecules/buttons/help-button.stories.tsx
@@ -6,11 +6,11 @@ export default {
   title: 'Molecules/Buttons',
   component: HelpButtonComponent,
   argTypes: {
-    classes: {
+    className: {
       control: {
         type: 'text',
       },
-      description: 'Set additional classes to the button.',
+      description: 'Set additional classnames to the button wrapper.',
       table: {
         category: 'Options',
       },
diff --git a/src/components/molecules/buttons/help-button.tsx b/src/components/molecules/buttons/help-button.tsx
index d933829..aeb84ec 100644
--- a/src/components/molecules/buttons/help-button.tsx
+++ b/src/components/molecules/buttons/help-button.tsx
@@ -1,13 +1,13 @@
 import Button, { ButtonProps } from '@components/atoms/buttons/button';
-import { FC } from 'react';
+import { VFC } from 'react';
 import { useIntl } from 'react-intl';
 import styles from './help-button.module.scss';
 
 export type HelpButtonProps = Pick<ButtonProps, 'onClick'> & {
   /**
-   * Set additional classes to the button.
+   * Set additional classnames to the button wrapper.
    */
-  classes?: string;
+  className?: string;
 };
 
 /**
@@ -15,7 +15,7 @@ export type HelpButtonProps = Pick<ButtonProps, 'onClick'> & {
  *
  * Render a button with an interrogation mark icon.
  */
-const HelpButton: FC<HelpButtonProps> = ({ classes = '', onClick }) => {
+const HelpButton: VFC<HelpButtonProps> = ({ className = '', onClick }) => {
   const intl = useIntl();
   const text = intl.formatMessage({
     defaultMessage: 'Help',
@@ -26,7 +26,7 @@ const HelpButton: FC<HelpButtonProps> = ({ classes = '', onClick }) => {
   return (
     <Button
       shape="circle"
-      additionalClasses={`${styles.btn} ${classes}`}
+      className={`${styles.btn} ${className}`}
       onClick={onClick}
     >
       <span className="screen-reader-text">{text}</span>
diff --git a/src/components/molecules/images/responsive-image.tsx b/src/components/molecules/images/responsive-image.tsx
index db2f5ab..9f96f18 100644
--- a/src/components/molecules/images/responsive-image.tsx
+++ b/src/components/molecules/images/responsive-image.tsx
@@ -1,6 +1,6 @@
 import Link from '@components/atoms/links/link';
 import Image, { ImageProps } from 'next/image';
-import { FC } from 'react';
+import { VFC } from 'react';
 import styles from './responsive-image.module.scss';
 
 type ResponsiveImageProps = Omit<ImageProps, 'alt' | 'width' | 'height'> & {
@@ -31,7 +31,7 @@ type ResponsiveImageProps = Omit<ImageProps, 'alt' | 'width' | 'height'> & {
  *
  * Render a responsive image wrapped in a figure element.
  */
-const ResponsiveImage: FC<ResponsiveImageProps> = ({
+const ResponsiveImage: VFC<ResponsiveImageProps> = ({
   alt,
   caption,
   layout,
@@ -42,7 +42,7 @@ const ResponsiveImage: FC<ResponsiveImageProps> = ({
   return (
     <figure className={styles.wrapper}>
       {target ? (
-        <Link href={target} classes={styles.link}>
+        <Link href={target} className={styles.link}>
           <Image alt={alt} layout={layout || 'intrinsic'} {...props} />
           {caption && (
             <figcaption className={styles.caption}>{caption}</figcaption>
diff --git a/src/components/molecules/layout/branding.tsx b/src/components/molecules/layout/branding.tsx
index efb2e34..9f564bf 100644
--- a/src/components/molecules/layout/branding.tsx
+++ b/src/components/molecules/layout/branding.tsx
@@ -1,6 +1,6 @@
 import Heading from '@components/atoms/headings/heading';
 import Link from 'next/link';
-import { FC } from 'react';
+import { VFC } from 'react';
 import { useIntl } from 'react-intl';
 import styles from './branding.module.scss';
 import FlippingLogo from './flipping-logo';
@@ -33,7 +33,7 @@ type BrandingProps = {
  *
  * Render the branding logo, title and optional baseline.
  */
-const Branding: FC<BrandingProps> = ({
+const Branding: VFC<BrandingProps> = ({
   baseline,
   isHome = false,
   photo,
@@ -61,7 +61,7 @@ const Branding: FC<BrandingProps> = ({
   return (
     <div className={styles.wrapper}>
       <FlippingLogo
-        additionalClasses={styles.logo}
+        className={styles.logo}
         altText={altText}
         logoTitle={logoTitle}
         photo={photo}
@@ -70,7 +70,7 @@ const Branding: FC<BrandingProps> = ({
         isFake={!isHome}
         level={1}
         withMargin={false}
-        additionalClasses={styles.title}
+        className={styles.title}
       >
         {withLink ? (
           <Link href="/">
@@ -85,7 +85,7 @@ const Branding: FC<BrandingProps> = ({
           isFake={true}
           level={4}
           withMargin={false}
-          additionalClasses={styles.baseline}
+          className={styles.baseline}
         >
           {baseline}
         </Heading>
diff --git a/src/components/molecules/layout/flipping-logo.stories.tsx b/src/components/molecules/layout/flipping-logo.stories.tsx
index 1508269..1ac8de8 100644
--- a/src/components/molecules/layout/flipping-logo.stories.tsx
+++ b/src/components/molecules/layout/flipping-logo.stories.tsx
@@ -5,11 +5,21 @@ export default {
   title: 'Molecules/Layout',
   component: FlippingLogoComponent,
   argTypes: {
-    additionalClasses: {
+    altText: {
+      control: {
+        type: 'text',
+      },
+      description: 'Photo alternative text.',
+      type: {
+        name: 'string',
+        required: true,
+      },
+    },
+    className: {
       control: {
         type: 'text',
       },
-      description: 'Adds additional classes to the logo wrapper.',
+      description: 'Set additional classnames to the logo wrapper.',
       table: {
         category: 'Options',
       },
@@ -18,14 +28,17 @@ export default {
         required: false,
       },
     },
-    altText: {
+    logoTitle: {
       control: {
         type: 'text',
       },
-      description: 'Photo alternative text.',
+      description: 'An accessible name for the logo.',
+      table: {
+        category: 'Accessibility',
+      },
       type: {
         name: 'string',
-        required: true,
+        required: false,
       },
     },
     photo: {
diff --git a/src/components/molecules/layout/flipping-logo.tsx b/src/components/molecules/layout/flipping-logo.tsx
index 7bb7afc..6f7645f 100644
--- a/src/components/molecules/layout/flipping-logo.tsx
+++ b/src/components/molecules/layout/flipping-logo.tsx
@@ -1,13 +1,13 @@
 import Logo from '@components/atoms/images/logo';
 import Image from 'next/image';
-import { FC } from 'react';
+import { VFC } from 'react';
 import styles from './flipping-logo.module.scss';
 
 type FlippingLogoProps = {
   /**
-   * Adds additional classes to the logo wrapper.
+   * Set additional classnames to the logo wrapper.
    */
-  additionalClasses?: string;
+  className?: string;
   /**
    * Photo alternative text.
    */
@@ -27,14 +27,14 @@ type FlippingLogoProps = {
  *
  * Render a logo and a photo with a flipping effect.
  */
-const FlippingLogo: FC<FlippingLogoProps> = ({
-  additionalClasses,
+const FlippingLogo: VFC<FlippingLogoProps> = ({
+  className = '',
   altText,
   logoTitle,
   photo,
 }) => {
   return (
-    <div className={`${styles.logo} ${additionalClasses}`}>
+    <div className={`${styles.logo} ${className}`}>
       <div className={styles.logo__front}>
         <Image src={photo} alt={altText} layout="fill" objectFit="cover" />
       </div>
diff --git a/src/components/molecules/modals/modal.stories.tsx b/src/components/molecules/modals/modal.stories.tsx
index b68a24b..bd7d9f4 100644
--- a/src/components/molecules/modals/modal.stories.tsx
+++ b/src/components/molecules/modals/modal.stories.tsx
@@ -15,6 +15,19 @@ export default {
         required: true,
       },
     },
+    className: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames to the modal.',
+      table: {
+        category: 'Styles',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
     icon: {
       control: {
         type: 'select',
diff --git a/src/components/molecules/modals/modal.tsx b/src/components/molecules/modals/modal.tsx
index 4dc3b0a..ce12e7a 100644
--- a/src/components/molecules/modals/modal.tsx
+++ b/src/components/molecules/modals/modal.tsx
@@ -1,17 +1,29 @@
 import Heading from '@components/atoms/headings/heading';
+import { CogProps } from '@components/atoms/icons/cog';
+import { MagnifyingGlassProps } from '@components/atoms/icons/magnifying-glass';
 import dynamic from 'next/dynamic';
-import { FC, ReactNode } from 'react';
+import { FC } from 'react';
 import styles from './modal.module.scss';
 
 export type Icons = 'cogs' | 'search';
 
 export type ModalProps = {
+  /**
+   * Set additional classnames.
+   */
+  className?: string;
+  /**
+   * A icon to illustrate the modal.
+   */
   icon?: Icons;
+  /**
+   * The modal title.
+   */
   title?: string;
 };
 
-const CogIcon = dynamic<ReactNode>(() => import('@components/atoms/icons/cog'));
-const SearchIcon = dynamic<ReactNode>(
+const CogIcon = dynamic<CogProps>(() => import('@components/atoms/icons/cog'));
+const SearchIcon = dynamic<MagnifyingGlassProps>(
   () => import('@components/atoms/icons/magnifying-glass')
 );
 
@@ -20,7 +32,7 @@ const SearchIcon = dynamic<ReactNode>(
  *
  * Render a modal component with an optional title and icon.
  */
-const Modal: FC<ModalProps> = ({ children, icon, title }) => {
+const Modal: FC<ModalProps> = ({ children, className = '', icon, title }) => {
   const getIcon = (id: Icons) => {
     switch (id) {
       case 'cogs':
@@ -33,7 +45,7 @@ const Modal: FC<ModalProps> = ({ children, icon, title }) => {
   };
 
   return (
-    <div className={styles.wrapper}>
+    <div className={`${styles.wrapper} ${className}`}>
       {title && (
         <Heading isFake={true} level={3}>
           {icon && <span className={styles.icon}>{getIcon(icon)}</span>}
diff --git a/src/components/molecules/modals/tooltip.stories.tsx b/src/components/molecules/modals/tooltip.stories.tsx
index a57cf34..63fc71d 100644
--- a/src/components/molecules/modals/tooltip.stories.tsx
+++ b/src/components/molecules/modals/tooltip.stories.tsx
@@ -5,6 +5,19 @@ export default {
   title: 'Molecules/Modals',
   component: TooltipComponent,
   argTypes: {
+    className: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames to the tooltip.',
+      table: {
+        category: 'Styles',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
     content: {
       control: {
         type: 'text',
@@ -15,6 +28,16 @@ export default {
         required: true,
       },
     },
+    icon: {
+      control: {
+        type: 'text',
+      },
+      description: 'The tooltip icon.',
+      type: {
+        name: 'string',
+        required: true,
+      },
+    },
     title: {
       control: {
         type: 'text',
diff --git a/src/components/molecules/modals/tooltip.tsx b/src/components/molecules/modals/tooltip.tsx
index ceb0b14..73f36e7 100644
--- a/src/components/molecules/modals/tooltip.tsx
+++ b/src/components/molecules/modals/tooltip.tsx
@@ -1,12 +1,12 @@
 import List, { type ListItem } from '@components/atoms/lists/list';
-import { FC, ReactNode } from 'react';
+import { ReactNode, VFC } from 'react';
 import styles from './tooltip.module.scss';
 
 export type TooltipProps = {
   /**
-   * Set additional classes to the tooltip wrapper.
+   * Set additional classnames to the tooltip wrapper.
    */
-  classes?: string;
+  className?: string;
   /**
    * The tooltip body.
    */
@@ -26,7 +26,12 @@ export type TooltipProps = {
  *
  * Render a tooltip modal.
  */
-const Tooltip: FC<TooltipProps> = ({ classes = '', content, icon, title }) => {
+const Tooltip: VFC<TooltipProps> = ({
+  className = '',
+  content,
+  icon,
+  title,
+}) => {
   /**
    * Format an array of strings to an array of object with id and value.
    *
@@ -40,7 +45,7 @@ const Tooltip: FC<TooltipProps> = ({ classes = '', content, icon, title }) => {
   };
 
   return (
-    <div className={`${styles.wrapper} ${classes}`}>
+    <div className={`${styles.wrapper} ${className}`}>
       <div className={styles.title}>
         <span className={styles.icon}>{icon}</span>
         {title}
-- 
cgit v1.2.3


From a08291b1586858fc894a27d56f55f87a88f8dbd3 Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
Date: Wed, 20 Apr 2022 19:24:21 +0200
Subject: refactor(storybook): reorganize design system

Add more stories for each components and change some components
categories for better organization.
---
 .storybook/main.js                                 |  14 ++-
 .../atoms/buttons/button-link.stories.tsx          |  46 +++++++--
 src/components/atoms/buttons/button-link.tsx       |   2 +-
 src/components/atoms/buttons/button.stories.tsx    |  42 ++++++--
 src/components/atoms/buttons/buttons.module.scss   |   5 +-
 src/components/atoms/forms/checkbox.stories.tsx    |   6 ++
 src/components/atoms/forms/field.stories.tsx       |  74 ++++++++++++--
 src/components/atoms/forms/label.stories.tsx       |   6 ++
 src/components/atoms/forms/select.stories.tsx      |   6 ++
 src/components/atoms/headings/heading.stories.tsx  |  72 ++++++++++++--
 src/components/atoms/icons/arrow.stories.tsx       |   8 +-
 src/components/atoms/icons/career.stories.tsx      |   8 +-
 src/components/atoms/icons/cc-by-sa.stories.tsx    |  19 +++-
 src/components/atoms/icons/close.stories.tsx       |   8 +-
 src/components/atoms/icons/cog.stories.tsx         |   8 +-
 .../atoms/icons/computer-screen.stories.tsx        |   8 +-
 src/components/atoms/icons/envelop.stories.tsx     |   8 +-
 src/components/atoms/icons/hamburger.stories.tsx   |   8 +-
 src/components/atoms/icons/home.stories.tsx        |   8 +-
 .../atoms/icons/magnifying-glass.stories.tsx       |   8 +-
 src/components/atoms/icons/moon.stories.tsx        |   8 +-
 src/components/atoms/icons/plus-minus.stories.tsx  |   8 +-
 src/components/atoms/icons/posts-stack.stories.tsx |   8 +-
 src/components/atoms/icons/sun.stories.tsx         |   8 +-
 src/components/atoms/images/logo.stories.tsx       |   8 +-
 src/components/atoms/layout/copyright.stories.tsx  |  17 +++-
 src/components/atoms/layout/main.stories.tsx       |   6 ++
 src/components/atoms/layout/no-script.stories.tsx  |  32 ++++--
 src/components/atoms/layout/notice.stories.tsx     |  39 +++++++-
 src/components/atoms/layout/section.stories.tsx    |  33 +++++--
 src/components/atoms/links/link.stories.tsx        |  43 +++++++--
 src/components/atoms/links/nav-link.stories.tsx    |   8 +-
 .../atoms/links/sharing-link.stories.tsx           |  57 ++++++++++-
 src/components/atoms/links/social-link.stories.tsx |  49 ++++++++--
 .../atoms/lists/description-list.stories.tsx       |   8 +-
 src/components/atoms/lists/list.stories.tsx        |  21 ++--
 .../atoms/loaders/progress-bar.stories.tsx         |  19 +++-
 src/components/atoms/loaders/spinner.stories.tsx   |  27 +++++-
 .../molecules/buttons/back-to-top.stories.tsx      |  17 +++-
 .../molecules/buttons/heading-button.stories.tsx   |  78 +++++++++++++--
 .../molecules/buttons/help-button.stories.tsx      |  17 +++-
 .../molecules/forms/ackee-select.stories.tsx       |  57 +++++++++--
 .../molecules/forms/labelled-field.stories.tsx     | 107 +++++++++++++++++++--
 .../molecules/forms/labelled-select.stories.tsx    |  69 ++++++++++---
 .../molecules/forms/motion-toggle.stories.tsx      |  36 +++++--
 .../molecules/forms/prism-theme-toggle.stories.tsx |  44 +++++++--
 .../forms/select-with-tooltip.stories.tsx          |  35 ++++---
 .../molecules/forms/theme-toggle.stories.tsx       |  44 +++++++--
 src/components/molecules/forms/toggle.stories.tsx  |  24 +++--
 .../molecules/images/flipping-logo.module.scss     |  59 ++++++++++++
 .../molecules/images/flipping-logo.stories.tsx     |  75 +++++++++++++++
 .../molecules/images/flipping-logo.test.tsx        |  25 +++++
 src/components/molecules/images/flipping-logo.tsx  |  55 +++++++++++
 .../molecules/images/responsive-image.module.scss  |   2 +-
 .../molecules/images/responsive-image.stories.tsx  |  63 ++++++++++--
 .../molecules/layout/branding.stories.tsx          |  46 +++++++--
 src/components/molecules/layout/branding.tsx       |   4 +-
 src/components/molecules/layout/card.module.scss   |   5 +-
 src/components/molecules/layout/card.stories.tsx   |  69 +++++++++++--
 src/components/molecules/layout/card.tsx           |   2 +-
 .../molecules/layout/flipping-logo.module.scss     |  59 ------------
 .../molecules/layout/flipping-logo.stories.tsx     |  66 -------------
 .../molecules/layout/flipping-logo.test.tsx        |  25 -----
 src/components/molecules/layout/flipping-logo.tsx  |  48 ---------
 src/components/molecules/layout/meta.stories.tsx   |  11 ++-
 src/components/molecules/layout/widget.module.scss |   5 +
 src/components/molecules/layout/widget.stories.tsx |  46 ++++++---
 src/components/molecules/modals/modal.stories.tsx  |  32 ++++--
 .../molecules/modals/tooltip.stories.tsx           |  22 +++--
 .../molecules/nav/breadcrumb.stories.tsx           |  60 +++++++++---
 src/components/molecules/nav/nav.stories.tsx       |  42 +++++---
 .../organisms/forms/comment-form.stories.tsx       |  31 ++++--
 .../organisms/forms/contact-form.stories.tsx       |  29 ++++--
 .../organisms/forms/search-form.stories.tsx        |  46 +++++++--
 .../organisms/layout/cards-list.stories.tsx        |  30 ++++++
 src/components/organisms/layout/footer.stories.tsx |  17 +++-
 .../organisms/layout/overview.stories.tsx          |  37 +++++--
 .../organisms/layout/summary.module.scss           |   1 +
 .../organisms/layout/summary.stories.tsx           |  60 +++++++++---
 src/components/organisms/layout/summary.tsx        |   4 +-
 .../organisms/modals/search-modal.stories.tsx      |  42 ++++++--
 .../organisms/modals/settings-modal.stories.tsx    |  30 +++++-
 .../organisms/toolbar/main-nav.stories.tsx         |  45 ++++++---
 .../organisms/toolbar/search.stories.tsx           |  41 +++++---
 .../organisms/toolbar/settings.stories.tsx         |  41 +++++---
 .../organisms/toolbar/toolbar.stories.tsx          |  40 +++++++-
 .../organisms/widgets/image-widget.module.scss     |   1 -
 .../organisms/widgets/image-widget.stories.tsx     |  71 ++++++++++++--
 .../widgets/links-list-widget.stories.tsx          |  37 +++++--
 .../organisms/widgets/sharing.stories.tsx          |  19 +++-
 src/components/organisms/widgets/sharing.tsx       |   2 +-
 .../organisms/widgets/social-media.stories.tsx     |  19 +++-
 92 files changed, 2117 insertions(+), 638 deletions(-)
 create mode 100644 src/components/molecules/images/flipping-logo.module.scss
 create mode 100644 src/components/molecules/images/flipping-logo.stories.tsx
 create mode 100644 src/components/molecules/images/flipping-logo.test.tsx
 create mode 100644 src/components/molecules/images/flipping-logo.tsx
 delete mode 100644 src/components/molecules/layout/flipping-logo.module.scss
 delete mode 100644 src/components/molecules/layout/flipping-logo.stories.tsx
 delete mode 100644 src/components/molecules/layout/flipping-logo.test.tsx
 delete mode 100644 src/components/molecules/layout/flipping-logo.tsx

(limited to 'src/components/atoms/links/link.stories.tsx')

diff --git a/.storybook/main.js b/.storybook/main.js
index 05aa578..bedbd0e 100644
--- a/.storybook/main.js
+++ b/.storybook/main.js
@@ -1,5 +1,9 @@
 const path = require('path');
 
+/**
+ * @typedef {import('webpack').Configuration} WebpackConfig
+ */
+
 const storybookConfig = {
   stories: ['../src/**/*.stories.@(md|mdx|js|jsx|ts|tsx)'],
   addons: [
@@ -12,6 +16,11 @@ const storybookConfig = {
   core: {
     builder: 'webpack5',
   },
+  staticDirs: ['../public'],
+  /**
+   * @param {WebpackConfig} config
+   * @return {Promise<WebpackConfig>}
+   */
   webpackFinal: async (config) => {
     // Use SVGR for SVG files. See: https://medium.com/@derek_19900/config-storybook-4-to-use-svgr-webpack-plugin-22cb1152f004
     const rules = config.module.rules;
@@ -22,6 +31,9 @@ const storybookConfig = {
       use: [{ loader: '@svgr/webpack', options: { dimensions: false } }],
     });
 
+    /** @type {import('next').NextConfig} */
+    const nextConfig = require('../next.config');
+
     // Set modules aliases.
     config.resolve.alias = {
       ...config.resolve.alias,
@@ -35,7 +47,7 @@ const storybookConfig = {
       '@utils': path.resolve(__dirname, '../src/utils'),
     };
 
-    return config;
+    return { ...config, ...nextConfig.webpack };
   },
 };
 
diff --git a/src/components/atoms/buttons/button-link.stories.tsx b/src/components/atoms/buttons/button-link.stories.tsx
index 92b7521..2e1c040 100644
--- a/src/components/atoms/buttons/button-link.stories.tsx
+++ b/src/components/atoms/buttons/button-link.stories.tsx
@@ -1,9 +1,15 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
-import ButtonLinkComponent from './button-link';
+import ButtonLink from './button-link';
 
+/**
+ * ButtonLink - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Buttons',
-  component: ButtonLinkComponent,
+  title: 'Atoms/Buttons/ButtonLink',
+  component: ButtonLink,
+  args: {
+    shape: 'rectangle',
+  },
   argTypes: {
     'aria-label': {
       control: {
@@ -82,14 +88,38 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof ButtonLinkComponent>;
+} as ComponentMeta<typeof ButtonLink>;
 
-const Template: ComponentStory<typeof ButtonLinkComponent> = (args) => (
-  <ButtonLinkComponent {...args} />
+const Template: ComponentStory<typeof ButtonLink> = (args) => (
+  <ButtonLink {...args} />
 );
 
-export const ButtonLink = Template.bind({});
-ButtonLink.args = {
+/**
+ * ButtonLink Story - Primary
+ */
+export const Primary = Template.bind({});
+Primary.args = {
+  children: 'Link',
+  kind: 'primary',
+  target: '#',
+};
+
+/**
+ * ButtonLink Story - Secondary
+ */
+export const Secondary = Template.bind({});
+Secondary.args = {
+  children: 'Link',
+  kind: 'secondary',
+  target: '#',
+};
+
+/**
+ * ButtonLink Story - Tertiary
+ */
+export const Tertiary = Template.bind({});
+Tertiary.args = {
   children: 'Link',
+  kind: 'tertiary',
   target: '#',
 };
diff --git a/src/components/atoms/buttons/button-link.tsx b/src/components/atoms/buttons/button-link.tsx
index 906fa76..64e0afd 100644
--- a/src/components/atoms/buttons/button-link.tsx
+++ b/src/components/atoms/buttons/button-link.tsx
@@ -22,7 +22,7 @@ export type ButtonLinkProps = {
   /**
    * ButtonLink kind. Default: secondary.
    */
-  kind?: 'primary' | 'secondary';
+  kind?: 'primary' | 'secondary' | 'tertiary';
   /**
    * ButtonLink shape. Default: rectangle.
    */
diff --git a/src/components/atoms/buttons/button.stories.tsx b/src/components/atoms/buttons/button.stories.tsx
index d47a1ea..6803706 100644
--- a/src/components/atoms/buttons/button.stories.tsx
+++ b/src/components/atoms/buttons/button.stories.tsx
@@ -1,12 +1,14 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
-import ButtonComponent from './button';
+import Button from './button';
 
+/**
+ * Button - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Buttons',
-  component: ButtonComponent,
+  title: 'Atoms/Buttons/Button',
+  component: Button,
   args: {
     disabled: false,
-    kind: 'secondary',
     type: 'button',
   },
   argTypes: {
@@ -119,9 +121,9 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof ButtonComponent>;
+} as ComponentMeta<typeof Button>;
 
-const Template: ComponentStory<typeof ButtonComponent> = (args) => {
+const Template: ComponentStory<typeof Button> = (args) => {
   const { children, type, ...props } = args;
 
   const getBody = () => {
@@ -139,10 +141,32 @@ const Template: ComponentStory<typeof ButtonComponent> = (args) => {
   };
 
   return (
-    <ButtonComponent type={type} {...props}>
+    <Button type={type} {...props}>
       {getBody()}
-    </ButtonComponent>
+    </Button>
   );
 };
 
-export const Button = Template.bind({});
+/**
+ * Button Story - Primary
+ */
+export const Primary = Template.bind({});
+Primary.args = {
+  kind: 'primary',
+};
+
+/**
+ * Button Story - Secondary
+ */
+export const Secondary = Template.bind({});
+Secondary.args = {
+  kind: 'secondary',
+};
+
+/**
+ * Button Story - Tertiary
+ */
+export const Tertiary = Template.bind({});
+Tertiary.args = {
+  kind: 'tertiary',
+};
diff --git a/src/components/atoms/buttons/buttons.module.scss b/src/components/atoms/buttons/buttons.module.scss
index 8e3e196..36c66b6 100644
--- a/src/components/atoms/buttons/buttons.module.scss
+++ b/src/components/atoms/buttons/buttons.module.scss
@@ -8,6 +8,7 @@
   border-radius: fun.convert-px(5);
   font-size: var(--font-size-md);
   font-weight: 600;
+  text-decoration: none;
   transition: all 0.3s ease-in-out 0s;
 
   &--initial {
@@ -44,7 +45,6 @@
       fun.convert-px(2) fun.convert-px(2) 0 fun.convert-px(3)
         var(--color-primary-dark);
     color: var(--color-fg-inverted);
-    text-decoration: none;
     text-shadow: fun.convert-px(2) fun.convert-px(2) 0 var(--color-shadow);
 
     &:disabled {
@@ -91,7 +91,6 @@
       fun.convert-px(3) fun.convert-px(4) fun.convert-px(5) fun.convert-px(-4)
         var(--color-shadow);
     color: var(--color-primary);
-    text-decoration: underline transparent 0;
 
     &:disabled {
       border-color: var(--color-border-dark);
@@ -122,7 +121,7 @@
         border-color: var(--color-primary-dark);
         box-shadow: 0 0 0 0 var(--color-shadow);
         color: var(--color-primary-dark);
-        text-decoration: underline transparent 0;
+        text-decoration: none;
         transform: scale(var(--scale-down, 0.94));
       }
     }
diff --git a/src/components/atoms/forms/checkbox.stories.tsx b/src/components/atoms/forms/checkbox.stories.tsx
index 7faf343..588fdcc 100644
--- a/src/components/atoms/forms/checkbox.stories.tsx
+++ b/src/components/atoms/forms/checkbox.stories.tsx
@@ -2,6 +2,9 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { useState } from 'react';
 import CheckboxComponent from './checkbox';
 
+/**
+ * Checkbox - Storybook Meta
+ */
 export default {
   title: 'Atoms/Forms',
   component: CheckboxComponent,
@@ -88,6 +91,9 @@ const Template: ComponentStory<typeof CheckboxComponent> = ({
   );
 };
 
+/**
+ * Checkbox Story
+ */
 export const Checkbox = Template.bind({});
 Checkbox.args = {
   id: 'storybook-checkbox',
diff --git a/src/components/atoms/forms/field.stories.tsx b/src/components/atoms/forms/field.stories.tsx
index ec81922..00a183d 100644
--- a/src/components/atoms/forms/field.stories.tsx
+++ b/src/components/atoms/forms/field.stories.tsx
@@ -1,14 +1,16 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { useState } from 'react';
-import FieldComponent from './field';
+import Field from './field';
 
+/**
+ * Field - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Forms',
-  component: FieldComponent,
+  title: 'Atoms/Forms/Fields',
+  component: Field,
   args: {
     disabled: false,
     required: false,
-    type: 'text',
   },
   argTypes: {
     'aria-labelledby': {
@@ -182,20 +184,74 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof FieldComponent>;
+} as ComponentMeta<typeof Field>;
 
-const Template: ComponentStory<typeof FieldComponent> = ({
+const Template: ComponentStory<typeof Field> = ({
   value: _value,
   setValue: _setValue,
   ...args
 }) => {
   const [value, setValue] = useState<string>('');
 
-  return <FieldComponent value={value} setValue={setValue} {...args} />;
+  return <Field value={value} setValue={setValue} {...args} />;
 };
 
-export const Field = Template.bind({});
-Field.args = {
+/**
+ * Field Story - DateTime
+ */
+export const DateTime = Template.bind({});
+DateTime.args = {
   id: 'field-storybook',
   name: 'field-storybook',
+  type: 'datetime-local',
+};
+
+/**
+ * Field Story - Email
+ */
+export const Email = Template.bind({});
+Email.args = {
+  id: 'field-storybook',
+  name: 'field-storybook',
+  type: 'email',
+};
+
+/**
+ * Field Story - Text
+ */
+export const Text = Template.bind({});
+Text.args = {
+  id: 'field-storybook',
+  name: 'field-storybook',
+  type: 'text',
+};
+
+/**
+ * Field Story - Number
+ */
+export const Number = Template.bind({});
+Number.args = {
+  id: 'field-storybook',
+  name: 'field-storybook',
+  type: 'number',
+};
+
+/**
+ * Field Story - TextArea
+ */
+export const TextArea = Template.bind({});
+TextArea.args = {
+  id: 'field-storybook',
+  name: 'field-storybook',
+  type: 'textarea',
+};
+
+/**
+ * Field Story - Time
+ */
+export const Time = Template.bind({});
+Time.args = {
+  id: 'field-storybook',
+  name: 'field-storybook',
+  type: 'time',
 };
diff --git a/src/components/atoms/forms/label.stories.tsx b/src/components/atoms/forms/label.stories.tsx
index 463e8ac..79f1a34 100644
--- a/src/components/atoms/forms/label.stories.tsx
+++ b/src/components/atoms/forms/label.stories.tsx
@@ -1,6 +1,9 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import LabelComponent from './label';
 
+/**
+ * Label - Storybook Meta
+ */
 export default {
   title: 'Atoms/Forms',
   component: LabelComponent,
@@ -79,6 +82,9 @@ const Template: ComponentStory<typeof LabelComponent> = ({
   ...args
 }) => <LabelComponent {...args}>{children}</LabelComponent>;
 
+/**
+ * Label Story
+ */
 export const Label = Template.bind({});
 Label.args = {
   children: 'A label',
diff --git a/src/components/atoms/forms/select.stories.tsx b/src/components/atoms/forms/select.stories.tsx
index c2fb8c6..7127597 100644
--- a/src/components/atoms/forms/select.stories.tsx
+++ b/src/components/atoms/forms/select.stories.tsx
@@ -8,6 +8,9 @@ const selectOptions = [
   { id: 'option3', name: 'Option 3', value: 'option3' },
 ];
 
+/**
+ * Select - Storybook Meta
+ */
 export default {
   title: 'Atoms/Forms',
   component: SelectComponent,
@@ -136,6 +139,9 @@ const Template: ComponentStory<typeof SelectComponent> = ({
   return <SelectComponent value={selected} setValue={setSelected} {...args} />;
 };
 
+/**
+ * Select Story
+ */
 export const Select = Template.bind({});
 Select.args = {
   id: 'storybook-select',
diff --git a/src/components/atoms/headings/heading.stories.tsx b/src/components/atoms/headings/heading.stories.tsx
index 66a84dc..da5a718 100644
--- a/src/components/atoms/headings/heading.stories.tsx
+++ b/src/components/atoms/headings/heading.stories.tsx
@@ -1,9 +1,12 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
-import HeadingComponent from './heading';
+import Heading from './heading';
 
+/**
+ * Heading - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Headings',
-  component: HeadingComponent,
+  title: 'Atoms/Typography/Headings',
+  component: Heading,
   args: {
     isFake: false,
     withMargin: true,
@@ -45,10 +48,11 @@ export default {
     },
     level: {
       control: {
-        type: 'select',
+        type: 'number',
+        min: 1,
+        max: 6,
       },
       description: 'Heading level.',
-      options: [1, 2, 3, 4, 5, 6],
       type: {
         name: 'number',
         required: true,
@@ -69,14 +73,62 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof HeadingComponent>;
+} as ComponentMeta<typeof Heading>;
 
-const Template: ComponentStory<typeof HeadingComponent> = (args) => (
-  <HeadingComponent {...args} />
+const Template: ComponentStory<typeof Heading> = (args) => (
+  <Heading {...args} />
 );
 
-export const Heading = Template.bind({});
-Heading.args = {
+/**
+ * Heading Story - h1
+ */
+export const H1 = Template.bind({});
+H1.args = {
   children: 'Your title',
   level: 1,
 };
+
+/**
+ * Heading Story - h2
+ */
+export const H2 = Template.bind({});
+H2.args = {
+  children: 'Your title',
+  level: 2,
+};
+
+/**
+ * Heading Story - h3
+ */
+export const H3 = Template.bind({});
+H3.args = {
+  children: 'Your title',
+  level: 3,
+};
+
+/**
+ * Heading Story - h4
+ */
+export const H4 = Template.bind({});
+H4.args = {
+  children: 'Your title',
+  level: 4,
+};
+
+/**
+ * Heading Story - h5
+ */
+export const H5 = Template.bind({});
+H5.args = {
+  children: 'Your title',
+  level: 5,
+};
+
+/**
+ * Heading Story - h6
+ */
+export const H6 = Template.bind({});
+H6.args = {
+  children: 'Your title',
+  level: 6,
+};
diff --git a/src/components/atoms/icons/arrow.stories.tsx b/src/components/atoms/icons/arrow.stories.tsx
index 96ce1d8..1941479 100644
--- a/src/components/atoms/icons/arrow.stories.tsx
+++ b/src/components/atoms/icons/arrow.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import ArrowIcon from './arrow';
 
+/**
+ * Arrow icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: ArrowIcon,
   argTypes: {
     className: {
@@ -36,6 +39,9 @@ const Template: ComponentStory<typeof ArrowIcon> = (args) => (
   <ArrowIcon {...args} />
 );
 
+/**
+ * Icons Stories - Arrow
+ */
 export const Arrow = Template.bind({});
 Arrow.args = {
   direction: 'right',
diff --git a/src/components/atoms/icons/career.stories.tsx b/src/components/atoms/icons/career.stories.tsx
index 8575cb9..7b11bb8 100644
--- a/src/components/atoms/icons/career.stories.tsx
+++ b/src/components/atoms/icons/career.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import CareerIcon from './career';
 
+/**
+ * Career icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: CareerIcon,
   argTypes: {
     className: {
@@ -25,4 +28,7 @@ const Template: ComponentStory<typeof CareerIcon> = (args) => (
   <CareerIcon {...args} />
 );
 
+/**
+ * Icons Stories - Career
+ */
 export const Career = Template.bind({});
diff --git a/src/components/atoms/icons/cc-by-sa.stories.tsx b/src/components/atoms/icons/cc-by-sa.stories.tsx
index 21d6cd5..f2bc8f0 100644
--- a/src/components/atoms/icons/cc-by-sa.stories.tsx
+++ b/src/components/atoms/icons/cc-by-sa.stories.tsx
@@ -2,8 +2,11 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import CCBySAIcon from './cc-by-sa';
 
+/**
+ * CC BY SA icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: CCBySAIcon,
   argTypes: {
     className: {
@@ -20,12 +23,20 @@ export default {
       },
     },
   },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof CCBySAIcon>;
 
 const Template: ComponentStory<typeof CCBySAIcon> = (args) => (
-  <IntlProvider locale="en">
-    <CCBySAIcon {...args} />
-  </IntlProvider>
+  <CCBySAIcon {...args} />
 );
 
+/**
+ * Icons Stories - CC BY SA
+ */
 export const CCBySA = Template.bind({});
diff --git a/src/components/atoms/icons/close.stories.tsx b/src/components/atoms/icons/close.stories.tsx
index b1d88cd..f9628db 100644
--- a/src/components/atoms/icons/close.stories.tsx
+++ b/src/components/atoms/icons/close.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import CloseIcon from './close';
 
+/**
+ * Close icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: CloseIcon,
   argTypes: {
     className: {
@@ -25,4 +28,7 @@ const Template: ComponentStory<typeof CloseIcon> = (args) => (
   <CloseIcon {...args} />
 );
 
+/**
+ * Icons Stories - Close
+ */
 export const Close = Template.bind({});
diff --git a/src/components/atoms/icons/cog.stories.tsx b/src/components/atoms/icons/cog.stories.tsx
index ee883d8..631f30d 100644
--- a/src/components/atoms/icons/cog.stories.tsx
+++ b/src/components/atoms/icons/cog.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import CogIcon from './cog';
 
+/**
+ * Cogs icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: CogIcon,
   argTypes: {
     className: {
@@ -25,4 +28,7 @@ const Template: ComponentStory<typeof CogIcon> = (args) => (
   <CogIcon {...args} />
 );
 
+/**
+ * Icons Stories - Cogs
+ */
 export const Cog = Template.bind({});
diff --git a/src/components/atoms/icons/computer-screen.stories.tsx b/src/components/atoms/icons/computer-screen.stories.tsx
index 46e3ad4..19649ad 100644
--- a/src/components/atoms/icons/computer-screen.stories.tsx
+++ b/src/components/atoms/icons/computer-screen.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import ComputerScreenIcon from './computer-screen';
 
+/**
+ * Computer Screen icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: ComputerScreenIcon,
   argTypes: {
     className: {
@@ -25,4 +28,7 @@ const Template: ComponentStory<typeof ComputerScreenIcon> = (args) => (
   <ComputerScreenIcon {...args} />
 );
 
+/**
+ * Icons Stories - Computer Screen
+ */
 export const ComputerScreen = Template.bind({});
diff --git a/src/components/atoms/icons/envelop.stories.tsx b/src/components/atoms/icons/envelop.stories.tsx
index 9139b44..efa94dd 100644
--- a/src/components/atoms/icons/envelop.stories.tsx
+++ b/src/components/atoms/icons/envelop.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import EnvelopIcon from './envelop';
 
+/**
+ * Envelop icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: EnvelopIcon,
   argTypes: {
     className: {
@@ -25,4 +28,7 @@ const Template: ComponentStory<typeof EnvelopIcon> = (args) => (
   <EnvelopIcon {...args} />
 );
 
+/**
+ * Icons Stories - Envelop
+ */
 export const Envelop = Template.bind({});
diff --git a/src/components/atoms/icons/hamburger.stories.tsx b/src/components/atoms/icons/hamburger.stories.tsx
index c753e69..0a8a8cc 100644
--- a/src/components/atoms/icons/hamburger.stories.tsx
+++ b/src/components/atoms/icons/hamburger.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import HamburgerIcon from './hamburger';
 
+/**
+ * Hamburger icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: HamburgerIcon,
   argTypes: {
     className: {
@@ -38,4 +41,7 @@ const Template: ComponentStory<typeof HamburgerIcon> = (args) => (
   <HamburgerIcon {...args} />
 );
 
+/**
+ * Icons Stories - Hamburger
+ */
 export const Hamburger = Template.bind({});
diff --git a/src/components/atoms/icons/home.stories.tsx b/src/components/atoms/icons/home.stories.tsx
index b1c995c..ffb3061 100644
--- a/src/components/atoms/icons/home.stories.tsx
+++ b/src/components/atoms/icons/home.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import HomeIcon from './home';
 
+/**
+ * Home icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: HomeIcon,
   argTypes: {
     className: {
@@ -25,4 +28,7 @@ const Template: ComponentStory<typeof HomeIcon> = (args) => (
   <HomeIcon {...args} />
 );
 
+/**
+ * Icons Stories - Home
+ */
 export const Home = Template.bind({});
diff --git a/src/components/atoms/icons/magnifying-glass.stories.tsx b/src/components/atoms/icons/magnifying-glass.stories.tsx
index 80e183e..3e33deb 100644
--- a/src/components/atoms/icons/magnifying-glass.stories.tsx
+++ b/src/components/atoms/icons/magnifying-glass.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import MagnifyingGlassIcon from './magnifying-glass';
 
+/**
+ * Magnifying Glass icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: MagnifyingGlassIcon,
   argTypes: {
     className: {
@@ -25,4 +28,7 @@ const Template: ComponentStory<typeof MagnifyingGlassIcon> = (args) => (
   <MagnifyingGlassIcon {...args} />
 );
 
+/**
+ * Icons Stories - Magnifying Glass
+ */
 export const MagnifyingGlass = Template.bind({});
diff --git a/src/components/atoms/icons/moon.stories.tsx b/src/components/atoms/icons/moon.stories.tsx
index 4d2fb9a..e8b34de 100644
--- a/src/components/atoms/icons/moon.stories.tsx
+++ b/src/components/atoms/icons/moon.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import MoonIcon from './moon';
 
+/**
+ * Moon icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: MoonIcon,
   argTypes: {
     className: {
@@ -38,4 +41,7 @@ const Template: ComponentStory<typeof MoonIcon> = (args) => (
   <MoonIcon {...args} />
 );
 
+/**
+ * Icons Stories - Moon
+ */
 export const Moon = Template.bind({});
diff --git a/src/components/atoms/icons/plus-minus.stories.tsx b/src/components/atoms/icons/plus-minus.stories.tsx
index ffa28f2..f7e55f8 100644
--- a/src/components/atoms/icons/plus-minus.stories.tsx
+++ b/src/components/atoms/icons/plus-minus.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import PlusMinusIcon from './plus-minus';
 
+/**
+ * Plus/Minus icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: PlusMinusIcon,
   argTypes: {
     className: {
@@ -37,6 +40,9 @@ const Template: ComponentStory<typeof PlusMinusIcon> = (args) => (
   <PlusMinusIcon {...args} />
 );
 
+/**
+ * Icons Stories - Plus/Minus
+ */
 export const PlusMinus = Template.bind({});
 PlusMinus.args = {
   state: 'plus',
diff --git a/src/components/atoms/icons/posts-stack.stories.tsx b/src/components/atoms/icons/posts-stack.stories.tsx
index 46bb39f..1990b98 100644
--- a/src/components/atoms/icons/posts-stack.stories.tsx
+++ b/src/components/atoms/icons/posts-stack.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import PostsStackIcon from './posts-stack';
 
+/**
+ * Posts Stack icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: PostsStackIcon,
   argTypes: {
     className: {
@@ -25,4 +28,7 @@ const Template: ComponentStory<typeof PostsStackIcon> = (args) => (
   <PostsStackIcon {...args} />
 );
 
+/**
+ * Icons Stories - Posts Stack
+ */
 export const PostsStack = Template.bind({});
diff --git a/src/components/atoms/icons/sun.stories.tsx b/src/components/atoms/icons/sun.stories.tsx
index 23c5b27..60af648 100644
--- a/src/components/atoms/icons/sun.stories.tsx
+++ b/src/components/atoms/icons/sun.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import SunIcon from './sun';
 
+/**
+ * Sun icon - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Icons',
+  title: 'Atoms/Illustrations/Icons',
   component: SunIcon,
   argTypes: {
     className: {
@@ -38,4 +41,7 @@ const Template: ComponentStory<typeof SunIcon> = (args) => (
   <SunIcon {...args} />
 );
 
+/**
+ * Icons Stories - Sun
+ */
 export const Sun = Template.bind({});
diff --git a/src/components/atoms/images/logo.stories.tsx b/src/components/atoms/images/logo.stories.tsx
index fbc7501..458ec08 100644
--- a/src/components/atoms/images/logo.stories.tsx
+++ b/src/components/atoms/images/logo.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import LogoComponent from './logo';
 
+/**
+ * Logo - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Images',
+  title: 'Atoms/Illustrations/Images',
   component: LogoComponent,
   argTypes: {
     title: {
@@ -25,4 +28,7 @@ const Template: ComponentStory<typeof LogoComponent> = (args) => (
   <LogoComponent {...args} />
 );
 
+/**
+ * Images Stories - Logo
+ */
 export const Logo = Template.bind({});
diff --git a/src/components/atoms/layout/copyright.stories.tsx b/src/components/atoms/layout/copyright.stories.tsx
index 3b315fa..b988165 100644
--- a/src/components/atoms/layout/copyright.stories.tsx
+++ b/src/components/atoms/layout/copyright.stories.tsx
@@ -3,6 +3,9 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import CopyrightComponent from './copyright';
 
+/**
+ * Copyright - Storybook Meta
+ */
 export default {
   title: 'Atoms/Layout',
   component: CopyrightComponent,
@@ -36,14 +39,22 @@ export default {
       },
     },
   },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof CopyrightComponent>;
 
 const Template: ComponentStory<typeof CopyrightComponent> = (args) => (
-  <IntlProvider locale="en">
-    <CopyrightComponent {...args} />
-  </IntlProvider>
+  <CopyrightComponent {...args} />
 );
 
+/**
+ * Layout Stories - Copyright
+ */
 export const Copyright = Template.bind({});
 Copyright.args = {
   dates: {
diff --git a/src/components/atoms/layout/main.stories.tsx b/src/components/atoms/layout/main.stories.tsx
index 64df890..5bde475 100644
--- a/src/components/atoms/layout/main.stories.tsx
+++ b/src/components/atoms/layout/main.stories.tsx
@@ -1,6 +1,9 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import MainComponent from './main';
 
+/**
+ * Main - Storybook Meta
+ */
 export default {
   title: 'Atoms/Layout',
   component: MainComponent,
@@ -45,6 +48,9 @@ const Template: ComponentStory<typeof MainComponent> = (args) => (
   <MainComponent {...args} />
 );
 
+/**
+ * Layout Stories - Main
+ */
 export const Main = Template.bind({});
 Main.args = {
   children: 'The main content.',
diff --git a/src/components/atoms/layout/no-script.stories.tsx b/src/components/atoms/layout/no-script.stories.tsx
index 474e2fb..22d2fea 100644
--- a/src/components/atoms/layout/no-script.stories.tsx
+++ b/src/components/atoms/layout/no-script.stories.tsx
@@ -1,9 +1,12 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
-import NoScriptComponent from './no-script';
+import NoScript from './no-script';
 
+/**
+ * NoScript - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Layout',
-  component: NoScriptComponent,
+  title: 'Atoms/Layout/NoScript',
+  component: NoScript,
   args: {
     position: 'initial',
   },
@@ -34,13 +37,26 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof NoScriptComponent>;
+} as ComponentMeta<typeof NoScript>;
 
-const Template: ComponentStory<typeof NoScriptComponent> = (args) => (
-  <NoScriptComponent {...args} />
+const Template: ComponentStory<typeof NoScript> = (args) => (
+  <NoScript {...args} />
 );
 
-export const NoScript = Template.bind({});
-NoScript.args = {
+/**
+ * NoScript Stories - Default
+ */
+export const Default = Template.bind({});
+Default.args = {
   message: 'A noscript only message.',
+  position: 'initial',
+};
+
+/**
+ * NoScript Stories - Top
+ */
+export const Top = Template.bind({});
+Top.args = {
+  message: 'A noscript only message.',
+  position: 'top',
 };
diff --git a/src/components/atoms/layout/notice.stories.tsx b/src/components/atoms/layout/notice.stories.tsx
index 0555a2e..62f4cba 100644
--- a/src/components/atoms/layout/notice.stories.tsx
+++ b/src/components/atoms/layout/notice.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import NoticeComponent from './notice';
 
+/**
+ * Notice - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Layout',
+  title: 'Atoms/Layout/Notice',
   component: NoticeComponent,
   argTypes: {
     kind: {
@@ -33,8 +36,38 @@ const Template: ComponentStory<typeof NoticeComponent> = (args) => (
   <NoticeComponent {...args} />
 );
 
-export const Notice = Template.bind({});
-Notice.args = {
+/**
+ * Notice stories - Error
+ */
+export const Error = Template.bind({});
+Error.args = {
+  kind: 'error',
+  message: 'Nisi provident sapiente.',
+};
+
+/**
+ * Notice stories - Info
+ */
+export const Info = Template.bind({});
+Info.args = {
   kind: 'info',
   message: 'Nisi provident sapiente.',
 };
+
+/**
+ * Notice stories - Success
+ */
+export const Success = Template.bind({});
+Success.args = {
+  kind: 'success',
+  message: 'Nisi provident sapiente.',
+};
+
+/**
+ * Notice stories - Warning
+ */
+export const Warning = Template.bind({});
+Warning.args = {
+  kind: 'warning',
+  message: 'Nisi provident sapiente.',
+};
diff --git a/src/components/atoms/layout/section.stories.tsx b/src/components/atoms/layout/section.stories.tsx
index abbbeed..530b2a0 100644
--- a/src/components/atoms/layout/section.stories.tsx
+++ b/src/components/atoms/layout/section.stories.tsx
@@ -1,9 +1,12 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
-import SectionComponent from './section';
+import Section from './section';
 
+/**
+ * Section - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Layout',
-  component: SectionComponent,
+  title: 'Atoms/Layout/Section',
+  component: Section,
   args: {
     variant: 'dark',
     withBorder: true,
@@ -72,14 +75,28 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof SectionComponent>;
+} as ComponentMeta<typeof Section>;
 
-const Template: ComponentStory<typeof SectionComponent> = (args) => (
-  <SectionComponent {...args} />
+const Template: ComponentStory<typeof Section> = (args) => (
+  <Section {...args} />
 );
 
-export const Section = Template.bind({});
-Section.args = {
+/**
+ * Section Stories - Light
+ */
+export const Light = Template.bind({});
+Light.args = {
   title: 'A title',
   content: 'The content.',
+  variant: 'light',
+};
+
+/**
+ * Section Stories - Dark
+ */
+export const Dark = Template.bind({});
+Dark.args = {
+  title: 'A title',
+  content: 'The content.',
+  variant: 'dark',
 };
diff --git a/src/components/atoms/links/link.stories.tsx b/src/components/atoms/links/link.stories.tsx
index 569c874..c3b3465 100644
--- a/src/components/atoms/links/link.stories.tsx
+++ b/src/components/atoms/links/link.stories.tsx
@@ -1,9 +1,12 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
-import LinkComponent from './link';
+import Link from './link';
 
+/**
+ * Link - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Links',
-  component: LinkComponent,
+  title: 'Atoms/Typography/Links',
+  component: Link,
   argTypes: {
     children: {
       control: {
@@ -65,15 +68,37 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof LinkComponent>;
+} as ComponentMeta<typeof Link>;
 
-const Template: ComponentStory<typeof LinkComponent> = (args) => (
-  <LinkComponent {...args} />
-);
+const Template: ComponentStory<typeof Link> = (args) => <Link {...args} />;
 
-export const Link = Template.bind({});
-Link.args = {
+/**
+ * Links Stories - Default
+ */
+export const Default = Template.bind({});
+Default.args = {
   children: 'A link',
   href: '#',
   external: false,
 };
+
+/**
+ * Links Stories - External
+ */
+export const External = Template.bind({});
+External.args = {
+  children: 'A link',
+  href: '#',
+  external: true,
+};
+
+/**
+ * Links Stories - External With Lang
+ */
+export const ExternalWithLang = Template.bind({});
+ExternalWithLang.args = {
+  children: 'A link',
+  href: '#',
+  external: true,
+  lang: 'en',
+};
diff --git a/src/components/atoms/links/nav-link.stories.tsx b/src/components/atoms/links/nav-link.stories.tsx
index 08553be..7f7a334 100644
--- a/src/components/atoms/links/nav-link.stories.tsx
+++ b/src/components/atoms/links/nav-link.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import NavLinkComponent from './nav-link';
 
+/**
+ * NavLink - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Links',
+  title: 'Atoms/Typography/Links',
   component: NavLinkComponent,
   argTypes: {
     href: {
@@ -42,6 +45,9 @@ const Template: ComponentStory<typeof NavLinkComponent> = (args) => (
   <NavLinkComponent {...args} />
 );
 
+/**
+ * Links Stories - Nav Link
+ */
 export const NavLink = Template.bind({});
 NavLink.args = {
   href: '#',
diff --git a/src/components/atoms/links/sharing-link.stories.tsx b/src/components/atoms/links/sharing-link.stories.tsx
index 335fa50..c91e938 100644
--- a/src/components/atoms/links/sharing-link.stories.tsx
+++ b/src/components/atoms/links/sharing-link.stories.tsx
@@ -2,8 +2,11 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import SharingLinkComponent from './sharing-link';
 
+/**
+ * SharingLink - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Links',
+  title: 'Atoms/Buttons/Sharing',
   component: SharingLinkComponent,
   argTypes: {
     medium: {
@@ -43,8 +46,56 @@ const Template: ComponentStory<typeof SharingLinkComponent> = (args) => (
   </IntlProvider>
 );
 
-export const SharingLink = Template.bind({});
-SharingLink.args = {
+/**
+ * Sharing Link Stories - Diaspora
+ */
+export const Diaspora = Template.bind({});
+Diaspora.args = {
   medium: 'diaspora',
   url: '#',
 };
+
+/**
+ * Sharing Link Stories - Email
+ */
+export const Email = Template.bind({});
+Email.args = {
+  medium: 'email',
+  url: '#',
+};
+
+/**
+ * Sharing Link Stories - Facebook
+ */
+export const Facebook = Template.bind({});
+Facebook.args = {
+  medium: 'facebook',
+  url: '#',
+};
+
+/**
+ * Sharing Link Stories - Journal du Hacker
+ */
+export const JournalDuHacker = Template.bind({});
+JournalDuHacker.args = {
+  medium: 'journal-du-hacker',
+  url: '#',
+};
+
+/**
+ * Sharing Link Stories - LinkedIn
+ */
+export const LinkedIn = Template.bind({});
+LinkedIn.args = {
+  medium: 'linkedin',
+  url: '#',
+};
+
+/**
+ * Sharing Link Stories - Twitter
+ */
+export const Twitter = Template.bind({});
+Twitter.args = {
+  medium: 'twitter',
+  url: '#',
+};
diff --git a/src/components/atoms/links/social-link.stories.tsx b/src/components/atoms/links/social-link.stories.tsx
index bd9a364..977ae6b 100644
--- a/src/components/atoms/links/social-link.stories.tsx
+++ b/src/components/atoms/links/social-link.stories.tsx
@@ -1,9 +1,12 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
-import SocialLinkComponent from './social-link';
+import SocialLink from './social-link';
 
+/**
+ * SocialLink - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Links',
-  component: SocialLinkComponent,
+  title: 'Atoms/Buttons/Social',
+  component: SocialLink,
   argTypes: {
     name: {
       control: {
@@ -27,14 +30,44 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof SocialLinkComponent>;
+} as ComponentMeta<typeof SocialLink>;
 
-const Template: ComponentStory<typeof SocialLinkComponent> = (args) => (
-  <SocialLinkComponent {...args} />
+const Template: ComponentStory<typeof SocialLink> = (args) => (
+  <SocialLink {...args} />
 );
 
-export const SocialLink = Template.bind({});
-SocialLink.args = {
+/**
+ * Social Link Stories - Github
+ */
+export const Github = Template.bind({});
+Github.args = {
   name: 'Github',
   url: '#',
 };
+
+/**
+ * Social Link Stories - Gitlab
+ */
+export const Gitlab = Template.bind({});
+Gitlab.args = {
+  name: 'Gitlab',
+  url: '#',
+};
+
+/**
+ * Social Link Stories - LinkedIn
+ */
+export const LinkedIn = Template.bind({});
+LinkedIn.args = {
+  name: 'LinkedIn',
+  url: '#',
+};
+
+/**
+ * Social Link Stories - Twitter
+ */
+export const Twitter = Template.bind({});
+Twitter.args = {
+  name: 'Twitter',
+  url: '#',
+};
diff --git a/src/components/atoms/lists/description-list.stories.tsx b/src/components/atoms/lists/description-list.stories.tsx
index 66d94af..43ee66e 100644
--- a/src/components/atoms/lists/description-list.stories.tsx
+++ b/src/components/atoms/lists/description-list.stories.tsx
@@ -3,8 +3,11 @@ import DescriptionListComponent, {
   DescriptionListItem,
 } from './description-list';
 
+/**
+ * DescriptionList - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Lists',
+  title: 'Atoms/Typography/Lists',
   component: DescriptionListComponent,
   args: {
     layout: 'column',
@@ -67,6 +70,9 @@ const items: DescriptionListItem[] = [
   { id: 'term-4', term: 'Term 4:', value: ['Value for term 4'] },
 ];
 
+/**
+ * List Stories - Description list
+ */
 export const DescriptionList = Template.bind({});
 DescriptionList.args = {
   items,
diff --git a/src/components/atoms/lists/list.stories.tsx b/src/components/atoms/lists/list.stories.tsx
index 30079cb..3a80962 100644
--- a/src/components/atoms/lists/list.stories.tsx
+++ b/src/components/atoms/lists/list.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import ListComponent, { type ListItem } from './list';
 
+/**
+ * List - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Lists',
+  title: 'Atoms/Typography/Lists',
   component: ListComponent,
   args: {
     kind: 'unordered',
@@ -68,13 +71,19 @@ const items: ListItem[] = [
   { id: 'item-4', value: 'Item 4' },
 ];
 
-export const Unordered = Template.bind({});
-Unordered.args = {
-  items,
-};
-
+/**
+ * List Stories - Ordered list
+ */
 export const Ordered = Template.bind({});
 Ordered.args = {
   items,
   kind: 'ordered',
 };
+
+/**
+ * List Stories - Unordered list
+ */
+export const Unordered = Template.bind({});
+Unordered.args = {
+  items,
+};
diff --git a/src/components/atoms/loaders/progress-bar.stories.tsx b/src/components/atoms/loaders/progress-bar.stories.tsx
index 4fde5a7..fcd631c 100644
--- a/src/components/atoms/loaders/progress-bar.stories.tsx
+++ b/src/components/atoms/loaders/progress-bar.stories.tsx
@@ -1,8 +1,11 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import ProgressBarComponent from './progress-bar';
 
+/**
+ * ProgressBar - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Loaders',
+  title: 'Atoms/Loaders/ProgressBar',
   component: ProgressBarComponent,
   argTypes: {
     'aria-label': {
@@ -68,9 +71,23 @@ const Template: ComponentStory<typeof ProgressBarComponent> = (args) => (
   <ProgressBarComponent {...args} />
 );
 
+/**
+ * Loaders Stories - Default Progress bar
+ */
 export const ProgressBar = Template.bind({});
 ProgressBar.args = {
   current: 10,
   min: 0,
   max: 50,
 };
+
+/**
+ * Loaders Stories - Progress bar With Info
+ */
+export const ProgressBarWithInfo = Template.bind({});
+ProgressBarWithInfo.args = {
+  current: 10,
+  info: 'Loaded: 10 / 50',
+  min: 0,
+  max: 50,
+};
diff --git a/src/components/atoms/loaders/spinner.stories.tsx b/src/components/atoms/loaders/spinner.stories.tsx
index 5006ce4..dc577dc 100644
--- a/src/components/atoms/loaders/spinner.stories.tsx
+++ b/src/components/atoms/loaders/spinner.stories.tsx
@@ -2,8 +2,11 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import SpinnerComponent from './spinner';
 
+/**
+ * Spinner - Storybook Meta
+ */
 export default {
-  title: 'Atoms/Loaders',
+  title: 'Atoms/Loaders/Spinner',
   component: SpinnerComponent,
   argTypes: {
     message: {
@@ -20,12 +23,28 @@ export default {
       },
     },
   },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof SpinnerComponent>;
 
 const Template: ComponentStory<typeof SpinnerComponent> = (args) => (
-  <IntlProvider locale="en">
-    <SpinnerComponent {...args} />
-  </IntlProvider>
+  <SpinnerComponent {...args} />
 );
 
+/**
+ * Loaders Stories - Default Spinner
+ */
 export const Spinner = Template.bind({});
+
+/**
+ * Loaders Stories - Spinner with custom message
+ */
+export const SpinnerCustomMessage = Template.bind({});
+SpinnerCustomMessage.args = {
+  message: 'Submitting...',
+};
diff --git a/src/components/molecules/buttons/back-to-top.stories.tsx b/src/components/molecules/buttons/back-to-top.stories.tsx
index fe58293..7d4bc39 100644
--- a/src/components/molecules/buttons/back-to-top.stories.tsx
+++ b/src/components/molecules/buttons/back-to-top.stories.tsx
@@ -2,6 +2,9 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import BackToTopComponent from './back-to-top';
 
+/**
+ * BackToTop - Storybook Meta
+ */
 export default {
   title: 'Molecules/Buttons',
   component: BackToTopComponent,
@@ -30,14 +33,22 @@ export default {
       },
     },
   },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof BackToTopComponent>;
 
 const Template: ComponentStory<typeof BackToTopComponent> = (args) => (
-  <IntlProvider locale="en">
-    <BackToTopComponent {...args} />
-  </IntlProvider>
+  <BackToTopComponent {...args} />
 );
 
+/**
+ * Buttons Stories - Back to top
+ */
 export const BackToTop = Template.bind({});
 BackToTop.args = {
   target: 'top',
diff --git a/src/components/molecules/buttons/heading-button.stories.tsx b/src/components/molecules/buttons/heading-button.stories.tsx
index 0a23b08..b0e1465 100644
--- a/src/components/molecules/buttons/heading-button.stories.tsx
+++ b/src/components/molecules/buttons/heading-button.stories.tsx
@@ -3,8 +3,11 @@ import { useState } from 'react';
 import { IntlProvider } from 'react-intl';
 import HeadingButtonComponent from './heading-button';
 
+/**
+ * HeadingButton - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Buttons',
+  title: 'Molecules/Buttons/HeadingButton',
   component: HeadingButtonComponent,
   argTypes: {
     expanded: {
@@ -20,6 +23,8 @@ export default {
     level: {
       control: {
         type: 'number',
+        min: 1,
+        max: 6,
       },
       description: 'Heading level.',
       type: {
@@ -48,6 +53,13 @@ export default {
       },
     },
   },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof HeadingButtonComponent>;
 
 const Template: ComponentStory<typeof HeadingButtonComponent> = ({
@@ -58,18 +70,64 @@ const Template: ComponentStory<typeof HeadingButtonComponent> = ({
   const [isExpanded, setIsExpanded] = useState<boolean>(expanded);
 
   return (
-    <IntlProvider locale="en">
-      <HeadingButtonComponent
-        expanded={isExpanded}
-        setExpanded={setIsExpanded}
-        {...args}
-      />
-    </IntlProvider>
+    <HeadingButtonComponent
+      expanded={isExpanded}
+      setExpanded={setIsExpanded}
+      {...args}
+    />
   );
 };
 
-export const HeadingButton = Template.bind({});
-HeadingButton.args = {
+/**
+ * Heading Button Stories - Level 1
+ */
+export const Level1 = Template.bind({});
+Level1.args = {
+  level: 1,
+  title: 'Your title',
+};
+
+/**
+ * Heading Button Stories - Level 2
+ */
+export const Level2 = Template.bind({});
+Level2.args = {
   level: 2,
   title: 'Your title',
 };
+
+/**
+ * Heading Button Stories - Level 3
+ */
+export const Level3 = Template.bind({});
+Level3.args = {
+  level: 3,
+  title: 'Your title',
+};
+
+/**
+ * Heading Button Stories - Level 4
+ */
+export const Level4 = Template.bind({});
+Level4.args = {
+  level: 4,
+  title: 'Your title',
+};
+
+/**
+ * Heading Button Stories - Level 5
+ */
+export const Level5 = Template.bind({});
+Level5.args = {
+  level: 5,
+  title: 'Your title',
+};
+
+/**
+ * Heading Button Stories - Level 6
+ */
+export const Level6 = Template.bind({});
+Level6.args = {
+  level: 6,
+  title: 'Your title',
+};
diff --git a/src/components/molecules/buttons/help-button.stories.tsx b/src/components/molecules/buttons/help-button.stories.tsx
index cfc1b0b..cfc603e 100644
--- a/src/components/molecules/buttons/help-button.stories.tsx
+++ b/src/components/molecules/buttons/help-button.stories.tsx
@@ -2,6 +2,9 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import HelpButtonComponent from './help-button';
 
+/**
+ * HelpButton - Storybook Meta
+ */
 export default {
   title: 'Molecules/Buttons',
   component: HelpButtonComponent,
@@ -33,12 +36,20 @@ export default {
       },
     },
   },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof HelpButtonComponent>;
 
 const Template: ComponentStory<typeof HelpButtonComponent> = (args) => (
-  <IntlProvider locale="en">
-    <HelpButtonComponent {...args} />
-  </IntlProvider>
+  <HelpButtonComponent {...args} />
 );
 
+/**
+ * Help Button Stories - Level 1
+ */
 export const HelpButton = Template.bind({});
diff --git a/src/components/molecules/forms/ackee-select.stories.tsx b/src/components/molecules/forms/ackee-select.stories.tsx
index a59bfa9..4e6adf1 100644
--- a/src/components/molecules/forms/ackee-select.stories.tsx
+++ b/src/components/molecules/forms/ackee-select.stories.tsx
@@ -1,10 +1,13 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
-import AckeeSelectComponent from './ackee-select';
+import AckeeSelect from './ackee-select';
 
+/**
+ * AckeeSelect - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Forms',
-  component: AckeeSelectComponent,
+  title: 'Molecules/Forms/Select',
+  component: AckeeSelect,
   argTypes: {
     initialValue: {
       control: {
@@ -17,16 +20,50 @@ export default {
         required: true,
       },
     },
+    labelClassName: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames to the label wrapper.',
+      table: {
+        category: 'Styles',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
+    tooltipClassName: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames to the tooltip wrapper.',
+      table: {
+        category: 'Styles',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
   },
-} as ComponentMeta<typeof AckeeSelectComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof AckeeSelect>;
 
-const Template: ComponentStory<typeof AckeeSelectComponent> = (args) => (
-  <IntlProvider locale="en">
-    <AckeeSelectComponent {...args} />
-  </IntlProvider>
+const Template: ComponentStory<typeof AckeeSelect> = (args) => (
+  <AckeeSelect {...args} />
 );
 
-export const AckeeSelect = Template.bind({});
-AckeeSelect.args = {
+/**
+ * Select Stories - Ackee select
+ */
+export const Ackee = Template.bind({});
+Ackee.args = {
   initialValue: 'full',
 };
diff --git a/src/components/molecules/forms/labelled-field.stories.tsx b/src/components/molecules/forms/labelled-field.stories.tsx
index b77d71e..56eef00 100644
--- a/src/components/molecules/forms/labelled-field.stories.tsx
+++ b/src/components/molecules/forms/labelled-field.stories.tsx
@@ -1,16 +1,45 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { useState } from 'react';
-import LabelledFieldComponent from './labelled-field';
+import LabelledField from './labelled-field';
 
+/**
+ * LabelledField - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Forms',
-  component: LabelledFieldComponent,
+  title: 'Molecules/Forms/Field',
+  component: LabelledField,
   args: {
     disabled: false,
     labelPosition: 'top',
     required: false,
   },
   argTypes: {
+    'aria-labelledby': {
+      control: {
+        type: 'text',
+      },
+      description: 'One or more ids that refers to the field name.',
+      table: {
+        category: 'Accessibility',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
+    className: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames to the field.',
+      table: {
+        category: 'Styles',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
     disabled: {
       control: {
         type: 'boolean',
@@ -35,6 +64,20 @@ export default {
         required: true,
       },
     },
+    hideLabel: {
+      control: {
+        type: 'boolean',
+      },
+      description: 'Visually hide the field label.',
+      table: {
+        category: 'Options',
+        defaultValue: { summary: false },
+      },
+      type: {
+        name: 'boolean',
+        required: false,
+      },
+    },
     label: {
       control: {
         type: 'text',
@@ -181,20 +224,68 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof LabelledFieldComponent>;
+} as ComponentMeta<typeof LabelledField>;
 
-const Template: ComponentStory<typeof LabelledFieldComponent> = ({
+const Template: ComponentStory<typeof LabelledField> = ({
   value: _value,
   setValue: _setValue,
   ...args
 }) => {
   const [value, setValue] = useState<string>('');
 
-  return <LabelledFieldComponent value={value} setValue={setValue} {...args} />;
+  return <LabelledField value={value} setValue={setValue} {...args} />;
+};
+
+/**
+ * Labelled Field Stories - Left
+ */
+export const Left = Template.bind({});
+Left.args = {
+  id: 'labelled-field-storybook',
+  label: 'Labelled field',
+  labelPosition: 'left',
+  name: 'labelled-field-storybook',
+};
+
+/**
+ * Labelled Field Stories - Top
+ */
+export const Top = Template.bind({});
+Top.args = {
+  id: 'labelled-field-storybook',
+  label: 'Labelled field',
+  labelPosition: 'top',
+  name: 'labelled-field-storybook',
+};
+
+/**
+ * Labelled Field Stories - Required
+ */
+export const Required = Template.bind({});
+Required.args = {
+  id: 'labelled-field-storybook',
+  label: 'Labelled field',
+  name: 'labelled-field-storybook',
+  required: true,
+};
+
+/**
+ * Labelled Field Stories - Hidden label
+ */
+export const HiddenLabel = Template.bind({});
+HiddenLabel.args = {
+  hideLabel: true,
+  id: 'labelled-field-storybook',
+  label: 'Labelled field',
+  name: 'labelled-field-storybook',
 };
 
-export const LabelledField = Template.bind({});
-LabelledField.args = {
+/**
+ * Labelled Field Stories - Disabled
+ */
+export const Disabled = Template.bind({});
+Disabled.args = {
+  disabled: true,
   id: 'labelled-field-storybook',
   label: 'Labelled field',
   name: 'labelled-field-storybook',
diff --git a/src/components/molecules/forms/labelled-select.stories.tsx b/src/components/molecules/forms/labelled-select.stories.tsx
index 0c569f5..d02732c 100644
--- a/src/components/molecules/forms/labelled-select.stories.tsx
+++ b/src/components/molecules/forms/labelled-select.stories.tsx
@@ -1,6 +1,6 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { useState } from 'react';
-import LabelledSelectComponent from './labelled-select';
+import LabelledSelect from './labelled-select';
 
 const selectOptions = [
   { id: 'option1', name: 'Option 1', value: 'option1' },
@@ -8,9 +8,12 @@ const selectOptions = [
   { id: 'option3', name: 'Option 3', value: 'option3' },
 ];
 
+/**
+ * LabelledSelect - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Forms',
-  component: LabelledSelectComponent,
+  title: 'Molecules/Forms/Select',
+  component: LabelledSelect,
   args: {
     disabled: false,
     labelPosition: 'top',
@@ -167,29 +170,67 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof LabelledSelectComponent>;
+} as ComponentMeta<typeof LabelledSelect>;
 
-const Template: ComponentStory<typeof LabelledSelectComponent> = ({
+const Template: ComponentStory<typeof LabelledSelect> = ({
   value,
   setValue: _setValue,
   ...args
 }) => {
   const [selected, setSelected] = useState<string>(value);
 
-  return (
-    <LabelledSelectComponent
-      value={selected}
-      setValue={setSelected}
-      {...args}
-    />
-  );
+  return <LabelledSelect value={selected} setValue={setSelected} {...args} />;
 };
 
-export const LabelledSelect = Template.bind({});
-LabelledSelect.args = {
+/**
+ * Labelled Select Stories - Left
+ */
+export const Left = Template.bind({});
+Left.args = {
   id: 'labelled-select-storybook',
   label: 'Labelled select',
+  labelPosition: 'left',
   name: 'labelled-select-storybook',
   options: selectOptions,
   value: 'option1',
 };
+
+/**
+ * Labelled Select Stories - Top
+ */
+export const Top = Template.bind({});
+Top.args = {
+  id: 'labelled-select-storybook',
+  label: 'Labelled select',
+  labelPosition: 'top',
+  name: 'labelled-select-storybook',
+  options: selectOptions,
+  value: 'option1',
+};
+
+/**
+ * Labelled Select Stories - Disabled
+ */
+export const Disabled = Template.bind({});
+Disabled.args = {
+  disabled: true,
+  id: 'labelled-select-storybook',
+  label: 'Labelled select',
+  name: 'labelled-select-storybook',
+  options: selectOptions,
+  value: 'option1',
+};
+
+/**
+ * Labelled Select Stories - Required
+ */
+export const Required = Template.bind({});
+Required.args = {
+  id: 'labelled-select-storybook',
+  label: 'Labelled select',
+  labelPosition: 'top',
+  name: 'labelled-select-storybook',
+  options: selectOptions,
+  required: true,
+  value: 'option1',
+};
diff --git a/src/components/molecules/forms/motion-toggle.stories.tsx b/src/components/molecules/forms/motion-toggle.stories.tsx
index dc4d2a9..dcfc68d 100644
--- a/src/components/molecules/forms/motion-toggle.stories.tsx
+++ b/src/components/molecules/forms/motion-toggle.stories.tsx
@@ -2,10 +2,26 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import MotionToggleComponent from './motion-toggle';
 
+/**
+ * MotionToggle - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Forms',
+  title: 'Molecules/Forms/Toggle',
   component: MotionToggleComponent,
   argTypes: {
+    labelClassName: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames to the label wrapper.',
+      table: {
+        category: 'Styles',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
     value: {
       control: {
         type: null,
@@ -17,15 +33,23 @@ export default {
       },
     },
   },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof MotionToggleComponent>;
 
 const Template: ComponentStory<typeof MotionToggleComponent> = (args) => (
-  <IntlProvider locale="en">
-    <MotionToggleComponent {...args} />
-  </IntlProvider>
+  <MotionToggleComponent {...args} />
 );
 
-export const MotionToggle = Template.bind({});
-MotionToggle.args = {
+/**
+ * Toggle Stories - Motion
+ */
+export const Motion = Template.bind({});
+Motion.args = {
   value: false,
 };
diff --git a/src/components/molecules/forms/prism-theme-toggle.stories.tsx b/src/components/molecules/forms/prism-theme-toggle.stories.tsx
index dc9090b..513ebfc 100644
--- a/src/components/molecules/forms/prism-theme-toggle.stories.tsx
+++ b/src/components/molecules/forms/prism-theme-toggle.stories.tsx
@@ -1,11 +1,27 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
-import PrismThemeToggleComponent from './prism-theme-toggle';
+import PrismThemeToggle from './prism-theme-toggle';
 
+/**
+ * PrismThemeToggle - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Forms',
-  component: PrismThemeToggleComponent,
+  title: 'Molecules/Forms/Toggle',
+  component: PrismThemeToggle,
   argTypes: {
+    labelClassName: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames to the label wrapper.',
+      table: {
+        category: 'Styles',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
     value: {
       control: {
         type: null,
@@ -17,15 +33,23 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof PrismThemeToggleComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof PrismThemeToggle>;
 
-const Template: ComponentStory<typeof PrismThemeToggleComponent> = (args) => (
-  <IntlProvider locale="en">
-    <PrismThemeToggleComponent {...args} />
-  </IntlProvider>
+const Template: ComponentStory<typeof PrismThemeToggle> = (args) => (
+  <PrismThemeToggle {...args} />
 );
 
-export const PrismThemeToggle = Template.bind({});
-PrismThemeToggle.args = {
+/**
+ * Toggle Stories - Prism theme
+ */
+export const PrismTheme = Template.bind({});
+PrismTheme.args = {
   value: false,
 };
diff --git a/src/components/molecules/forms/select-with-tooltip.stories.tsx b/src/components/molecules/forms/select-with-tooltip.stories.tsx
index c63e9b8..d757b2b 100644
--- a/src/components/molecules/forms/select-with-tooltip.stories.tsx
+++ b/src/components/molecules/forms/select-with-tooltip.stories.tsx
@@ -1,11 +1,14 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { useState } from 'react';
 import { IntlProvider } from 'react-intl';
-import SelectWithTooltipComponent from './select-with-tooltip';
+import SelectWithTooltip from './select-with-tooltip';
 
+/**
+ * SelectWithTooltip - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Forms',
-  component: SelectWithTooltipComponent,
+  title: 'Molecules/Forms/Select',
+  component: SelectWithTooltip,
   argTypes: {
     content: {
       control: {
@@ -175,7 +178,14 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof SelectWithTooltipComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof SelectWithTooltip>;
 
 const selectOptions = [
   { id: 'option1', name: 'Option 1', value: 'option1' },
@@ -183,25 +193,22 @@ const selectOptions = [
   { id: 'option3', name: 'Option 3', value: 'option3' },
 ];
 
-const Template: ComponentStory<typeof SelectWithTooltipComponent> = ({
+const Template: ComponentStory<typeof SelectWithTooltip> = ({
   value: _value,
   setValue: _setValue,
   ...args
 }) => {
   const [selected, setSelected] = useState<string>('option1');
   return (
-    <IntlProvider locale="en">
-      <SelectWithTooltipComponent
-        value={selected}
-        setValue={setSelected}
-        {...args}
-      />
-    </IntlProvider>
+    <SelectWithTooltip value={selected} setValue={setSelected} {...args} />
   );
 };
 
-export const SelectWithTooltip = Template.bind({});
-SelectWithTooltip.args = {
+/**
+ * Select Stories - With tooltip
+ */
+export const WithTooltip = Template.bind({});
+WithTooltip.args = {
   content: 'Illo voluptatibus quia minima placeat sit nostrum excepturi.',
   title: 'Possimus quidem dolor',
   id: 'storybook-select',
diff --git a/src/components/molecules/forms/theme-toggle.stories.tsx b/src/components/molecules/forms/theme-toggle.stories.tsx
index a9bcf73..05d94b9 100644
--- a/src/components/molecules/forms/theme-toggle.stories.tsx
+++ b/src/components/molecules/forms/theme-toggle.stories.tsx
@@ -1,11 +1,27 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
-import ThemeToggleComponent from './theme-toggle';
+import ThemeToggle from './theme-toggle';
 
+/**
+ * ThemeToggle - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Forms',
-  component: ThemeToggleComponent,
+  title: 'Molecules/Forms/Toggle',
+  component: ThemeToggle,
   argTypes: {
+    labelClassName: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames to the label wrapper.',
+      table: {
+        category: 'Styles',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
     value: {
       control: {
         type: null,
@@ -17,15 +33,23 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof ThemeToggleComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof ThemeToggle>;
 
-const Template: ComponentStory<typeof ThemeToggleComponent> = (args) => (
-  <IntlProvider locale="en">
-    <ThemeToggleComponent {...args} />
-  </IntlProvider>
+const Template: ComponentStory<typeof ThemeToggle> = (args) => (
+  <ThemeToggle {...args} />
 );
 
-export const ThemeToggle = Template.bind({});
-ThemeToggle.args = {
+/**
+ * Toggle Stories - Theme
+ */
+export const Theme = Template.bind({});
+Theme.args = {
   value: false,
 };
diff --git a/src/components/molecules/forms/toggle.stories.tsx b/src/components/molecules/forms/toggle.stories.tsx
index 078a34c..0351ab7 100644
--- a/src/components/molecules/forms/toggle.stories.tsx
+++ b/src/components/molecules/forms/toggle.stories.tsx
@@ -1,10 +1,13 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { useState } from 'react';
-import ToggleComponent from './toggle';
+import Toggle from './toggle';
 
+/**
+ * ThemeToggle - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Forms',
-  component: ToggleComponent,
+  title: 'Molecules/Forms/Toggle',
+  component: Toggle,
   argTypes: {
     choices: {
       description: 'The toggle choices.',
@@ -92,21 +95,22 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof ToggleComponent>;
+} as ComponentMeta<typeof Toggle>;
 
-const Template: ComponentStory<typeof ToggleComponent> = ({
+const Template: ComponentStory<typeof Toggle> = ({
   value: _value,
   setValue: _setValue,
   ...args
 }) => {
   const [isChecked, setIsChecked] = useState<boolean>(false);
-  return (
-    <ToggleComponent value={isChecked} setValue={setIsChecked} {...args} />
-  );
+  return <Toggle value={isChecked} setValue={setIsChecked} {...args} />;
 };
 
-export const Toggle = Template.bind({});
-Toggle.args = {
+/**
+ * Toggle Stories - Default
+ */
+export const Default = Template.bind({});
+Default.args = {
   choices: {
     left: 'On',
     right: 'Off',
diff --git a/src/components/molecules/images/flipping-logo.module.scss b/src/components/molecules/images/flipping-logo.module.scss
new file mode 100644
index 0000000..89b9499
--- /dev/null
+++ b/src/components/molecules/images/flipping-logo.module.scss
@@ -0,0 +1,59 @@
+@use "@styles/abstracts/functions" as fun;
+
+.logo {
+  width: var(--logo-size, fun.convert-px(100));
+  height: var(--logo-size, fun.convert-px(100));
+  position: relative;
+  border-radius: 50%;
+  transform-style: preserve-3d;
+  transition: all 0.6s linear 0s;
+
+  &__front,
+  &__back {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    top: 0;
+    left: 0;
+    backface-visibility: hidden;
+    background: var(--color-bg);
+    border: fun.convert-px(2) solid var(--color-primary-dark);
+    border-radius: 50%;
+    transition: all 0.6s linear 0s;
+
+    svg,
+    img {
+      // !important is required to override next/image styles...
+      padding: fun.convert-px(2) !important;
+      border-radius: 50%;
+    }
+  }
+
+  &__front {
+    box-shadow: fun.convert-px(1) fun.convert-px(2) fun.convert-px(1) 0
+        var(--color-shadow-light),
+      fun.convert-px(2) fun.convert-px(3) fun.convert-px(3) 0
+        var(--color-shadow-light);
+  }
+
+  &__back {
+    transform: rotateY(180deg);
+  }
+
+  &:hover {
+    transform: rotateY(180deg);
+  }
+
+  &:hover & {
+    &__front {
+      box-shadow: none;
+    }
+
+    &__back {
+      box-shadow: fun.convert-px(1) fun.convert-px(2) fun.convert-px(1) 0
+          var(--color-shadow-light),
+        fun.convert-px(2) fun.convert-px(3) fun.convert-px(3) 0
+          var(--color-shadow-light);
+    }
+  }
+}
diff --git a/src/components/molecules/images/flipping-logo.stories.tsx b/src/components/molecules/images/flipping-logo.stories.tsx
new file mode 100644
index 0000000..40a4c49
--- /dev/null
+++ b/src/components/molecules/images/flipping-logo.stories.tsx
@@ -0,0 +1,75 @@
+import { ComponentMeta, ComponentStory } from '@storybook/react';
+import FlippingLogoComponent from './flipping-logo';
+
+/**
+ * FlippingLogo - Storybook Meta
+ */
+export default {
+  title: 'Molecules/Images',
+  component: FlippingLogoComponent,
+  argTypes: {
+    altText: {
+      control: {
+        type: 'text',
+      },
+      description: 'Photo alternative text.',
+      type: {
+        name: 'string',
+        required: true,
+      },
+    },
+    className: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames to the logo wrapper.',
+      table: {
+        category: 'Options',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
+    logoTitle: {
+      control: {
+        type: 'text',
+      },
+      description: 'An accessible name for the logo.',
+      table: {
+        category: 'Accessibility',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
+    photo: {
+      control: {
+        type: 'text',
+      },
+      description: 'Photo url.',
+      type: {
+        name: 'string',
+        required: true,
+      },
+    },
+    unoptimized: { table: { disable: true } },
+  },
+} as ComponentMeta<typeof FlippingLogoComponent>;
+
+const Template: ComponentStory<typeof FlippingLogoComponent> = (args) => (
+  <FlippingLogoComponent {...args} />
+);
+
+/**
+ * Images Stories - Flipping Logo
+ */
+export const FlippingLogo = Template.bind({});
+FlippingLogo.args = {
+  altText: 'Website picture',
+  logoTitle: 'Website logo',
+  photo: 'http://placeimg.com/640/480',
+  // @ts-ignore - Needed because of the placeholder image.
+  unoptimized: true,
+};
diff --git a/src/components/molecules/images/flipping-logo.test.tsx b/src/components/molecules/images/flipping-logo.test.tsx
new file mode 100644
index 0000000..806fdbe
--- /dev/null
+++ b/src/components/molecules/images/flipping-logo.test.tsx
@@ -0,0 +1,25 @@
+import { render, screen } from '@test-utils';
+import FlippingLogo from './flipping-logo';
+
+describe('FlippingLogo', () => {
+  it('renders a photo', () => {
+    render(
+      <FlippingLogo
+        altText="Alternative text"
+        photo="http://placeimg.com/640/480"
+      />
+    );
+    expect(screen.getByAltText('Alternative text')).toBeInTheDocument();
+  });
+
+  it('renders a logo', () => {
+    render(
+      <FlippingLogo
+        altText="Alternative text"
+        logoTitle="A logo title"
+        photo="http://placeimg.com/640/480"
+      />
+    );
+    expect(screen.getByTitle('A logo title')).toBeInTheDocument();
+  });
+});
diff --git a/src/components/molecules/images/flipping-logo.tsx b/src/components/molecules/images/flipping-logo.tsx
new file mode 100644
index 0000000..0d31fa3
--- /dev/null
+++ b/src/components/molecules/images/flipping-logo.tsx
@@ -0,0 +1,55 @@
+import Logo, { type LogoProps } from '@components/atoms/images/logo';
+import Image from 'next/image';
+import { FC } from 'react';
+import styles from './flipping-logo.module.scss';
+
+export type FlippingLogoProps = {
+  /**
+   * Set additional classnames to the logo wrapper.
+   */
+  className?: string;
+  /**
+   * Photo alternative text.
+   */
+  altText: string;
+  /**
+   * Logo image title.
+   */
+  logoTitle?: LogoProps['title'];
+  /**
+   * Photo url.
+   */
+  photo: string;
+};
+
+/**
+ * FlippingLogo component
+ *
+ * Render a logo and a photo with a flipping effect.
+ */
+const FlippingLogo: FC<FlippingLogoProps> = ({
+  className = '',
+  altText,
+  logoTitle,
+  photo,
+  ...props
+}) => {
+  return (
+    <div className={`${styles.logo} ${className}`}>
+      <div className={styles.logo__front}>
+        <Image
+          src={photo}
+          alt={altText}
+          layout="fill"
+          objectFit="cover"
+          {...props}
+        />
+      </div>
+      <div className={styles.logo__back}>
+        <Logo title={logoTitle} />
+      </div>
+    </div>
+  );
+};
+
+export default FlippingLogo;
diff --git a/src/components/molecules/images/responsive-image.module.scss b/src/components/molecules/images/responsive-image.module.scss
index 83e8d10..3566421 100644
--- a/src/components/molecules/images/responsive-image.module.scss
+++ b/src/components/molecules/images/responsive-image.module.scss
@@ -5,7 +5,7 @@
   flex-flow: column;
   width: 100%;
   max-width: max-content;
-  margin: var(--spacing-sm) auto;
+  margin: 0;
   position: relative;
   text-align: center;
 }
diff --git a/src/components/molecules/images/responsive-image.stories.tsx b/src/components/molecules/images/responsive-image.stories.tsx
index f9c1d2b..a1f5295 100644
--- a/src/components/molecules/images/responsive-image.stories.tsx
+++ b/src/components/molecules/images/responsive-image.stories.tsx
@@ -1,9 +1,12 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
-import ResponsiveImageComponent from './responsive-image';
+import ResponsiveImage from './responsive-image';
 
+/**
+ * ResponsiveImage - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Images',
-  component: ResponsiveImageComponent,
+  title: 'Molecules/Images/ResponsiveImage',
+  component: ResponsiveImage,
   argTypes: {
     alt: {
       control: {
@@ -72,16 +75,60 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof ResponsiveImageComponent>;
+} as ComponentMeta<typeof ResponsiveImage>;
 
-const Template: ComponentStory<typeof ResponsiveImageComponent> = (args) => (
-  <ResponsiveImageComponent {...args} />
+const Template: ComponentStory<typeof ResponsiveImage> = (args) => (
+  <ResponsiveImage {...args} />
 );
 
-export const ResponsiveImage = Template.bind({});
-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,
+  unoptimized: 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,
+  unoptimized: true,
+  target: '#',
+};
+
+/**
+ * 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',
+  unoptimized: 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: '#',
+  unoptimized: true,
 };
diff --git a/src/components/molecules/layout/branding.stories.tsx b/src/components/molecules/layout/branding.stories.tsx
index 726ba26..1637c99 100644
--- a/src/components/molecules/layout/branding.stories.tsx
+++ b/src/components/molecules/layout/branding.stories.tsx
@@ -1,10 +1,13 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
-import BrandingComponent from './branding';
+import Branding from './branding';
 
+/**
+ * Branding - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Layout',
-  component: BrandingComponent,
+  title: 'Molecules/Layout/Branding',
+  component: Branding,
   args: {
     isHome: false,
   },
@@ -53,6 +56,7 @@ export default {
         required: true,
       },
     },
+    unoptimized: { table: { disable: true } },
     withLink: {
       control: {
         type: 'boolean',
@@ -68,16 +72,38 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof BrandingComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof Branding>;
 
-const Template: ComponentStory<typeof BrandingComponent> = (args) => (
-  <IntlProvider locale="en">
-    <BrandingComponent {...args} />
-  </IntlProvider>
+const Template: ComponentStory<typeof Branding> = (args) => (
+  <Branding {...args} />
 );
 
-export const Branding = Template.bind({});
-Branding.args = {
+/**
+ * Branding Stories - Default
+ */
+export const Default = Template.bind({});
+Default.args = {
   title: 'Website title',
   photo: 'http://placeimg.com/640/480',
+  // @ts-ignore - Needed because of the placeholder image.
+  unoptimized: true,
+};
+
+/**
+ * Branding Stories - With baseline
+ */
+export const WithBaseline = Template.bind({});
+WithBaseline.args = {
+  title: 'Website title',
+  baseline: 'Maiores corporis qui',
+  photo: 'http://placeimg.com/640/480',
+  // @ts-ignore - Needed because of the placeholder image.
+  unoptimized: true,
 };
diff --git a/src/components/molecules/layout/branding.tsx b/src/components/molecules/layout/branding.tsx
index 9fe89e7..423c54f 100644
--- a/src/components/molecules/layout/branding.tsx
+++ b/src/components/molecules/layout/branding.tsx
@@ -2,8 +2,8 @@ import Heading from '@components/atoms/headings/heading';
 import Link from 'next/link';
 import { FC } from 'react';
 import { useIntl } from 'react-intl';
+import FlippingLogo, { type FlippingLogoProps } from '../images/flipping-logo';
 import styles from './branding.module.scss';
-import FlippingLogo, { type FlippingLogoProps } from './flipping-logo';
 
 export type BrandingProps = Pick<FlippingLogoProps, 'photo'> & {
   /**
@@ -35,6 +35,7 @@ const Branding: FC<BrandingProps> = ({
   photo,
   title,
   withLink = false,
+  ...props
 }) => {
   const intl = useIntl();
   const altText = intl.formatMessage(
@@ -61,6 +62,7 @@ const Branding: FC<BrandingProps> = ({
         altText={altText}
         logoTitle={logoTitle}
         photo={photo}
+        {...props}
       />
       <Heading
         isFake={!isHome}
diff --git a/src/components/molecules/layout/card.module.scss b/src/components/molecules/layout/card.module.scss
index 2b1b7dc..85c319a 100644
--- a/src/components/molecules/layout/card.module.scss
+++ b/src/components/molecules/layout/card.module.scss
@@ -17,10 +17,6 @@
     justify-content: flex-start;
   }
 
-  .footer {
-    margin-top: var(--spacing-md);
-  }
-
   .cover {
     align-self: flex-start;
     max-height: fun.convert-px(150);
@@ -46,6 +42,7 @@
 
   .tagline {
     flex: 1;
+    margin-bottom: var(--spacing-md);
     color: var(--color-fg);
     font-weight: 400;
   }
diff --git a/src/components/molecules/layout/card.stories.tsx b/src/components/molecules/layout/card.stories.tsx
index a07f8dc..ed78d00 100644
--- a/src/components/molecules/layout/card.stories.tsx
+++ b/src/components/molecules/layout/card.stories.tsx
@@ -1,9 +1,12 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
-import CardComponent from './card';
+import Card from './card';
 
+/**
+ * Card - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Layout',
-  component: CardComponent,
+  title: 'Molecules/Layout/Card',
+  component: Card,
   argTypes: {
     cover: {
       description: 'The card cover data (src, dimensions, alternative text).',
@@ -53,6 +56,8 @@ export default {
     titleLevel: {
       control: {
         type: 'number',
+        min: 1,
+        max: 6,
       },
       description: 'The title level.',
       type: {
@@ -71,17 +76,16 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof CardComponent>;
+} as ComponentMeta<typeof Card>;
 
-const Template: ComponentStory<typeof CardComponent> = (args) => (
-  <CardComponent {...args} />
-);
+const Template: ComponentStory<typeof Card> = (args) => <Card {...args} />;
 
 const cover = {
   alt: 'A picture',
   height: 480,
   src: 'http://placeimg.com/640/480',
   width: 640,
+  unoptimized: true,
 };
 
 const meta = [
@@ -92,10 +96,57 @@ const meta = [
   },
 ];
 
-export const Card = Template.bind({});
-Card.args = {
+/**
+ * Card Stories - Default
+ */
+export const Default = Template.bind({});
+Default.args = {
+  title: 'Veritatis dicta quod',
+  titleLevel: 2,
+  url: '#',
+};
+
+/**
+ * Card Stories - With cover
+ */
+export const WithCover = Template.bind({});
+WithCover.args = {
+  cover,
+  title: 'Veritatis dicta quod',
+  titleLevel: 2,
+  url: '#',
+};
+
+/**
+ * Card Stories - With meta
+ */
+export const WithMeta = Template.bind({});
+WithMeta.args = {
+  meta,
+  title: 'Veritatis dicta quod',
+  titleLevel: 2,
+  url: '#',
+};
+
+/**
+ * Card Stories - With tagline
+ */
+export const WithTagline = Template.bind({});
+WithTagline.args = {
+  tagline: 'Ullam accusantium ipsa',
+  title: 'Veritatis dicta quod',
+  titleLevel: 2,
+  url: '#',
+};
+
+/**
+ * Card Stories - With all data
+ */
+export const WithAll = Template.bind({});
+WithAll.args = {
   cover,
   meta,
+  tagline: 'Ullam accusantium ipsa',
   title: 'Veritatis dicta quod',
   titleLevel: 2,
   url: '#',
diff --git a/src/components/molecules/layout/card.tsx b/src/components/molecules/layout/card.tsx
index 89f100e..15927e9 100644
--- a/src/components/molecules/layout/card.tsx
+++ b/src/components/molecules/layout/card.tsx
@@ -93,7 +93,7 @@ const Card: FC<CardProps> = ({
             {title}
           </Heading>
         </header>
-        <div className={styles.tagline}>{tagline}</div>
+        {tagline && <div className={styles.tagline}>{tagline}</div>}
         {meta && (
           <footer className={styles.footer}>
             <DescriptionList
diff --git a/src/components/molecules/layout/flipping-logo.module.scss b/src/components/molecules/layout/flipping-logo.module.scss
deleted file mode 100644
index 89b9499..0000000
--- a/src/components/molecules/layout/flipping-logo.module.scss
+++ /dev/null
@@ -1,59 +0,0 @@
-@use "@styles/abstracts/functions" as fun;
-
-.logo {
-  width: var(--logo-size, fun.convert-px(100));
-  height: var(--logo-size, fun.convert-px(100));
-  position: relative;
-  border-radius: 50%;
-  transform-style: preserve-3d;
-  transition: all 0.6s linear 0s;
-
-  &__front,
-  &__back {
-    width: 100%;
-    height: 100%;
-    position: absolute;
-    top: 0;
-    left: 0;
-    backface-visibility: hidden;
-    background: var(--color-bg);
-    border: fun.convert-px(2) solid var(--color-primary-dark);
-    border-radius: 50%;
-    transition: all 0.6s linear 0s;
-
-    svg,
-    img {
-      // !important is required to override next/image styles...
-      padding: fun.convert-px(2) !important;
-      border-radius: 50%;
-    }
-  }
-
-  &__front {
-    box-shadow: fun.convert-px(1) fun.convert-px(2) fun.convert-px(1) 0
-        var(--color-shadow-light),
-      fun.convert-px(2) fun.convert-px(3) fun.convert-px(3) 0
-        var(--color-shadow-light);
-  }
-
-  &__back {
-    transform: rotateY(180deg);
-  }
-
-  &:hover {
-    transform: rotateY(180deg);
-  }
-
-  &:hover & {
-    &__front {
-      box-shadow: none;
-    }
-
-    &__back {
-      box-shadow: fun.convert-px(1) fun.convert-px(2) fun.convert-px(1) 0
-          var(--color-shadow-light),
-        fun.convert-px(2) fun.convert-px(3) fun.convert-px(3) 0
-          var(--color-shadow-light);
-    }
-  }
-}
diff --git a/src/components/molecules/layout/flipping-logo.stories.tsx b/src/components/molecules/layout/flipping-logo.stories.tsx
deleted file mode 100644
index 1ac8de8..0000000
--- a/src/components/molecules/layout/flipping-logo.stories.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import { ComponentMeta, ComponentStory } from '@storybook/react';
-import FlippingLogoComponent from './flipping-logo';
-
-export default {
-  title: 'Molecules/Layout',
-  component: FlippingLogoComponent,
-  argTypes: {
-    altText: {
-      control: {
-        type: 'text',
-      },
-      description: 'Photo alternative text.',
-      type: {
-        name: 'string',
-        required: true,
-      },
-    },
-    className: {
-      control: {
-        type: 'text',
-      },
-      description: 'Set additional classnames to the logo wrapper.',
-      table: {
-        category: 'Options',
-      },
-      type: {
-        name: 'string',
-        required: false,
-      },
-    },
-    logoTitle: {
-      control: {
-        type: 'text',
-      },
-      description: 'An accessible name for the logo.',
-      table: {
-        category: 'Accessibility',
-      },
-      type: {
-        name: 'string',
-        required: false,
-      },
-    },
-    photo: {
-      control: {
-        type: 'text',
-      },
-      description: 'Photo url.',
-      type: {
-        name: 'string',
-        required: true,
-      },
-    },
-  },
-} as ComponentMeta<typeof FlippingLogoComponent>;
-
-const Template: ComponentStory<typeof FlippingLogoComponent> = (args) => (
-  <FlippingLogoComponent {...args} />
-);
-
-export const FlippingLogo = Template.bind({});
-FlippingLogo.args = {
-  altText: 'Website picture',
-  logoTitle: 'Website logo',
-  photo: 'http://placeimg.com/640/480',
-};
diff --git a/src/components/molecules/layout/flipping-logo.test.tsx b/src/components/molecules/layout/flipping-logo.test.tsx
deleted file mode 100644
index 806fdbe..0000000
--- a/src/components/molecules/layout/flipping-logo.test.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { render, screen } from '@test-utils';
-import FlippingLogo from './flipping-logo';
-
-describe('FlippingLogo', () => {
-  it('renders a photo', () => {
-    render(
-      <FlippingLogo
-        altText="Alternative text"
-        photo="http://placeimg.com/640/480"
-      />
-    );
-    expect(screen.getByAltText('Alternative text')).toBeInTheDocument();
-  });
-
-  it('renders a logo', () => {
-    render(
-      <FlippingLogo
-        altText="Alternative text"
-        logoTitle="A logo title"
-        photo="http://placeimg.com/640/480"
-      />
-    );
-    expect(screen.getByTitle('A logo title')).toBeInTheDocument();
-  });
-});
diff --git a/src/components/molecules/layout/flipping-logo.tsx b/src/components/molecules/layout/flipping-logo.tsx
deleted file mode 100644
index 4a216ef..0000000
--- a/src/components/molecules/layout/flipping-logo.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import Logo, { type LogoProps } from '@components/atoms/images/logo';
-import Image from 'next/image';
-import { FC } from 'react';
-import styles from './flipping-logo.module.scss';
-
-export type FlippingLogoProps = {
-  /**
-   * Set additional classnames to the logo wrapper.
-   */
-  className?: string;
-  /**
-   * Photo alternative text.
-   */
-  altText: string;
-  /**
-   * Logo image title.
-   */
-  logoTitle?: LogoProps['title'];
-  /**
-   * Photo url.
-   */
-  photo: string;
-};
-
-/**
- * FlippingLogo component
- *
- * Render a logo and a photo with a flipping effect.
- */
-const FlippingLogo: FC<FlippingLogoProps> = ({
-  className = '',
-  altText,
-  logoTitle,
-  photo,
-}) => {
-  return (
-    <div className={`${styles.logo} ${className}`}>
-      <div className={styles.logo__front}>
-        <Image src={photo} alt={altText} layout="fill" objectFit="cover" />
-      </div>
-      <div className={styles.logo__back}>
-        <Logo title={logoTitle} />
-      </div>
-    </div>
-  );
-};
-
-export default FlippingLogo;
diff --git a/src/components/molecules/layout/meta.stories.tsx b/src/components/molecules/layout/meta.stories.tsx
index e7a932d..0323f90 100644
--- a/src/components/molecules/layout/meta.stories.tsx
+++ b/src/components/molecules/layout/meta.stories.tsx
@@ -1,6 +1,9 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import MetaComponent from './meta';
 
+/**
+ * Meta - Storybook Meta
+ */
 export default {
   title: 'Molecules/Layout',
   component: MetaComponent,
@@ -18,10 +21,7 @@ export default {
         required: false,
       },
     },
-    meta: {
-      control: {
-        type: null,
-      },
+    data: {
       description: 'The page metadata.',
       type: {
         name: 'object',
@@ -51,6 +51,9 @@ const data = {
   },
 };
 
+/**
+ * Layout Stories - Meta
+ */
 export const Meta = Template.bind({});
 Meta.args = {
   data,
diff --git a/src/components/molecules/layout/widget.module.scss b/src/components/molecules/layout/widget.module.scss
index 727ffb7..5854206 100644
--- a/src/components/molecules/layout/widget.module.scss
+++ b/src/components/molecules/layout/widget.module.scss
@@ -5,9 +5,14 @@
   flex-flow: column;
 
   &__header {
+    z-index: 2;
     background: var(--color-bg);
   }
 
+  &__body {
+    position: relative;
+  }
+
   &--has-borders & {
     &__body {
       border: fun.convert-px(2) solid var(--color-primary-dark);
diff --git a/src/components/molecules/layout/widget.stories.tsx b/src/components/molecules/layout/widget.stories.tsx
index d79f66e..c113db9 100644
--- a/src/components/molecules/layout/widget.stories.tsx
+++ b/src/components/molecules/layout/widget.stories.tsx
@@ -1,12 +1,14 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
-import WidgetComponent from './widget';
+import Widget from './widget';
 
+/**
+ * Widget - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Layout',
-  component: WidgetComponent,
+  title: 'Molecules/Layout/Widget',
+  component: Widget,
   args: {
-    expanded: true,
     withBorders: false,
   },
   argTypes: {
@@ -37,6 +39,8 @@ export default {
     level: {
       control: {
         type: 'number',
+        min: 1,
+        max: 6,
       },
       description: 'The heading level.',
       type: {
@@ -69,17 +73,35 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof WidgetComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof Widget>;
 
-const Template: ComponentStory<typeof WidgetComponent> = (args) => (
-  <IntlProvider locale="en">
-    <WidgetComponent {...args} />
-  </IntlProvider>
-);
+const Template: ComponentStory<typeof Widget> = (args) => <Widget {...args} />;
 
-export const Widget = Template.bind({});
-Widget.args = {
+/**
+ * Widget Stories - Expanded
+ */
+export const Expanded = Template.bind({});
+Expanded.args = {
   children: 'Widget body',
+  expanded: true,
+  level: 2,
+  title: 'Widget title',
+};
+
+/**
+ * Widget Stories - Collapsed
+ */
+export const Collapsed = Template.bind({});
+Collapsed.args = {
+  children: 'Widget body',
+  expanded: false,
   level: 2,
   title: 'Widget title',
 };
diff --git a/src/components/molecules/modals/modal.stories.tsx b/src/components/molecules/modals/modal.stories.tsx
index bd7d9f4..55b7677 100644
--- a/src/components/molecules/modals/modal.stories.tsx
+++ b/src/components/molecules/modals/modal.stories.tsx
@@ -1,9 +1,12 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
-import ModalComponent from './modal';
+import Modal from './modal';
 
+/**
+ * Widget - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Modals',
-  component: ModalComponent,
+  title: 'Molecules/Modals/Modal',
+  component: Modal,
   argTypes: {
     children: {
       control: {
@@ -56,14 +59,25 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof ModalComponent>;
+} as ComponentMeta<typeof Modal>;
 
-const Template: ComponentStory<typeof ModalComponent> = (args) => (
-  <ModalComponent {...args} />
-);
+const Template: ComponentStory<typeof Modal> = (args) => <Modal {...args} />;
 
-export const Modal = Template.bind({});
-Modal.args = {
+/**
+ * Modal Stories - Default
+ */
+export const Default = Template.bind({});
+Default.args = {
   children:
     'Inventore natus dignissimos aut illum modi asperiores. Et voluptatibus delectus.',
 };
+
+/**
+ * Modal Stories - With title
+ */
+export const WithTitle = Template.bind({});
+WithTitle.args = {
+  children:
+    'Inventore natus dignissimos aut illum modi asperiores. Et voluptatibus delectus.',
+  title: 'Alias praesentium corporis',
+};
diff --git a/src/components/molecules/modals/tooltip.stories.tsx b/src/components/molecules/modals/tooltip.stories.tsx
index 63fc71d..06a4855 100644
--- a/src/components/molecules/modals/tooltip.stories.tsx
+++ b/src/components/molecules/modals/tooltip.stories.tsx
@@ -1,9 +1,12 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
-import TooltipComponent from './tooltip';
+import Tooltip from './tooltip';
 
+/**
+ * Tooltip - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Modals',
-  component: TooltipComponent,
+  title: 'Molecules/Modals/Tooltip',
+  component: Tooltip,
   argTypes: {
     className: {
       control: {
@@ -49,14 +52,17 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof TooltipComponent>;
+} as ComponentMeta<typeof Tooltip>;
 
-const Template: ComponentStory<typeof TooltipComponent> = (args) => (
-  <TooltipComponent {...args} />
+const Template: ComponentStory<typeof Tooltip> = (args) => (
+  <Tooltip {...args} />
 );
 
-export const Tooltip = Template.bind({});
-Tooltip.args = {
+/**
+ * Tooltip Stories - Help
+ */
+export const Help = Template.bind({});
+Help.args = {
   content:
     'Minima tempora fuga omnis ratione doloribus ut. Totam ea vitae consequatur. Fuga hic ipsum. In non debitis ex assumenda ut dicta. Sit ut maxime eligendi est.',
   icon: '?',
diff --git a/src/components/molecules/nav/breadcrumb.stories.tsx b/src/components/molecules/nav/breadcrumb.stories.tsx
index d283619..500ae6c 100644
--- a/src/components/molecules/nav/breadcrumb.stories.tsx
+++ b/src/components/molecules/nav/breadcrumb.stories.tsx
@@ -1,10 +1,13 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
-import BreadcrumbComponent, { type BreadcrumbItem } from './breadcrumb';
+import Breadcrumb from './breadcrumb';
 
+/**
+ * Breadcrumb - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Nav',
-  component: BreadcrumbComponent,
+  title: 'Molecules/Navigation/Breadcrumb',
+  component: Breadcrumb,
   argTypes: {
     className: {
       control: {
@@ -28,21 +31,46 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof BreadcrumbComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof Breadcrumb>;
 
-const Template: ComponentStory<typeof BreadcrumbComponent> = (args) => (
-  <IntlProvider locale="en">
-    <BreadcrumbComponent {...args} />
-  </IntlProvider>
+const Template: ComponentStory<typeof Breadcrumb> = (args) => (
+  <Breadcrumb {...args} />
 );
 
-const items: BreadcrumbItem[] = [
-  { id: 'home', url: '#', name: 'Home' },
-  { id: 'blog', url: '#', name: 'Blog' },
-  { id: 'post1', url: '#', name: 'A Post' },
-];
+/**
+ * Breadcrumb Stories - One item
+ */
+export const OneItem = Template.bind({});
+OneItem.args = {
+  items: [{ id: 'home', url: '#', name: 'Home' }],
+};
+
+/**
+ * Breadcrumb Stories - Two items
+ */
+export const TwoItems = Template.bind({});
+TwoItems.args = {
+  items: [
+    { id: 'home', url: '#', name: 'Home' },
+    { id: 'blog', url: '#', name: 'Blog' },
+  ],
+};
 
-export const Breadcrumb = Template.bind({});
-Breadcrumb.args = {
-  items,
+/**
+ * Breadcrumb Stories - Three items
+ */
+export const ThreeItems = Template.bind({});
+ThreeItems.args = {
+  items: [
+    { id: 'home', url: '#', name: 'Home' },
+    { id: 'blog', url: '#', name: 'Blog' },
+    { id: 'post1', url: '#', name: 'A Post' },
+  ],
 };
diff --git a/src/components/molecules/nav/nav.stories.tsx b/src/components/molecules/nav/nav.stories.tsx
index 9975bbd..25455fd 100644
--- a/src/components/molecules/nav/nav.stories.tsx
+++ b/src/components/molecules/nav/nav.stories.tsx
@@ -4,18 +4,11 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import NavComponent, { type NavItem } from './nav';
 
-const MainNavItems: NavItem[] = [
-  { id: 'homeLink', href: '/', label: 'Home', logo: <Home /> },
-  { id: 'contactLink', href: '/contact', label: 'Contact', logo: <Envelop /> },
-];
-
-const FooterNavItems: NavItem[] = [
-  { id: 'contactLink', href: '/contact', label: 'Contact' },
-  { id: 'legalLink', href: '/legal-notice', label: 'Legal notice' },
-];
-
+/**
+ * Nav - Storybook Meta
+ */
 export default {
-  title: 'Molecules/Nav',
+  title: 'Molecules/Navigation/Nav',
   component: NavComponent,
   argTypes: {
     className: {
@@ -54,20 +47,41 @@ export default {
       },
     },
   },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof NavComponent>;
 
 const Template: ComponentStory<typeof NavComponent> = (args) => (
-  <IntlProvider locale="en">
-    <NavComponent {...args} />
-  </IntlProvider>
+  <NavComponent {...args} />
 );
 
+const MainNavItems: NavItem[] = [
+  { id: 'homeLink', href: '/', label: 'Home', logo: <Home /> },
+  { id: 'contactLink', href: '/contact', label: 'Contact', logo: <Envelop /> },
+];
+
+const FooterNavItems: NavItem[] = [
+  { id: 'contactLink', href: '/contact', label: 'Contact' },
+  { id: 'legalLink', href: '/legal-notice', label: 'Legal notice' },
+];
+
+/**
+ * Nav Stories - Main navigation
+ */
 export const MainNav = Template.bind({});
 MainNav.args = {
   items: MainNavItems,
   kind: 'main',
 };
 
+/**
+ * Nav Stories - Footer navigation
+ */
 export const FooterNav = Template.bind({});
 FooterNav.args = {
   items: FooterNavItems,
diff --git a/src/components/organisms/forms/comment-form.stories.tsx b/src/components/organisms/forms/comment-form.stories.tsx
index 670176c..f66d35c 100644
--- a/src/components/organisms/forms/comment-form.stories.tsx
+++ b/src/components/organisms/forms/comment-form.stories.tsx
@@ -1,10 +1,13 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
-import CommentFormComponent from './comment-form';
+import CommentForm from './comment-form';
 
+/**
+ * CommentForm - Storybook Meta
+ */
 export default {
   title: 'Organisms/Forms',
-  component: CommentFormComponent,
+  component: CommentForm,
   argTypes: {
     className: {
       control: {
@@ -58,6 +61,8 @@ export default {
     titleLevel: {
       control: {
         type: 'number',
+        min: 1,
+        max: 6,
       },
       description: 'The title level (hn).',
       table: {
@@ -69,16 +74,24 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof CommentFormComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof CommentForm>;
 
-const Template: ComponentStory<typeof CommentFormComponent> = (args) => (
-  <IntlProvider locale="en">
-    <CommentFormComponent {...args} />
-  </IntlProvider>
+const Template: ComponentStory<typeof CommentForm> = (args) => (
+  <CommentForm {...args} />
 );
 
-export const CommentForm = Template.bind({});
-CommentForm.args = {
+/**
+ * Forms Stories - Comment
+ */
+export const Comment = Template.bind({});
+Comment.args = {
   saveComment: (reset: () => void) => {
     reset();
   },
diff --git a/src/components/organisms/forms/contact-form.stories.tsx b/src/components/organisms/forms/contact-form.stories.tsx
index 2c8ab32..9b936f9 100644
--- a/src/components/organisms/forms/contact-form.stories.tsx
+++ b/src/components/organisms/forms/contact-form.stories.tsx
@@ -1,10 +1,13 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
-import ContactFormComponent from './contact-form';
+import ContactForm from './contact-form';
 
+/**
+ * ContactForm - Storybook Meta
+ */
 export default {
   title: 'Organisms/Forms',
-  component: ContactFormComponent,
+  component: ContactForm,
   argTypes: {
     className: {
       control: {
@@ -43,16 +46,24 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof ContactFormComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof ContactForm>;
 
-const Template: ComponentStory<typeof ContactFormComponent> = (args) => (
-  <IntlProvider locale="en">
-    <ContactFormComponent {...args} />
-  </IntlProvider>
+const Template: ComponentStory<typeof ContactForm> = (args) => (
+  <ContactForm {...args} />
 );
 
-export const ContactForm = Template.bind({});
-ContactForm.args = {
+/**
+ * Forms Stories - Contact
+ */
+export const Contact = Template.bind({});
+Contact.args = {
   sendMail: (reset: () => void) => {
     reset();
   },
diff --git a/src/components/organisms/forms/search-form.stories.tsx b/src/components/organisms/forms/search-form.stories.tsx
index 4ec1c21..7f4c7c0 100644
--- a/src/components/organisms/forms/search-form.stories.tsx
+++ b/src/components/organisms/forms/search-form.stories.tsx
@@ -1,10 +1,16 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
-import SearchFormComponent from './search-form';
+import SearchForm from './search-form';
 
+/**
+ * SearchForm - Storybook Meta
+ */
 export default {
   title: 'Organisms/Forms',
-  component: SearchFormComponent,
+  component: SearchForm,
+  args: {
+    hideLabel: false,
+  },
   argTypes: {
     className: {
       control: {
@@ -19,16 +25,38 @@ export default {
         required: false,
       },
     },
+    hideLabel: {
+      control: {
+        type: 'boolean',
+      },
+      description: 'Determine if the input label should be visually hidden.',
+      table: {
+        category: 'Options',
+        defaultValue: { summary: false },
+      },
+      type: {
+        name: 'boolean',
+        required: false,
+      },
+    },
   },
-} as ComponentMeta<typeof SearchFormComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof SearchForm>;
 
-const Template: ComponentStory<typeof SearchFormComponent> = (args) => (
-  <IntlProvider locale="en">
-    <SearchFormComponent {...args} />
-  </IntlProvider>
+const Template: ComponentStory<typeof SearchForm> = (args) => (
+  <SearchForm {...args} />
 );
 
-export const SearchForm = Template.bind({});
-SearchForm.args = {
+/**
+ * Forms Stories - Search
+ */
+export const Search = Template.bind({});
+Search.args = {
   hideLabel: true,
 };
diff --git a/src/components/organisms/layout/cards-list.stories.tsx b/src/components/organisms/layout/cards-list.stories.tsx
index 5182808..7ff4365 100644
--- a/src/components/organisms/layout/cards-list.stories.tsx
+++ b/src/components/organisms/layout/cards-list.stories.tsx
@@ -1,13 +1,32 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import CardsListComponent, { type CardsListItem } from './cards-list';
 
+/**
+ * CardsList - Storybook Meta
+ */
 export default {
   title: 'Organisms/Layout',
   component: CardsListComponent,
   args: {
+    coverFit: 'cover',
     kind: 'unordered',
   },
   argTypes: {
+    coverFit: {
+      control: {
+        type: 'select',
+      },
+      description: 'The cover fit.',
+      options: ['fill', 'contain', 'cover', 'none', 'scale-down'],
+      table: {
+        category: 'Options',
+        defaultValue: { summary: 'cover' },
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
     items: {
       description: 'The cards data.',
       type: {
@@ -34,6 +53,8 @@ export default {
     titleLevel: {
       control: {
         type: 'number',
+        min: 1,
+        max: 6,
       },
       description: 'The heading level for each card.',
       type: {
@@ -56,6 +77,8 @@ const items: CardsListItem[] = [
       src: 'http://placeimg.com/640/480',
       width: 640,
       height: 480,
+      // @ts-ignore - Needed because of the placeholder image.
+      unoptimized: true,
     },
     meta: [
       { id: 'meta-1', term: 'Quibusdam', value: ['Velit', 'Ex', 'Alias'] },
@@ -71,6 +94,8 @@ const items: CardsListItem[] = [
       src: 'http://placeimg.com/640/480',
       width: 640,
       height: 480,
+      // @ts-ignore - Needed because of the placeholder image.
+      unoptimized: true,
     },
     meta: [{ id: 'meta-1', term: 'Est', value: ['Voluptas'] }],
     tagline: 'Quod vel accusamus',
@@ -84,6 +109,8 @@ const items: CardsListItem[] = [
       src: 'http://placeimg.com/640/480',
       width: 640,
       height: 480,
+      // @ts-ignore - Needed because of the placeholder image.
+      unoptimized: true,
     },
     meta: [
       {
@@ -98,6 +125,9 @@ const items: CardsListItem[] = [
   },
 ];
 
+/**
+ * Layout Stories - Cards list
+ */
 export const CardsList = Template.bind({});
 CardsList.args = {
   items,
diff --git a/src/components/organisms/layout/footer.stories.tsx b/src/components/organisms/layout/footer.stories.tsx
index 2ce7ee1..06819da 100644
--- a/src/components/organisms/layout/footer.stories.tsx
+++ b/src/components/organisms/layout/footer.stories.tsx
@@ -2,6 +2,9 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import FooterComponent from './footer';
 
+/**
+ * Footer - Storybook Meta
+ */
 export default {
   title: 'Organisms/Layout',
   component: FooterComponent,
@@ -50,12 +53,17 @@ export default {
       },
     },
   },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof FooterComponent>;
 
 const Template: ComponentStory<typeof FooterComponent> = (args) => (
-  <IntlProvider locale="en">
-    <FooterComponent {...args} />
-  </IntlProvider>
+  <FooterComponent {...args} />
 );
 
 const copyright = {
@@ -66,6 +74,9 @@ const copyright = {
 
 const navItems = [{ id: 'legal-notice', href: '#', label: 'Legal notice' }];
 
+/**
+ * Layout Stories - Footer
+ */
 export const Footer = Template.bind({});
 Footer.args = {
   copyright,
diff --git a/src/components/organisms/layout/overview.stories.tsx b/src/components/organisms/layout/overview.stories.tsx
index 61d8b35..b18a6b6 100644
--- a/src/components/organisms/layout/overview.stories.tsx
+++ b/src/components/organisms/layout/overview.stories.tsx
@@ -1,15 +1,21 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
-import OverviewComponent from './overview';
+import Overview from './overview';
 
+/**
+ * Overview - Storybook Meta
+ */
 export default {
-  title: 'Organisms/Layout',
-  component: OverviewComponent,
+  title: 'Organisms/Layout/Overview',
+  component: Overview,
   argTypes: {
     cover: {
       description: 'The overview cover.',
+      table: {
+        category: 'Options',
+      },
       type: {
         name: 'object',
-        required: true,
+        required: false,
         value: {},
       },
     },
@@ -22,10 +28,10 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof OverviewComponent>;
+} as ComponentMeta<typeof Overview>;
 
-const Template: ComponentStory<typeof OverviewComponent> = (args) => (
-  <OverviewComponent {...args} />
+const Template: ComponentStory<typeof Overview> = (args) => (
+  <Overview {...args} />
 );
 
 const cover = {
@@ -33,6 +39,7 @@ const cover = {
   height: 480,
   src: 'http://placeimg.com/640/480/cats',
   width: 640,
+  unoptimized: true,
 };
 
 const meta = {
@@ -43,8 +50,20 @@ const meta = {
   },
 };
 
-export const Overview = Template.bind({});
-Overview.args = {
+/**
+ * Overview Stories - Default
+ */
+export const Default = Template.bind({});
+Default.args = {
+  cover,
+  meta,
+};
+
+/**
+ * Overview Stories - With cover
+ */
+export const WithCover = Template.bind({});
+WithCover.args = {
   cover,
   meta,
 };
diff --git a/src/components/organisms/layout/summary.module.scss b/src/components/organisms/layout/summary.module.scss
index 5da0a18..3919e15 100644
--- a/src/components/organisms/layout/summary.module.scss
+++ b/src/components/organisms/layout/summary.module.scss
@@ -28,6 +28,7 @@
   width: auto;
   max-height: fun.convert-px(100);
   max-width: 100%;
+  margin-bottom: var(--spacing-sm);
   border: fun.convert-px(1) solid var(--color-border);
 
   @include mix.media("screen") {
diff --git a/src/components/organisms/layout/summary.stories.tsx b/src/components/organisms/layout/summary.stories.tsx
index b33acde..05be7da 100644
--- a/src/components/organisms/layout/summary.stories.tsx
+++ b/src/components/organisms/layout/summary.stories.tsx
@@ -1,10 +1,13 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
-import SummaryComponent from './summary';
+import Summary from './summary';
 
+/**
+ * Summary - Storybook Meta
+ */
 export default {
-  title: 'Organisms/Layout',
-  component: SummaryComponent,
+  title: 'Organisms/Layout/Summary',
+  component: Summary,
   args: {
     titleLevel: 2,
   },
@@ -51,6 +54,8 @@ export default {
     titleLevel: {
       control: {
         type: 'number',
+        min: 1,
+        max: 6,
       },
       description: 'The page title level (hn)',
       table: {
@@ -73,14 +78,27 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof SummaryComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof Summary>;
 
-const Template: ComponentStory<typeof SummaryComponent> = (args) => (
-  <IntlProvider locale="en">
-    <SummaryComponent {...args} />
-  </IntlProvider>
+const Template: ComponentStory<typeof Summary> = (args) => (
+  <Summary {...args} />
 );
 
+const cover = {
+  alt: 'A cover',
+  height: 480,
+  src: 'http://placeimg.com/640/480',
+  width: 640,
+  unoptimized: true,
+};
+
 const meta = {
   publication: { name: 'Published on:', value: 'April 11th 2022' },
   readingTime: { name: 'Reading time:', value: '5 minutes' },
@@ -98,14 +116,24 @@ const meta = {
   comments: { name: 'Comments:', value: '1 comment' },
 };
 
-export const Summary = Template.bind({});
-Summary.args = {
-  cover: {
-    alt: 'A cover',
-    height: 480,
-    src: 'http://placeimg.com/640/480',
-    width: 640,
-  },
+/**
+ * Summary Stories - Default
+ */
+export const Default = Template.bind({});
+Default.args = {
+  excerpt:
+    'Perspiciatis quasi libero nemo non eligendi nam minima. Deleniti expedita tempore. Praesentium explicabo molestiae eaque consectetur vero. Quae nostrum quisquam similique. Ut hic est quas ut esse quisquam nobis.',
+  meta,
+  title: 'Odio odit necessitatibus',
+  url: '#',
+};
+
+/**
+ * Summary Stories - With cover
+ */
+export const WithCover = Template.bind({});
+WithCover.args = {
+  cover,
   excerpt:
     'Perspiciatis quasi libero nemo non eligendi nam minima. Deleniti expedita tempore. Praesentium explicabo molestiae eaque consectetur vero. Quae nostrum quisquam similique. Ut hic est quas ut esse quisquam nobis.',
   meta,
diff --git a/src/components/organisms/layout/summary.tsx b/src/components/organisms/layout/summary.tsx
index 733a660..28aac68 100644
--- a/src/components/organisms/layout/summary.tsx
+++ b/src/components/organisms/layout/summary.tsx
@@ -6,7 +6,7 @@ import ResponsiveImage, {
   type ResponsiveImageProps,
 } from '@components/molecules/images/responsive-image';
 import Meta, { type MetaItem } from '@components/molecules/layout/meta';
-import { FC } from 'react';
+import { FC, ReactNode } from 'react';
 import { useIntl } from 'react-intl';
 import styles from './summary.module.scss';
 
@@ -83,7 +83,7 @@ const Summary: FC<SummaryProps> = ({
     },
     {
       title,
-      a11y: (chunks: string) => (
+      a11y: (chunks: ReactNode) => (
         <span className="screen-reader-text">{chunks}</span>
       ),
     }
diff --git a/src/components/organisms/modals/search-modal.stories.tsx b/src/components/organisms/modals/search-modal.stories.tsx
index b35c841..3ad6abd 100644
--- a/src/components/organisms/modals/search-modal.stories.tsx
+++ b/src/components/organisms/modals/search-modal.stories.tsx
@@ -1,16 +1,42 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
-import SearchModalComponent from './search-modal';
+import SearchModal from './search-modal';
 
+/**
+ * SearchModal - Storybook Meta
+ */
 export default {
   title: 'Organisms/Modals',
-  component: SearchModalComponent,
-} as ComponentMeta<typeof SearchModalComponent>;
+  component: SearchModal,
+  argTypes: {
+    className: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames to the search modal wrapper.',
+      table: {
+        category: 'Options',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
+  },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof SearchModal>;
 
-const Template: ComponentStory<typeof SearchModalComponent> = (args) => (
-  <IntlProvider locale="en">
-    <SearchModalComponent {...args} />
-  </IntlProvider>
+const Template: ComponentStory<typeof SearchModal> = (args) => (
+  <SearchModal {...args} />
 );
 
-export const SearchModal = Template.bind({});
+/**
+ * Modals Stories - Search
+ */
+export const Search = Template.bind({});
diff --git a/src/components/organisms/modals/settings-modal.stories.tsx b/src/components/organisms/modals/settings-modal.stories.tsx
index c19a6d7..0abe004 100644
--- a/src/components/organisms/modals/settings-modal.stories.tsx
+++ b/src/components/organisms/modals/settings-modal.stories.tsx
@@ -2,6 +2,9 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import SettingsModal from './settings-modal';
 
+/**
+ * SettingsModal - Storybook Meta
+ */
 export default {
   title: 'Organisms/Modals',
   component: SettingsModal,
@@ -19,13 +22,34 @@ export default {
         required: false,
       },
     },
+    tooltipClassName: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames to the tooltip wrapper.',
+      table: {
+        category: 'Styles',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
   },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof SettingsModal>;
 
 const Template: ComponentStory<typeof SettingsModal> = (args) => (
-  <IntlProvider locale="en">
-    <SettingsModal {...args} />
-  </IntlProvider>
+  <SettingsModal {...args} />
 );
 
+/**
+ * Modals Stories - Settings
+ */
 export const Settings = Template.bind({});
diff --git a/src/components/organisms/toolbar/main-nav.stories.tsx b/src/components/organisms/toolbar/main-nav.stories.tsx
index 27387c0..04b22cb 100644
--- a/src/components/organisms/toolbar/main-nav.stories.tsx
+++ b/src/components/organisms/toolbar/main-nav.stories.tsx
@@ -1,11 +1,14 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { useState } from 'react';
 import { IntlProvider } from 'react-intl';
-import MainNavComponent from './main-nav';
+import MainNav from './main-nav';
 
+/**
+ * MainNav - Storybook Meta
+ */
 export default {
-  title: 'Organisms/Toolbar',
-  component: MainNavComponent,
+  title: 'Organisms/Toolbar/MainNav',
+  component: MainNav,
   argTypes: {
     className: {
       control: {
@@ -49,27 +52,45 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof MainNavComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof MainNav>;
 
-const Template: ComponentStory<typeof MainNavComponent> = ({
+const Template: ComponentStory<typeof MainNav> = ({
   isActive,
   setIsActive: _setIsActive,
   ...args
 }) => {
   const [isOpen, setIsOpen] = useState<boolean>(isActive);
 
-  return (
-    <IntlProvider locale="en">
-      <MainNavComponent isActive={isOpen} setIsActive={setIsOpen} {...args} />
-    </IntlProvider>
-  );
+  return <MainNav isActive={isOpen} setIsActive={setIsOpen} {...args} />;
 };
 
-export const MainNav = Template.bind({});
-MainNav.args = {
+/**
+ * MainNav Stories - Inactive
+ */
+export const Inactive = Template.bind({});
+Inactive.args = {
   isActive: false,
   items: [
     { id: 'home', label: 'Home', href: '#' },
     { id: 'contact', label: 'Contact', href: '#' },
   ],
 };
+
+/**
+ * MainNav Stories - Active
+ */
+export const Active = Template.bind({});
+Active.args = {
+  isActive: true,
+  items: [
+    { id: 'home', label: 'Home', href: '#' },
+    { id: 'contact', label: 'Contact', href: '#' },
+  ],
+};
diff --git a/src/components/organisms/toolbar/search.stories.tsx b/src/components/organisms/toolbar/search.stories.tsx
index 8c2e871..0421c8c 100644
--- a/src/components/organisms/toolbar/search.stories.tsx
+++ b/src/components/organisms/toolbar/search.stories.tsx
@@ -1,11 +1,14 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { useState } from 'react';
 import { IntlProvider } from 'react-intl';
-import SearchComponent from './search';
+import Search from './search';
 
+/**
+ * Search - Storybook Meta
+ */
 export default {
-  title: 'Organisms/Toolbar',
-  component: SearchComponent,
+  title: 'Organisms/Toolbar/Search',
+  component: Search,
   argTypes: {
     className: {
       control: {
@@ -41,23 +44,37 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof SearchComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof Search>;
 
-const Template: ComponentStory<typeof SearchComponent> = ({
+const Template: ComponentStory<typeof Search> = ({
   isActive,
   setIsActive: _setIsActive,
   ...args
 }) => {
   const [isOpen, setIsOpen] = useState<boolean>(isActive);
 
-  return (
-    <IntlProvider locale="en">
-      <SearchComponent isActive={isOpen} setIsActive={setIsOpen} {...args} />
-    </IntlProvider>
-  );
+  return <Search isActive={isOpen} setIsActive={setIsOpen} {...args} />;
 };
 
-export const Search = Template.bind({});
-Search.args = {
+/**
+ * Search Stories - Inactive
+ */
+export const Inactive = Template.bind({});
+Inactive.args = {
   isActive: false,
 };
+
+/**
+ * Search Stories - Active
+ */
+export const Active = Template.bind({});
+Active.args = {
+  isActive: true,
+};
diff --git a/src/components/organisms/toolbar/settings.stories.tsx b/src/components/organisms/toolbar/settings.stories.tsx
index f01e772..1ec0897 100644
--- a/src/components/organisms/toolbar/settings.stories.tsx
+++ b/src/components/organisms/toolbar/settings.stories.tsx
@@ -1,11 +1,14 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { useState } from 'react';
 import { IntlProvider } from 'react-intl';
-import SettingsComponent from './settings';
+import Settings from './settings';
 
+/**
+ * Settings - Storybook Meta
+ */
 export default {
-  title: 'Organisms/Toolbar',
-  component: SettingsComponent,
+  title: 'Organisms/Toolbar/Settings',
+  component: Settings,
   argTypes: {
     className: {
       control: {
@@ -54,23 +57,37 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof SettingsComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof Settings>;
 
-const Template: ComponentStory<typeof SettingsComponent> = ({
+const Template: ComponentStory<typeof Settings> = ({
   isActive,
   setIsActive: _setIsActive,
   ...args
 }) => {
   const [isOpen, setIsOpen] = useState<boolean>(isActive);
 
-  return (
-    <IntlProvider locale="en">
-      <SettingsComponent isActive={isOpen} setIsActive={setIsOpen} {...args} />
-    </IntlProvider>
-  );
+  return <Settings isActive={isOpen} setIsActive={setIsOpen} {...args} />;
 };
 
-export const Settings = Template.bind({});
-Settings.args = {
+/**
+ * Settings Stories - Inactive
+ */
+export const Inactive = Template.bind({});
+Inactive.args = {
   isActive: false,
 };
+
+/**
+ * Settings Stories - Active
+ */
+export const Active = Template.bind({});
+Active.args = {
+  isActive: true,
+};
diff --git a/src/components/organisms/toolbar/toolbar.stories.tsx b/src/components/organisms/toolbar/toolbar.stories.tsx
index 75d70d8..de94e31 100644
--- a/src/components/organisms/toolbar/toolbar.stories.tsx
+++ b/src/components/organisms/toolbar/toolbar.stories.tsx
@@ -2,15 +2,46 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import ToolbarComponent from './toolbar';
 
+/**
+ * Toolbar - Storybook Meta
+ */
 export default {
   title: 'Organisms/Toolbar',
   component: ToolbarComponent,
+  argTypes: {
+    className: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames to the toolbar wrapper.',
+      table: {
+        category: 'Styles',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
+    nav: {
+      description: 'The main nav items.',
+      type: {
+        name: 'object',
+        required: true,
+        value: {},
+      },
+    },
+  },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof ToolbarComponent>;
 
 const Template: ComponentStory<typeof ToolbarComponent> = (args) => (
-  <IntlProvider locale="en">
-    <ToolbarComponent {...args} />
-  </IntlProvider>
+  <ToolbarComponent {...args} />
 );
 
 const nav = [
@@ -20,6 +51,9 @@ const nav = [
   { id: 'contact-link', href: '#', label: 'Contact' },
 ];
 
+/**
+ * Toolbar Story
+ */
 export const Toolbar = Template.bind({});
 Toolbar.args = {
   nav,
diff --git a/src/components/organisms/widgets/image-widget.module.scss b/src/components/organisms/widgets/image-widget.module.scss
index 78c0d26..8e4d0aa 100644
--- a/src/components/organisms/widgets/image-widget.module.scss
+++ b/src/components/organisms/widgets/image-widget.module.scss
@@ -1,7 +1,6 @@
 @use "@styles/abstracts/functions" as fun;
 
 .img {
-  max-height: fun.convert-px(350);
   margin: 0;
 }
 
diff --git a/src/components/organisms/widgets/image-widget.stories.tsx b/src/components/organisms/widgets/image-widget.stories.tsx
index 1c2397b..27871ae 100644
--- a/src/components/organisms/widgets/image-widget.stories.tsx
+++ b/src/components/organisms/widgets/image-widget.stories.tsx
@@ -1,10 +1,13 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
-import ImageWidgetComponent from './image-widget';
+import ImageWidget from './image-widget';
 
+/**
+ * ImageWidget - Storybook Meta
+ */
 export default {
-  title: 'Organisms/Widgets',
-  component: ImageWidgetComponent,
+  title: 'Organisms/Widgets/Image',
+  component: ImageWidget,
   args: {
     alignment: 'left',
   },
@@ -58,6 +61,8 @@ export default {
     level: {
       control: {
         type: 'number',
+        min: 1,
+        max: 6,
       },
       description: 'The widget title level (hn).',
       type: {
@@ -89,12 +94,17 @@ export default {
       },
     },
   },
-} as ComponentMeta<typeof ImageWidgetComponent>;
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
+} as ComponentMeta<typeof ImageWidget>;
 
-const Template: ComponentStory<typeof ImageWidgetComponent> = (args) => (
-  <IntlProvider locale="en">
-    <ImageWidgetComponent {...args} />
-  </IntlProvider>
+const Template: ComponentStory<typeof ImageWidget> = (args) => (
+  <ImageWidget {...args} />
 );
 
 const img = {
@@ -102,10 +112,51 @@ const img = {
   height: 480,
   src: 'http://placeimg.com/640/480/nature',
   width: 640,
+  unoptimized: true,
 };
 
-export const ImageWidget = Template.bind({});
-ImageWidget.args = {
+/**
+ * ImageWidget Stories - Align left
+ */
+export const AlignLeft = Template.bind({});
+AlignLeft.args = {
+  alignment: 'left',
+  expanded: true,
+  img,
+  level: 2,
+  title: 'Quo et totam',
+};
+
+/**
+ * ImageWidget Stories - Align center
+ */
+export const AlignCenter = Template.bind({});
+AlignCenter.args = {
+  alignment: 'center',
+  expanded: true,
+  img,
+  level: 2,
+  title: 'Quo et totam',
+};
+
+/**
+ * ImageWidget Stories - Align right
+ */
+export const AlignRight = Template.bind({});
+AlignRight.args = {
+  alignment: 'right',
+  expanded: true,
+  img,
+  level: 2,
+  title: 'Quo et totam',
+};
+
+/**
+ * ImageWidget Stories - With description
+ */
+export const WithDescription = Template.bind({});
+WithDescription.args = {
+  description: 'Sint enim harum',
   expanded: true,
   img,
   level: 2,
diff --git a/src/components/organisms/widgets/links-list-widget.stories.tsx b/src/components/organisms/widgets/links-list-widget.stories.tsx
index 528f6f7..0f03a2c 100644
--- a/src/components/organisms/widgets/links-list-widget.stories.tsx
+++ b/src/components/organisms/widgets/links-list-widget.stories.tsx
@@ -2,8 +2,11 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import LinksListWidget from './links-list-widget';
 
+/**
+ * LinksListWidget - Storybook Meta
+ */
 export default {
-  title: 'Organisms/Widgets',
+  title: 'Organisms/Widgets/LinksList',
   component: LinksListWidget,
   args: {
     kind: 'unordered',
@@ -35,6 +38,8 @@ export default {
     level: {
       control: {
         type: 'number',
+        min: 1,
+        max: 6,
       },
       description: 'The heading level.',
       type: {
@@ -53,12 +58,17 @@ export default {
       },
     },
   },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof LinksListWidget>;
 
 const Template: ComponentStory<typeof LinksListWidget> = (args) => (
-  <IntlProvider locale="en">
-    <LinksListWidget {...args} />
-  </IntlProvider>
+  <LinksListWidget {...args} />
 );
 
 const items = [
@@ -84,9 +94,24 @@ const items = [
   { name: 'Level 1: Item 4', url: '#' },
 ];
 
-export const LinksList = Template.bind({});
-LinksList.args = {
+/**
+ * Links List Widget Stories - Unordered
+ */
+export const Unordered = Template.bind({});
+Unordered.args = {
   items,
+  kind: 'unordered',
+  level: 2,
+  title: 'A list of links',
+};
+
+/**
+ * Links List Widget Stories - Ordered
+ */
+export const Ordered = Template.bind({});
+Ordered.args = {
+  items,
+  kind: 'ordered',
   level: 2,
   title: 'A list of links',
 };
diff --git a/src/components/organisms/widgets/sharing.stories.tsx b/src/components/organisms/widgets/sharing.stories.tsx
index be20b84..c3c3488 100644
--- a/src/components/organisms/widgets/sharing.stories.tsx
+++ b/src/components/organisms/widgets/sharing.stories.tsx
@@ -2,6 +2,9 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import SharingWidget from './sharing';
 
+/**
+ * Sharing - Storybook Meta
+ */
 export default {
   title: 'Organisms/Widgets',
   component: SharingWidget,
@@ -27,6 +30,8 @@ export default {
     level: {
       control: {
         type: 'number',
+        min: 1,
+        max: 6,
       },
       description: 'The heading level.',
       type: {
@@ -55,14 +60,22 @@ export default {
       },
     },
   },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof SharingWidget>;
 
 const Template: ComponentStory<typeof SharingWidget> = (args) => (
-  <IntlProvider locale="en">
-    <SharingWidget {...args} />
-  </IntlProvider>
+  <SharingWidget {...args} />
 );
 
+/**
+ * Widgets Stories - Sharing
+ */
 export const Sharing = Template.bind({});
 Sharing.args = {
   expanded: true,
diff --git a/src/components/organisms/widgets/sharing.tsx b/src/components/organisms/widgets/sharing.tsx
index 571c1a4..05a3f73 100644
--- a/src/components/organisms/widgets/sharing.tsx
+++ b/src/components/organisms/widgets/sharing.tsx
@@ -21,7 +21,7 @@ export type SharingData = {
   url: string;
 };
 
-export type SharingProps = Omit<WidgetProps, 'children'> & {
+export type SharingProps = Pick<WidgetProps, 'expanded' | 'level' | 'title'> & {
   /**
    * The page data to share.
    */
diff --git a/src/components/organisms/widgets/social-media.stories.tsx b/src/components/organisms/widgets/social-media.stories.tsx
index 2b84012..2fa8bd7 100644
--- a/src/components/organisms/widgets/social-media.stories.tsx
+++ b/src/components/organisms/widgets/social-media.stories.tsx
@@ -2,6 +2,9 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
 import { IntlProvider } from 'react-intl';
 import SocialMediaWidget, { Media } from './social-media';
 
+/**
+ * SocialMedia - Storybook Meta
+ */
 export default {
   title: 'Organisms/Widgets',
   component: SocialMediaWidget,
@@ -9,6 +12,8 @@ export default {
     level: {
       control: {
         type: 'number',
+        min: 1,
+        max: 6,
       },
       description: 'The heading level.',
       type: {
@@ -35,12 +40,17 @@ export default {
       },
     },
   },
+  decorators: [
+    (Story) => (
+      <IntlProvider locale="en">
+        <Story />
+      </IntlProvider>
+    ),
+  ],
 } as ComponentMeta<typeof SocialMediaWidget>;
 
 const Template: ComponentStory<typeof SocialMediaWidget> = (args) => (
-  <IntlProvider locale="en">
-    <SocialMediaWidget {...args} />
-  </IntlProvider>
+  <SocialMediaWidget {...args} />
 );
 
 const media: Media[] = [
@@ -48,6 +58,9 @@ const media: Media[] = [
   { name: 'LinkedIn', url: '#' },
 ];
 
+/**
+ * Widgets Stories - Social media
+ */
 export const SocialMedia = Template.bind({});
 SocialMedia.args = {
   media,
-- 
cgit v1.2.3


From ee04742d1f0645908baa30e47845126c28848f50 Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
Date: Tue, 3 May 2022 16:53:55 +0200
Subject: chore: add a CV page

---
 src/components/atoms/links/link.module.scss        |  87 ++++++++-
 src/components/atoms/links/link.stories.tsx        |  20 ++-
 src/components/atoms/links/link.tsx                |  18 +-
 .../molecules/images/responsive-image.module.scss  |  11 +-
 .../molecules/images/responsive-image.stories.tsx  |   1 +
 .../molecules/images/responsive-image.tsx          |   6 +-
 .../organisms/widgets/image-widget.module.scss     |  13 +-
 .../organisms/widgets/image-widget.stories.tsx     |  25 ++-
 .../organisms/widgets/image-widget.test.tsx        |  11 +-
 src/components/organisms/widgets/image-widget.tsx  |  18 +-
 src/pages/cv.tsx                                   | 198 +++++++++++++++++++++
 src/styles/pages/cv.module.scss                    |   3 +
 12 files changed, 375 insertions(+), 36 deletions(-)
 create mode 100644 src/pages/cv.tsx
 create mode 100644 src/styles/pages/cv.module.scss

(limited to 'src/components/atoms/links/link.stories.tsx')

diff --git a/src/components/atoms/links/link.module.scss b/src/components/atoms/links/link.module.scss
index d23667a..1b89727 100644
--- a/src/components/atoms/links/link.module.scss
+++ b/src/components/atoms/links/link.module.scss
@@ -5,23 +5,64 @@
   &[hreflang] {
     &::after {
       display: inline-block;
+
       /* Prettier is removing spacing between content parts. */
+
       /* prettier-ignore */
       content: "\0000a0[" attr(hreflang) "]";
       font-size: var(--font-size-sm);
     }
   }
 
+  &--download {
+    &::after {
+      display: inline-block;
+
+      /* Prettier is removing spacing between content parts. */
+
+      /* prettier-ignore */
+      content: "\0000a0" url(
+fun.encode-svg(
+        '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'
+));
+    }
+
+    &:focus:not(:active)::after {
+      /* Prettier is removing spacing between content parts. */
+
+      /* prettier-ignore */
+      content: "\0000a0" url(
+fun.encode-svg(
+        '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_white}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'
+));
+    }
+
+    &[hreflang] {
+      &::after {
+        /* Prettier is removing spacing between content parts. */
+
+        /* prettier-ignore */
+        content: "\0000a0[" attr(hreflang) "]\0000a0" url(
+fun.encode-svg(
+          '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'
+));
+      }
+    }
+  }
+
   &--external {
     &::after {
       display: inline-block;
+
       /* Prettier is removing spacing between content parts. */
+
       /* prettier-ignore */
       content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
     }
 
     &:focus:not(:active)::after {
       /* Prettier is removing spacing between content parts. */
+
       /* prettier-ignore */
       content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_white}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
     }
@@ -29,18 +70,56 @@
     &[hreflang] {
       &::after {
         /* Prettier is removing spacing between content parts. */
+
         /* prettier-ignore */
-        content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg(
+        content: "\0000a0[" attr(hreflang) "]\0000a0" url(
+fun.encode-svg(
             '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'
-          ));
+));
       }
 
       &:focus:not(:active)::after {
         /* Prettier is removing spacing between content parts. */
+
         /* prettier-ignore */
-        content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg(
+        content: "\0000a0[" attr(hreflang) "]\0000a0" url(
+fun.encode-svg(
             '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_white}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'
-          ));
+));
+      }
+    }
+  }
+
+  &--external#{&}--download {
+    &::after {
+      /* Prettier is removing spacing between content parts. */
+
+      /* prettier-ignore */
+      content: "\0000a0" url(
+fun.encode-svg(
+          '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'
+)) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+    }
+
+    &[hreflang] {
+      &::after {
+        /* Prettier is removing spacing between content parts. */
+
+        /* prettier-ignore */
+        content: "\0000a0[" attr(hreflang) "]\0000a0" url(
+fun.encode-svg(
+          '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'
+)) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+      }
+
+      &:focus:not(:active)::after {
+        /* Prettier is removing spacing between content parts. */
+
+        /* prettier-ignore */
+        content: "\0000a0[" attr(hreflang) "]\0000a0" url(
+fun.encode-svg(
+          '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'
+)) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_white}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
       }
     }
   }
diff --git a/src/components/atoms/links/link.stories.tsx b/src/components/atoms/links/link.stories.tsx
index c3b3465..420eafe 100644
--- a/src/components/atoms/links/link.stories.tsx
+++ b/src/components/atoms/links/link.stories.tsx
@@ -31,14 +31,29 @@ export default {
         required: false,
       },
     },
-    external: {
+    download: {
       control: {
         type: 'boolean',
       },
+      description: 'Determine if the link purpose is to download a file.',
       table: {
         category: 'Options',
+        defaultValue: { summary: false },
+      },
+      type: {
+        name: 'boolean',
+        required: false,
+      },
+    },
+    external: {
+      control: {
+        type: 'boolean',
       },
       description: 'Determine if the link is external of the current website.',
+      table: {
+        category: 'Options',
+        defaultValue: { summary: false },
+      },
       type: {
         name: 'boolean',
         required: false,
@@ -79,6 +94,7 @@ export const Default = Template.bind({});
 Default.args = {
   children: 'A link',
   href: '#',
+  download: false,
   external: false,
 };
 
@@ -89,6 +105,7 @@ export const External = Template.bind({});
 External.args = {
   children: 'A link',
   href: '#',
+  download: false,
   external: true,
 };
 
@@ -99,6 +116,7 @@ export const ExternalWithLang = Template.bind({});
 ExternalWithLang.args = {
   children: 'A link',
   href: '#',
+  download: false,
   external: true,
   lang: 'en',
 };
diff --git a/src/components/atoms/links/link.tsx b/src/components/atoms/links/link.tsx
index 674c07b..c8ba273 100644
--- a/src/components/atoms/links/link.tsx
+++ b/src/components/atoms/links/link.tsx
@@ -11,6 +11,10 @@ export type LinkProps = {
    * Set additional classnames to the link.
    */
   className?: string;
+  /**
+   * True if it is a download link. Default: false.
+   */
+  download?: boolean;
   /**
    * True if it is an external link. Default: false.
    */
@@ -33,21 +37,29 @@ export type LinkProps = {
 const Link: FC<LinkProps> = ({
   children,
   className = '',
+  download = false,
+  external = false,
   href,
   lang,
-  external = false,
 }) => {
+  const downloadClass = download ? styles['link--download'] : '';
+
   return external ? (
     <a
       href={href}
       hrefLang={lang}
-      className={`${styles.link} ${styles['link--external']} ${className}`}
+      className={`${styles.link} ${styles['link--external']} ${downloadClass} ${className}`}
     >
       {children}
     </a>
   ) : (
     <NextLink href={href}>
-      <a className={`${styles.link} ${className}`}>{children}</a>
+      <a
+        hrefLang={lang}
+        className={`${styles.link} ${downloadClass} ${className}`}
+      >
+        {children}
+      </a>
     </NextLink>
   );
 };
diff --git a/src/components/molecules/images/responsive-image.module.scss b/src/components/molecules/images/responsive-image.module.scss
index 3566421..3a4f283 100644
--- a/src/components/molecules/images/responsive-image.module.scss
+++ b/src/components/molecules/images/responsive-image.module.scss
@@ -3,8 +3,7 @@
 .wrapper {
   display: flex;
   flex-flow: column;
-  width: 100%;
-  max-width: max-content;
+  width: fit-content;
   margin: 0;
   position: relative;
   text-align: center;
@@ -14,9 +13,7 @@
   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);
+  border: fun.convert-px(1) solid var(--color-border-light);
   font-weight: 500;
 }
 
@@ -32,7 +29,7 @@
 
   &:hover,
   &:focus {
-    transform: scale(1.1);
+    transform: scale(var(--scale-up, 1.05));
   }
 
   &:focus {
@@ -43,7 +40,7 @@
   }
 
   &:active {
-    transform: scale(0.9);
+    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
index a1f5295..35d9116 100644
--- a/src/components/molecules/images/responsive-image.stories.tsx
+++ b/src/components/molecules/images/responsive-image.stories.tsx
@@ -64,6 +64,7 @@ export default {
         required: false,
       },
     },
+    unoptimized: { table: { disable: true } },
     width: {
       control: {
         type: 'number',
diff --git a/src/components/molecules/images/responsive-image.tsx b/src/components/molecules/images/responsive-image.tsx
index 31cbcd1..d07dd6c 100644
--- a/src/components/molecules/images/responsive-image.tsx
+++ b/src/components/molecules/images/responsive-image.tsx
@@ -1,6 +1,6 @@
 import Link, { type LinkProps } from '@components/atoms/links/link';
 import Image, { type ImageProps } from 'next/image';
-import { FC } from 'react';
+import { FC, ReactNode } from 'react';
 import styles from './responsive-image.module.scss';
 
 export type ResponsiveImageProps = Omit<
@@ -14,7 +14,7 @@ export type ResponsiveImageProps = Omit<
   /**
    * A figure caption.
    */
-  caption?: string;
+  caption?: ReactNode;
   /**
    * Set additional classnames to the figure wrapper.
    */
@@ -55,6 +55,7 @@ const ResponsiveImage: FC<ResponsiveImageProps> = ({
             alt={alt}
             layout={layout || 'intrinsic'}
             objectFit={objectFit || 'contain'}
+            className={styles.img}
             {...props}
           />
           {caption && (
@@ -67,6 +68,7 @@ const ResponsiveImage: FC<ResponsiveImageProps> = ({
             alt={alt}
             layout={layout || 'intrinsic'}
             objectFit={objectFit || 'contain'}
+            className={styles.img}
             {...props}
           />
           {caption && (
diff --git a/src/components/organisms/widgets/image-widget.module.scss b/src/components/organisms/widgets/image-widget.module.scss
index 8e4d0aa..0d69441 100644
--- a/src/components/organisms/widgets/image-widget.module.scss
+++ b/src/components/organisms/widgets/image-widget.module.scss
@@ -1,7 +1,12 @@
 @use "@styles/abstracts/functions" as fun;
 
-.img {
+.figure {
+  --scale-up: 1.02;
+  --scale-down: 0.98;
+
   margin: 0;
+  padding: fun.convert-px(5);
+  border: fun.convert-px(1) solid var(--color-border);
 }
 
 .txt {
@@ -10,7 +15,7 @@
 
 .widget {
   &--left {
-    .img {
+    .figure {
       margin-right: auto;
     }
 
@@ -20,7 +25,7 @@
   }
 
   &--center {
-    .img {
+    .figure {
       margin-left: auto;
       margin-right: auto;
     }
@@ -31,7 +36,7 @@
   }
 
   &--right {
-    .img {
+    .figure {
       margin-left: auto;
     }
 
diff --git a/src/components/organisms/widgets/image-widget.stories.tsx b/src/components/organisms/widgets/image-widget.stories.tsx
index 27871ae..3014b36 100644
--- a/src/components/organisms/widgets/image-widget.stories.tsx
+++ b/src/components/organisms/widgets/image-widget.stories.tsx
@@ -50,7 +50,7 @@ export default {
         required: true,
       },
     },
-    img: {
+    image: {
       description: 'An image object.',
       type: {
         name: 'object',
@@ -58,6 +58,19 @@ export default {
         value: {},
       },
     },
+    imageClassName: {
+      control: {
+        type: 'text',
+      },
+      description: 'Set additional classnames to the image wrapper.',
+      table: {
+        category: 'Styles',
+      },
+      type: {
+        name: 'string',
+        required: false,
+      },
+    },
     level: {
       control: {
         type: 'number',
@@ -107,7 +120,7 @@ const Template: ComponentStory<typeof ImageWidget> = (args) => (
   <ImageWidget {...args} />
 );
 
-const img = {
+const image = {
   alt: 'Et perferendis quaerat',
   height: 480,
   src: 'http://placeimg.com/640/480/nature',
@@ -122,7 +135,7 @@ export const AlignLeft = Template.bind({});
 AlignLeft.args = {
   alignment: 'left',
   expanded: true,
-  img,
+  image,
   level: 2,
   title: 'Quo et totam',
 };
@@ -134,7 +147,7 @@ export const AlignCenter = Template.bind({});
 AlignCenter.args = {
   alignment: 'center',
   expanded: true,
-  img,
+  image,
   level: 2,
   title: 'Quo et totam',
 };
@@ -146,7 +159,7 @@ export const AlignRight = Template.bind({});
 AlignRight.args = {
   alignment: 'right',
   expanded: true,
-  img,
+  image,
   level: 2,
   title: 'Quo et totam',
 };
@@ -158,7 +171,7 @@ export const WithDescription = Template.bind({});
 WithDescription.args = {
   description: 'Sint enim harum',
   expanded: true,
-  img,
+  image,
   level: 2,
   title: 'Quo et totam',
 };
diff --git a/src/components/organisms/widgets/image-widget.test.tsx b/src/components/organisms/widgets/image-widget.test.tsx
index 8c24bd9..c6b1a3a 100644
--- a/src/components/organisms/widgets/image-widget.test.tsx
+++ b/src/components/organisms/widgets/image-widget.test.tsx
@@ -18,7 +18,12 @@ const url = '/another-page';
 describe('ImageWidget', () => {
   it('renders an image', () => {
     render(
-      <ImageWidget expanded={true} img={img} title={title} level={titleLevel} />
+      <ImageWidget
+        expanded={true}
+        image={img}
+        title={title}
+        level={titleLevel}
+      />
     );
     expect(screen.getByRole('img', { name: img.alt })).toBeInTheDocument();
   });
@@ -27,7 +32,7 @@ describe('ImageWidget', () => {
     render(
       <ImageWidget
         expanded={true}
-        img={img}
+        image={img}
         title={title}
         level={titleLevel}
         url={url}
@@ -43,7 +48,7 @@ describe('ImageWidget', () => {
     render(
       <ImageWidget
         expanded={true}
-        img={img}
+        image={img}
         description={description}
         title={title}
         level={titleLevel}
diff --git a/src/components/organisms/widgets/image-widget.tsx b/src/components/organisms/widgets/image-widget.tsx
index ba04c6a..873337b 100644
--- a/src/components/organisms/widgets/image-widget.tsx
+++ b/src/components/organisms/widgets/image-widget.tsx
@@ -14,7 +14,7 @@ export type Image = Pick<
 
 export type ImageWidgetProps = Pick<
   WidgetProps,
-  'expanded' | 'level' | 'title'
+  'className' | 'expanded' | 'level' | 'title'
 > & {
   /**
    * The content alignment.
@@ -27,7 +27,11 @@ export type ImageWidgetProps = Pick<
   /**
    * An object describing the image.
    */
-  img: Image;
+  image: Image;
+  /**
+   * Set additional classnames to the image wrapper.
+   */
+  imageClassName?: string;
   /**
    * Add a link to the image.
    */
@@ -41,20 +45,22 @@ export type ImageWidgetProps = Pick<
  */
 const ImageWidget: FC<ImageWidgetProps> = ({
   alignment = 'left',
+  className = '',
   description,
-  img,
+  image,
+  imageClassName = '',
   url,
   ...props
 }) => {
   const alignmentClass = `widget--${alignment}`;
 
   return (
-    <Widget className={styles[alignmentClass]} {...props}>
+    <Widget className={`${styles[alignmentClass]} ${className}`} {...props}>
       <ResponsiveImage
         target={url}
         caption={description}
-        className={styles.img}
-        {...img}
+        className={`${styles.figure} ${imageClassName}`}
+        {...image}
       />
     </Widget>
   );
diff --git a/src/pages/cv.tsx b/src/pages/cv.tsx
new file mode 100644
index 0000000..d47edc6
--- /dev/null
+++ b/src/pages/cv.tsx
@@ -0,0 +1,198 @@
+import Link from '@components/atoms/links/link';
+import { type BreadcrumbItem } from '@components/molecules/nav/breadcrumb';
+import ImageWidget from '@components/organisms/widgets/image-widget';
+import SocialMedia from '@components/organisms/widgets/social-media';
+import PageLayout, {
+  type PageLayoutProps,
+} from '@components/templates/page/page-layout';
+import CVContent, { data, meta } from '@content/pages/cv.mdx';
+import styles from '@styles/pages/cv.module.scss';
+import { getFormattedDate } from '@utils/helpers/dates';
+import { loadTranslation } from '@utils/helpers/i18n';
+import useSettings from '@utils/hooks/use-settings';
+import { GetStaticProps, NextPage } from 'next';
+import Head from 'next/head';
+import { useRouter } from 'next/router';
+import Script from 'next/script';
+import { ReactNode } from 'react';
+import { useIntl } from 'react-intl';
+import { AboutPage, Graph, WebPage } from 'schema-dts';
+
+/**
+ * CV page.
+ */
+const CVPage: NextPage = () => {
+  const intl = useIntl();
+  const { file, image } = data;
+  const { dates, intro, seo, title } = meta;
+  const homeLabel = intl.formatMessage({
+    defaultMessage: 'Home',
+    description: 'Breadcrumb: home label',
+    id: 'j5k9Fe',
+  });
+  const breadcrumb: BreadcrumbItem[] = [
+    { id: 'home', name: homeLabel, url: '/' },
+    { id: 'cv', name: title, url: '/cv' },
+  ];
+
+  const imageWidgetTitle = intl.formatMessage({
+    defaultMessage: 'Others formats',
+    description: 'CVPage: cv preview widget title',
+    id: 'B9OCyV',
+  });
+  const socialMediaTitle = intl.formatMessage({
+    defaultMessage: 'Open-source projects',
+    description: 'CVPage: social media widget title',
+    id: '+Dre5J',
+  });
+
+  const publicationLabel = intl.formatMessage({
+    defaultMessage: 'Published on:',
+    description: 'Meta: publication date label',
+    id: 'QGi5uD',
+  });
+
+  const updateLabel = intl.formatMessage({
+    defaultMessage: 'Updated on:',
+    description: 'Meta: update date label',
+    id: 'tLC7bh',
+  });
+
+  const headerMeta: PageLayoutProps['headerMeta'] = {
+    publication: {
+      name: publicationLabel,
+      value: getFormattedDate(dates.publication),
+    },
+    update: { name: updateLabel, value: getFormattedDate(dates.update) },
+  };
+
+  const { website } = useSettings();
+  const cvAlt = intl.formatMessage(
+    {
+      defaultMessage: '{name} CV',
+      description: 'CVPage: CV image alternative text',
+      id: 'KUowUk',
+    },
+    { name: website.name }
+  );
+  const cvCaption = intl.formatMessage(
+    {
+      defaultMessage: '<link>Download the CV in PDF</link>',
+      id: 'fN04AJ',
+      description: 'CVPage: download CV in PDF text',
+    },
+    {
+      link: (chunks: ReactNode) => (
+        <Link download={true} href={file}>
+          {chunks}
+        </Link>
+      ),
+    }
+  );
+
+  const widgets = [
+    <ImageWidget
+      key="image-widget"
+      expanded={true}
+      title={imageWidgetTitle}
+      level={2}
+      image={{ alt: cvAlt, ...image }}
+      description={cvCaption}
+      imageClassName={styles.image}
+    />,
+    <SocialMedia
+      key="social-media"
+      title={socialMediaTitle}
+      level={2}
+      media={[
+        { name: 'Github', url: 'https://github.com/ArmandPhilippot' },
+        { name: 'Gitlab', url: 'https://gitlab.com/ArmandPhilippot' },
+        {
+          name: 'LinkedIn',
+          url: 'https://www.linkedin.com/in/armandphilippot',
+        },
+      ]}
+    />,
+  ];
+
+  const { asPath } = useRouter();
+  const pageUrl = `${website.url}${asPath}`;
+  const pagePublicationDate = new Date(dates.publication);
+  const pageUpdateDate = new Date(dates.update);
+
+  const webpageSchema: WebPage = {
+    '@id': `${pageUrl}`,
+    '@type': 'WebPage',
+    breadcrumb: { '@id': `${website.url}/#breadcrumb` },
+    name: seo.title,
+    description: seo.description,
+    reviewedBy: { '@id': `${website.url}/#branding` },
+    url: `${pageUrl}`,
+    isPartOf: {
+      '@id': `${website.url}`,
+    },
+  };
+
+  const cvSchema: AboutPage = {
+    '@id': `${website.url}/#cv`,
+    '@type': 'AboutPage',
+    name: seo.title,
+    description: intro,
+    author: { '@id': `${website.url}/#branding` },
+    creator: { '@id': `${website.url}/#branding` },
+    dateCreated: pagePublicationDate.toISOString(),
+    dateModified: pageUpdateDate.toISOString(),
+    datePublished: pagePublicationDate.toISOString(),
+    editor: { '@id': `${website.url}/#branding` },
+    image: image.src,
+    inLanguage: website.locales.default,
+    license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr',
+    thumbnailUrl: image.src,
+    mainEntityOfPage: { '@id': `${pageUrl}` },
+  };
+
+  const schemaJsonLd: Graph = {
+    '@context': 'https://schema.org',
+    '@graph': [webpageSchema, cvSchema],
+  };
+
+  return (
+    <PageLayout
+      title={title}
+      intro={intro}
+      headerMeta={headerMeta}
+      breadcrumb={breadcrumb}
+      withToC={true}
+      widgets={widgets}
+    >
+      <Head>
+        <title>{`${seo.title} - ${website.name}`}</title>
+        <meta name="description" content={seo.description} />
+        <meta property="og:url" content={`${pageUrl}`} />
+        <meta property="og:type" content="article" />
+        <meta property="og:title" content={title} />
+        <meta property="og:description" content={intro} />
+        <meta property="og:image" content={image.src} />
+        <meta property="og:image:alt" content={title} />
+      </Head>
+      <Script
+        id="schema-cv"
+        type="application/ld+json"
+        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }}
+      />
+      <CVContent />
+    </PageLayout>
+  );
+};
+
+export const getStaticProps: GetStaticProps = async ({ locale }) => {
+  const translation = await loadTranslation(locale);
+
+  return {
+    props: {
+      translation,
+    },
+  };
+};
+
+export default CVPage;
diff --git a/src/styles/pages/cv.module.scss b/src/styles/pages/cv.module.scss
new file mode 100644
index 0000000..615c50d
--- /dev/null
+++ b/src/styles/pages/cv.module.scss
@@ -0,0 +1,3 @@
+.image {
+  max-width: min(100%, 25ch);
+}
-- 
cgit v1.2.3


From 0f8f963ba3eccd7fd94785bf7fb216b6287cec57 Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
Date: Sun, 22 May 2022 19:26:45 +0200
Subject: chore: adjust dark mode styles

---
 src/components/atoms/icons/plus-minus.stories.tsx |   2 +-
 src/components/atoms/links/link.module.scss       | 158 +++++++++++++++++-----
 src/components/atoms/links/link.stories.tsx       |  58 ++++++++
 src/components/molecules/layout/card.tsx          |   2 +-
 src/components/molecules/layout/code.module.scss  |   2 +
 src/styles/pages/partials/_article-links.scss     | 100 ++++++++++++++
 6 files changed, 288 insertions(+), 34 deletions(-)

(limited to 'src/components/atoms/links/link.stories.tsx')

diff --git a/src/components/atoms/icons/plus-minus.stories.tsx b/src/components/atoms/icons/plus-minus.stories.tsx
index f7e55f8..eebf1e5 100644
--- a/src/components/atoms/icons/plus-minus.stories.tsx
+++ b/src/components/atoms/icons/plus-minus.stories.tsx
@@ -24,9 +24,9 @@ export default {
     state: {
       control: {
         type: 'radio',
-        options: ['plus', 'minus'],
       },
       description: 'Which state should be displayed.',
+      options: ['plus', 'minus'],
       type: {
         name: 'enum',
         required: true,
diff --git a/src/components/atoms/links/link.module.scss b/src/components/atoms/links/link.module.scss
index 1b89727..bb5775f 100644
--- a/src/components/atoms/links/link.module.scss
+++ b/src/components/atoms/links/link.module.scss
@@ -1,6 +1,7 @@
 @use "@styles/abstracts/functions" as fun;
 @use "@styles/abstracts/variables" as var;
 
+/* stylelint-disable no-descending-specificity */
 .link {
   &[hreflang] {
     &::after {
@@ -21,20 +22,14 @@
       /* Prettier is removing spacing between content parts. */
 
       /* prettier-ignore */
-      content: "\0000a0" url(
-fun.encode-svg(
-        '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'
-));
+      content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'));
     }
 
     &:focus:not(:active)::after {
       /* Prettier is removing spacing between content parts. */
 
       /* prettier-ignore */
-      content: "\0000a0" url(
-fun.encode-svg(
-        '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_white}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'
-));
+      content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_white}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'));
     }
 
     &[hreflang] {
@@ -42,10 +37,14 @@ fun.encode-svg(
         /* Prettier is removing spacing between content parts. */
 
         /* prettier-ignore */
-        content: "\0000a0[" attr(hreflang) "]\0000a0" url(
-fun.encode-svg(
-          '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'
-));
+        content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'));
+      }
+
+      &:focus:not(:active)::after {
+        /* Prettier is removing spacing between content parts. */
+
+        /* prettier-ignore */
+        content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_white}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'));
       }
     }
   }
@@ -72,20 +71,14 @@ fun.encode-svg(
         /* Prettier is removing spacing between content parts. */
 
         /* prettier-ignore */
-        content: "\0000a0[" attr(hreflang) "]\0000a0" url(
-fun.encode-svg(
-            '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'
-));
+        content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
       }
 
       &:focus:not(:active)::after {
         /* Prettier is removing spacing between content parts. */
 
         /* prettier-ignore */
-        content: "\0000a0[" attr(hreflang) "]\0000a0" url(
-fun.encode-svg(
-            '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_white}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'
-));
+        content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_white}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
       }
     }
   }
@@ -95,10 +88,14 @@ fun.encode-svg(
       /* Prettier is removing spacing between content parts. */
 
       /* prettier-ignore */
-      content: "\0000a0" url(
-fun.encode-svg(
-          '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'
-)) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+      content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>')) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+    }
+
+    &:focus:not(:active)::after {
+      /* Prettier is removing spacing between content parts. */
+
+      /* prettier-ignore */
+      content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_white}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>')) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_white}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
     }
 
     &[hreflang] {
@@ -106,21 +103,118 @@ fun.encode-svg(
         /* Prettier is removing spacing between content parts. */
 
         /* prettier-ignore */
-        content: "\0000a0[" attr(hreflang) "]\0000a0" url(
-fun.encode-svg(
-          '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'
-)) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+        content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>')) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
       }
 
       &:focus:not(:active)::after {
         /* Prettier is removing spacing between content parts. */
 
         /* prettier-ignore */
-        content: "\0000a0[" attr(hreflang) "]\0000a0" url(
-fun.encode-svg(
-          '<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'
-)) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_white}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+        content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$light-theme_white}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>')) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$light-theme_white}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$light-theme_white}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+      }
+    }
+  }
+}
+
+:global([data-theme="dark"]) {
+  :local {
+    .link {
+      &--download {
+        &::after {
+          /* Prettier is removing spacing between content parts. */
+
+          /* prettier-ignore */
+          content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'));
+        }
+
+        &:focus:not(:active)::after {
+          /* Prettier is removing spacing between content parts. */
+
+          /* prettier-ignore */
+          content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_black}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'));
+        }
+
+        &[hreflang] {
+          &::after {
+            /* Prettier is removing spacing between content parts. */
+
+            /* prettier-ignore */
+            content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'));
+          }
+
+          &:focus:not(:active)::after {
+            /* Prettier is removing spacing between content parts. */
+
+            /* prettier-ignore */
+            content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_black}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'));
+          }
+        }
+      }
+
+      &--external {
+        &::after {
+          /* Prettier is removing spacing between content parts. */
+
+          /* prettier-ignore */
+          content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+        }
+
+        &:focus:not(:active)::after {
+          /* Prettier is removing spacing between content parts. */
+
+          /* prettier-ignore */
+          content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_black}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+        }
+
+        &[hreflang] {
+          &::after {
+            /* Prettier is removing spacing between content parts. */
+
+            /* prettier-ignore */
+            content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+          }
+
+          &:focus:not(:active)::after {
+            /* Prettier is removing spacing between content parts. */
+
+            /* prettier-ignore */
+            content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_black}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+          }
+        }
+      }
+
+      &--external.link--download {
+        &::after {
+          /* Prettier is removing spacing between content parts. */
+
+          /* prettier-ignore */
+          content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>')) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+        }
+
+        &:focus:not(:active)::after {
+          /* Prettier is removing spacing between content parts. */
+
+          /* prettier-ignore */
+          content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_black}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>')) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_black}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+        }
+
+        &[hreflang] {
+          &::after {
+            /* Prettier is removing spacing between content parts. */
+
+            /* prettier-ignore */
+            content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>')) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+          }
+
+          &:focus:not(:active)::after {
+            /* Prettier is removing spacing between content parts. */
+
+            /* prettier-ignore */
+            content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_black}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>')) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_black}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+          }
+        }
       }
     }
   }
 }
+/* stylelint-enable no-descending-specificity */
diff --git a/src/components/atoms/links/link.stories.tsx b/src/components/atoms/links/link.stories.tsx
index 420eafe..4baabe5 100644
--- a/src/components/atoms/links/link.stories.tsx
+++ b/src/components/atoms/links/link.stories.tsx
@@ -98,6 +98,29 @@ Default.args = {
   external: false,
 };
 
+/**
+ * Links Stories - Download
+ */
+export const Download = Template.bind({});
+Download.args = {
+  children: 'A link to a file',
+  href: '#',
+  download: true,
+  external: false,
+};
+
+/**
+ * Links Stories - DownloadWithLang
+ */
+export const DownloadWithLang = Template.bind({});
+DownloadWithLang.args = {
+  children: 'A link to a file',
+  href: '#',
+  download: true,
+  external: false,
+  lang: 'en',
+};
+
 /**
  * Links Stories - External
  */
@@ -109,6 +132,17 @@ External.args = {
   external: true,
 };
 
+/**
+ * Links Stories - External download
+ */
+export const ExternalDownload = Template.bind({});
+ExternalDownload.args = {
+  children: 'A link',
+  href: '#',
+  download: true,
+  external: true,
+};
+
 /**
  * Links Stories - External With Lang
  */
@@ -120,3 +154,27 @@ ExternalWithLang.args = {
   external: true,
   lang: 'en',
 };
+
+/**
+ * Links Stories - External download with lang
+ */
+export const ExternalDownloadWithLang = Template.bind({});
+ExternalDownloadWithLang.args = {
+  children: 'A link',
+  href: '#',
+  download: true,
+  external: true,
+  lang: 'en',
+};
+
+/**
+ * Links Stories - With Lang
+ */
+export const WithLang = Template.bind({});
+WithLang.args = {
+  children: 'A link',
+  href: '#',
+  download: false,
+  external: false,
+  lang: 'en',
+};
diff --git a/src/components/molecules/layout/card.tsx b/src/components/molecules/layout/card.tsx
index 003060f..e465f76 100644
--- a/src/components/molecules/layout/card.tsx
+++ b/src/components/molecules/layout/card.tsx
@@ -95,7 +95,7 @@ const Card: FC<CardProps> = ({
             {title}
           </Heading>
         </header>
-        <div className={styles.tagline}>{tagline}</div>
+        {tagline && <div className={styles.tagline}>{tagline}</div>}
         {meta && (
           <footer className={styles.footer}>
             <Meta
diff --git a/src/components/molecules/layout/code.module.scss b/src/components/molecules/layout/code.module.scss
index 2855fc2..1feeccc 100644
--- a/src/components/molecules/layout/code.module.scss
+++ b/src/components/molecules/layout/code.module.scss
@@ -105,7 +105,9 @@
 
       position: relative;
       overflow: auto;
+      background: var(--color-bg-secondary);
       border: fun.convert-px(1) solid var(--color-border-light);
+      color: var(--color-fg);
       hyphens: none;
       tab-size: 4;
       text-align: left;
diff --git a/src/styles/pages/partials/_article-links.scss b/src/styles/pages/partials/_article-links.scss
index df86dcf..543337a 100644
--- a/src/styles/pages/partials/_article-links.scss
+++ b/src/styles/pages/partials/_article-links.scss
@@ -16,6 +16,7 @@
     }
   }
 
+  /* stylelint-disable no-descending-specificity */
   a.download {
     &::after {
       display: inline-block;
@@ -101,4 +102,103 @@
       }
     }
   }
+
+  [data-theme="dark"] {
+    a.download {
+      &::after {
+        /* Prettier is removing spacing between content parts. */
+
+        /* prettier-ignore */
+        content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'));
+      }
+
+      &:focus:not(:active)::after {
+        /* Prettier is removing spacing between content parts. */
+
+        /* prettier-ignore */
+        content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_black}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'));
+      }
+
+      &[hreflang] {
+        &::after {
+          /* Prettier is removing spacing between content parts. */
+
+          /* prettier-ignore */
+          content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'));
+        }
+
+        &:focus:not(:active)::after {
+          /* Prettier is removing spacing between content parts. */
+
+          /* prettier-ignore */
+          content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_black}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>'));
+        }
+      }
+    }
+
+    a.external {
+      &::after {
+        /* Prettier is removing spacing between content parts. */
+
+        /* prettier-ignore */
+        content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+      }
+
+      &:focus:not(:active)::after {
+        /* Prettier is removing spacing between content parts. */
+
+        /* prettier-ignore */
+        content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_black}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+      }
+
+      &[hreflang] {
+        &::after {
+          /* Prettier is removing spacing between content parts. */
+
+          /* prettier-ignore */
+          content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+        }
+
+        &:focus:not(:active)::after {
+          /* Prettier is removing spacing between content parts. */
+
+          /* prettier-ignore */
+          content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_black}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+        }
+      }
+    }
+
+    a.external.download {
+      &::after {
+        /* Prettier is removing spacing between content parts. */
+
+        /* prettier-ignore */
+        content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>')) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+      }
+
+      &:focus:not(:active)::after {
+        /* Prettier is removing spacing between content parts. */
+
+        /* prettier-ignore */
+        content: "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_black}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>')) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_black}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+      }
+
+      &[hreflang] {
+        &::after {
+          /* Prettier is removing spacing between content parts. */
+
+          /* prettier-ignore */
+          content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_blue}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>')) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_blue}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_blue}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+        }
+
+        &:focus:not(:active)::after {
+          /* Prettier is removing spacing between content parts. */
+
+          /* prettier-ignore */
+          content: "\0000a0[" attr(hreflang) "]\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="m49 80.048-28.445-30.77 19.32 4.095V5.06h18.252v48.313l21.318-4.095z"/><path fill="#{var.$dark-theme_black}" d="M0 67.57v27.37h100V67.57H87.973v15.344H12.027V67.569z"/></svg>')) "\0000a0" url(fun.encode-svg('<svg width="13" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path fill="#{var.$dark-theme_black}" d="M100 0 59.543 5.887l20.8 6.523-51.134 51.134 7.249 7.248L87.59 19.66l6.522 20.798z"/><path fill="#{var.$dark-theme_black}" d="M4 10a4 4 0 0 0-4 4v82a4 4 0 0 0 4 4h82a4 4 0 0 0 4-4V62.314h-8V92H8V18h29.686v-8z"/></svg>'));
+        }
+      }
+    }
+  }
 }
+/* stylelint-enable no-descending-specificity */
-- 
cgit v1.2.3

