All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Added MobileFooterNavigation component for improved navigation on mobile devices, featuring segmented navigation for key sections. - Updated DashboardLayout to conditionally render MobileFooterNavigation based on screen size. - Enhanced DashboardNavigation to dynamically adjust menu items based on mobile view, improving user experience. - Refactored CSS styles for mobile footer navigation to ensure proper layout and responsiveness. - Adjusted ObjectTable component to account for new mobile layout, ensuring consistent display across devices.
182 lines
5.3 KiB
JavaScript
182 lines
5.3 KiB
JavaScript
import {
|
|
cloneElement,
|
|
isValidElement,
|
|
useState,
|
|
useEffect,
|
|
useContext
|
|
} from 'react'
|
|
import { Layout, Menu, Flex, Button, Divider } from 'antd'
|
|
import CollapseSidebarIcon from '../../Icons/CollapseSidebarIcon'
|
|
import ExpandSidebarIcon from '../../Icons/ExpandSidebarIcon'
|
|
import { useMediaQuery } from 'react-responsive'
|
|
import { useNavigate } from 'react-router-dom'
|
|
import PropTypes from 'prop-types'
|
|
import { ElectronContext } from '../context/ElectronContext'
|
|
import { AuthContext } from '../context/AuthContext'
|
|
import { getSidebarIconNode } from '../../Icons/sidebarIconMap'
|
|
import SimpleBar from 'simplebar-react'
|
|
import { useThemeContext } from '../context/ThemeContext'
|
|
import { filterSidebarItemsByListPermission } from '../../../database/Sidebars'
|
|
import Tooltip from './Tooltip'
|
|
import KeyboardShortcut from './KeyboardShortcut'
|
|
const { Sider } = Layout
|
|
|
|
const CollapsedItemIcon = ({ className, icon, title }) => {
|
|
const iconNode = isValidElement(icon)
|
|
? cloneElement(icon, {
|
|
className: [icon.props.className, className].filter(Boolean).join(' ')
|
|
})
|
|
: icon
|
|
|
|
return (
|
|
<Tooltip title={title} listenParents={1}>
|
|
{iconNode ?? <span className={className} />}
|
|
</Tooltip>
|
|
)
|
|
}
|
|
|
|
CollapsedItemIcon.propTypes = {
|
|
className: PropTypes.string,
|
|
icon: PropTypes.node,
|
|
title: PropTypes.node
|
|
}
|
|
|
|
const DashboardSidebar = ({
|
|
items = [],
|
|
selectedKey = '',
|
|
onCollapse,
|
|
collapsed: collapsedProp,
|
|
collapsedWidth: collapsedWidthProp,
|
|
key = 'DashboardSidebar_collapseState'
|
|
}) => {
|
|
const [collapsed, setCollapsed] = useState(() => {
|
|
if (typeof collapsedProp === 'boolean') return collapsedProp
|
|
const savedState = sessionStorage.getItem(key)
|
|
return savedState ? JSON.parse(savedState) : false
|
|
})
|
|
const isMobile = useMediaQuery({ maxWidth: 768 })
|
|
const navigate = useNavigate()
|
|
const { isDarkMode } = useThemeContext()
|
|
const { isElectron } = useContext(ElectronContext)
|
|
const collapsedWidth = collapsedWidthProp ?? (isElectron ? 55 : 80)
|
|
const { userProfile } = useContext(AuthContext)
|
|
const allowedItems = filterSidebarItemsByListPermission(items, userProfile)
|
|
|
|
useEffect(() => {
|
|
if (typeof collapsedProp === 'boolean') {
|
|
setCollapsed(collapsedProp)
|
|
}
|
|
}, [collapsedProp])
|
|
|
|
const handleCollapse = (newCollapsed) => {
|
|
setCollapsed(newCollapsed)
|
|
sessionStorage.setItem(key, JSON.stringify(newCollapsed))
|
|
if (onCollapse) onCollapse(newCollapsed)
|
|
}
|
|
|
|
// Recursive function to map items and their children
|
|
const mapItemsRecursively = (items, showCollapsedTooltip = true) => {
|
|
return items.map((item) => {
|
|
if (item?.type === 'divider') {
|
|
return item
|
|
}
|
|
|
|
const icon = item.icon || getSidebarIconNode(item.iconKey)
|
|
const mappedItem = {
|
|
key: item.key,
|
|
icon:
|
|
collapsed && !isMobile && showCollapsedTooltip && !item.children ? (
|
|
<CollapsedItemIcon title={item.label} icon={icon} />
|
|
) : (
|
|
icon
|
|
),
|
|
label: item.label
|
|
}
|
|
|
|
// Add onClick for items with paths (leaf nodes)
|
|
if (item.path) {
|
|
mappedItem.onClick = () => navigate(item.path)
|
|
}
|
|
|
|
// Recursively map children if they exist
|
|
if (item?.children && Array.isArray(item.children)) {
|
|
mappedItem.children = mapItemsRecursively(item.children, false)
|
|
}
|
|
|
|
return mappedItem
|
|
})
|
|
}
|
|
|
|
// Map items recursively
|
|
const _items = mapItemsRecursively(allowedItems)
|
|
|
|
if (isMobile) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<Sider
|
|
width='100%'
|
|
collapsedWidth={collapsedWidth}
|
|
theme='light'
|
|
collapsed={collapsed}
|
|
className={`dashboard-sider${isElectron ? ' electron-sider' : ''}`}
|
|
style={{
|
|
'--dashboard-sidebar-collapsed-width': `${collapsedWidth}px`
|
|
}}
|
|
>
|
|
<Flex
|
|
style={{ height: '100%', minHeight: 0 }}
|
|
vertical
|
|
className='ant-menu-root ant-menu-inline ant-menu-light'
|
|
>
|
|
<SimpleBar
|
|
style={{ flexGrow: 1, minHeight: 0 }}
|
|
className={`sidebar-scroll ${isDarkMode ? 'dark' : 'light'}`}
|
|
>
|
|
<Menu
|
|
mode='inline'
|
|
selectedKeys={[selectedKey]}
|
|
items={_items}
|
|
className={isElectron ? 'electron-sidebar' : null}
|
|
style={{ flexGrow: 1, border: 'none' }}
|
|
_internalDisableMenuItemTitleTooltip
|
|
/>
|
|
</SimpleBar>
|
|
|
|
<Flex vertical style={{ width: '100%' }}>
|
|
<Divider style={{ margin: 0 }} />
|
|
<Flex style={{ padding: '4px', width: '100%' }}>
|
|
<KeyboardShortcut
|
|
shortcut='alt+shift+s'
|
|
hint='ALT ⇧ S'
|
|
onTrigger={() => handleCollapse(!collapsed)}
|
|
>
|
|
<Button
|
|
size={isElectron ? 'middle' : 'large'}
|
|
type='text'
|
|
icon={
|
|
collapsed ? <ExpandSidebarIcon /> : <CollapseSidebarIcon />
|
|
}
|
|
style={{ flexGrow: 1, width: '100%' }}
|
|
onClick={() => handleCollapse(!collapsed)}
|
|
/>
|
|
</KeyboardShortcut>
|
|
</Flex>
|
|
</Flex>
|
|
</Flex>
|
|
</Sider>
|
|
)
|
|
}
|
|
|
|
DashboardSidebar.propTypes = {
|
|
items: PropTypes.array.isRequired,
|
|
selectedKey: PropTypes.string,
|
|
onCollapse: PropTypes.func,
|
|
collapsed: PropTypes.bool,
|
|
collapsedWidth: PropTypes.number,
|
|
key: PropTypes.string
|
|
}
|
|
|
|
export default DashboardSidebar
|