Fixed spotify
All checks were successful
Docker Deploy / build-and-push (push) Successful in 3m26s

This commit is contained in:
2025-06-19 23:34:44 -06:00
parent 7161584dcd
commit 41614a49a8
8 changed files with 413 additions and 282 deletions

View File

@@ -0,0 +1,250 @@
import type { FileSystemNode } from "./types";
import { getCurrentDirectory, resolvePath } from "./fs";
export interface CommandContext {
currentPath: string;
fileSystem: { [key: string]: FileSystemNode };
setCurrentPath: (path: string) => void;
setIsTrainRunning: (running: boolean) => void;
setTrainPosition: (position: number) => void;
}
export function executeCommand(input: string, context: CommandContext): string {
const trimmedInput = input.trim();
if (!trimmedInput) return "";
const [command, ...args] = trimmedInput.split(" ");
switch (command.toLowerCase()) {
case "help":
return handleHelp();
case "ls":
return handleLs(args, context);
case "cd":
return handleCd(args, context);
case "pwd":
return handlePwd(context);
case "cat":
return handleCat(args, context);
case "tree":
return handleTree(context);
case "clear":
return "";
case "whoami":
return handleWhoami();
case "open":
return handleOpen(args);
case "sl":
return handleSl(context);
default:
return `${command}: command not found. Type 'help' for available commands.`;
}
}
function handleHelp(): string {
return `Available commands:
ls [path] - List directory contents
cd <path> - Change directory
cat <file> - Display file contents
pwd - Show current directory
clear - Clear terminal
tree - Show directory structure
whoami - Display user info
open <path> - Open page in browser (simulated)
help - Show this help message
Navigation:
Use "cd .." to go up one directory
Use "cd /" to go to root directory
File paths can be relative or absolute
Use TAB for auto-completion
Examples:
ls
cd resume
cat about.txt
open /resume
open /talks
cat /talks/README.txt
cd social
cat /tech/README.txt`;
}
function handleLs(args: string[], context: CommandContext): string {
const { currentPath, fileSystem } = context;
const targetPath = args[0] ? resolvePath(currentPath, args[0]) : currentPath;
const pathParts = targetPath.split("/").filter((part: string) => part !== "");
let target = fileSystem["/"];
for (const part of pathParts) {
if (
target?.children &&
target.children[part] &&
target.children[part].type === "directory"
) {
target = target.children[part];
} else if (pathParts.length > 0) {
return `ls: cannot access '${targetPath}': No such file or directory`;
}
}
if (!target?.children) {
return `ls: cannot access '${targetPath}': Not a directory`;
}
const items = Object.values(target.children)
.map((item) => {
const color = item.type === "directory" ? "\x1b[34m" : "\x1b[0m";
const suffix = item.type === "directory" ? "/" : "";
return `${color}${item.name}${suffix}\x1b[0m`;
})
.join(" ");
return items || "Directory is empty";
}
function handleCd(args: string[], context: CommandContext): string {
const { currentPath, fileSystem, setCurrentPath } = context;
const targetPath = args[0] ? resolvePath(currentPath, args[0]) : "/";
const pathParts = targetPath.split("/").filter((part: string) => part !== "");
let current = fileSystem["/"];
for (const part of pathParts) {
if (
current?.children &&
current.children[part] &&
current.children[part].type === "directory"
) {
current = current.children[part];
} else {
return `cd: no such file or directory: ${targetPath}`;
}
}
setCurrentPath(targetPath || "/");
return "";
}
function handlePwd(context: CommandContext): string {
return context.currentPath || "/";
}
function handleCat(args: string[], context: CommandContext): string {
const { currentPath, fileSystem } = context;
if (!args[0]) {
return "cat: missing file argument";
}
const filePath = resolvePath(currentPath, args[0]);
const pathParts = filePath.split("/").filter((part: string) => part !== "");
const fileName = pathParts.pop();
let current = fileSystem["/"];
for (const part of pathParts) {
if (
current?.children &&
current.children[part] &&
current.children[part].type === "directory"
) {
current = current.children[part];
} else {
return `cat: ${filePath}: No such file or directory`;
}
}
if (!fileName || !current?.children || !current.children[fileName]) {
return `cat: ${filePath}: No such file or directory`;
}
const file = current.children[fileName];
if (file.type !== "file") {
return `cat: ${filePath}: Is a directory`;
}
return file.content || "";
}
function handleTree(context: CommandContext): string {
const { fileSystem } = context;
const buildTree = (
node: FileSystemNode,
prefix: string = "",
isLast: boolean = true,
): string => {
let result = "";
if (!node.children) return result;
const entries = Object.entries(node.children);
entries.forEach(([name, child], index) => {
const isLastChild = index === entries.length - 1;
const connector = isLastChild ? "└── " : "├── ";
const color = child.type === "directory" ? "\x1b[34m" : "\x1b[0m";
const suffix = child.type === "directory" ? "/" : "";
result += `${prefix}${connector}${color}${name}${suffix}\x1b[0m\n`;
if (child.type === "directory") {
const newPrefix = prefix + (isLastChild ? " " : "│ ");
result += buildTree(child, newPrefix, isLastChild);
}
});
return result;
};
return ".\n" + buildTree(fileSystem["/"]);
}
function handleWhoami(): string {
return "guest@atri.dad";
}
function handleOpen(args: string[]): string {
const path = args[0];
if (!path) {
return "open: missing path argument";
}
let url = "";
if (path === "/resume" || path.startsWith("/resume")) {
url = "/resume";
} else if (path === "/projects" || path.startsWith("/projects")) {
url = "/projects";
} else if (path === "/posts" || path.startsWith("/posts")) {
url = "/posts";
} else if (path === "/talks" || path.startsWith("/talks")) {
url = "/talks";
} else if (path === "/" || path === "/about.txt") {
url = "/";
} else {
return `open: cannot open '${path}': No associated page`;
}
window.open(url, "_blank");
return `Opening ${url} in new tab...`;
}
function handleSl(context: CommandContext): string {
const { setIsTrainRunning, setTrainPosition } = context;
setIsTrainRunning(true);
setTrainPosition(100);
const animateTrain = () => {
let position = 100;
const interval = setInterval(() => {
position -= 1.5;
setTrainPosition(position);
if (position < -50) {
clearInterval(interval);
setIsTrainRunning(false);
}
}, 60);
};
setTimeout(animateTrain, 100);
return "";
}