All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Added a new `logo` prop to the `MenuButton` component to conditionally adjust padding and margin based on the presence of a logo. - Updated the `MenuButton` prop types to include the new `logo` boolean, improving flexibility in rendering menu items with logos.
260 lines
6.3 KiB
JavaScript
260 lines
6.3 KiB
JavaScript
import { useContext, useMemo } from 'react'
|
|
import PropTypes from 'prop-types'
|
|
import { Button, Dropdown, Flex } from 'antd'
|
|
import { useNavigate } from 'react-router-dom'
|
|
import { ElectronContext } from '../context/ElectronContext'
|
|
import { useAppUpdateContext } from '../context/AppUpdateContext'
|
|
import { getSidebarMenuSections } from '../../../database/Sidebars'
|
|
import FarmControlLogoSmall from '../../Logos/FarmControlLogoSmall'
|
|
|
|
const runEditCommand = (command) => {
|
|
try {
|
|
document.execCommand(command)
|
|
} catch (error) {
|
|
console.warn(
|
|
`[WindowAppMenu] Failed to run edit command: ${command}`,
|
|
error
|
|
)
|
|
}
|
|
}
|
|
|
|
const mapSidebarItemsToMenuItems = (items = [], navigate) =>
|
|
items
|
|
.map((item, index) => {
|
|
if (item?.type === 'divider') {
|
|
return { type: 'divider', key: `divider-${index}` }
|
|
}
|
|
|
|
if (item?.children?.length) {
|
|
return {
|
|
key: item.key || `group-${item.label}-${index}`,
|
|
label: item.label,
|
|
children: mapSidebarItemsToMenuItems(item.children, navigate)
|
|
}
|
|
}
|
|
|
|
if (item?.path) {
|
|
return {
|
|
key: item.path,
|
|
label: item.label,
|
|
onClick: () => navigate(item.path)
|
|
}
|
|
}
|
|
|
|
return {
|
|
key: item.key || `disabled-${item.label}-${index}`,
|
|
label: item.label,
|
|
disabled: true
|
|
}
|
|
})
|
|
.filter(Boolean)
|
|
|
|
const MenuButton = ({ label, items, logo }) => (
|
|
<Dropdown menu={{ items }} trigger={['click']} placement='bottomLeft'>
|
|
<Button
|
|
type='text'
|
|
size='small'
|
|
className='electrobun-webkit-app-region-no-drag'
|
|
style={{
|
|
height: '28px',
|
|
paddingInline: logo ? '6px' : '8px',
|
|
marginRight: logo ? '1px' : '0',
|
|
fontWeight: 500
|
|
}}
|
|
>
|
|
{label}
|
|
</Button>
|
|
</Dropdown>
|
|
)
|
|
|
|
MenuButton.propTypes = {
|
|
label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
|
|
items: PropTypes.array.isRequired,
|
|
logo: PropTypes.bool
|
|
}
|
|
|
|
const WindowAppMenu = () => {
|
|
const navigate = useNavigate()
|
|
const { handleWindowControl } = useContext(ElectronContext)
|
|
const { checkForUpdates } = useAppUpdateContext()
|
|
const includeDev = import.meta.env.DEV
|
|
|
|
const viewSections = useMemo(
|
|
() => getSidebarMenuSections({ includeDev }),
|
|
[includeDev]
|
|
)
|
|
|
|
const appMenuItems = useMemo(
|
|
() => [
|
|
{
|
|
key: 'about',
|
|
label: 'About Farm Control',
|
|
onClick: () => navigate('/dashboard/management/about')
|
|
},
|
|
{ type: 'divider' },
|
|
{
|
|
key: 'check-for-updates',
|
|
label: 'Check For Updates...',
|
|
onClick: () => checkForUpdates()
|
|
},
|
|
{ type: 'divider' },
|
|
{
|
|
key: 'quit',
|
|
label: 'Quit Farm Control',
|
|
onClick: () => handleWindowControl('quit')
|
|
}
|
|
],
|
|
[checkForUpdates, handleWindowControl, navigate]
|
|
)
|
|
|
|
const fileMenuItems = useMemo(
|
|
() => [
|
|
{
|
|
key: 'close',
|
|
label: 'Close Window',
|
|
onClick: () => handleWindowControl('close')
|
|
}
|
|
],
|
|
[handleWindowControl]
|
|
)
|
|
|
|
const editMenuItems = useMemo(
|
|
() => [
|
|
{
|
|
key: 'undo',
|
|
label: 'Undo',
|
|
onClick: () => runEditCommand('undo')
|
|
},
|
|
{
|
|
key: 'redo',
|
|
label: 'Redo',
|
|
onClick: () => runEditCommand('redo')
|
|
},
|
|
{ type: 'divider' },
|
|
{
|
|
key: 'cut',
|
|
label: 'Cut',
|
|
onClick: () => runEditCommand('cut')
|
|
},
|
|
{
|
|
key: 'copy',
|
|
label: 'Copy',
|
|
onClick: () => runEditCommand('copy')
|
|
},
|
|
{
|
|
key: 'paste',
|
|
label: 'Paste',
|
|
onClick: () => runEditCommand('paste')
|
|
},
|
|
{
|
|
key: 'pasteAndMatchStyle',
|
|
label: 'Paste and Match Style',
|
|
onClick: () => runEditCommand('paste')
|
|
},
|
|
{
|
|
key: 'delete',
|
|
label: 'Delete',
|
|
onClick: () => runEditCommand('delete')
|
|
},
|
|
{ type: 'divider' },
|
|
{
|
|
key: 'selectAll',
|
|
label: 'Select All',
|
|
onClick: () => runEditCommand('selectAll')
|
|
}
|
|
],
|
|
[]
|
|
)
|
|
|
|
const viewMenuItems = useMemo(() => {
|
|
const sectionItems =
|
|
viewSections.length > 0
|
|
? viewSections.map((section) => ({
|
|
key: `view-section-${section.key}`,
|
|
label: section.label,
|
|
children: mapSidebarItemsToMenuItems(section.items || [], navigate)
|
|
}))
|
|
: [
|
|
{
|
|
key: 'no-sidebar-items',
|
|
label: 'No sidebar items available',
|
|
disabled: true
|
|
}
|
|
]
|
|
|
|
if (!includeDev) {
|
|
return sectionItems
|
|
}
|
|
|
|
return [
|
|
...sectionItems,
|
|
{ type: 'divider' },
|
|
{
|
|
key: 'toggle-devtools',
|
|
label: 'Toggle Developer Tools',
|
|
onClick: () => handleWindowControl('toggle-devtools')
|
|
}
|
|
]
|
|
}, [handleWindowControl, includeDev, navigate, viewSections])
|
|
|
|
const windowMenuItems = useMemo(
|
|
() => [
|
|
{
|
|
key: 'minimize',
|
|
label: 'Minimize',
|
|
onClick: () => handleWindowControl('minimize')
|
|
},
|
|
{
|
|
key: 'zoom',
|
|
label: 'Zoom',
|
|
onClick: () => handleWindowControl('maximize')
|
|
}
|
|
],
|
|
[handleWindowControl]
|
|
)
|
|
|
|
const menus = useMemo(
|
|
() => [
|
|
{ key: 'app', label: 'Farm Control', items: appMenuItems },
|
|
{ key: 'file', label: 'File', items: fileMenuItems },
|
|
{ key: 'edit', label: 'Edit', items: editMenuItems },
|
|
{ key: 'view', label: 'View', items: viewMenuItems },
|
|
{ key: 'window', label: 'Window', items: windowMenuItems }
|
|
],
|
|
[appMenuItems, editMenuItems, fileMenuItems, viewMenuItems, windowMenuItems]
|
|
)
|
|
|
|
return (
|
|
<Flex
|
|
align='center'
|
|
className='electrobun-webkit-app-region-no-drag'
|
|
style={{ marginRight: '8px', flexShrink: 0, marginLeft: '4px' }}
|
|
>
|
|
{menus.map((menu) => {
|
|
if (menu.key === 'app') {
|
|
return (
|
|
<MenuButton
|
|
key={menu.key}
|
|
logo={true}
|
|
label={
|
|
<FarmControlLogoSmall
|
|
style={{
|
|
fontSize: '46px',
|
|
height: '16px'
|
|
}}
|
|
/>
|
|
}
|
|
items={menu.items}
|
|
/>
|
|
)
|
|
}
|
|
return (
|
|
<MenuButton key={menu.key} label={menu.label} items={menu.items} />
|
|
)
|
|
})}
|
|
</Flex>
|
|
)
|
|
}
|
|
|
|
export default WindowAppMenu
|