165 lines
7.0 KiB
HTML
165 lines
7.0 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de" data-theme="dark">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>KeySelector — Harmonic DJ Assistant</title>
|
||
<link rel="icon" type="image/png" href="favicon.png">
|
||
<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=JetBrains+Mono:wght@400;500;700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||
<link rel="stylesheet" href="styles.css">
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<!-- Topbar -->
|
||
<div class="topbar">
|
||
<div class="topbar-left">
|
||
<div class="brand">KEYSELECTOR</div>
|
||
<div class="audio-source-wrapper">
|
||
<select id="audio-source-select" class="source-select" onchange="changeAudioSource(this.value)">
|
||
<option value="system">🖥️ PC / System-Audio (VLC, DJ, YouTube)</option>
|
||
<option value="mic">🎤 Mikrofon (Raum / Pult)</option>
|
||
<option value="device">🎙️ Spezifisches Eingabegerät...</option>
|
||
</select>
|
||
<select id="audio-device-select" class="source-select" style="display: none;" onchange="selectSpecificDevice(this.value)">
|
||
<option value="">Gerät wählen...</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="topbar-right">
|
||
<!-- Live Audio Level Meter -->
|
||
<div class="audio-meter-container" title="Audio-Eingangspegel">
|
||
<div class="audio-meter-bar" id="audio-meter-fill"></div>
|
||
</div>
|
||
|
||
<div class="status" id="listening-status" onclick="toggleListening()" title="Klicken zum Pausieren / Fortsetzen">
|
||
<i class="fa-solid fa-microphone"></i>
|
||
<span id="listening-text">Bereit</span>
|
||
</div>
|
||
|
||
<button class="theme-toggle" id="theme-btn" onclick="toggleTheme()">Light</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Live Search Bar -->
|
||
<div class="search-box-container">
|
||
<div class="search-input-wrapper">
|
||
<i class="fa-solid fa-magnifying-glass search-icon"></i>
|
||
<input type="text" id="search-input" placeholder="Song oder Artist suchen (z. B. Daft Punk, Fisher, Avicii)..." autocomplete="off">
|
||
<button id="search-clear-btn" class="search-clear" onclick="clearSearch()" style="display:none">×</button>
|
||
</div>
|
||
<div id="search-results-dropdown" class="search-results-dropdown" style="display:none"></div>
|
||
</div>
|
||
|
||
<!-- Hero Card -->
|
||
<div class="hero" id="hero">
|
||
<div class="cover" id="cover" onclick="toggleCover()" title="Klicken zum Vergrößern">
|
||
<div class="cover-placeholder">
|
||
<span class="note">♪</span>
|
||
<span>No Cover</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="info">
|
||
<div class="info-top">
|
||
<div class="track-title" id="track-title">Warte auf Audio...</div>
|
||
<div class="track-artist" id="track-artist">Starte PC-Audio oder Mikrofon oben rechts</div>
|
||
</div>
|
||
|
||
<div class="info-mid">
|
||
<div class="stats-row">
|
||
<div class="stat" onclick="openKeyBpmModal()" title="Klicken zum Korrigieren von Key & BPM">
|
||
<div class="stat-header">
|
||
<span class="stat-label">Key</span>
|
||
<i class="fa-solid fa-pen-to-square edit-btn"></i>
|
||
</div>
|
||
<div class="stat-value k" id="stat-key">-</div>
|
||
<div class="stat-sub" id="stat-key-sub">-</div>
|
||
</div>
|
||
|
||
<div class="stat" onclick="openKeyBpmModal()" title="Klicken zum Korrigieren von Key & BPM">
|
||
<div class="stat-header">
|
||
<span class="stat-label">BPM</span>
|
||
<i class="fa-solid fa-pen-to-square edit-btn"></i>
|
||
</div>
|
||
<div class="stat-value b" id="stat-bpm">-</div>
|
||
<div class="stat-sub" id="stat-bpm-sub">± 0</div>
|
||
</div>
|
||
|
||
<div class="stat">
|
||
<div class="stat-header">
|
||
<span class="stat-label">Status</span>
|
||
</div>
|
||
<div class="stat-value m" id="stat-match">-</div>
|
||
<div class="stat-sub" id="stat-source-sub">Lokal / DB</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tags-row" id="tags-row"></div>
|
||
</div>
|
||
|
||
<div class="info-bot">
|
||
<div class="wheel-container" id="wheel-container" onclick="toggleWheel()" title="Klicken für Vollansicht des Camelot Wheels">
|
||
<svg viewBox="-110 -110 220 220" id="wheel-small" preserveAspectRatio="xMidYMid meet"></svg>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<button class="close-btn" id="close-btn" onclick="resetHero()" title="Schließen">×</button>
|
||
</div>
|
||
|
||
<!-- Suggestions Grid -->
|
||
<div class="section-title">Harmonisch passende Folge-Tracks (Up Next)</div>
|
||
<div class="suggestions" id="suggestions">
|
||
<div style="color:var(--text-dim);font-size:12px;font-family:'JetBrains Mono',monospace;">Wähle oder spiele einen Track ab, um harmonische Übergänge zu berechnen.</div>
|
||
</div>
|
||
|
||
<div style="text-align: center; margin-top: 40px; font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--text-dim);">
|
||
KeySelector — Local-First PostgreSQL DJ Suite
|
||
<br>
|
||
<span style="opacity: 0.5;">v2.0.0</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Key & BPM Correction Modal -->
|
||
<div id="edit-modal" class="modal-overlay" style="display:none;" onclick="closeModalOnOverlay(event)">
|
||
<div class="modal-card">
|
||
<div class="modal-header">
|
||
<h3 id="modal-track-title">Track-Daten korrigieren</h3>
|
||
<button class="modal-close" onclick="closeKeyBpmModal()">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<p class="modal-desc">Werte werden dauerhaft in deiner lokalen PostgreSQL-Datenbank gespeichert und haben bei künftigen Suchen/Erkennungen Vorrang.</p>
|
||
|
||
<div class="form-group">
|
||
<label for="edit-key-select">Camelot Key:</label>
|
||
<select id="edit-key-select" class="form-input"></select>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="edit-bpm-input">BPM:</label>
|
||
<input type="number" id="edit-bpm-input" class="form-input" min="60" max="220" step="1">
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-secondary" onclick="closeKeyBpmModal()">Abbrechen</button>
|
||
<button class="btn btn-primary" onclick="saveKeyBpmCorrection()">In PostgreSQL speichern</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="../shared/mixing-rules.js"></script>
|
||
<script src="../shared/color-matrix.js"></script>
|
||
<script src="../shared/camelot-angle.js"></script>
|
||
<script src="../shared/camelot-to-musickey.js"></script>
|
||
|
||
<script src="wheel.js"></script>
|
||
<script src="cover.js"></script>
|
||
<script src="search.js"></script>
|
||
<script src="app.js"></script>
|
||
</body>
|
||
</html>
|