From dfe5103297e15ce6c52b388b1b368fdcf7c1399f Mon Sep 17 00:00:00 2001 From: Natalie Bridgers Date: Wed, 24 Jun 2026 16:29:16 -0500 Subject: [PATCH] feat(stream): half-height offline player, chat available but closed offline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two small refinements to the offline state: 1. Shorten the offline player to half the height of the live video. Override the wrapper's maxHeight and aspectRatio when liveness is 'offline' so the offline banner sits as a compact block at the top of the page rather than a full video-sized box. Theatre mode is unchanged (still 100vh). 2. Keep the chat sidebar mounted always; default it to closed when the stream is offline or has never been live. The user can still open it via the toggle in StreamInfo to see the backlog. The 'useState' initializer reads liveness so the chat starts closed without a flash; a useEffect also auto-closes it when a live stream goes offline. The reverse (auto-opening on live) doesn't happen — the user has the toggle for that. --- .../src/components/stream/video-section.tsx | 16 +++++-- js/web/src/routes/$user/index.tsx | 44 +++++++++++-------- 2 files changed, 38 insertions(+), 22 deletions(-) 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 && ( -
- -
- )} +
+ +
); -- 2.51.2