diff --git a/app/components/ContextMenu/MenuItem.js b/app/components/ContextMenu/MenuItem.js index a82d9222c..7ebc4bc9a 100644 --- a/app/components/ContextMenu/MenuItem.js +++ b/app/components/ContextMenu/MenuItem.js @@ -15,6 +15,7 @@ type Props = {| target?: "_blank", as?: string | React.ComponentType<*>, hide?: () => void, + level?: number, |}; const MenuItem = ({ @@ -86,6 +87,7 @@ const Spacer = styled.svg` export const MenuAnchor = styled.a` display: flex; margin: 0; + margin-left: ${(props) => props.level * 10}px; border: 0; padding: 12px; width: 100%; diff --git a/app/components/ContextMenu/Template.js b/app/components/ContextMenu/Template.js index bbd3bd120..f8a2507ca 100644 --- a/app/components/ContextMenu/Template.js +++ b/app/components/ContextMenu/Template.js @@ -9,6 +9,7 @@ import { MenuItem as BaseMenuItem, } from "reakit/Menu"; import styled from "styled-components"; +import Header from "./Header"; import MenuItem, { MenuAnchor } from "./MenuItem"; import Separator from "./Separator"; import ContextMenu from "."; @@ -34,6 +35,7 @@ type TMenuItem = visible?: boolean, selected?: boolean, disabled?: boolean, + level?: number, |} | {| title: React.Node, @@ -128,7 +130,8 @@ function Template({ items, ...menu }: Props): React.Node { key={index} disabled={item.disabled} selected={item.selected} - target="_blank" + level={item.level} + target={item.href.startsWith("#") ? undefined : "_blank"} {...menu} > {item.title} @@ -167,6 +170,10 @@ function Template({ items, ...menu }: Props): React.Node { return ; } + if (item.type === "heading") { + return
{item.title}
; + } + return null; }); } diff --git a/app/menus/TableOfContentsMenu.js b/app/menus/TableOfContentsMenu.js new file mode 100644 index 000000000..abe1f9780 --- /dev/null +++ b/app/menus/TableOfContentsMenu.js @@ -0,0 +1,66 @@ +// @flow +import { observer } from "mobx-react"; +import { TableOfContentsIcon } from "outline-icons"; +import * as React from "react"; +import { useTranslation } from "react-i18next"; +import { MenuButton, useMenuState } from "reakit/Menu"; +import Button from "components/Button"; +import ContextMenu from "components/ContextMenu"; +import Template from "components/ContextMenu/Template"; + +type Props = {| + headings: { title: string, level: number, id: string }[], +|}; + +function TableOfContentsMenu({ headings }: Props) { + const menu = useMenuState({ + modal: true, + unstable_preventOverflow: true, + unstable_fixed: true, + unstable_flip: true, + }); + + const { t } = useTranslation(); + + const minHeading = headings.reduce( + (memo, heading) => (heading.level < memo ? heading.level : memo), + Infinity + ); + + return ( + <> + + {(props) => ( +