diff --git a/web/components/menu.css b/web/components/menu.css index 453ec1417..ff732c5ce 100644 --- a/web/components/menu.css +++ b/web/components/menu.css @@ -1,96 +1,105 @@ button.menuButton { background-color: transparent; border: none; cursor: pointer; color: inherit; } div.menuActionList { position: absolute; z-index: 4; display: flex; flex-direction: column; background-color: var(--menu-bg); color: var(--menu-color); stroke: var(--menu-color); border-radius: 4px; padding: 4px 0; line-height: var(--line-height-text); min-width: max-content; } div.menuActionListThreadActions { font-size: var(--m-font-16); top: 40px; right: -20px; } div.menuActionListMemberActions { font-size: var(--xs-font-12); background-color: var(--menu-bg-light); color: var(--menu-color-light); stroke: var(--menu-color-light); top: 0; right: 5px; } div.menuActionListCommunityActions { font-size: var(--m-font-16); background-color: var(--menu-bg-light); color: var(--menu-color); stroke: var(--menu-color); top: 24px; } div.menuActionListRoleActions { font-size: var(--s-font-14); background-color: var(--menu-bg-light); color: var(--menu-color); stroke: var(--menu-color); margin-top: 20px; } +div.userProfileActions { + font-size: var(--s-font-14); + background-color: var(--menu-bg-light); + color: var(--menu-color); + stroke: var(--menu-color); + top: 24px; + right: -16px; +} + button.menuAction { color: inherit; z-index: 1; padding: 12px 16px; line-height: 1.5; font-size: inherit; justify-content: start; } button.menuAction:hover { color: var(--menu-color-hover); stroke: var(--menu-color-hover); } div.menuActionIcon { display: flex; justify-content: center; align-items: center; margin-right: 8px; height: 24px; width: 24px; } div.menuActionListMemberActions div.menuActionIcon { height: 18px; width: 18px; } button.menuActionDangerous { color: var(--menu-color-dangerous); stroke: var(--menu-color-dangerous); } button.menuActionDangerous:hover { color: var(--menu-color-dangerous-hover); stroke: var(--menu-color-dangerous-hover); } hr.separator { height: 1px; background: var(--menu-separator-color); margin: 10px 16px; max-width: 130px; border: none; } diff --git a/web/components/menu.react.js b/web/components/menu.react.js index a000ef8d6..90ff25b8f 100644 --- a/web/components/menu.react.js +++ b/web/components/menu.react.js @@ -1,126 +1,128 @@ // @flow import classnames from 'classnames'; import * as React from 'react'; import css from './menu.css'; import { useRenderMenu } from '../menu-provider.react.js'; type MenuVariant = | 'thread-actions' | 'member-actions' | 'community-actions' - | 'role-actions'; + | 'role-actions' + | 'user-profile'; type MenuProps = { +icon: React.Node, +children?: React.Node, +variant?: MenuVariant, +onChange?: boolean => void, }; function Menu(props: MenuProps): React.Node { const buttonRef = React.useRef(); const { renderMenu, setMenuPosition, closeMenu, setCurrentOpenMenu, currentOpenMenu, } = useRenderMenu(); const { icon, children, variant = 'thread-actions', onChange } = props; const ourSymbol = React.useRef(Symbol()); const menuActionListClasses = classnames(css.menuActionList, { [css.menuActionListThreadActions]: variant === 'thread-actions', [css.menuActionListMemberActions]: variant === 'member-actions', [css.menuActionListCommunityActions]: variant === 'community-actions', [css.menuActionListRoleActions]: variant === 'role-actions', + [css.userProfileActions]: variant === 'user-profile', }); const menuActionList = React.useMemo( () =>
{children}
, [children, menuActionListClasses], ); const isOurMenuOpen = currentOpenMenu === ourSymbol.current; const updatePosition = React.useCallback(() => { if (buttonRef.current && isOurMenuOpen) { const { top, left } = buttonRef.current.getBoundingClientRect(); setMenuPosition({ top, left }); } }, [isOurMenuOpen, setMenuPosition]); React.useEffect(() => { if (!window) { return undefined; } window.addEventListener('resize', updatePosition); return () => window.removeEventListener('resize', updatePosition); }, [updatePosition]); React.useEffect(updatePosition, [updatePosition]); const closeMenuCallback = React.useCallback(() => { closeMenu(ourSymbol.current); }, [closeMenu]); React.useEffect(() => { onChange?.(isOurMenuOpen); }, [isOurMenuOpen, onChange]); React.useEffect(() => { if (!isOurMenuOpen) { return undefined; } document.addEventListener('click', closeMenuCallback); return () => { document.removeEventListener('click', closeMenuCallback); }; }, [closeMenuCallback, isOurMenuOpen]); const prevActionListRef = React.useRef(null); React.useEffect(() => { if (!isOurMenuOpen) { prevActionListRef.current = null; return; } if (prevActionListRef.current === menuActionList) { return; } renderMenu(menuActionList); prevActionListRef.current = menuActionList; }, [isOurMenuOpen, menuActionList, renderMenu]); React.useEffect(() => { const ourSymbolValue = ourSymbol.current; return () => closeMenu(ourSymbolValue); }, [closeMenu]); const onClickMenuCallback = React.useCallback( e => { e.stopPropagation(); setCurrentOpenMenu(ourSymbol.current); }, [setCurrentOpenMenu], ); if (React.Children.count(children) === 0) { return null; } return ( ); } export default Menu;