@use "sass:map";

@use "../01-functions/functions" as *;

////////////////////////////////////////////////////////////////////////////////
// *
// * Mixins: Typography
// *
////////////////////////////////////////////////////////////////////////////////

// * Overview
// =============================================================================

// ** font-face
// ** font-size
// ** font-awesome
// ** hide-text
// ** hide-icontext
// ** text-nobreak
// ** ellipsis
// ** word-break
// ** m-p-reset

// * Mixins
// =============================================================================

// ** enable font-smoothing can be helpful on older screens,
//    for fonts that do not have subpixel rendering
//    or it could not? Who the hell knows…

@mixin font-smoothing($value: off) {
  @if $value == on {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
  }
  @else {
    -webkit-font-smoothing: subpixel-antialiased;
    -moz-osx-font-smoothing: auto;
  }
}

// ** use font-face to generate all the different url's for the various font files
//    By default will only load woff and woff2 files, but you can use legacy formats as well
//     using the 'legacy' variable
//    Settings:
//       font-family,
//       font-style: normal,
//       font-weight: normal,
//       font-display: swap, (best for loading and display of fonts)
//       file-path, (location of font files, relative to css-folder, or can be absolute using '://')
//       unicode-range: null,
//       legacy: false, (if set to true, it will try to load older font file formats: eot and ttf)
// -- USAGE: @include font-face(($font-family: "Montserat", $font-style: "normal"));

@mixin font-face($settings) {
  // some defaults, used in case no $settings were given
  // or when either of the settings is omitted
  $font-family-default: "";
  $font-style-default: normal;
  $font-weight-default: normal;
  $font-display-default: swap;
  $file-path-default: "";
  $unicode-range-default: null;
  $legacy-default: false;

  // initiate the actual variables that will be used
  $font-family: null;
  $font-style: null;
  $font-weight: null;
  $font-display: null;
  $file-path: null;
  $unicode-range: null;
  $legacy: null;

  // map the variables to the settings if actual settings are passed
  @if ($settings != null) {
    $font-family: map.get($settings, font-family);
    $font-style: map.get($settings, font-style);
    $font-weight: map.get($settings, font-weight);
    $font-display: map.get($settings, font-display);
    $file-path: map.get($settings, file-path);
    $unicode-range: map.get($settings, unicode-range);
    $legacy: map.get($settings, legacy);
  }

  // if any are not filled in, fall back to defaults
  @if ($font-family == null) {
    $font-family: $font-family-default;
  }
  @if ($font-style == null) {
    $font-style: $font-style-default;
  }
  @if ($font-weight == null) {
    $font-weight: $font-weight-default;
  }
  @if ($font-display == null) {
    $font-display: $font-display-default;
  }
  @if ($file-path == null) {
    $file-path: $file-path-default;
  }
  @if ($unicode-range == null) {
    $unicode-range: $unicode-range-default;
  }
  @if ($legacy == null) {
    $legacy: $legacy-default;
  }

  @font-face {
    font-family: $font-family;
    font-style: $font-style;
    font-weight: $font-weight;
    src: font-source-declaration($font-family, $file-path, $legacy);
    font-display: $font-display;
    @if ($unicode-range != null) {
      unicode-range: $unicode-range;
    }
    @content;
  }
}

// *
// * Font-awesome mixin: add a font-awesome icon before or after an element
//
// * NOTE: before is default, margin is default 0.
//
// * Settings via an object, containing:
// * $element: pseudo-element, default = before,
// * $position,
// * $left,
// * $top,
// * $type:"regular",
// * $icon: e.g. a fontawesome variable,
// * $color,
// * $color-secondary: for duotone icons, this is the second the icon, defaults to same as primary,
// * $size,
// * $align:middle,
// * $margin...
//
// * USAGE:
// * $hamburgerIcon: (icon: $fa-var-hamburger, color: hsl(var(--clr-white)), size: 21px);
// * @include font-awesome($hamburgerIcon);
// * $duotoneIcon: (icon: $fa-var-hamburger, color: hsl(var(--clr-white)), color-secondary: hsl(var(--clr-white)), size: 21px)
// * @include font-awesome($hamburgerIcon);

