/* =========================================================== * * Type Writer Effect * /* =========================================================== */ /// Replace `$search` with `$replace` in `$string` /// @author Kitty Giraudel /// @param {String} $string - Initial string /// @param {String} $search - Substring to replace /// @param {String} $replace ('') - New value /// @return {String} - Updated string @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; } @function sanitize-int($int) { @return str-replace(#{$int}, '.', '_') } /* ================== * Graphical Container */ @mixin typing-wrapper($prompt-width, $command-width) { .typing-wrapper-#{$prompt-width}-#{$command-width} { // wrapper shape + center position margin: auto auto; width: $prompt-width + $command-width + 1ch; // +1 for cursor width // flexbox alignments display: flex; flex-direction: column; justify-content: center; align-content: center; align-items: start; text-align: start; // XXX: TODO: for some reason this causes an error?? /* border: 0.5ch solid base.$color-txt; */ border: 0.5ch solid #ffc0cb; padding: 20px; } } /* ================== * TTY Prompt */ @mixin typing-prompt($prompt-width, $command-width, $typing-duration, $blink-period) { // XXX: TODO: relearn SCSS cause the thing below will break whenever an input is given as a float // XXX: TODO: (period character interpretted as sub-attribute) .typing-prompt-#{$prompt-width}-#{$command-width}-#{$typing-duration}-#{sanitize-int($blink-period)} { width: $prompt-width + $command-width; // ignore cursor (right border) border-right: 1ch solid; // cursor // hide what the animation hasn't shown yet white-space: nowrap; overflow: hidden; // typing animation then start cursor blink animation: typing($prompt-width) $typing-duration steps($command-width), cursor-blink $blink-period steps(1, start) $typing-duration infinite alternate; } } @mixin typing($prompt-width) { @keyframes typing-#{$prompt-width} { from { width: $prompt-width // ignore effect for prompt } } } @keyframes cursor-blink { 50% { border-color: transparent } } /* ===================== * TTY Output */ @mixin typing-result($typing-duration, $reveal-delay) { // XXX: TODO: relearn SCSS cause the thing below will break whenever an input is given as a float // XXX: TODO: (period character interpretted as sub-attribute) .typing-result-#{$typing-duration}-#{sanitize-int($reveal-delay)} { visibility: hidden; white-space: pre-wrap; // preserve linebreaks // show result once typing ends + delay animation: unhide-result 1s ($typing-duration + $reveal-delay) forwards; } } @keyframes unhide-result { to { visibility: visible } } /* ========================= * Intended Public Interface */ @mixin tty($prompt-width, $command-width, $typing-duration: 3s, $blink-period: 0.6s, $reveal-delay: 0.8s) { @include typing-wrapper($prompt-width, $command-width); @include typing-prompt($prompt-width, $command-width, $typing-duration, $blink-period); @include typing-result($typing-duration, $reveal-delay); }