From 062cd79952e72a0dc61cae419d5840b122f75c8b Mon Sep 17 00:00:00 2001 From: zai-bot Date: Fri, 6 Nov 2026 08:40:11 +0000 Subject: [PATCH] =?UTF-8?q?v7.16.0=20=E2=80=94=20presets=20tab=20rearrange?= =?UTF-8?q?d:=20management=20panel=20on=20top,=20full-width=20tree=20below?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User request: drop the side-by-side split so the 'Load Preset' section sits on top at full width with no wasted height (even when a preset is selected) and the preset tree below uses the whole section width, so preset names never clip. Buttons pack into one compact grid row on desktop (2x3 for a user folder; phones keep the old stacking); the tree fills the tab body's leftover height on desktop (h-full flex chain, 420px cap only below lg); club-mode scope line + RANDOM/SEQUENCE pill share one row. No logic changes. Worklog Task 48. --- src/components/ava/presets-tab.tsx | 461 +++++++++++++++-------------- src/lib/release-notes.ts | 14 + src/lib/version.ts | 28 +- worklog.md | 27 ++ 4 files changed, 306 insertions(+), 224 deletions(-) diff --git a/src/components/ava/presets-tab.tsx b/src/components/ava/presets-tab.tsx index 20ddfc1..f661f16 100755 --- a/src/components/ava/presets-tab.tsx +++ b/src/components/ava/presets-tab.tsx @@ -9,9 +9,14 @@ // nothing is sent to the server, so nobody can spam or vandalize what // other visitors see. // -// Left column: the tree (chevron expands, row selects, double-click runs, -// running preset flagged emerald, originals download from the row). -// Right column: context-sensitive management + the club-mode randomizer. +// v7.16 layout (user request): the two old side-by-side columns are gone. +// The context-sensitive management panel (selection header + action buttons +// + the club-mode randomizer) sits ON TOP at full width and its natural +// height -- one compact button grid row on desktop, never stretched, so no +// empty space is wasted below it. The folder/file tree (chevron expands, +// row selects, double-click runs, running preset flagged emerald, originals +// download from the row) fills the remaining tab height BELOW it at full +// width too -- full-width rows mean preset names never clip. 'use client' @@ -751,8 +756,11 @@ export function PresetsTab() { // ----------------------------------------------------------------- return ( -
-
+ // v7.16: h-full lets the tree fill the tab body's height on desktop + // (where the panel scrolls internally); below lg the chain is + // auto-height, so this stays natural and the page scrolls. +
+

