diff --git a/CHANGELOG.md b/CHANGELOG.md index 8228c3db..447d9535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ the frozen-backend fallback mirror it for their toolchains. **Highlights** -- Voice modes now lead the workspace as full-width tabs, with the active engine above them and each workflow below (#1823) +- Voice modes now lead the workspace as full-width tabs, with the active engine above them and Synthesize pinned below the scrolling form (#1823) - Voice cloning now starts with a clear upload-or-record choice, reveals recording and reference details only when needed, and keeps sampling controls under Production Overrides (#1817) ### Changed diff --git a/README.md b/README.md index f4b5e003..fa7bbcc9 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ | **Storage** | Voices, projects, settings, and outputs stay on the machine by default | | **License** | AGPL-3.0 application; downloaded models keep their upstream terms | -The Voice workspace starts with the active engine selector and three tabs: **From audio** for cloning, **By design** for creating a voice, and **Convert** for speech-to-speech conversion. Each tab displays its own workflow below. +The Voice workspace starts with the active engine selector and three tabs: **From audio** for cloning, **By design** for creating a voice, and **Convert** for speech-to-speech conversion. Each tab displays its own workflow below. In From audio and By design, Synthesize Audio stays at the bottom while the form scrolls above it. diff --git a/frontend/src/index.css b/frontend/src/index.css index f66714ec..b4fac723 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -2148,6 +2148,11 @@ div[role="dialog"].audio-trimmer { gap: 8px; } +.studio-action-bar .override-content { + max-height: 40vh; + overflow-y: auto; +} + /* ═══════════════════════════════════════════════════════════ RESPONSIVE — make every component adapt to viewport width ════════════════════════════════════════════════════════════ */ @@ -4953,7 +4958,7 @@ button.dub-stepper__action:focus-visible { .shell-narrow .studio-with-history__main, .shell-mini .studio-with-history__main { overflow: visible; - flex: 0 0 auto; + flex: 1 0 auto; order: 1; } .shell-narrow .studio-with-history__main .studio-action-bar, diff --git a/frontend/src/pages/CloneDesignTab.jsx b/frontend/src/pages/CloneDesignTab.jsx index e90db158..088ef307 100644 --- a/frontend/src/pages/CloneDesignTab.jsx +++ b/frontend/src/pages/CloneDesignTab.jsx @@ -443,14 +443,8 @@ export default function CloneDesignTab(props) { - {/* #1771 follow-up (item 6): NOT flex-1 — the old always-open 12-row - Design block was tall enough that this area routinely filled the - full column height on its own. Now that Details defaults collapsed, - forcing this to grow-fill would strand a dead gap between it and - ActionBar below. Sizing to content (min-h-0 + overflow-y-auto still - in play) lets it shrink for short content and still scroll when - content genuinely exceeds the available height. */} -
+ {/* The form owns the remaining height and scrolls above the action bar. */} +
{/* ═══ SCRIPT — what should it say ═══ Hidden for Convert: the source clip IS the script (the backend transcribes it), so a text panel would only mislead. */} diff --git a/frontend/src/test/workspaceHistoryReflow.test.js b/frontend/src/test/workspaceHistoryReflow.test.js index 1a5f1172..9c09dab5 100644 --- a/frontend/src/test/workspaceHistoryReflow.test.js +++ b/frontend/src/test/workspaceHistoryReflow.test.js @@ -46,6 +46,13 @@ describe('workspace narrow-shell reflow (#476 CTA-clipping guard)', () => { expect(css).toMatch(/\.studio-action-bar\s*\{[^}]*position:\s*sticky/s); }); + it('fills narrow workspaces and bounds expanded settings above the pinned action', () => { + expect(css).toMatch(/\.shell-mini\s+\.studio-with-history__main\s*\{[^}]*flex:\s*1 0 auto/s); + expect(indexRaw).toMatch( + /\.studio-action-bar\s+\.override-content\s*\{[^}]*max-height:\s*40vh;[^}]*overflow-y:\s*auto/s, + ); + }); + it('keeps saved voices in the left rail and generation history alone on the right', () => { expect(app).toMatch( /className="studio-voices">\s*\s*
/,