From 67bf9ec7b11edd1c7fbdf6acc4ff2b56559ad415 Mon Sep 17 00:00:00 2001 From: Dotty Dotter Date: Mon, 20 Apr 2026 03:01:59 +0200 Subject: [PATCH] Webapp v2: UX-sicheres Audio, Transkript-Mitlesen, Volltextsuche MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - #3: Audio startet nicht mehr durch Card-Klick. Separater Play-Button pro Zitat, Audio-Bar mit Play/Pause. Bewusste Aktion statt Versehen. - #4: Navigation durch Themes/Episoden stoppt laufendes Audio nicht. Audio-State ist komplett vom Panel-State getrennt. - #1: Transkript-Ansicht mit synchronem Mitlesen. Aktiver Absatz wird hervorgehoben und auto-gescrollt. Klick auf Absatz springt im Audio. - #5: Suchfeld im Header durchsucht alle Transkripte und Zitate. Treffer mit Kontext, Klick öffnet Transkript an der Stelle. AudioPlayer als eigenständiges Objekt, TranscriptView und Search als separate Module. Alle dynamisch aus mindmap_data.json + srt_index.json. Co-Authored-By: Claude Opus 4.6 (1M context) --- webapp/index.html | 1158 +++++++++++++++++++++++---------------------- 1 file changed, 587 insertions(+), 571 deletions(-) diff --git a/webapp/index.html b/webapp/index.html index 5617d6a..f7ef9e9 100644 --- a/webapp/index.html +++ b/webapp/index.html @@ -12,9 +12,9 @@ --text: #e8e6e3; --text-muted: #9ca3af; --accent: #60a5fa; + --accent-green: #22c55e; --border: #374151; } - * { margin: 0; padding: 0; box-sizing: border-box; } body { @@ -27,314 +27,206 @@ #app { display: grid; - grid-template-columns: 1fr 380px; - grid-template-rows: 56px 1fr; + grid-template-columns: 1fr 400px; + grid-template-rows: 52px 1fr; height: 100vh; } @media (max-width: 800px) { #app { grid-template-columns: 1fr; - grid-template-rows: 48px 50vh 1fr; + grid-template-rows: 48px 45vh 1fr; } - header { padding: 0 12px; } - header h1 { font-size: 14px; } - .filter-bar { gap: 4px; } - .filter-btn { padding: 4px 10px; font-size: 11px; } + header { padding: 0 12px; gap: 8px; } + header h1 { font-size: 13px; } + .search-box { max-width: 120px; } + .filter-bar { gap: 3px; } + .filter-btn { padding: 3px 8px; font-size: 10px; } #panel { border-left: none; border-top: 1px solid var(--border); } } - /* Header */ + /* ── Header ── */ header { grid-column: 1 / -1; background: var(--surface); border-bottom: 1px solid var(--border); display: flex; align-items: center; - padding: 0 24px; - gap: 16px; + padding: 0 20px; + gap: 12px; } - - header h1 { - font-size: 18px; - font-weight: 600; - letter-spacing: -0.02em; - } - + header h1 { font-size: 16px; font-weight: 600; letter-spacing: -0.02em; white-space: nowrap; } header h1 span { color: var(--accent); } - .filter-bar { - display: flex; - gap: 8px; - margin-left: auto; - } - - .filter-btn { + .search-box { background: var(--surface2); border: 1px solid var(--border); - color: var(--text-muted); - padding: 6px 14px; - border-radius: 20px; + border-radius: 6px; + padding: 5px 10px; + color: var(--text); font-size: 12px; - cursor: pointer; - transition: all 0.2s; + width: 200px; + outline: none; } + .search-box:focus { border-color: var(--accent); } + .search-box::placeholder { color: var(--text-muted); } + .filter-bar { display: flex; gap: 6px; margin-left: auto; } + .filter-btn { + background: var(--surface2); border: 1px solid var(--border); + color: var(--text-muted); padding: 5px 12px; border-radius: 16px; + font-size: 11px; cursor: pointer; transition: all 0.2s; white-space: nowrap; + } .filter-btn:hover, .filter-btn.active { - background: var(--accent); - color: var(--bg); - border-color: var(--accent); + background: var(--accent); color: var(--bg); border-color: var(--accent); } - /* Mindmap Canvas */ - #mindmap { - position: relative; - overflow: hidden; - background: var(--bg); - } + /* ── Mindmap ── */ + #mindmap { position: relative; overflow: hidden; background: var(--bg); } + #mindmap svg { width: 100%; height: 100%; } - #mindmap svg { - width: 100%; - height: 100%; - } + .node-theme { cursor: pointer; } + .node-theme circle { stroke-width: 2; transition: r 0.3s, stroke-width 0.3s; } + .node-theme:hover circle { stroke-width: 4; } + .node-theme text { fill: var(--text); font-size: 11px; font-weight: 600; text-anchor: middle; pointer-events: none; } - /* Nodes */ - .node-theme { - cursor: pointer; - } + .node-episode circle { stroke-width: 1.5; cursor: pointer; transition: r 0.3s; } + .node-episode:hover circle { r: 22; } + .node-episode text { fill: var(--text-muted); font-size: 9px; text-anchor: middle; pointer-events: none; } - .node-theme circle { - stroke-width: 2; - transition: r 0.3s, stroke-width 0.3s; - } + .node-quote { cursor: pointer; } + .node-quote circle { transition: r 0.3s, opacity 0.3s; } + .node-quote:hover circle { r: 8; opacity: 1; } - .node-theme:hover circle { - stroke-width: 4; - } + .link { stroke: var(--border); stroke-opacity: 0.3; fill: none; } + .link-theme-episode { stroke-opacity: 0.15; stroke-width: 1; } + .link-episode-quote { stroke-opacity: 0.08; stroke-width: 0.5; } - .node-theme text { - fill: var(--text); - font-size: 12px; - font-weight: 600; - text-anchor: middle; - pointer-events: none; - } - - .node-episode circle { - stroke-width: 1.5; - cursor: pointer; - transition: r 0.3s; - } - - .node-episode:hover circle { - r: 22; - } - - .node-episode text { - fill: var(--text-muted); - font-size: 9px; - text-anchor: middle; - pointer-events: none; - } - - .node-quote { - cursor: pointer; - } - - .node-quote circle { - transition: r 0.3s, opacity 0.3s; - } - - .node-quote:hover circle { - r: 8; - opacity: 1; - } - - .link { - stroke: var(--border); - stroke-opacity: 0.3; - fill: none; - } - - .link-theme-episode { - stroke-opacity: 0.15; - stroke-width: 1; - } - - .link-episode-quote { - stroke-opacity: 0.08; - stroke-width: 0.5; - } - - /* Side Panel */ + /* ── Side Panel ── */ #panel { background: var(--surface); border-left: 1px solid var(--border); overflow-y: auto; - padding: 20px; + padding: 16px; display: flex; flex-direction: column; - gap: 16px; - } - - #panel h2 { - font-size: 16px; - font-weight: 600; - color: var(--text); - } - - #panel .subtitle { - font-size: 13px; - color: var(--text-muted); - margin-top: 4px; + gap: 12px; + padding-bottom: 80px; /* space for audio bar */ } + #panel h2 { font-size: 15px; font-weight: 600; } + #panel .subtitle { font-size: 12px; color: var(--text-muted); margin-top: 2px; } + /* ── Quote Cards ── */ .quote-card { background: var(--surface2); border-radius: 8px; - padding: 14px; - border-left: 3px solid var(--accent); - cursor: pointer; - transition: transform 0.15s, background 0.15s; + padding: 12px; + border-left: 3px solid var(--border); + transition: background 0.15s; + position: relative; } - - .quote-card:hover { - transform: translateX(4px); - background: #2d3142; - } - - .quote-card.playing { - border-left-color: #22c55e; - background: #1a2e1a; - } - .quote-card .quote-text { - font-size: 13px; - line-height: 1.5; - color: var(--text); - font-style: italic; + font-size: 13px; line-height: 1.5; color: var(--text); font-style: italic; + cursor: default; } - .quote-card .quote-meta { - margin-top: 8px; - font-size: 11px; - color: var(--text-muted); - display: flex; - justify-content: space-between; - align-items: center; + margin-top: 6px; font-size: 11px; color: var(--text-muted); + display: flex; justify-content: space-between; align-items: center; } + .quote-card.loaded { border-left-color: var(--accent); } + .quote-card.playing { border-left-color: var(--accent-green); background: #1a2e1a; } - .quote-card .play-icon { - width: 24px; - height: 24px; - border-radius: 50%; - background: var(--accent); - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; - opacity: 0.7; - transition: opacity 0.2s; + /* Play button inside card — explicit, not the whole card */ + .play-btn { + width: 28px; height: 28px; border-radius: 50%; + background: var(--accent); border: none; color: var(--bg); + display: flex; align-items: center; justify-content: center; + cursor: pointer; flex-shrink: 0; opacity: 0.7; transition: opacity 0.2s, transform 0.1s; } - - .quote-card:hover .play-icon { opacity: 1; } - - .quote-card .play-icon svg { - width: 12px; - height: 12px; - fill: var(--bg); - } - - .no-audio .play-icon { display: none; } + .play-btn:hover { opacity: 1; transform: scale(1.1); } + .play-btn:active { transform: scale(0.95); } + .play-btn svg { width: 12px; height: 12px; fill: currentColor; } + .no-audio .play-btn { display: none; } .top-badge { - display: inline-block; - background: #f59e0b; - color: #000; - font-size: 9px; - font-weight: 700; - padding: 1px 6px; - border-radius: 3px; - margin-left: 6px; + display: inline-block; background: #f59e0b; color: #000; + font-size: 9px; font-weight: 700; padding: 1px 6px; + border-radius: 3px; margin-left: 4px; } - /* Audio Player Bar */ - #audio-bar { - position: fixed; - bottom: 0; - left: 0; - right: 0; - height: 64px; - background: var(--surface); - border-top: 1px solid var(--border); - display: none; - align-items: center; - padding: 0 24px; - gap: 16px; - z-index: 100; + /* ── Transcript View ── */ + .transcript-toggle { + background: var(--surface2); border: 1px solid var(--border); + color: var(--text-muted); padding: 6px 14px; border-radius: 6px; + font-size: 11px; cursor: pointer; transition: all 0.2s; } + .transcript-toggle:hover { border-color: var(--accent); color: var(--text); } - #audio-bar.visible { display: flex; } - - #audio-bar .now-playing { - font-size: 12px; - color: var(--text-muted); - flex: 1; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - #audio-bar .now-playing strong { - color: var(--text); - } - - #audio-bar button { - background: var(--accent); - border: none; - color: var(--bg); - width: 36px; - height: 36px; - border-radius: 50%; + .transcript-para { + font-size: 13px; line-height: 1.6; color: var(--text-muted); + padding: 8px 12px; border-radius: 6px; border-left: 2px solid transparent; + transition: background 0.3s, border-color 0.3s, color 0.3s; cursor: pointer; - display: flex; - align-items: center; - justify-content: center; } - - #audio-bar .time { - font-size: 11px; - color: var(--text-muted); - font-variant-numeric: tabular-nums; - } - - /* Welcome state */ - .welcome { - text-align: center; - padding: 40px 20px; - color: var(--text-muted); - } - - .welcome h2 { + .transcript-para:hover { background: var(--surface2); } + .transcript-para.active { + background: var(--surface2); border-left-color: var(--accent-green); color: var(--text); - margin-bottom: 8px; + } + .transcript-para .ts { + font-size: 10px; color: var(--text-muted); font-variant-numeric: tabular-nums; + margin-right: 6px; } - .welcome p { - font-size: 13px; - line-height: 1.6; + /* ── Search Results ── */ + .search-result { + background: var(--surface2); border-radius: 8px; padding: 12px; + border-left: 3px solid var(--accent); cursor: pointer; + transition: background 0.15s; } + .search-result:hover { background: #2d3142; } + .search-result .sr-episode { font-size: 10px; color: var(--accent); font-weight: 600; } + .search-result .sr-text { font-size: 12px; line-height: 1.5; margin-top: 4px; } + .search-result mark { background: #f59e0b44; color: var(--text); border-radius: 2px; padding: 0 2px; } + + /* ── Audio Bar ── */ + #audio-bar { + position: fixed; bottom: 0; left: 0; right: 0; height: 64px; + background: var(--surface); border-top: 1px solid var(--border); + display: none; align-items: center; padding: 0 20px; gap: 12px; z-index: 100; + } + #audio-bar.visible { display: flex; } + #audio-bar .bar-play-btn { + background: var(--accent); border: none; color: var(--bg); + width: 36px; height: 36px; border-radius: 50%; + cursor: pointer; display: flex; align-items: center; justify-content: center; + flex-shrink: 0; + } + #audio-bar .now-playing { + font-size: 12px; color: var(--text-muted); flex: 1; + overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + cursor: pointer; + } + #audio-bar .now-playing:hover { color: var(--text); } + #audio-bar .now-playing strong { color: var(--text); } + #audio-bar .time { + font-size: 11px; color: var(--text-muted); font-variant-numeric: tabular-nums; + } + #audio-bar .bar-transcript-btn { + background: transparent; border: 1px solid var(--border); color: var(--text-muted); + padding: 4px 10px; border-radius: 4px; font-size: 10px; cursor: pointer; + } + #audio-bar .bar-transcript-btn:hover { border-color: var(--accent); color: var(--text); } + + .welcome { text-align: center; padding: 40px 20px; color: var(--text-muted); } + .welcome h2 { color: var(--text); margin-bottom: 8px; } + .welcome p { font-size: 13px; line-height: 1.6; } .theme-tag { - display: inline-block; - padding: 3px 10px; - border-radius: 12px; - font-size: 11px; - font-weight: 500; - margin: 2px; + display: inline-block; padding: 3px 10px; border-radius: 12px; + font-size: 11px; font-weight: 500; margin: 2px; cursor: pointer; } - /* Scrollbar */ #panel::-webkit-scrollbar { width: 6px; } #panel::-webkit-scrollbar-track { background: transparent; } #panel::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; } @@ -343,67 +235,397 @@
-

Podcast Themen-Mindmap

+

Podcast Mindmap

+
- -
- -
- -
-
-
-
+
+
- -
- 00:00 +
+ 0:00 +