Move server rack inline styles to CSS classes

Replace the per-element inline positioning in createServerRack()
with rack-*-pos utility classes in style.css. Also stop drawing
a random switch face brand from a list (only Framework ships)
and simplify the hero-click terminal toggle to use the shared
expand/collapse helpers.
This commit is contained in:
2026-09-18 17:23:37 -04:00
parent 3898dc3c5e
commit 010758b3e9
2 changed files with 70 additions and 57 deletions
+16 -56
View File
@@ -60,7 +60,8 @@ function createServerRack() {
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']; // Only one brand in the rack for now
const RACK_BRAND = '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'];
@@ -88,7 +89,7 @@ function createServerRack() {
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 = RACK_BRAND;
switchFace.appendChild(brandLabel); switchFace.appendChild(brandLabel);
const portCount = Math.floor(Math.random() * 4) + 5; const portCount = Math.floor(Math.random() * 4) + 5;
@@ -139,19 +140,12 @@ function createServerRack() {
bar.className = 'grill-v-bar'; bar.className = 'grill-v-bar';
grillV.appendChild(bar); grillV.appendChild(bar);
} }
grillV.style.position = 'absolute'; grillV.classList.add('rack-grill-v-pos');
grillV.style.left = '16px';
grillV.style.top = '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.classList.add('rack-fans-pos');
fanContainer.style.right = '16px';
fanContainer.style.top = '50%';
fanContainer.style.transform = 'translateY(-50%)';
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'];
@@ -174,10 +168,7 @@ function createServerRack() {
const ledGroup = document.createElement('div'); const ledGroup = document.createElement('div');
ledGroup.className = 'led-group'; ledGroup.className = 'led-group';
ledGroup.style.position = 'absolute'; ledGroup.classList.add('rack-leds-pos-top');
ledGroup.style.top = '8px';
ledGroup.style.left = '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'];
@@ -201,18 +192,12 @@ function createServerRack() {
bar.className = 'grill-h-bar'; bar.className = 'grill-h-bar';
grillH.appendChild(bar); grillH.appendChild(bar);
} }
grillH.style.position = 'absolute'; grillH.classList.add('rack-grill-h-pos');
grillH.style.left = '50%';
grillH.style.top = '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.classList.add('rack-leds-pos-right');
ledGroup.style.right = '16px';
ledGroup.style.top = '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'];
@@ -230,13 +215,7 @@ function createServerRack() {
} else { } else {
// Drive bays // Drive bays
const driveBayContainer = document.createElement('div'); const driveBayContainer = document.createElement('div');
driveBayContainer.style.display = 'flex'; driveBayContainer.className = 'rack-drives-pos';
driveBayContainer.style.gap = '8px';
driveBayContainer.style.alignItems = 'center';
driveBayContainer.style.position = 'absolute';
driveBayContainer.style.left = '50%';
driveBayContainer.style.top = '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++) {
@@ -248,10 +227,7 @@ function createServerRack() {
const ledGroup = document.createElement('div'); const ledGroup = document.createElement('div');
ledGroup.className = 'led-group'; ledGroup.className = 'led-group';
ledGroup.style.position = 'absolute'; ledGroup.classList.add('rack-leds-pos-right-tight');
ledGroup.style.right = '10px';
ledGroup.style.top = '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'];
@@ -319,28 +295,12 @@ heroEl.addEventListener('mouseup', () => { heroMouseDown = false; });
// Toggle terminal expansion when clicking the hero section // Toggle terminal expansion when clicking the hero section
heroEl.addEventListener('click', (e) => { heroEl.addEventListener('click', (e) => {
if (e.target.closest('.btn')) return; if (e.target.closest('.btn')) return;
if (activeTerminal && activeTerminal._mobileInput) { if (!activeTerminal) return;
if (activeTerminal.classList.contains('grown')) { if (activeTerminal.classList.contains('grown')) {
activeTerminal.classList.remove('grown'); collapseTerminal(activeTerminal);
activeTerminal.classList.remove('opaque'); activeTerminal._mobileInput?.blur();
const face = activeTerminal.closest('.server-face'); } else {
const unit = face?.closest('.rack-unit'); expandTerminal(activeTerminal);
face?.classList.remove('grown');
unit?.classList.remove('grown');
heroEl.classList.remove('shifted');
activeTerminal._mobileInput.blur();
document.querySelector('.rack-container')?.classList.remove('opaque');
} else {
activeTerminal._mobileInput.focus();
activeTerminal.classList.add('grown');
activeTerminal.classList.add('opaque');
const face = activeTerminal.closest('.server-face');
const unit = face?.closest('.rack-unit');
face?.classList.add('grown');
unit?.classList.add('grown');
heroEl.classList.add('shifted');
document.querySelector('.rack-container')?.classList.add('opaque');
}
} }
}); });
+54 -1
View File
@@ -1881,4 +1881,57 @@ footer p {
.about-stats { .about-stats {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
} }
/* Rack decoration placement (moved out of inline styles in script.js) */
.rack-grill-v-pos {
position: absolute;
left: 16px;
top: 50%;
transform: translateY(-50%);
}
.rack-grill-h-pos {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.rack-fans-pos {
position: absolute;
right: 16px;
top: 50%;
transform: translateY(-50%);
z-index: 1;
}
.rack-leds-pos-top {
position: absolute;
top: 8px;
left: 50%;
transform: translateX(-50%);
}
.rack-leds-pos-right {
position: absolute;
right: 16px;
top: 50%;
transform: translateY(-50%);
}
.rack-leds-pos-right-tight {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
}
.rack-drives-pos {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: flex;
gap: 8px;
align-items: center;
}