From bd76193eb52fd487bdd947346e1e2acdb9159f4d Mon Sep 17 00:00:00 2001 From: David <33458145+davidmcpowell@users.noreply.github.com> Date: Thu, 6 Feb 2025 15:41:18 +0000 Subject: [PATCH] Merge pull request #23300 from overleaf/mj-ide-menu-hover [web] Introduce menu bar shared component GitOrigin-RevId: c304cc4e1e5961fe4ef7d2112e8d9f91c47dd0ec --- .../components/toolbar/menu-bar.tsx | 84 +++++++++---------- .../components/types/dropdown-menu-props.ts | 2 + .../components/menu-bar/menu-bar-dropdown.tsx | 53 ++++++++++++ .../components/menu-bar/menu-bar-option.tsx | 15 ++++ .../shared/components/menu-bar/menu-bar.tsx | 17 ++++ .../js/shared/context/menu-bar-context.tsx | 11 +++ .../frontend/js/shared/hooks/use-menu-bar.tsx | 10 +++ .../web/frontend/stories/menu-bar.stories.tsx | 38 +++++++++ .../bootstrap-5/components/all.scss | 1 + .../bootstrap-5/components/menu-bar.scss | 13 +++ 10 files changed, 199 insertions(+), 45 deletions(-) create mode 100644 services/web/frontend/js/shared/components/menu-bar/menu-bar-dropdown.tsx create mode 100644 services/web/frontend/js/shared/components/menu-bar/menu-bar-option.tsx create mode 100644 services/web/frontend/js/shared/components/menu-bar/menu-bar.tsx create mode 100644 services/web/frontend/js/shared/context/menu-bar-context.tsx create mode 100644 services/web/frontend/js/shared/hooks/use-menu-bar.tsx create mode 100644 services/web/frontend/stories/menu-bar.stories.tsx create mode 100644 services/web/frontend/stylesheets/bootstrap-5/components/menu-bar.scss diff --git a/services/web/frontend/js/features/ide-redesign/components/toolbar/menu-bar.tsx b/services/web/frontend/js/features/ide-redesign/components/toolbar/menu-bar.tsx index b5bb831ea2..502cf44323 100644 --- a/services/web/frontend/js/features/ide-redesign/components/toolbar/menu-bar.tsx +++ b/services/web/frontend/js/features/ide-redesign/components/toolbar/menu-bar.tsx @@ -1,32 +1,29 @@ -import { - Dropdown, - DropdownDivider, - DropdownMenu, - DropdownToggle, -} from '@/features/ui/components/bootstrap-5/dropdown-menu' -import OLDropdownMenuItem from '@/features/ui/components/ol/ol-dropdown-menu-item' -import { FC } from 'react' +import { DropdownDivider } from '@/features/ui/components/bootstrap-5/dropdown-menu' +import { MenuBar } from '@/shared/components/menu-bar/menu-bar' +import { MenuBarDropdown } from '@/shared/components/menu-bar/menu-bar-dropdown' +import { MenuBarOption } from '@/shared/components/menu-bar/menu-bar-option' import { useTranslation } from 'react-i18next' -type MenuBarOptionProps = { - title: string - onClick?: () => void -} - -type MenuBarDropdownProps = { - title: string - id: string -} - export const ToolbarMenuBar = () => { const { t } = useTranslation() return ( -
- + + - + @@ -34,44 +31,41 @@ export const ToolbarMenuBar = () => { - + - + - + - + -
+ ) } - -const MenuBarDropdown: FC = ({ title, children, id }) => { - return ( - - - {title} - - {children} - - ) -} - -const MenuBarOption = ({ title, onClick }: MenuBarOptionProps) => { - return {title} -} diff --git a/services/web/frontend/js/features/ui/components/types/dropdown-menu-props.ts b/services/web/frontend/js/features/ui/components/types/dropdown-menu-props.ts index b4ee76a4a0..c0c8aa85ae 100644 --- a/services/web/frontend/js/features/ui/components/types/dropdown-menu-props.ts +++ b/services/web/frontend/js/features/ui/components/types/dropdown-menu-props.ts @@ -57,6 +57,7 @@ export type DropdownToggleProps = PropsWithChildren<{ size?: 'sm' | 'lg' | undefined tabIndex?: number 'aria-label'?: string + onMouseEnter?: React.MouseEventHandler }> export type DropdownMenuProps = PropsWithChildren<{ @@ -66,6 +67,7 @@ export type DropdownMenuProps = PropsWithChildren<{ className?: string flip?: boolean id?: string + renderOnMount?: boolean }> export type DropdownDividerProps = PropsWithChildren<{ diff --git a/services/web/frontend/js/shared/components/menu-bar/menu-bar-dropdown.tsx b/services/web/frontend/js/shared/components/menu-bar/menu-bar-dropdown.tsx new file mode 100644 index 0000000000..ab9d389168 --- /dev/null +++ b/services/web/frontend/js/shared/components/menu-bar/menu-bar-dropdown.tsx @@ -0,0 +1,53 @@ +import { + Dropdown, + DropdownMenu, + DropdownToggle, +} from '@/features/ui/components/bootstrap-5/dropdown-menu' +import { FC, useCallback } from 'react' +import classNames from 'classnames' +import { useMenuBar } from '@/shared/hooks/use-menu-bar' + +type MenuBarDropdownProps = { + title: string + id: string + className?: string +} + +export const MenuBarDropdown: FC = ({ + title, + children, + id, + className, +}) => { + const { menuId, selected, setSelected } = useMenuBar() + + const onToggle = useCallback( + show => { + setSelected(show ? id : null) + }, + [id, setSelected] + ) + + const onHover = useCallback(() => { + setSelected(prev => { + if (prev === null) { + return null + } + return id + }) + }, [id, setSelected]) + + return ( + + + {title} + + {children} + + ) +} diff --git a/services/web/frontend/js/shared/components/menu-bar/menu-bar-option.tsx b/services/web/frontend/js/shared/components/menu-bar/menu-bar-option.tsx new file mode 100644 index 0000000000..b1683aa377 --- /dev/null +++ b/services/web/frontend/js/shared/components/menu-bar/menu-bar-option.tsx @@ -0,0 +1,15 @@ +import DropdownListItem from '@/features/ui/components/bootstrap-5/dropdown-list-item' +import { DropdownItem } from '@/features/ui/components/bootstrap-5/dropdown-menu' + +type MenuBarOptionProps = { + title: string + onClick?: () => void +} + +export const MenuBarOption = ({ title, onClick }: MenuBarOptionProps) => { + return ( + + {title} + + ) +} diff --git a/services/web/frontend/js/shared/components/menu-bar/menu-bar.tsx b/services/web/frontend/js/shared/components/menu-bar/menu-bar.tsx new file mode 100644 index 0000000000..45298c32e0 --- /dev/null +++ b/services/web/frontend/js/shared/components/menu-bar/menu-bar.tsx @@ -0,0 +1,17 @@ +import { MenuBarContext } from '@/shared/context/menu-bar-context' +import { FC, HTMLProps, useState } from 'react' + +export const MenuBar: FC & { id: string }> = ({ + children, + id, + ...props +}) => { + const [selected, setSelected] = useState(null) + return ( +
+ + {children} + +
+ ) +} diff --git a/services/web/frontend/js/shared/context/menu-bar-context.tsx b/services/web/frontend/js/shared/context/menu-bar-context.tsx new file mode 100644 index 0000000000..e303e19417 --- /dev/null +++ b/services/web/frontend/js/shared/context/menu-bar-context.tsx @@ -0,0 +1,11 @@ +import { createContext, Dispatch, SetStateAction } from 'react' + +export type MenuBarContextType = { + selected: string | null + setSelected: Dispatch> + menuId: string +} + +export const MenuBarContext = createContext( + undefined +) diff --git a/services/web/frontend/js/shared/hooks/use-menu-bar.tsx b/services/web/frontend/js/shared/hooks/use-menu-bar.tsx new file mode 100644 index 0000000000..1493668c09 --- /dev/null +++ b/services/web/frontend/js/shared/hooks/use-menu-bar.tsx @@ -0,0 +1,10 @@ +import { MenuBarContext } from '@/shared/context/menu-bar-context' +import { useContext } from 'react' + +export const useMenuBar = () => { + const context = useContext(MenuBarContext) + if (context === undefined) { + throw new Error('useMenuBarContext must be used within a MenuBarContext') + } + return context +} diff --git a/services/web/frontend/stories/menu-bar.stories.tsx b/services/web/frontend/stories/menu-bar.stories.tsx new file mode 100644 index 0000000000..b7126ce374 --- /dev/null +++ b/services/web/frontend/stories/menu-bar.stories.tsx @@ -0,0 +1,38 @@ +import { DropdownDivider } from '@/features/ui/components/bootstrap-5/dropdown-menu' +import { MenuBar } from '@/shared/components/menu-bar/menu-bar' +import { MenuBarDropdown } from '@/shared/components/menu-bar/menu-bar-dropdown' +import { MenuBarOption } from '@/shared/components/menu-bar/menu-bar-option' +import { Meta } from '@storybook/react/*' + +export const Default = () => { + return ( + + + + + + + + + + + + + + + + + + ) +} + +const meta: Meta = { + title: 'Shared / Components / MenuBar', + component: MenuBar, + argTypes: {}, + parameters: { + bootstrap5: true, + }, +} + +export default meta diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/all.scss b/services/web/frontend/stylesheets/bootstrap-5/components/all.scss index 50caa792af..772ad200d6 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/components/all.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/components/all.scss @@ -37,3 +37,4 @@ @import 'tos'; @import 'collapsible-file-header'; @import 'panel-heading'; +@import 'menu-bar'; diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/menu-bar.scss b/services/web/frontend/stylesheets/bootstrap-5/components/menu-bar.scss new file mode 100644 index 0000000000..0764f5785e --- /dev/null +++ b/services/web/frontend/stylesheets/bootstrap-5/components/menu-bar.scss @@ -0,0 +1,13 @@ +.menu-bar-toggle { + border: none; + border-radius: var(--border-radius-base); + padding: var(--spacing-02); + font-size: var(--font-size-03); + line-height: var(--line-height-03); + font-weight: 400; + box-sizing: border-box; + + &.dropdown-toggle::after { + display: none; + } +}