SKEDUZ / templates /terminal.html
Zhofang's picture
Update templates/terminal.html
8f9404d verified
raw
history blame
7.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Terminal</title>
<!-- tailwind -->
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-900 text-white p-6">
<div class="flex flex-col items-center justify-center">
<div class="container space-y-8 md:my-12 max-w-4xl">
<!-- banner -->
<div class="">
<h1 class="text-3xl">@VANO_GANZZZ INTERFACE <span class="font-bold text-gray-400"
style="animation: blinker 1s linear infinite;">_</span></h1>
<style>
@keyframes blinker {
50% {
opacity: 0;
}
}
</style>
</div>
<!-- history console -->
<div id="history" class=" space-y-4 w-full">
<!-- input in right -->
<div id="history-input" class="w-full flex justify-end">
<div class="bg-gray-800 rounded-lg p-4 overflow-y-auto w-fit">
<pre class="whitespace-pre-line">{{ welcome_input }}</pre>
</div>
</div>
<!-- output in left -->
<div id="history-output" class="w-full flex justify-start">
<div class="bg-gray-700 rounded-lg p-4 overflow-y-auto w-fit">
<pre class="whitespace-pre-line">{{ welcome_output }}</pre>
</div>
</div>
</div>
<!-- input -->
<div class="bg-gray-800 rounded-lg p-4 w-full shadow-lg">
<form action="/exec" method="GET" onsubmit="return executeCommand(event)">
<div class="flex items-center space-x-2">
<span class="text-gray-400 flex-shrink-0" id="pwd_placeholder">{{ pwd }}</span>
<input type="text" id="command" name="command" class="w-full p-2 bg-gray-700 rounded-md"
placeholder="{{ welcome_input }}" autocomplete="off" autofocus>
</div>
<input type="hidden" id="pwd" name="pwd" value="{{ pwd }}">
</form>
</div>
</div>
</div>
<script>
window.addEventListener("load", function () {
const topButton = document.querySelector(".top-button");
const bottomButton = document.querySelector(".bottom-button");
window.addEventListener("scroll", function () {
if (window.scrollY + window.innerHeight < document.body.scrollHeight - 100) {
topButton.style.display = "block";
scrollLock = true;
} else {
topButton.style.display = "none";
scrollLock = false;
}
if (window.scrollY > 100) {
bottomButton.style.display = "block";
} else {
bottomButton.style.display = "none";
}
});
});
</script>
<!-- scroll to top button -->
<div class="fixed bottom-0 right-0 m-8 top-button" style="display: none;">
<button onclick="window.scrollTo(0, document.body.scrollHeight)" class="text-3xl p-4 text-white">↓</button>
</div>
<!-- scroll to bottom button -->
<div class="fixed top-0 right-0 m-8 bottom-button" style="display: none;">
<button onclick="window.scrollTo(0, 0)" class="text-3xl p-4 text-white">↑</button>
</div>
<script>
const historyElement = document.getElementById("history");
const command = document.getElementById("command");
const pwd = document.getElementById("pwd");
let scrollLock = false;
// tambhakan history input dan output
function addHistory(input, output) {
const copyInputElement = document.getElementById("history-input").cloneNode(true);
const copyOutputElement = document.getElementById("history-output").cloneNode(true);
// set input and output content
copyInputElement.querySelector("pre").textContent = input;
copyOutputElement.querySelector("pre").textContent = output;
// add running arttribute to output
copyOutputElement.setAttribute("x-running", "");
// append input and output
document.getElementById("history").appendChild(copyInputElement);
document.getElementById("history").appendChild(copyOutputElement);
}
// ANSI removal
// example: 
function removeAnsi(text) {
return text.replace(/\[(\d+)(;\d+)*[mK]/g, "");
}
// if on focus input and press UP
command.addEventListener("focus", () => {
window.addEventListener("keydown", (event) => {
// on TAB
if (event.key === "Tab") {
event.preventDefault();
command.value = command.placeholder;
}
})
});
const executeCommand = (event) => {
event.preventDefault();
// disable input
command.disabled = true;
// add history
addHistory(command.value, "");
outputRunningElement = document.querySelector("div[x-running]");
window.scrollTo(0, document.body.scrollHeight);
scrollLock = false;
const eventSource = new EventSource("/exec?" + new URLSearchParams({
command: command.value,
pwd: pwd.value
}));
eventSource.onmessage = function (event) {
const data = JSON.parse(event.data);
if (data.pwd) {
// set pwd
document.getElementById("pwd").value = data.pwd;
document.getElementById("pwd_placeholder").textContent = data.pwd;
}
// if done stop listening
if (data.output === "[DONE]") {
eventSource.close();
// enable input
command.disabled = false;
// set command value to placeholder
command.placeholder = command.value;
// remove running arttribute
outputRunningElement.removeAttribute("x-running");
// if output is empty remove element
if (outputRunningElement.querySelector("pre").textContent === "") {
outputRunningElement.remove();
}
// clear input and make command focus
command.value = "";
command.focus();
return;
}
if (data.output) {
// update output
outputRunningElement.querySelector("pre").textContent += removeAnsi(data.output);
// if you scroll down to bottom, scroll to bottom automatically
if (!scrollLock) {
window.scrollTo(0, document.body.scrollHeight);
}
}
}
};
</script>
</body>
</html>