error-page-studio / templates /export_theme.html
duqing2026's picture
升级优化
d2cc112
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title | default('404') }}</title>
<style>
:root {
--bg-color: {{ bgColor | default('#ffffff') }};
--text-color: {{ textColor | default('#1f2937') }};
--accent-color: {{ accentColor | default('#ef4444') }};
}
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background-color: var(--bg-color);
color: var(--text-color);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
text-align: center;
overflow-x: hidden;
}
.container {
max-width: 600px;
padding: 20px;
}
h1 {
font-size: 5rem;
margin: 0;
line-height: 1;
font-weight: 800;
color: var(--accent-color);
}
p {
font-size: 1.5rem;
margin: 20px 0;
opacity: 0.8;
}
.btn {
display: inline-block;
padding: 12px 24px;
background-color: var(--accent-color);
color: var(--bg-color);
text-decoration: none;
border-radius: 6px;
font-weight: 600;
transition: opacity 0.2s;
margin-top: 20px;
}
.btn:hover {
opacity: 0.9;
}
/* Retro Theme Overrides */
{% if theme == 'retro' %}
body {
font-family: 'Courier New', Courier, monospace;
}
h1 {
text-shadow: 2px 2px 0px var(--text-color);
}
.btn {
border-radius: 0;
border: 2px solid var(--text-color);
background: transparent;
color: var(--text-color);
}
.btn:hover {
background: var(--text-color);
color: var(--bg-color);
}
{% endif %}
/* Minimal Theme Overrides */
{% if theme == 'minimal' %}
h1 {
font-size: 3rem;
font-weight: 300;
}
p {
font-size: 1rem;
}
.btn {
border-radius: 50px;
}
{% endif %}
/* Illustrations */
.illustration {
margin-bottom: 30px;
height: 150px;
display: flex;
align-items: center;
justify-content: center;
}
.ghost {
font-size: 100px;
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
100% { transform: translateY(0px); }
}
/* Game Container */
#game-container {
margin-top: 40px;
display: none;
border: 2px solid var(--text-color);
padding: 10px;
background: rgba(0,0,0,0.05);
}
canvas {
background: var(--bg-color);
display: block;
}
.game-toggle {
margin-top: 20px;
font-size: 0.9rem;
cursor: pointer;
text-decoration: underline;
color: var(--accent-color);
}
</style>
</head>
<body>
<div class="container">
<div class="illustration">
{% if illustration == 'ghost' %}
<div class="ghost">👻</div>
{% elif illustration == 'robot' %}
<div class="ghost">🤖</div>
{% elif illustration == 'broken' %}
<div class="ghost">💔</div>
{% elif illustration == 'planet' %}
<div class="ghost">🪐</div>
{% else %}
<!-- Default fallback if illustration matches nothing -->
<div class="ghost">👻</div>
{% endif %}
</div>
<h1>{{ title | default('404') }}</h1>
<p>{{ message | default('Page not found') }}</p>
<a href="{{ buttonLink | default('/') }}" class="btn">{{ buttonText | default('Go Home') }}</a>
{% if showGame %}
<div class="game-toggle" onclick="toggleGame()">Play Snake while you wait?</div>
<div id="game-container">
<canvas id="gameCanvas" width="300" height="300"></canvas>
<div style="font-size: 0.8rem; margin-top: 5px;">Use Arrow Keys to Move</div>
</div>
<script>
let gameRunning = false;
let canvas, ctx;
let snake = [{x: 10, y: 10}];
let food = {x: 15, y: 15};
let dx = 0;
let dy = 0;
let score = 0;
let gridSize = 15;
let tileCount = 20;
let gameInterval;
function toggleGame() {
const container = document.getElementById('game-container');
if (container.style.display === 'block') {
container.style.display = 'none';
gameRunning = false;
clearInterval(gameInterval);
} else {
container.style.display = 'block';
if (!canvas) initGame();
resetGame();
}
}
function initGame() {
canvas = document.getElementById('gameCanvas');
ctx = canvas.getContext('2d');
document.addEventListener('keydown', keyDownEvent);
}
function resetGame() {
snake = [{x: 10, y: 10}];
food = {x: 15, y: 15};
dx = 0;
dy = 0;
score = 0;
gameRunning = true;
if (gameInterval) clearInterval(gameInterval);
gameInterval = setInterval(drawGame, 100);
}
function drawGame() {
if (!gameRunning) return;
// Move snake
const head = {x: snake[0].x + dx, y: snake[0].y + dy};
// Wrap around
if (head.x < 0) head.x = tileCount - 1;
if (head.x >= tileCount) head.x = 0;
if (head.y < 0) head.y = tileCount - 1;
if (head.y >= tileCount) head.y = 0;
// Check collision with self
for (let i = 0; i < snake.length; i++) {
if (head.x === snake[i].x && head.y === snake[i].y) {
// Game Over logic (soft reset)
snake = [{x: 10, y: 10}];
dx = 0;
dy = 0;
}
}
snake.unshift(head);
// Check food
if (head.x === food.x && head.y === food.y) {
score++;
food = {
x: Math.floor(Math.random() * tileCount),
y: Math.floor(Math.random() * tileCount)
};
} else {
snake.pop();
}
// Draw
ctx.fillStyle = '{{ bgColor | default("#ffffff") }}';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Snake
ctx.fillStyle = '{{ accentColor | default("#ef4444") }}';
for (let i = 0; i < snake.length; i++) {
ctx.fillRect(snake[i].x * gridSize, snake[i].y * gridSize, gridSize - 2, gridSize - 2);
}
// Food
ctx.fillStyle = '{{ textColor | default("#1f2937") }}';
ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize - 2, gridSize - 2);
}
function keyDownEvent(e) {
switch(e.keyCode) {
case 37: if(dx !== 1) { dx = -1; dy = 0; } break;
case 38: if(dy !== 1) { dx = 0; dy = -1; } break;
case 39: if(dx !== -1) { dx = 1; dy = 0; } break;
case 40: if(dy !== -1) { dx = 0; dy = 1; } break;
}
}
</script>
{% endif %}
</div>
</body>
</html>