Begrüßungsseite (Landing Page) hinzugefügt

Features:
- Neue Welcome-Page als Einstiegspunkt (/)
- Minimalistische Landing Page mit Features-Übersicht
- Training jetzt unter /train erreichbar
- Theme-Toggle und Hilfe-Button integriert
- Alle internen Links aktualisiert

Routing:
- / → welcome() - Landing Page
- /train → train() - Hauptanwendung (vorher /)

Templates:
- welcome.html - Neue Begrüßungsseite
- statistics.html, settings.html, session_end.html - Links auf /train
- main.js - Redirect zu /train

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
jamulix 2025-10-28 13:46:54 +01:00
commit 423b978384
6 changed files with 197 additions and 6 deletions

7
app.py
View file

@ -334,7 +334,12 @@ with app.app_context():
logger.info(f"{len(lessons)} Lektionen geladen")
@app.route('/')
def index():
def welcome():
"""Begrüßungsseite / Landing Page"""
return render_template('welcome.html')
@app.route('/train')
def train():
"""Hauptseite des Tipptrainers"""
try:
# Hole den aktuellen Fortschritt aus der Datenbank

View file

@ -482,7 +482,7 @@ class TypewriterApp {
if (response.redirect) {
window.location.href = response.redirect;
} else {
window.location.href = '/';
window.location.href = '/train';
}
} catch (error) {
this.uiManager.alert('Fehler beim Beenden der Sitzung: ' + error.message);

View file

@ -135,7 +135,7 @@
<!-- Action Buttons -->
<div class="action-buttons">
<a href="/" class="btn btn-success btn-lg">Weiter üben</a>
<a href="/train" class="btn btn-success btn-lg">Weiter üben</a>
<button onclick="shutdownServer()" class="btn btn-danger btn-lg">ENDE</button>
</div>
</div>

View file

@ -24,7 +24,7 @@
<i data-lucide="sun" id="theme-toggle-sun" style="width: 24px; height: 24px; position: absolute; top: 0; left: 0;"></i>
<i data-lucide="moon" id="theme-toggle-moon" style="width: 24px; height: 24px; position: absolute; top: 0; left: 0; display: none;"></i>
</div>
<button onclick="window.location.href='/'" class="btn btn-outline-light">
<button onclick="window.location.href='/train'" class="btn btn-outline-light">
Zurück zum Training
</button>
</div>
@ -191,7 +191,7 @@
.then(data => {
if (data.status === 'success') {
alert('Einstellungen wurden gespeichert!');
window.location.href = '/';
window.location.href = '/train';
} else {
alert('Fehler beim Speichern der Einstellungen!');
}

View file

@ -25,7 +25,7 @@
<i data-lucide="sun" id="theme-toggle-sun" style="width: 24px; height: 24px; position: absolute; top: 0; left: 0;"></i>
<i data-lucide="moon" id="theme-toggle-moon" style="width: 24px; height: 24px; position: absolute; top: 0; left: 0; display: none;"></i>
</div>
<button onclick="window.location.href='/'" class="btn btn-outline-light">
<button onclick="window.location.href='/train'" class="btn btn-outline-light">
Zurück zum Training
</button>
</div>

186
templates/welcome.html Normal file
View file

@ -0,0 +1,186 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Willkommen - Typewriter Trainer</title>
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='favicon.svg') }}">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
<style>
.welcome-container {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.welcome-card {
max-width: 600px;
width: 100%;
}
.logo-icon {
font-size: 5rem;
margin-bottom: 1rem;
}
.feature-list {
text-align: left;
display: inline-block;
}
.feature-item {
font-size: 1.1rem;
margin: 0.5rem 0;
}
.btn-start {
font-size: 1.3rem;
padding: 1rem 3rem;
border-radius: 50px;
font-weight: 600;
transition: all 0.3s;
}
.btn-start:hover {
transform: translateY(-2px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
.version-badge {
font-size: 0.9rem;
opacity: 0.7;
}
.footer-icons {
position: fixed;
top: 20px;
right: 20px;
display: flex;
gap: 15px;
}
.footer-icons button {
background: none;
border: none;
cursor: pointer;
padding: 8px;
border-radius: 8px;
transition: background-color 0.3s;
}
.footer-icons button:hover {
background-color: rgba(0, 0, 0, 0.1);
}
[data-bs-theme="dark"] .footer-icons button:hover {
background-color: rgba(255, 255, 255, 0.1);
}
</style>
</head>
<body class="bg-light" data-bs-theme="light">
<!-- Theme & Hilfe Icons -->
<div class="footer-icons">
<button id="theme-toggle" aria-label="Theme wechseln" title="Theme wechseln">
<i data-lucide="sun" id="theme-toggle-sun" style="width: 24px; height: 24px;"></i>
<i data-lucide="moon" id="theme-toggle-moon" style="width: 24px; height: 24px; display: none;"></i>
</button>
<button onclick="window.open('/hilfe', '_blank')" aria-label="Hilfe öffnen" title="Hilfe öffnen">
<i data-lucide="help-circle" style="width: 24px; height: 24px;"></i>
</button>
</div>
<div class="welcome-container">
<div class="welcome-card text-center p-4">
<div class="card shadow-lg border-0">
<div class="card-body p-5">
<!-- Logo -->
<div class="logo-icon">
🎹
</div>
<!-- Title -->
<h1 class="mb-2">Typewriter Trainer</h1>
<p class="version-badge mb-4">{{ APP_VERSION }}</p>
<!-- Subtitle -->
<p class="lead mb-4">
Lernen Sie das Zehnfingersystem<br>
mit adaptivem Metronom
</p>
<!-- Features -->
<div class="mb-4">
<ul class="feature-list list-unstyled">
<li class="feature-item">✓ 43 aufbauende Lektionen</li>
<li class="feature-item">✓ Echtzeit-Statistiken & Präzisions-Anzeige</li>
<li class="feature-item">✓ Adaptives Metronom mit max. Geschwindigkeit</li>
<li class="feature-item">✓ Dark/Light Mode & persistente Einstellungen</li>
</ul>
</div>
<!-- CTA Buttons -->
<div class="d-grid gap-3">
<a href="/train" class="btn btn-success btn-start">
Training starten
</a>
<a href="/statistics" class="btn btn-outline-primary">
Statistiken ansehen
</a>
</div>
<!-- Info Links -->
<div class="mt-4">
<small class="text-muted">
<a href="/hilfe" target="_blank" class="text-decoration-none">Hilfe & Anleitung</a>
|
<a href="/settings" class="text-decoration-none">Einstellungen</a>
</small>
</div>
</div>
</div>
<!-- Footer -->
<div class="mt-3 text-muted">
<small>
Entwickelt mit ❤️ für effektives Tipptraining<br>
<a href="https://github.com/jamulix/typewriter" target="_blank" class="text-decoration-none">
<i data-lucide="github" style="width: 16px; height: 16px; display: inline;"></i>
GitHub
</a>
</small>
</div>
</div>
</div>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Theme Management
function initializeTheme() {
const savedTheme = localStorage.getItem('theme') || 'light';
document.body.setAttribute('data-bs-theme', savedTheme);
updateThemeButton(savedTheme);
}
function toggleTheme() {
const currentTheme = document.body.getAttribute('data-bs-theme');
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
document.body.setAttribute('data-bs-theme', newTheme);
localStorage.setItem('theme', newTheme);
updateThemeButton(newTheme);
}
function updateThemeButton(theme) {
const sunIcon = document.getElementById('theme-toggle-sun');
const moonIcon = document.getElementById('theme-toggle-moon');
if (theme === 'dark') {
sunIcon.style.display = 'none';
moonIcon.style.display = 'inline';
} else {
sunIcon.style.display = 'inline';
moonIcon.style.display = 'none';
}
}
// Initialize
document.addEventListener('DOMContentLoaded', function() {
lucide.createIcons();
initializeTheme();
document.getElementById('theme-toggle').addEventListener('click', toggleTheme);
});
</script>
</body>
</html>