{presets.length} presets ·{' '} {folders.length} folders @@ -760,256 +768,263 @@ export function PresetsTab() {

double-click a preset to run it

-
- {/* LEFT -- folder/file tree */} -
-
- {tree.map((node) => ( - - ))} - {presets.length === 0 && ( -

Loading presets…

+ {/* TOP -- management panel: full width, natural height (never + stretched), buttons packed into one compact grid row on desktop */} +
+
+ {selectedPreset ? ( + + ) : ( + + )} +
+

+ {selectedPreset ? selectedPreset.name : folderName} +

+

+ {selectedPreset ? selectedPreset.folderPath : selectedFolder} +

+ {!selectedPreset && ( +

+ {plural(folderPresetCount, 'preset')} · {plural(childFolderCount, 'subfolder')} +

)}
+ {(folderReadOnly || (selectedPreset && !presetOwn)) && ( + + read-only + + )}
- {/* RIGHT -- management panel */} -
-
- {selectedPreset ? ( - - ) : ( - - )} -
-

- {selectedPreset ? selectedPreset.name : folderName} -

-

- {selectedPreset ? selectedPreset.folderPath : selectedFolder} -

- {!selectedPreset && ( -

- {plural(folderPresetCount, 'preset')} · {plural(childFolderCount, 'subfolder')} -

- )} -
- {(folderReadOnly || (selectedPreset && !presetOwn)) && ( - - read-only - - )} -
- -
- {selectedPreset ? ( - <> +
+ {selectedPreset ? ( + presetOwn ? ( + /* one row on desktop: Load (primary, wider) | Rename | Delete */ +
- {presetOwn ? ( -
- - -
- ) : ( - - )} - - ) : folderReadOnly ? ( - <> -
- - -
- + + +
) : ( - <> + /* embedded preset: Load | Copy to my presets */ +
-
- - -
-
- - -
- - )} -
- - {/* preset mixing (club mode) -- Random or Sequence, one timer in the store */} -
-
- - useAvaStore.getState().setRandomize(v === true)} - aria-label="Random presets" - className="size-4 data-[state=checked]:border-emerald-400 data-[state=checked]:bg-emerald-400 data-[state=checked]:text-emerald-950" - /> - - - - useAvaStore.getState().setSequenceMode(v === true)} - aria-label="Sequence presets" - className="size-4 data-[state=checked]:border-emerald-400 data-[state=checked]:bg-emerald-400 data-[state=checked]:text-emerald-950" - /> - - - - onDelayChange(e.target.value)} - onBlur={onDelayBlur} - inputMode="numeric" - aria-label="Random switch delay in seconds" - className="h-8 w-16 border-zinc-700 bg-zinc-900 px-2 text-center font-mono text-xs tabular-nums" - /> - sec - +
+ ) + ) : folderReadOnly ? ( +
+ +
- {delayError && ( -

Delay must be between 3 and 60 seconds.

- )} -

+ ) : ( + /* own folder: 3-wide grid on desktop -- [Create | Subfolder | + Rename] over [Delete | Export | Import] -- two compact rows */ +

+ + + + + + +
+ )} +
+ + {/* preset mixing (club mode) -- Random or Sequence, one timer in the store */} +
+
+ + useAvaStore.getState().setRandomize(v === true)} + aria-label="Random presets" + className="size-4 data-[state=checked]:border-emerald-400 data-[state=checked]:bg-emerald-400 data-[state=checked]:text-emerald-950" + /> + + + + useAvaStore.getState().setSequenceMode(v === true)} + aria-label="Sequence presets" + className="size-4 data-[state=checked]:border-emerald-400 data-[state=checked]:bg-emerald-400 data-[state=checked]:text-emerald-950" + /> + + + + onDelayChange(e.target.value)} + onBlur={onDelayBlur} + inputMode="numeric" + aria-label="Random switch delay in seconds" + className="h-8 w-16 border-zinc-700 bg-zinc-900 px-2 text-center font-mono text-xs tabular-nums" + /> + sec + +
+ {delayError && ( +

Delay must be between 3 and 60 seconds.

+ )} +
+

{sequenceMode ? 'Sequence from:' : 'Random from:'}{' '} {scopeLabel} {scopeCount === 0 && -- no presets in this folder yet}

