480 lines
23 KiB
HTML
480 lines
23 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||
<meta name="theme-color" content="#000000">
|
||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||
<title>VBB Netz Status</title>
|
||
<link rel="manifest" href="manifest.json">
|
||
<link rel="icon" type="image/png" href="images/favicon.png">
|
||
<link rel="apple-touch-icon" href="images/favicon.png">
|
||
<link rel="stylesheet" href="styles.css">
|
||
</head>
|
||
|
||
<!-- Leaflet CSS für Live-Map -->
|
||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
||
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
|
||
crossorigin=""/>
|
||
|
||
<!-- Leaflet JS für Live-Map -->
|
||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
||
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
|
||
crossorigin=""></script>
|
||
</head>
|
||
<body>
|
||
<div class="offline-indicator" id="offlineIndicator" role="status">
|
||
📵 Offline-Modus - Zeige gespeicherte Daten
|
||
</div>
|
||
|
||
<div class="ptr-container" id="ptrContainer">
|
||
<div class="ptr-spinner"></div>
|
||
</div>
|
||
|
||
<div class="header">
|
||
<div class="header-content">
|
||
<div class="header-title">
|
||
<h1>VBB NETZ STATUS</h1>
|
||
<div class="subtitle">Live-Nahverkehr für Berlin & Brandenburg</div>
|
||
<div class="author">by Aaron K. & Claude (Anthropic)</div>
|
||
</div>
|
||
<button class="menu-btn" id="menuBtn" aria-label="Menü öffnen">
|
||
☰
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Navigation Menu -->
|
||
<nav class="nav-menu" id="navMenu" aria-label="Hauptnavigation">
|
||
<div class="nav-header">
|
||
<h3>Funktionen</h3>
|
||
<button class="nav-close" id="navClose" aria-label="Menü schließen">×</button>
|
||
</div>
|
||
<div class="nav-items">
|
||
<button class="nav-item" data-view="home">
|
||
<span class="nav-icon">🏠</span>
|
||
<span class="nav-label">Start</span>
|
||
</button>
|
||
<button class="nav-item" data-view="departures">
|
||
<span class="nav-icon">🚇</span>
|
||
<span class="nav-label">Abfahrten</span>
|
||
</button>
|
||
<button class="nav-item" data-view="journey">
|
||
<span class="nav-icon">🗺️</span>
|
||
<span class="nav-label">Routenplaner</span>
|
||
</button>
|
||
<button class="nav-item" data-view="livemap">
|
||
<span class="nav-icon">🌍</span>
|
||
<span class="nav-label">Live-Map</span>
|
||
</button>
|
||
<button class="nav-item" data-view="developer">
|
||
<span class="nav-icon">👨💻</span>
|
||
<span class="nav-label">Für Entwickler</span>
|
||
</button>
|
||
</div>
|
||
</nav>
|
||
<div class="nav-overlay" id="navOverlay"></div>
|
||
|
||
<!-- View: Home -->
|
||
<div class="view-container active" id="view-home">
|
||
<div class="home-container">
|
||
|
||
<!-- Combined Hero + Navigation Box -->
|
||
<div class="home-hero-combined">
|
||
<!-- Navigation Hint OHNE Pfeil -->
|
||
<div class="home-nav-hint">
|
||
<div class="home-hint-text">
|
||
Tippe <strong>oben rechts auf "≡"</strong> um das Menü zu öffnen.<br>
|
||
Wähle dann <strong>Abfahrten</strong>, <strong>Routenplaner</strong> oder <strong>Live-Map</strong>.
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Hero Section -->
|
||
<div class="home-hero-title">
|
||
<h1>VBB NETZ STATUS</h1>
|
||
<p>Live-Nahverkehr für Berlin & Brandenburg</p>
|
||
<div class="home-version">v33.0</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Favoriten (per JS aus localStorage gerendert) -->
|
||
<div class="home-favorites" id="homeFavorites" style="display: none;"></div>
|
||
|
||
<!-- Quick Info Cards -->
|
||
<div class="home-quick-info">
|
||
<div class="home-info-card">
|
||
<div class="home-info-icon">🚇</div>
|
||
<div class="home-info-text">
|
||
<strong>Live-Abfahrten</strong>
|
||
<p>Echtzeit für alle VBB-Stationen</p>
|
||
</div>
|
||
</div>
|
||
<div class="home-info-card">
|
||
<div class="home-info-icon">🗺️</div>
|
||
<div class="home-info-text">
|
||
<strong>Routenplaner</strong>
|
||
<p>Schnellste Verbindungen finden</p>
|
||
</div>
|
||
</div>
|
||
<div class="home-info-card">
|
||
<div class="home-info-icon">🌍</div>
|
||
<div class="home-info-text">
|
||
<strong>Live-Map</strong>
|
||
<p>Fahrzeuge in Echtzeit verfolgen</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- Footer -->
|
||
<div class="home-footer">
|
||
<p><strong>Inoffizielle App</strong> – Nicht von VBB/BVG betrieben</p>
|
||
<p class="home-footer-small">Made with ❤️ for Berlin & Brandenburg</p>
|
||
<p class="home-footer-github">
|
||
<a href="https://github.com/Serverlele30/VBB-Status-Web-App" target="_blank">
|
||
⭐ Star on GitHub
|
||
</a>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- View: Abfahrten -->
|
||
<div class="view-container" id="view-departures">
|
||
<div class="container">
|
||
<div class="controls">
|
||
<div class="search-row">
|
||
<div class="search-container">
|
||
<input
|
||
type="text"
|
||
id="stationSearch"
|
||
class="search-input"
|
||
placeholder="Station suchen..."
|
||
aria-label="Station suchen"
|
||
autocomplete="off"
|
||
>
|
||
<button class="clear-btn" id="clearBtn" aria-label="Suche löschen">×</button>
|
||
<div class="suggestions" id="suggestions"></div>
|
||
</div>
|
||
<button class="location-btn-side" id="locationBtn" title="Nächste Station per GPS finden" aria-label="Nächste Station per GPS finden">
|
||
📍
|
||
</button>
|
||
</div>
|
||
<div class="button-group">
|
||
<button class="btn" id="refreshBtn" disabled>🔄 Aktualisieren</button>
|
||
</div>
|
||
|
||
<!-- Filter für Linientypen -->
|
||
<div class="departure-filters" id="departureFilters" style="display: none;">
|
||
<div class="filter-label">Filter:</div>
|
||
<button class="filter-btn active" data-filter="all">Alle</button>
|
||
<button class="filter-btn" data-filter="subway">🚇 U-Bahn</button>
|
||
<button class="filter-btn" data-filter="suburban">🚆 S-Bahn</button>
|
||
<button class="filter-btn" data-filter="tram">🚊 Tram</button>
|
||
<button class="filter-btn" data-filter="bus">🚌 Bus</button>
|
||
<button class="filter-btn" data-filter="regional">🚄 Regional</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="departuresContainer" class="departures-container"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- View: Routenplaner -->
|
||
<div class="view-container" id="view-journey">
|
||
<div class="container">
|
||
<div class="controls">
|
||
<div class="journey-inputs">
|
||
<div class="journey-input-group">
|
||
<label class="journey-label">🔵 Von</label>
|
||
<div class="search-row">
|
||
<div class="search-container">
|
||
<input
|
||
type="text"
|
||
id="journeyFrom"
|
||
class="search-input"
|
||
placeholder="Startstation..."
|
||
aria-label="Startstation"
|
||
autocomplete="off"
|
||
>
|
||
<button class="clear-btn" id="clearFromBtn" aria-label="Startstation löschen">×</button>
|
||
<div class="suggestions" id="suggestionsFrom"></div>
|
||
</div>
|
||
<button class="location-btn-side" id="locationFromBtn" title="Aktuellen Standort nutzen" aria-label="Aktuellen Standort als Start nutzen">
|
||
📍
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<button class="swap-btn" id="swapBtn" title="Start und Ziel tauschen" aria-label="Start und Ziel tauschen">
|
||
⇅
|
||
</button>
|
||
|
||
<div class="journey-input-group">
|
||
<label class="journey-label">🔴 Nach</label>
|
||
<div class="search-row">
|
||
<div class="search-container">
|
||
<input
|
||
type="text"
|
||
id="journeyTo"
|
||
class="search-input"
|
||
placeholder="Zielstation..."
|
||
aria-label="Zielstation"
|
||
autocomplete="off"
|
||
>
|
||
<button class="clear-btn" id="clearToBtn" aria-label="Zielstation löschen">×</button>
|
||
<div class="suggestions" id="suggestionsTo"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Zeitwahl: Abfahrt/Ankunft -->
|
||
<div class="journey-time-row">
|
||
<label class="journey-label" for="journeyTimeMode">🕐 Zeit</label>
|
||
<div class="journey-time-controls">
|
||
<select id="journeyTimeMode" class="journey-time-select" aria-label="Abfahrts- oder Ankunftszeit">
|
||
<option value="departure">Abfahrt um</option>
|
||
<option value="arrival">Ankunft bis</option>
|
||
</select>
|
||
<input type="datetime-local" id="journeyTimeInput" class="journey-time-input"
|
||
aria-label="Datum und Uhrzeit (leer = jetzt)">
|
||
<button type="button" id="journeyTimeClear" class="clear-btn journey-time-clear"
|
||
aria-label="Zeitwahl zurücksetzen" title="Zurücksetzen (= jetzt)">×</button>
|
||
</div>
|
||
<div class="journey-time-hint">Leer lassen = jetzt abfahren</div>
|
||
</div>
|
||
|
||
<div class="button-group">
|
||
<div style="font-size: 12px; opacity: 0.7; text-align: center; margin-bottom: 10px; color: #FFED00;">
|
||
Garantiert mind. 5 Min Umstiegszeit
|
||
</div>
|
||
<button class="btn btn-full-width" id="searchJourneyBtn" disabled>🔍 Route suchen</button>
|
||
</div>
|
||
|
||
<!-- Verkehrsmittel-Filter -->
|
||
<div class="journey-transport-filters">
|
||
<div class="filter-label">Verkehrsmittel:</div>
|
||
<button class="transport-filter-btn active" data-transport="subway">🚇 U-Bahn</button>
|
||
<button class="transport-filter-btn active" data-transport="suburban">🚆 S-Bahn</button>
|
||
<button class="transport-filter-btn active" data-transport="tram">🚊 Tram</button>
|
||
<button class="transport-filter-btn active" data-transport="bus">🚌 Bus</button>
|
||
<button class="transport-filter-btn active" data-transport="regional">🚄 Regional</button>
|
||
<button class="transport-filter-btn active" data-transport="express">🚅 Express</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="journeyContainer" class="journey-container"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- View: Live-Map -->
|
||
<div class="view-container" id="view-livemap">
|
||
<div class="livemap-container">
|
||
<div class="livemap-controls">
|
||
<div class="livemap-info">
|
||
<span id="vehicleCount" aria-live="polite">🚇 Lade Fahrzeuge...</span>
|
||
</div>
|
||
<div class="livemap-filters">
|
||
<button class="filter-btn active" data-type="all">🌐 Alle</button>
|
||
<button class="filter-btn" data-type="subway">🚇 U-Bahn</button>
|
||
<button class="filter-btn" data-type="suburban">🚆 S-Bahn</button>
|
||
<button class="filter-btn" data-type="tram">🚊 Tram</button>
|
||
<button class="filter-btn" data-type="bus">🚌 Bus</button>
|
||
</div>
|
||
</div>
|
||
<div id="liveMap"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- View: Für Entwickler -->
|
||
<div class="view-container" id="view-developer">
|
||
<div class="container">
|
||
<div class="developer-header">
|
||
<h2>👨💻 Für Entwickler</h2>
|
||
<p class="developer-subtitle">Technische Details, Changelog & Funktionen</p>
|
||
</div>
|
||
|
||
<!-- Developer Tabs -->
|
||
<div class="developer-tabs">
|
||
<button class="dev-tab active" data-tab="changelog">📋 Changelog</button>
|
||
<button class="dev-tab" data-tab="info">ℹ️ Info</button>
|
||
<button class="dev-tab" data-tab="features">✨ Features</button>
|
||
</div>
|
||
|
||
<!-- Tab: Changelog -->
|
||
<div class="dev-tab-content active" id="dev-changelog">
|
||
<div id="changelogContent" class="changelog-container">
|
||
<div class="loading-detail">⏳ Lade Changelog...</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tab: Info -->
|
||
<div class="dev-tab-content" id="dev-info">
|
||
<div class="dev-info-container">
|
||
<div class="dev-info-box">
|
||
<h3>🚀 Version Info</h3>
|
||
<table class="dev-info-table">
|
||
<tr><td>Version:</td><td><strong>30.0</strong></td></tr>
|
||
<tr><td>Release:</td><td>10.02.2026</td></tr>
|
||
<tr><td>Lizenz:</td><td>MIT</td></tr>
|
||
<tr><td>Status:</td><td><span class="status-badge-dev">✅ Stabil</span></td></tr>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="dev-info-box">
|
||
<h3>📦 Dependencies</h3>
|
||
<table class="dev-info-table">
|
||
<tr><td>Node.js:</td><td>≥ 16.0.0</td></tr>
|
||
<tr><td>npm:</td><td>≥ 8.0.0</td></tr>
|
||
<tr><td>mime-types:</td><td>^2.1.35</td></tr>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="dev-info-box">
|
||
<h3>🛠️ Tech Stack</h3>
|
||
<table class="dev-info-table">
|
||
<tr><td>Frontend:</td><td>Vanilla JS, CSS3, HTML5</td></tr>
|
||
<tr><td>Maps:</td><td>Leaflet.js</td></tr>
|
||
<tr><td>API:</td><td>VBB Transport REST v6</td></tr>
|
||
<tr><td>PWA:</td><td>Service Worker, Manifest</td></tr>
|
||
<tr><td>Server:</td><td>Node.js HTTPS</td></tr>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="dev-info-box">
|
||
<h3>📊 Statistiken</h3>
|
||
<table class="dev-info-table">
|
||
<tr><td>HTML:</td><td>407 Zeilen</td></tr>
|
||
<tr><td>CSS:</td><td>2689 Zeilen</td></tr>
|
||
<tr><td>JavaScript:</td><td>2161 Zeilen</td></tr>
|
||
<tr><td>Gesamt:</td><td>~5.300 Zeilen Code</td></tr>
|
||
</table>
|
||
</div>
|
||
|
||
<a href="https://github.com/Serverlele30/VBB-Status-Web-App"
|
||
target="_blank"
|
||
class="github-link-btn">
|
||
💻 Code auf GitHub ansehen
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tab: Features Detail -->
|
||
<div class="dev-tab-content" id="dev-features">
|
||
<div class="dev-features-container">
|
||
<details class="feature-detail" open>
|
||
<summary>🚇 Abfahrten-Monitor</summary>
|
||
<div class="feature-content">
|
||
<p><strong>Echtzeit-Abfahrten für alle VBB-Stationen</strong></p>
|
||
<ul>
|
||
<li>GPS-Standortsuche (nur Mobile)</li>
|
||
<li>Manuelle Stationssuche</li>
|
||
<li>Auto-Refresh alle 30s</li>
|
||
<li>Verspätungsanzeige</li>
|
||
<li>Linien-Filter</li>
|
||
<li>Detail-Ansicht mit Zwischenhalten</li>
|
||
</ul>
|
||
<p class="feature-api"><strong>API:</strong> <code>GET /stops/:id/departures</code></p>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="feature-detail">
|
||
<summary>🗺️ Routenplaner</summary>
|
||
<div class="feature-content">
|
||
<p><strong>Intelligente Routenplanung im VBB-Netz</strong></p>
|
||
<ul>
|
||
<li>Von/Nach Suche mit Autocomplete</li>
|
||
<li>GPS-Standort als Start/Ziel (nur Mobile)</li>
|
||
<li>Mehrere Routenoptionen</li>
|
||
<li>Umstiegsanzeige mit Zeiten</li>
|
||
<li>Verkehrsmittel-Filter</li>
|
||
<li>Detail-Ansicht mit allen Haltestellen</li>
|
||
</ul>
|
||
<p class="feature-api"><strong>API:</strong> <code>GET /journeys</code></p>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="feature-detail">
|
||
<summary>🌍 Live-Map</summary>
|
||
<div class="feature-content">
|
||
<p><strong>Echtzeit-Fahrzeugverfolgung</strong></p>
|
||
<ul>
|
||
<li>Leaflet.js Kartenintegration</li>
|
||
<li>Dynamische Bounding Box</li>
|
||
<li>Fahrzeug-Filter (U-Bahn, S-Bahn, Bus, Tram)</li>
|
||
<li>BVG-Linienfarben</li>
|
||
<li>Auto-Update alle 15s</li>
|
||
<li>Zoom & Pan optimiert</li>
|
||
</ul>
|
||
<p class="feature-api"><strong>API:</strong> <code>GET /radar</code></p>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="feature-detail">
|
||
<summary>📱 Progressive Web App</summary>
|
||
<div class="feature-content">
|
||
<p><strong>Moderne PWA-Funktionen</strong></p>
|
||
<ul>
|
||
<li>Installierbar (Add to Home Screen)</li>
|
||
<li>Service Worker mit Caching</li>
|
||
<li>Offline-Modus</li>
|
||
<li>Push-Benachrichtigungen (geplant)</li>
|
||
<li>App-Manifest</li>
|
||
</ul>
|
||
<p class="feature-api"><strong>Cache:</strong> <code>vbb-status-v30</code></p>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="feature-detail">
|
||
<summary>🎨 UI/UX Features</summary>
|
||
<div class="feature-content">
|
||
<p><strong>Design & Benutzerfreundlichkeit</strong></p>
|
||
<ul>
|
||
<li>Dark Mode (Standard)</li>
|
||
<li>Responsive Design (Mobile → Desktop)</li>
|
||
<li>Touch-optimiert</li>
|
||
<li>Hover-Effekte (Desktop)</li>
|
||
<li>Accessibility (WCAG)</li>
|
||
</ul>
|
||
</div>
|
||
</details>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Detail Modal -->
|
||
<div class="detail-modal" id="detailModal">
|
||
<div class="detail-header">
|
||
<button class="detail-back-btn" id="detailBackBtn">←</button>
|
||
<div class="detail-title" id="detailTitle">Fahrzeug-Details</div>
|
||
<div style="width: 34px;"></div>
|
||
</div>
|
||
<div class="detail-content" id="detailContent">
|
||
<div class="loading-detail">⏳ Lade Details...</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Journey Detail Modal -->
|
||
<div class="detail-modal" id="journeyDetailModal">
|
||
<div class="detail-header">
|
||
<button class="detail-back-btn" id="journeyDetailBackBtn">←</button>
|
||
<div class="detail-title" id="journeyDetailTitle">Routen-Details</div>
|
||
<div style="width: 34px;"></div>
|
||
</div>
|
||
<div class="detail-content" id="journeyDetailContent">
|
||
<div class="loading-detail">⏳ Lade Details...</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Module in fester Reihenfolge (klassische Scripts, gemeinsamer Scope) -->
|
||
<script src="js/api.js"></script>
|
||
<script src="js/app.js"></script>
|
||
<script src="js/livemap.js"></script>
|
||
<script src="js/changelog.js"></script>
|
||
<script src="js/extras.js"></script>
|
||
</body>
|
||
</html>
|