|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Mini Linux OS</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
<style> |
|
@keyframes blink { |
|
0%, 100% { opacity: 1; } |
|
50% { opacity: 0; } |
|
} |
|
.cursor-blink { |
|
animation: blink 1s infinite; |
|
} |
|
.window { |
|
box-shadow: 0 0 15px rgba(0, 0, 0, 0.3); |
|
} |
|
.file-icon:hover { |
|
transform: scale(1.05); |
|
} |
|
.terminal-line::before { |
|
content: "> "; |
|
color: #4ade80; |
|
font-weight: bold; |
|
} |
|
.resize-handle { |
|
width: 100%; |
|
height: 5px; |
|
background-color: rgba(0, 0, 0, 0.1); |
|
cursor: ns-resize; |
|
} |
|
.process-bar { |
|
transition: width 0.5s ease; |
|
} |
|
.directory-item:hover { |
|
background-color: rgba(74, 222, 128, 0.1); |
|
} |
|
.file-item:hover { |
|
background-color: rgba(96, 165, 250, 0.1); |
|
} |
|
</style> |
|
</head> |
|
<body class="bg-gray-900 text-gray-200 h-screen overflow-hidden font-mono"> |
|
|
|
<div class="h-full flex flex-col"> |
|
|
|
<div class="bg-gray-800 px-4 py-2 flex justify-between items-center border-b border-gray-700"> |
|
<div class="flex items-center space-x-4"> |
|
<span class="font-bold text-green-400">MiniLinux</span> |
|
<div class="hidden md:flex space-x-2"> |
|
<button class="px-3 py-1 hover:bg-gray-700 rounded">File</button> |
|
<button class="px-3 py-1 hover:bg-gray-700 rounded">Edit</button> |
|
<button class="px-3 py-1 hover:bg-gray-700 rounded">View</button> |
|
<button class="px-3 py-1 hover:bg-gray-700 rounded">Help</button> |
|
</div> |
|
</div> |
|
<div class="flex items-center space-x-2"> |
|
<span id="clock" class="px-3 py-1 bg-gray-700 rounded">00:00:00</span> |
|
<button class="w-8 h-8 flex items-center justify-center hover:bg-gray-700 rounded-full"> |
|
<i class="fas fa-power-off"></i> |
|
</button> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="flex-grow relative p-4"> |
|
<div class="absolute top-4 left-4 flex flex-col items-center w-20 text-center cursor-pointer file-icon"> |
|
<div class="w-12 h-12 bg-blue-500 rounded flex items-center justify-center mb-1"> |
|
<i class="fas fa-folder text-white text-2xl"></i> |
|
</div> |
|
<span class="text-xs">Home</span> |
|
</div> |
|
<div class="absolute top-4 left-28 flex flex-col items-center w-20 text-center cursor-pointer file-icon"> |
|
<div class="w-12 h-12 bg-green-500 rounded flex items-center justify-center mb-1"> |
|
<i class="fas fa-terminal text-white text-2xl"></i> |
|
</div> |
|
<span class="text-xs">Terminal</span> |
|
</div> |
|
<div class="absolute top-28 left-4 flex flex-col items-center w-20 text-center cursor-pointer file-icon"> |
|
<div class="w-12 h-12 bg-purple-500 rounded flex items-center justify-center mb-1"> |
|
<i class="fas fa-file-alt text-white text-2xl"></i> |
|
</div> |
|
<span class="text-xs">Documents</span> |
|
</div> |
|
<div class="absolute top-28 left-28 flex flex-col items-center w-20 text-center cursor-pointer file-icon"> |
|
<div class="w-12 h-12 bg-yellow-500 rounded flex items-center justify-center mb-1"> |
|
<i class="fas fa-chart-bar text-white text-2xl"></i> |
|
</div> |
|
<span class="text-xs">System</span> |
|
</div> |
|
|
|
|
|
<div id="terminal-window" class="window absolute top-20 left-20 w-3/4 md:w-1/2 bg-gray-800 rounded-lg overflow-hidden z-10"> |
|
<div class="bg-gray-700 px-3 py-2 flex justify-between items-center"> |
|
<div class="flex items-center space-x-2"> |
|
<i class="fas fa-terminal text-green-400"></i> |
|
<span>Terminal</span> |
|
</div> |
|
<div class="flex space-x-2"> |
|
<button class="w-5 h-5 flex items-center justify-center hover:bg-gray-600 rounded"> |
|
<i class="fas fa-minus text-xs"></i> |
|
</button> |
|
<button class="w-5 h-5 flex items-center justify-center hover:bg-gray-600 rounded"> |
|
<i class="fas fa-square text-xs"></i> |
|
</button> |
|
<button class="w-5 h-5 flex items-center justify-center hover:bg-red-500 rounded"> |
|
<i class="fas fa-times text-xs"></i> |
|
</button> |
|
</div> |
|
</div> |
|
<div class="resize-handle"></div> |
|
<div id="terminal-content" class="p-3 h-64 overflow-y-auto"> |
|
<div class="text-green-400 mb-2">Welcome to MiniLinux Terminal</div> |
|
<div class="text-gray-400 mb-4">Type 'help' to see available commands</div> |
|
<div id="terminal-history"></div> |
|
<div class="flex items-center"> |
|
<span id="terminal-prompt" class="text-green-400 mr-2">user@minilinux:~$</span> |
|
<input id="terminal-input" type="text" class="bg-transparent border-none outline-none flex-grow" autofocus> |
|
<span class="cursor-blink">|</span> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div id="files-window" class="window absolute top-40 left-40 w-3/4 md:w-1/2 bg-gray-800 rounded-lg overflow-hidden hidden"> |
|
<div class="bg-gray-700 px-3 py-2 flex justify-between items-center"> |
|
<div class="flex items-center space-x-2"> |
|
<i class="fas fa-folder text-blue-400"></i> |
|
<span id="files-window-title">File Explorer</span> |
|
</div> |
|
<div class="flex space-x-2"> |
|
<button class="w-5 h-5 flex items-center justify-center hover:bg-gray-600 rounded"> |
|
<i class="fas fa-minus text-xs"></i> |
|
</button> |
|
<button class="w-5 h-5 flex items-center justify-center hover:bg-gray-600 rounded"> |
|
<i class="fas fa-square text-xs"></i> |
|
</button> |
|
<button class="w-5 h-5 flex items-center justify-center hover:bg-red-500 rounded"> |
|
<i class="fas fa-times text-xs"></i> |
|
</button> |
|
</div> |
|
</div> |
|
<div class="resize-handle"></div> |
|
<div class="p-3 h-64 overflow-y-auto"> |
|
<div class="flex items-center mb-2"> |
|
<button id="files-back" class="mr-3 text-gray-400 hover:text-white cursor-pointer disabled:opacity-50" disabled> |
|
<i class="fas fa-arrow-left"></i> |
|
</button> |
|
<button id="files-forward" class="mr-3 text-gray-400 hover:text-white cursor-pointer disabled:opacity-50" disabled> |
|
<i class="fas fa-arrow-right"></i> |
|
</button> |
|
<button id="files-home" class="mr-3 text-gray-400 hover:text-white cursor-pointer"> |
|
<i class="fas fa-home"></i> |
|
</button> |
|
<div id="files-path" class="bg-gray-700 px-2 py-1 rounded text-sm flex-grow">/home/user</div> |
|
</div> |
|
<div id="files-content" class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4"> |
|
|
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div id="system-window" class="window absolute top-60 left-60 w-3/4 md:w-1/2 bg-gray-800 rounded-lg overflow-hidden hidden"> |
|
<div class="bg-gray-700 px-3 py-2 flex justify-between items-center"> |
|
<div class="flex items-center space-x-2"> |
|
<i class="fas fa-chart-bar text-yellow-400"></i> |
|
<span>System Monitor</span> |
|
</div> |
|
<div class="flex space-x-2"> |
|
<button class="w-5 h-5 flex items-center justify-center hover:bg-gray-600 rounded"> |
|
<i class="fas fa-minus text-xs"></i> |
|
</button> |
|
<button class="w-5 h-5 flex items-center justify-center hover:bg-gray-600 rounded"> |
|
<i class="fas fa-square text-xs"></i> |
|
</button> |
|
<button class="w-5 h-5 flex items-center justify-center hover:bg-red-500 rounded"> |
|
<i class="fas fa-times text-xs"></i> |
|
</button> |
|
</div> |
|
</div> |
|
<div class="resize-handle"></div> |
|
<div class="p-3 h-64 overflow-y-auto"> |
|
<div class="mb-4"> |
|
<div class="flex justify-between mb-1"> |
|
<span>CPU Usage</span> |
|
<span id="cpu-usage">0%</span> |
|
</div> |
|
<div class="w-full bg-gray-700 rounded-full h-2.5"> |
|
<div id="cpu-bar" class="bg-blue-500 h-2.5 rounded-full process-bar" style="width: 0%"></div> |
|
</div> |
|
</div> |
|
<div class="mb-4"> |
|
<div class="flex justify-between mb-1"> |
|
<span>Memory Usage</span> |
|
<span id="mem-usage">0%</span> |
|
</div> |
|
<div class="w-full bg-gray-700 rounded-full h-2.5"> |
|
<div id="mem-bar" class="bg-purple-500 h-2.5 rounded-full process-bar" style="width: 0%"></div> |
|
</div> |
|
</div> |
|
<div class="mb-4"> |
|
<div class="flex justify-between mb-1"> |
|
<span>Disk Usage</span> |
|
<span id="disk-usage">0%</span> |
|
</div> |
|
<div class="w-full bg-gray-700 rounded-full h-2.5"> |
|
<div id="disk-bar" class="bg-green-500 h-2.5 rounded-full process-bar" style="width: 0%"></div> |
|
</div> |
|
</div> |
|
<div> |
|
<h3 class="font-bold mb-2">Running Processes</h3> |
|
<div class="bg-gray-700 rounded p-2"> |
|
<div class="grid grid-cols-4 gap-2 text-sm mb-1 font-bold border-b border-gray-600 pb-1"> |
|
<span>PID</span> |
|
<span>Name</span> |
|
<span>CPU</span> |
|
<span>Memory</span> |
|
</div> |
|
<div id="process-list" class="text-sm"> |
|
|
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="bg-gray-800 px-3 py-2 flex items-center space-x-3 border-t border-gray-700"> |
|
<button id="terminal-launcher" class="w-10 h-10 flex items-center justify-center hover:bg-gray-700 rounded"> |
|
<i class="fas fa-terminal text-green-400"></i> |
|
</button> |
|
<button id="files-launcher" class="w-10 h-10 flex items-center justify-center hover:bg-gray-700 rounded"> |
|
<i class="fas fa-folder text-blue-400"></i> |
|
</button> |
|
<button id="system-launcher" class="w-10 h-10 flex items-center justify-center hover:bg-gray-700 rounded"> |
|
<i class="fas fa-chart-bar text-yellow-400"></i> |
|
</button> |
|
<div class="flex-grow"></div> |
|
<div class="flex items-center space-x-2"> |
|
<span id="network-status" class="px-2 py-1 bg-gray-700 rounded text-xs flex items-center"> |
|
<i class="fas fa-wifi mr-1"></i> |
|
<span>Connected</span> |
|
</span> |
|
<span id="battery-status" class="px-2 py-1 bg-gray-700 rounded text-xs flex items-center"> |
|
<i class="fas fa-battery-full mr-1"></i> |
|
<span>100%</span> |
|
</span> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
|
|
const fileSystem = { |
|
name: '/', |
|
type: 'directory', |
|
children: [ |
|
{ |
|
name: 'bin', |
|
type: 'directory', |
|
children: [ |
|
{ name: 'bash', type: 'executable', size: '1.2MB' }, |
|
{ name: 'ls', type: 'executable', size: '56KB' }, |
|
{ name: 'cat', type: 'executable', size: '48KB' } |
|
] |
|
}, |
|
{ |
|
name: 'etc', |
|
type: 'directory', |
|
children: [ |
|
{ name: 'passwd', type: 'file', size: '2KB' }, |
|
{ name: 'hosts', type: 'file', size: '1KB' }, |
|
{ |
|
name: 'network', |
|
type: 'directory', |
|
children: [ |
|
{ name: 'interfaces', type: 'file', size: '3KB' } |
|
] |
|
} |
|
] |
|
}, |
|
{ |
|
name: 'home', |
|
type: 'directory', |
|
children: [ |
|
{ |
|
name: 'user', |
|
type: 'directory', |
|
children: [ |
|
{ |
|
name: 'Documents', |
|
type: 'directory', |
|
children: [ |
|
{ name: 'notes.txt', type: 'file', size: '4KB', content: 'These are my personal notes.\n\nTodo:\n- Learn JavaScript\n- Build a Linux simulator\n- Have fun!' }, |
|
{ name: 'report.pdf', type: 'file', size: '2.4MB' } |
|
] |
|
}, |
|
{ |
|
name: 'Downloads', |
|
type: 'directory', |
|
children: [ |
|
{ name: 'linux_handbook.pdf', type: 'file', size: '5.2MB' } |
|
] |
|
}, |
|
{ |
|
name: 'Pictures', |
|
type: 'directory', |
|
children: [ |
|
{ name: 'vacation.jpg', type: 'file', size: '3.8MB' } |
|
] |
|
}, |
|
{ name: '.bashrc', type: 'file', size: '2KB', content: '# User specific aliases and functions\nalias ll=\'ls -la\'\nalias ..=\'cd ..\'' }, |
|
{ name: 'todo.txt', type: 'file', size: '1KB', content: '- Buy groceries\n- Call mom\n- Finish project' } |
|
] |
|
} |
|
] |
|
}, |
|
{ |
|
name: 'usr', |
|
type: 'directory', |
|
children: [ |
|
{ |
|
name: 'bin', |
|
type: 'directory', |
|
children: [ |
|
{ name: 'python', type: 'executable', size: '4.8MB' }, |
|
{ name: 'gcc', type: 'executable', size: '3.2MB' } |
|
] |
|
}, |
|
{ |
|
name: 'lib', |
|
type: 'directory', |
|
children: [ |
|
{ name: 'libc.so.6', type: 'library', size: '2.1MB' } |
|
] |
|
} |
|
] |
|
}, |
|
{ |
|
name: 'var', |
|
type: 'directory', |
|
children: [ |
|
{ |
|
name: 'log', |
|
type: 'directory', |
|
children: [ |
|
{ name: 'syslog', type: 'file', size: '12KB' } |
|
] |
|
} |
|
] |
|
}, |
|
{ name: 'README.md', type: 'file', size: '1KB', content: '# MiniLinux\n\nThis is a simulated Linux environment running in your browser.' } |
|
] |
|
}; |
|
|
|
|
|
let currentDir = ['home', 'user']; |
|
let dirHistory = []; |
|
let dirHistoryIndex = -1; |
|
|
|
|
|
function updateClock() { |
|
const now = new Date(); |
|
const timeString = now.toLocaleTimeString(); |
|
document.getElementById('clock').textContent = timeString; |
|
} |
|
setInterval(updateClock, 1000); |
|
updateClock(); |
|
|
|
|
|
const terminalInput = document.getElementById('terminal-input'); |
|
const terminalHistory = document.getElementById('terminal-history'); |
|
const terminalPrompt = document.getElementById('terminal-prompt'); |
|
|
|
|
|
function updateTerminalPrompt() { |
|
const path = currentDir.length > 0 ? currentDir.join('/') : '~'; |
|
terminalPrompt.textContent = `user@minilinux:${path}$`; |
|
} |
|
|
|
|
|
function getCurrentDirectory() { |
|
let dir = fileSystem; |
|
for (const part of currentDir) { |
|
const found = dir.children.find(child => child.name === part && child.type === 'directory'); |
|
if (!found) return null; |
|
dir = found; |
|
} |
|
return dir; |
|
} |
|
|
|
|
|
const commands = { |
|
help: () => { |
|
return `Available commands:<br> |
|
- help: Show this help message<br> |
|
- ls: List directory contents<br> |
|
- clear: Clear the terminal<br> |
|
- date: Show current date and time<br> |
|
- echo [text]: Print text to terminal<br> |
|
- neofetch: Show system information<br> |
|
- cpu: Show CPU usage<br> |
|
- mem: Show memory usage<br> |
|
- pwd: Print working directory<br> |
|
- cd [dir]: Change directory<br> |
|
- cat [file]: Display file contents<br> |
|
- mkdir [dir]: Create new directory<br> |
|
- touch [file]: Create new file<br> |
|
- rm [file]: Remove file<br> |
|
- rmdir [dir]: Remove directory<br> |
|
- shutdown: Power off the system`; |
|
}, |
|
ls: (args) => { |
|
const dir = getCurrentDirectory(); |
|
if (!dir) return `ls: cannot access '${currentDir.join('/')}': No such file or directory`; |
|
|
|
let output = ''; |
|
const showHidden = args.includes('-a'); |
|
const longFormat = args.includes('-l'); |
|
|
|
dir.children.forEach(child => { |
|
if (!showHidden && child.name.startsWith('.')) return; |
|
|
|
if (longFormat) { |
|
const typeChar = child.type === 'directory' ? 'd' : '-'; |
|
const size = child.size || '0'; |
|
output += `${typeChar}rw-r--r-- 1 user user ${size.padEnd(8)} ${child.name}<br>`; |
|
} else { |
|
output += child.name + ' '; |
|
} |
|
}); |
|
|
|
return output || (longFormat ? '' : '(empty directory)'); |
|
}, |
|
clear: () => { |
|
terminalHistory.innerHTML = ''; |
|
return ''; |
|
}, |
|
date: () => { |
|
return new Date().toString(); |
|
}, |
|
echo: (args) => { |
|
return args.join(' '); |
|
}, |
|
neofetch: () => { |
|
return `user@minilinux<br> |
|
-----------------<br> |
|
OS: MiniLinux 1.0<br> |
|
Host: Web Browser<br> |
|
Kernel: 5.15.0-76-generic<br> |
|
Uptime: 2 hours, 15 minutes<br> |
|
Shell: bash 5.1.16<br> |
|
CPU: Virtual CPU @ 2.5GHz<br> |
|
Memory: 1024MB / 2048MB (50%)<br> |
|
Disk: 15GB / 50GB (30%)`; |
|
}, |
|
cpu: () => { |
|
const usage = Math.floor(Math.random() * 100); |
|
return `CPU usage: ${usage}%`; |
|
}, |
|
mem: () => { |
|
const usage = Math.floor(Math.random() * 100); |
|
const total = 2048; |
|
const used = Math.floor(total * usage / 100); |
|
return `Memory: ${used}MB / ${total}MB (${usage}%)`; |
|
}, |
|
pwd: () => { |
|
return currentDir.length > 0 ? '/' + currentDir.join('/') : '/'; |
|
}, |
|
cd: (args) => { |
|
if (args.length === 0) { |
|
|
|
currentDir = ['home', 'user']; |
|
updateTerminalPrompt(); |
|
updateFilesWindow(); |
|
return ''; |
|
} |
|
|
|
const target = args[0]; |
|
let newDir; |
|
|
|
if (target === '..') { |
|
|
|
if (currentDir.length > 0) { |
|
currentDir.pop(); |
|
} |
|
} else if (target === '/') { |
|
|
|
currentDir = []; |
|
} else if (target.startsWith('/')) { |
|
|
|
const parts = target.split('/').filter(p => p); |
|
currentDir = parts; |
|
} else { |
|
|
|
newDir = [...currentDir, ...target.split('/')]; |
|
} |
|
|
|
|
|
if (newDir) { |
|
let dir = fileSystem; |
|
for (const part of newDir) { |
|
const found = dir.children.find(child => child.name === part && child.type === 'directory'); |
|
if (!found) { |
|
return `cd: no such file or directory: ${target}`; |
|
} |
|
dir = found; |
|
} |
|
currentDir = newDir; |
|
} |
|
|
|
updateTerminalPrompt(); |
|
updateFilesWindow(); |
|
return ''; |
|
}, |
|
cat: (args) => { |
|
if (args.length === 0) { |
|
return 'cat: missing file operand'; |
|
} |
|
|
|
const filename = args[0]; |
|
const dir = getCurrentDirectory(); |
|
if (!dir) return `cat: ${currentDir.join('/')}: No such file or directory`; |
|
|
|
const file = dir.children.find(child => child.name === filename && child.type === 'file'); |
|
if (!file) { |
|
return `cat: ${filename}: No such file or directory`; |
|
} |
|
|
|
return file.content || '(empty file)'; |
|
}, |
|
mkdir: (args) => { |
|
if (args.length === 0) { |
|
return 'mkdir: missing operand'; |
|
} |
|
|
|
const dirname = args[0]; |
|
const dir = getCurrentDirectory(); |
|
if (!dir) return `mkdir: cannot create directory '${dirname}': No such file or directory`; |
|
|
|
if (dir.children.some(child => child.name === dirname)) { |
|
return `mkdir: cannot create directory '${dirname}': File exists`; |
|
} |
|
|
|
dir.children.push({ |
|
name: dirname, |
|
type: 'directory', |
|
children: [] |
|
}); |
|
|
|
updateFilesWindow(); |
|
return ''; |
|
}, |
|
touch: (args) => { |
|
if (args.length === 0) { |
|
return 'touch: missing file operand'; |
|
} |
|
|
|
const filename = args[0]; |
|
const dir = getCurrentDirectory(); |
|
if (!dir) return `touch: cannot touch '${filename}': No such file or directory`; |
|
|
|
if (dir.children.some(child => child.name === filename)) { |
|
return ''; |
|
} |
|
|
|
dir.children.push({ |
|
name: filename, |
|
type: 'file', |
|
size: '0KB' |
|
}); |
|
|
|
updateFilesWindow(); |
|
return ''; |
|
}, |
|
rm: (args) => { |
|
if (args.length === 0) { |
|
return 'rm: missing operand'; |
|
} |
|
|
|
const filename = args[0]; |
|
const dir = getCurrentDirectory(); |
|
if (!dir) return `rm: cannot remove '${filename}': No such file or directory`; |
|
|
|
const index = dir.children.findIndex(child => child.name === filename && child.type === 'file'); |
|
if (index === -1) { |
|
return `rm: cannot remove '${filename}': No such file or directory`; |
|
} |
|
|
|
dir.children.splice(index, 1); |
|
updateFilesWindow(); |
|
return ''; |
|
}, |
|
rmdir: (args) => { |
|
if (args.length === 0) { |
|
return 'rmdir: missing operand'; |
|
} |
|
|
|
const dirname = args[0]; |
|
const dir = getCurrentDirectory(); |
|
if (!dir) return `rmdir: failed to remove '${dirname}': No such file or directory`; |
|
|
|
const target = dir.children.find(child => child.name === dirname && child.type === 'directory'); |
|
if (!target) { |
|
return `rmdir: failed to remove '${dirname}': No such file or directory`; |
|
} |
|
|
|
if (target.children.length > 0) { |
|
return `rmdir: failed to remove '${dirname}': Directory not empty`; |
|
} |
|
|
|
dir.children = dir.children.filter(child => child !== target); |
|
updateFilesWindow(); |
|
return ''; |
|
}, |
|
shutdown: () => { |
|
setTimeout(() => { |
|
alert('System is shutting down...'); |
|
document.body.innerHTML = '<div class="h-screen w-screen bg-black flex items-center justify-center"><div class="text-white text-2xl">System halted. It\'s now safe to close this window.</div></div>'; |
|
}, 1000); |
|
return 'Shutting down system...'; |
|
} |
|
}; |
|
|
|
terminalInput.addEventListener('keydown', (e) => { |
|
if (e.key === 'Enter') { |
|
const input = terminalInput.value.trim(); |
|
terminalInput.value = ''; |
|
|
|
|
|
const commandLine = document.createElement('div'); |
|
commandLine.className = 'mb-2'; |
|
commandLine.innerHTML = `<span class="text-green-400">${terminalPrompt.textContent}</span> ${input}`; |
|
terminalHistory.appendChild(commandLine); |
|
|
|
|
|
const parts = input.split(' '); |
|
const cmd = parts[0].toLowerCase(); |
|
const args = parts.slice(1); |
|
|
|
let output = ''; |
|
if (commands[cmd]) { |
|
output = commands[cmd](args); |
|
} else if (cmd) { |
|
output = `Command not found: ${cmd}. Type 'help' for available commands.`; |
|
} |
|
|
|
if (output) { |
|
const outputElement = document.createElement('div'); |
|
outputElement.className = 'mb-2 terminal-line'; |
|
outputElement.innerHTML = output; |
|
terminalHistory.appendChild(outputElement); |
|
} |
|
|
|
|
|
terminalHistory.scrollTop = terminalHistory.scrollHeight; |
|
} |
|
}); |
|
|
|
|
|
function updateFilesWindow() { |
|
const dir = getCurrentDirectory(); |
|
const filesContent = document.getElementById('files-content'); |
|
const filesPath = document.getElementById('files-path'); |
|
const filesWindowTitle = document.getElementById('files-window-title'); |
|
|
|
|
|
const path = currentDir.length > 0 ? '/' + currentDir.join('/') : '/'; |
|
filesPath.textContent = path; |
|
filesWindowTitle.textContent = `File Explorer - ${path}`; |
|
|
|
|
|
document.getElementById('files-back').disabled = dirHistoryIndex <= 0; |
|
document.getElementById('files-forward').disabled = dirHistoryIndex >= dirHistory.length - 1; |
|
|
|
|
|
filesContent.innerHTML = ''; |
|
|
|
if (!dir) { |
|
filesContent.innerHTML = '<div class="text-red-400">Error: Directory not found</div>'; |
|
return; |
|
} |
|
|
|
|
|
if (currentDir.length > 0) { |
|
const parentItem = document.createElement('div'); |
|
parentItem.className = 'file-icon flex flex-col items-center p-2 hover:bg-gray-700 rounded cursor-pointer'; |
|
parentItem.innerHTML = ` |
|
<i class="fas fa-level-up-alt text-gray-400 text-3xl mb-1"></i> |
|
<span class="text-xs text-center">..</span> |
|
`; |
|
parentItem.addEventListener('dblclick', () => { |
|
navigateToParentDirectory(); |
|
}); |
|
filesContent.appendChild(parentItem); |
|
} |
|
|
|
|
|
dir.children.forEach(child => { |
|
const item = document.createElement('div'); |
|
item.className = 'file-icon flex flex-col items-center p-2 hover:bg-gray-700 rounded cursor-pointer'; |
|
|
|
let icon, color; |
|
if (child.type === 'directory') { |
|
icon = 'fa-folder'; |
|
color = 'text-blue-400'; |
|
} else if (child.type === 'executable') { |
|
icon = 'fa-file-code'; |
|
color = 'text-green-400'; |
|
} else { |
|
icon = 'fa-file'; |
|
color = 'text-gray-300'; |
|
} |
|
|
|
item.innerHTML = ` |
|
<i class="fas ${icon} ${color} text-3xl mb-1"></i> |
|
<span class="text-xs text-center">${child.name}</span> |
|
`; |
|
|
|
if (child.type === 'directory') { |
|
item.addEventListener('dblclick', () => { |
|
navigateToDirectory(child.name); |
|
}); |
|
} else { |
|
item.addEventListener('dblclick', () => { |
|
|
|
const content = child.content || `This is a ${child.type} file named ${child.name}`; |
|
alert(`File: ${child.name}\n\n${content}`); |
|
}); |
|
} |
|
|
|
filesContent.appendChild(item); |
|
}); |
|
} |
|
|
|
function navigateToDirectory(dirName) { |
|
dirHistory = dirHistory.slice(0, dirHistoryIndex + 1); |
|
dirHistory.push([...currentDir]); |
|
dirHistoryIndex++; |
|
|
|
currentDir.push(dirName); |
|
updateTerminalPrompt(); |
|
updateFilesWindow(); |
|
} |
|
|
|
function navigateToParentDirectory() { |
|
dirHistory = dirHistory.slice(0, dirHistoryIndex + 1); |
|
dirHistory.push([...currentDir]); |
|
dirHistoryIndex++; |
|
|
|
if (currentDir.length > 0) { |
|
currentDir.pop(); |
|
} |
|
updateTerminalPrompt(); |
|
updateFilesWindow(); |
|
} |
|
|
|
|
|
document.getElementById('files-back').addEventListener('click', () => { |
|
if (dirHistoryIndex > 0) { |
|
dirHistoryIndex--; |
|
currentDir = [...dirHistory[dirHistoryIndex]]; |
|
updateTerminalPrompt(); |
|
updateFilesWindow(); |
|
} |
|
}); |
|
|
|
document.getElementById('files-forward').addEventListener('click', () => { |
|
if (dirHistoryIndex < dirHistory.length - 1) { |
|
dirHistoryIndex++; |
|
currentDir = [...dirHistory[dirHistoryIndex]]; |
|
updateTerminalPrompt(); |
|
updateFilesWindow(); |
|
} |
|
}); |
|
|
|
document.getElementById('files-home').addEventListener('click', () => { |
|
dirHistory = dirHistory.slice(0, dirHistoryIndex + 1); |
|
dirHistory.push([...currentDir]); |
|
dirHistoryIndex++; |
|
|
|
currentDir = ['home', 'user']; |
|
updateTerminalPrompt(); |
|
updateFilesWindow(); |
|
}); |
|
|
|
|
|
function toggleWindow(windowId) { |
|
const window = document.getElementById(windowId); |
|
window.classList.toggle('hidden'); |
|
if (!window.classList.contains('hidden')) { |
|
|
|
document.querySelectorAll('.window').forEach(w => { |
|
w.style.zIndex = '10'; |
|
}); |
|
window.style.zIndex = '20'; |
|
|
|
|
|
if (windowId === 'files-window') { |
|
updateFilesWindow(); |
|
} else if (windowId === 'system-window') { |
|
updateSystemStats(); |
|
} |
|
} |
|
} |
|
|
|
document.getElementById('terminal-launcher').addEventListener('click', () => { |
|
toggleWindow('terminal-window'); |
|
document.getElementById('terminal-input').focus(); |
|
}); |
|
|
|
document.getElementById('files-launcher').addEventListener('click', () => { |
|
toggleWindow('files-window'); |
|
}); |
|
|
|
document.getElementById('system-launcher').addEventListener('click', () => { |
|
toggleWindow('system-window'); |
|
updateSystemStats(); |
|
}); |
|
|
|
|
|
document.querySelectorAll('.file-icon').forEach((icon, index) => { |
|
icon.addEventListener('dblclick', () => { |
|
if (index === 0) { |
|
|
|
dirHistory = dirHistory.slice(0, dirHistoryIndex + 1); |
|
dirHistory.push([...currentDir]); |
|
dirHistoryIndex++; |
|
|
|
currentDir = ['home', 'user']; |
|
updateTerminalPrompt(); |
|
toggleWindow('files-window'); |
|
} |
|
if (index === 1) { |
|
toggleWindow('terminal-window'); |
|
document.getElementById('terminal-input').focus(); |
|
} |
|
if (index === 3) toggleWindow('system-window'); |
|
}); |
|
}); |
|
|
|
|
|
function updateSystemStats() { |
|
|
|
const cpuUsage = Math.floor(Math.random() * 100); |
|
document.getElementById('cpu-usage').textContent = `${cpuUsage}%`; |
|
document.getElementById('cpu-bar').style.width = `${cpuUsage}%`; |
|
|
|
|
|
const memUsage = 30 + Math.floor(Math.random() * 50); |
|
document.getElementById('mem-usage').textContent = `${memUsage}%`; |
|
document.getElementById('mem-bar').style.width = `${memUsage}%`; |
|
|
|
|
|
const diskUsage = 10 + Math.floor(Math.random() * 40); |
|
document.getElementById('disk-usage').textContent = `${diskUsage}%`; |
|
document.getElementById('disk-bar').style.width = `${diskUsage}%`; |
|
|
|
|
|
const processes = [ |
|
{ pid: 1234, name: 'bash', cpu: Math.floor(Math.random() * 5), mem: Math.floor(Math.random() * 3) }, |
|
{ pid: 2345, name: 'systemd', cpu: Math.floor(Math.random() * 3), mem: 5 + Math.floor(Math.random() * 5) }, |
|
{ pid: 3456, name: 'Xorg', cpu: 10 + Math.floor(Math.random() * 15), mem: 50 + Math.floor(Math.random() * 30) }, |
|
{ pid: 4567, name: 'chrome', cpu: 20 + Math.floor(Math.random() * 30), mem: 100 + Math.floor(Math.random() * 150) }, |
|
{ pid: 5678, name: 'node', cpu: 5 + Math.floor(Math.random() * 10), mem: 30 + Math.floor(Math.random() * 20) } |
|
]; |
|
|
|
const processList = document.getElementById('process-list'); |
|
processList.innerHTML = ''; |
|
|
|
processes.forEach(proc => { |
|
const procElement = document.createElement('div'); |
|
procElement.className = 'grid grid-cols-4 gap-2 text-sm mb-1'; |
|
procElement.innerHTML = ` |
|
<span>${proc.pid}</span> |
|
<span>${proc.name}</span> |
|
<span>${proc.cpu}%</span> |
|
<span>${proc.mem}MB</span> |
|
`; |
|
processList.appendChild(procElement); |
|
}); |
|
} |
|
|
|
|
|
setInterval(() => { |
|
if (!document.getElementById('system-window').classList.contains('hidden')) { |
|
updateSystemStats(); |
|
} |
|
}, 3000); |
|
|
|
|
|
let batteryLevel = 100; |
|
setInterval(() => { |
|
batteryLevel = Math.max(0, batteryLevel - 0.1); |
|
const batteryIcon = batteryLevel > 80 ? 'fa-battery-full' : |
|
batteryLevel > 60 ? 'fa-battery-three-quarters' : |
|
batteryLevel > 40 ? 'fa-battery-half' : |
|
batteryLevel > 20 ? 'fa-battery-quarter' : 'fa-battery-empty'; |
|
|
|
document.getElementById('battery-status').innerHTML = ` |
|
<i class="fas ${batteryIcon} mr-1"></i> |
|
<span>${Math.floor(batteryLevel)}%</span> |
|
`; |
|
}, 10000); |
|
|
|
|
|
document.querySelectorAll('.window').forEach(window => { |
|
const header = window.querySelector('.bg-gray-700'); |
|
|
|
header.addEventListener('mousedown', (e) => { |
|
if (e.target.tagName === 'BUTTON' || e.target.tagName === 'I') return; |
|
|
|
const startX = e.clientX; |
|
const startY = e.clientY; |
|
const startLeft = parseInt(window.style.left || '0'); |
|
const startTop = parseInt(window.style.top || '0'); |
|
|
|
function moveWindow(e) { |
|
const dx = e.clientX - startX; |
|
const dy = e.clientY - startY; |
|
window.style.left = (startLeft + dx) + 'px'; |
|
window.style.top = (startTop + dy) + 'px'; |
|
} |
|
|
|
function stopMoving() { |
|
document.removeEventListener('mousemove', moveWindow); |
|
document.removeEventListener('mouseup', stopMoving); |
|
} |
|
|
|
document.addEventListener('mousemove', moveWindow); |
|
document.addEventListener('mouseup', stopMoving); |
|
}); |
|
}); |
|
|
|
|
|
document.querySelectorAll('.window').forEach(window => { |
|
const closeBtn = window.querySelectorAll('button')[2]; |
|
const minimizeBtn = window.querySelectorAll('button')[0]; |
|
const maximizeBtn = window.querySelectorAll('button')[1]; |
|
|
|
closeBtn.addEventListener('click', () => { |
|
window.classList.add('hidden'); |
|
}); |
|
|
|
minimizeBtn.addEventListener('click', () => { |
|
const content = window.querySelector('.h-64'); |
|
if (content.style.display === 'none') { |
|
content.style.display = ''; |
|
} else { |
|
content.style.display = 'none'; |
|
} |
|
}); |
|
|
|
maximizeBtn.addEventListener('click', () => { |
|
if (window.style.width === '90%') { |
|
window.style.width = ''; |
|
window.style.height = ''; |
|
window.style.left = ''; |
|
window.style.top = ''; |
|
} else { |
|
window.style.width = '90%'; |
|
window.style.height = '80%'; |
|
window.style.left = '5%'; |
|
window.style.top = '10%'; |
|
} |
|
}); |
|
}); |
|
|
|
|
|
document.querySelectorAll('.resize-handle').forEach(handle => { |
|
handle.addEventListener('mousedown', (e) => { |
|
const window = handle.parentElement; |
|
const startY = e.clientY; |
|
const startHeight = parseInt(window.style.height || window.offsetHeight); |
|
|
|
function resizeWindow(e) { |
|
const dy = e.clientY - startY; |
|
const newHeight = startHeight + dy; |
|
window.style.height = Math.max(200, newHeight) + 'px'; |
|
} |
|
|
|
function stopResizing() { |
|
document.removeEventListener('mousemove', resizeWindow); |
|
document.removeEventListener('mouseup', stopResizing); |
|
} |
|
|
|
document.addEventListener('mousemove', resizeWindow); |
|
document.addEventListener('mouseup', stopResizing); |
|
}); |
|
}); |
|
|
|
|
|
updateTerminalPrompt(); |
|
</script> |
|
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=ayokings/myspace" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
</html> |