Enhance Dashboard Navigation and Settings with Show Navigation Labels Feature
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good

- Introduced a new setting for showNavigationLabels in the ThemeContext to manage the visibility of navigation labels.
- Updated the Settings component to allow users to toggle navigation labels and persist this setting.
- Modified the DashboardNavigation component to conditionally render navigation labels based on user preference.
- Adjusted App.css to improve styling for navigation items when labels are hidden.
This commit is contained in:
Tom Butcher 2026-08-22 20:32:20 +01:00
parent 3e86170e5c
commit 978f444538
4 changed files with 143 additions and 44 deletions

View File

@ -1734,3 +1734,7 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
border: 1px solid #000; border: 1px solid #000;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
} }
.no-navigation-labels.ant-menu-horizontal .ant-menu-item {
padding: 0 5px;
}

View File

@ -28,8 +28,15 @@ const engineLabel = (engine) => {
} }
const Settings = () => { const Settings = () => {
const { isDarkMode, isCompact, isSystem, setThemeMode, setDensityMode } = const {
useThemeContext() isDarkMode,
isCompact,
isSystem,
setThemeMode,
setDensityMode,
showNavigationLabels,
setShowNavigationLabels
} = useThemeContext()
const { fetchAppUpdateBranches } = useContext(ApiServerContext) const { fetchAppUpdateBranches } = useContext(ApiServerContext)
const { isElectron, getAppSettings, setAppSettings, getAppEngine } = const { isElectron, getAppSettings, setAppSettings, getAppEngine } =
useContext(ElectronContext) useContext(ElectronContext)
@ -77,11 +84,16 @@ const Settings = () => {
if (settingsLoading || isEditing) return if (settingsLoading || isEditing) return
if (appSettings.theme) setThemeMode(appSettings.theme) if (appSettings.theme) setThemeMode(appSettings.theme)
if (appSettings.density) setDensityMode(appSettings.density) if (appSettings.density) setDensityMode(appSettings.density)
if (appSettings.showNavigationLabels !== undefined) {
setShowNavigationLabels(appSettings.showNavigationLabels)
}
}, [ }, [
appSettings.density, appSettings.density,
appSettings.showNavigationLabels,
appSettings.theme, appSettings.theme,
isEditing, isEditing,
setDensityMode, setDensityMode,
setShowNavigationLabels,
setThemeMode, setThemeMode,
settingsLoading settingsLoading
]) ])
@ -137,6 +149,8 @@ const Settings = () => {
const currentThemeValue = getCurrentThemeValue() const currentThemeValue = getCurrentThemeValue()
const currentDensityValue = isCompact ? 'compact' : 'comfortable' const currentDensityValue = isCompact ? 'compact' : 'comfortable'
const currentShowNavigationLabels =
appSettings.showNavigationLabels ?? showNavigationLabels ?? false
const currentBranch = const currentBranch =
appSettings.appUpdateBranch || appSettings.appUpdateBranch ||
(branches.includes(DEFAULT_UPDATE_BRANCH) ? DEFAULT_UPDATE_BRANCH : null) || (branches.includes(DEFAULT_UPDATE_BRANCH) ? DEFAULT_UPDATE_BRANCH : null) ||
@ -154,7 +168,8 @@ const Settings = () => {
currentBranch === 'Not configured' ? undefined : currentBranch, currentBranch === 'Not configured' ? undefined : currentBranch,
appUpdateEngine: currentEngine, appUpdateEngine: currentEngine,
theme: currentThemeValue, theme: currentThemeValue,
density: currentDensityValue density: currentDensityValue,
showNavigationLabels: currentShowNavigationLabels
}) })
setIsEditing(true) setIsEditing(true)
} }
@ -175,6 +190,7 @@ const Settings = () => {
...appSettings, ...appSettings,
theme: draftSettings.theme, theme: draftSettings.theme,
density: draftSettings.density, density: draftSettings.density,
showNavigationLabels: Boolean(draftSettings.showNavigationLabels),
...(isElectron ...(isElectron
? { ? {
appUpdateBranch: draftSettings.appUpdateBranch, appUpdateBranch: draftSettings.appUpdateBranch,
@ -197,13 +213,15 @@ const Settings = () => {
settings: { settings: {
...(previous?.settings || {}), ...(previous?.settings || {}),
theme: draftSettings.theme, theme: draftSettings.theme,
density: draftSettings.density density: draftSettings.density,
showNavigationLabels: Boolean(draftSettings.showNavigationLabels)
} }
})) }))
} }
setThemeMode(draftSettings.theme) setThemeMode(draftSettings.theme)
setDensityMode(draftSettings.density) setDensityMode(draftSettings.density)
setShowNavigationLabels(draftSettings.showNavigationLabels)
setAppSettingsState(nextSettings) setAppSettingsState(nextSettings)
setDraftSettings(nextSettings) setDraftSettings(nextSettings)
setIsEditing(false) setIsEditing(false)
@ -311,6 +329,29 @@ const Settings = () => {
<Text>{isCompact ? 'Compact' : 'Comfortable'}</Text> <Text>{isCompact ? 'Compact' : 'Comfortable'}</Text>
)} )}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label='Navigation Labels'>
{isEditing ? (
<Select
value={
draftSettings.showNavigationLabels ? 'show' : 'hide'
}
onChange={(value) =>
setDraftSettings((previous) => ({
...previous,
showNavigationLabels: value === 'show'
}))
}
style={{ width: '100%' }}
>
<Option value='show'>Show</Option>
<Option value='hide'>Hide</Option>
</Select>
) : (
<Text>
{currentShowNavigationLabels ? 'Show' : 'Hide'}
</Text>
)}
</Descriptions.Item>
</Descriptions> </Descriptions>
</InfoCollapse> </InfoCollapse>
{isElectron && ( {isElectron && (

View File

@ -48,6 +48,7 @@ import {
} from '../../../database/Sidebars' } from '../../../database/Sidebars'
import { useAppUpdateContext } from '../context/AppUpdateContext' import { useAppUpdateContext } from '../context/AppUpdateContext'
import { useThemeContext } from '../context/ThemeContext'
const { Text } = Typography const { Text } = Typography
@ -56,6 +57,7 @@ const DashboardNavigation = () => {
const { showSpotlight } = useContext(SpotlightContext) const { showSpotlight } = useContext(SpotlightContext)
const { connecting, connected } = useContext(ApiServerContext) const { connecting, connected } = useContext(ApiServerContext)
const { authenticated } = useContext(AuthContext) const { authenticated } = useContext(AuthContext)
const { showNavigationLabels, setShowNavigationLabels } = useThemeContext()
const { toggleNotificationCenter, unreadCount } = const { toggleNotificationCenter, unreadCount } =
useContext(NotificationContext) useContext(NotificationContext)
const [apiServerState, setApiServerState] = useState('disconnected') const [apiServerState, setApiServerState] = useState('disconnected')
@ -71,50 +73,81 @@ const DashboardNavigation = () => {
const { const {
platform, platform,
isElectron, isElectron,
getAppSettings,
setSidebarViewMenu, setSidebarViewMenu,
isFullScreen, isFullScreen,
isMaximized isMaximized
} = useContext(ElectronContext) } = useContext(ElectronContext)
const { availableUpdate, checkForUpdates } = useAppUpdateContext() const { availableUpdate, checkForUpdates } = useAppUpdateContext()
useEffect(() => {
const hydrateNavigationLabels = async () => {
const settings = isElectron
? await getAppSettings()
: userProfile?.settings || {}
if (settings?.showNavigationLabels !== undefined) {
setShowNavigationLabels(settings.showNavigationLabels)
}
}
void hydrateNavigationLabels()
}, [
getAppSettings,
isElectron,
setShowNavigationLabels,
userProfile?.settings
])
const includeDev = import.meta.env.DEV const includeDev = import.meta.env.DEV
const mainMenuItems = useMemo( const mainMenuItems = useMemo(() => {
() => const iconStyles = {
[ fontSize: !showNavigationLabels ? '16px' : undefined,
{ marginLeft: !showNavigationLabels ? '10px' : undefined
key: 'production', }
label: 'Production', const navigationIcon = (icon, label) =>
className: 'electrobun-webkit-app-region-no-drag', showNavigationLabels ? (
icon: <ProductionIcon /> icon
}, ) : (
{ <Tooltip title={label} listenParents={1}>
key: 'inventory', {icon}
label: 'Inventory', </Tooltip>
className: 'electrobun-webkit-app-region-no-drag', )
icon: <InventoryIcon />
}, return [
{ {
key: 'sales', key: 'production',
label: 'Sales', label: 'Production',
className: 'electrobun-webkit-app-region-no-drag', className: 'electrobun-webkit-app-region-no-drag',
icon: <SalesIcon /> icon: navigationIcon(<ProductionIcon style={iconStyles} />, 'Production')
}, },
{ {
key: 'finance', key: 'inventory',
label: 'Finance', label: 'Inventory',
className: 'electrobun-webkit-app-region-no-drag', className: 'electrobun-webkit-app-region-no-drag',
icon: <FinanceIcon /> icon: navigationIcon(<InventoryIcon style={iconStyles} />, 'Inventory')
}, },
{ {
key: 'management', key: 'sales',
label: 'Management', label: 'Sales',
className: 'electrobun-webkit-app-region-no-drag', className: 'electrobun-webkit-app-region-no-drag',
icon: <SettingsIcon /> icon: navigationIcon(<SalesIcon style={iconStyles} />, 'Sales')
} },
].filter((item) => {
isSidebarSectionVisible(item.key, { includeDev, userProfile }) key: 'finance',
), label: 'Finance',
[includeDev, userProfile] className: 'electrobun-webkit-app-region-no-drag',
) icon: navigationIcon(<FinanceIcon style={iconStyles} />, 'Finance')
},
{
key: 'management',
label: 'Management',
className: 'electrobun-webkit-app-region-no-drag',
icon: navigationIcon(<SettingsIcon style={iconStyles} />, 'Management')
}
].filter((item) =>
isSidebarSectionVisible(item.key, { includeDev, userProfile })
)
}, [includeDev, showNavigationLabels, userProfile])
const [userPopoverOpen, setUserPopoverOpen] = useState(false) const [userPopoverOpen, setUserPopoverOpen] = useState(false)
@ -219,8 +252,12 @@ const DashboardNavigation = () => {
{showControls && ( {showControls && (
<Menu <Menu
mode='horizontal' mode='horizontal'
className={isElectron ? 'electron-navigation' : null} className={`${isElectron ? 'electron-navigation' : null} ${!showNavigationLabels ? 'no-navigation-labels' : ''}`}
items={mainMenuItems} items={
showNavigationLabels
? mainMenuItems
: mainMenuItems.map((item) => ({ ...item, label: undefined }))
}
style={{ style={{
flexWrap: 'wrap', flexWrap: 'wrap',
flexGrow: isMobile ? 0 : 1, flexGrow: isMobile ? 0 : 1,

View File

@ -39,6 +39,10 @@ export const ThemeProvider = ({ children }) => {
const savedCompact = sessionStorage.getItem('isCompact') const savedCompact = sessionStorage.getItem('isCompact')
return savedCompact ? JSON.parse(savedCompact) : false return savedCompact ? JSON.parse(savedCompact) : false
}) })
const [showNavigationLabels, setShowNavigationLabelsState] = useState(() => {
const savedLabels = sessionStorage.getItem('showNavigationLabels')
return savedLabels ? JSON.parse(savedLabels) : false
})
const [primaryColorOverride, setPrimaryColorOverride] = useState(null) const [primaryColorOverride, setPrimaryColorOverride] = useState(null)
@ -77,6 +81,13 @@ export const ThemeProvider = ({ children }) => {
sessionStorage.setItem('isCompact', JSON.stringify(isCompact)) sessionStorage.setItem('isCompact', JSON.stringify(isCompact))
}, [isCompact]) }, [isCompact])
useEffect(() => {
sessionStorage.setItem(
'showNavigationLabels',
JSON.stringify(showNavigationLabels)
)
}, [showNavigationLabels])
const toggleTheme = () => { const toggleTheme = () => {
if (isSystem) { if (isSystem) {
setIsSystem(false) setIsSystem(false)
@ -111,6 +122,10 @@ export const ThemeProvider = ({ children }) => {
setIsCompact(value === 'compact') setIsCompact(value === 'compact')
}, []) }, [])
const setShowNavigationLabels = useCallback((value) => {
setShowNavigationLabelsState(Boolean(value))
}, [])
const getThemeAlgorithm = () => { const getThemeAlgorithm = () => {
var baseAlgorithm var baseAlgorithm
if (isDarkMode == true) { if (isDarkMode == true) {
@ -191,6 +206,8 @@ export const ThemeProvider = ({ children }) => {
toggleSystem, toggleSystem,
setThemeMode, setThemeMode,
setDensityMode, setDensityMode,
showNavigationLabels,
setShowNavigationLabels,
getColors, getColors,
setPrimaryColorOverride, setPrimaryColorOverride,
themeConfig themeConfig