add formatting
This commit is contained in:
+571
-456
File diff suppressed because it is too large
Load Diff
+189
-189
@@ -50,56 +50,56 @@ function createServerRack() {
|
|||||||
const bgContainer = document.querySelector('.server-rack-bg');
|
const bgContainer = document.querySelector('.server-rack-bg');
|
||||||
const rackContainer = document.createElement('div');
|
const rackContainer = document.createElement('div');
|
||||||
rackContainer.className = 'rack-container';
|
rackContainer.className = 'rack-container';
|
||||||
|
|
||||||
const topBar = document.createElement('div');
|
const topBar = document.createElement('div');
|
||||||
topBar.className = 'rack-top-bar';
|
topBar.className = 'rack-top-bar';
|
||||||
rackContainer.appendChild(topBar);
|
rackContainer.appendChild(topBar);
|
||||||
|
|
||||||
const unitHeight = 98;
|
const unitHeight = 98;
|
||||||
const barHeight = 72;
|
const barHeight = 72;
|
||||||
const totalPageHeight = document.documentElement.scrollHeight;
|
const totalPageHeight = document.documentElement.scrollHeight;
|
||||||
const totalUnits = Math.max(Math.ceil((totalPageHeight - 100 - barHeight) / unitHeight), 10);
|
const totalUnits = Math.max(Math.ceil((totalPageHeight - 100 - barHeight) / unitHeight), 10);
|
||||||
|
|
||||||
const brands = ['Framework'];
|
const brands = ['Framework'];
|
||||||
|
|
||||||
const services = ['Borg', 'Gitea', 'Nextcloud', 'Jellyfin', 'Open WebUI', 'llama.cpp', 'Immich', 'LiteLLM', 'Caddy', 'Nginx', 'Samba', 'Slopbox'];
|
const services = ['Borg', 'Gitea', 'Nextcloud', 'Jellyfin', 'Open WebUI', 'llama.cpp', 'Immich', 'LiteLLM', 'Caddy', 'Nginx', 'Samba', 'Slopbox'];
|
||||||
|
|
||||||
for (let i = 0; i < totalUnits; i++) {
|
for (let i = 0; i < totalUnits; i++) {
|
||||||
const unit = document.createElement('div');
|
const unit = document.createElement('div');
|
||||||
unit.className = 'rack-unit';
|
unit.className = 'rack-unit';
|
||||||
|
|
||||||
const leftRail = document.createElement('div');
|
const leftRail = document.createElement('div');
|
||||||
leftRail.className = 'rail left';
|
leftRail.className = 'rail left';
|
||||||
unit.appendChild(leftRail);
|
unit.appendChild(leftRail);
|
||||||
|
|
||||||
const rightRail = document.createElement('div');
|
const rightRail = document.createElement('div');
|
||||||
rightRail.className = 'rail right';
|
rightRail.className = 'rail right';
|
||||||
unit.appendChild(rightRail);
|
unit.appendChild(rightRail);
|
||||||
|
|
||||||
const isSwitch = i > 0 && (i % 7 === 0 || i % 11 === 0);
|
const isSwitch = i > 0 && (i % 7 === 0 || i % 11 === 0);
|
||||||
|
|
||||||
if (isSwitch) {
|
if (isSwitch) {
|
||||||
const switchFace = document.createElement('div');
|
const switchFace = document.createElement('div');
|
||||||
switchFace.className = 'eth-switch-face';
|
switchFace.className = 'eth-switch-face';
|
||||||
|
|
||||||
const powerLed = document.createElement('div');
|
const powerLed = document.createElement('div');
|
||||||
powerLed.className = 'eth-switch-led';
|
powerLed.className = 'eth-switch-led';
|
||||||
switchFace.appendChild(powerLed);
|
switchFace.appendChild(powerLed);
|
||||||
|
|
||||||
const brandLabel = document.createElement('div');
|
const brandLabel = document.createElement('div');
|
||||||
brandLabel.className = 'eth-brand';
|
brandLabel.className = 'eth-brand';
|
||||||
brandLabel.textContent = brands[Math.floor(Math.random() * brands.length)];
|
brandLabel.textContent = brands[Math.floor(Math.random() * brands.length)];
|
||||||
switchFace.appendChild(brandLabel);
|
switchFace.appendChild(brandLabel);
|
||||||
|
|
||||||
const portCount = Math.floor(Math.random() * 4) + 5;
|
const portCount = Math.floor(Math.random() * 4) + 5;
|
||||||
const cappedCount = Math.min(portCount, 8);
|
const cappedCount = Math.min(portCount, 8);
|
||||||
const row = document.createElement('div');
|
const row = document.createElement('div');
|
||||||
row.className = 'eth-port-row';
|
row.className = 'eth-port-row';
|
||||||
|
|
||||||
for (let p = 0; p < cappedCount; p++) {
|
for (let p = 0; p < cappedCount; p++) {
|
||||||
const port = document.createElement('div');
|
const port = document.createElement('div');
|
||||||
port.className = 'eth-port';
|
port.className = 'eth-port';
|
||||||
|
|
||||||
const led = document.createElement('div');
|
const led = document.createElement('div');
|
||||||
led.className = 'eth-port-led';
|
led.className = 'eth-port-led';
|
||||||
if (Math.random() > 0.3) {
|
if (Math.random() > 0.3) {
|
||||||
@@ -110,32 +110,32 @@ function createServerRack() {
|
|||||||
}
|
}
|
||||||
led.style.animationDelay = `${Math.random() * 2}s`;
|
led.style.animationDelay = `${Math.random() * 2}s`;
|
||||||
port.appendChild(led);
|
port.appendChild(led);
|
||||||
|
|
||||||
row.appendChild(port);
|
row.appendChild(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
switchFace.appendChild(row);
|
switchFace.appendChild(row);
|
||||||
|
|
||||||
const label = document.createElement('div');
|
const label = document.createElement('div');
|
||||||
label.className = 'eth-port-label';
|
label.className = 'eth-port-label';
|
||||||
label.textContent = `1-${cappedCount}`;
|
label.textContent = `1-${cappedCount}`;
|
||||||
switchFace.appendChild(label);
|
switchFace.appendChild(label);
|
||||||
|
|
||||||
unit.appendChild(switchFace);
|
unit.appendChild(switchFace);
|
||||||
} else {
|
} else {
|
||||||
const face = document.createElement('div');
|
const face = document.createElement('div');
|
||||||
face.className = 'server-face';
|
face.className = 'server-face';
|
||||||
|
|
||||||
const serverType = Math.random();
|
const serverType = Math.random();
|
||||||
|
|
||||||
const isTerminal = i === 0;
|
const isTerminal = i === 0;
|
||||||
|
|
||||||
if (isTerminal) {
|
if (isTerminal) {
|
||||||
// Terminal display
|
// Terminal display
|
||||||
const terminal = document.createElement('div');
|
const terminal = document.createElement('div');
|
||||||
terminal.className = 'terminal-display';
|
terminal.className = 'terminal-display';
|
||||||
terminal.setAttribute('tabindex', '0');
|
terminal.setAttribute('tabindex', '0');
|
||||||
|
|
||||||
const mobileInput = document.createElement('input');
|
const mobileInput = document.createElement('input');
|
||||||
mobileInput.type = 'text';
|
mobileInput.type = 'text';
|
||||||
mobileInput.style.opacity = '0';
|
mobileInput.style.opacity = '0';
|
||||||
@@ -153,40 +153,40 @@ function createServerRack() {
|
|||||||
mobileInput.autocapitalize = 'off';
|
mobileInput.autocapitalize = 'off';
|
||||||
terminal.appendChild(mobileInput);
|
terminal.appendChild(mobileInput);
|
||||||
terminal._mobileInput = mobileInput;
|
terminal._mobileInput = mobileInput;
|
||||||
|
|
||||||
const content = document.createElement('div');
|
const content = document.createElement('div');
|
||||||
content.className = 'terminal-content';
|
content.className = 'terminal-content';
|
||||||
|
|
||||||
const line1 = document.createElement('div');
|
const line1 = document.createElement('div');
|
||||||
line1.innerHTML = '<span class="terminal-prompt">$</span> uptime';
|
line1.innerHTML = '<span class="terminal-prompt">$</span> uptime';
|
||||||
content.appendChild(line1);
|
content.appendChild(line1);
|
||||||
|
|
||||||
const line2 = document.createElement('div');
|
const line2 = document.createElement('div');
|
||||||
line2.textContent = 'optional';
|
line2.textContent = 'optional';
|
||||||
content.appendChild(line2);
|
content.appendChild(line2);
|
||||||
|
|
||||||
const line3 = document.createElement('div');
|
const line3 = document.createElement('div');
|
||||||
line3.innerHTML = '<span class="terminal-prompt">$</span> ';
|
line3.innerHTML = '<span class="terminal-prompt">$</span> ';
|
||||||
content.appendChild(line3);
|
content.appendChild(line3);
|
||||||
|
|
||||||
const cursor = document.createElement('span');
|
const cursor = document.createElement('span');
|
||||||
cursor.className = 'terminal-cursor';
|
cursor.className = 'terminal-cursor';
|
||||||
line3.appendChild(cursor);
|
line3.appendChild(cursor);
|
||||||
|
|
||||||
terminal.appendChild(content);
|
terminal.appendChild(content);
|
||||||
face.appendChild(terminal);
|
face.appendChild(terminal);
|
||||||
|
|
||||||
activeTerminal = terminal;
|
activeTerminal = terminal;
|
||||||
|
|
||||||
terminal.addEventListener('click', () => {
|
terminal.addEventListener('click', () => {
|
||||||
mobileInput.focus();
|
mobileInput.focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
const commandHistory = [];
|
const commandHistory = [];
|
||||||
let historyIndex = -1;
|
let historyIndex = -1;
|
||||||
let isRoot = false;
|
let isRoot = false;
|
||||||
let isLoginScreen = false;
|
let isLoginScreen = false;
|
||||||
|
|
||||||
terminal.addEventListener('keydown', (e) => {
|
terminal.addEventListener('keydown', (e) => {
|
||||||
if (e.key === 'ArrowUp') {
|
if (e.key === 'ArrowUp') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -201,7 +201,7 @@ function createServerRack() {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.key === 'ArrowDown') {
|
if (e.key === 'ArrowDown') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (historyIndex > 0) {
|
if (historyIndex > 0) {
|
||||||
@@ -222,7 +222,7 @@ function createServerRack() {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
mobileInput.value = '';
|
mobileInput.value = '';
|
||||||
@@ -230,14 +230,14 @@ function createServerRack() {
|
|||||||
const lastLine = content.lastElementChild;
|
const lastLine = content.lastElementChild;
|
||||||
const oldCursor = lastLine?.querySelector('.terminal-cursor');
|
const oldCursor = lastLine?.querySelector('.terminal-cursor');
|
||||||
if (oldCursor) oldCursor.remove();
|
if (oldCursor) oldCursor.remove();
|
||||||
|
|
||||||
const cmdText = lastLine.textContent.replace(/^[\$#]\s*/, '').trim();
|
const cmdText = lastLine.textContent.replace(/^[\$#]\s*/, '').trim();
|
||||||
|
|
||||||
if (cmdText) {
|
if (cmdText) {
|
||||||
commandHistory.unshift(cmdText);
|
commandHistory.unshift(cmdText);
|
||||||
historyIndex = -1;
|
historyIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdText.startsWith('ls')) {
|
if (cmdText.startsWith('ls')) {
|
||||||
const output = [
|
const output = [
|
||||||
'total 20K',
|
'total 20K',
|
||||||
@@ -252,14 +252,14 @@ function createServerRack() {
|
|||||||
'-rw-r--r-- 1 reese reese 42K May 28 14:25 style.css',
|
'-rw-r--r-- 1 reese reese 42K May 28 14:25 style.css',
|
||||||
'drwxr-xr-x 2 reese reese 4.0K May 27 09:00 src'
|
'drwxr-xr-x 2 reese reese 4.0K May 27 09:00 src'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
const outLine = document.createElement('div');
|
const outLine = document.createElement('div');
|
||||||
outLine.style.whiteSpace = 'pre-wrap';
|
outLine.style.whiteSpace = 'pre-wrap';
|
||||||
outLine.style.color = '#ccc';
|
outLine.style.color = '#ccc';
|
||||||
outLine.textContent = output;
|
outLine.textContent = output;
|
||||||
content.appendChild(outLine);
|
content.appendChild(outLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdText.startsWith('ss')) {
|
if (cmdText.startsWith('ss')) {
|
||||||
const output = 'Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port\ntcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:80 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:443 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:222 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:3000 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:3001 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:3002 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:8080 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:8081 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:8096 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:9090 0.0.0.0:*\ntcp LISTEN 0 128 [::]:22 [::]:*';
|
const output = 'Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port\ntcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:80 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:443 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:222 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:3000 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:3001 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:3002 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:8080 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:8081 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:8096 0.0.0.0:*\ntcp LISTEN 0 128 0.0.0.0:9090 0.0.0.0:*\ntcp LISTEN 0 128 [::]:22 [::]:*';
|
||||||
const outLine = document.createElement('div');
|
const outLine = document.createElement('div');
|
||||||
@@ -268,105 +268,105 @@ function createServerRack() {
|
|||||||
outLine.textContent = output;
|
outLine.textContent = output;
|
||||||
content.appendChild(outLine);
|
content.appendChild(outLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdText === 'clear') {
|
if (cmdText === 'clear') {
|
||||||
content.innerHTML = '';
|
content.innerHTML = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdText === 'exit') {
|
if (cmdText === 'exit') {
|
||||||
if (!isRoot) {
|
if (!isRoot) {
|
||||||
const newAchievements = checkAchievements(cmdText, false);
|
const newAchievements = checkAchievements(cmdText, false);
|
||||||
if (newAchievements.length > 0) {
|
if (newAchievements.length > 0) {
|
||||||
revealAchievements();
|
revealAchievements();
|
||||||
newAchievements.forEach(a => showToast(a));
|
newAchievements.forEach(a => showToast(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
isLoginScreen = true;
|
isLoginScreen = true;
|
||||||
document.body.innerHTML = '';
|
document.body.innerHTML = '';
|
||||||
document.body.style.background = '#000';
|
document.body.style.background = '#000';
|
||||||
document.body.style.color = '#fff';
|
document.body.style.color = '#fff';
|
||||||
document.body.style.fontFamily = 'monospace';
|
document.body.style.fontFamily = 'monospace';
|
||||||
document.body.style.padding = '20px';
|
document.body.style.padding = '20px';
|
||||||
document.body.style.minHeight = '100vh';
|
document.body.style.minHeight = '100vh';
|
||||||
document.body.style.margin = '0';
|
document.body.style.margin = '0';
|
||||||
document.body.style.lineHeight = '1.6';
|
document.body.style.lineHeight = '1.6';
|
||||||
|
|
||||||
const loginContainer = document.createElement('div');
|
const loginContainer = document.createElement('div');
|
||||||
loginContainer.style.marginBottom = '10px';
|
loginContainer.style.marginBottom = '10px';
|
||||||
loginContainer.textContent = 'homelab tty1';
|
loginContainer.textContent = 'homelab tty1';
|
||||||
document.body.appendChild(loginContainer);
|
document.body.appendChild(loginContainer);
|
||||||
|
|
||||||
const loginInput = document.createElement('input');
|
const loginInput = document.createElement('input');
|
||||||
loginInput.type = 'text';
|
loginInput.type = 'text';
|
||||||
loginInput.style.background = 'transparent';
|
loginInput.style.background = 'transparent';
|
||||||
loginInput.style.border = 'none';
|
loginInput.style.border = 'none';
|
||||||
loginInput.style.outline = 'none';
|
loginInput.style.outline = 'none';
|
||||||
loginInput.style.color = '#fff';
|
loginInput.style.color = '#fff';
|
||||||
loginInput.style.fontFamily = 'monospace';
|
loginInput.style.fontFamily = 'monospace';
|
||||||
loginInput.style.fontSize = '14px';
|
loginInput.style.fontSize = '14px';
|
||||||
loginInput.style.width = '300px';
|
loginInput.style.width = '300px';
|
||||||
loginInput.style.caretColor = '#fff';
|
loginInput.style.caretColor = '#fff';
|
||||||
loginInput.autofocus = true;
|
loginInput.autofocus = true;
|
||||||
|
|
||||||
const loginLine = document.createElement('div');
|
const loginLine = document.createElement('div');
|
||||||
loginLine.style.marginBottom = '20px';
|
loginLine.style.marginBottom = '20px';
|
||||||
loginLine.appendChild(document.createTextNode('homelab login: '));
|
loginLine.appendChild(document.createTextNode('homelab login: '));
|
||||||
loginLine.appendChild(loginInput);
|
loginLine.appendChild(loginInput);
|
||||||
|
|
||||||
document.body.appendChild(loginLine);
|
document.body.appendChild(loginLine);
|
||||||
|
|
||||||
loginInput.focus();
|
loginInput.focus();
|
||||||
|
|
||||||
const handleLogin = (e) => {
|
const handleLogin = (e) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
const deniedLine = document.createElement('div');
|
const deniedLine = document.createElement('div');
|
||||||
deniedLine.textContent = 'Access denied';
|
deniedLine.textContent = 'Access denied';
|
||||||
deniedLine.style.marginTop = '10px';
|
deniedLine.style.marginTop = '10px';
|
||||||
document.body.appendChild(deniedLine);
|
document.body.appendChild(deniedLine);
|
||||||
|
|
||||||
const newLoginLine = document.createElement('div');
|
const newLoginLine = document.createElement('div');
|
||||||
newLoginLine.style.marginTop = '10px';
|
newLoginLine.style.marginTop = '10px';
|
||||||
const newInput = document.createElement('input');
|
const newInput = document.createElement('input');
|
||||||
newInput.type = 'text';
|
newInput.type = 'text';
|
||||||
newInput.style.background = 'transparent';
|
newInput.style.background = 'transparent';
|
||||||
newInput.style.border = 'none';
|
newInput.style.border = 'none';
|
||||||
newInput.style.outline = 'none';
|
newInput.style.outline = 'none';
|
||||||
newInput.style.color = '#fff';
|
newInput.style.color = '#fff';
|
||||||
newInput.style.fontFamily = 'monospace';
|
newInput.style.fontFamily = 'monospace';
|
||||||
newInput.style.fontSize = '14px';
|
newInput.style.fontSize = '14px';
|
||||||
newInput.style.width = '300px';
|
newInput.style.width = '300px';
|
||||||
newInput.style.caretColor = '#fff';
|
newInput.style.caretColor = '#fff';
|
||||||
newInput.autofocus = true;
|
newInput.autofocus = true;
|
||||||
newLoginLine.appendChild(document.createTextNode('homelab login: '));
|
newLoginLine.appendChild(document.createTextNode('homelab login: '));
|
||||||
newLoginLine.appendChild(newInput);
|
newLoginLine.appendChild(newInput);
|
||||||
|
|
||||||
document.body.appendChild(newLoginLine);
|
document.body.appendChild(newLoginLine);
|
||||||
|
|
||||||
loginInput.remove();
|
loginInput.remove();
|
||||||
newInput.focus();
|
newInput.focus();
|
||||||
|
|
||||||
newInput.addEventListener('keydown', handleLogin);
|
newInput.addEventListener('keydown', handleLogin);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
loginInput.addEventListener('keydown', handleLogin);
|
loginInput.addEventListener('keydown', handleLogin);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
isRoot = false;
|
isRoot = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newLine = document.createElement('div');
|
const newLine = document.createElement('div');
|
||||||
newLine.innerHTML = '<span class="terminal-prompt">$</span> ';
|
newLine.innerHTML = '<span class="terminal-prompt">$</span> ';
|
||||||
content.appendChild(newLine);
|
content.appendChild(newLine);
|
||||||
const newCursor = document.createElement('span');
|
const newCursor = document.createElement('span');
|
||||||
newCursor.className = 'terminal-cursor';
|
newCursor.className = 'terminal-cursor';
|
||||||
newLine.appendChild(newCursor);
|
newLine.appendChild(newCursor);
|
||||||
content.scrollTop = content.scrollHeight;
|
content.scrollTop = content.scrollHeight;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdText === 'rm -rf /') {
|
if (cmdText === 'rm -rf /') {
|
||||||
if (!isRoot) {
|
if (!isRoot) {
|
||||||
const outLine = document.createElement('div');
|
const outLine = document.createElement('div');
|
||||||
@@ -385,7 +385,7 @@ function createServerRack() {
|
|||||||
document.title = '';
|
document.title = '';
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newLine = document.createElement('div');
|
const newLine = document.createElement('div');
|
||||||
if (isRoot) {
|
if (isRoot) {
|
||||||
newLine.innerHTML = '<span class="terminal-prompt">#</span> ';
|
newLine.innerHTML = '<span class="terminal-prompt">#</span> ';
|
||||||
@@ -398,25 +398,25 @@ function createServerRack() {
|
|||||||
newCursor.className = 'terminal-cursor' + (isRoot ? ' red' : '');
|
newCursor.className = 'terminal-cursor' + (isRoot ? ' red' : '');
|
||||||
newLine.appendChild(newCursor);
|
newLine.appendChild(newCursor);
|
||||||
content.scrollTop = content.scrollHeight;
|
content.scrollTop = content.scrollHeight;
|
||||||
|
|
||||||
const newAchievements = checkAchievements(cmdText, isRoot);
|
const newAchievements = checkAchievements(cmdText, isRoot);
|
||||||
if (newAchievements.length > 0) {
|
if (newAchievements.length > 0) {
|
||||||
revealAchievements();
|
revealAchievements();
|
||||||
newAchievements.forEach(a => showToast(a));
|
newAchievements.forEach(a => showToast(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdText === 'sudo su -' || cmdText === 'sudo -i') {
|
if (cmdText === 'sudo su -' || cmdText === 'sudo -i') {
|
||||||
const outLine = document.createElement('div');
|
const outLine = document.createElement('div');
|
||||||
outLine.style.whiteSpace = 'pre-wrap';
|
outLine.style.whiteSpace = 'pre-wrap';
|
||||||
outLine.style.color = '#ef4444';
|
outLine.style.color = '#ef4444';
|
||||||
outLine.textContent = 'I hope you know what you\'re doing';
|
outLine.textContent = 'I hope you know what you\'re doing';
|
||||||
content.appendChild(outLine);
|
content.appendChild(outLine);
|
||||||
|
|
||||||
isRoot = true;
|
isRoot = true;
|
||||||
|
|
||||||
const newLine = document.createElement('div');
|
const newLine = document.createElement('div');
|
||||||
newLine.innerHTML = '<span class="terminal-prompt">#</span> ';
|
newLine.innerHTML = '<span class="terminal-prompt">#</span> ';
|
||||||
newLine.style.color = '#ef4444';
|
newLine.style.color = '#ef4444';
|
||||||
@@ -425,16 +425,16 @@ function createServerRack() {
|
|||||||
newCursor.className = 'terminal-cursor red';
|
newCursor.className = 'terminal-cursor red';
|
||||||
newLine.appendChild(newCursor);
|
newLine.appendChild(newCursor);
|
||||||
content.scrollTop = content.scrollHeight;
|
content.scrollTop = content.scrollHeight;
|
||||||
|
|
||||||
const newAchievements = checkAchievements(cmdText, isRoot);
|
const newAchievements = checkAchievements(cmdText, isRoot);
|
||||||
if (newAchievements.length > 0) {
|
if (newAchievements.length > 0) {
|
||||||
revealAchievements();
|
revealAchievements();
|
||||||
newAchievements.forEach(a => showToast(a));
|
newAchievements.forEach(a => showToast(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const commands = {
|
const commands = {
|
||||||
'pwd': '/home/reese/portfolio',
|
'pwd': '/home/reese/portfolio',
|
||||||
'whoami': 'reese',
|
'whoami': 'reese',
|
||||||
@@ -464,7 +464,7 @@ function createServerRack() {
|
|||||||
'sl': '____\n|DD|____T_\n|_ |_____|<\n @-@-@-oo\\',
|
'sl': '____\n|DD|____T_\n|_ |_____|<\n @-@-@-oo\\',
|
||||||
'help': 'Available commands:\n ls List directory contents\n pwd Print working directory\n whoami Print current user\n hostname Print hostname\n date Print current date/time\n uname Print system information\n uptime Print system uptime\n id Print user identity\n cat Print file contents (try: cat /etc/os-release)\n docker List running containers\n podman List running pods\n systemctl List running systemd services\n ss Show listening ports\n ip Show network interfaces\n df Show disk usage\n free Show memory usage\n ps Show running processes\n neofetch System info display\n sl Steam locomotive\n help Show this help message',
|
'help': 'Available commands:\n ls List directory contents\n pwd Print working directory\n whoami Print current user\n hostname Print hostname\n date Print current date/time\n uname Print system information\n uptime Print system uptime\n id Print user identity\n cat Print file contents (try: cat /etc/os-release)\n docker List running containers\n podman List running pods\n systemctl List running systemd services\n ss Show listening ports\n ip Show network interfaces\n df Show disk usage\n free Show memory usage\n ps Show running processes\n neofetch System info display\n sl Steam locomotive\n help Show this help message',
|
||||||
};
|
};
|
||||||
|
|
||||||
if (cmdText.startsWith('echo ')) {
|
if (cmdText.startsWith('echo ')) {
|
||||||
const output = cmdText.replace(/^echo\s+/, '');
|
const output = cmdText.replace(/^echo\s+/, '');
|
||||||
const outLine = document.createElement('div');
|
const outLine = document.createElement('div');
|
||||||
@@ -484,13 +484,13 @@ function createServerRack() {
|
|||||||
}
|
}
|
||||||
content.appendChild(outLine);
|
content.appendChild(outLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newAchievements = checkAchievements(cmdText, isRoot);
|
const newAchievements = checkAchievements(cmdText, isRoot);
|
||||||
if (newAchievements.length > 0) {
|
if (newAchievements.length > 0) {
|
||||||
revealAchievements();
|
revealAchievements();
|
||||||
newAchievements.forEach(a => showToast(a));
|
newAchievements.forEach(a => showToast(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
const newLine = document.createElement('div');
|
const newLine = document.createElement('div');
|
||||||
if (isRoot) {
|
if (isRoot) {
|
||||||
newLine.innerHTML = '<span class="terminal-prompt">#</span> ';
|
newLine.innerHTML = '<span class="terminal-prompt">#</span> ';
|
||||||
@@ -524,7 +524,7 @@ function createServerRack() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
terminal.addEventListener('focus', () => {
|
terminal.addEventListener('focus', () => {
|
||||||
mobileInput.focus();
|
mobileInput.focus();
|
||||||
terminal.style.boxShadow = '0 0 8px rgba(234, 179, 8, 0.3), inset 0 0 20px rgba(34, 197, 94, 0.1)';
|
terminal.style.boxShadow = '0 0 8px rgba(234, 179, 8, 0.3), inset 0 0 20px rgba(34, 197, 94, 0.1)';
|
||||||
@@ -538,7 +538,7 @@ function createServerRack() {
|
|||||||
document.getElementById('hero').classList.add('shifted');
|
document.getElementById('hero').classList.add('shifted');
|
||||||
document.querySelector('.rack-container')?.classList.add('opaque');
|
document.querySelector('.rack-container')?.classList.add('opaque');
|
||||||
});
|
});
|
||||||
|
|
||||||
terminal.addEventListener('blur', () => {
|
terminal.addEventListener('blur', () => {
|
||||||
if (heroMouseDown) return;
|
if (heroMouseDown) return;
|
||||||
terminal.style.boxShadow = '';
|
terminal.style.boxShadow = '';
|
||||||
@@ -552,13 +552,13 @@ function createServerRack() {
|
|||||||
document.getElementById('hero').classList.remove('shifted');
|
document.getElementById('hero').classList.remove('shifted');
|
||||||
document.querySelector('.rack-container')?.classList.remove('opaque');
|
document.querySelector('.rack-container')?.classList.remove('opaque');
|
||||||
});
|
});
|
||||||
|
|
||||||
mobileInput.addEventListener('keydown', (e) => {
|
mobileInput.addEventListener('keydown', (e) => {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
mobileInput.blur();
|
mobileInput.blur();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mobileInput.addEventListener('blur', () => {
|
mobileInput.addEventListener('blur', () => {
|
||||||
if (heroMouseDown) return;
|
if (heroMouseDown) return;
|
||||||
terminal.style.boxShadow = '';
|
terminal.style.boxShadow = '';
|
||||||
@@ -572,17 +572,17 @@ function createServerRack() {
|
|||||||
document.getElementById('hero').classList.remove('shifted');
|
document.getElementById('hero').classList.remove('shifted');
|
||||||
document.querySelector('.rack-container')?.classList.remove('opaque');
|
document.querySelector('.rack-container')?.classList.remove('opaque');
|
||||||
});
|
});
|
||||||
|
|
||||||
let lastInputValue = '';
|
let lastInputValue = '';
|
||||||
|
|
||||||
mobileInput.addEventListener('input', () => {
|
mobileInput.addEventListener('input', () => {
|
||||||
const lastLine = content.lastElementChild;
|
const lastLine = content.lastElementChild;
|
||||||
if (!lastLine) return;
|
if (!lastLine) return;
|
||||||
|
|
||||||
const cursorEl = lastLine.querySelector('.terminal-cursor');
|
const cursorEl = lastLine.querySelector('.terminal-cursor');
|
||||||
const inputText = mobileInput.value;
|
const inputText = mobileInput.value;
|
||||||
const addedText = inputText.slice(lastInputValue.length);
|
const addedText = inputText.slice(lastInputValue.length);
|
||||||
|
|
||||||
if (addedText) {
|
if (addedText) {
|
||||||
if (cursorEl) cursorEl.remove();
|
if (cursorEl) cursorEl.remove();
|
||||||
lastLine.insertAdjacentText('beforeend', addedText);
|
lastLine.insertAdjacentText('beforeend', addedText);
|
||||||
@@ -590,10 +590,10 @@ function createServerRack() {
|
|||||||
newCursor.className = 'terminal-cursor' + (isRoot ? ' red' : '');
|
newCursor.className = 'terminal-cursor' + (isRoot ? ' red' : '');
|
||||||
lastLine.appendChild(newCursor);
|
lastLine.appendChild(newCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastInputValue = inputText;
|
lastInputValue = inputText;
|
||||||
});
|
});
|
||||||
|
|
||||||
} else if (serverType < 0.35) {
|
} else if (serverType < 0.35) {
|
||||||
// Vertical grill + fans
|
// Vertical grill + fans
|
||||||
const grillV = document.createElement('div');
|
const grillV = document.createElement('div');
|
||||||
@@ -608,7 +608,7 @@ function createServerRack() {
|
|||||||
grillV.style.top = '50%';
|
grillV.style.top = '50%';
|
||||||
grillV.style.transform = 'translateY(-50%)';
|
grillV.style.transform = 'translateY(-50%)';
|
||||||
face.appendChild(grillV);
|
face.appendChild(grillV);
|
||||||
|
|
||||||
const fanContainer = document.createElement('div');
|
const fanContainer = document.createElement('div');
|
||||||
fanContainer.className = 'fan-container';
|
fanContainer.className = 'fan-container';
|
||||||
fanContainer.style.position = 'absolute';
|
fanContainer.style.position = 'absolute';
|
||||||
@@ -616,46 +616,46 @@ function createServerRack() {
|
|||||||
fanContainer.style.top = '50%';
|
fanContainer.style.top = '50%';
|
||||||
fanContainer.style.transform = 'translateY(-50%)';
|
fanContainer.style.transform = 'translateY(-50%)';
|
||||||
fanContainer.style.zIndex = '1';
|
fanContainer.style.zIndex = '1';
|
||||||
|
|
||||||
const fanCount = Math.floor(Math.random() * 2) + 1;
|
const fanCount = Math.floor(Math.random() * 2) + 1;
|
||||||
const fanSpeeds = ['fan-slow', 'fan-medium', 'fan-fast'];
|
const fanSpeeds = ['fan-slow', 'fan-medium', 'fan-fast'];
|
||||||
for (let f = 0; f < fanCount; f++) {
|
for (let f = 0; f < fanCount; f++) {
|
||||||
const fan = document.createElement('div');
|
const fan = document.createElement('div');
|
||||||
fan.className = `fan ${fanSpeeds[Math.floor(Math.random() * fanSpeeds.length)]}`;
|
fan.className = `fan ${fanSpeeds[Math.floor(Math.random() * fanSpeeds.length)]}`;
|
||||||
|
|
||||||
const blade = document.createElement('div');
|
const blade = document.createElement('div');
|
||||||
blade.className = 'fan-blade';
|
blade.className = 'fan-blade';
|
||||||
fan.appendChild(blade);
|
fan.appendChild(blade);
|
||||||
|
|
||||||
const center = document.createElement('div');
|
const center = document.createElement('div');
|
||||||
center.className = 'fan-center';
|
center.className = 'fan-center';
|
||||||
fan.appendChild(center);
|
fan.appendChild(center);
|
||||||
|
|
||||||
fanContainer.appendChild(fan);
|
fanContainer.appendChild(fan);
|
||||||
}
|
}
|
||||||
|
|
||||||
face.appendChild(fanContainer);
|
face.appendChild(fanContainer);
|
||||||
|
|
||||||
const ledGroup = document.createElement('div');
|
const ledGroup = document.createElement('div');
|
||||||
ledGroup.className = 'led-group';
|
ledGroup.className = 'led-group';
|
||||||
ledGroup.style.position = 'absolute';
|
ledGroup.style.position = 'absolute';
|
||||||
ledGroup.style.top = '8px';
|
ledGroup.style.top = '8px';
|
||||||
ledGroup.style.left = '50%';
|
ledGroup.style.left = '50%';
|
||||||
ledGroup.style.transform = 'translateX(-50%)';
|
ledGroup.style.transform = 'translateX(-50%)';
|
||||||
|
|
||||||
const ledCount = Math.floor(Math.random() * 3) + 1;
|
const ledCount = Math.floor(Math.random() * 3) + 1;
|
||||||
const blinkClasses = ['led-blink-1', 'led-blink-2', 'led-blink-3', 'led-blink-4'];
|
const blinkClasses = ['led-blink-1', 'led-blink-2', 'led-blink-3', 'led-blink-4'];
|
||||||
const colorClasses = ['led-green', 'led-blue', 'led-yellow', 'led-red'];
|
const colorClasses = ['led-green', 'led-blue', 'led-yellow', 'led-red'];
|
||||||
|
|
||||||
for (let l = 0; l < ledCount; l++) {
|
for (let l = 0; l < ledCount; l++) {
|
||||||
const led = document.createElement('div');
|
const led = document.createElement('div');
|
||||||
led.className = `led ${colorClasses[Math.floor(Math.random() * colorClasses.length)]} ${blinkClasses[Math.floor(Math.random() * blinkClasses.length)]}`;
|
led.className = `led ${colorClasses[Math.floor(Math.random() * colorClasses.length)]} ${blinkClasses[Math.floor(Math.random() * blinkClasses.length)]}`;
|
||||||
led.style.animationDelay = `${Math.random() * 3}s`;
|
led.style.animationDelay = `${Math.random() * 3}s`;
|
||||||
ledGroup.appendChild(led);
|
ledGroup.appendChild(led);
|
||||||
}
|
}
|
||||||
|
|
||||||
face.appendChild(ledGroup);
|
face.appendChild(ledGroup);
|
||||||
|
|
||||||
} else if (serverType < 0.7) {
|
} else if (serverType < 0.7) {
|
||||||
// Horizontal grill
|
// Horizontal grill
|
||||||
const grillH = document.createElement('div');
|
const grillH = document.createElement('div');
|
||||||
@@ -670,27 +670,27 @@ function createServerRack() {
|
|||||||
grillH.style.top = '50%';
|
grillH.style.top = '50%';
|
||||||
grillH.style.transform = 'translate(-50%, -50%)';
|
grillH.style.transform = 'translate(-50%, -50%)';
|
||||||
face.appendChild(grillH);
|
face.appendChild(grillH);
|
||||||
|
|
||||||
const ledGroup = document.createElement('div');
|
const ledGroup = document.createElement('div');
|
||||||
ledGroup.className = 'led-group';
|
ledGroup.className = 'led-group';
|
||||||
ledGroup.style.position = 'absolute';
|
ledGroup.style.position = 'absolute';
|
||||||
ledGroup.style.right = '16px';
|
ledGroup.style.right = '16px';
|
||||||
ledGroup.style.top = '50%';
|
ledGroup.style.top = '50%';
|
||||||
ledGroup.style.transform = 'translateY(-50%)';
|
ledGroup.style.transform = 'translateY(-50%)';
|
||||||
|
|
||||||
const ledCount = Math.floor(Math.random() * 3) + 1;
|
const ledCount = Math.floor(Math.random() * 3) + 1;
|
||||||
const blinkClasses = ['led-blink-1', 'led-blink-2', 'led-blink-3', 'led-blink-4'];
|
const blinkClasses = ['led-blink-1', 'led-blink-2', 'led-blink-3', 'led-blink-4'];
|
||||||
const colorClasses = ['led-green', 'led-blue', 'led-yellow', 'led-red'];
|
const colorClasses = ['led-green', 'led-blue', 'led-yellow', 'led-red'];
|
||||||
|
|
||||||
for (let l = 0; l < ledCount; l++) {
|
for (let l = 0; l < ledCount; l++) {
|
||||||
const led = document.createElement('div');
|
const led = document.createElement('div');
|
||||||
led.className = `led ${colorClasses[Math.floor(Math.random() * colorClasses.length)]} ${blinkClasses[Math.floor(Math.random() * blinkClasses.length)]}`;
|
led.className = `led ${colorClasses[Math.floor(Math.random() * colorClasses.length)]} ${blinkClasses[Math.floor(Math.random() * blinkClasses.length)]}`;
|
||||||
led.style.animationDelay = `${Math.random() * 3}s`;
|
led.style.animationDelay = `${Math.random() * 3}s`;
|
||||||
ledGroup.appendChild(led);
|
ledGroup.appendChild(led);
|
||||||
}
|
}
|
||||||
|
|
||||||
face.appendChild(ledGroup);
|
face.appendChild(ledGroup);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Drive bays
|
// Drive bays
|
||||||
const driveBayContainer = document.createElement('div');
|
const driveBayContainer = document.createElement('div');
|
||||||
@@ -701,7 +701,7 @@ function createServerRack() {
|
|||||||
driveBayContainer.style.left = '50%';
|
driveBayContainer.style.left = '50%';
|
||||||
driveBayContainer.style.top = '50%';
|
driveBayContainer.style.top = '50%';
|
||||||
driveBayContainer.style.transform = 'translate(-50%, -50%)';
|
driveBayContainer.style.transform = 'translate(-50%, -50%)';
|
||||||
|
|
||||||
const driveBays = Math.floor(Math.random() * 3) + 6;
|
const driveBays = Math.floor(Math.random() * 3) + 6;
|
||||||
for (let b = 0; b < driveBays; b++) {
|
for (let b = 0; b < driveBays; b++) {
|
||||||
const bay = document.createElement('div');
|
const bay = document.createElement('div');
|
||||||
@@ -709,60 +709,60 @@ function createServerRack() {
|
|||||||
driveBayContainer.appendChild(bay);
|
driveBayContainer.appendChild(bay);
|
||||||
}
|
}
|
||||||
face.appendChild(driveBayContainer);
|
face.appendChild(driveBayContainer);
|
||||||
|
|
||||||
const ledGroup = document.createElement('div');
|
const ledGroup = document.createElement('div');
|
||||||
ledGroup.className = 'led-group';
|
ledGroup.className = 'led-group';
|
||||||
ledGroup.style.position = 'absolute';
|
ledGroup.style.position = 'absolute';
|
||||||
ledGroup.style.right = '10px';
|
ledGroup.style.right = '10px';
|
||||||
ledGroup.style.top = '50%';
|
ledGroup.style.top = '50%';
|
||||||
ledGroup.style.transform = 'translateY(-50%)';
|
ledGroup.style.transform = 'translateY(-50%)';
|
||||||
|
|
||||||
const ledCount = Math.floor(Math.random() * 3) + 1;
|
const ledCount = Math.floor(Math.random() * 3) + 1;
|
||||||
const blinkClasses = ['led-blink-1', 'led-blink-2', 'led-blink-3', 'led-blink-4'];
|
const blinkClasses = ['led-blink-1', 'led-blink-2', 'led-blink-3', 'led-blink-4'];
|
||||||
const colorClasses = ['led-green', 'led-blue', 'led-yellow', 'led-red'];
|
const colorClasses = ['led-green', 'led-blue', 'led-yellow', 'led-red'];
|
||||||
|
|
||||||
for (let l = 0; l < ledCount; l++) {
|
for (let l = 0; l < ledCount; l++) {
|
||||||
const led = document.createElement('div');
|
const led = document.createElement('div');
|
||||||
led.className = `led ${colorClasses[Math.floor(Math.random() * colorClasses.length)]} ${blinkClasses[Math.floor(Math.random() * blinkClasses.length)]}`;
|
led.className = `led ${colorClasses[Math.floor(Math.random() * colorClasses.length)]} ${blinkClasses[Math.floor(Math.random() * blinkClasses.length)]}`;
|
||||||
led.style.animationDelay = `${Math.random() * 3}s`;
|
led.style.animationDelay = `${Math.random() * 3}s`;
|
||||||
ledGroup.appendChild(led);
|
ledGroup.appendChild(led);
|
||||||
}
|
}
|
||||||
|
|
||||||
face.appendChild(ledGroup);
|
face.appendChild(ledGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isTerminal) {
|
if (!isTerminal) {
|
||||||
const serviceLabel = document.createElement('div');
|
const serviceLabel = document.createElement('div');
|
||||||
serviceLabel.className = 'service-label';
|
serviceLabel.className = 'service-label';
|
||||||
serviceLabel.textContent = services[Math.floor(Math.random() * services.length)];
|
serviceLabel.textContent = services[Math.floor(Math.random() * services.length)];
|
||||||
face.appendChild(serviceLabel);
|
face.appendChild(serviceLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
unit.appendChild(face);
|
unit.appendChild(face);
|
||||||
}
|
}
|
||||||
|
|
||||||
rackContainer.appendChild(unit);
|
rackContainer.appendChild(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bottomBar = document.createElement('div');
|
const bottomBar = document.createElement('div');
|
||||||
bottomBar.className = 'rack-bottom-bar';
|
bottomBar.className = 'rack-bottom-bar';
|
||||||
rackContainer.appendChild(bottomBar);
|
rackContainer.appendChild(bottomBar);
|
||||||
|
|
||||||
bgContainer.appendChild(rackContainer);
|
bgContainer.appendChild(rackContainer);
|
||||||
|
|
||||||
let ticking = false;
|
let ticking = false;
|
||||||
|
|
||||||
// Update the parallax scroll position of the rack container
|
// Update the parallax scroll position of the rack container
|
||||||
function updateParallax() {
|
function updateParallax() {
|
||||||
const scrolled = window.pageYOffset;
|
const scrolled = window.pageYOffset;
|
||||||
const parallaxSpeed = 0.3;
|
const parallaxSpeed = 0.3;
|
||||||
const translateY = scrolled * parallaxSpeed;
|
const translateY = scrolled * parallaxSpeed;
|
||||||
|
|
||||||
rackContainer.style.transform = `translateX(-50%) translateY(${-translateY}px)`;
|
rackContainer.style.transform = `translateX(-50%) translateY(${-translateY}px)`;
|
||||||
|
|
||||||
ticking = false;
|
ticking = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('scroll', () => {
|
window.addEventListener('scroll', () => {
|
||||||
if (!ticking) {
|
if (!ticking) {
|
||||||
requestAnimationFrame(updateParallax);
|
requestAnimationFrame(updateParallax);
|
||||||
|
|||||||
+141
-47
@@ -1,4 +1,6 @@
|
|||||||
*, *::before, *::after {
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@@ -225,13 +227,11 @@ body {
|
|||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
background: repeating-linear-gradient(
|
background: repeating-linear-gradient(0deg,
|
||||||
0deg,
|
transparent,
|
||||||
transparent,
|
transparent 2px,
|
||||||
transparent 2px,
|
rgba(0, 0, 0, 0.15) 2px,
|
||||||
rgba(0, 0, 0, 0.15) 2px,
|
rgba(0, 0, 0, 0.15) 4px);
|
||||||
rgba(0, 0, 0, 0.15) 4px
|
|
||||||
);
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
@@ -270,8 +270,15 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes cursorBlink {
|
@keyframes cursorBlink {
|
||||||
0%, 100% { opacity: 1; }
|
|
||||||
50% { opacity: 0; }
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.eth-brand {
|
.eth-brand {
|
||||||
@@ -305,7 +312,7 @@ body {
|
|||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
inset 0 1px 0 rgba(255, 255, 255, 0.03),
|
inset 0 1px 0 rgba(255, 255, 255, 0.03),
|
||||||
0 2px 8px rgba(0, 0, 0, 0.4);
|
0 2px 8px rgba(0, 0, 0, 0.4);
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
@@ -506,8 +513,13 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
from { transform: rotate(0deg); }
|
from {
|
||||||
to { transform: rotate(360deg); }
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fan-slow {
|
.fan-slow {
|
||||||
@@ -572,25 +584,59 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes blink1 {
|
@keyframes blink1 {
|
||||||
0%, 100% { opacity: 1; }
|
|
||||||
50% { opacity: 0.2; }
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes blink2 {
|
@keyframes blink2 {
|
||||||
0%, 100% { opacity: 0.3; }
|
|
||||||
50% { opacity: 1; }
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes blink3 {
|
@keyframes blink3 {
|
||||||
0%, 100% { opacity: 1; }
|
|
||||||
30% { opacity: 0.1; }
|
0%,
|
||||||
60% { opacity: 0.8; }
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
30% {
|
||||||
|
opacity: 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
60% {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes blink4 {
|
@keyframes blink4 {
|
||||||
0%, 100% { opacity: 0.5; }
|
|
||||||
25% { opacity: 1; }
|
0%,
|
||||||
75% { opacity: 0.2; }
|
100% {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
25% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
75% {
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-mount {
|
.rack-mount {
|
||||||
@@ -649,13 +695,11 @@ body {
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background: repeating-linear-gradient(
|
background: repeating-linear-gradient(180deg,
|
||||||
180deg,
|
transparent,
|
||||||
transparent,
|
transparent 20px,
|
||||||
transparent 20px,
|
rgba(0, 0, 0, 0.3) 20px,
|
||||||
rgba(0, 0, 0, 0.3) 20px,
|
rgba(0, 0, 0, 0.3) 21px);
|
||||||
rgba(0, 0, 0, 0.3) 21px
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-label {
|
.rack-label {
|
||||||
@@ -808,8 +852,15 @@ nav .nav-inner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
0%, 100% { opacity: 1; }
|
|
||||||
50% { opacity: 0.4; }
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero h1 {
|
.hero h1 {
|
||||||
@@ -1234,12 +1285,30 @@ section {
|
|||||||
line-height: 1.8;
|
line-height: 1.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.code-keyword { color: #c084fc; }
|
.code-keyword {
|
||||||
.code-function { color: #60a5fa; }
|
color: #c084fc;
|
||||||
.code-string { color: #34d399; }
|
}
|
||||||
.code-comment { color: #52525b; font-style: italic; }
|
|
||||||
.code-variable { color: #f472b6; }
|
.code-function {
|
||||||
.code-operator { color: #fbbf24; }
|
color: #60a5fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-string {
|
||||||
|
color: #34d399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-comment {
|
||||||
|
color: #52525b;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-variable {
|
||||||
|
color: #f472b6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-operator {
|
||||||
|
color: #fbbf24;
|
||||||
|
}
|
||||||
|
|
||||||
.project-info {
|
.project-info {
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
@@ -1625,6 +1694,7 @@ footer p {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(100px) scale(0.9);
|
transform: translateX(100px) scale(0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateX(0) scale(1);
|
transform: translateX(0) scale(1);
|
||||||
@@ -1636,6 +1706,7 @@ footer p {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateX(0) scale(1);
|
transform: translateX(0) scale(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(100px) scale(0.9);
|
transform: translateX(100px) scale(0.9);
|
||||||
@@ -1679,14 +1750,37 @@ footer p {
|
|||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-links.active li:nth-child(1) { transition-delay: 0.05s; }
|
.nav-links.active li:nth-child(1) {
|
||||||
.nav-links.active li:nth-child(2) { transition-delay: 0.1s; }
|
transition-delay: 0.05s;
|
||||||
.nav-links.active li:nth-child(3) { transition-delay: 0.15s; }
|
}
|
||||||
.nav-links.active li:nth-child(4) { transition-delay: 0.2s; }
|
|
||||||
.nav-links.active li:nth-child(5) { transition-delay: 0.25s; }
|
.nav-links.active li:nth-child(2) {
|
||||||
.nav-links.active li:nth-child(6) { transition-delay: 0.3s; }
|
transition-delay: 0.1s;
|
||||||
.nav-links.active li:nth-child(7) { transition-delay: 0.35s; }
|
}
|
||||||
.nav-links.active li:nth-child(8) { transition-delay: 0.4s; }
|
|
||||||
|
.nav-links.active li:nth-child(3) {
|
||||||
|
transition-delay: 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links.active li:nth-child(4) {
|
||||||
|
transition-delay: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links.active li:nth-child(5) {
|
||||||
|
transition-delay: 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links.active li:nth-child(6) {
|
||||||
|
transition-delay: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links.active li:nth-child(7) {
|
||||||
|
transition-delay: 0.35s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links.active li:nth-child(8) {
|
||||||
|
transition-delay: 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
.hamburger {
|
.hamburger {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -1780,4 +1874,4 @@ footer p {
|
|||||||
.about-stats {
|
.about-stats {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user