From e7c60e7c473cadb798c64f2f47ffaa16444e239e Mon Sep 17 00:00:00 2001 From: pavel Date: Tue, 24 Feb 2026 01:18:00 +0100 Subject: [PATCH] g --- static/app.js | 40 ++++++++++++++++++++++++++++------------ static/index.html | 1 - static/styles.css | 15 +++++++-------- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/static/app.js b/static/app.js index cfd3964..f6eaa85 100644 --- a/static/app.js +++ b/static/app.js @@ -22,7 +22,7 @@ const state = { muted: false, sharingVideo: false, sharingScreen: false, - watchingVideo: true, + viewMode: 'chat', // 'chat' or 'video' iceServers: [{ urls: "stun:stun.l.google.com:19302" }], }, voicePresencePollId: null, @@ -66,10 +66,11 @@ const el = { vcChannelName: document.getElementById("vc-channel-name"), voiceVideoBtn: document.getElementById("voice-video-btn"), voiceScreenBtn: document.getElementById("voice-screen-btn"), - voiceWatchBtn: document.getElementById("voice-watch-btn"), voiceMuteBtn: document.getElementById("voice-mute-btn"), voiceLeaveBtn: document.getElementById("voice-leave-btn"), videoGrid: document.getElementById("video-grid"), + messageForm: document.getElementById("message-form"), + messageInputWrapper: document.querySelector(".chat-input-wrapper"), // Members memberList: document.getElementById("member-list"), @@ -249,17 +250,20 @@ function renderChannels() { state.selectedDmUserId = null; state.selectedDmDisplayName = null; state.selectedTextChannelId = channel.id; + state.voice.viewMode = 'chat'; renderChannels(); renderDMs(); + updateView(); updateHeaderLabels(); const messages = await api(`/channels/${channel.id}/messages?limit=100`); renderMessages(messages); } else { - state.selectedDmUserId = null; - state.selectedDmDisplayName = null; state.selectedVoiceChannelId = channel.id; + state.voice.viewMode = 'video'; renderChannels(); renderDMs(); + updateView(); + updateHeaderLabels(); joinVoice(); } if (window.innerWidth <= 768) closeMobileMenus(); @@ -307,8 +311,10 @@ function renderDMs() { state.selectedDmDisplayName = dm.display_name; state.selectedTextChannelId = null; state.selectedVoiceChannelId = null; + state.voice.viewMode = 'chat'; renderChannels(); renderDMs(); + updateView(); updateHeaderLabels(); const messages = await api(`/dms/${dm.user_id}/messages?limit=100`); renderMessages(messages); @@ -380,8 +386,10 @@ function renderMembers() { state.selectedDmDisplayName = m.display_name; state.selectedTextChannelId = null; state.selectedVoiceChannelId = null; + state.voice.viewMode = 'chat'; renderChannels(); renderDMs(); + updateView(); updateHeaderLabels(); const messages = await api(`/dms/${m.id}/messages?limit=100`); renderMessages(messages); @@ -406,6 +414,12 @@ function updateHeaderLabels() { return; } + if (state.voice.viewMode === 'video' && state.selectedVoiceChannelId) { + const channel = state.channels.find((c) => c.id === state.selectedVoiceChannelId); + el.channelTitle.textContent = channel ? channel.name : "Voice Arena"; + return; + } + const channel = state.channels.find((c) => c.id === state.selectedTextChannelId); el.channelTitle.textContent = channel ? channel.name : "Select a channel"; el.messageBody.placeholder = channel ? `Message #${channel.name}` : "Select a channel"; @@ -569,7 +583,6 @@ function stopAndClearVideoPipeline() { state.voice.videoStream = null; state.voice.sharingVideo = false; document.getElementById(`video-${state.me.id}-camera`)?.parentElement?.remove(); - updateVideoGridVisibility(); } function stopAndClearScreenPipeline() { @@ -579,15 +592,22 @@ function stopAndClearScreenPipeline() { state.voice.screenStream = null; state.voice.sharingScreen = false; document.getElementById(`video-${state.me.id}-screen`)?.parentElement?.remove(); - updateVideoGridVisibility(); } function updateVideoGridVisibility() { - const hasVideos = el.videoGrid.children.length > 0; - if (hasVideos && state.voice.watchingVideo) { + // Persistence logic: we always update the grid visibility based on participants + // however the actual container visibility in the UI is managed by updateView() +} + +function updateView() { + if (state.voice.viewMode === 'video') { el.videoGrid.classList.remove("hidden"); + el.messageList.classList.add("hidden"); + el.messageInputWrapper.classList.add("hidden"); } else { el.videoGrid.classList.add("hidden"); + el.messageList.classList.remove("hidden"); + el.messageInputWrapper.classList.remove("hidden"); } } @@ -606,7 +626,6 @@ function renderVideo(peerId, displayName, stream, source) { videoEl = container.querySelector("video"); } videoEl.srcObject = stream; - updateVideoGridVisibility(); } async function buildAudioPipeline(rawStream) { @@ -815,12 +834,10 @@ async function joinVoice() { } else if (msg.type === "video_status_changed") { if (!msg.is_sharing_video) { document.getElementById(`video-${msg.user_id}-camera`)?.parentElement?.remove(); - updateVideoGridVisibility(); } } else if (msg.type === "screen_status_changed") { if (!msg.is_sharing_screen) { document.getElementById(`video-${msg.user_id}-screen`)?.parentElement?.remove(); - updateVideoGridVisibility(); } } refreshVoicePresence().catch(() => { }); @@ -1121,7 +1138,6 @@ async function init() { el.voiceVideoBtn.onclick = toggleVideo; el.voiceScreenBtn.onclick = toggleScreenShare; - el.voiceWatchBtn.onclick = toggleWatchVideo; el.voiceMuteBtn.onclick = toggleMute; el.voiceLeaveBtn.onclick = leaveVoice; diff --git a/static/index.html b/static/index.html index 06c0458..5bab6c8 100644 --- a/static/index.html +++ b/static/index.html @@ -87,7 +87,6 @@
-
diff --git a/static/styles.css b/static/styles.css index 1ad62a2..3077a78 100644 --- a/static/styles.css +++ b/static/styles.css @@ -527,15 +527,13 @@ select { /* Video Grid */ .video-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - gap: 12px; - padding: 12px; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: 16px; + padding: 16px; background: var(--bg-tertiary); - flex-grow: 1; - min-height: 200px; - max-height: 100%; + flex: 1; + min-height: 0; overflow-y: auto; - border-bottom: 1px solid rgba(0, 0, 0, 0.2); } .video-grid.hidden { @@ -553,7 +551,8 @@ select { .video-item video { width: 100%; height: 100%; - object-fit: cover; + object-fit: contain; + background: #000; } .video-item .video-label {