diff --git a/src/frontend/src/layout/Header.tsx b/src/frontend/src/layout/Header.tsx index 25eae694..2fe8348d 100644 --- a/src/frontend/src/layout/Header.tsx +++ b/src/frontend/src/layout/Header.tsx @@ -2,11 +2,13 @@ import { Link } from 'wouter' import { css } from '@/styled-system/css' import { Stack } from '@/styled-system/jsx' import { useTranslation } from 'react-i18next' -import { A, Button, Popover, PopoverList, Text } from '@/primitives' +import { A, Text, Button } from '@/primitives' import { SettingsButton } from '@/features/settings' import { authUrl, logoutUrl, useUser } from '@/features/auth' import { useMatchesRoute } from '@/navigation/useMatchesRoute' import { Feedback } from '@/components/Feedback' +import { Menu } from '@/primitives/Menu' +import { MenuList } from '@/primitives/MenuList' export const Header = () => { const { t } = useTranslation() @@ -64,7 +66,7 @@ export const Header = () => { {t('login')} )} {!!user && ( - + - { if (value === 'logout') { window.location.href = logoutUrl() } }} /> - + )} diff --git a/src/frontend/src/primitives/Menu.tsx b/src/frontend/src/primitives/Menu.tsx new file mode 100644 index 00000000..d26765e9 --- /dev/null +++ b/src/frontend/src/primitives/Menu.tsx @@ -0,0 +1,25 @@ +import { ReactNode } from 'react' +import { MenuTrigger } from 'react-aria-components' +import { StyledPopover } from './Popover' +import { Box } from './Box' + +/** + * a Menu is a tuple of a trigger component (most usually a Button) that toggles menu items in a tooltip around the trigger + */ +export const Menu = ({ + children, +}: { + children: [trigger: ReactNode, menu: ReactNode] +}) => { + const [trigger, menu] = children + return ( + + {trigger} + + + {menu} + + + + ) +} diff --git a/src/frontend/src/primitives/MenuList.tsx b/src/frontend/src/primitives/MenuList.tsx new file mode 100644 index 00000000..c35d76bb --- /dev/null +++ b/src/frontend/src/primitives/MenuList.tsx @@ -0,0 +1,44 @@ +import { ReactNode } from 'react' +import { Menu, MenuProps, MenuItem as RACMenuItem } from 'react-aria-components' +import { styled } from '@/styled-system/jsx' +import { menuItemStyles } from './menuItemStyles' + +const MenuItem = styled(RACMenuItem, menuItemStyles) + +/** + * render a Button primitive that shows a popover showing a list of pressable items + */ +export const MenuList = ({ + onAction, + selectedItem, + items = [], + ...menuProps +}: { + onAction: (key: T) => void + selectedItem?: T + items: Array +} & MenuProps) => { + return ( + + {items.map((item) => { + const value = typeof item === 'string' ? item : item.value + const label = typeof item === 'string' ? item : item.label + return ( + { + onAction(value as T) + }} + > + {label} + + ) + })} + + ) +} diff --git a/src/frontend/src/primitives/Popover.tsx b/src/frontend/src/primitives/Popover.tsx index e50462ab..c0863a15 100644 --- a/src/frontend/src/primitives/Popover.tsx +++ b/src/frontend/src/primitives/Popover.tsx @@ -49,7 +49,10 @@ const StyledOverlayArrow = styled(OverlayArrow, { }) /** - * a Popover is a tuple of a trigger component (most usually a Button) that toggles some interactive content in a tooltip around the trigger + * a Popover is a tuple of a trigger component (most usually a Button) that toggles some content in a tooltip around the trigger + * + * Note: to show a list of actionable items, like a dropdown menu, prefer using a or