Fit browser workspace within viewport below dynamic header bars

This commit is contained in:
Mikei386
2026-09-29 19:52:58 +02:00
parent 32aece7ff7
commit 9ff96db3c8
4 changed files with 29 additions and 15 deletions
+12
View File
@@ -51,3 +51,15 @@ Validation: build/typecheck and all 8 tests pass; integration tests now assert
reported image's existence/read permission was verified from inside LTX without
opening its content. A fresh synthetic upload was also checked from LTX and then
removed. Only the GUI was recreated; real image generation remains a user retry.
## Browser viewport layout — 2026-09-29
Replaced desktop view-level `100vh` sizing with parent-relative heights. The web
shell owns `100dvh`; headers/status banners do not shrink, and the workspace takes
only the remaining height with `min-height: 0`. Information panels are internally
scrollable and height-limited. Home and Project no longer add a second viewport.
Typecheck, build and all 8 existing tests pass. In an isolated browser fixture at
720 px viewport height, document/shell height remains 720 px and the Generate
button's bottom stays at 693 px, both with the information panel open and closed.
No production prompts or media were used for this check.
+10 -8
View File
@@ -19,13 +19,15 @@ function Workspace() {
const { isLoaded, runtimePolicyLoaded } = useAppSettings()
useGenerationRecoveryWatcher()
const ready = connected && isLoaded && runtimePolicyLoaded
return <>
<div className={`px-4 py-2 text-sm ${ready ? 'bg-emerald-950 text-emerald-200' : 'bg-amber-950 text-amber-200'}`} role="status">
return <div className="flex flex-1 min-h-0 min-w-0 flex-col overflow-hidden" data-testid="workspace">
<div className={`shrink-0 px-4 py-2 text-sm ${ready ? 'bg-emerald-950 text-emerald-200' : 'bg-amber-950 text-amber-200'}`} role="status">
{ready ? 'LTX backend connected · generation runs on the remote server' : isLoading ? 'Checking LTX connection…' : 'LTX is not ready. Activate Video mode in Athena Deck. The connection is checked automatically.'}
</div>
<div className="flex-1 min-h-0 min-w-0 overflow-hidden" data-testid="workspace-content">
{currentView === 'home' ? <Home /> : ready ? <Project /> : <div className="p-12"><p>Projects are retained. Generation becomes available when the LTX backend and its settings are reachable.</p><button className="mt-4 underline" onClick={goHome}>Back to projects</button></div>}
</div>
<KeyboardShortcutsModal /><DevPanel />
</>
</div>
}
export default function App() {
const [session, setSession] = useState<{ backendUrl: string } | null>(null)
@@ -48,18 +50,18 @@ export default function App() {
<button className="bg-blue-600 rounded px-4 py-2" type="submit">Sign in</button><p role="alert" className="mt-4 text-red-300">{error}</p>
</form>
</main>
return <>
<header className="flex justify-between items-center px-4 py-2 bg-zinc-900 border-b border-zinc-700 text-sm">
return <div className="h-dvh w-full min-h-0 flex flex-col overflow-hidden" data-testid="web-shell">
<header className="shrink-0 flex justify-between items-center px-4 py-2 bg-zinc-900 border-b border-zinc-700 text-sm">
<strong>LTX DeskWEB · Preview</strong><div className="flex gap-4"><button onClick={() => setHelp(!help)}>Connection & information</button><button onClick={async () => { await webRequest('/web/logout', {}); location.reload() }}>Sign out</button></div>
</header>
{help && <aside className="p-5 bg-zinc-900 border-b border-zinc-700 space-y-2">
{help && <aside className="shrink-0 max-h-[35dvh] overflow-y-auto p-5 bg-zinc-900 border-b border-zinc-700 space-y-2">
<p>Native LTX API via: <code>{session.backendUrl}</code>. Change the address and token in the container configuration.</p>
<p>Video mode is managed in Athena Deck. This web app never starts or installs a model.</p>
<p>Preview: projects are saved in this browser. Use “Back up projects” before clearing browser data. Timeline rendering, desktop folder dialogs and Hugging Face desktop login are not yet ported.</p>
<WebProjectBackup />
<button className="ml-4 underline" onClick={() => setHelp(false)}>Close</button>
</aside>}
{message && <div className="p-3 bg-blue-950 flex justify-between" role="status">{message}<button onClick={() => setMessage('')}>Dismiss</button></div>}
{message && <div className="shrink-0 max-h-[15dvh] overflow-y-auto p-3 bg-blue-950 flex justify-between gap-4" role="status">{message}<button onClick={() => setMessage('')}>Dismiss</button></div>}
<AppSettingsProvider><ProjectProvider><ViewProvider><KeyboardShortcutsProvider><DevFlagsProvider><Workspace /></DevFlagsProvider></KeyboardShortcutsProvider></ViewProvider></ProjectProvider></AppSettingsProvider>
</>
</div>
}
+2 -2
View File
@@ -172,7 +172,7 @@ export function Home() {
: 0
return (
<div className="h-screen bg-background flex items-center justify-center">
<div className="h-full min-h-0 bg-background flex items-center justify-center">
<div className="w-[360px]">
<p className="text-center text-sm text-zinc-300 mb-4">
Migrating project references...
@@ -189,7 +189,7 @@ export function Home() {
}
return (
<div className="h-screen bg-background flex">
<div className="h-full min-h-0 bg-background flex">
{/* Sidebar */}
<aside className="w-64 border-r border-zinc-800 flex flex-col">
<div className="p-6">
+5 -5
View File
@@ -82,7 +82,7 @@ export function Project() {
if (!activeProject) {
return (
<div className="h-screen bg-background flex items-center justify-center">
<div className="h-full min-h-0 bg-background flex items-center justify-center">
<div className="text-center">
<p className="text-zinc-400 mb-4">Project not found</p>
<Button onClick={goHome}>Go Home</Button>
@@ -104,7 +104,7 @@ export function Project() {
: 0
return (
<div className="h-screen bg-background flex items-center justify-center">
<div className="h-full min-h-0 bg-background flex items-center justify-center">
<div className="w-[360px]">
<p className="text-center text-sm text-zinc-300 mb-4">
Preparing your project assets...
@@ -121,9 +121,9 @@ export function Project() {
}
return (
<div className="h-screen bg-background flex flex-col">
<div className="h-full min-h-0 bg-background flex flex-col">
{/* Header */}
<header className="flex items-center px-4 py-3 border-b border-zinc-800">
<header className="shrink-0 flex items-center px-4 py-3 border-b border-zinc-800">
<div className="flex-1 flex items-center gap-4">
{/* Back button and logo */}
<button
@@ -161,7 +161,7 @@ export function Project() {
<div className="flex-1" />
</header>
<main className="flex-1 overflow-hidden relative">
<main className="flex-1 min-h-0 overflow-hidden relative">
{currentTab === 'gen-space' ? (
<GenSpace />
) : (