From f116cc07f224703c50ff460f4b8b52800e93407c Mon Sep 17 00:00:00 2001 From: Tristan Maat Date: Sun, 8 Apr 2018 20:49:17 +0000 Subject: [PATCH] index/*: Add main title typing animation --- src/index/index.js | 113 +++++++++++++++++++++++++++++++++++++++++++ src/index/index.pug | 10 +++- src/index/index.scss | 4 ++ 3 files changed, 126 insertions(+), 1 deletion(-) diff --git a/src/index/index.js b/src/index/index.js index 9dd5dd1..112bc14 100644 --- a/src/index/index.js +++ b/src/index/index.js @@ -1,2 +1,115 @@ import "bootstrap"; import "./index.scss"; + +// Helpers + +/** + * "Types" out a DOM element, emulating the way a human might. + */ +class Typer { + /** + * Create the typer. + * @param {HTMLElement} element - The element to type. + * @param {number} blink - The time between cursor blinks. + * @param {number} blink_timeout - How long the cursor should keep + * blinking for after the text + * finishes typing. + */ + constructor(element, blink, blink_timeout) { + // Retrieve the current content and wipe it. We also make the + // element visible if it was hidden. + this._element = $(element); + this._text = this._element.html(); + this._element.html(""); + this._element.css("visibility", "visible"); + + + this._cursor = false; + this._typed = 0; + + this._min = 20; + this._max = 70; + this._blink_tick = blink; + this._blink_timeout = blink_timeout; + + this._end = null; + } + + /** + * Start typing. + */ + type() { + this._type(); + this._blink(); + } + + /** + * Draw the current text line, i.e., anything that has been typed + * so far, and a cursor if it is currently supposed to be on. + * @private + */ + _draw() { + let text = this._text.slice(0, this._typed); + + if (this._cursor) + text += "\u2588"; + + window.requestAnimationFrame(() => this._element.html(text)); + } + + /** + * Type the next character, and prepare to draw the next one. If + * no new characters are to be drawn, set the end timestamp. + * @private + */ + _type() { + this._typed += 1; + this._draw(); + + if (this._typed != this._text.length) + setTimeout(this._type.bind(this), this._type_tick()); + else + this._end = Date.now(); + } + + /** + * Make the cursor change blink status, and prepare for the next + * blink. + * @private + */ + _blink() { + this._cursor = !this._cursor; + this._draw(); + + // As long as we are typing, keep blinking + if (this._typed != this._text.length) + setTimeout(this._blink.bind(this), this._blink_tick); + + // Once typing ends, keep going for a little bit + else if (Date.now() - this._end < this._blink_timeout) + setTimeout(this._blink.bind(this), this._blink_tick); + + // Make sure we get rid of the cursor in the end + else { + this._cursor = true; + setTimeout(this._blink.bind(this), this._blink_tick); + } + } + + /** + * Calculate a "human" time for the next character to type. + * @private + */ + _type_tick() { + return Math.round(Math.random() * this._max) + this._min; + } +} + +// Application code +function main() { + // Type the head line + let typer = new Typer($(".head-line .typed").get(0), 500, 3000); + typer.type(); +} + +$(document).ready(main); diff --git a/src/index/index.pug b/src/index/index.pug index 2975f60..7553014 100644 --- a/src/index/index.pug +++ b/src/index/index.pug @@ -1,7 +1,15 @@ extends ../lib/pug/base block content - h1.head-line Welcome to tlater.net! + noscript + style. + .head-line .typed { + visibility: visible; + } + + h1.head-line + | $  + span.typed Welcome to tlater.net! h5.tag-line: em Your #1 site for useless time sinks hr diff --git a/src/index/index.scss b/src/index/index.scss index 5572cae..03b07ff 100644 --- a/src/index/index.scss +++ b/src/index/index.scss @@ -1,2 +1,6 @@ @import "../lib/scss/main"; @import "~bootstrap/scss/bootstrap"; + +.head-line .typed { + visibility: hidden; +}