Compare commits

...

2 commits

Author SHA1 Message Date
d3a109a0cc sdfg
All checks were successful
/ upload (release) Successful in 20s
2026-02-24 23:18:46 +01:00
58a459a1dc h 2026-02-24 22:37:42 +01:00
6 changed files with 166 additions and 15 deletions

View file

@ -702,6 +702,19 @@ function renderVideo(peerId, displayName, stream, source) {
<video id="${videoId}" autoplay playsinline ${peerId === state.me.id ? "muted" : ""}></video> <video id="${videoId}" autoplay playsinline ${peerId === state.me.id ? "muted" : ""}></video>
<div class="video-label">${label}</div> <div class="video-label">${label}</div>
`; `;
container.onclick = () => {
const isFullscreen = container.classList.contains('fullscreen');
// Reset all
document.querySelectorAll('.video-item').forEach(el => el.classList.remove('fullscreen'));
if (isFullscreen) {
el.videoGrid.classList.remove('has-fullscreen');
} else {
container.classList.add('fullscreen');
el.videoGrid.classList.add('has-fullscreen');
}
};
el.videoGrid.appendChild(container); el.videoGrid.appendChild(container);
videoEl = container.querySelector("video"); videoEl = container.querySelector("video");
} }

View file

@ -638,7 +638,14 @@ select {
background: #000; background: #000;
border-radius: var(--radius-lg); border-radius: var(--radius-lg);
overflow: hidden; overflow: hidden;
transition: box-shadow var(--transition); transition: all var(--transition);
cursor: pointer;
z-index: 1;
}
.video-item:hover {
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.2);
z-index: 2;
} }
.video-item video { .video-item video {
@ -646,6 +653,37 @@ select {
height: 100%; height: 100%;
object-fit: contain; object-fit: contain;
background: #000; background: #000;
pointer-events: none;
}
/* Fullscreen Feed Support */
.video-grid.has-fullscreen {
display: flex;
padding: 0;
overflow: hidden;
position: absolute;
top: 48px;
/* Below chat-header */
left: 0;
right: 0;
bottom: 0;
z-index: 100;
background: var(--bg-main);
}
.video-grid.has-fullscreen .video-item {
display: none;
}
.video-grid.has-fullscreen .video-item.fullscreen {
display: block;
flex: 1;
width: 100%;
height: 100%;
border-radius: 0;
cursor: zoom-out;
z-index: 10;
aspect-ratio: auto;
} }
.video-item .video-label { .video-item .video-label {
@ -659,6 +697,8 @@ select {
border-radius: 100px; border-radius: 100px;
font-size: 12px; font-size: 12px;
font-weight: 500; font-weight: 500;
pointer-events: none;
z-index: 5;
} }
/* Voice Activity */ /* Voice Activity */
@ -786,6 +826,7 @@ select {
/* Chat Pane */ /* Chat Pane */
/* ═══════════════════════════════════════════════════════════ */ /* ═══════════════════════════════════════════════════════════ */
.chat-pane { .chat-pane {
position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: var(--bg-main); background: var(--bg-main);

36
main.js
View file

@ -64,29 +64,36 @@ function createWindow() {
console.log(`Loading desktop app from: ${localUrl}`); console.log(`Loading desktop app from: ${localUrl}`);
const loadDesktopApp = () => { const loadDesktopApp = (queryParams = '') => {
win.loadURL(localUrl).catch((err) => { const fullUrl = queryParams ? `${localUrl}&${queryParams}` : localUrl;
win.loadURL(fullUrl).catch((err) => {
console.error(`Failed to load desktop file: ${err}`); console.error(`Failed to load desktop file: ${err}`);
}); });
}; };
// Use a navigation listener to detect when the remote login is complete // Use a navigation listener to detect when the remote login is complete
win.webContents.on('will-navigate', (event, navigatedUrl) => { win.webContents.on('will-navigate', (event, navigatedUrl) => {
const normalizedNav = navigatedUrl.replace(/\/$/, ''); try {
// If the user lands back on the remote root, they are logged in. const urlObj = new URL(navigatedUrl);
// Redirect them back to our local bugfixed desktop UI. const backendObj = new URL(backendUrl);
if (normalizedNav === backendUrl) { if (urlObj.origin === backendObj.origin && urlObj.pathname === '/') {
console.log("Detected remote landing (login success), returning to desktop UI..."); console.log("Detected remote landing (login success), returning to desktop UI...");
event.preventDefault(); event.preventDefault();
loadDesktopApp(); loadDesktopApp(urlObj.search.slice(1));
}
} catch (e) {
console.error(e);
} }
}); });
win.webContents.on('did-navigate', (event, navigatedUrl) => { win.webContents.on('did-navigate', (event, navigatedUrl) => {
const normalizedNav = navigatedUrl.replace(/\/$/, ''); try {
if (normalizedNav === backendUrl) { const urlObj = new URL(navigatedUrl);
loadDesktopApp(); const backendObj = new URL(backendUrl);
} if (urlObj.origin === backendObj.origin && urlObj.pathname === '/') {
loadDesktopApp(urlObj.search.slice(1));
}
} catch (e) { }
}); });
loadDesktopApp(); loadDesktopApp();
@ -95,6 +102,9 @@ function createWindow() {
// win.webContents.openDevTools(); // win.webContents.openDevTools();
} }
app.commandLine.appendSwitch('disable-webrtc-hw-encoding'); // Sometime helps resolve codec mismatch behavior
app.commandLine.appendSwitch('log-level', '3'); // Silences standard Chromium warning logs (like SRTP transport unprotect logs which are benign timing issues)
app.whenReady().then(() => { app.whenReady().then(() => {
createWindow(); createWindow();

View file

@ -684,6 +684,19 @@ function renderVideo(peerId, displayName, stream, source) {
<video id="${videoId}" autoplay playsinline ${peerId === state.me.id ? "muted" : ""}></video> <video id="${videoId}" autoplay playsinline ${peerId === state.me.id ? "muted" : ""}></video>
<div class="video-label">${label}</div> <div class="video-label">${label}</div>
`; `;
container.onclick = () => {
const isFullscreen = container.classList.contains('fullscreen');
// Reset all
document.querySelectorAll('.video-item').forEach(el => el.classList.remove('fullscreen'));
if (isFullscreen) {
el.videoGrid.classList.remove('has-fullscreen');
} else {
container.classList.add('fullscreen');
el.videoGrid.classList.add('has-fullscreen');
}
};
el.videoGrid.appendChild(container); el.videoGrid.appendChild(container);
videoEl = container.querySelector("video"); videoEl = container.querySelector("video");
} }

View file

@ -638,7 +638,14 @@ select {
background: #000; background: #000;
border-radius: var(--radius-lg); border-radius: var(--radius-lg);
overflow: hidden; overflow: hidden;
transition: box-shadow var(--transition); transition: all var(--transition);
cursor: pointer;
z-index: 1;
}
.video-item:hover {
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.2);
z-index: 2;
} }
.video-item video { .video-item video {
@ -646,6 +653,37 @@ select {
height: 100%; height: 100%;
object-fit: contain; object-fit: contain;
background: #000; background: #000;
pointer-events: none;
}
/* Fullscreen Feed Support */
.video-grid.has-fullscreen {
display: flex;
padding: 0;
overflow: hidden;
position: absolute;
top: 48px;
/* Below chat-header */
left: 0;
right: 0;
bottom: 0;
z-index: 100;
background: var(--bg-main);
}
.video-grid.has-fullscreen .video-item {
display: none;
}
.video-grid.has-fullscreen .video-item.fullscreen {
display: block;
flex: 1;
width: 100%;
height: 100%;
border-radius: 0;
cursor: zoom-out;
z-index: 10;
aspect-ratio: auto;
} }
.video-item .video-label { .video-item .video-label {
@ -659,6 +697,8 @@ select {
border-radius: 100px; border-radius: 100px;
font-size: 12px; font-size: 12px;
font-weight: 500; font-weight: 500;
pointer-events: none;
z-index: 5;
} }
/* Voice Activity */ /* Voice Activity */
@ -786,6 +826,7 @@ select {
/* Chat Pane */ /* Chat Pane */
/* ═══════════════════════════════════════════════════════════ */ /* ═══════════════════════════════════════════════════════════ */
.chat-pane { .chat-pane {
position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: var(--bg-main); background: var(--bg-main);

33
test.html Normal file
View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="static/styles.css" />
<style>
body { margin: 0; height: 100vh; display: flex; }
.chat-pane { flex: 1; position: relative; background: #333; }
.chat-header { height: 48px; background: #222; }
</style>
</head>
<body>
<div class="chat-pane">
<div class="chat-header">Header</div>
<div id="video-grid" class="video-grid">
<div class="video-item" onclick="toggle(this)" style="display:flex; justify-content:center; align-items:center; color:white;">Click me</div>
<div class="video-item" style="color:white;">Another</div>
</div>
</div>
<script>
function toggle(el) {
const grid = document.getElementById('video-grid');
const isFullscreen = el.classList.contains('fullscreen');
document.querySelectorAll('.video-item').forEach(e => e.classList.remove('fullscreen'));
if (isFullscreen) {
grid.classList.remove('has-fullscreen');
} else {
el.classList.add('fullscreen');
grid.classList.add('has-fullscreen');
}
}
</script>
</body>
</html>