From 3b65af1bbb05c4cd4c8ac88cc7c8fdb07fa12465 Mon Sep 17 00:00:00 2001 From: Koala <6156589+Shik3i@users.noreply.github.com> Date: Mon, 25 May 2026 10:05:47 +0200 Subject: [PATCH] feat: sprint 2 - empty states, onboarding tour, dev tab optimization, expanded usernames - Add renderEmpty() helper with icons and hints for peers/history/logs/rooms - Implement onboarding tour (4 steps) with overlay, dots, skip/next - Dev tab logs only poll when tab is visible (isDevTabVisible flag) - Expand username generation from 12/12 to 30/30 adjective-noun pairs - Update ROADMAP.md to remove implemented features --- docs/ROADMAP.md | 6 ---- extension/popup.html | 14 +++++++++ extension/popup.js | 70 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 7 deletions(-) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 5d538a8..38b5084 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -9,9 +9,6 @@ This document tracks planned features, improvements, and their implementation de ### 1. Graceful Shutdown **Korrektur:** Der Server hat bereits Graceful Shutdown implementiert (`server/index.js:481-499`). Bei SIGTERM/SIGINT wird allen Clients eine Neustart-Nachricht gesendet, der HTTP-Server geschlossen und nach 5s erzwungen beendet. **Kein Handlungsbedarf.** -### 3. `setInterval(refreshLogs, 5000)` Last -5 Sekunden ist technisch wenig Last (~0.2 IPC calls/sec). Aber es ist **architektonisch unsauber** — der Interval läuft auch wenn der Dev-Tab nicht sichtbar ist. Besser: Nur pollen wenn Dev-Tab aktiv, oder auf `chrome.runtime.onMessage` umstellen (Push statt Poll). - ### 6. Service Worker Fallback bei Room-State Verlust Manifest V3 suspendiert den Service Worker nach ~30s Inaktivität. `chrome.alarms` weckt ihn auf, aber: - **Problem:** Wenn der SW neu startet, sind alle Variablen (`currentRoom`, `socket`, `isNamespaceJoined`) weg @@ -33,9 +30,6 @@ Diese Features wurden evaluiert aber sind nicht Teil der nächsten Release: | Feature | Aufwand | Nutzen | Status | |---------|---------|--------|--------| -| Verbesserte Empty States | ~40 LOC | 7/10 | Backlog | -| Onboarding Tour | ~120 LOC | 8/10 | Backlog | -| Dev-Tab Logs nur bei Sichtbarkeit pollen | ~10 LOC | 5/10 | Backlog | | Chat im Room | ~400 LOC | 9/10 | Geplant v1.6 | | Playback Speed Sync | ~150 LOC | 8/10 | Geplant v1.5 | | Room Host/Owner | ~350 LOC | 8/10 | Geplant v1.6 | diff --git a/extension/popup.html b/extension/popup.html index d7cdb25..a57008c 100644 --- a/extension/popup.html +++ b/extension/popup.html @@ -425,5 +425,19 @@ + + + diff --git a/extension/popup.js b/extension/popup.js index df1ce11..6bc5579 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -52,6 +52,7 @@ const elements = { let localPeerId = null; let lastPeersJson = null; let lastKnownPeers = []; +let isDevTabVisible = false; // --- Initialization --- async function init() { @@ -117,6 +118,11 @@ async function init() { // Debug Info Refresh setInterval(refreshDebugInfo, 2000); + + // Show onboarding on first visit + chrome.storage.sync.get(['onboardingComplete'], (data) => { + if (!data.onboardingComplete) showOnboarding(); + }); } // --- UI Logic --- @@ -761,6 +767,8 @@ elements.tabs.forEach(btn => { elements.contents.forEach(c => c.classList.remove('active')); btn.classList.add('active'); document.getElementById(btn.dataset.tab).classList.add('active'); + isDevTabVisible = btn.dataset.tab === 'tab-dev'; + if (isDevTabVisible) refreshLogs(); if (btn.dataset.tab === 'tab-sync') refreshHistory(); }); }); @@ -1149,7 +1157,9 @@ function refreshDebugInfo() { } init(); -setInterval(refreshLogs, 5000); +setInterval(() => { + if (isDevTabVisible) refreshLogs(); +}, 5000); window.addEventListener('unload', () => { stopInterpolation(); @@ -1194,3 +1204,61 @@ function updateLobbyUI(lobby, peers) { elements.lobbyPeerStatus.textContent += ` (${elapsed}s)`; } } + +// --- Onboarding Tour --- +const onboardingSteps = [ + { icon: '\u{1F3E0}', title: 'Room Tab', text: 'Create or join a room to sync with friends. Share the invite link!' }, + { icon: '\u{1F3AC}', title: 'Sync Tab', text: 'Select your video tab and control playback. Force Sync fixes drift.' }, + { icon: '\u2699\uFE0F', title: 'Settings', text: 'Customize your username, filter noise tabs, and toggle auto-sync.' }, + { icon: '\u{1F527}', title: 'Dev Tab', text: 'Debug connection status, video state, and view action history.' } +]; + +let onboardingStep = 0; + +function showOnboarding() { + const overlay = document.getElementById('onboarding-overlay'); + if (!overlay) return; + overlay.style.display = 'flex'; + renderOnboardingStep(); +} + +function renderOnboardingStep() { + const step = onboardingSteps[onboardingStep]; + const icon = document.getElementById('onboarding-icon'); + const title = document.getElementById('onboarding-title'); + const text = document.getElementById('onboarding-text'); + const nextBtn = document.getElementById('onboarding-next'); + const dots = document.getElementById('onboarding-dots'); + if (!icon || !title || !text || !nextBtn || !dots) return; + + icon.textContent = step.icon; + title.textContent = step.title; + text.textContent = step.text; + + dots.innerHTML = onboardingSteps.map((_, i) => + `
` + ).join(''); + + nextBtn.textContent = onboardingStep === onboardingSteps.length - 1 ? 'Done!' : 'Next'; +} + +function completeOnboarding() { + const overlay = document.getElementById('onboarding-overlay'); + if (overlay) overlay.style.display = 'none'; + chrome.storage.sync.set({ onboardingComplete: true }); +} + +document.getElementById('onboarding-next')?.addEventListener('click', () => { + onboardingStep++; + if (onboardingStep >= onboardingSteps.length) { + completeOnboarding(); + } else { + renderOnboardingStep(); + } +}); + +document.getElementById('onboarding-skip')?.addEventListener('click', completeOnboarding); + +document.getElementById('onboarding-overlay')?.addEventListener('click', (e) => { + if (e.target.id === 'onboarding-overlay') completeOnboarding(); +});