mirror of
https://github.com/NanmiCoder/claude-code-haha.git
synced 2026-10-10 11:53:10 +08:00
fix(desktop): keep the window gutter on the panel paper
With the workspace panel open, the titlebar's right section was paper right up to a 16px notch of sidebar grey welded to the window's top-right corner. The paper was painted by the window header, but the drag gutter — and, on Windows, the window controls — are its transparent siblings inside the same frame, so whatever their parent showed came through. Closed, that is invisible: the whole strip is the sidebar's ground and the gutter just continues it. Open, it is a strip of trough next to a white panel. The frame now owns the ground for everything above the panel, so the header, the gutter and the native controls share one surface.
This commit is contained in:
@@ -1545,6 +1545,51 @@ describe('TabBar', () => {
|
||||
expect(tab).not.toHaveAttribute('data-desktop-drag-region')
|
||||
})
|
||||
|
||||
it('keeps the window gutter on the panel paper while the workspace is open', async () => {
|
||||
const { TabBar } = await import('./TabBar')
|
||||
const { useTabStore } = await import('../../stores/tabStore')
|
||||
const { useChatStore } = await import('../../stores/chatStore')
|
||||
const { useWorkspaceStore } = await import('../../stores/workspaceStore')
|
||||
// Imported here, not at the top of the file: `vi.resetModules()` hands the
|
||||
// strip a fresh provider module, and a statically imported one would be a
|
||||
// second React context that the strip can never see.
|
||||
const { WorkspaceHeaderProvider } = await import('./WorkspaceHeaderContext')
|
||||
const sessionId = 'gutter-session'
|
||||
|
||||
useTabStore.setState({
|
||||
tabs: [{ sessionId, title: 'Gutter session', type: 'session', status: 'idle' }],
|
||||
activeTabId: sessionId,
|
||||
})
|
||||
useChatStore.setState({
|
||||
sessions: {},
|
||||
disconnectSession: vi.fn(),
|
||||
} as Partial<ReturnType<typeof useChatStore.getState>>)
|
||||
|
||||
await act(async () => {
|
||||
// The window owns the header slot; without it the strip falls back to
|
||||
// the dock and there is no header frame to paint.
|
||||
render(<WorkspaceHeaderProvider><TabBar /></WorkspaceHeaderProvider>)
|
||||
})
|
||||
|
||||
const frame = screen.getByTestId('workspace-header-frame')
|
||||
const gutter = screen.getByTestId('tab-bar-drag-gutter')
|
||||
|
||||
// Closed, the trough runs to the window edge and the gutter disappears
|
||||
// into it. Painting the frame unconditionally would paste a white block
|
||||
// over the end of the strip instead.
|
||||
expect(frame).not.toHaveClass('bg-[var(--color-surface)]')
|
||||
|
||||
// Open, everything above the panel is one ground. The gutter is a
|
||||
// transparent sibling of the header, so whichever element paints paper has
|
||||
// to contain it — otherwise the trough shows through the strip and the
|
||||
// window's top-right corner carries a grey notch beside the panel.
|
||||
await act(async () => {
|
||||
useWorkspaceStore.getState().toggleWorkspace(sessionId)
|
||||
})
|
||||
expect(frame).toHaveClass('bg-[var(--color-surface)]')
|
||||
expect(frame).toContainElement(gutter)
|
||||
})
|
||||
|
||||
it('lifts the active tab onto the paper ground without turning it into a pill', async () => {
|
||||
const { TabBar } = await import('./TabBar')
|
||||
const { useTabStore } = await import('../../stores/tabStore')
|
||||
|
||||
@@ -621,15 +621,23 @@ export function TabBar() {
|
||||
against paper, it all but disappears on the trough (1.12:1 on 素白),
|
||||
which left the toolbar looking welded to the last tab.
|
||||
*/}
|
||||
/*
|
||||
The frame owns the paper, not the header inside it. The drag gutter —
|
||||
and, on Windows, the window controls — are the header's siblings in
|
||||
here, and they are transparent: while the workspace is closed that is
|
||||
invisible, because the whole strip is the sidebar's ground. Next to an
|
||||
open panel it showed as a 16px strip of trough welded to the window's
|
||||
top-right corner. One ground for everything above the panel.
|
||||
*/
|
||||
<div
|
||||
data-testid="workspace-header-frame"
|
||||
style={hasWorkspaceHeader ? { width: workspaceHeader.width, maxWidth: '100%' } : undefined}
|
||||
className="flex min-w-0 shrink-0 items-stretch"
|
||||
className={`flex min-w-0 shrink-0 items-stretch ${hasWorkspaceHeader ? 'bg-[var(--color-surface)]' : ''}`}
|
||||
>
|
||||
<div
|
||||
data-testid="workspace-window-header"
|
||||
className={hasWorkspaceHeader
|
||||
? 'flex min-w-0 flex-1 items-center gap-1 bg-[var(--color-surface)] pr-2'
|
||||
? 'flex min-w-0 flex-1 items-center gap-1 pr-2'
|
||||
: 'relative flex shrink-0 items-center gap-1 px-2 before:absolute before:left-0 before:top-1/2 before:h-4 before:w-px before:-translate-y-1/2 before:bg-[var(--color-tab-separator)]'}
|
||||
>
|
||||
{hasWorkspaceHeader ? <div ref={workspaceHeader.ref} data-testid="workspace-header-slot" className="tab-bar-interactive flex h-[52px] min-w-0 flex-1" /> : null}
|
||||
|
||||
Reference in New Issue
Block a user