From d058dcc46d377daa54e06cd0441e6e10af0ecb69 Mon Sep 17 00:00:00 2001 From: digital-garbage <133010426+digital-garbage@users.noreply.github.com> Date: Thu, 11 Jun 2026 21:17:52 +0300 Subject: [PATCH] =?UTF-8?q?Add=20media=20bin=20grid=20column=20picker=20(A?= =?UTF-8?q?uto,=201=C3=97=E2=80=934=C3=97).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let users lock the Media Browser to 1–4 columns so previews scale with panel width. --- movie_editor/frontend/mediabrowser.js | 29 +++++++++++++++++++++++++++ movie_editor/frontend/styles.css | 13 ++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/movie_editor/frontend/mediabrowser.js b/movie_editor/frontend/mediabrowser.js index 9f8f8097..b352d313 100644 --- a/movie_editor/frontend/mediabrowser.js +++ b/movie_editor/frontend/mediabrowser.js @@ -13,8 +13,11 @@ let mediaSelectMode = false; // when off, click = preview; when on, click = toggle selection const MF_KEY = "fp_media_filter"; const MS_KEY = "fp_media_sort"; + const MC_KEY = "fp_media_grid_cols"; let mediaFilter = localStorage.getItem(MF_KEY) || "all"; let mediaSort = localStorage.getItem(MS_KEY) || "name_asc"; + let mediaGridCols = parseInt(localStorage.getItem(MC_KEY) || "0", 10); + if (![0, 1, 2, 3, 4].includes(mediaGridCols)) mediaGridCols = 0; const MEDIA_FILTERS = [ { id: "all", label: "All" }, @@ -28,6 +31,13 @@ { id: "type", label: "Type" }, { id: "date_desc", label: "Date added" }, ]; + const MEDIA_GRID_COLS = [ + { id: 0, label: "Auto" }, + { id: 1, label: "1×" }, + { id: 2, label: "2×" }, + { id: 3, label: "3×" }, + { id: 4, label: "4×" }, + ]; const MEDIA_KIND_ORDER = { image: 0, video: 1, audio: 2, other: 3 }; const MEDIA_GROUP_LABELS = { image: "Images", video: "Video", audio: "Audio", other: "Other" }; @@ -351,6 +361,24 @@ sortRow.append(sortSel); controls.append(sortRow); + const colsRow = el("div", "media-bin-cols"); + colsRow.append(el("span", "media-bin-sort-lbl", "Grid")); + const colsSeg = el("div", "insp-switch media-bin-cols-switch"); + MEDIA_GRID_COLS.forEach((c) => { + const btn = el("button", "insp-seg" + (mediaGridCols === c.id ? " active" : ""), c.label); + btn.title = c.id === 0 + ? "Column count follows panel width" + : `${c.id} column${c.id > 1 ? "s" : ""} (× rows)`; + btn.onclick = () => { + mediaGridCols = c.id; + localStorage.setItem(MC_KEY, String(c.id)); + render(S.get()); + }; + colsSeg.append(btn); + }); + colsRow.append(colsSeg); + controls.append(colsRow); + if (total > 0 && shown !== total) { controls.append(el("div", "pj-meta media-bin-count", `${shown} of ${total} shown`)); } @@ -513,6 +541,7 @@ } const grid = el("div", "media-grid"); + grid.dataset.cols = String(mediaGridCols); if (items.length) _appendMediaGrid(grid, items, st); else if (total) grid.append(el("div", "pj-meta media-grid-empty", "No items match this filter.")); else grid.append(el("div", "pj-meta media-grid-empty", "No media yet.")); diff --git a/movie_editor/frontend/styles.css b/movie_editor/frontend/styles.css index 1ec25de8..41add823 100644 --- a/movie_editor/frontend/styles.css +++ b/movie_editor/frontend/styles.css @@ -259,10 +259,16 @@ input[type=number] { font-family: var(--font-mono); } /* media grid — default compact (pickers, modals); media browser scales with panel width */ .media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(76px, 1fr)); gap: 8px; } #media-zone .media-grid { - --mb-cell: clamp(96px, 46cqw, 240px); - grid-template-columns: repeat(auto-fill, minmax(var(--mb-cell), 1fr)); gap: clamp(8px, 2.5cqw, 14px); } +#media-zone .media-grid[data-cols="0"] { + --mb-cell: clamp(96px, 46cqw, 240px); + grid-template-columns: repeat(auto-fill, minmax(var(--mb-cell), 1fr)); +} +#media-zone .media-grid[data-cols="1"] { grid-template-columns: repeat(1, minmax(0, 1fr)); --mb-cell: 92cqw; } +#media-zone .media-grid[data-cols="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); --mb-cell: 44cqw; } +#media-zone .media-grid[data-cols="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); --mb-cell: 29cqw; } +#media-zone .media-grid[data-cols="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); --mb-cell: 21cqw; } #media-zone .media-thumb { height: auto; aspect-ratio: 16 / 10; @@ -329,6 +335,9 @@ input[type=number] { font-family: var(--font-mono); } .media-bin-controls { display: flex; flex-direction: column; gap: 8px; margin: 4px 0 2px; } .media-bin-type { margin: 0; } .media-bin-sort { display: flex; align-items: center; gap: 8px; } +.media-bin-cols { display: flex; align-items: center; gap: 8px; } +.media-bin-cols-switch { flex: 1; min-width: 0; } +.media-bin-cols-switch .insp-seg { flex: 1; min-width: 0; padding-left: 4px; padding-right: 4px; } .media-bin-sort-lbl { flex: 0 0 auto; font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .8px; text-transform: uppercase; color: var(--faint); } .media-bin-sort-sel { flex: 1; min-width: 0; padding: 5px 7px; font-size: 12px; } .media-bin-count { margin: 0; }