mirror of
https://github.com/Shik3i/KoalaSync.git
synced 2026-07-27 04:20:25 +00:00
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
This commit is contained in:
@@ -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 |
|
||||
|
||||
@@ -425,5 +425,19 @@
|
||||
</div>
|
||||
|
||||
<script src="popup.js" type="module"></script>
|
||||
|
||||
<!-- Onboarding Overlay -->
|
||||
<div id="onboarding-overlay" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.7); z-index:1000; align-items:center; justify-content:center;">
|
||||
<div id="onboarding-card" style="background:var(--card); padding:24px; border-radius:16px; max-width:280px; width:90%; text-align:center; box-shadow:0 8px 32px rgba(0,0,0,0.5);">
|
||||
<div id="onboarding-icon" style="font-size:48px; margin-bottom:12px;">\u{1F44B}</div>
|
||||
<h2 id="onboarding-title" style="color:var(--accent); margin:0 0 8px; font-size:16px;">Welcome to KoalaSync!</h2>
|
||||
<p id="onboarding-text" style="color:var(--text-muted); font-size:13px; margin:0 0 16px; line-height:1.4;">Let's get you started.</p>
|
||||
<div style="display:flex; gap:8px; justify-content:center;">
|
||||
<button id="onboarding-skip" class="secondary" style="width:auto; padding:8px 16px;">Skip</button>
|
||||
<button id="onboarding-next" class="primary" style="width:auto; padding:8px 16px;">Next</button>
|
||||
</div>
|
||||
<div id="onboarding-dots" style="margin-top:12px; display:flex; gap:6px; justify-content:center;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+69
-1
@@ -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) =>
|
||||
`<div style="width:8px; height:8px; border-radius:50%; background:${i === onboardingStep ? 'var(--accent)' : '#475569'};"></div>`
|
||||
).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();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user