Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/css/termynal.css
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@
text-align: center;
}

a[data-terminal-control] {
text-align: right;
display: block;
color: #aebbff;
}

[data-ty] {
display: block;
line-height: 2;
Expand Down
129 changes: 72 additions & 57 deletions docs/js/custom.js
Original file line number Diff line number Diff line change
@@ -1,76 +1,91 @@
document.querySelectorAll(".use-termynal").forEach(node => {
node.style.display = "block";
new Termynal(node);
new Termynal(node, {
lineDelay: 500
});
});
const progressLiteralStart = "---> 100%";
const promptLiteralStart = "$ ";
const termynalActivateClass = "termy";
let termynals = [];

function loadVisibleTermynals() {
function createTermynals() {
document
.querySelectorAll(`.${termynalActivateClass} .codehilite`)
.forEach(node => {
if (node.getBoundingClientRect().top - innerHeight <= 0) {
const text = node.textContent;
const lines = text.split("\n");
const useLines = [];
let buffer = [];
function saveBuffer() {
if (buffer.length) {
let isBlankSpace = true
buffer.forEach(line => {
if (line) {
isBlankSpace = false
}
})
dataValue = {}
if (isBlankSpace) {
dataValue["delay"] = 0
}
if (buffer.length > 1 && buffer[buffer.length - 1] === "") {
// The last single <br> won't have effect
// so put an additional one
buffer.push("");
const text = node.textContent;
const lines = text.split("\n");
const useLines = [];
let buffer = [];
function saveBuffer() {
if (buffer.length) {
let isBlankSpace = true;
buffer.forEach(line => {
if (line) {
isBlankSpace = false;
}
const bufferValue = buffer.join("<br>");
dataValue["value"] = bufferValue
useLines.push(dataValue);
buffer = [];
});
dataValue = {};
if (isBlankSpace) {
dataValue["delay"] = 0;
}
}
for (let line of lines) {
if (line === progressLiteralStart) {
saveBuffer();
useLines.push({
type: "progress"
});
} else if (line.startsWith(promptLiteralStart)) {
saveBuffer();
const value = line.replace(promptLiteralStart, "").trimEnd();
useLines.push({
type: "input",
value: value
});
} else if (line.startsWith("// ")) {
saveBuffer();
const value = line.replace("// ", "").trimEnd();
useLines.push({
value: value,
class: "termynal-comment",
delay: 0
});
} else {
buffer.push(line);
if (buffer.length > 1 && buffer[buffer.length - 1] === "") {
// The last single <br> won't have effect
// so put an additional one
buffer.push("");
}
const bufferValue = buffer.join("<br>");
dataValue["value"] = bufferValue;
useLines.push(dataValue);
buffer = [];
}
}
for (let line of lines) {
if (line === progressLiteralStart) {
saveBuffer();
useLines.push({
type: "progress"
});
} else if (line.startsWith(promptLiteralStart)) {
saveBuffer();
const value = line.replace(promptLiteralStart, "").trimEnd();
useLines.push({
type: "input",
value: value
});
} else if (line.startsWith("// ")) {
saveBuffer();
const value = line.replace("// ", "").trimEnd();
useLines.push({
value: value,
class: "termynal-comment",
delay: 0
});
} else {
buffer.push(line);
}
saveBuffer();
const div = document.createElement("div");
node.replaceWith(div);
const termynal = new Termynal(div, {
lineData: useLines
});
}
saveBuffer();
const div = document.createElement("div");
node.replaceWith(div);
const termynal = new Termynal(div, {
lineData: useLines,
noInit: true,
lineDelay: 500
});
termynals.push(termynal);
});
}

function loadVisibleTermynals() {
termynals = termynals.filter(termynal => {
if (termynal.container.getBoundingClientRect().top - innerHeight <= 0) {
termynal.init();
return false;
}
return true;
});
}
window.addEventListener("scroll", loadVisibleTermynals);
createTermynals();
loadVisibleTermynals();
78 changes: 71 additions & 7 deletions docs/js/termynal.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ class Termynal {
constructor(container = '#termynal', options = {}) {
this.container = (typeof container === 'string') ? document.querySelector(container) : container;
this.pfx = `data-${options.prefix || 'ty'}`;
this.startDelay = options.startDelay
this.originalStartDelay = this.startDelay = options.startDelay
|| parseFloat(this.container.getAttribute(`${this.pfx}-startDelay`)) || 600;
this.typeDelay = options.typeDelay
this.originalTypeDelay = this.typeDelay = options.typeDelay
|| parseFloat(this.container.getAttribute(`${this.pfx}-typeDelay`)) || 90;
this.lineDelay = options.lineDelay
this.originalLineDelay = this.lineDelay = options.lineDelay
|| parseFloat(this.container.getAttribute(`${this.pfx}-lineDelay`)) || 1500;
this.progressLength = options.progressLength
|| parseFloat(this.container.getAttribute(`${this.pfx}-progressLength`)) || 40;
Expand All @@ -45,16 +45,33 @@ class Termynal {
this.cursor = options.cursor
|| this.container.getAttribute(`${this.pfx}-cursor`) || '▋';
this.lineData = this.lineDataToElements(options.lineData || []);
this.loadLines()
if (!options.noInit) this.init()
}

loadLines() {
// Load all the lines and create the container so that the size is fixed
// Otherwise it would be changing and the user viewport would be constantly
// moving as she/he scrolls
const finish = this.generateFinish()
finish.style.visibility = 'hidden'
this.container.appendChild(finish)
// Appends dynamically loaded lines to existing line elements.
this.lines = [...this.container.querySelectorAll(`[${this.pfx}]`)].concat(this.lineData);
for (let line of this.lines) {
line.style.visibility = 'hidden'
this.container.appendChild(line)
}
const restart = this.generateRestart()
restart.style.visibility = 'hidden'
this.container.appendChild(restart)
this.container.setAttribute('data-termynal', '');
}

/**
* 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.
Expand All @@ -67,13 +84,17 @@ class Termynal {

this.container.setAttribute('data-termynal', '');
this.container.innerHTML = '';
for (let line of this.lines) {
line.style.visibility = 'visible'
}
this.start();
}

/**
* Start the animation and rener the lines depending on their data attributes.
*/
async start() {
this.addFinish()
await this._wait(this.startDelay);

for (let line of this.lines) {
Expand All @@ -98,6 +119,49 @@ class Termynal {

line.removeAttribute(`${this.pfx}-cursor`);
}
this.addRestart()
this.finishElement.style.visibility = 'hidden'
this.lineDelay = this.originalLineDelay
this.typeDelay = this.originalTypeDelay
this.startDelay = this.originalStartDelay
}

generateRestart() {
const restart = document.createElement('a')
restart.onclick = (e) => {
e.preventDefault()
this.container.innerHTML = ''
this.init()
}
restart.href = '#'
restart.setAttribute('data-terminal-control', '')
restart.innerHTML = "restart \u27f3" // Refresh emoji
return restart
}

generateFinish() {
const finish = document.createElement('a')
finish.onclick = (e) => {
e.preventDefault()
this.lineDelay = 0
this.typeDelay = 0
this.startDelay = 0
}
finish.href = '#'
finish.setAttribute('data-terminal-control', '')
finish.innerHTML = "fast \u2b95" // Fast emoji arrow
this.finishElement = finish
return finish
}

addRestart() {
const restart = this.generateRestart()
this.container.appendChild(restart)
}

addFinish() {
const finish = this.generateFinish()
this.container.appendChild(finish)
}

/**
Expand All @@ -106,11 +170,11 @@ class Termynal {
*/
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) {
const delay = line.getAttribute(`${this.pfx}-typeDelay`) || this.typeDelay;
await this._wait(delay);
line.textContent += char;
}
Expand Down
Loading