diff --git a/package-lock.json b/package-lock.json index c65e51f..11dfdd5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2260,12 +2260,27 @@ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, + "@types/jquery": { + "version": "3.3.33", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.33.tgz", + "integrity": "sha512-U6IdXYGkfUI42SR79vB2Spj+h1Ly3J3UZjpd8mi943lh126TK7CB+HZOxGh2nM3IySor7wqVQdemD/xtydsBKA==", + "dev": true, + "requires": { + "@types/sizzle": "*" + } + }, "@types/q": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", "dev": true }, + "@types/sizzle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz", + "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==", + "dev": true + }, "@types/unist": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", @@ -3465,6 +3480,12 @@ "randomfill": "^1.0.3" } }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, "css-color-names": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", @@ -4545,6 +4566,17 @@ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4685,6 +4717,12 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -5694,6 +5732,15 @@ "minimist": "^1.2.0" } }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -6551,6 +6598,12 @@ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", "dev": true }, + "p-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-debounce/-/p-debounce-1.0.0.tgz", + "integrity": "sha1-y38svu/YegnrqGHhErZ1J+Yh4v0=", + "dev": true + }, "p-limit": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", @@ -8710,6 +8763,22 @@ "readable-stream": "^3.1.1" } }, + "temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", + "dev": true + }, + "tempy": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.2.1.tgz", + "integrity": "sha512-LB83o9bfZGrntdqPuRdanIVCPReam9SOZKW0fOy5I9X3A854GGWi0tjCqoXEk84XIEYBc/x9Hq3EFop/H5wJaw==", + "dev": true, + "requires": { + "temp-dir": "^1.0.0", + "unique-string": "^1.0.0" + } + }, "term-size": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", @@ -8885,6 +8954,29 @@ "prelude-ls": "~1.1.2" } }, + "typescript-language-server": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/typescript-language-server/-/typescript-language-server-0.4.0.tgz", + "integrity": "sha512-K8jNOmDFn+QfrCh8ujby2pGDs5rpjYZQn+zvQnf42rxG4IHbfw5CHoMvbGkWPK/J5Gw8/l5K3i03kVZC2IBElg==", + "dev": true, + "requires": { + "command-exists": "1.2.6", + "commander": "^2.11.0", + "fs-extra": "^7.0.0", + "p-debounce": "^1.0.0", + "tempy": "^0.2.1", + "vscode-languageserver": "^5.3.0-next", + "vscode-uri": "^1.0.5" + }, + "dependencies": { + "command-exists": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.6.tgz", + "integrity": "sha512-Qst/zUUNmS/z3WziPxyqjrcz09pm+2Knbs5mAZL4VAE0sSrNY1/w8+/YxeHcoBTsO6iojA6BW7eFf27Eg2MRuw==", + "dev": true + } + } + }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -9046,6 +9138,15 @@ "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", "dev": true }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, "unist-builder": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-1.0.4.tgz", @@ -9149,6 +9250,12 @@ "unist-util-is": "^3.0.0" } }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -9359,6 +9466,50 @@ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", "dev": true }, + "vscode-jsonrpc": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz", + "integrity": "sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A==", + "dev": true + }, + "vscode-languageserver": { + "version": "5.3.0-next.10", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-5.3.0-next.10.tgz", + "integrity": "sha512-QL7Fe1FT6PdLtVzwJeZ78pTic4eZbzLRy7yAQgPb9xalqqgZESR0+yDZPwJrM3E7PzOmwHBceYcJR54eQZ7Kng==", + "dev": true, + "requires": { + "vscode-languageserver-protocol": "^3.15.0-next.8", + "vscode-textbuffer": "^1.0.0" + } + }, + "vscode-languageserver-protocol": { + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.3.tgz", + "integrity": "sha512-zrMuwHOAQRhjDSnflWdJG+O2ztMWss8GqUUB8dXLR/FPenwkiBNkMIJJYfSN6sgskvsF0rHAoBowNQfbyZnnvw==", + "dev": true, + "requires": { + "vscode-jsonrpc": "^5.0.1", + "vscode-languageserver-types": "3.15.1" + } + }, + "vscode-languageserver-types": { + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz", + "integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ==", + "dev": true + }, + "vscode-textbuffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vscode-textbuffer/-/vscode-textbuffer-1.0.0.tgz", + "integrity": "sha512-zPaHo4urgpwsm+PrJWfNakolRpryNja18SUip/qIIsfhuEqEIPEXMxHOlFPjvDC4JgTaimkncNW7UMXRJTY6ow==", + "dev": true + }, + "vscode-uri": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.8.tgz", + "integrity": "sha512-obtSWTlbJ+a+TFRYGaUumtVwb+InIUVI0Lu0VBUAPmj2cU5JutEXg3xUE0c2J5Tcy7h2DEKVJBFi+Y9ZSFzzPQ==", + "dev": true + }, "w3c-hr-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", diff --git a/package.json b/package.json index ed7e983..5ce1291 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,12 @@ "private": true, "devDependencies": { "@babel/preset-env": "^7.8.4", + "@types/jquery": "^3.3.33", "jstransformer-markdown-it": "^2.1.0", "parcel": "^2.0.0-alpha.3.2", "pug": "^2.0.4", - "sass": "^1.25.0" + "sass": "^1.25.0", + "typescript-language-server": "^0.4.0" }, "dependencies": { "@fortawesome/fontawesome-free": "^5.12.1", diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 4f01543..0000000 --- a/src/index.js +++ /dev/null @@ -1,109 +0,0 @@ -import $ from "jquery"; - -// 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; - } -} - -$(document).ready(() => { - let typer = new Typer($(".head-line .typed").get(0), 500, 3000); - typer.type(); -}); diff --git a/src/index.pug b/src/index.pug index 896a2c6..909c660 100644 --- a/src/index.pug +++ b/src/index.pug @@ -76,4 +76,4 @@ block content [GitHub](https://github.com/tlater) pages. block footer - script(type="text/javascript" src="./index.js" defer) + script(type="text/javascript" src="./index.ts" defer) diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..c35abda --- /dev/null +++ b/src/index.ts @@ -0,0 +1,119 @@ +import $ from "jquery"; + +// Helpers + +/** + * "Types" out a DOM element, emulating the way a human might. + */ +class Typer { + private element: JQuery; + private text: string; + private cursor: boolean; + private typed: number; + private min: number; + private max: number; + private blink_tick: number; + private blink_timeout: number; + private end?: number; + + /** + * 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: HTMLElement, blink: number, blink_timeout: number) { + // 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; + } +} + +$(document).ready(() => { + let typer = new Typer($(".head-line .typed").get(0), 500, 3000); + typer.type(); +}); diff --git a/src/lib/js/main.js b/src/lib/js/main.ts similarity index 100% rename from src/lib/js/main.js rename to src/lib/js/main.ts diff --git a/src/lib/pug/base.pug b/src/lib/pug/base.pug index ab07f17..b3ec049 100644 --- a/src/lib/pug/base.pug +++ b/src/lib/pug/base.pug @@ -18,5 +18,5 @@ html.no-js(lang="en") script(type="text/javascript", src="~/node_modules/jquery/dist/jquery.min.js" defer) script(type="text/javascript", src="~/node_modules/bootstrap/dist/js/bootstrap.min.js" defer) - script(type="text/javascript", src="~/src/lib/js/main.js" defer) + script(type="text/javascript", src="~/src/lib/js/main.ts" defer) block footer