// ---------------------------------------- /* Forces an element to get rendered on its own layer, increasing the performance when animated. Use only transform and opacity in animations! */ @mixin FastAnimation { will-change: transform, opacity, filter; // transform: translateZ(0); backface-visibility: hidden; -webkit-backface-visibility: hidden; } // Helper which includes the translateZ webkit fix, use together with Fast animation // $hardwareAcc: translateZ(0); $hardwareAcc: null; // ---------------------------------------- /** Increased click area for this element, helpful on mobile */ @mixin IncreasedClickArea($size) { // &::after { // content: ""; // position: absolute; // top: #{D(-$size)}; // bottom: #{D(-$size)}; // left: #{D(-$size)}; // right: #{D(-$size)}; // // background: rgba(255, 0, 0, 0.3); // } } button, .increasedClickArea { position: relative; @include IncreasedClickArea(15px); } // ---------------------------------------- /* Duplicates an animation and adds two classes .Even and .Odd which uses the animation. This can be used to replay the animation by toggling between the classes, because it is not possible to restart a css animation */ @mixin MakeAnimationWrappedEvenOdd($duration, $classPrefix: "anim", $childSelector: "") { $animName: autogen_anim_#{unique-id()}; @at-root { @keyframes #{$animName}_even { @content; } @keyframes #{$animName}_odd { @content; } } &.#{$classPrefix}Even #{$childSelector} { animation: #{$animName}_even $duration; } &.#{$classPrefix}Odd #{$childSelector} { animation: #{$animName}_odd $duration; } } // ---------------------------------------- /* Allows to use and define an animation without specifying its name */ @mixin InlineAnimation($duration) { $animName: autogen_anim_#{unique-id()}; @at-root { @keyframes #{$animName} { @content; } } animation: $animName $duration !important; } // ---------------------------------------- /* Animation prefab for a double bounce pop-in animation, useful for dialogs */ @mixin DoubleBounceAnim($duration: 0.5s ease-in-out, $amount: 0.2, $initialOpacity: 0) { @include InlineAnimation($duration) { 0% { opacity: $initialOpacity; transform: scale(0) $hardwareAcc; } 25% { opacity: 0.5; transform: scale(1 + $amount) $hardwareAcc; } 50% { opacity: 1; transform: scale(1 - $amount * 0.5) $hardwareAcc; } 75% { transform: scale(1 + $amount * 0.25) $hardwareAcc; } 100% { transform: scale(1) $hardwareAcc; } } opacity: 1; } // ---------------------------------------- /* Automatically transforms the game state if a hardware keyboard is open */ @mixin TransformToMatchKeyboard { transition: transform 0.2s ease-in-out; @include AndroidHwKeyboardOpen { @include VerticalStyle { transform: translateY(#{D(-125px)}) $hardwareAcc; } @include HorizontalStyle { transform: translateY(#{D(-100px)}) $hardwareAcc; } } } // ---------------------------------------- /* Define a style which is only applied when the viewport is at least X pixels wide */ @mixin StyleAtWidth($minW) { @media (min-width: #{$minW}) { @content; } } // ---------------------------------------- /* Define a style which is only applied when the viewport is at least X pixels height */ @mixin StyleAtHeight($minH) { @media (min-height: #{$minH}) { @content; } } // ---------------------------------------- /* Define a style which is only applied when the viewport has at least the given dimensions */ @mixin StyleAtDims($minW, $minH) { @media (min-height: #{$minH}) and (min-width: #{$minW}) { @content; } } // ---------------------------------------- /* Define a style which is only applied when the viewport has at maximum the given dimensions */ @mixin StyleBelowDims($maxW, $maxH) { @media (max-height: #{$maxH}) and (max-width: #{$maxW}) { @content; } } // ---------------------------------------- /* Define a style which is only applied when the viewport has at maximum the given height */ @mixin StyleBelowHeight($maxH) { @media (max-height: #{$maxH}) { @content; } } // ---------------------------------------- /* Define a style which is only applied when the viewport has at maximum the given width */ @mixin StyleBelowWidth($maxW) { @media (max-width: #{$maxW}) { @content; } } // ---------------------------------------- // Dynamic graphics quality styles @mixin BoxShadow3D($bgColor, $size: 3px, $pressEffect: true) { background-color: $bgColor; $borderSize: 1.5px; $borderColor: rgb(18, 20, 24); // box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1), // 0 D($size) 0 D($borderSize) $borderColor; // box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 D($borderSize) $borderColor, // D(-$size * 1.5) D($size * 2) 0 D($borderSize) rgba(0, 0, 0, 0.1); // transition: box-shadow 0.1s ease-in-out; // @if $pressEffect { // &.pressed { // transform: none !important; // $pSize: max(0, $size - 1.5px); // transition: none !important; // box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($pSize) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1), // 0 D($pSize) 0 D($borderSize) $borderColor; // top: D($size - $pSize); // } // } } @mixin BorderRadius($v1: 2px, $v2: "", $v3: "", $v4: "") { @include S(border-radius, $v1, $v2, $v3, $v4); } @mixin BoxShadow($x, $y, $blur, $offset, $color) { box-shadow: D($x) D($y) D($blur) D($offset) $color; } @mixin DropShadow($yOffset: 2px, $blur: 2px, $amount: 0.2) { @include BoxShadow(0, $yOffset, $blur, 0, rgba(#000, $amount)); } @mixin TextShadow($yOffset: 2px, $blur: 1px, $amount: 0.6) { text-shadow: 0 D($yOffset) D($blur) rgba(#000, $amount); } @mixin Button3D($bgColor, $pressEffect: true) { @include BoxShadow3D($bgColor, 2px, $pressEffect); } @mixin ButtonDisabled3D($bgColor) { @include BoxShadow3D($bgColor, 0.5px, false); } @mixin BoxShadowInset($bgColor, $size: 3px) { background-color: $bgColor; $borderSize: 1px; $borderColor: rgb(15, 19, 24); box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 rgba(#fff, 0.07); border-top: D($size) solid rgba(#000, 0.1); //, 0 D($size) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1), // 0 D($size + $borderSize) 0 0 $borderColor; } @mixin TextShadow3D($color: rgb(222, 234, 238), $borderColor: #000) { color: $color; } // ---------------------------------------- /* String replacement */ @function str-replace($string, $search, $replace: "") { $index: str-index($string, $search); @if $index { @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); } @return $string; } @mixin BounceInFromSide($mul, $duration: 0.18s ease-in-out) { @include InlineAnimation($duration) { 0% { transform: translateY(#{D(-100px * $mul)}) scale(0.9); opacity: 0; } 100% { opacity: 1; transform: none; } } opacity: 1; transform: none; } @mixin BreakText { word-wrap: break-word; word-break: break-all; overflow-wrap: break-all; } @mixin SupportsAndroidNotchQuery { @supports (color: constant(--notch-inset-left)) { @content; } } @mixin SupportsiOsNotchQuery { @supports (color: env(safe-area-inset-left, 0px)) { @content; } } @mixin DarkThemeOverride { @at-root html[data-theme="dark"] &, &[data-theme="dark"] { @content; } } @mixin DarkThemeInvert { @include DarkThemeOverride { filter: invert(1); } }