fix: constrain floating terminal to titlebar (#1955)
This commit is contained in:
parent
e42c78107c
commit
69700466e9
|
|
@ -0,0 +1,61 @@
|
|||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
TITLEBAR_SAFE_TOP,
|
||||
clampFloatingTerminalBounds,
|
||||
getDefaultFloatingTerminalBounds,
|
||||
getMaximizedFloatingTerminalBounds
|
||||
} from './floating-terminal-panel-bounds'
|
||||
|
||||
function stubViewport(width: number, height: number, userAgent: string): void {
|
||||
vi.stubGlobal('window', { innerWidth: width, innerHeight: height })
|
||||
vi.stubGlobal('navigator', { userAgent })
|
||||
}
|
||||
|
||||
describe('floating terminal panel bounds', () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals()
|
||||
})
|
||||
|
||||
it('lets dragged panels touch the macOS titlebar without going above it', () => {
|
||||
stubViewport(1200, 800, 'Macintosh')
|
||||
|
||||
const bounds = clampFloatingTerminalBounds({
|
||||
left: 32,
|
||||
top: 8,
|
||||
width: 640,
|
||||
height: 360
|
||||
})
|
||||
|
||||
expect(bounds.top).toBe(TITLEBAR_SAFE_TOP)
|
||||
})
|
||||
|
||||
it('keeps dragged panels below the renderer titlebar on other platforms', () => {
|
||||
stubViewport(1200, 800, 'Windows NT')
|
||||
|
||||
const bounds = clampFloatingTerminalBounds({
|
||||
left: 32,
|
||||
top: 8,
|
||||
width: 640,
|
||||
height: 360
|
||||
})
|
||||
|
||||
expect(bounds.top).toBe(TITLEBAR_SAFE_TOP)
|
||||
})
|
||||
|
||||
it('maximizes below the renderer titlebar on non-mac platforms', () => {
|
||||
stubViewport(1200, 800, 'Windows NT')
|
||||
|
||||
expect(getMaximizedFloatingTerminalBounds()).toEqual(
|
||||
expect.objectContaining({
|
||||
top: TITLEBAR_SAFE_TOP,
|
||||
height: 800 - TITLEBAR_SAFE_TOP - 36
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('defaults at or below the titlebar on compact macOS windows', () => {
|
||||
stubViewport(760, 420, 'Macintosh')
|
||||
|
||||
expect(getDefaultFloatingTerminalBounds().top).toBeGreaterThanOrEqual(TITLEBAR_SAFE_TOP)
|
||||
})
|
||||
})
|
||||
|
|
@ -4,7 +4,7 @@ export const MIN_PANEL_WIDTH = 420
|
|||
export const MIN_PANEL_HEIGHT = 280
|
||||
export const MAXIMIZED_MARGIN = 12
|
||||
export const MAXIMIZED_BOTTOM_GAP = 36
|
||||
export const MAC_TITLEBAR_SAFE_TOP = 44
|
||||
export const TITLEBAR_SAFE_TOP = 36
|
||||
const DEFAULT_RIGHT_GAP = 24
|
||||
const DEFAULT_BOTTOM_GAP = 84
|
||||
|
||||
|
|
@ -18,11 +18,14 @@ export type FloatingTerminalPanelBounds = {
|
|||
export function getDefaultFloatingTerminalBounds(): FloatingTerminalPanelBounds {
|
||||
const viewportWidth = typeof window === 'undefined' ? 1200 : window.innerWidth
|
||||
const viewportHeight = typeof window === 'undefined' ? 800 : window.innerHeight
|
||||
// Why: the floating panel may touch the renderer titlebar, but must not
|
||||
// overlap it or the native window controls above it.
|
||||
const safeTop = TITLEBAR_SAFE_TOP
|
||||
const width = Math.min(DEFAULT_PANEL_WIDTH, Math.max(MIN_PANEL_WIDTH, viewportWidth - 48))
|
||||
const height = Math.min(DEFAULT_PANEL_HEIGHT, Math.max(MIN_PANEL_HEIGHT, viewportHeight - 96))
|
||||
return {
|
||||
left: Math.max(16, viewportWidth - width - DEFAULT_RIGHT_GAP),
|
||||
top: Math.max(40, viewportHeight - height - DEFAULT_BOTTOM_GAP),
|
||||
top: Math.max(safeTop, viewportHeight - height - DEFAULT_BOTTOM_GAP),
|
||||
width,
|
||||
height
|
||||
}
|
||||
|
|
@ -35,20 +38,18 @@ export function clampFloatingTerminalBounds(
|
|||
typeof window === 'undefined' ? bounds.left + bounds.width : window.innerWidth
|
||||
const viewportHeight =
|
||||
typeof window === 'undefined' ? bounds.top + bounds.height : window.innerHeight
|
||||
const safeTop = TITLEBAR_SAFE_TOP
|
||||
return {
|
||||
...bounds,
|
||||
left: Math.min(Math.max(8, bounds.left), Math.max(8, viewportWidth - 80)),
|
||||
top: Math.min(Math.max(8, bounds.top), Math.max(8, viewportHeight - 80))
|
||||
top: Math.min(Math.max(safeTop, bounds.top), Math.max(safeTop, viewportHeight - 80))
|
||||
}
|
||||
}
|
||||
|
||||
export function getMaximizedFloatingTerminalBounds(): FloatingTerminalPanelBounds {
|
||||
const viewportWidth = typeof window === 'undefined' ? 1200 : window.innerWidth
|
||||
const viewportHeight = typeof window === 'undefined' ? 800 : window.innerHeight
|
||||
const top =
|
||||
typeof navigator !== 'undefined' && navigator.userAgent.includes('Mac')
|
||||
? MAC_TITLEBAR_SAFE_TOP
|
||||
: MAXIMIZED_MARGIN
|
||||
const top = TITLEBAR_SAFE_TOP
|
||||
return {
|
||||
left: MAXIMIZED_MARGIN,
|
||||
top,
|
||||
|
|
|
|||
Loading…
Reference in New Issue