Enhance window management and navigation handling
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good

- Added `isFullscreen` context to `DashboardNavigation` for improved UI responsiveness.
- Updated navigation class logic to conditionally apply styles based on fullscreen state.
- Refined window control logic in `window.js` to handle maximize/unmaximize actions more reliably, including asynchronous state synchronization on Windows.
- Introduced adjustments for window frame dimensions in `windows-work-area.js` to account for Win32 DWM overhangs, ensuring accurate maximized state detection and clamping.
This commit is contained in:
Tom Butcher 2026-08-04 01:57:51 +01:00
parent eb1ee1e82b
commit d28bed7136
3 changed files with 43 additions and 8 deletions

View File

@ -64,7 +64,7 @@ const DashboardNavigation = () => {
icon: <ProductionIcon />
})
const isMobile = useMediaQuery({ maxWidth: 768 })
const { platform, isElectron, setSidebarViewMenu } =
const { platform, isElectron, setSidebarViewMenu, isFullscreen } =
useContext(ElectronContext)
const { availableUpdate, checkForUpdates } = useAppUpdateContext()
const mainMenuItems = useMemo(
@ -349,7 +349,7 @@ const DashboardNavigation = () => {
<>
{isElectron ? (
<Flex
className={`ant-menu-horizontal ant-menu-light${!notificationCenterVisible ? ' electron-navigation-wrapper electrobun-webkit-app-region-drag' : ''}`}
className={`ant-menu-horizontal ant-menu-light${!notificationCenterVisible && !isFullscreen ? ' electron-navigation-wrapper electrobun-webkit-app-region-drag' : ''}`}
style={{ lineHeight: '40px', padding: '0 2px 0 2px' }}
>
{navigationContents}

View File

@ -184,6 +184,8 @@ function applyWindowsStartupWindowState(window) {
setTimeout(() => {
window.maximize?.()
// maximize() settles asynchronously; sync state after the frame updates.
setTimeout(() => handleWindowsWindowChange(window), 100)
}, WINDOWS_STARTUP_MAXIMIZE_DELAY_MS)
}
@ -339,17 +341,23 @@ export function handleWindowControl(action) {
case 'minimize':
mainWindow.minimize?.()
break
case 'maximize':
if (mainWindow.isMaximized?.()) {
case 'maximize': {
const currentlyMaximized = isWindows
? isWindowWorkAreaMaximized(mainWindow)
: (mainWindow.isMaximized?.() ?? false)
if (currentlyMaximized) {
mainWindow.unmaximize?.()
} else {
mainWindow.maximize?.()
}
if (isWindows) {
handleWindowsWindowChange(mainWindow)
// Frame updates after maximize/unmaximize are async on Windows.
setTimeout(() => handleWindowsWindowChange(mainWindow), 100)
}
break
}
case 'fullscreen':
if (mainWindow.isFullScreen?.()) {
mainWindow.setFullScreen?.(false)

View File

@ -1,6 +1,15 @@
import { Screen } from 'electrobun/bun'
const FRAME_TOLERANCE_PX = 4
// Win32 DWM invisible borders sit outside the client work area; Electrobun's
// maximized frame includes those overhangs, so we treat this adjusted rect as
// the canonical "maximized to work area" geometry.
const WIN32_FRAME_OVERHANG = {
x: -8,
y: 0,
width: 16,
height: 8
}
function framesMatch(a, b, tolerance = FRAME_TOLERANCE_PX) {
return (
@ -11,6 +20,15 @@ function framesMatch(a, b, tolerance = FRAME_TOLERANCE_PX) {
)
}
function getMaximizedWorkAreaFrame(workArea) {
return {
x: workArea.x + WIN32_FRAME_OVERHANG.x,
y: workArea.y + WIN32_FRAME_OVERHANG.y,
width: workArea.width + WIN32_FRAME_OVERHANG.width,
height: workArea.height + WIN32_FRAME_OVERHANG.height
}
}
function getFrameCenter(frame) {
return {
x: frame.x + frame.width / 2,
@ -50,7 +68,10 @@ export function isWindowWorkAreaMaximized(window) {
const frame = window.getFrame()
const { workArea } = getDisplayForFrame(frame)
return framesMatch(frame, workArea)
return (
framesMatch(frame, workArea) ||
framesMatch(frame, getMaximizedWorkAreaFrame(workArea))
)
}
export function clampWindowToWorkArea(window) {
@ -69,8 +90,9 @@ export function clampWindowToWorkArea(window) {
const display = getDisplayForFrame(frame)
const { bounds, workArea } = display
const maximizedFrame = getMaximizedWorkAreaFrame(workArea)
if (framesMatch(frame, workArea)) {
if (framesMatch(frame, workArea) || framesMatch(frame, maximizedFrame)) {
return false
}
@ -78,6 +100,11 @@ export function clampWindowToWorkArea(window) {
return false
}
window.setFrame(workArea.x - 8, workArea.y, workArea.width + 16, workArea.height + 8)
window.setFrame(
maximizedFrame.x,
maximizedFrame.y,
maximizedFrame.width,
maximizedFrame.height
)
return true
}