portfolio: terminal Debian plein ecran, sans components — prompt/input dans le flux de sortie

This commit is contained in:
riricdev 2026-09-08 21:36:55 +02:00
commit 008eefbb3f
4 changed files with 155 additions and 261 deletions

View file

@ -4,14 +4,12 @@
var FR = /^\/en(\/|$)/.test(location.pathname) ? false : true;
var T = {
title: FR ? "dotriric@zektyc: ~ — bash" : "dotriric@zektyc: ~ — bash",
boot: FR
? ["Debian GNU/Linux 12 (bookworm) tty1", "zektyc login: dotriric", "Password: ********", "Last login: a l'instant depuis votre navigateur", "Bienvenue sur le terminal de presentation de Riric.", "Tapez 'help' pour la liste des commandes."]
: ["Debian GNU/Linux 12 (bookworm) tty1", "zektyc login: dotriric", "Password: ********", "Last login: right now from your browser", "Welcome to Riric's presentation terminal.", "Type 'help' for the list of commands."],
promptUser: "dotriric",
promptHost: "zektyc",
unknown: function (c) { return FR ? ("bash: " + c + " : commande introuvable") : ("bash: " + c + ": command not found"); },
pwEmpty: FR ? "bash: passage en racine impossible : ne peut pas se connecter en tant que root" : "bash: cannot become root: cannot login as root",
helpLines: FR
? [
"Commandes disponibles :",
@ -115,13 +113,10 @@
contact: FR
? ["Email: riric65@protonmail.com", "Mastodon: @zektyc@piaille.fr", "Repond generalement en francais ou en anglais."]
: ["Email: riric65@protonmail.com", "Mastodon: @zektyc@piaille.fr", "Usually replies in French or English."],
files: ["about.txt", "projects.txt", "contact.txt", ".bashrc", ".profile"],
contactFile: FR ? ["ouvrez contact.txt, ou tapez 'contact'"] : ["open contact.txt, or type 'contact'"],
bashrc: FR ? ["# Config bash de dotriric", 'export PS1="dotriric@zektyc:~$ "', "alias ll='ls -alF'", "# Je n'aime pas le sucre."] : ["# dotriric's bash config", 'export PS1="dotriric@zektyc:~$ "', "alias ll='ls -alF'", "# I don't like sugar."],
profile: FR ? ["# .profile — charge le bashrc", "source ~/.bashrc", "# Bienvenue."] : ["# .profile — loads bashrc", "source ~/.bashrc", "# Welcome."],
sudo: FR ? ["dotriric n'est pas dans le fichier sudoers. Cet incident sera signale."] : ["dotriric is not in the sudoers file. This incident will be reported."],
apt: FR ? ["Lecture des listes de paquets... Termine.", "Construction de l'arbre des dependances... Termine.", "0 paquet(s) mis a niveau."] : ["Reading package lists... Done.", "Building dependency tree... Done.", "0 packages can be upgraded."],
contactCmd: FR ? "Me contacter : taper 'contact'" : "To contact me: type 'contact'",
shutdown: FR ? ["connexion fermee.", "terminal de presentation quitte — la page reste, evidemment. :)"] : ["connection closed.", "presentation terminal exited — the page stays, of course. :)"],
};
@ -130,21 +125,9 @@
if (!root) return;
var body = root.querySelector(".terminal-body");
var input = root.querySelector(".term-input");
var history = [];
var histIdx = -1;
function makeLine(text, cls) {
var div = document.createElement("div");
div.className = "terminal-line";
if (cls) div.classList.add(cls);
if (typeof text === "string") {
div.textContent = text;
} else {
div.appendChild(text);
}
return div;
}
var locked = false;
function makeLink(text, href) {
var a = document.createElement("a");
@ -191,30 +174,90 @@
body.scrollTop = body.scrollHeight;
}
function promptLine() {
var p = document.createElement("div");
function promptEl() {
var p = document.createElement("span");
p.className = "term-prompt";
var sp = document.createElement("span");
sp.className = "t-user";
sp.textContent = T.promptUser + "@" + T.promptHost;
var ct = document.createElement("span");
ct.className = "t-path";
ct.textContent = ":" + "\u007e" + "$ ";
ct.textContent = ":~$ ";
p.appendChild(sp);
p.appendChild(ct);
return p;
}
function runCommand(raw) {
var cmd = raw.trim();
function currentPrompt() {
return body.querySelector(".prompt-line");
}
function newPrompt() {
var line = document.createElement("div");
line.className = "terminal-line";
line.appendChild(promptLine());
line.appendChild(document.createTextNode(raw));
line.className = "terminal-line prompt-line term-line-input";
line.appendChild(promptEl());
var inp = document.createElement("input");
inp.type = "text";
inp.className = "term-input";
inp.setAttribute("autocomplete", "off");
inp.setAttribute("autocapitalize", "off");
inp.setAttribute("spellcheck", "false");
inp.setAttribute("aria-label", FR ? "Commande" : "Command");
line.appendChild(inp);
body.appendChild(line);
bindInput(inp);
scrollDown();
return inp;
}
if (!cmd) { scrollDown(); return; }
function bindInput(inp) {
inp.addEventListener("keydown", function (e) {
if (e.key === "Enter") {
e.preventDefault();
submit(inp);
} else if (e.key === "ArrowUp") {
e.preventDefault();
if (history.length) {
histIdx = Math.max(0, histIdx - 1);
inp.value = history[histIdx] || "";
}
} else if (e.key === "ArrowDown") {
e.preventDefault();
if (history.length) {
histIdx = Math.min(history.length, histIdx + 1);
inp.value = histIdx >= history.length ? "" : history[histIdx];
}
}
});
inp.addEventListener("input", scrollDown);
}
function submit(inp) {
var raw = inp.value;
var line = inp.closest(".prompt-line");
var txt = document.createElement("span");
txt.textContent = raw;
inp.replaceWith(txt);
if (raw.trim()) history.push(raw);
histIdx = history.length;
var cmd = raw.trim();
if (cmd === "clear" || cmd === "cls") {
body.innerHTML = "";
newPrompt().focus();
return;
}
if (cmd) runCommand(cmd);
if (locked) return;
newPrompt().focus();
scrollDown();
}
function runCommand(cmd) {
var parts = cmd.split(/[ \t]+/);
var c = parts[0].toLowerCase();
var arg = parts.slice(1).join(" ");
@ -223,9 +266,6 @@
case c === "help" || c === "h" || c === "?":
print(T.helpLines);
break;
case c === "clear" || c === "cls":
body.innerHTML = "";
break;
case c === "whoami":
print("dotriric");
break;
@ -298,8 +338,7 @@
break;
case c === "exit" || c === "logout" || c === "quit":
print(T.shutdown);
input.disabled = true;
input.setAttribute("placeholder", "");
locked = true;
break;
case c === "echo":
print(arg || "");
@ -310,45 +349,21 @@
default:
print(T.unknown(c));
}
scrollDown();
}
function submit() {
var v = input.value;
if (v.trim()) history.push(v);
histIdx = history.length;
runCommand(v);
input.value = "";
}
input.addEventListener("keydown", function (e) {
if (e.key === "Enter") {
e.preventDefault();
submit();
} else if (e.key === "ArrowUp") {
e.preventDefault();
if (history.length) {
histIdx = Math.max(0, histIdx - 1);
input.value = history[histIdx] || "";
}
} else if (e.key === "ArrowDown") {
e.preventDefault();
if (history.length) {
histIdx = Math.min(history.length, histIdx + 1);
input.value = histIdx >= history.length ? "" : history[histIdx];
}
}
});
root.addEventListener("click", function () {
if (!input.disabled) input.focus();
var ln = currentPrompt();
if (ln) {
var inp = ln.querySelector(".term-input");
if (inp && !inp.disabled) inp.focus();
}
});
(function boot() {
printAscii(["", T.boot.join("\n"), ""]);
var inp = newPrompt();
setTimeout(function () {
inp.focus();
}, 50);
})();
setTimeout(function () {
input.focus();
}, 50);
})();