Enhance Dashboard Navigation with New Modal Visibility Handling and Styling

- Introduced state management for modal visibility in the DashboardNavigation component to improve user interaction and layout responsiveness.
- Added new CSS styles for dashboard navigation elements, including transitions and layout adjustments for better visual clarity.
- Refactored the rendering logic to conditionally display navigation elements based on modal visibility, enhancing the overall user experience.
This commit is contained in:
Tom Butcher 2026-09-18 01:42:07 +01:00
parent c39051a891
commit 65417f75b8
2 changed files with 117 additions and 36 deletions

View File

@ -112,6 +112,42 @@
--webkit-user-select: none; --webkit-user-select: none;
} }
.dashboard-navigation-center {
position: relative;
flex: 1;
min-width: 0;
align-self: stretch;
display: flex;
align-items: center;
}
.dashboard-navigation-fade {
opacity: 1;
visibility: visible;
transition:
opacity 0.2s ease,
visibility 0.2s ease;
}
.dashboard-navigation-fade-hidden {
opacity: 0;
visibility: hidden;
pointer-events: none;
}
.dashboard-navigation-window-title {
position: absolute;
inset: 0;
display: flex;
align-items: center;
padding-left: 14px;
font-size: 14px;
pointer-events: none;
user-select: none;
-webkit-user-select: none;
border-bottom: 1px solid var(--color-header-border);
}
.electron-navigation-leading, .electron-navigation-leading,
.electron-navigation-trailing { .electron-navigation-trailing {
align-self: stretch; align-self: stretch;

View File

@ -216,6 +216,7 @@ const DashboardNavigation = () => {
: mainMenuItems.map((item) => ({ ...item, label: undefined })) : mainMenuItems.map((item) => ({ ...item, label: undefined }))
const [userPopoverOpen, setUserPopoverOpen] = useState(false) const [userPopoverOpen, setUserPopoverOpen] = useState(false)
const [anyModalVisible, setAnyModalVisible] = useState(false)
const userPopoverContent = ( const userPopoverContent = (
<UserProfilePopover onClose={() => setUserPopoverOpen(false)} /> <UserProfilePopover onClose={() => setUserPopoverOpen(false)} />
@ -255,7 +256,48 @@ const DashboardNavigation = () => {
const showDesktopLogo = !isElectron && !isMobile const showDesktopLogo = !isElectron && !isMobile
const showMobileLogo = !isElectron && isMobile const showMobileLogo = !isElectron && isMobile
const showControls = !isElectron || authenticated useEffect(() => {
const isModalWrapVisible = (node) => {
if (!(node instanceof Element)) return false
if (node.getAttribute('aria-hidden') === 'true') return false
const style = window.getComputedStyle(node)
return (
style.display !== 'none' &&
style.visibility !== 'hidden' &&
style.pointerEvents !== 'none'
)
}
const updateModalVisibility = () => {
const wraps = document.querySelectorAll('.ant-modal-wrap')
setAnyModalVisible(Array.from(wraps).some(isModalWrapVisible))
}
let frameId = 0
const scheduleUpdate = () => {
if (frameId) return
frameId = window.requestAnimationFrame(() => {
frameId = 0
updateModalVisibility()
})
}
updateModalVisibility()
const observer = new MutationObserver(scheduleUpdate)
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['style', 'class', 'aria-hidden']
})
return () => {
observer.disconnect()
if (frameId) window.cancelAnimationFrame(frameId)
}
}, [])
const showControls = (!isElectron || authenticated) && !anyModalVisible
const menu = ( const menu = (
<Menu <Menu
@ -434,28 +476,35 @@ const DashboardNavigation = () => {
</> </>
) )
const windowTitle = (
<Text
type='secondary'
className={`dashboard-navigation-window-title dashboard-navigation-fade${
showControls ? ' dashboard-navigation-fade-hidden' : ''
}`}
aria-hidden={showControls}
>
Farm Control
</Text>
)
const navigationContents = ( const navigationContents = (
<Flex style={{ width: '100%' }} align='center'> <Flex style={{ width: '100%' }} align='center'>
{navigationLeading} {navigationLeading}
<div style={{ flexGrow: 1, minWidth: 0 }}> <div className='dashboard-navigation-center'>
{showControls && !isMobile ? ( {!isMobile ? (
<Flex align='center' style={{ width: '100%', minWidth: 0 }}> <Flex
align='center'
className={`dashboard-navigation-fade${
showControls ? '' : ' dashboard-navigation-fade-hidden'
}`}
style={{ width: '100%', minWidth: 0 }}
aria-hidden={!showControls}
>
{menu} {menu}
</Flex> </Flex>
) : null} ) : null}
{!showControls && ( {windowTitle}
<Text
type='secondary'
style={{
fontSize: '14px',
marginLeft: '8px',
userSelect: 'none',
'--webkit-user-select': 'none'
}}
>
Farm Control
</Text>
)}
</div> </div>
{navigationTrailing} {navigationTrailing}
</Flex> </Flex>
@ -473,11 +522,7 @@ const DashboardNavigation = () => {
className={`electron-navigation-wrapper ${electronDragClass}`} className={`electron-navigation-wrapper ${electronDragClass}`}
style={{ lineHeight: '40px', padding: '0 2px 0 2px' }} style={{ lineHeight: '40px', padding: '0 2px 0 2px' }}
> >
<Flex <Flex align='center' className='electron-navigation-leading'>
align='center'
className='electron-navigation-leading'
style={{ flexGrow: !showControls ? 1 : 0 }}
>
{navigationLeading} {navigationLeading}
{showControls && !isMobile ? menu : null} {showControls && !isMobile ? menu : null}
{showControls && !isMobile ? ( {showControls && !isMobile ? (
@ -491,21 +536,21 @@ const DashboardNavigation = () => {
}} }}
/> />
) : null} ) : null}
{!showControls ? (
<Text
type='secondary'
style={{
fontSize: '14px',
marginLeft: '8px',
userSelect: 'none',
'--webkit-user-select': 'none'
}}
>
Farm Control
</Text>
) : null}
</Flex> </Flex>
{showControls && !isMobile ? <DashboardTabs /> : null} <div className='dashboard-navigation-center'>
{!isMobile ? (
<div
className={`dashboard-navigation-fade${
showControls ? '' : ' dashboard-navigation-fade-hidden'
}`}
style={{ flex: 1, minWidth: 0, display: 'flex' }}
aria-hidden={!showControls}
>
<DashboardTabs />
</div>
) : null}
{windowTitle}
</div>
<Flex align='center' className='electron-navigation-trailing'> <Flex align='center' className='electron-navigation-trailing'>
{navigationTrailing} {navigationTrailing}
</Flex> </Flex>