summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoris Roovers <joris.roovers@gmail.com>2023-04-14 10:56:52 +0200
committerGitHub <noreply@github.com>2023-04-14 10:56:52 +0200
commite0bd48dc9a4ab3bbf8eee7f3a5c39d2370c55b51 (patch)
tree9fe5d50283b2f9d13d80897a74c2d8c6377ad74e
parent8a38a58735bcbf05632d4cb21a2c56e854012d97 (diff)
Docs: Termynal demo (#488)
Replaces ASCII Cinema demo with Termynal, allowing mocking the demo rather than use a CLI recording which is error prone, slow and difficult to edit and maintain.
-rw-r--r--docs/extra.css18
-rw-r--r--docs/extra.js10
-rw-r--r--docs/index.md26
-rw-r--r--docs/termynal.css101
-rw-r--r--docs/termynal.js197
-rw-r--r--mkdocs.yml2
6 files changed, 351 insertions, 3 deletions
diff --git a/docs/extra.css b/docs/extra.css
index 12a7663..495c838 100644
--- a/docs/extra.css
+++ b/docs/extra.css
@@ -9,4 +9,20 @@ a.toctree-l3 {
.document hr {
border-top: 1px solid #666;
-} \ No newline at end of file
+}
+
+/* Termynal */
+
+[data-termynal]:after {
+ content: ''; /* Don't display a window title */
+}
+
+[data-termynal] {
+ width: 100%;
+ font-size: 0.9rem;
+ margin-bottom: 1rem;
+}
+
+[data-termynal] > [data-ty="comment"] {
+ color: #DAD6AF;
+}
diff --git a/docs/extra.js b/docs/extra.js
index 4af1fa4..83dd081 100644
--- a/docs/extra.js
+++ b/docs/extra.js
@@ -2,4 +2,12 @@ document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll("table").forEach(function (table) {
table.classList.add("docutils");
});
-}); \ No newline at end of file
+
+ document.querySelectorAll(".termynal").forEach(function (termynalEl) {
+ new Termynal(termynalEl);
+ });
+});
+
+
+
+
diff --git a/docs/index.md b/docs/index.md
index b735b6b..3fb2202 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -4,7 +4,31 @@ Gitlint is a git commit message linter written in python: it checks your commit
Great for use as a [commit-msg git hook](#using-gitlint-as-a-commit-msg-hook) or as part of your gating script in a
[CI pipeline (e.g. Jenkins)](index.md#using-gitlint-in-a-ci-environment).
-<script type="text/javascript" src="https://asciinema.org/a/30477.js" id="asciicast-30477" async></script>
+<!-- <script type="text/javascript" src="https://asciinema.org/a/30477.js" id="asciicast-30477" async></script> -->
+
+<div class="termynal" data-termynal data-ty-typeDelay="25" data-ty-startDelay="600" data-ty-lineDelay="500">
+ <span data-ty="input">pip install gitlint</span>
+ <span data-ty="progress"></span>
+ <span data-ty>Successfully installed gitlint-core, gitlint</span>
+ <span data-ty></span>
+ <span data-ty="comment"># Add a bad commit message</span>
+ <span data-ty="input">git commit --allow-empty -m " WIP: My bad commit title." -m "who &emsp; cares "</span>
+ <span>[main a9f9368] WIP: My bad commit title.</span>
+ <span data-ty></span>
+ <span data-ty="comment"># Run gitlint!</span>
+ <span data-ty="input">gitlint</span>e
+ <span data-ty>1: T3 Title has trailing punctuation (.): " WIP: My bad commit title."<br />
+ 1: T5 Title contains the word 'WIP' (case-insensitive): " WIP: My bad commit title."<br />
+ 1: T6 Title has leading whitespace: " WIP: My bad commit title."<br />
+ 3: B2 Line has trailing whitespace: "who &emsp; cares "<br />
+ 3: B3 Line contains hard tab characters (\t): "who &emsp; cares "<br />
+ 3: B5 Body message is too short (10&lt;20): "who &emsp; cares "
+ </span>
+ <span data-ty data-ty-delay="2000"></span>
+ <span data-ty></span>
+ <span data-ty="comment"># Gitlint is perfect for use in your CI pipeline.</span>
+ <span data-ty="comment"># Also available as a commit-msg hook or via pre-commit.</span>
+</div>
!!! note
**Gitlint works on Windows**, but [there are some known issues](https://github.com/jorisroovers/gitlint/issues?q=is%3Aissue+is%3Aopen+label%3Awindows).
diff --git a/docs/termynal.css b/docs/termynal.css
new file mode 100644
index 0000000..cb79513
--- /dev/null
+++ b/docs/termynal.css
@@ -0,0 +1,101 @@
+/**
+ * termynal.js
+ *
+ * @author Ines Montani <ines@ines.io>
+ * @version 0.0.1
+ * @license MIT
+ */
+
+:root {
+ --color-bg: #252a33;
+ --color-text: #eee;
+ --color-text-subtle: #a2a2a2;
+}
+
+[data-termynal] {
+ width: 750px;
+ max-width: 100%;
+ background: var(--color-bg);
+ color: var(--color-text);
+ font-size: 18px;
+ font-family: 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace;
+ border-radius: 4px;
+ padding: 75px 45px 35px;
+ position: relative;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+[data-termynal]:before {
+ content: '';
+ position: absolute;
+ top: 15px;
+ left: 15px;
+ display: inline-block;
+ width: 15px;
+ height: 15px;
+ border-radius: 50%;
+ /* A little hack to display the window buttons in one pseudo element. */
+ background: #d9515d;
+ -webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
+ box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
+}
+
+[data-termynal]:after {
+ content: 'bash';
+ position: absolute;
+ color: var(--color-text-subtle);
+ top: 5px;
+ left: 0;
+ width: 100%;
+ text-align: center;
+}
+
+[data-ty] {
+ display: block;
+ line-height: 2;
+}
+
+[data-ty]:before {
+ /* Set up defaults and ensure empty lines are displayed. */
+ content: '';
+ display: inline-block;
+ vertical-align: middle;
+}
+
+[data-ty="input"]:before,
+[data-ty-prompt]:before {
+ margin-right: 0.75em;
+ color: var(--color-text-subtle);
+}
+
+[data-ty="input"]:before {
+ content: '$';
+}
+
+[data-ty][data-ty-prompt]:before {
+ content: attr(data-ty-prompt);
+}
+
+[data-ty-cursor]:after {
+ content: attr(data-ty-cursor);
+ font-family: monospace;
+ margin-left: 0.5em;
+ -webkit-animation: blink 1s infinite;
+ animation: blink 1s infinite;
+}
+
+
+/* Cursor animation */
+
+@-webkit-keyframes blink {
+ 50% {
+ opacity: 0;
+ }
+}
+
+@keyframes blink {
+ 50% {
+ opacity: 0;
+ }
+}
diff --git a/docs/termynal.js b/docs/termynal.js
new file mode 100644
index 0000000..77ec6cb
--- /dev/null
+++ b/docs/termynal.js
@@ -0,0 +1,197 @@
+/**
+ * termynal.js
+ * A lightweight, modern and extensible animated terminal window, using
+ * async/await.
+ *
+ * @author Ines Montani <ines@ines.io>
+ * @version 0.0.1
+ * @license MIT
+ */
+
+'use strict';
+
+/** Generate a terminal widget. */
+class Termynal {
+ /**
+ * Construct the widget's settings.
+ * @param {(string|Node)=} container - Query selector or container element.
+ * @param {Object=} options - Custom settings.
+ * @param {string} options.prefix - Prefix to use for data attributes.
+ * @param {number} options.startDelay - Delay before animation, in ms.
+ * @param {number} options.typeDelay - Delay between each typed character, in ms.
+ * @param {number} options.lineDelay - Delay between each line, in ms.
+ * @param {number} options.progressLength - Number of characters displayed as progress bar.
+ * @param {string} options.progressChar – Character to use for progress bar, defaults to █.
+ * @param {number} options.progressPercent - Max percent of progress.
+ * @param {string} options.cursor – Character to use for cursor, defaults to ▋.
+ * @param {Object[]} lineData - Dynamically loaded line data objects.
+ * @param {boolean} options.noInit - Don't initialise the animation.
+ */
+ constructor(container = '#termynal', options = {}) {
+ this.container = (typeof container === 'string') ? document.querySelector(container) : container;
+ this.pfx = `data-${options.prefix || 'ty'}`;
+ this.startDelay = options.startDelay
+ || parseFloat(this.container.getAttribute(`${this.pfx}-startDelay`)) || 600;
+ this.typeDelay = options.typeDelay
+ || parseFloat(this.container.getAttribute(`${this.pfx}-typeDelay`)) || 90;
+ this.lineDelay = options.lineDelay
+ || parseFloat(this.container.getAttribute(`${this.pfx}-lineDelay`)) || 1500;
+ this.progressLength = options.progressLength
+ || parseFloat(this.container.getAttribute(`${this.pfx}-progressLength`)) || 40;
+ this.progressChar = options.progressChar
+ || this.container.getAttribute(`${this.pfx}-progressChar`) || '█';
+ this.progressPercent = options.progressPercent
+ || parseFloat(this.container.getAttribute(`${this.pfx}-progressPercent`)) || 100;
+ this.cursor = options.cursor
+ || this.container.getAttribute(`${this.pfx}-cursor`) || '▋';
+ this.lineData = this.lineDataToElements(options.lineData || []);
+ if (!options.noInit) this.init()
+ }
+
+ /**
+ * Initialise the widget, get lines, clear container and start animation.
+ */
+ init() {
+ // Appends dynamically loaded lines to existing line elements.
+ this.lines = [...this.container.querySelectorAll(`[${this.pfx}]`)].concat(this.lineData);
+
+ /**
+ * Calculates width and height of Termynal container.
+ * If container is empty and lines are dynamically loaded, defaults to browser `auto` or CSS.
+ */
+ const containerStyle = getComputedStyle(this.container);
+ this.container.style.width = containerStyle.width !== '0px' ?
+ containerStyle.width : undefined;
+ this.container.style.minHeight = containerStyle.height !== '0px' ?
+ containerStyle.height : undefined;
+
+ this.container.setAttribute('data-termynal', '');
+ this.container.innerHTML = '';
+ this.start();
+ }
+
+ /**
+ * Start the animation and rener the lines depending on their data attributes.
+ */
+ async start() {
+ await this._wait(this.startDelay);
+
+ for (let line of this.lines) {
+ const type = line.getAttribute(this.pfx);
+ const delay = line.getAttribute(`${this.pfx}-delay`) || this.lineDelay;
+
+ if (type == 'input') {
+ line.setAttribute(`${this.pfx}-cursor`, this.cursor);
+ await this.type(line);
+ await this._wait(delay);
+ }
+
+ else if (type == 'progress') {
+ await this.progress(line);
+ await this._wait(delay);
+ }
+
+ else {
+ this.container.appendChild(line);
+ await this._wait(delay);
+ }
+
+ line.removeAttribute(`${this.pfx}-cursor`);
+ }
+ }
+
+ /**
+ * Animate a typed line.
+ * @param {Node} line - The line element to render.
+ */
+ async type(line) {
+ const chars = [...line.textContent];
+ const delay = line.getAttribute(`${this.pfx}-typeDelay`) || this.typeDelay;
+ line.textContent = '';
+ this.container.appendChild(line);
+
+ for (let char of chars) {
+ await this._wait(delay);
+ line.textContent += char;
+ }
+ }
+
+ /**
+ * Animate a progress bar.
+ * @param {Node} line - The line element to render.
+ */
+ async progress(line) {
+ const progressLength = line.getAttribute(`${this.pfx}-progressLength`)
+ || this.progressLength;
+ const progressChar = line.getAttribute(`${this.pfx}-progressChar`)
+ || this.progressChar;
+ const chars = progressChar.repeat(progressLength);
+ const progressPercent = line.getAttribute(`${this.pfx}-progressPercent`)
+ || this.progressPercent;
+ line.textContent = '';
+ this.container.appendChild(line);
+
+ for (let i = 1; i < chars.length + 1; i++) {
+ await this._wait(this.typeDelay);
+ const percent = Math.round(i / chars.length * 100);
+ line.textContent = `${chars.slice(0, i)} ${percent}%`;
+ if (percent>progressPercent) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Helper function for animation delays, called with `await`.
+ * @param {number} time - Timeout, in ms.
+ */
+ _wait(time) {
+ return new Promise(resolve => setTimeout(resolve, time));
+ }
+
+ /**
+ * Converts line data objects into line elements.
+ *
+ * @param {Object[]} lineData - Dynamically loaded lines.
+ * @param {Object} line - Line data object.
+ * @returns {Element[]} - Array of line elements.
+ */
+ lineDataToElements(lineData) {
+ return lineData.map(line => {
+ let div = document.createElement('div');
+ div.innerHTML = `<span ${this._attributes(line)}>${line.value || ''}</span>`;
+
+ return div.firstElementChild;
+ });
+ }
+
+ /**
+ * Helper function for generating attributes string.
+ *
+ * @param {Object} line - Line data object.
+ * @returns {string} - String of attributes.
+ */
+ _attributes(line) {
+ let attrs = '';
+ for (let prop in line) {
+ attrs += this.pfx;
+
+ if (prop === 'type') {
+ attrs += `="${line[prop]}" `
+ } else if (prop !== 'value') {
+ attrs += `-${prop}="${line[prop]}" `
+ }
+ }
+
+ return attrs;
+ }
+}
+
+/**
+* HTML API: If current script has container(s) specified, initialise Termynal.
+*/
+if (document.currentScript.hasAttribute('data-termynal-container')) {
+ const containers = document.currentScript.getAttribute('data-termynal-container');
+ containers.split('|')
+ .forEach(container => new Termynal(container))
+}
diff --git a/mkdocs.yml b/mkdocs.yml
index 23ceb23..5937c1e 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -18,6 +18,8 @@ theme:
navigation_depth: 2
strict: true
extra_css:
+ - termynal.css
- extra.css
extra_javascript:
+ - termynal.js
- extra.js \ No newline at end of file