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 e72800db62..472dcf8baf 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,6 +1,12 @@
-import { DropdownDivider } from '@/features/ui/components/bootstrap-5/dropdown-menu'
+import {
+ DropdownDivider,
+ DropdownHeader,
+} 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 {
+ MenuBarDropdown,
+ NestedMenuBarDropdown,
+} from '@/shared/components/menu-bar/menu-bar-dropdown'
import { MenuBarOption } from '@/shared/components/menu-bar/menu-bar-option'
import { useTranslation } from 'react-i18next'
import ChangeLayoutOptions from './change-layout-options'
@@ -17,8 +23,16 @@ export const ToolbarMenuBar = () => {
id="file"
className="ide-redesign-toolbar-dropdown-toggle-subdued ide-redesign-toolbar-button-subdued"
>
-
-
+
+
+
+
+
+
+
+
+
+
{
-
+
+
+
+
+
{
className="ide-redesign-toolbar-dropdown-toggle-subdued ide-redesign-toolbar-button-subdued"
>
+ Editor settings
+
+
+ PDF preview
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+ Paragraph styles
+
+
+
+
+
+
= ({
@@ -18,8 +23,9 @@ export const MenuBarDropdown: FC = ({
children,
id,
className,
+ align = 'start',
}) => {
- const { menuId, selected, setSelected } = useMenuBar()
+ const { menuId, selected, setSelected } = useNestableDropdown()
const onToggle = useCallback(
show => {
@@ -38,7 +44,12 @@ export const MenuBarDropdown: FC = ({
}, [id, setSelected])
return (
-
+
- {children}
+
+
+ )
+}
+
+const NestableDropdownMenu: FC = ({
+ children,
+ id,
+ ...props
+}) => {
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+const NestedDropdownToggle: FC = forwardRef(
+ function NestedDropdownToggle(
+ { children, className, onMouseEnter, id },
+ ref
+ ) {
+ return (
+ // eslint-disable-next-line jsx-a11y/anchor-is-valid
+
+ {children}
+
+
+ )
+ }
+)
+
+export const NestedMenuBarDropdown: FC<{ id: string; title: string }> = ({
+ children,
+ id,
+ title,
+}) => {
+ const { menuId, selected, setSelected } = useNestableDropdown()
+ const select = useCallback(() => {
+ setSelected(id)
+ }, [id, setSelected])
+ const onToggle = useCallback(
+ show => {
+ setSelected(show ? id : null)
+ },
+ [setSelected, id]
+ )
+ const active = selected === id
+ return (
+
+
+
)
}
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
index b1683aa377..916dd79f80 100644
--- 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
@@ -1,5 +1,6 @@
import DropdownListItem from '@/features/ui/components/bootstrap-5/dropdown-list-item'
import { DropdownItem } from '@/features/ui/components/bootstrap-5/dropdown-menu'
+import { useNestableDropdown } from '@/shared/hooks/use-nestable-dropdown'
type MenuBarOptionProps = {
title: string
@@ -7,9 +8,12 @@ type MenuBarOptionProps = {
}
export const MenuBarOption = ({ title, onClick }: MenuBarOptionProps) => {
+ const { setSelected } = useNestableDropdown()
return (
- {title}
+ setSelected(null)} onClick={onClick}>
+ {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
index 45298c32e0..4236bfa5e8 100644
--- a/services/web/frontend/js/shared/components/menu-bar/menu-bar.tsx
+++ b/services/web/frontend/js/shared/components/menu-bar/menu-bar.tsx
@@ -1,17 +1,16 @@
-import { MenuBarContext } from '@/shared/context/menu-bar-context'
-import { FC, HTMLProps, useState } from 'react'
+import { NestableDropdownContextProvider } from '@/shared/context/nestable-dropdown-context'
+import { FC, HTMLProps } 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
deleted file mode 100644
index e303e19417..0000000000
--- a/services/web/frontend/js/shared/context/menu-bar-context.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-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/context/nestable-dropdown-context.tsx b/services/web/frontend/js/shared/context/nestable-dropdown-context.tsx
new file mode 100644
index 0000000000..3f1b7f9c0f
--- /dev/null
+++ b/services/web/frontend/js/shared/context/nestable-dropdown-context.tsx
@@ -0,0 +1,25 @@
+import { createContext, Dispatch, FC, SetStateAction, useState } from 'react'
+
+export type NestableDropdownContextType = {
+ selected: string | null
+ setSelected: Dispatch>
+ menuId: string
+}
+
+export const NestableDropdownContext = createContext<
+ NestableDropdownContextType | undefined
+>(undefined)
+
+export const NestableDropdownContextProvider: FC<{ id: string }> = ({
+ id,
+ children,
+}) => {
+ const [selected, setSelected] = useState(null)
+ return (
+
+ {children}
+
+ )
+}
diff --git a/services/web/frontend/js/shared/hooks/use-menu-bar.tsx b/services/web/frontend/js/shared/hooks/use-menu-bar.tsx
deleted file mode 100644
index 1493668c09..0000000000
--- a/services/web/frontend/js/shared/hooks/use-menu-bar.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-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/js/shared/hooks/use-nestable-dropdown.tsx b/services/web/frontend/js/shared/hooks/use-nestable-dropdown.tsx
new file mode 100644
index 0000000000..170b6f6d4d
--- /dev/null
+++ b/services/web/frontend/js/shared/hooks/use-nestable-dropdown.tsx
@@ -0,0 +1,12 @@
+import { NestableDropdownContext } from '@/shared/context/nestable-dropdown-context'
+import { useContext } from 'react'
+
+export const useNestableDropdown = () => {
+ const context = useContext(NestableDropdownContext)
+ if (context === undefined) {
+ throw new Error(
+ 'useNestableDropdown must be used within a NestableDropdownContextProvider'
+ )
+ }
+ return context
+}
diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/dropdown-menu.scss b/services/web/frontend/stylesheets/bootstrap-5/components/dropdown-menu.scss
index a05963f00e..719e04adf2 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/components/dropdown-menu.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/components/dropdown-menu.scss
@@ -72,7 +72,8 @@ $dropdown-item-min-height: 36px;
}
&:hover:not(.active),
- &:focus:not(.active) {
+ &:focus:not(.active),
+ &.nested-dropdown-toggle-shown {
background-color: var(--bg-light-secondary);
cursor: pointer;
text-decoration: none;
@@ -211,3 +212,12 @@ $dropdown-item-min-height: 36px;
text-align: center;
}
}
+
+.nested-dropdown-toggle {
+ &::after {
+ content: none !important;
+ }
+
+ display: flex;
+ justify-content: space-between;
+}