Add IT-Tools and Retro Arcade, fix category styling, update RPi5 specs

This commit is contained in:
Roberth Rajala 2026-02-01 17:41:47 +01:00
parent 0c61760313
commit 040254f81d
3 changed files with 564 additions and 5 deletions

View File

@ -209,11 +209,11 @@
<div class="infra-icon">🍓</div> <div class="infra-icon">🍓</div>
<div class="infra-content"> <div class="infra-content">
<h3>RPi 5 Node</h3> <h3>RPi 5 Node</h3>
<p>Raspberry Pi 5 running Docker containers and Portainer for edge workloads</p> <p>Raspberry Pi 5 8GB with 128GB NVMe running Docker containers and Portainer</p>
<div class="infra-specs"> <div class="infra-specs">
<span class="spec">8GB RAM</span>
<span class="spec">128GB NVMe</span>
<span class="spec">ARM64</span> <span class="spec">ARM64</span>
<span class="spec">Docker</span>
<span class="spec">Portainer</span>
</div> </div>
</div> </div>
</div> </div>
@ -283,6 +283,42 @@
</svg> </svg>
</div> </div>
</a> </a>
<a href="https://tool.lemonlink.eu" class="service-card public" target="_blank" rel="noopener">
<div class="service-glow"></div>
<div class="service-icon" style="--icon-color: #f59e0b;">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M22.7 19l-9.1-9.1c.9-2.3.4-5-1.5-6.9-2-2-5-2.4-7.4-1.3L9 6 6 9 1.6 4.7C.4 7.1.9 10.1 2.9 12.1c1.9 1.9 4.6 2.4 6.9 1.5l9.1 9.1c.4.4 1 .4 1.4 0l2.3-2.3c.5-.4.5-1.1.1-1.4z"/></svg>
</div>
<h3 class="service-name">IT-Tools</h3>
<p class="service-desc">Handy tools for developers and IT professionals</p>
<div class="service-status checking" data-status-url="https://tool.lemonlink.eu">
<span class="status-dot"></span>
<span class="status-text">Checking...</span>
</div>
<div class="service-arrow">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M7 17L17 7M17 7H7M17 7V17"/>
</svg>
</div>
</a>
<a href="https://retro.lemonlink.eu" class="service-card public" target="_blank" rel="noopener">
<div class="service-glow"></div>
<div class="service-icon" style="--icon-color: #8b5cf6;">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-10 7H8v3H6v-3H3v-2h3V8h2v3h3v2zm4.5 2c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm4-3c-.83 0-1.5-.67-1.5-1.5S18.67 9 19.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></svg>
</div>
<h3 class="service-name">🎮 Retro Arcade</h3>
<p class="service-desc">Play classic DOS games including Doom! (Legally free)</p>
<div class="service-status checking" data-status-url="https://retro.lemonlink.eu">
<span class="status-dot"></span>
<span class="status-text">Checking...</span>
</div>
<div class="service-arrow">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M7 17L17 7M17 7H7M17 7V17"/>
</svg>
</div>
</a>
</div> </div>
</div> </div>
@ -550,6 +586,11 @@
<span class="node-name">projects</span> <span class="node-name">projects</span>
<span class="node-desc">My Code</span> <span class="node-desc">My Code</span>
</a> </a>
<a href="https://retro.lemonlink.eu" class="domain-node" target="_blank">
<div class="node-pulse"></div>
<span class="node-name">retro</span>
<span class="node-desc">🎮 Classic Games</span>
</a>
</div> </div>
</div> </div>
</div> </div>

520
retro.html Normal file
View File

