Add collapsible YouTube panel

This commit is contained in:
codex
2026-06-09 22:33:43 +02:00
parent 6cb1cc2230
commit 6d6a501b25
3 changed files with 107 additions and 19 deletions
+39
View File
@@ -11,6 +11,7 @@ const youtubeInput = document.querySelector("#youtube-input");
const youtubeShell = document.querySelector("#youtube-shell");
const watchPanel = document.querySelector(".watch-panel");
const watchResizeHandle = document.querySelector("#watch-resize-handle");
const watchCollapseButton = document.querySelector("#watch-collapse-button");
const playlistList = document.querySelector("#playlist-list");
const clearPlaylistButton = document.querySelector("#clear-playlist-button");
const cameraSelect = document.querySelector("#camera-select");
@@ -24,6 +25,7 @@ const nameStorageKey = "kkkmeet.displayName";
const cameraStorageKey = "kkkmeet.cameraDeviceId";
const micStorageKey = "kkkmeet.micDeviceId";
const watchHeightStorageKey = "kkkmeet.watchPanelHeight";
const watchCollapsedStorageKey = "kkkmeet.watchPanelCollapsed";
const rtcConfig = {
iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
};
@@ -49,6 +51,28 @@ function applyStoredWatchHeight() {
if (savedHeight > 0) {
stage.style.setProperty("--watch-panel-height", `${savedHeight}px`);
}
setWatchCollapsed(localStorage.getItem(watchCollapsedStorageKey) === "true");
}
function setWatchCollapsed(collapsed) {
stage.classList.toggle("is-watch-collapsed", collapsed);
watchCollapseButton.textContent = collapsed ? "↓" : "↑";
watchCollapseButton.setAttribute(
"aria-label",
collapsed ? "Expand YouTube panel" : "Collapse YouTube panel"
);
watchCollapseButton.title = collapsed ? "Expand YouTube panel" : "Collapse YouTube panel";
localStorage.setItem(watchCollapsedStorageKey, String(collapsed));
}
function toggleWatchCollapsed() {
if (!stage.classList.contains("is-watch-collapsed")) {
const height = Math.round(watchPanel.getBoundingClientRect().height);
if (height > 0) {
localStorage.setItem(watchHeightStorageKey, String(height));
}
}
setWatchCollapsed(!stage.classList.contains("is-watch-collapsed"));
}
function setStatus(message) {
@@ -752,6 +776,10 @@ navigator.mediaDevices?.addEventListener?.("devicechange", () => {
applyStoredWatchHeight();
watchResizeHandle.addEventListener("pointerdown", (event) => {
if (event.target.closest("#watch-collapse-button") || stage.classList.contains("is-watch-collapsed")) {
return;
}
event.preventDefault();
watchResizeHandle.setPointerCapture(event.pointerId);
stage.classList.add("is-resizing-watch");
@@ -779,3 +807,14 @@ watchResizeHandle.addEventListener("pointerdown", (event) => {
watchResizeHandle.addEventListener("pointerup", stop);
watchResizeHandle.addEventListener("pointercancel", stop);
});
watchCollapseButton.addEventListener("click", (event) => {
event.stopPropagation();
toggleWatchCollapsed();
});
watchCollapseButton.addEventListener("keydown", (event) => {
if (event.key !== "Enter" && event.key !== " ") return;
event.preventDefault();
toggleWatchCollapsed();
});
+22 -11
View File
@@ -22,16 +22,6 @@
<section class="stage" aria-label="Video call">
<section class="watch-panel" aria-label="Watch together">
<div class="watch-main">
<form id="youtube-form" class="youtube-form">
<input
id="youtube-input"
type="url"
inputmode="url"
placeholder="YouTube URL"
autocomplete="off"
/>
<button type="submit">Add</button>
</form>
<div class="youtube-shell" id="youtube-shell">
<div id="youtube-player"></div>
</div>
@@ -42,6 +32,16 @@
<button id="clear-playlist-button" type="button">Clear list</button>
</div>
<ul id="playlist-list" class="playlist-list"></ul>
<form id="youtube-form" class="youtube-form">
<input
id="youtube-input"
type="url"
inputmode="url"
placeholder="YouTube URL"
autocomplete="off"
/>
<button type="submit">Add</button>
</form>
</aside>
</section>
<button
@@ -50,7 +50,18 @@
type="button"
aria-label="Resize YouTube panel"
title="Resize YouTube panel"
></button>
>
<span
id="watch-collapse-button"
class="watch-collapse-button"
role="button"
tabindex="0"
aria-label="Collapse YouTube panel"
title="Collapse YouTube panel"
>
↑
</span>
</button>
<div class="remote-grid" id="remote-grid">
<div class="empty-stage" id="empty-stage">Waiting for others to join</div>
</div>
+46 -8
View File
@@ -110,6 +110,10 @@ button[aria-pressed="false"] {
padding: 18px 18px 12px;
}
.stage.is-watch-collapsed {
grid-template-rows: 0 20px minmax(0, 1fr);
}
.watch-panel {
display: grid;
grid-template-columns: minmax(320px, 1fr) minmax(240px, 360px);
@@ -120,17 +124,21 @@ button[aria-pressed="false"] {
overflow: auto;
}
.stage.is-watch-collapsed .watch-panel {
overflow: hidden;
}
.watch-main {
display: grid;
grid-template-rows: auto minmax(0, 1fr);
gap: 10px;
min-height: 0;
}
.youtube-form {
display: flex;
align-items: end;
align-items: stretch;
gap: 10px;
padding: 10px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.youtube-form input {
@@ -171,6 +179,10 @@ button[aria-pressed="false"] {
cursor: row-resize;
}
.stage.is-watch-collapsed .watch-resize-handle {
cursor: default;
}
.watch-resize-handle::before {
content: "";
position: absolute;
@@ -183,6 +195,32 @@ button[aria-pressed="false"] {
transform: translate(-50%, -50%);
}
.watch-collapse-button {
position: absolute;
left: 50%;
top: 50%;
z-index: 1;
display: inline-grid;
place-items: center;
width: 34px;
height: 20px;
border-radius: 999px;
background: #1f8f5f;
color: #ffffff;
font-size: 14px;
font-weight: 800;
line-height: 1;
cursor: pointer;
transform: translate(-50%, -50%);
}
.watch-collapse-button:hover,
.watch-collapse-button:focus-visible {
filter: brightness(1.12);
outline: 2px solid rgba(255, 255, 255, 0.42);
outline-offset: 2px;
}
.watch-resize-handle:hover::before,
.watch-resize-handle:focus-visible::before,
.stage.is-resizing-watch .watch-resize-handle::before {
@@ -195,7 +233,7 @@ button[aria-pressed="false"] {
.playlist-panel {
display: grid;
grid-template-rows: auto minmax(0, 1fr);
grid-template-rows: auto minmax(0, 1fr) auto;
min-height: 0;
border-radius: 8px;
background: rgba(255, 255, 255, 0.05);
@@ -490,16 +528,16 @@ button[aria-pressed="false"] {
grid-template-rows: var(--watch-panel-height, 430px) 14px minmax(0, 1fr);
}
.stage.is-watch-collapsed {
grid-template-rows: 0 20px minmax(0, 1fr);
}
.watch-panel {
grid-template-columns: 1fr;
grid-template-rows: minmax(220px, 1fr) minmax(160px, auto);
min-height: 430px;
}
.youtube-form {
align-items: stretch;
}
.remote-grid {
grid-template-columns: 1fr;
grid-auto-rows: minmax(190px, 1fr);