{(randomize || sequenceMode) && ( -
- - - {sequenceMode ? 'SEQUENCE' : 'RANDOM'} · every {randomIntervalSec}s - -
+ + + {sequenceMode ? 'SEQUENCE' : 'RANDOM'} · every {randomIntervalSec}s + )}
+ {/* BELOW -- the folder/file tree: full width, filling every bit of + height the tab has left (capped only when the page itself + scrolls, below lg) so long names never clip */} +
+
+ {tree.map((node) => ( + + ))} + {presets.length === 0 && ( +

Loading presets…

+ )} +
+
+ {/* name dialogs */} one grid row [Load Preset (1.3fr, primary) | Rename | Delete] (own) or [Load Preset | Copy to my presets] (embedded); read-only folder -> [Export .zip | Import .zip]; own folder -> 2x3 grid [Create | Subfolder | Rename] over [Delete | Export | Import]. All cells uniform h-9 (the old h-8/h-9 mix normalized), minmax(0,fr) tracks + whitespace-nowrap so nothing ever wraps or clips; phones keep the previous stacking (primary action full-width, pairs below) via col-span-2/sm:col-span-1. +- The tree fills the tab body's remaining height on desktop: PresetsTab root becomes flex h-full min-h-0 flex-col (h-full resolves against TabBody's definite lg height; below lg the chain is auto-height so it is inert), tree card flex-1 min-h-[160px], inner scroll div flex-1 with max-h-[420px] lg:max-h-none (the cap survives only where the page itself scrolls). Short viewports overflow the root and the TabBody scrolls -- every control stays reachable. +- Club mode: the scope line and the active RANDOM/SEQUENCE pill now share one row (min-w-0 truncate text + shrink-0 pill), saving the old stacked line. + +Work Log: +- presets-tab.tsx: file header comment rewritten for the new layout; root space-y-3 -> flex h-full min-h-0 flex-col gap-3; counts row + management panel shrink-0; panel div- -> shrink-0 card; all four action-button states rebuilt as responsive grids; button heights normalized to h-9; club-mode scope+badge merged into one justify-between row; tree moved below as flex min-h-[160px] flex-1 card with the flex-1/max-h inner scroller. No logic, store, dialog, or tree-row changes -- selection, load, create/copy/rename/delete, zip io and the randomizer are untouched. +- version.ts: APP_VERSION 7.16.0 + history entry. release-notes.ts: 7.16.0 "Presets tab, rearranged" (2 improved, first-person voice, no em dashes). + +BROWSER E2E (agent-browser, ALL PASS): +- Desktop 1280x800: panel (y=184) above tree (y=404), both 402 px = full section width; panel natural height 207 px (not stretched); tab body 570 = 570 scrollHeight -- the tree fills the remaining 322 px with NO internal tab scroll; 0 treeitem names clipped (was the whole point of the request). +- Selection states, all one row / 2x3 as designed, uniform 36 px cells, zero button overflow: own preset [Load 142 | Rename 109 | Delete 109], embedded preset [Load 184 | Copy 184], root folder [Export 184 | Import 184], user folder 2x3 [Create 126 | Subfolder 126 | Rename 107] / [Delete 126 | Export 126 | Import 107]. +- Flows: Load Preset click -> footer "SCRIPT: Adrealine rush" + emerald running flag in the tree; Copy to my presets -> own-preset row appears; Create Preset dialog -> created + selected + auto-switch to Script tab (pre-existing behavior); Random tick -> "RANDOM · every 10s" pill INLINE with "Random from: user created" (same row), unticked cleanly. +- Tightest widths: 1024x800 (aside 420 px, panel 382 px) -> all grids overflow-free (Load 134 / Rename 103 / Delete 103; folder cells 119/119/101); 800x900 -> 2x3 rows at full width; 375x812 mobile -> panel above tree, both 305 px full width, Load full-row + Rename|Delete pair, folder grid keeps the old 4-row stacking, tree capped at 420 px, no horizontal scroll, footer pushed to the document bottom naturally (docH 1419). +- Version: title "OVE -- Open Visualization Engine (v7.16.0)"; What's New dialog opens with 7.16.0 "Presets tab, rearranged" first; console 0 errors / 0 warnings / no version-drift guard trip; dev.log clean (200s only). + +Pre-flight hygiene (before the feature work): the working tree carried three leftover modifications from the v7.15.3 session -- db/custom.db.seed binary drift and 100755 modes on .env.ove + secrets/README.md. Both seeds verified content-identical via Prisma (106 presets / 8 folders / 1 settings, all rows equal), so the seed was reset to the committed baseline and the modes normalized back to 644 -- tree clean before the v7.16.0 commit. + +Stage Summary: +- v7.16.0 shipped: the Presets tab's management panel (Load Preset and friends) sits on top at full width and natural height -- no stretched empty space even with a preset selected -- with its buttons packed into one compact grid row on desktop, and the preset tree below it uses the whole section width (filling the tab's leftover height on desktop), so preset names no longer clip. Browser E2E green across every selection state, four viewports, the load/create/copy/randomizer flows and the What's New dialog.