Beforeunload-Warnung + Vollbild-Button fuer Viewer

- beforeunload Event verhindert versehentliches Verlassen/Reload
  waehrend Broadcasting oder Viewing aktiv ist
- Vollbild-Button im Viewer-Header (Fullscreen API)
- Fullscreen-State wird korrekt getrackt und Icon wechselt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Daniel 2026-03-07 01:37:21 +01:00
parent 2ee36789b2
commit 3ef25fc10a
5 changed files with 109 additions and 51 deletions

View file

@ -456,6 +456,37 @@ export default function StreamingTab({ data }: { data: any }) {
setViewing(null);
}, [cleanupViewer, wsSend]);
// ── Warn before leaving page while active ──
useEffect(() => {
const handler = (e: BeforeUnloadEvent) => {
if (isBroadcastingRef.current || viewingRef.current) {
e.preventDefault();
}
};
window.addEventListener('beforeunload', handler);
return () => window.removeEventListener('beforeunload', handler);
}, []);
// ── Fullscreen toggle for viewer ──
const viewerContainerRef = useRef<HTMLDivElement | null>(null);
const [isFullscreen, setIsFullscreen] = useState(false);
const toggleFullscreen = useCallback(() => {
const el = viewerContainerRef.current;
if (!el) return;
if (!document.fullscreenElement) {
el.requestFullscreen().catch(() => {});
} else {
document.exitFullscreen().catch(() => {});
}
}, []);
useEffect(() => {
const handler = () => setIsFullscreen(!!document.fullscreenElement);
document.addEventListener('fullscreenchange', handler);
return () => document.removeEventListener('fullscreenchange', handler);
}, []);
// ── Cleanup on unmount ──
useEffect(() => {
return () => {
@ -473,7 +504,7 @@ export default function StreamingTab({ data }: { data: any }) {
if (viewing) {
const stream = streams.find(s => s.id === viewing.streamId);
return (
<div className="stream-viewer-overlay">
<div className="stream-viewer-overlay" ref={viewerContainerRef}>
<div className="stream-viewer-header">
<div className="stream-viewer-header-left">
<span className="stream-live-badge"><span className="stream-live-dot" /> LIVE</span>
@ -484,7 +515,12 @@ export default function StreamingTab({ data }: { data: any }) {
</div>
</div>
</div>
<button className="stream-viewer-close" onClick={leaveViewing}>Verlassen</button>
<div className="stream-viewer-header-right">
<button className="stream-viewer-fullscreen" onClick={toggleFullscreen} title={isFullscreen ? 'Vollbild verlassen' : 'Vollbild'}>
{isFullscreen ? '\u2716' : '\u26F6'}
</button>
<button className="stream-viewer-close" onClick={leaveViewing}>Verlassen</button>
</div>
</div>
<div className="stream-viewer-video">
{viewing.phase === 'connecting' ? (