add achievements
Build and Push Container / build-and-push (push) Successful in 1m19s

This commit is contained in:
2026-05-28 13:02:10 -04:00
parent 5004b68817
commit 79c491d7ee
3 changed files with 462 additions and 88 deletions
+290 -86
View File
@@ -274,92 +274,99 @@ function createServerRack() {
content.innerHTML = '';
}
if (cmdText === 'exit') {
if (!isRoot) {
isLoginScreen = true;
document.body.innerHTML = '';
document.body.style.background = '#000';
document.body.style.color = '#fff';
document.body.style.fontFamily = 'monospace';
document.body.style.padding = '20px';
document.body.style.minHeight = '100vh';
document.body.style.margin = '0';
document.body.style.lineHeight = '1.6';
const loginContainer = document.createElement('div');
loginContainer.style.marginBottom = '10px';
loginContainer.textContent = 'homelab tty1';
document.body.appendChild(loginContainer);
const loginInput = document.createElement('input');
loginInput.type = 'text';
loginInput.style.background = 'transparent';
loginInput.style.border = 'none';
loginInput.style.outline = 'none';
loginInput.style.color = '#fff';
loginInput.style.fontFamily = 'monospace';
loginInput.style.fontSize = '14px';
loginInput.style.width = '300px';
loginInput.style.caretColor = '#fff';
loginInput.autofocus = true;
const loginLine = document.createElement('div');
loginLine.style.marginBottom = '20px';
loginLine.appendChild(document.createTextNode('homelab login: '));
loginLine.appendChild(loginInput);
document.body.appendChild(loginLine);
loginInput.focus();
const handleLogin = (e) => {
if (e.key === 'Enter') {
const deniedLine = document.createElement('div');
deniedLine.textContent = 'Access denied';
deniedLine.style.marginTop = '10px';
document.body.appendChild(deniedLine);
const newLoginLine = document.createElement('div');
newLoginLine.style.marginTop = '10px';
const newInput = document.createElement('input');
newInput.type = 'text';
newInput.style.background = 'transparent';
newInput.style.border = 'none';
newInput.style.outline = 'none';
newInput.style.color = '#fff';
newInput.style.fontFamily = 'monospace';
newInput.style.fontSize = '14px';
newInput.style.width = '300px';
newInput.style.caretColor = '#fff';
newInput.autofocus = true;
newLoginLine.appendChild(document.createTextNode('homelab login: '));
newLoginLine.appendChild(newInput);
document.body.appendChild(newLoginLine);
loginInput.remove();
newInput.focus();
newInput.addEventListener('keydown', handleLogin);
}
};
loginInput.addEventListener('keydown', handleLogin);
return;
} else {
isRoot = false;
}
const newLine = document.createElement('div');
newLine.innerHTML = '<span class="terminal-prompt">$</span> ';
content.appendChild(newLine);
const newCursor = document.createElement('span');
newCursor.className = 'terminal-cursor';
newLine.appendChild(newCursor);
content.scrollTop = content.scrollHeight;
return;
}
if (cmdText === 'exit') {
if (!isRoot) {
const newAchievements = checkAchievements(cmdText, false);
if (newAchievements.length > 0) {
revealAchievements();
newAchievements.forEach(a => showToast(a));
}
isLoginScreen = true;
document.body.innerHTML = '';
document.body.style.background = '#000';
document.body.style.color = '#fff';
document.body.style.fontFamily = 'monospace';
document.body.style.padding = '20px';
document.body.style.minHeight = '100vh';
document.body.style.margin = '0';
document.body.style.lineHeight = '1.6';
const loginContainer = document.createElement('div');
loginContainer.style.marginBottom = '10px';
loginContainer.textContent = 'homelab tty1';
document.body.appendChild(loginContainer);
const loginInput = document.createElement('input');
loginInput.type = 'text';
loginInput.style.background = 'transparent';
loginInput.style.border = 'none';
loginInput.style.outline = 'none';
loginInput.style.color = '#fff';
loginInput.style.fontFamily = 'monospace';
loginInput.style.fontSize = '14px';
loginInput.style.width = '300px';
loginInput.style.caretColor = '#fff';
loginInput.autofocus = true;
const loginLine = document.createElement('div');
loginLine.style.marginBottom = '20px';
loginLine.appendChild(document.createTextNode('homelab login: '));
loginLine.appendChild(loginInput);
document.body.appendChild(loginLine);
loginInput.focus();
const handleLogin = (e) => {
if (e.key === 'Enter') {
const deniedLine = document.createElement('div');
deniedLine.textContent = 'Access denied';
deniedLine.style.marginTop = '10px';
document.body.appendChild(deniedLine);
const newLoginLine = document.createElement('div');
newLoginLine.style.marginTop = '10px';
const newInput = document.createElement('input');
newInput.type = 'text';
newInput.style.background = 'transparent';
newInput.style.border = 'none';
newInput.style.outline = 'none';
newInput.style.color = '#fff';
newInput.style.fontFamily = 'monospace';
newInput.style.fontSize = '14px';
newInput.style.width = '300px';
newInput.style.caretColor = '#fff';
newInput.autofocus = true;
newLoginLine.appendChild(document.createTextNode('homelab login: '));
newLoginLine.appendChild(newInput);
document.body.appendChild(newLoginLine);
loginInput.remove();
newInput.focus();
newInput.addEventListener('keydown', handleLogin);
}
};
loginInput.addEventListener('keydown', handleLogin);
return;
} else {
isRoot = false;
}
const newLine = document.createElement('div');
newLine.innerHTML = '<span class="terminal-prompt">$</span> ';
content.appendChild(newLine);
const newCursor = document.createElement('span');
newCursor.className = 'terminal-cursor';
newLine.appendChild(newCursor);
content.scrollTop = content.scrollHeight;
return;
}
if (cmdText === 'rm -rf /') {
if (!isRoot) {
@@ -392,6 +399,13 @@ function createServerRack() {
newCursor.className = 'terminal-cursor' + (isRoot ? ' red' : '');
newLine.appendChild(newCursor);
content.scrollTop = content.scrollHeight;
const newAchievements = checkAchievements(cmdText, isRoot);
if (newAchievements.length > 0) {
revealAchievements();
newAchievements.forEach(a => showToast(a));
}
return;
}
@@ -412,6 +426,13 @@ function createServerRack() {
newCursor.className = 'terminal-cursor red';
newLine.appendChild(newCursor);
content.scrollTop = content.scrollHeight;
const newAchievements = checkAchievements(cmdText, isRoot);
if (newAchievements.length > 0) {
revealAchievements();
newAchievements.forEach(a => showToast(a));
}
return;
}
@@ -464,6 +485,12 @@ function createServerRack() {
content.appendChild(outLine);
}
const newAchievements = checkAchievements(cmdText, isRoot);
if (newAchievements.length > 0) {
revealAchievements();
newAchievements.forEach(a => showToast(a));
}
const newLine = document.createElement('div');
if (isRoot) {
newLine.innerHTML = '<span class="terminal-prompt">#</span> ';
@@ -716,3 +743,180 @@ document.getElementById('hero').addEventListener('click', (e) => {
activeTerminal._mobileInput.focus();
}
});
// Achievement System
const ACHIEVEMENTS_STORAGE_KEY = 'reese-terminal-achievements';
const ACHIEVEMENTS = {
time_flies: { name: 'Time Flies', desc: 'Check the system uptime', icon: '⏱️', cmd: 'uptime' },
curious: { name: 'Curious', desc: 'List directory contents', icon: '📁', cmd: 'ls', prefix: true },
port_scanner: { name: 'Port Scanner', desc: 'Check listening ports', icon: '🔍', cmd: 'ss', prefix: true },
password_reset: { name: 'Password Reset Request', desc: 'Submit a SNOW request', icon: '🚪', cmd: 'exit' },
power_user: { name: 'Power User', desc: 'Gain root access', icon: '👑', cmd: 'sudo su -' },
nice_try: { name: 'Nice Try', desc: 'Attempt rm -rf / as a normal user', icon: '😏', cmd: 'rm -rf /' },
restore_backup: { name: 'Restore from Backup', desc: 'Actually destroy the system as root', icon: '💥', cmd: 'rm -rf / root' },
where_am_i: { name: 'Where Am I?', desc: 'Print working directory', icon: '📍', cmd: 'pwd' },
self_aware: { name: 'Self-Aware', desc: 'Print current user', icon: '🪞', cmd: 'whoami' },
identity: { name: 'Identity Crisis', desc: 'Print hostname', icon: '🖥️', cmd: 'hostname' },
time_keeper: { name: 'Time Keeper', desc: 'Print current date', icon: '📅', cmd: 'date' },
system_explorer: { name: 'System Explorer', desc: 'Print system information', icon: '🔧', cmd: 'uname' },
access_granted: { name: 'Access Granted', desc: 'Check user identity', icon: '🆔', cmd: 'id' },
os_detective: { name: 'OS Detective', desc: 'Read the OS release file', icon: '🐧', cmd: 'cat /etc/os-release' },
ssh_explorer: { name: 'SSH Explorer', desc: 'View SSH public key', icon: '🔑', cmd: 'cat ~/.ssh/id_ed25519.pub' },
container_watcher: { name: 'Container Watcher', desc: 'List Docker containers', icon: '🐳', cmd: 'docker ps', prefix: true },
docker_confused: { name: 'Docker Confused', desc: 'Use wrong Docker command', icon: '🤔', cmd: 'docker ls', prefix: true },
container_pro: { name: 'Container Pro', desc: 'Use correct container command', icon: '✅', cmd: 'docker container ls', prefix: true },
podman_fan: { name: 'Podman Fan', desc: 'List Podman containers', icon: '📦', cmd: 'podman ps', prefix: true },
podman_confused: { name: 'Podman Confused', desc: 'Use wrong Podman command', icon: '🤔', cmd: 'podman ls', prefix: true },
podman_pro: { name: 'Podman Pro', desc: 'Use correct Podman command', icon: '✅', cmd: 'podman container ls', prefix: true },
service_hunter: { name: 'Service Hunter', desc: 'List systemd units', icon: '🔎', cmd: 'systemctl list-units', prefix: true },
service_filter: { name: 'Service Filter', desc: 'Filter running services', icon: '🎯', cmd: 'systemctl list-units --type=service --state=running --no-pager' },
network_ninja: { name: 'Network Ninja', desc: 'Show network interfaces', icon: '🌐', cmd: 'ip addr show', prefix: true },
disk_detective: { name: 'Disk Detective', desc: 'Check disk usage', icon: '💾', cmd: 'df -h' },
memory_minded: { name: 'Memory Minded', desc: 'Check memory usage', icon: '🧠', cmd: 'free -h' },
process_watcher: { name: 'Process Watcher', desc: 'List running processes', icon: '👁️', cmd: 'ps aux', prefix: true },
memory_hog: { name: 'Memory Hog', desc: 'Find top memory consumers', icon: '🐗', cmd: 'ps aux --sort=-%mem | head -10' },
aesthetic_mode: { name: 'Aesthetic Mode', desc: 'Display system info with style', icon: '✨', cmd: 'neofetch' },
help_seeker: { name: 'Help Seeker', desc: 'Look up available commands', icon: '📖', cmd: 'help' },
clean_slate: { name: 'Clean Slate', desc: 'Clear the terminal', icon: '🧹', cmd: 'clear' },
};
function loadAchievements() {
try {
const saved = localStorage.getItem(ACHIEVEMENTS_STORAGE_KEY);
return saved ? JSON.parse(saved) : [];
} catch {
return [];
}
}
function saveAchievements(achieved) {
localStorage.setItem(ACHIEVEMENTS_STORAGE_KEY, JSON.stringify(achieved));
}
function checkAchievements(cmdText, isRoot) {
const achieved = loadAchievements();
const newAchievements = [];
for (const [key, achievement] of Object.entries(ACHIEVEMENTS)) {
if (achieved.includes(key)) continue;
if (key === 'restore_backup' && cmdText === 'rm -rf /' && isRoot) {
achieved.push(key);
newAchievements.push(achievement);
} else if (key === 'power_user' && (cmdText === 'sudo su -' || cmdText === 'sudo -i')) {
achieved.push(key);
newAchievements.push(achievement);
} else if (key === 'password_reset' && cmdText === 'exit' && !isRoot) {
achieved.push(key);
newAchievements.push(achievement);
} else if (key === 'nice_try' && cmdText === 'rm -rf /' && !isRoot) {
achieved.push(key);
newAchievements.push(achievement);
} else if (key === 'system_explorer' && (cmdText === 'uname' || cmdText === 'uname -a')) {
achieved.push(key);
newAchievements.push(achievement);
} else if (key === 'docker_confused' && cmdText === 'docker ls') {
achieved.push(key);
newAchievements.push(achievement);
} else if (key === 'podman_confused' && cmdText === 'podman ls') {
achieved.push(key);
newAchievements.push(achievement);
} else if (achievement.prefix ? cmdText.startsWith(achievement.cmd) : achievement.cmd === cmdText) {
achieved.push(key);
newAchievements.push(achievement);
}
}
if (newAchievements.length > 0) {
saveAchievements(achieved);
}
return newAchievements;
}
function showToast(achievement) {
const container = document.getElementById('toast-container') || createToastContainer();
const toast = document.createElement('div');
toast.className = 'toast';
toast.innerHTML = `
<div class="toast-icon">${achievement.icon}</div>
<div class="toast-content">
<div class="toast-label">Achievement Unlocked</div>
<div class="toast-title">${achievement.name}</div>
</div>
`;
container.appendChild(toast);
setTimeout(() => {
toast.classList.add('removing');
setTimeout(() => toast.remove(), 300);
}, 4000);
}
function createToastContainer() {
const container = document.createElement('div');
container.id = 'toast-container';
container.className = 'toast-container';
document.body.appendChild(container);
return container;
}
function revealAchievements() {
const section = document.getElementById('achievements');
if (section.style.display === 'none' || !section.style.display) {
section.style.display = 'block';
section.classList.add('fade-in');
setTimeout(() => section.classList.add('visible'), 50);
addAchievementsNav();
}
renderAchievements();
}
function renderAchievements() {
const achieved = loadAchievements();
const total = Object.keys(ACHIEVEMENTS).length;
const count = achieved.length;
const countEl = document.getElementById('achievements-count');
countEl.textContent = `${count} / ${total} achievements unlocked`;
const grid = document.getElementById('achievements-grid');
grid.innerHTML = '';
for (const [key, achievement] of Object.entries(ACHIEVEMENTS)) {
const isUnlocked = achieved.includes(key);
const card = document.createElement('div');
card.className = `achievement-card ${isUnlocked ? 'unlocked' : 'locked'}`;
card.innerHTML = `
<div class="achievement-icon">${achievement.icon}</div>
<div class="achievement-info">
<h3>${isUnlocked ? achievement.name : '???'}</h3>
<p>${isUnlocked ? achievement.desc : 'Keep exploring the terminal...'}</p>
</div>
`;
grid.appendChild(card);
}
}
function addAchievementsNav() {
const navLinks = document.getElementById('navLinks');
const existing = document.getElementById('nav-achievements');
if (!existing && loadAchievements().length > 0) {
const li = document.createElement('li');
li.id = 'nav-achievements';
li.innerHTML = '<a href="#achievements">Achievements</a>';
navLinks.appendChild(li);
}
}
// Initialize
(function initAchievements() {
const achieved = loadAchievements();
if (achieved.length > 0) {
revealAchievements();
addAchievementsNav();
}
})();