index/*: Add main title typing animation
This commit is contained in:
parent
ce6309e7a5
commit
f116cc07f2
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,2 +1,6 @@
|
|||
@import "../lib/scss/main";
|
||||
@import "~bootstrap/scss/bootstrap";
|
||||
|
||||
.head-line .typed {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
|
Reference in a new issue