diff options
34 files changed, 692 insertions, 615 deletions
| diff --git a/.cspell/french-contents.txt b/.cspell/french-contents.txt index 1931b21..2d25575 100644 --- a/.cspell/french-contents.txt +++ b/.cspell/french-contents.txt @@ -1,6 +1,10 @@  Adwords  Auxseo +Coreutils +dotfiles +dotig  GIDO +htdocs  Jasson  Londe  Massena @@ -12,3 +16,4 @@ référenceur  Superdoc  Symfony  webmarketing +webroot diff --git a/.cspell/project-words.txt b/.cspell/project-words.txt index c9d6014..e2b983c 100644 --- a/.cspell/project-words.txt +++ b/.cspell/project-words.txt @@ -4,8 +4,10 @@ autodocs  changefreq  coldark  commitlint +creativecommons  Eckles  formatjs +gitlab  Gitlab  Jamstack  LINKEDIN diff --git a/src/components/atoms/links/index.ts b/src/components/atoms/links/index.ts index ad8824e..619f05c 100644 --- a/src/components/atoms/links/index.ts +++ b/src/components/atoms/links/index.ts @@ -1,4 +1,3 @@  export * from './link'; -export * from './nav-link';  export * from './sharing-link';  export * from './social-link'; diff --git a/src/components/atoms/links/link.module.scss b/src/components/atoms/links/link.module.scss deleted file mode 100644 index 4980a1c..0000000 --- a/src/components/atoms/links/link.module.scss +++ /dev/null @@ -1,220 +0,0 @@ -@use "../../../styles/abstracts/functions" as fun; -@use "../../../styles/abstracts/variables" as var; - -/* stylelint-disable no-descending-specificity */ -.link { -  &[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>')); -      } - -      &: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>')); -      } -    } -  } - -  &--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>')); -    } - -    &[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="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>')); -      } -    } -  } - -  &--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>')); -    } - -    &: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] { -      &::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_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.test.tsx b/src/components/atoms/links/link.test.tsx deleted file mode 100644 index 9829c1b..0000000 --- a/src/components/atoms/links/link.test.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { describe, expect, it } from '@jest/globals'; -import { render, screen } from '../../../../tests/utils'; -import { Link } from './link'; - -describe('Link', () => { -  it('render a link', () => { -    render(<Link href="#">A link</Link>); -    expect(screen.getByRole('link')).toHaveTextContent('A link'); -  }); -}); diff --git a/src/components/atoms/links/link.tsx b/src/components/atoms/links/link.tsx deleted file mode 100644 index 1765bb5..0000000 --- a/src/components/atoms/links/link.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import NextLink from 'next/link'; -import { AnchorHTMLAttributes, FC, ReactNode } from 'react'; -import styles from './link.module.scss'; - -export type LinkProps = AnchorHTMLAttributes<HTMLAnchorElement> & { -  /** -   * The link body. -   */ -  children: ReactNode; -  /** -   * True if it is a download link. Default: false. -   */ -  download?: boolean; -  /** -   * True if it is an external link. Default: false. -   */ -  external?: boolean; -  /** -   * The link target. -   */ -  href: string; -  /** -   * The link target code language. -   */ -  lang?: string; -}; - -/** - * Link Component - * - * Render a link. - */ -export const Link: FC<LinkProps> = ({ -  children, -  className = '', -  download = false, -  external = false, -  href, -  lang, -  ...props -}) => { -  const downloadClass = download ? styles['link--download'] : ''; -  const linkClass = `${styles.link} ${downloadClass} ${className}`; -  const externalLinkClass = `${linkClass} ${styles['link--external']}`; - -  return external ? ( -    <a {...props} className={externalLinkClass} href={href} hrefLang={lang}> -      {children} -    </a> -  ) : ( -    <NextLink {...props} className={linkClass} href={href} hrefLang={lang}> -      {children} -    </NextLink> -  ); -}; diff --git a/src/components/atoms/links/link/index.ts b/src/components/atoms/links/link/index.ts new file mode 100644 index 0000000..e33728e --- /dev/null +++ b/src/components/atoms/links/link/index.ts @@ -0,0 +1 @@ +export * from './link'; diff --git a/src/components/atoms/links/link/link.module.scss b/src/components/atoms/links/link/link.module.scss new file mode 100644 index 0000000..8f94a54 --- /dev/null +++ b/src/components/atoms/links/link/link.module.scss @@ -0,0 +1,70 @@ +@use "../../../../styles/abstracts/placeholders"; + +.link { +  color: var(--color-primary); + +  &--regular { +    @extend %link; +  } + +  &[hreflang], +  &--download, +  &--external { +    @extend %link-with-icon; +  } + +  &[hreflang]:not(#{&}--download):not(#{&}--external) { +    --is-icon-hidden: ""; +  } + +  &[hreflang] { +    @extend %link-with-lang; +  } + +  &--download { +    @extend %download-link; +  } + +  &--external { +    @extend %external-link; +  } + +  &--download, +  &--external { +    &:not([hreflang]) { +      --is-lang-hidden: ""; +    } +  } + +  &--external#{&}--download { +    @extend %external-download-link; +  } +} + +:global([data-theme="light"]) { +  :local { +    .link { +      &--download { +        @extend %light-download-link; +      } + +      &--external { +        @extend %light-external-link; +      } +    } +  } +} + +:global([data-theme="dark"]) { +  :local { +    .link { +      &--download { +        @extend %dark-download-link; +      } + +      &--external { +        @extend %dark-external-link; +      } +    } +  } +} diff --git a/src/components/atoms/links/link.stories.tsx b/src/components/atoms/links/link/link.stories.tsx index 8351de7..0a6a6c5 100644 --- a/src/components/atoms/links/link.stories.tsx +++ b/src/components/atoms/links/link/link.stories.tsx @@ -1,11 +1,11 @@ -import { ComponentMeta, ComponentStory } from '@storybook/react'; +import type { ComponentMeta, ComponentStory } from '@storybook/react';  import { Link } from './link';  /**   * Link - Storybook Meta   */  export default { -  title: 'Atoms/Typography/Links', +  title: 'Atoms/Links/Link',    component: Link,    argTypes: {      children: { @@ -31,7 +31,17 @@ export default {          required: false,        },      }, -    download: { +    href: { +      control: { +        type: 'text', +      }, +      description: 'The link target.', +      type: { +        name: 'string', +        required: true, +      }, +    }, +    isDownload: {        control: {          type: 'boolean',        }, @@ -45,7 +55,7 @@ export default {          required: false,        },      }, -    external: { +    isExternal: {        control: {          type: 'boolean',        }, @@ -59,16 +69,6 @@ export default {          required: false,        },      }, -    href: { -      control: { -        type: 'text', -      }, -      description: 'The link target.', -      type: { -        name: 'string', -        required: true, -      }, -    },      lang: {        control: {          type: 'text', @@ -94,64 +94,62 @@ export const Default = Template.bind({});  Default.args = {    children: 'A link',    href: '#', -  download: false, -  external: false,  };  /**   * Links Stories - Download   */ -export const Download = Template.bind({}); -Download.args = { +export const DownloadLink = Template.bind({}); +DownloadLink.args = {    children: 'A link to a file',    href: '#', -  download: true, -  external: false, +  isDownload: true, +  isExternal: false,  };  /** - * Links Stories - DownloadWithLang + * Links Stories - Download link with lang   */ -export const DownloadWithLang = Template.bind({}); -DownloadWithLang.args = { +export const DownloadLinkWithLang = Template.bind({}); +DownloadLinkWithLang.args = {    children: 'A link to a file',    href: '#', -  download: true, -  external: false, +  isDownload: true, +  isExternal: false,    lang: 'en',  };  /**   * Links Stories - External   */ -export const External = Template.bind({}); -External.args = { +export const ExternalLink = Template.bind({}); +ExternalLink.args = {    children: 'A link',    href: '#', -  download: false, -  external: true, +  isDownload: false, +  isExternal: true,  };  /** - * Links Stories - External download + * Links Stories - External download link   */  export const ExternalDownload = Template.bind({});  ExternalDownload.args = {    children: 'A link',    href: '#', -  download: true, -  external: true, +  isDownload: true, +  isExternal: true,  };  /** - * Links Stories - External With Lang + * Links Stories - External link with Lang   */ -export const ExternalWithLang = Template.bind({}); -ExternalWithLang.args = { +export const ExternalLinkWithLang = Template.bind({}); +ExternalLinkWithLang.args = {    children: 'A link',    href: '#', -  download: false, -  external: true, +  isDownload: false, +  isExternal: true,    lang: 'en',  }; @@ -162,19 +160,19 @@ export const ExternalDownloadWithLang = Template.bind({});  ExternalDownloadWithLang.args = {    children: 'A link',    href: '#', -  download: true, -  external: true, +  isDownload: true, +  isExternal: true,    lang: 'en',  };  /**   * Links Stories - With Lang   */ -export const WithLang = Template.bind({}); -WithLang.args = { +export const LinkLang = Template.bind({}); +LinkLang.args = {    children: 'A link',    href: '#', -  download: false, -  external: false, +  isDownload: false, +  isExternal: false,    lang: 'en',  }; diff --git a/src/components/atoms/links/link/link.test.tsx b/src/components/atoms/links/link/link.test.tsx new file mode 100644 index 0000000..ad1951d --- /dev/null +++ b/src/components/atoms/links/link/link.test.tsx @@ -0,0 +1,47 @@ +import { describe, expect, it } from '@jest/globals'; +import { render, screen as rtlScreen } from '@testing-library/react'; +import { Link } from './link'; + +describe('Link', () => { +  it('renders a link', () => { +    const anchor = 'porro'; +    const target = '/tempora'; + +    render(<Link href={target}>{anchor}</Link>); + +    expect(rtlScreen.getByRole('link', { name: anchor })).toHaveAttribute( +      'href', +      target +    ); +  }); + +  it('can render an external link', () => { +    const anchor = 'accusamus'; +    const target = 'https://www.example.com'; + +    render( +      <Link href={target} isExternal> +        {anchor} +      </Link> +    ); + +    expect(rtlScreen.getByRole('link', { name: anchor })).toHaveClass( +      'link--external' +    ); +  }); + +  it('can render a download link', () => { +    const anchor = 'dolor'; +    const target = '/officiis.pdf'; + +    render( +      <Link href={target} isDownload> +        {anchor} +      </Link> +    ); + +    expect(rtlScreen.getByRole('link', { name: anchor })).toHaveClass( +      'link--download' +    ); +  }); +}); diff --git a/src/components/atoms/links/link/link.tsx b/src/components/atoms/links/link/link.tsx new file mode 100644 index 0000000..e88cc7c --- /dev/null +++ b/src/components/atoms/links/link/link.tsx @@ -0,0 +1,90 @@ +import NextLink from 'next/link'; +import { +  forwardRef, +  type AnchorHTMLAttributes, +  type ForwardRefRenderFunction, +  type ReactNode, +} from 'react'; +import styles from './link.module.scss'; + +export type LinkProps = Omit< +  AnchorHTMLAttributes<HTMLAnchorElement>, +  'children' | 'download' | 'hrefLang' | 'lang' +> & { +  /** +   * The link body. +   */ +  children: ReactNode; +  /** +   * Should we disable the default transition on links? +   * +   * @default false +   */ +  disableTransition?: boolean; +  /** +   * True if it is a download link. +   * +   * @default false +   */ +  isDownload?: boolean; +  /** +   * True if it is an external link. +   * +   * @default false +   */ +  isExternal?: boolean; +  /** +   * The link target. +   */ +  href: string; +  /** +   * The link target code language. +   */ +  lang?: string; +}; + +const LinkWithRef: ForwardRefRenderFunction<HTMLAnchorElement, LinkProps> = ( +  { +    children, +    className = '', +    disableTransition = false, +    isDownload = false, +    isExternal = false, +    href, +    lang, +    rel = '', +    ...props +  }, +  ref +) => { +  const LinkComponent = isExternal ? 'a' : NextLink; +  const linkClass = [ +    styles.link, +    styles[disableTransition ? '' : 'link--regular'], +    styles[isDownload ? 'link--download' : ''], +    styles[isExternal ? 'link--external' : ''], +    className, +  ].join(' '); +  const linkRel = +    isExternal && !rel.includes('external') ? `external ${rel}` : rel; + +  return ( +    <LinkComponent +      {...props} +      className={linkClass} +      href={href} +      hrefLang={lang} +      ref={ref} +      rel={linkRel} +    > +      {children} +    </LinkComponent> +  ); +}; + +/** + * Link Component + * + * Render a link. + */ +export const Link = forwardRef(LinkWithRef); diff --git a/src/components/atoms/links/nav-link.test.tsx b/src/components/atoms/links/nav-link.test.tsx deleted file mode 100644 index acf3225..0000000 --- a/src/components/atoms/links/nav-link.test.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { describe, expect, it } from '@jest/globals'; -import { render, screen } from '../../../../tests/utils'; -import { NavLink } from './nav-link'; - -describe('NavLink', () => { -  it('renders a nav link to blog page', () => { -    render(<NavLink href="/blog" label="Blog" />); -    expect(screen.getByRole('link', { name: 'Blog' })).toHaveAttribute( -      'href', -      '/blog' -    ); -  }); -}); diff --git a/src/components/atoms/links/nav-link.tsx b/src/components/atoms/links/nav-link.tsx deleted file mode 100644 index 109529c..0000000 --- a/src/components/atoms/links/nav-link.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import Link from 'next/link'; -import { FC, ReactNode } from 'react'; -import styles from './nav-link.module.scss'; - -export type NavLinkProps = { -  /** -   * Link target. -   */ -  href: string; -  /** -   * Link label. -   */ -  label: string; -  /** -   * Link logo. -   */ -  logo?: ReactNode; -}; - -/** - * NavLink component - * - * Render a navigation link. - */ -export const NavLink: FC<NavLinkProps> = ({ href, label, logo }) => { -  return ( -    <Link className={styles.link} href={href}> -      {logo} -      {label} -    </Link> -  ); -}; diff --git a/src/components/molecules/layout/branding.tsx b/src/components/molecules/layout/branding.tsx index 981da74..dceee5e 100644 --- a/src/components/molecules/layout/branding.tsx +++ b/src/components/molecules/layout/branding.tsx @@ -1,8 +1,7 @@ -import Link from 'next/link';  import { type FC, useRef } from 'react';  import { useIntl } from 'react-intl';  import { useStyles } from '../../../utils/hooks'; -import { Heading } from '../../atoms'; +import { Heading, Link } from '../../atoms';  import { FlippingLogo, type FlippingLogoProps } from '../images';  import styles from './branding.module.scss'; diff --git a/src/components/molecules/layout/meta.tsx b/src/components/molecules/layout/meta.tsx index 094c420..63909a4 100644 --- a/src/components/molecules/layout/meta.tsx +++ b/src/components/molecules/layout/meta.tsx @@ -336,7 +336,7 @@ export const Meta: FC<MetaProps> = ({          );        case 'website':          return typeof value === 'string' ? ( -          <Link href={value} external={true}> +          <Link href={value} isExternal>              {value}            </Link>          ) : null; diff --git a/src/components/molecules/nav/index.ts b/src/components/molecules/nav/index.ts index 9c46050..fe7cd0b 100644 --- a/src/components/molecules/nav/index.ts +++ b/src/components/molecules/nav/index.ts @@ -1,3 +1,4 @@  export * from './breadcrumb'; +export * from './nav-link';  export * from './nav-list';  export * from './pagination'; diff --git a/src/components/molecules/nav/nav-link/index.ts b/src/components/molecules/nav/nav-link/index.ts new file mode 100644 index 0000000..f1b68c2 --- /dev/null +++ b/src/components/molecules/nav/nav-link/index.ts @@ -0,0 +1 @@ +export * from './nav-link'; diff --git a/src/components/atoms/links/nav-link.module.scss b/src/components/molecules/nav/nav-link/nav-link.module.scss index e72885a..8a7d371 100644 --- a/src/components/atoms/links/nav-link.module.scss +++ b/src/components/molecules/nav/nav-link/nav-link.module.scss @@ -1,29 +1,39 @@ -@use "../../../styles/abstracts/functions" as fun; -@use "../../../styles/abstracts/mixins" as mix; -@use "../../../styles/abstracts/placeholders"; +@use "../../../../styles/abstracts/functions" as fun; +@use "../../../../styles/abstracts/placeholders";  .link {    --draw-border-thickness: #{fun.convert-px(4)};    --draw-border-color1: var(--color-primary-light);    --draw-border-color2: var(--color-primary-lighter); -  display: inline-flex; -  flex-flow: column nowrap; +  display: flex; +  flex-flow: row wrap;    place-items: center;    place-content: center;    row-gap: var(--spacing-2xs); -  min-width: var(--link-min-width, fun.convert-px(85)); -  padding: var(--spacing-xs); -  background: inherit; +  min-width: var(--link-min-width, fun.convert-px(80)); +  padding: var(--spacing-xs) var(--spacing-xs) var(--spacing-2xs); +  background: none; +  border-radius: 8%;    font-size: var(--font-size-sm);    font-variant: small-caps;    font-weight: 600; -  line-height: 1; +  text-align: center;    text-decoration: none; -  @include mix.media("screen") { -    @include mix.dimensions("md") { -      border-radius: 8%; +  &--inline { +    width: fit-content; + +    .logo { +      margin-right: var(--spacing-xs); +    } +  } + +  &--stack { +    .logo { +      flex: 0 0 100%; +      display: flex; +      place-content: center;      }    } @@ -32,6 +42,10 @@      @extend %draw-borders;    } +  &:hover { +    color: var(--color-primary-light); +  } +    &:focus {      color: var(--color-primary-light);    } @@ -40,6 +54,8 @@      --draw-border-color1: var(--color-primary-dark);      --draw-border-color2: var(--color-primary-light); +    color: var(--color-primary-dark); +      @extend %draw-borders;    }  } diff --git a/src/components/atoms/links/nav-link.stories.tsx b/src/components/molecules/nav/nav-link/nav-link.stories.tsx index 7fca926..4e8400f 100644 --- a/src/components/atoms/links/nav-link.stories.tsx +++ b/src/components/molecules/nav/nav-link/nav-link.stories.tsx @@ -1,11 +1,12 @@ -import { ComponentMeta, ComponentStory } from '@storybook/react'; +import type { ComponentMeta, ComponentStory } from '@storybook/react'; +import { Icon } from '../../../atoms';  import { NavLink as NavLinkComponent } from './nav-link';  /**   * NavLink - Storybook Meta   */  export default { -  title: 'Atoms/Typography/Links', +  title: 'Molecules/Nav/NavLink',    component: NavLinkComponent,    argTypes: {      href: { @@ -42,14 +43,37 @@ export default {  } as ComponentMeta<typeof NavLinkComponent>;  const Template: ComponentStory<typeof NavLinkComponent> = (args) => ( -  <NavLinkComponent {...args} /> +  <div style={{ width: 'fit-content' }}> +    <NavLinkComponent {...args} /> +  </div>  );  /** - * Links Stories - Nav Link + * NavLink Stories - Default   */ -export const NavLink = Template.bind({}); -NavLink.args = { +export const Default = Template.bind({}); +Default.args = {    href: '#',    label: 'A nav link',  }; + +/** + * NavLink Stories - StackWithLogo + */ +export const StackWithLogo = Template.bind({}); +StackWithLogo.args = { +  href: '#example', +  label: 'A nav link', +  logo: <Icon aria-hidden shape="home" />, +}; + +/** + * NavLink Stories - InlineWithLogo + */ +export const InlineWithLogo = Template.bind({}); +InlineWithLogo.args = { +  href: '#example', +  isInline: true, +  label: 'A nav link', +  logo: <Icon aria-hidden shape="home" />, +}; diff --git a/src/components/molecules/nav/nav-link/nav-link.test.tsx b/src/components/molecules/nav/nav-link/nav-link.test.tsx new file mode 100644 index 0000000..aa9b557 --- /dev/null +++ b/src/components/molecules/nav/nav-link/nav-link.test.tsx @@ -0,0 +1,28 @@ +import { describe, expect, it } from '@jest/globals'; +import { render, screen as rtlScreen } from '@testing-library/react'; +import { NavLink } from './nav-link'; + +describe('NavLink', () => { +  it('renders a link', () => { +    const label = 'eius'; +    const target = '#harum'; + +    render(<NavLink href={target} label={label} />); + +    expect(rtlScreen.getByRole('link', { name: label })).toHaveAttribute( +      'href', +      target +    ); +  }); + +  it('can render a nav link with inlined contents', () => { +    const label = 'eius'; +    const target = '#harum'; + +    render(<NavLink href={target} isInline label={label} />); + +    expect(rtlScreen.getByRole('link', { name: label })).toHaveClass( +      'link--inline' +    ); +  }); +}); diff --git a/src/components/molecules/nav/nav-link/nav-link.tsx b/src/components/molecules/nav/nav-link/nav-link.tsx new file mode 100644 index 0000000..f9fc529 --- /dev/null +++ b/src/components/molecules/nav/nav-link/nav-link.tsx @@ -0,0 +1,44 @@ +import { +  type ForwardRefRenderFunction, +  forwardRef, +  type ReactNode, +} from 'react'; +import { Link, type LinkProps } from '../../../atoms'; +import styles from './nav-link.module.scss'; + +export type NavLinkProps = Omit<LinkProps, 'children' | 'disableTransition'> & { +  /** +   * Should the logo and label be inlined? +   * +   * @default false +   */ +  isInline?: boolean; +  /** +   * The link label. +   */ +  label: string; +  /** +   * The link logo. +   */ +  logo?: ReactNode; +}; + +const NavLinkWithRef: ForwardRefRenderFunction< +  HTMLAnchorElement, +  NavLinkProps +> = ({ className = '', isInline = false, label, logo, ...props }, ref) => { +  const linkClass = [ +    styles.link, +    styles[isInline ? 'link--inline' : 'link--stack'], +    className, +  ].join(' '); + +  return ( +    <Link {...props} className={linkClass} disableTransition ref={ref}> +      {logo ? <span className={styles.logo}>{logo}</span> : null} +      {label} +    </Link> +  ); +}; + +export const NavLink = forwardRef(NavLinkWithRef); diff --git a/src/components/molecules/nav/nav-list.module.scss b/src/components/molecules/nav/nav-list.module.scss index ff99581..316638e 100644 --- a/src/components/molecules/nav/nav-list.module.scss +++ b/src/components/molecules/nav/nav-list.module.scss @@ -1,4 +1,14 @@  .nav { +  &--main { +    width: fit-content; +  } + +  &--main & { +    &__item { +      flex: 1; +    } +  } +    &--footer & {      &__item:not(:first-child) {        &::before { diff --git a/src/components/molecules/nav/nav-list.tsx b/src/components/molecules/nav/nav-list.tsx index 55c2aa9..b3c7138 100644 --- a/src/components/molecules/nav/nav-list.tsx +++ b/src/components/molecules/nav/nav-list.tsx @@ -1,5 +1,6 @@  import type { FC, ReactNode } from 'react'; -import { Link, List, ListItem, Nav, NavLink, type NavProps } from '../../atoms'; +import { Link, List, ListItem, Nav, type NavProps } from '../../atoms'; +import { NavLink } from './nav-link';  import styles from './nav-list.module.scss';  export type NavItem = { @@ -49,7 +50,7 @@ export const NavList: FC<NavListProps> = ({    ...props  }) => {    const kindClass = `nav--${kind}`; -  const navClass = `${styles[kindClass]} ${className}`; +  const navClass = `${styles.nav} ${styles[kindClass]} ${className}`;    /**     * Get the nav items. diff --git a/src/components/organisms/layout/comment.module.scss b/src/components/organisms/layout/comment.module.scss index f645354..bf8aada 100644 --- a/src/components/organisms/layout/comment.module.scss +++ b/src/components/organisms/layout/comment.module.scss @@ -1,11 +1,13 @@  @use "../../../styles/abstracts/functions" as fun;  @use "../../../styles/abstracts/mixins" as mix; +@use "../../../styles/abstracts/placeholders";  .wrapper {    padding: var(--spacing-md);    background: var(--color-bg);    border: fun.convert-px(1) solid var(--color-border); -  box-shadow: fun.convert-px(3) fun.convert-px(3) 0 0 var(--color-shadow-light), +  box-shadow: +    fun.convert-px(3) fun.convert-px(3) 0 0 var(--color-shadow-light),      fun.convert-px(4) fun.convert-px(4) fun.convert-px(3) fun.convert-px(-2)        var(--color-shadow); @@ -50,7 +52,8 @@      height: fun.convert-px(85);      position: relative;      border-radius: fun.convert-px(3); -    box-shadow: 0 0 0 fun.convert-px(1) var(--color-shadow-light), +    box-shadow: +      0 0 0 fun.convert-px(1) var(--color-shadow-light),        fun.convert-px(2) fun.convert-px(2) 0 fun.convert-px(1)          var(--color-shadow); @@ -80,6 +83,45 @@    .body {      overflow-wrap: break-word; + +    :global { +      a { +        @extend %link; + +        &[hreflang], +        &.download, +        &.external { +          @extend %link-with-icon; +        } + +        &[hreflang] { +          @extend %link-with-lang; +        } + +        &[hreflang]:not(.download, .external) { +          --is-icon-hidden: ""; +        } + +        &.download { +          @extend %download-link; +        } + +        &.external { +          @extend %external-link; +        } + +        &.download, +        &.external { +          &:not([hreflang]) { +            --is-lang-hidden: ""; +          } +        } + +        &.external.download { +          @extend %external-download-link; +        } +      } +    }    }    .footer { diff --git a/src/components/organisms/layout/summary.module.scss b/src/components/organisms/layout/summary.module.scss index 5052f73..b6cb4f4 100644 --- a/src/components/organisms/layout/summary.module.scss +++ b/src/components/organisms/layout/summary.module.scss @@ -1,5 +1,6 @@  @use "../../../styles/abstracts/functions" as fun;  @use "../../../styles/abstracts/mixins" as mix; +@use "../../../styles/abstracts/placeholders";  .wrapper {    display: grid; @@ -118,3 +119,80 @@      }    }  } + +.intro { +  :global { +    a { +      @extend %link; + +      &[hreflang], +      &.download, +      &.external { +        @extend %link-with-icon; +      } + +      &[hreflang] { +        @extend %link-with-lang; +      } + +      &[hreflang]:not(.download, .external) { +        --is-icon-hidden: ""; +      } + +      &.download { +        @extend %download-link; +      } + +      &.external { +        @extend %external-link; +      } + +      &.download, +      &.external { +        &:not([hreflang]) { +          --is-lang-hidden: ""; +        } +      } + +      &.external.download { +        @extend %external-download-link; +      } +    } +  } +} + +:global([data-theme="light"]) { +  :local { +    .intro { +      :global { +        a { +          &.download { +            @extend %light-download-link; +          } + +          &.external { +            @extend %light-external-link; +          } +        } +      } +    } +  } +} + +:global([data-theme="dark"]) { +  :local { +    .intro { +      :global { +        a { +          &.download { +            @extend %dark-download-link; +          } + +          &.external { +            @extend %dark-external-link; +          } +        } +      } +    } +  } +} diff --git a/src/components/organisms/layout/summary.tsx b/src/components/organisms/layout/summary.tsx index d66af75..e21e4c7 100644 --- a/src/components/organisms/layout/summary.tsx +++ b/src/components/organisms/layout/summary.tsx @@ -117,9 +117,11 @@ export const Summary: FC<SummaryProps> = ({          </Link>        </header>        <div className={styles.body}> -        {/* eslint-disable-next-line react/no-danger -- Not safe but intro can -         * contains links or formatting so we need it. */} -        <div dangerouslySetInnerHTML={{ __html: intro }} /> +        <div +          className={styles.intro} +          // eslint-disable-next-line react/no-danger +          dangerouslySetInnerHTML={{ __html: intro }} +        />          <ButtonLink className={styles['read-more']} to={url}>            <>              {readMore} diff --git a/src/content b/src/content -Subproject c7236df956a4f9e242126540c175ac5dfd0b9c7 +Subproject 0a5267ca7df1b6600741aa172ffdfe7b4f762d9 diff --git a/src/pages/cv.tsx b/src/pages/cv.tsx index 5882ff6..b23c7a2 100644 --- a/src/pages/cv.tsx +++ b/src/pages/cv.tsx @@ -38,7 +38,7 @@ const ExternalLink = ({    href = '',    ...props  }: AnchorHTMLAttributes<HTMLAnchorElement>) => ( -  <Link {...props} external={true} href={href}> +  <Link {...props} isExternal href={href}>      {children}    </Link>  ); @@ -172,7 +172,7 @@ const CVPage: NextPageWithLayout = () => {      },      {        link: (chunks: ReactNode) => ( -        <Link download={true} href={file}> +        <Link href={file} isDownload>            {chunks}          </Link>        ), diff --git a/src/styles/abstracts/_placeholders.scss b/src/styles/abstracts/_placeholders.scss index c978f96..04522d7 100644 --- a/src/styles/abstracts/_placeholders.scss +++ b/src/styles/abstracts/_placeholders.scss @@ -3,4 +3,5 @@  @forward "./placeholders/clearfix";  @forward "./placeholders/headings";  @forward "./placeholders/layout"; +@forward "./placeholders/links";  @forward "./placeholders/lists"; diff --git a/src/styles/abstracts/functions/_encode.scss b/src/styles/abstracts/functions/_encode.scss index 4350185..388d106 100644 --- a/src/styles/abstracts/functions/_encode.scss +++ b/src/styles/abstracts/functions/_encode.scss @@ -4,7 +4,7 @@  /// @param {String} $svg A complete svg (`<svg>...</svg>`).  /// @return The encoded svg, ready to use for background-image.  @function encode-svg($svg) { -  $svg-encoding: (("<", "%3C"), (">", "%3E"), ("#", "%23")); +  $svg-encoding: (('"', "'"), ("<", "%3C"), (">", "%3E"), ("#", "%23"));    @each $char, $encoded in $svg-encoding {      $svg: fun.str-replace($svg, $char, $encoded); diff --git a/src/styles/abstracts/placeholders/_links.scss b/src/styles/abstracts/placeholders/_links.scss new file mode 100644 index 0000000..a230e70 --- /dev/null +++ b/src/styles/abstracts/placeholders/_links.scss @@ -0,0 +1,102 @@ +@use "../../abstracts/functions" as fun; +@use "../../abstracts/variables" as var; + +%link { +  background: linear-gradient(to top, var(--color-primary) 50%, transparent 50%) +    0 0 / 100% 201% no-repeat; +  color: var(--color-primary); +  text-decoration-thickness: 0.15em; +  text-underline-offset: 20%; +  transition: +    all 0.3s linear 0s, +    text-decoration 0.18s ease-in-out 0s; + +  &:hover { +    color: var(--color-primary-light); +    text-decoration-thickness: 0.25em; +  } + +  &:focus { +    background-position: 0 100%; +    color: var(--color-fg-inverted); +  } + +  &:active { +    background-position: 0 0; +    color: var(--color-primary-dark); +    text-decoration-thickness: 18%; +  } +} + +%link-with-icon { +  &::after { +    display: inline-block; +    content: var(--is-lang-hidden, "\0000a0" var(--lang-icon, "")) +      var(--is-icon-hidden, "\0000a0" var(--link-icon, "")); +    font-size: var(--font-size-sm); +  } +} + +%link-with-lang { +  --lang-icon: "[" attr(hreflang) "]"; +} + +%light-download-link { +  // Prettier is removing spacing between attributes. +  // prettier-ignore +  --download-icon: 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) { +    // Prettier is removing spacing between attributes. +    // prettier-ignore +    --download-icon: 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>')}'); +  } +} + +%dark-download-link { +  // Prettier is removing spacing between attributes. +  // prettier-ignore +  --download-icon: 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) { +    // Prettier is removing spacing between attributes. +    // prettier-ignore +    --download-icon: 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>')}'); +  } +} + +%light-external-link { +  // Prettier is removing spacing between attributes. +  // prettier-ignore +  --external-icon: 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) { +    // Prettier is removing spacing between attributes. +    // prettier-ignore +    --external-icon: 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>')}'); +  } +} + +%dark-external-link { +  // Prettier is removing spacing between attributes. +  // prettier-ignore +  --external-icon: 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) { +    // Prettier is removing spacing between attributes. +    // prettier-ignore +    --external-icon: 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>')}'); +  } +} + +%download-link { +  --link-icon: var(--download-icon); +} + +%external-link { +  --link-icon: var(--external-icon); +} + +%external-download-link { +  --link-icon: var(--download-icon) "\0000a0" var(--external-icon); +} diff --git a/src/styles/base/_typography.scss b/src/styles/base/_typography.scss index c98533e..170f246 100644 --- a/src/styles/base/_typography.scss +++ b/src/styles/base/_typography.scss @@ -9,33 +9,6 @@ small {    font-size: var(--font-size-sm);  } -a { -  background: linear-gradient(to top, var(--color-primary) 50%, transparent 50%) -    0 0 / 100% 201% no-repeat; -  color: var(--color-primary); -  text-decoration-thickness: 0.15em; -  text-underline-offset: 20%; -  transition: -    all 0.3s linear 0s, -    text-decoration 0.18s ease-in-out 0s; - -  &:hover { -    color: var(--color-primary-light); -    text-decoration-thickness: 0.25em; -  } - -  &:focus { -    background-position: 0 100%; -    color: var(--color-fg-inverted); -  } - -  &:active { -    background-position: 0 0; -    color: var(--color-primary-dark); -    text-decoration-thickness: 18%; -  } -} -  button,  input,  optgroup, diff --git a/src/styles/pages/article.module.scss b/src/styles/pages/article.module.scss index 088718f..068826f 100644 --- a/src/styles/pages/article.module.scss +++ b/src/styles/pages/article.module.scss @@ -1,5 +1,6 @@  @use "../abstracts/functions" as fun;  @use "../abstracts/mixins" as mix; +@use "../abstracts/placeholders";  @use "partials/article-headings";  @use "partials/article-links";  @use "partials/article-lists"; @@ -28,6 +29,42 @@    }  } +:global([data-theme="light"]) { +  :local { +    .body { +      :global { +        a { +          &.download { +            @extend %light-download-link; +          } + +          &.external { +            @extend %light-external-link; +          } +        } +      } +    } +  } +} + +:global([data-theme="dark"]) { +  :local { +    .body { +      :global { +        a { +          &.download { +            @extend %dark-download-link; +          } + +          &.external { +            @extend %dark-external-link; +          } +        } +      } +    } +  } +} +  .widget {    @include mix.media("screen") {      @include mix.dimensions("md") { diff --git a/src/styles/pages/partials/_article-links.scss b/src/styles/pages/partials/_article-links.scss index e88b81e..1627220 100644 --- a/src/styles/pages/partials/_article-links.scss +++ b/src/styles/pages/partials/_article-links.scss @@ -1,204 +1,40 @@ -@use "../../abstracts/functions" as fun; -@use "../../abstracts/variables" as var; +@use "../../abstracts/placeholders";  @mixin styles {    a { -    &[hreflang] { -      &::after { -        display: inline-block; - -        /* Prettier is removing spacing between content parts. */ +    @extend %link; -        /* prettier-ignore */ -        content: "\0000a0[" attr(hreflang) "]"; -        font-size: var(--font-size-sm); -      } -    } -  } - -  /* stylelint-disable no-descending-specificity */ -  a.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], +    &.download, +    &.external { +      @extend %link-with-icon;      }      &[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>')); -      } -    } -  } - -  a.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>')); +      @extend %link-with-lang;      } -    &: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>')); +    &[hreflang]:not(.download, .external) { +      --is-icon-hidden: "";      } -    &[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="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>')); -      } +    &.download { +      @extend %download-link;      } -  } -  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.$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>')); +    &.external { +      @extend %external-link;      } -    &[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>')); +    &.download, +    &.external { +      &:not([hreflang]) { +        --is-lang-hidden: "";        }      } -  } - -  [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>')); -        } -      } +    &.external.download { +      @extend %external-download-link;      }    }  } -/* stylelint-enable no-descending-specificity */ | 
