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 (
-
-
+
+
)
}
-
-const MenuBarDropdown: FC = ({ title, children, id }) => {
- return (
-
-
- {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 (
+
+
+ {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;
+ }
+}