Grid density: cut the board finer or coarser, per browser #14
@@ -277,8 +277,10 @@ below. Nothing is installed without someone clicking.
|
||||
**Grid** stepper sets how many columns this browser cuts the board into —
|
||||
8 to 24, 12 by default. Finer lets tiles be smaller so more fit across (a
|
||||
4K wall), coarser suits a small screen read close up; row height follows,
|
||||
so tiles keep their shape and simply change size. It saves with the
|
||||
layout, so a named layout comes back at the density it was arranged on.
|
||||
so tiles keep their shape and simply change size. Going coarser, a tile
|
||||
that no longer fits where it was moves to the first free spot rather than
|
||||
onto another tile. It saves with the layout, so a named layout comes back
|
||||
at the density it was arranged on.
|
||||
- Every tile has a **status dot**: green = live, amber = connecting,
|
||||
red = upstream unreachable (hover it for details). Tiles reconnect
|
||||
automatically.
|
||||
|
||||
+22
-3
@@ -296,8 +296,9 @@ function cellHeightFor(cols) {
|
||||
}
|
||||
|
||||
/** Cut the board into `cols` columns. Tiles keep their grid units — the
|
||||
board gets denser or coarser and everything on it changes size with it;
|
||||
only a tile now past the right edge is pulled back in. */
|
||||
board gets denser or coarser and everything on it changes size with it.
|
||||
A tile now past the right edge is pulled back in, and one that would then
|
||||
sit on another moves to the first free spot instead. */
|
||||
function setGridCols(value, { save = true } = {}) {
|
||||
const next = normalizeGridCols(value);
|
||||
const changed = next !== COLS;
|
||||
@@ -305,9 +306,16 @@ function setGridCols(value, { save = true } = {}) {
|
||||
grid.style.gridTemplateColumns = `repeat(${COLS}, minmax(0, 1fr))`;
|
||||
document.documentElement.style.setProperty('--cell-h', cellHeightFor(COLS) + 'px');
|
||||
if (changed) {
|
||||
for (const tile of tiles) {
|
||||
// A coarser board may not have room for every tile where it was. Settle
|
||||
// them in reading order: pull a tile past the right edge back in, and
|
||||
// give one that would then land on a tile already settled the first free
|
||||
// spot instead — tiles never overlap here, any more than under a drag.
|
||||
const settled = [];
|
||||
for (const tile of tiles.slice().sort((a, b) => a.y - b.y || a.x - b.x)) {
|
||||
tile.w = Math.max(1, Math.min(COLS, tile.w));
|
||||
tile.x = Math.max(0, Math.min(COLS - tile.w, tile.x));
|
||||
if (settled.some((s) => overlaps(tile, s))) Object.assign(tile, spotAmong(tile.w, tile.h, settled));
|
||||
settled.push(tile);
|
||||
applyRect(tile);
|
||||
notifyResize(tile);
|
||||
}
|
||||
@@ -386,6 +394,17 @@ function isFree(rect, excludeId) {
|
||||
return isFreeExcept(rect, [excludeId]);
|
||||
}
|
||||
|
||||
/** First spot, scanning top-to-bottom, left-to-right, clear of these tiles. */
|
||||
function spotAmong(w, h, others) {
|
||||
for (let y = 0; y < 400; y += 1) {
|
||||
for (let x = 0; x <= COLS - w; x += 1) {
|
||||
const rect = { x, y, w, h };
|
||||
if (!others.some((o) => overlaps(rect, o))) return { x, y };
|
||||
}
|
||||
}
|
||||
return { x: 0, y: 0 };
|
||||
}
|
||||
|
||||
/** First free spot scanning top-to-bottom, left-to-right. */
|
||||
function findSpot(w, h) {
|
||||
for (let y = 0; y < 200; y += 1) {
|
||||
|
||||
Reference in New Issue
Block a user