@mixin font-awesome($settings) {
  // set variables
  $type: map.get($settings, type);
  $icon: map.get($settings, icon);
  $element: map.get($settings, element);
  $position: map.get($settings, position);
  $left: map.get($settings, left);
  $right: map.get($settings, right);
  $top: map.get($settings, top);
  $bottom: map.get($settings, bottom);
  $bottom: map.get($settings, bottom);


  // some defaults, used in case no $settings were given
  // or when either of the settings is omitted
  $swap-opacity-default: false;
  $opacity-default: 1;
  $opacity-secondary-default: .4;
  $color-default: inherit;

  // set up the actual variables that will be used
  $swap-opacity: null;
  $opacity: null;
  $opacity-secondary: null;
  $color: null;
  $color-secondary: null;

  // map the variables to the settings if actual settings are passed
  @if ($settings != null) {
    $swap-opacity: map.get($settings, swap-opacity);
    $opacity: map.get($settings, opacity);
    $opacity-secondary: map.get($settings, opacity-secondary);
    $color: map.get($settings, color);
    $color-secondary: map.get($settings, color-secondary);
  }

  // if any are not filled in, fall back to defaults
  @if ($swap-opacity == null) {
    $swap-opacity: $swap-opacity-default;
  }
  @if ($opacity == null) {
    $opacity: $opacity-default;
  }
  @if ($opacity-secondary == null) {
    $opacity-secondary: $opacity-secondary-default;
  }
  @if ($color == null) {
    $color: $color-default;
  }
  // secondary color falls back to primary if none set
  @if ($color-secondary == null) {
    $color-secondary: $color;
  }

  // can only use this mixin if we are using font for custom icons
  // as well as no custom icons set
  @if ($custom-icons == false) {
    // if using duotone icons, we need to stack 2 pseudo-elements
    @if ($type == "duotone") {
      &::before,
      &::after {
        display: inline-block;
      }

      &::before {
        @include font-awesome-pseudo($settings);
        opacity: $opacity;

        @if ($position != null) {
          position: $position;
        } @else {
          position: relative;
          line-height: inherit;
          vertical-align: bottom;
        }
        @if ($left != null) {
          left: $left;
        }
        @else if($left == null and $right != null) {
          right: $right;
        }
        @if ($top != null) {
          top: $top;
        }
        @else if($top == null and $bottom != null) {
          bottom: $bottom;
        }
      }

      &::after {
        // all second icons in the duotone stack use the same variant name: '10' + the original icon unicode
        // so we can manipulate that string in Sass to obtain that icon
        // eg: \f805 becomes \10f805
        $icon-secondary: str-insert($icon, "10", 2);

        // copy the icon settings but replace the color + the icon
        // by basically merging the original map with a new one only containing the color
        $settings-secondary: map-merge($settings, (color: $color-secondary, icon: $icon-secondary));

        @include font-awesome-pseudo($settings-secondary);
        opacity: $opacity-secondary;

        @if ($position != null) {
          position: $position;
        } @else {
          position: absolute;
          left: 0;
          line-height: inherit;
          vertical-align: bottom;
        }
        @if ($left != null) {
          left: $left;
        }
        @else if($left == null and $right != null) {
          right: $right;
        }
        @if ($top != null) {
          top: $top;
        }
        @else if($top == null and $bottom != null) {
          bottom: $bottom;
        }
      }

      @if ($swap-opacity) {
        &::before {
          opacity: $opacity-secondary;
        }

        &::after {
          opacity: $opacity;
        }
      }

      // if no duotone needed, we can add fontawesome styling to a single pseudo-element only
    } @else {
      @if ($element == "after" or $element == ":after" or $element == "::after") {
        &::after {
          @if ($position != null) {
            position: $position;
          }
          @if ($left != null) {
            left: $left;
          }
          @else if($left == null and $right != null) {
            right: $right;
          }
          @if ($top != null) {
            top: $top;
          }
          @else if($top == null and $bottom != null) {
            bottom: $bottom;
          }
          @include font-awesome-pseudo($settings);
        }
      } @else {
        &::before {
          @if ($position != null) {
            position: $position;
          }
          @if ($left != null) {
            left: $left;
          }
          @else if($left == null and $right != null) {
            right: $right;
          }
          @if ($top != null) {
            top: $top;
          }
          @else if($top == null and $bottom != null) {
            bottom: $bottom;
          }
          @include font-awesome-pseudo($settings);
        }
      }
    }
  }
}