@ -0,0 +1,520 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🎮 Retro Arcade | LemonLink</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&family=Space+Grotesk:wght@400;600;700&display=swap" rel="stylesheet">
<style>
:root {
--retro-bg: #0a0a0f;
--retro-purple: #8b5cf6;
--retro-pink: #ec4899;
--retro-cyan: #22d3ee;
--retro-yellow: #facc15;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Space Grotesk', sans-serif;
background: var(--retro-bg);
color: #fff;
min-height: 100vh;
overflow-x: hidden;
}
/* CRT Scanline Effect */
.crt::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
rgba(18, 16, 16, 0) 50%,
rgba(0, 0, 0, 0.25) 50%
);
background-size: 100% 4px;
pointer-events: none;
z-index: 9999;
animation: scanline 8s linear infinite;
}
@keyframes scanline {
0% { transform: translateY(0); }
100% { transform: translateY(10px); }
}
/* Header */
.retro-header {
text-align: center;
padding: 3rem 1rem;
background: linear-gradient(180deg, rgba(139, 92, 246, 0.2) 0%, transparent 100%);
position: relative;
}
.back-link {
position: absolute;
top: 1.5rem;
left: 1.5rem;
color: var(--retro-cyan);
text-decoration: none;
font-size: 0.875rem;
display: flex;
align-items: center;
gap: 0.5rem;
transition: all 0.3s;
}
.back-link:hover {
color: var(--retro-yellow);
transform: translateX(-5px);
}
.retro-title {
font-family: 'Press Start 2P', cursive;
font-size: clamp(1.5rem, 5vw, 3rem);
background: linear-gradient(90deg, var(--retro-purple), var(--retro-pink), var(--retro-cyan));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-shadow: 0 0 30px rgba(139, 92, 246, 0.5);
animation: glow 2s ease-in-out infinite alternate;
margin-bottom: 1rem;
}
@keyframes glow {
from { filter: drop-shadow(0 0 10px rgba(139, 92, 246, 0.5)); }
to { filter: drop-shadow(0 0 20px rgba(236, 72, 153, 0.8)); }
}
.retro-subtitle {
color: #94a3b8;
font-size: 1.1rem;
max-width: 600px;
margin: 0 auto;
}
.legal-note {
margin-top: 1rem;
padding: 0.75rem 1.5rem;
background: rgba(34, 211, 238, 0.1);
border: 1px solid rgba(34, 211, 238, 0.3);
border-radius: 100px;
display: inline-block;
font-size: 0.8rem;
color: var(--retro-cyan);
}
/* Games Grid */
.games-container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.games-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
.game-card {
background: rgba(20, 20, 30, 0.8);
border: 2px solid rgba(139, 92, 246, 0.3);
border-radius: 16px;
overflow: hidden;
transition: all 0.3s;
position: relative;
}
.game-card::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(139, 92, 246, 0.1) 0%, transparent 50%);
opacity: 0;
transition: opacity 0.3s;
}
.game-card:hover {
transform: translateY(-5px);
border-color: var(--retro-purple);
box-shadow: 0 10px 40px rgba(139, 92, 246, 0.3);
}
.game-card:hover::before {
opacity: 1;
}
.game-preview {
height: 180px;
background: linear-gradient(135deg, #1a1a2e 0%, #0f0f1a 100%);
display: flex;
align-items: center;
justify-content: center;
font-size: 4rem;
position: relative;
overflow: hidden;
}
.game-preview::after {
content: '▶';
position: absolute;
font-size: 2rem;
opacity: 0;
transition: all 0.3s;
color: var(--retro-yellow);
text-shadow: 0 0 20px rgba(250, 204, 21, 0.8);
}
.game-card:hover .game-preview::after {
opacity: 1;
transform: scale(1.2);
}
.game-info {
padding: 1.5rem;
}
.game-title {
font-family: 'Press Start 2P', cursive;
font-size: 0.9rem;
color: var(--retro-yellow);
margin-bottom: 0.5rem;
}
.game-desc {
color: #94a3b8;
font-size: 0.9rem;
margin-bottom: 1rem;
}
.game-meta {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
}
.game-tag {
padding: 0.25rem 0.75rem;
background: rgba(139, 92, 246, 0.2);
border-radius: 100px;
font-size: 0.75rem;
color: var(--retro-purple);
}
.play-btn {
width: 100%;
padding: 1rem;
background: linear-gradient(90deg, var(--retro-purple), var(--retro-pink));
border: none;
border-radius: 8px;
color: #fff;
font-family: 'Space Grotesk', sans-serif;
font-weight: 600;
font-size: 1rem;
cursor: pointer;
transition: all 0.3s;
text-transform: uppercase;
letter-spacing: 1px;
}
.play-btn:hover {
transform: scale(1.02);
box-shadow: 0 5px 20px rgba(139, 92, 246, 0.4);
}
/* Game Modal */
.game-modal {
display: none;
position: fixed;
inset: 0;
z-index: 10000;
background: rgba(0, 0, 0, 0.95);
backdrop-filter: blur(10px);
}
.game-modal.active {
display: flex;
flex-direction: column;
}
.game-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
background: rgba(20, 20, 30, 0.9);
border-bottom: 1px solid rgba(139, 92, 246, 0.3);
}
.game-modal-title {
font-family: 'Press Start 2P', cursive;
font-size: 0.8rem;
color: var(--retro-yellow);
}
.close-game {
background: rgba(239, 68, 68, 0.2);
border: 1px solid rgba(239, 68, 68, 0.5);
color: #ef4444;
padding: 0.5rem 1rem;
border-radius: 8px;
cursor: pointer;
font-family: 'Space Grotesk', sans-serif;
font-weight: 600;
transition: all 0.3s;
}
.close-game:hover {
background: rgba(239, 68, 68, 0.4);
}
.game-frame-container {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
.game-frame {
width: 100%;
max-width: 960px;
aspect-ratio: 4/3;
border: 2px solid var(--retro-purple);
border-radius: 8px;
background: #000;
}
.game-placeholder {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #94a3b8;
gap: 1rem;
}
.game-placeholder h3 {
color: var(--retro-cyan);
font-family: 'Press Start 2P', cursive;
font-size: 1rem;
}
.controls-hint {
background: rgba(20, 20, 30, 0.9);
padding: 1rem 2rem;
text-align: center;
color: #94a3b8;
font-size: 0.875rem;
}
.controls-hint kbd {
background: rgba(139, 92, 246, 0.2);
padding: 0.25rem 0.5rem;
border-radius: 4px;
color: var(--retro-cyan);
font-family: monospace;
}
/* Footer */
.retro-footer {
text-align: center;
padding: 2rem;
color: #64748b;
font-size: 0.875rem;
border-top: 1px solid rgba(139, 92, 246, 0.2);
}
.retro-footer a {
color: var(--retro-cyan);
text-decoration: none;
}
/* Responsive */
@media (max-width: 768px) {
.retro-title {
font-size: 1.2rem;
}
.games-grid {
grid-template-columns: 1fr;
}
.game-frame-container {
padding: 0.5rem;
}
}
</style>
</head>
<body class="crt">
<header class="retro-header">
<a href="https://lemonlink.eu" class="back-link">← Back to LemonLink</a>
<h1 class="retro-title">🎮 RETRO ARCADE</h1>
<p class="retro-subtitle">Classic DOS games running in your browser via WebAssembly</p>
<div class="legal-note">✅ All games are legally free/shareware</div>
</header>
<main class="games-container">
<div class="games-grid">
<!-- DOOM -->
<div class="game-card" data-game="doom">
<div class="game-preview">👹</div>
<div class="game-info">
<h2 class="game-title">DOOM</h2>
<p class="game-desc">The legendary first-person shooter that defined a genre. Fight demons on Mars!</p>
<div class="game-meta">
<span class="game-tag">FPS</span>
<span class="game-tag">1993</span>
<span class="game-tag">Shareware</span>
</div>
<button class="play-btn" onclick="openGame('doom', 'DOOM')">▶ PLAY NOW</button>
</div>
</div>
<!-- Duke Nukem 3D -->
<div class="game-card" data-game="duke3d">
<div class="game-preview">😎</div>
<div class="game-info">
<h2 class="game-title">Duke Nukem 3D</h2>
<p class="game-desc">Hail to the king, baby! Classic action shooter with attitude.</p>
<div class="game-meta">
<span class="game-tag">FPS</span>
<span class="game-tag">1996</span>
<span class="game-tag">Shareware</span>
</div>
<button class="play-btn" onclick="openGame('duke3d', 'Duke Nukem 3D')">▶ PLAY NOW</button>
</div>
</div>
<!-- Wolfenstein 3D -->
<div class="game-card" data-game="wolf3d">
<div class="game-preview">🪖</div>
<div class="game-info">
<h2 class="game-title">Wolfenstein 3D</h2>
<p class="game-desc">The grandfather of FPS games. Escape from Castle Wolfenstein!</p>
<div class="game-meta">
<span class="game-tag">FPS</span>
<span class="game-tag">1992</span>
<span class="game-tag">Free</span>
</div>
<button class="play-btn" onclick="openGame('wolf3d', 'Wolfenstein 3D')">▶ PLAY NOW</button>
</div>
</div>
<!-- Quake -->
<div class="game-card" data-game="quake">
<div class="game-preview"></div>
<div class="game-info">
<h2 class="game-title">Quake</h2>
<p class="game-desc">Revolutionary true 3D shooter. Fight the Lovecraftian horde!</p>
<div class="game-meta">
<span class="game-tag">FPS</span>
<span class="game-tag">1996</span>
<span class="game-tag">Shareware</span>
</div>
<button class="play-btn" onclick="openGame('quake', 'Quake')">▶ PLAY NOW</button>
</div>
</div>
<!-- SimCity Classic -->
<div class="game-card" data-game="simcity">
<div class="game-preview">🏙️</div>
<div class="game-info">
<h2 class="game-title">SimCity Classic</h2>
<p class="game-desc">Build and manage your own city. The ultimate city builder!</p>
<div class="game-meta">
<span class="game-tag">Strategy</span>
<span class="game-tag">1989</span>
<span class="game-tag">Free</span>
</div>
<button class="play-btn" onclick="openGame('simcity', 'SimCity Classic')">▶ PLAY NOW</button>
</div>
</div>
<!-- Oregon Trail -->
<div class="game-card" data-game="oregon">
<div class="game-preview">🐂</div>
<div class="game-info">
<h2 class="game-title">The Oregon Trail</h2>
<p class="game-desc">Relive the classic educational journey to the West Coast!</p>
<div class="game-meta">
<span class="game-tag">Edutainment</span>
<span class="game-tag">1971</span>
<span class="game-tag">Free</span>
</div>
<button class="play-btn" onclick="openGame('oregon', 'The Oregon Trail')">▶ PLAY NOW</button>
</div>
</div>
</div>
</main>
<!-- Game Modal -->
<div id="gameModal" class="game-modal">
<div class="game-modal-header">
<h2 class="game-modal-title" id="modalGameTitle">GAME</h2>
<button class="close-game" onclick="closeGame()">✕ CLOSE</button>
</div>
<div class="game-frame-container">
<div class="game-frame">
<div class="game-placeholder" id="gamePlaceholder">
<h3>🎮 Game Loading...</h3>
<p>This is a placeholder. To make games work, you'll need to:</p>
<ol style="text-align: left; max-width: 500px; line-height: 2;">
<li>Set up a DOSBox WebAssembly server</li>
<li>Host the game files (shareware versions are legal)</li>
<li>Point this iframe to your game server</li>
</ol>
<p style="margin-top: 1rem;">Recommended: Use <a href="https://js-dos.com" target="_blank" style="color: #22d3ee;">JS-DOS</a> or <a href="https://dosbox-x.com" target="_blank" style="color: #22d3ee;">DOSBox-X</a></p>
</div>
</div>
</div>
<div class="controls-hint">
Controls: <kbd>WASD</kbd> or <kbd>Arrows</kbd> to move • <kbd>Ctrl</kbd> to fire • <kbd>Space</kbd> to use • <kbd>Esc</kbd> for menu
</div>
</div>
<footer class="retro-footer">
<p>🍋 Powered by <a href="https://lemonlink.eu">LemonLink</a> | Games are shareware/freeware</p>
<p style="margin-top: 0.5rem; font-size: 0.75rem;">Doom, Quake, Duke Nukem are trademarks of their respective owners. Shareware versions used.</p>
</footer>
<script>
function openGame(game, title) {
document.getElementById('modalGameTitle').textContent = '🎮 ' + title;
document.getElementById('gameModal').classList.add('active');
document.body.style.overflow = 'hidden';
// Here you would load the actual game
// For now, it shows instructions on how to set it up
}
function closeGame() {
document.getElementById('gameModal').classList.remove('active');
document.body.style.overflow = '';
}
// Close on Escape
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') closeGame();
});
// Close on backdrop click
document.getElementById('gameModal').addEventListener('click', (e) => {
if (e.target.id === 'gameModal') closeGame();
});
</script>
</body>
</html>

View File

@ -1716,8 +1716,6 @@ body {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.75rem; gap: 0.75rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid var(--color-border);
} }
.category-icon { .category-icon {