Computer panel: reserve chat space (--computer-width) so the chat condenses, not hides
The absolute panel overlaid the full-width centered chat column, hiding the messages/composer behind it (WorkClaw avoids this by reserving the panel's width as padding on the chat). Introduced a shared --computer-width var, set once on the ChatWorkspace row per ?device= (phone 448px, tablet 67%, full 100%; 0 when closed). Both the panel <aside> width and a new chat- column wrapper's md:pr read it, so they never drift: opening the panel squeezes the centered max-w-3xl column into the left space (re-centered) while the panel overlays the reserved right area. Animated with transition-[padding]/[width] + the signature easing for the 'condense' effect. The header is outside the padded wrapper, so its cluster shift is unaffected. Verified at 1440: composer right clears the panel left edge in both tablet (561<593) and phone (920<992) — nothing hidden. 86 unit + 31 functional E2E green. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5
parent
914ffae8f9
commit
21da4dca19
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { useState, type CSSProperties } from "react";
|
||||
import { useQueryStates } from "nuqs";
|
||||
|
||||
import type { Agent } from "@/lib/api/schemas";
|
||||
@@ -9,7 +9,17 @@ import type { Session } from "@/lib/api/sessions";
|
||||
import { useChat } from "@/lib/gateway/use-chat";
|
||||
import type { UiMessage } from "@/lib/gateway/transcript";
|
||||
import { encodeSessionKeyParam } from "@/lib/url/session-key";
|
||||
import { panelParsers } from "@/lib/url/panel-params";
|
||||
import { panelParsers, type DeviceSize } from "@/lib/url/panel-params";
|
||||
|
||||
/* One source of truth for the Computer panel's width (measured): both the
|
||||
panel <aside> (width) and the chat column (padding-right) read this var,
|
||||
so the chat condenses into the left space instead of hiding behind the
|
||||
panel — WorkClaw's reserve-space model. Collapses to 0 when closed. */
|
||||
const COMPUTER_WIDTH: Record<DeviceSize, string> = {
|
||||
phone: "448px",
|
||||
tablet: "67%",
|
||||
full: "100%",
|
||||
};
|
||||
import { SlidePanel } from "@/components/ui/SlidePanel";
|
||||
import { SessionsColumn } from "@/components/sessions/SessionsColumn";
|
||||
import { DevicePanel } from "@/components/computer/DevicePanel";
|
||||
@@ -41,9 +51,11 @@ export function ChatWorkspace({
|
||||
);
|
||||
const [draft, setDraft] = useState("");
|
||||
const empty = state.messages.length === 0;
|
||||
const [{ sessions: showSessions }] = useQueryStates(panelParsers, {
|
||||
shallow: true,
|
||||
});
|
||||
const [{ sessions: showSessions, app, device }] = useQueryStates(
|
||||
panelParsers,
|
||||
{ shallow: true },
|
||||
);
|
||||
const computerWidth = app !== null ? COMPUTER_WIDTH[device] : "0px";
|
||||
|
||||
function openSession(session: Session) {
|
||||
router.push(
|
||||
@@ -66,7 +78,10 @@ export function ChatWorkspace({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative flex h-dvh">
|
||||
<div
|
||||
className="relative flex h-dvh"
|
||||
style={{ "--computer-width": computerWidth } as CSSProperties}
|
||||
>
|
||||
<SlidePanel open={showSessions} width={208} label="Sessions">
|
||||
<SessionsColumn
|
||||
sessions={sessions}
|
||||
@@ -77,7 +92,11 @@ export function ChatWorkspace({
|
||||
</SlidePanel>
|
||||
<section className="flex min-w-0 flex-1 flex-col">
|
||||
<ChatHeader agent={agent} onNewSession={newSession} />
|
||||
<div className="mx-auto flex w-full max-w-3xl min-w-0 flex-1 flex-col overflow-hidden px-4">
|
||||
{/* Reserve the panel's width as right-padding so the centered chat
|
||||
column re-centers in the left space and never hides behind the
|
||||
absolute panel (animates in sync with the panel). */}
|
||||
<div className="flex min-h-0 flex-1 flex-col transition-[padding] duration-(--duration-normal) ease-app md:pr-[var(--computer-width)]">
|
||||
<div className="mx-auto flex w-full max-w-3xl min-w-0 flex-1 flex-col overflow-hidden px-4">
|
||||
{empty ? (
|
||||
// Empty state: the composer is part of the centered welcome
|
||||
// stack (avatar → heading → subtitle → composer → chips).
|
||||
@@ -116,6 +135,7 @@ export function ChatWorkspace({
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<DevicePanel agent={agent} />
|
||||
|
||||
Reference in New Issue
Block a user