Refactors site to use interactive terminal UI
Moves site from static HTML to a dynamic terminal interface. This commit represents a major overhaul, introducing: - A functional terminal emulator implemented in JavaScript. - Command parsing and execution framework. - Various terminal commands for navigation and utility functions. - SASS conversion. The old CSS and simple HTML are completely removed. A new Hugo theme is implemented.
This commit is contained in:
parent
d22b4ec65a
commit
23369f4ace
46 changed files with 3524 additions and 860 deletions
41
assets/js/commands/core.js
Normal file
41
assets/js/commands/core.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Core Commands Module
|
||||
// These are essential commands for the terminal
|
||||
|
||||
// Help command
|
||||
window.terminal.registerCommand("help", "Display available commands", () => {
|
||||
window.terminal.print("Available commands:", "success");
|
||||
window.terminal.print("");
|
||||
|
||||
const commands = Object.keys(window.terminal.commands).sort();
|
||||
commands.forEach((cmd) => {
|
||||
const desc = window.terminal.commands[cmd].description || "No description";
|
||||
window.terminal.print(` ${cmd.padEnd(15)} - ${desc}`);
|
||||
});
|
||||
window.terminal.print("");
|
||||
});
|
||||
|
||||
// Clear command
|
||||
window.terminal.registerCommand("clear", "Clear the terminal screen", () => {
|
||||
window.terminal.clear();
|
||||
});
|
||||
|
||||
// Echo command
|
||||
window.terminal.registerCommand("echo", "Echo text to the terminal", (args) => {
|
||||
window.terminal.print(args.join(" "));
|
||||
});
|
||||
|
||||
// History command
|
||||
window.terminal.registerCommand("history", "Show command history", () => {
|
||||
if (window.terminal.history.length === 0) {
|
||||
window.terminal.print("No commands in history");
|
||||
return;
|
||||
}
|
||||
|
||||
window.terminal.print("Command history:", "info");
|
||||
window.terminal.history
|
||||
.slice()
|
||||
.reverse()
|
||||
.forEach((cmd, idx) => {
|
||||
window.terminal.print(` ${idx + 1}. ${cmd}`);
|
||||
});
|
||||
});
|
||||
101
assets/js/commands/custom.js
Normal file
101
assets/js/commands/custom.js
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// Custom Commands Module
|
||||
// Add your custom commands here!
|
||||
// This file is a template for creating your own commands
|
||||
|
||||
// Example: Weather command (placeholder)
|
||||
// window.terminal.registerCommand(
|
||||
// "weather",
|
||||
// "Show weather information",
|
||||
// (args) => {
|
||||
// const city = args.length > 0 ? args.join(" ") : "your location";
|
||||
// window.terminal.printInfo(`Fetching weather for ${city}...`);
|
||||
// window.terminal.print("☀️ Sunny, 72°F");
|
||||
// window.terminal.print("");
|
||||
// window.terminal.printWarning(
|
||||
// "Note: This is a placeholder. Integrate with a real weather API!",
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
|
||||
// Example: Random quote
|
||||
// window.terminal.registerCommand("quote", "Display a random quote", () => {
|
||||
// const quotes = [
|
||||
// "The only way to do great work is to love what you do. - Steve Jobs",
|
||||
// "Innovation distinguishes between a leader and a follower. - Steve Jobs",
|
||||
// "Stay hungry, stay foolish. - Steve Jobs",
|
||||
// "First, solve the problem. Then, write the code. - John Johnson",
|
||||
// ];
|
||||
|
||||
// const randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
|
||||
// window.terminal.printSuccess(randomQuote);
|
||||
// });
|
||||
|
||||
// Example: List command (demonstrates dynamic content)
|
||||
// window.terminal.registerCommand(
|
||||
// "list",
|
||||
// "List items in a collection",
|
||||
// (args) => {
|
||||
// if (args.length === 0) {
|
||||
// window.terminal.printError("Usage: list <category>");
|
||||
// window.terminal.print("Available categories: files, users, tasks");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const category = args[0].toLowerCase();
|
||||
|
||||
// switch (category) {
|
||||
// case "files":
|
||||
// window.terminal.print("Files:", "info");
|
||||
// window.terminal.print(" 📄 document.txt");
|
||||
// window.terminal.print(" 📄 notes.md");
|
||||
// window.terminal.print(" 📁 projects/");
|
||||
// break;
|
||||
// case "users":
|
||||
// window.terminal.print("Users:", "info");
|
||||
// window.terminal.print(" 👤 admin");
|
||||
// window.terminal.print(" 👤 guest");
|
||||
// break;
|
||||
// case "tasks":
|
||||
// window.terminal.print("Tasks:", "info");
|
||||
// window.terminal.print(" ✓ Complete terminal setup");
|
||||
// window.terminal.print(" ☐ Add more commands");
|
||||
// window.terminal.print(" ☐ Customize appearance");
|
||||
// break;
|
||||
// default:
|
||||
// window.terminal.printError(`Unknown category: ${category}`);
|
||||
// }
|
||||
// },
|
||||
// );
|
||||
|
||||
// Example: Color command (demonstrates HTML output)
|
||||
window.terminal.registerCommand("colors", "Display available colors", () => {
|
||||
window.terminal.print("Available terminal colors:", "info");
|
||||
window.terminal.print("");
|
||||
window.terminal.printHTML("<span>● Standard (green)</span>");
|
||||
window.terminal.printHTML('<span class="error">● Error (red)</span>');
|
||||
window.terminal.printHTML(
|
||||
'<span class="success">● Success (bright green)</span>',
|
||||
);
|
||||
window.terminal.printHTML('<span class="info">● Info (blue)</span>');
|
||||
window.terminal.printHTML('<span class="warning">● Warning (orange)</span>');
|
||||
});
|
||||
|
||||
// ADD YOUR OWN COMMANDS BELOW THIS LINE
|
||||
// ========================================
|
||||
|
||||
// Template for new command:
|
||||
/*
|
||||
window.terminal.registerCommand('commandname', 'Command description', (args) => {
|
||||
// args is an array of arguments
|
||||
// Example: if user types "mycommand hello world"
|
||||
// args will be ['hello', 'world']
|
||||
|
||||
// Print output using:
|
||||
window.terminal.print('Regular text');
|
||||
window.terminal.printSuccess('Success message');
|
||||
window.terminal.printError('Error message');
|
||||
window.terminal.printInfo('Info message');
|
||||
window.terminal.printWarning('Warning message');
|
||||
window.terminal.printHTML('<strong>HTML content</strong>');
|
||||
});
|
||||
*/
|
||||
52
assets/js/commands/navigation.js
Normal file
52
assets/js/commands/navigation.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// Navigation Commands Module
|
||||
// Commands for navigating to different pages or URLs
|
||||
|
||||
// Navigate to URL command
|
||||
window.terminal.registerCommand("goto", "Navigate to a URL", (args) => {
|
||||
if (args.length === 0) {
|
||||
window.terminal.printError("Usage: goto <url>");
|
||||
window.terminal.print("Examples:");
|
||||
window.terminal.print(" goto google.com");
|
||||
window.terminal.print(" goto https://github.com");
|
||||
return;
|
||||
}
|
||||
|
||||
const url = args[0];
|
||||
window.terminal.printInfo(`Navigating to ${url}...`);
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.href = url.startsWith("http") ? url : `https://${url}`;
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// Open in new tab command
|
||||
window.terminal.registerCommand("open", "Open URL in new tab", (args) => {
|
||||
if (args.length === 0) {
|
||||
window.terminal.printError("Usage: open <url>");
|
||||
window.terminal.print("Examples:");
|
||||
window.terminal.print(" open google.com");
|
||||
window.terminal.print(" open https://github.com");
|
||||
return;
|
||||
}
|
||||
|
||||
const url = args[0];
|
||||
window.terminal.printInfo(`Opening ${url} in new tab...`);
|
||||
|
||||
const fullUrl = url.startsWith("http") ? url : `https://${url}`;
|
||||
window.open(fullUrl, "_blank");
|
||||
});
|
||||
|
||||
// Reload page command
|
||||
window.terminal.registerCommand("reload", "Reload the current page", () => {
|
||||
window.terminal.printInfo("Reloading page...");
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// PAGE NAVIGATION
|
||||
|
||||
// About command
|
||||
window.terminal.registerCommand("about", "About this site", () => {
|
||||
window.location.href = "/about/";
|
||||
});
|
||||
97
assets/js/commands/utility.js
Normal file
97
assets/js/commands/utility.js
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// Utility Commands Module
|
||||
// Useful utility commands
|
||||
|
||||
// Time command
|
||||
window.terminal.registerCommand("time", "Display current time", () => {
|
||||
const now = new Date();
|
||||
window.terminal.print(`Current time: ${now.toLocaleString()}`);
|
||||
});
|
||||
|
||||
// Calculator command
|
||||
window.terminal.registerCommand("calc", "Simple calculator", (args) => {
|
||||
if (args.length === 0) {
|
||||
window.terminal.printError("Usage: calc <expression>");
|
||||
window.terminal.print("Example: calc 5 + 3");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const expression = args.join(" ");
|
||||
// Note: eval is dangerous in production! This is just for demo purposes
|
||||
const result = eval(expression);
|
||||
window.terminal.printSuccess(`Result: ${result}`);
|
||||
} catch (error) {
|
||||
window.terminal.printError("Invalid expression");
|
||||
}
|
||||
});
|
||||
|
||||
// Demo command
|
||||
// window.terminal.registerCommand("demo", "Show demo content", () => {
|
||||
// window.terminal.printSuccess("=== Demo Content ===");
|
||||
// window.terminal.print("");
|
||||
// window.terminal.print("This is regular text");
|
||||
// window.terminal.printInfo("This is info text");
|
||||
// window.terminal.printWarning("This is warning text");
|
||||
// window.terminal.printError("This is error text");
|
||||
// window.terminal.print("");
|
||||
// window.terminal.printHTML(
|
||||
// 'You can also use <strong>HTML</strong> with <a href="#">links</a>!',
|
||||
// );
|
||||
// });
|
||||
|
||||
// ASCII art command
|
||||
// window.terminal.registerCommand("ascii", "Display ASCII art", () => {
|
||||
// const art = `
|
||||
// _____ _ _
|
||||
// |_ _|__ _ __ _ __ ___ (_)_ __ __ _| |
|
||||
// | |/ _ \\ '__| '_ \` _ \\| | '_ \\ / _\` | |
|
||||
// | | __/ | | | | | | | | | | | (_| | |
|
||||
// |_|\\___|_| |_| |_| |_|_|_| |_|\\__,_|_|
|
||||
// `;
|
||||
// window.terminal.print(art, "success");
|
||||
// });
|
||||
|
||||
// ASCII art command
|
||||
window.terminal.registerCommand("nerv", "Display NERV logo", () => {
|
||||
const art = `
|
||||
# ## %*###
|
||||
#******************
|
||||
#*******************
|
||||
********************
|
||||
%* **************************
|
||||
*** #*****************************
|
||||
** *******************************%
|
||||
*# *********************************
|
||||
%* %************************************
|
||||
******************************************
|
||||
*************************************
|
||||
**********************# ******#*
|
||||
*** *% %** %**********************
|
||||
*%**# * ** #*************************
|
||||
* *** * ** *************************
|
||||
* %**# * **#####*************************#
|
||||
* *** * ** * %**********************%
|
||||
* %**#* ** #*********************
|
||||
* *** ** %% ********************#
|
||||
*% %* %** ** *******************
|
||||
%******************
|
||||
#********# #*******************
|
||||
** #** ******************
|
||||
** **# *** *************#
|
||||
** #** **# ************
|
||||
*******# **% %**********
|
||||
** %** ** *%#*******#
|
||||
** *** #**#* ******
|
||||
** #**% *** ****#
|
||||
%****% ***% * %***
|
||||
#*
|
||||
|
||||
`;
|
||||
window.terminal.print(art, "success");
|
||||
});
|
||||
|
||||
// Greet command
|
||||
window.terminal.registerCommand("greet", "Greet the user", (args) => {
|
||||
const name = args.length > 0 ? args.join(" ") : "User";
|
||||
window.terminal.printSuccess(`Hello, ${name}! Welcome to the terminal.`);
|
||||
});
|
||||
16
assets/js/init.js
Normal file
16
assets/js/init.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Terminal Initialization Script
|
||||
// This script creates the terminal instance immediately
|
||||
// so command modules can register commands
|
||||
|
||||
// Create global terminal instance immediately
|
||||
window.terminal = new TerminalShell();
|
||||
|
||||
// Boot the terminal when DOM is ready
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
terminal.boot();
|
||||
});
|
||||
} else {
|
||||
// DOM already loaded
|
||||
terminal.boot();
|
||||
}
|
||||
70
assets/js/lavalamp.js
Normal file
70
assets/js/lavalamp.js
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
(function () {
|
||||
const lavaLamp = document.getElementById("lavaLamp");
|
||||
let blobs = [];
|
||||
let baseSpeed = 0.8;
|
||||
|
||||
function createBlob() {
|
||||
const blob = document.createElement("div");
|
||||
blob.className = "blob";
|
||||
const size = Math.random() * 30 + 20; // Smaller blobs (20-50px)
|
||||
const startY = Math.random() * 100; // Within ~150px height
|
||||
const duration = (Math.random() * 8 + 12) / baseSpeed;
|
||||
const maxX = 60 - size; // Adjusted for narrower tube (80px wide)
|
||||
const startX = Math.random() * maxX;
|
||||
|
||||
blob.style.width = `${size}px`;
|
||||
blob.style.height = `${size}px`;
|
||||
blob.style.left = `${startX}px`;
|
||||
blob.style.setProperty("--duration", `${duration}s`);
|
||||
blob.style.setProperty("--start-x", "0px");
|
||||
blob.style.setProperty("--start-y", `${startY}px`);
|
||||
blob.style.setProperty("--mid1-x", `${Math.random() * 15 - 15}px`);
|
||||
blob.style.setProperty("--mid1-y", `${Math.random() * -40 - 40}px`);
|
||||
blob.style.setProperty("--mid2-x", `${Math.random() * 20 - 20}px`);
|
||||
blob.style.setProperty("--mid2-y", `${Math.random() * -80 - 40}px`);
|
||||
blob.style.setProperty("--mid3-x", `${Math.random() * 15 - 15}px`);
|
||||
blob.style.setProperty("--mid3-y", `${Math.random() * -60 - 10}px`);
|
||||
blob.style.setProperty("--scale1", (Math.random() * 0.3 + 1.0).toFixed(2));
|
||||
blob.style.setProperty("--scale2", (Math.random() * 0.3 + 0.85).toFixed(2));
|
||||
blob.style.setProperty("--scale3", (Math.random() * 0.3 + 0.95).toFixed(2));
|
||||
blob.style.animationDelay = `${Math.random() * -20}s`;
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
function updateBlobColors() {
|
||||
const color1 = "#FF7800";
|
||||
const color2 = "#E01B24";
|
||||
const gradient = `radial-gradient(circle at 30% 30%, ${color1}, ${color2})`;
|
||||
blobs.forEach((blob) => {
|
||||
blob.style.background = gradient;
|
||||
});
|
||||
}
|
||||
|
||||
function updateLampBackground() {
|
||||
const bg1 = "#F8E45C";
|
||||
const bg2 = "#FF7800";
|
||||
lavaLamp.style.background = `linear-gradient(180deg, ${bg1} 0%, ${bg2} 100%)`;
|
||||
}
|
||||
|
||||
function updateBlobCount() {
|
||||
const count = parseInt(6);
|
||||
while (blobs.length > count) {
|
||||
const blob = blobs.pop();
|
||||
lavaLamp.removeChild(blob);
|
||||
}
|
||||
while (blobs.length < count) {
|
||||
const blob = createBlob();
|
||||
blobs.push(blob);
|
||||
lavaLamp.appendChild(blob);
|
||||
updateBlobColors();
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
updateBlobCount();
|
||||
updateLampBackground();
|
||||
}
|
||||
|
||||
init();
|
||||
})();
|
||||
190
assets/js/terminal.js
Normal file
190
assets/js/terminal.js
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
// Terminal Shell System
|
||||
class TerminalShell {
|
||||
constructor() {
|
||||
this.output = document.getElementById("output");
|
||||
this.input = document.getElementById("input");
|
||||
this.inputContainer = document.getElementById("input-container");
|
||||
this.history = [];
|
||||
this.historyIndex = -1;
|
||||
this.commands = {};
|
||||
|
||||
this.setupEventListeners();
|
||||
}
|
||||
|
||||
// Boot sequence
|
||||
async boot() {
|
||||
const bootMessages = [
|
||||
" _ _ _____ ______ __",
|
||||
" | \\ | | ____| _ \\ \\ / /",
|
||||
" | \\| | _| | |_) \\ \\ / / ",
|
||||
" | |\\ | |___| _ < \\ V / ",
|
||||
" |_| \\_|_____|_| \\_\\ \\_/ ",
|
||||
"",
|
||||
"NERV OS v2.015 - MAGI System Interface",
|
||||
"Initializing A.T. Field protocols...",
|
||||
"CASPER... ONLINE",
|
||||
"BALTHASAR... ONLINE",
|
||||
"MELCHIOR... ONLINE",
|
||||
"Synchronization ratio: 41.3%... 67.8%... 89.2%... OK",
|
||||
"Loading Evangelion Unit-01 core drivers... OK",
|
||||
"Mounting LCL interface... OK",
|
||||
"Neural connection established... OK",
|
||||
"",
|
||||
"Running pattern analysis... PATTERN BLUE",
|
||||
"",
|
||||
"All systems optimal.",
|
||||
"",
|
||||
"",
|
||||
];
|
||||
for (let i = 0; i < bootMessages.length; i++) {
|
||||
await this.sleep(100);
|
||||
const line = document.createElement("div");
|
||||
line.className = "output-line boot-line";
|
||||
line.textContent = bootMessages[i];
|
||||
line.style.animationDelay = "0s";
|
||||
this.output.appendChild(line);
|
||||
this.scrollToBottom();
|
||||
}
|
||||
|
||||
this.printHTML(
|
||||
'<span class="info">Type "help" for available commands.</span>',
|
||||
);
|
||||
|
||||
this.printHTML(
|
||||
'<span class="warning">This site is under contstruction. There\'s nothing of interest here yet.</span>',
|
||||
);
|
||||
|
||||
this.inputContainer.classList.remove("hidden");
|
||||
this.input.focus();
|
||||
}
|
||||
|
||||
// Utility function for delays
|
||||
sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
// Setup event listeners
|
||||
setupEventListeners() {
|
||||
this.input.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
this.executeCommand(this.input.value.trim());
|
||||
this.input.value = "";
|
||||
} else if (e.key === "ArrowUp") {
|
||||
e.preventDefault();
|
||||
this.navigateHistory("up");
|
||||
} else if (e.key === "ArrowDown") {
|
||||
e.preventDefault();
|
||||
this.navigateHistory("down");
|
||||
}
|
||||
});
|
||||
|
||||
// Keep input focused
|
||||
document.addEventListener("click", () => {
|
||||
this.input.focus();
|
||||
});
|
||||
}
|
||||
|
||||
// Command history navigation
|
||||
navigateHistory(direction) {
|
||||
if (this.history.length === 0) return;
|
||||
|
||||
if (direction === "up") {
|
||||
if (this.historyIndex < this.history.length - 1) {
|
||||
this.historyIndex++;
|
||||
this.input.value = this.history[this.historyIndex];
|
||||
}
|
||||
} else if (direction === "down") {
|
||||
if (this.historyIndex > 0) {
|
||||
this.historyIndex--;
|
||||
this.input.value = this.history[this.historyIndex];
|
||||
} else {
|
||||
this.historyIndex = -1;
|
||||
this.input.value = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute command
|
||||
executeCommand(commandString) {
|
||||
if (!commandString) return;
|
||||
|
||||
// Echo the command
|
||||
this.print(`> ${commandString}`);
|
||||
|
||||
// Add to history
|
||||
this.history.unshift(commandString);
|
||||
this.historyIndex = -1;
|
||||
|
||||
// Parse command and arguments
|
||||
const parts = commandString.split(" ");
|
||||
const command = parts[0].toLowerCase();
|
||||
const args = parts.slice(1);
|
||||
|
||||
// Execute command
|
||||
if (this.commands[command]) {
|
||||
try {
|
||||
this.commands[command](args);
|
||||
} catch (error) {
|
||||
this.printError(`Error executing command: ${error.message}`);
|
||||
}
|
||||
} else {
|
||||
this.printError(`Command not found: ${command}`);
|
||||
}
|
||||
|
||||
this.scrollToBottom();
|
||||
}
|
||||
|
||||
// Register a new command
|
||||
registerCommand(name, description, callback) {
|
||||
this.commands[name.toLowerCase()] = callback;
|
||||
this.commands[name.toLowerCase()].description = description;
|
||||
}
|
||||
|
||||
// Print methods
|
||||
print(text, className = "") {
|
||||
const line = document.createElement("div");
|
||||
line.className = `output-line ${className}`;
|
||||
|
||||
if (typeof text === "string") {
|
||||
line.textContent = text;
|
||||
} else {
|
||||
line.appendChild(text);
|
||||
}
|
||||
|
||||
this.output.appendChild(line);
|
||||
}
|
||||
|
||||
printHTML(html, className = "") {
|
||||
const line = document.createElement("div");
|
||||
line.className = `output-line ${className}`;
|
||||
line.innerHTML = html;
|
||||
this.output.appendChild(line);
|
||||
}
|
||||
|
||||
printError(text) {
|
||||
this.print(text, "error");
|
||||
}
|
||||
|
||||
printSuccess(text) {
|
||||
this.print(text, "success");
|
||||
}
|
||||
|
||||
printInfo(text) {
|
||||
this.print(text, "info");
|
||||
}
|
||||
|
||||
printWarning(text) {
|
||||
this.print(text, "warning");
|
||||
}
|
||||
|
||||
scrollToBottom() {
|
||||
this.output.parentElement.scrollTop =
|
||||
this.output.parentElement.scrollHeight;
|
||||
}
|
||||
|
||||
// Clear the terminal
|
||||
clear() {
|
||||
this.output.innerHTML = "";
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue