@use 'sass:math'; // Taken from https://gist.github.com/johanlef/518a511b2b2f6b96c4f429b3af2f169a // Those functions overrides built-in bootstrap's computation color functions (that // generate flat variants and its darken/lighten alterations) to allow `var(--color)` CSS // variables to be used as primary colors and be instead computed on the fly with `calc()`s @function is-color($color) { @if (type-of($color) == color) { @return true; } @return false; } @function count-occurrences($string, $search) { $searchIndex: str-index($string, $search); $searchCount: 0; @while $searchIndex { $searchCount: $searchCount + 1; $string: str-slice($string, $searchIndex + 1); $searchIndex: str-index($string, $search); } @return $searchCount; } @function str-is-between($string, $first, $last) { $firstCount: count-occurrences($string, $first); $lastCount: count-occurrences($string, $last); @return $firstCount == $lastCount; } @function recursive-color($color, $index: 0) { $indices: ( 0: h, 1: s, 2: l, 3: a, ); // find end of part $end: str-index($color, ','); @while ( $end and not str-is-between(str-slice($color, 0, $end - 1), '(', ')') ) { $newEnd: str-index(str-slice($color, $end + 1), ','); @if (not $newEnd) { $newEnd: 0; } $end: 2 + $end + $newEnd; } @if ($end) { $part: str-slice($color, 0, $end - 1); $value: map-merge( ( map-get($indices, $index): $part, ), recursive-color(str-slice($color, $end + 1), $index + 1) ); @return $value; } @return (); } @function to-hsl($color) { $c: inspect($color); $h: 0; $s: 0; $l: 0; $a: 1; @if (is-color($color)) { // std color $h: hue($color); $s: saturation($color); $l: lightness($color); $a: alpha($color); @return (h: $h, s: $s, l: $l, a: $a); } @if (str-slice($c, 0, 3) == 'var') { // var(--color) $commaPos: str-index($c, ','); $end: -2; @if ($commaPos) { $end: $commaPos - 1; } $var: str-slice($c, 7, $end); $h: var(--#{$var}-h); $s: var(--#{$var}-s); $l: var(--#{$var}-l); $a: var(--#{$var}-a, 1); @return (h: $h, s: $s, l: $l, a: $a); } @if ($c == '0') { @return (h: $h, s: $s, l: $l, a: $a); } // color is (maybe complex) calculated color // e.g.: hsla(calc((var(--white-h) + var(--primary-h)) / 2), calc((var(--white-s) + var(--primary-s)) / 2), calc((var(--white-l) + var(--primary-l)) / 2), calc((var(--white-a, 1) + var(--primary-a, 1)) / 2)), hsla(calc((var(--white-h) + var(--primary-h)) / 2), calc((var(--white-s) + var(--primary-s)) / 2), calc((var(--white-l) + var(--primary-l)) / 2), calc((var(--white-a, 1) + var(--primary-a, 1)) / 2)) $startPos: str-index($c, '('); $c: str-slice($c, $startPos + 1, -2); // 3 or 4 comma-separated vomplex values @return recursive-color($c); // $hEnd: str-index($c, ','); // @if ($hEnd) { // $h: str-slice($c, 0, $hEnd - 1); // $c: str-slice($c, $hEnd + 1); // $sEnd: str-index($c, ','); // @if ($hEnd) { // $h: str-slice($c, 0, $hEnd - 1); // $c: str-slice($c, $hEnd + 1); // $sEnd: str-index($c, ','); // } // } // @return (h: $h, s: $s, l: $l, a: $a); } @function render-hsla($h, $s, $l, $a: 1) { // @return hsla($h, #{$s}, #{$l}, $a); // Error when using sass `hsla` with css variables, fallback to browser native `hsla` @return unquote('hsla(#{$h}, #{$s}, #{$l}, #{$a})'); } @function lighten($color, $amount) { @if (is-color($color)) { @return scale-color($color: $color, $lightness: $amount); } $c: to-hsl($color); $h: map-get($c, h); $s: map-get($c, s); $l: map-get($c, l); $a: map-get($c, a); @return render-hsla($h, $s, calc(#{$l} + #{$amount}), $a); } @function darken($color, $amount) { @return lighten($color, $amount * -1); } @function rgba($red, $green, $blue: false, $alpha: false) { $color: $red; @if (not $blue and not $alpha) { $alpha: $green; $color: $red; } $c: to-hsl($color); $h: map-get($c, h); $s: map-get($c, s); $l: map-get($c, l); @return render-hsla($h, $s, $l, $alpha); } @function rgb($red, $green, $blue) { @return rgba($red, $green, $blue, 1); } @function mix($color-1, $color-2, $weight: 50%) { $c1: to-hsl($color-1); $c2: to-hsl($color-2); $h1: map-get($c1, h); $s1: map-get($c1, s); $l1: map-get($c1, l); $a1: map-get($c1, a); $h2: map-get($c2, h); $s2: map-get($c2, s); $l2: map-get($c2, l); $a2: map-get($c2, a); $h: calc((#{$h1} + #{$h2}) / 2); $s: calc((#{$s1} + #{$s2}) / 2); $l: calc((#{$l1} + #{$l2}) / 2); $a: calc((#{$a1} + #{$a2}) / 2); @return render-hsla($h, $s, $l, $a); } @function fade-in($color, $amount) { $c: to-hsl($color); $h: map-get($c, h); $s: map-get($c, s); $l: map-get($c, l); $a: map-get($c, a); @if (not $a) { $a: 1; } @return render-hsla($h, $s, $l, $a + $amount); } @function color-yiq($color, $dark: $yiq-text-dark, $light: $yiq-text-light) { @if (is-color($color)) { $r: red($color); $g: green($color); $b: blue($color); $yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000; @if ($yiq >= $yiq-contrasted-threshold) { @return $dark; } @else { @return $light; } } @else { $c: to-hsl($color); $l: map-get($c, l); $th: calc($yiq-contrasted-threshold / 2.56); // convert hex to dec $lightness: calc(-100 * calc(#{$l} - calc(#{$th} * 1%))); // ignoring hue and saturation, just a light or dark gray @return render-hsla(0, 0%, $lightness, 1); } } // Taken from https://gist.github.com/johanlef/518a511b2b2f6b96c4f429b3af2f169a?permalink_comment_id=4053335#gistcomment-4053335 @function theme-color-level($color-name: 'primary', $level: 0) { $color: theme-color($color-name); @if ($level == 0) { @return $color; } $amount: math.div($theme-color-interval * abs($level), 100%); $c: to-hsl($color); $h: map-get($c, h); $s: map-get($c, s); $l: map-get($c, l); $a: map-get($c, a); @if ($level > 0) { // Darken -X%: L = L * (1 - X) // $rl: calc((#{$l} * #{1 - $amount})); $rl: calc((#{$l} * #{$amount})); @return render-hsla($h, $s, $rl, $a); } @if ($level < 0) { // Ligthen +X%: L = L + X * (100 - L) $rl: calc(#{$l} + #{$amount} * (100% - #{$l})); @return render-hsla($h, $s, $rl, $a); } }