Skip to content

Commit e40b9a3

Browse files
committed
fix: square-only grid layout for all live views
Two fixes: 1. WebRTCVideoCell: add missing stream disable button + overlays (power icon in controls, inline confirm, disabled overlay with re-enable button — matches HLS and MSE cells added in previous commit) 2. GridPicker / computeOptimalGrid: always produce square grids Before: lookup table returned rectangles for many counts n=2 → [2,1], n=5 → [3,2], n=6 → [3,2], n=12 → [4,3] etc. After: s = ceil(sqrt(n)), always return [s, s] n=2 → [2,2], n=5 → [3,3], n=6 → [3,3], n=12 → [4,4] The GridPicker popover itself also used a rectangular cell grid (gridRows = ceil(max/gridCols)) which could produce 3×2, 4×3, etc. Now gridRows = gridCols = ceil(sqrt(effectiveMax)) so the picker is always a square and never forces a landscape/portrait orientation.
1 parent 0886259 commit e40b9a3

1 file changed

Lines changed: 11 additions & 18 deletions

File tree

web/js/components/preact/GridPicker.jsx

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,16 @@ const DEFAULT_COLS = 6;
1515
const DEFAULT_ROWS = 6;
1616

1717
/**
18-
* Return the best [cols, rows] to display N streams in a near-square grid.
18+
* Return the best [cols, rows] to display N streams in a square grid.
19+
* Always returns [s, s] where s = ceil(sqrt(n)), so the layout is never a
20+
* landscape or portrait rectangle that would force a particular screen orientation.
1921
* @param {number} n
2022
* @returns {[number, number]}
2123
*/
2224
export function computeOptimalGrid(n) {
23-
if (n <= 1) return [1, 1];
24-
if (n <= 2) return [2, 1];
25-
if (n <= 4) return [2, 2];
26-
if (n <= 6) return [3, 2];
27-
if (n <= 9) return [3, 3];
28-
if (n <= 12) return [4, 3];
29-
if (n <= 16) return [4, 4];
30-
if (n <= 20) return [5, 4];
31-
if (n <= 24) return [6, 4];
32-
if (n <= 28) return [7, 4];
33-
if (n <= 32) return [8, 4];
34-
// 33-36 and beyond: 9×4 = 36 per page (pagination handles the rest)
35-
return [9, 4];
25+
if (n <= 1) return [1, 1];
26+
const s = Math.ceil(Math.sqrt(n));
27+
return [s, s];
3628
}
3729

3830
/**
@@ -52,11 +44,12 @@ export function GridPicker({ cols, rows, onSelect, maxCells }) {
5244
const [open, setOpen] = useState(false);
5345
const containerRef = useRef(null);
5446

55-
// Scale the picker grid to fit the stream count, capped at MAX_GRID_CELLS.
56-
// e.g. 6 streams → 3×2, 205×4, 32+6×6 (cells beyond 32 are greyed out)
47+
// Scale the picker grid to fit the stream count, always as a square.
48+
// e.g. 3 streams → 2×2, 53×3, 93×3, 10 → 4×4
5749
const effectiveMax = Math.min(maxCells > 0 ? maxCells : DEFAULT_COLS * DEFAULT_ROWS, MAX_GRID_CELLS);
58-
const gridCols = Math.max(2, Math.ceil(Math.sqrt(effectiveMax)));
59-
const gridRows = Math.max(2, Math.ceil(effectiveMax / gridCols));
50+
const gridSide = Math.max(2, Math.ceil(Math.sqrt(effectiveMax)));
51+
const gridCols = gridSide;
52+
const gridRows = gridSide;
6053

6154
// Keep hover in sync when external selection changes (e.g. auto-grid on load)
6255
useEffect(() => { setHover({ c: cols, r: rows }); }, [cols, rows]);

0 commit comments

Comments
 (0)