Files
goodbuddy/src/renderer/src/ApplicationMenu.tsx
T
mesalogo 8650907b75 fix: distinguish Apps and Settings in the sidebar footer
Keep the horizontal footer layout with visible labels, matching button heights, a subtle divider, and an Apps dropdown indicator. Use a layout icon for Manage Apps so it is distinct from global Settings.

Release note: Make the bottom-left Apps and Settings entries easier to distinguish with labeled buttons and separate visual boundaries.
2026-09-28 18:08:52 +08:00

43 lines
2.0 KiB
TypeScript

import { useMemo, type RefObject } from 'react'
import { LayoutGrid } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { defaultApplicationNavigation, type ApplicationSettings, type BuiltInApplicationId } from '../../shared/application-settings-contracts'
import { applicationDefinitions, isApplicationEnabled } from './ApplicationCenter'
import { AnchoredMenu } from './AnchoredMenu'
export function ApplicationMenu({ anchorRef, settings, pending, error, onClose, onOpen, onManage, onRetry }: {
anchorRef: RefObject<HTMLButtonElement | null>
settings?: ApplicationSettings
pending: boolean
error?: string
onClose: () => void
onOpen: (id: BuiltInApplicationId) => void
onManage: () => void
onRetry: () => void
}): React.JSX.Element {
const { t } = useTranslation('app')
const applications = useMemo(() => {
const order = (settings?.applicationNavigation ?? defaultApplicationNavigation).order
return order
.filter(id => isApplicationEnabled(settings, id))
}, [settings])
return <AnchoredMenu anchorRef={anchorRef} id="application-menu" label={t('applications.title')} onClose={onClose}>
{pending && <p role="status">{t('route.loading')}</p>}
{error && <>
<p role="alert">{error}</p>
<button type="button" role="menuitem" tabIndex={-1} disabled={pending} onClick={onRetry}>{t('applications.retry')}</button>
</>}
{applications.map(id => {
const definition = applicationDefinitions[id]
const Icon = definition.icon
return <button key={id} type="button" role="menuitem" tabIndex={-1} onClick={() => { onClose(); onOpen(id) }}>
<Icon size={16} aria-hidden="true" /><span>{t(definition.title)}</span>
</button>
})}
<div role="separator" />
<button type="button" role="menuitem" tabIndex={-1} onClick={() => { onClose(); anchorRef.current?.focus(); onManage() }}>
<LayoutGrid size={16} aria-hidden="true" /><span>{t('applications.manage')}</span>
</button>
</AnchoredMenu>
}