Split the reels view into panels
A panel can be split to the right or below, and the panel that appears can be split again, so any arrangement is reachable. The layout is a binary tree and the leaves, read in order, are the panels of a step. Scrolling drives all of them: with N panels a step covers N videos and one swipe advances the whole set. That runs through every index in the feed -- opening on a video, realigning after a rotation, the prefetch buffer, the render window -- all of which now convert between a video and the step that holds it. Each panel has its own sound, so two can play at once if that is what you want. A new panel inherits the feed-wide setting rather than starting muted, so a step built later doesn't disagree with what is already on screen, and the feed-wide button reads as muted only while every panel is. Two things fall out of panels that are worth knowing. The render window narrows as panels are added -- five steps ahead of a four-panel split would be twenty live <video> elements -- so splitting does not multiply decoding. And splitting rebuilds around the video you are on rather than keeping it in the panel you split from: steps are aligned to the panel count, so it stays on screen but not necessarily first. The per-video helpers were already written against an element holding one video's controls, so they took a panel unchanged; a slide became the container that fans out over them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QBDkEXP4htyXTCZUwMLphd
This commit is contained in:
@@ -1324,7 +1324,7 @@ body.theme-light .video-menu-btn {
|
||||
}
|
||||
|
||||
/* Live streams can't be seeked, so hide the feed scrubber. */
|
||||
.feed-slide.is-live .feed-timeline {
|
||||
.feed-pane.is-live .feed-timeline {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -2158,6 +2158,9 @@ body.feed-mode-open .mode-toggle-btn .icon-svg {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
/* One screenful. It holds the pane tree rather than a video directly: with
|
||||
several panes, a step shows that many videos at once and one swipe advances
|
||||
the whole set. */
|
||||
.feed-slide {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
@@ -2165,6 +2168,34 @@ body.feed-mode-open .mode-toggle-btn .icon-svg {
|
||||
height: 100dvh;
|
||||
scroll-snap-align: start;
|
||||
scroll-snap-stop: always;
|
||||
overflow: hidden;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
/* A branch of the tree: two children sharing the space, side by side or
|
||||
stacked. Nesting these is what makes any arrangement reachable. */
|
||||
.feed-split {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.feed-split.is-row { flex-direction: row; }
|
||||
.feed-split.is-col { flex-direction: column; }
|
||||
|
||||
/* min-* is what stops a flex child refusing to shrink below its content. */
|
||||
.feed-split > .feed-pane,
|
||||
.feed-split > .feed-split {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.feed-pane {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -2172,6 +2203,45 @@ body.feed-mode-open .mode-toggle-btn .icon-svg {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.feed-pane-tools {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
/* Above the video, below the right-hand controls it sits beside. */
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.feed-pane-btn {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid rgba(244, 232, 212, 0.18);
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
color: var(--text-primary);
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
backdrop-filter: blur(6px);
|
||||
transition: background 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.feed-pane-btn:hover {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
border-color: var(--border-hover);
|
||||
}
|
||||
|
||||
.feed-pane-mute.is-muted {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
/* The HUD's idle fade takes the panel tools with it, like every other control. */
|
||||
body.feed-hud-idle .feed-pane-tools {
|
||||
opacity: 0;
|
||||
transition: opacity 0.4s ease;
|
||||
}
|
||||
|
||||
.feed-poster,
|
||||
.feed-video {
|
||||
position: absolute;
|
||||
@@ -2185,7 +2255,7 @@ body.feed-mode-open .mode-toggle-btn .icon-svg {
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.feed-slide.is-loaded .feed-poster {
|
||||
.feed-pane.is-loaded .feed-poster {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@@ -2310,6 +2380,22 @@ body.feed-mode-open .mode-toggle-btn .icon-svg {
|
||||
}
|
||||
|
||||
/* Per-slide favorite (heart) button on the feed HUD right rail. */
|
||||
/* The right-hand controls stack upwards from just above the caption, rather
|
||||
than sitting at fixed distances from the bottom. A pane can be a third of
|
||||
the viewport tall, and viewport-scale offsets put these outside it -- clipped
|
||||
by the pane's own overflow and unreachable. */
|
||||
.feed-pane .feed-fav-btn,
|
||||
.feed-pane .feed-pip-btn,
|
||||
.feed-pane .feed-format-btn {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
bottom: auto;
|
||||
top: 56px;
|
||||
}
|
||||
|
||||
.feed-pane .feed-pip-btn { top: 100px; }
|
||||
.feed-pane .feed-format-btn { top: 144px; }
|
||||
|
||||
.feed-fav-btn {
|
||||
position: absolute;
|
||||
top: auto;
|
||||
|
||||
Reference in New Issue
Block a user