parent
a2557c0194
commit
e7c60e7c47
3 changed files with 35 additions and 21 deletions
|
|
@ -22,7 +22,7 @@ const state = {
|
||||||
muted: false,
|
muted: false,
|
||||||
sharingVideo: false,
|
sharingVideo: false,
|
||||||
sharingScreen: false,
|
sharingScreen: false,
|
||||||
watchingVideo: true,
|
viewMode: 'chat', // 'chat' or 'video'
|
||||||
iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
|
iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
|
||||||
},
|
},
|
||||||
voicePresencePollId: null,
|
voicePresencePollId: null,
|
||||||
|
|
@ -66,10 +66,11 @@ const el = {
|
||||||
vcChannelName: document.getElementById("vc-channel-name"),
|
vcChannelName: document.getElementById("vc-channel-name"),
|
||||||
voiceVideoBtn: document.getElementById("voice-video-btn"),
|
voiceVideoBtn: document.getElementById("voice-video-btn"),
|
||||||
voiceScreenBtn: document.getElementById("voice-screen-btn"),
|
voiceScreenBtn: document.getElementById("voice-screen-btn"),
|
||||||
voiceWatchBtn: document.getElementById("voice-watch-btn"),
|
|
||||||
voiceMuteBtn: document.getElementById("voice-mute-btn"),
|
voiceMuteBtn: document.getElementById("voice-mute-btn"),
|
||||||
voiceLeaveBtn: document.getElementById("voice-leave-btn"),
|
voiceLeaveBtn: document.getElementById("voice-leave-btn"),
|
||||||
videoGrid: document.getElementById("video-grid"),
|
videoGrid: document.getElementById("video-grid"),
|
||||||
|
messageForm: document.getElementById("message-form"),
|
||||||
|
messageInputWrapper: document.querySelector(".chat-input-wrapper"),
|
||||||
|
|
||||||
// Members
|
// Members
|
||||||
memberList: document.getElementById("member-list"),
|
memberList: document.getElementById("member-list"),
|
||||||
|
|
@ -249,17 +250,20 @@ function renderChannels() {
|
||||||
state.selectedDmUserId = null;
|
state.selectedDmUserId = null;
|
||||||
state.selectedDmDisplayName = null;
|
state.selectedDmDisplayName = null;
|
||||||
state.selectedTextChannelId = channel.id;
|
state.selectedTextChannelId = channel.id;
|
||||||
|
state.voice.viewMode = 'chat';
|
||||||
renderChannels();
|
renderChannels();
|
||||||
renderDMs();
|
renderDMs();
|
||||||
|
updateView();
|
||||||
updateHeaderLabels();
|
updateHeaderLabels();
|
||||||
const messages = await api(`/channels/${channel.id}/messages?limit=100`);
|
const messages = await api(`/channels/${channel.id}/messages?limit=100`);
|
||||||
renderMessages(messages);
|
renderMessages(messages);
|
||||||
} else {
|
} else {
|
||||||
state.selectedDmUserId = null;
|
|
||||||
state.selectedDmDisplayName = null;
|
|
||||||
state.selectedVoiceChannelId = channel.id;
|
state.selectedVoiceChannelId = channel.id;
|
||||||
|
state.voice.viewMode = 'video';
|
||||||
renderChannels();
|
renderChannels();
|
||||||
renderDMs();
|
renderDMs();
|
||||||
|
updateView();
|
||||||
|
updateHeaderLabels();
|
||||||
joinVoice();
|
joinVoice();
|
||||||
}
|
}
|
||||||
if (window.innerWidth <= 768) closeMobileMenus();
|
if (window.innerWidth <= 768) closeMobileMenus();
|
||||||
|
|
@ -307,8 +311,10 @@ function renderDMs() {
|
||||||
state.selectedDmDisplayName = dm.display_name;
|
state.selectedDmDisplayName = dm.display_name;
|
||||||
state.selectedTextChannelId = null;
|
state.selectedTextChannelId = null;
|
||||||
state.selectedVoiceChannelId = null;
|
state.selectedVoiceChannelId = null;
|
||||||
|
state.voice.viewMode = 'chat';
|
||||||
renderChannels();
|
renderChannels();
|
||||||
renderDMs();
|
renderDMs();
|
||||||
|
updateView();
|
||||||
updateHeaderLabels();
|
updateHeaderLabels();
|
||||||
const messages = await api(`/dms/${dm.user_id}/messages?limit=100`);
|
const messages = await api(`/dms/${dm.user_id}/messages?limit=100`);
|
||||||
renderMessages(messages);
|
renderMessages(messages);
|
||||||
|
|
@ -380,8 +386,10 @@ function renderMembers() {
|
||||||
state.selectedDmDisplayName = m.display_name;
|
state.selectedDmDisplayName = m.display_name;
|
||||||
state.selectedTextChannelId = null;
|
state.selectedTextChannelId = null;
|
||||||
state.selectedVoiceChannelId = null;
|
state.selectedVoiceChannelId = null;
|
||||||
|
state.voice.viewMode = 'chat';
|
||||||
renderChannels();
|
renderChannels();
|
||||||
renderDMs();
|
renderDMs();
|
||||||
|
updateView();
|
||||||
updateHeaderLabels();
|
updateHeaderLabels();
|
||||||
const messages = await api(`/dms/${m.id}/messages?limit=100`);
|
const messages = await api(`/dms/${m.id}/messages?limit=100`);
|
||||||
renderMessages(messages);
|
renderMessages(messages);
|
||||||
|
|
@ -406,6 +414,12 @@ function updateHeaderLabels() {
|
||||||
return;
|
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);
|
const channel = state.channels.find((c) => c.id === state.selectedTextChannelId);
|
||||||
el.channelTitle.textContent = channel ? channel.name : "Select a channel";
|
el.channelTitle.textContent = channel ? channel.name : "Select a channel";
|
||||||
el.messageBody.placeholder = channel ? `Message #${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.videoStream = null;
|
||||||
state.voice.sharingVideo = false;
|
state.voice.sharingVideo = false;
|
||||||
document.getElementById(`video-${state.me.id}-camera`)?.parentElement?.remove();
|
document.getElementById(`video-${state.me.id}-camera`)?.parentElement?.remove();
|
||||||
updateVideoGridVisibility();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopAndClearScreenPipeline() {
|
function stopAndClearScreenPipeline() {
|
||||||
|
|
@ -579,15 +592,22 @@ function stopAndClearScreenPipeline() {
|
||||||
state.voice.screenStream = null;
|
state.voice.screenStream = null;
|
||||||
state.voice.sharingScreen = false;
|
state.voice.sharingScreen = false;
|
||||||
document.getElementById(`video-${state.me.id}-screen`)?.parentElement?.remove();
|
document.getElementById(`video-${state.me.id}-screen`)?.parentElement?.remove();
|
||||||
updateVideoGridVisibility();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateVideoGridVisibility() {
|
function updateVideoGridVisibility() {
|
||||||
const hasVideos = el.videoGrid.children.length > 0;
|
// Persistence logic: we always update the grid visibility based on participants
|
||||||
if (hasVideos && state.voice.watchingVideo) {
|
// 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.videoGrid.classList.remove("hidden");
|
||||||
|
el.messageList.classList.add("hidden");
|
||||||
|
el.messageInputWrapper.classList.add("hidden");
|
||||||
} else {
|
} else {
|
||||||
el.videoGrid.classList.add("hidden");
|
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 = container.querySelector("video");
|
||||||
}
|
}
|
||||||
videoEl.srcObject = stream;
|
videoEl.srcObject = stream;
|
||||||
updateVideoGridVisibility();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildAudioPipeline(rawStream) {
|
async function buildAudioPipeline(rawStream) {
|
||||||
|
|
@ -815,12 +834,10 @@ async function joinVoice() {
|
||||||
} else if (msg.type === "video_status_changed") {
|
} else if (msg.type === "video_status_changed") {
|
||||||
if (!msg.is_sharing_video) {
|
if (!msg.is_sharing_video) {
|
||||||
document.getElementById(`video-${msg.user_id}-camera`)?.parentElement?.remove();
|
document.getElementById(`video-${msg.user_id}-camera`)?.parentElement?.remove();
|
||||||
updateVideoGridVisibility();
|
|
||||||
}
|
}
|
||||||
} else if (msg.type === "screen_status_changed") {
|
} else if (msg.type === "screen_status_changed") {
|
||||||
if (!msg.is_sharing_screen) {
|
if (!msg.is_sharing_screen) {
|
||||||
document.getElementById(`video-${msg.user_id}-screen`)?.parentElement?.remove();
|
document.getElementById(`video-${msg.user_id}-screen`)?.parentElement?.remove();
|
||||||
updateVideoGridVisibility();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
refreshVoicePresence().catch(() => { });
|
refreshVoicePresence().catch(() => { });
|
||||||
|
|
@ -1121,7 +1138,6 @@ async function init() {
|
||||||
|
|
||||||
el.voiceVideoBtn.onclick = toggleVideo;
|
el.voiceVideoBtn.onclick = toggleVideo;
|
||||||
el.voiceScreenBtn.onclick = toggleScreenShare;
|
el.voiceScreenBtn.onclick = toggleScreenShare;
|
||||||
el.voiceWatchBtn.onclick = toggleWatchVideo;
|
|
||||||
el.voiceMuteBtn.onclick = toggleMute;
|
el.voiceMuteBtn.onclick = toggleMute;
|
||||||
el.voiceLeaveBtn.onclick = leaveVoice;
|
el.voiceLeaveBtn.onclick = leaveVoice;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,6 @@
|
||||||
<div class="vc-actions">
|
<div class="vc-actions">
|
||||||
<button id="voice-video-btn" title="Turn on Camera"><i data-lucide="video-off"></i></button>
|
<button id="voice-video-btn" title="Turn on Camera"><i data-lucide="video-off"></i></button>
|
||||||
<button id="voice-screen-btn" title="Share Screen"><i data-lucide="monitor-off"></i></button>
|
<button id="voice-screen-btn" title="Share Screen"><i data-lucide="monitor-off"></i></button>
|
||||||
<button id="voice-watch-btn" title="Stop Watching"><i data-lucide="eye"></i></button>
|
|
||||||
<button id="voice-mute-btn" title="Mute"><i data-lucide="mic"></i></button>
|
<button id="voice-mute-btn" title="Mute"><i data-lucide="mic"></i></button>
|
||||||
<button id="voice-leave-btn" title="Disconnect"><i data-lucide="phone-off"></i></button>
|
<button id="voice-leave-btn" title="Disconnect"><i data-lucide="phone-off"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -527,15 +527,13 @@ select {
|
||||||
/* Video Grid */
|
/* Video Grid */
|
||||||
.video-grid {
|
.video-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||||
gap: 12px;
|
gap: 16px;
|
||||||
padding: 12px;
|
padding: 16px;
|
||||||
background: var(--bg-tertiary);
|
background: var(--bg-tertiary);
|
||||||
flex-grow: 1;
|
flex: 1;
|
||||||
min-height: 200px;
|
min-height: 0;
|
||||||
max-height: 100%;
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-grid.hidden {
|
.video-grid.hidden {
|
||||||
|
|
@ -553,7 +551,8 @@ select {
|
||||||
.video-item video {
|
.video-item video {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: contain;
|
||||||
|
background: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-item .video-label {
|
.video-item .video-label {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue