diff --git a/js/web/src/components/stream/video-section.tsx b/js/web/src/components/stream/video-section.tsx index 9be3ee1c1..d5e17053d 100644 --- a/js/web/src/components/stream/video-section.tsx +++ b/js/web/src/components/stream/video-section.tsx @@ -127,12 +127,20 @@ export function VideoSectionInner({ style={{ // In theatre mode the sidebar and header are hidden, so the video // fills the full viewport. Otherwise constrain to aspect ratio. + // When offline, halve the height so the offline banner sits as a + // shorter block at the top of the page (matching the Twitch-style + // "offline card" layout) instead of a full video-sized box. ...(theatre ? { height: "100vh" } - : { - maxHeight: `min(calc(100vw / ${segRatio}), calc(100vh - 240px))`, - aspectRatio: `${segRatio}`, - }), + : offline + ? { + maxHeight: `min(calc(50vw / ${segRatio}), calc(50vh - 120px))`, + aspectRatio: `${segRatio * 2}`, + } + : { + maxHeight: `min(calc(100vw / ${segRatio}), calc(100vh - 240px))`, + aspectRatio: `${segRatio}`, + }), }} >
diff --git a/js/web/src/routes/$user/index.tsx b/js/web/src/routes/$user/index.tsx index e7d578e91..e9cfd4a40 100644 --- a/js/web/src/routes/$user/index.tsx +++ b/js/web/src/routes/$user/index.tsx @@ -127,7 +127,12 @@ function StreamPage() { function StreamBody({ store, user }: { store: LivestreamStore; user: string }) { const liveness = useLivenessState(store); const { theatre } = useFullscreen(); + // Offline streams default to a closed chat — the chat has nothing + // to show, and the shorter offline player should take the page + // width. Live streams honor the user's saved preference. + const isOffline = liveness === "offline" || liveness === "never-live"; const [chatOpen, setChatOpen] = useState(() => { + if (isOffline) return false; if (typeof localStorage === "undefined") return true; return localStorage.getItem("streamplace:chat-open") !== "false"; }); @@ -140,16 +145,23 @@ function StreamBody({ store, user }: { store: LivestreamStore; user: string }) { }); }, []); - // Hide the chat sidebar when the stream is offline or the streamer - // has never gone live — no chat to show in either case. - const showChat = liveness !== "offline" && liveness !== "never-live"; + // Auto-close the chat when a live stream goes offline. The user + // can still open it manually to see the backlog; this just gets + // the page back to a sensible default. (The reverse case — a + // closed chat reopening when the stream goes live — doesn't + // auto-open, the user has the toggle for that.) + useEffect(() => { + if (isOffline && chatOpen) { + setChatOpen(false); + } + }, [isOffline, chatOpen]); return (
{/* Sidebar layout (wide viewport) */}
@@ -165,15 +177,13 @@ function StreamBody({ store, user }: { store: LivestreamStore; user: string }) {
- {showChat && ( -
- -
- )} +
+ +
{/* Stacked layout (portrait/tall) */} @@ -182,11 +192,9 @@ function StreamBody({ store, user }: { store: LivestreamStore; user: string }) { - {showChat && ( -
- -
- )} +
+ +
);