@mixin font-awesome-pseudo($settings) {
  // -- set variables
  $type: map.get($settings, type);
  $icon: map.get($settings, icon);
  $color: map.get($settings, color);
  $size: map.get($settings, size);
  $align: map.get($settings, align);
  $margin: map.get($settings, margin);

  // -- fontawesome defaults:
  //
  // $fa-font-path:         "../webfonts" !default;
  // $fa-font-size-base:    16px !default;
  // $fa-font-display:      auto !default;
  // $fa-css-prefix:        fa !default;
  // $fa-version:           "5.12.0" !default;
  // $fa-border-color:      #eee !default;
  // $fa-inverse:           #fff !default;
  // $fa-li-width:          2em !default;
  // $fa-fw-width:          math.div(20em / 16);
  // $fa-primary-opacity:   1 !default;
  // $fa-secondary-opacity: .4 !default;

  content: unquote("\"#{ $icon }\"");
  display: inline-block;
  $newMargin: if(length($margin) == 0, 0px, $margin);
  margin: $newMargin;

  @include font-awesome-core;

  @if ($align == null) {
    vertical-align: middle;
  } @else {
    vertical-align: $align;
  }

  // -- set default size
  @if ($size == 16px or $size == 16 or $size == null) {
    $size: $fa-font-size-base;
  }

  font-size: rem($size);

  // -- set font style/weight

  @if ($fontawesome-version == "free") {
    @if ($type == "brand") {
      font-family: "Font Awesome 5 Brands", sans-serif;
      font-weight: normal;
    } @else if ($type == "regular") {
      font-family: "Font Awesome 5 Free", sans-serif;
      font-weight: 400;
    } @else {
      // solid (so anything marked as "light" will fallback to this)
      font-family: "Font Awesome 5 Free", sans-serif;
      font-weight: 900;
    }
  } @else {
    @if ($type == "duotone") {
      font-family: "Font Awesome 5 Duotone", sans-serif;
      font-weight: 900;
    } @else if ($type == "brand") {
      font-family: "Font Awesome 5 Brands", sans-serif;
      font-weight: normal;
    } @else if ($type == "regular") {
      font-family: "Font Awesome 5 Pro", sans-serif;
      font-weight: 400;
    } @else if ($type == "light") {
      font-family: "Font Awesome 5 Pro", sans-serif;
      font-weight: 300;
    } @else {
      // solid
      font-family: "Font Awesome 5 Pro", sans-serif;
      font-weight: 900;
    }
  }

  color: $color;
}

@mixin font-awesome-core {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-style: normal;
  font-variant: normal;
  font-weight: normal;
  line-height: 1;
}

// ** Hide an element's content
@mixin hide-text {
  overflow: hidden;
  text-indent: 110%;
  white-space: nowrap;
}

// ** hide text of an element with a font-awesome icon without hiding icon itself
@mixin hide-icontext() {
  overflow: hidden;
  text-indent: 110%;
  white-space: nowrap;

  &::before {
    text-indent: -110%; // compensate for text-indent
  }
}

// ** Don't break up text
@mixin text-nobreak {
  white-space: nowrap;
  word-break: keep-all;
}

// ** end text if no space
@mixin ellipsis($width: 100%) {
  display: inline-block;
  overflow: hidden;
  max-width: $width;
  text-overflow: ellipsis;
  white-space: nowrap;
  word-wrap: normal;
}

// ** Break long strings (e.g. email-addresses).
@mixin word-break($hyphen:false) {
  /* These are technically the same, but use both */
  overflow-wrap: break-word;
  word-wrap: break-word;

  /* This is the dangerous one in WebKit, as it breaks things wherever */
  word-break: break-all;
  /* Instead use this non-standard one: */
  word-break: break-word;

  /* Adds a hyphen where the word breaks, if supported (No Blink) */
  @if ($hyphen) {
    -moz-hyphens: auto;
    -webkit-hyphens: auto;
    hyphens: auto;
  }
}

// ** remove all padding and margin on element
@mixin m-p-reset {
  margin: 0;
  padding: 0;
}
