fix: Add icons to menu items (#2373)

Co-authored-by: Tom Moor <tom.moor@gmail.com>
This commit is contained in:
Saumya Pandey
2021-08-14 02:51:25 +05:30
committed by GitHub
parent 1db31eed41
commit 2c52a8cb8b
13 changed files with 242 additions and 162 deletions

View File

@ -4,6 +4,7 @@ import * as React from "react";
import { MenuItem as BaseMenuItem } from "reakit/Menu"; import { MenuItem as BaseMenuItem } from "reakit/Menu";
import styled from "styled-components"; import styled from "styled-components";
import breakpoint from "styled-components-breakpoint"; import breakpoint from "styled-components-breakpoint";
import MenuIconWrapper from "../MenuIconWrapper";
type Props = {| type Props = {|
onClick?: (SyntheticEvent<>) => void | Promise<void>, onClick?: (SyntheticEvent<>) => void | Promise<void>,
@ -16,6 +17,7 @@ type Props = {|
as?: string | React.ComponentType<*>, as?: string | React.ComponentType<*>,
hide?: () => void, hide?: () => void,
level?: number, level?: number,
icon?: React.Node,
|}; |};
const MenuItem = ({ const MenuItem = ({
@ -25,6 +27,7 @@ const MenuItem = ({
disabled, disabled,
as, as,
hide, hide,
icon,
...rest ...rest
}: Props) => { }: Props) => {
const handleClick = React.useCallback( const handleClick = React.useCallback(
@ -71,6 +74,7 @@ const MenuItem = ({
&nbsp; &nbsp;
</> </>
)} )}
{icon && <MenuIconWrapper>{icon}</MenuIconWrapper>}
{children} {children}
</MenuAnchor> </MenuAnchor>
)} )}
@ -130,8 +134,8 @@ export const MenuAnchor = styled.a`
`}; `};
${breakpoint("tablet")` ${breakpoint("tablet")`
padding: ${(props) => (props.$toggleable ? "4px 12px" : "6px 12px")}; padding: 4px 12px;
font-size: 15px; font-size: 14px;
`}; `};
`; `;

View File

@ -9,6 +9,8 @@ import {
MenuItem as BaseMenuItem, MenuItem as BaseMenuItem,
} from "reakit/Menu"; } from "reakit/Menu";
import styled from "styled-components"; import styled from "styled-components";
import Flex from "components/Flex";
import MenuIconWrapper from "components/MenuIconWrapper";
import Header from "./Header"; import Header from "./Header";
import MenuItem, { MenuAnchor } from "./MenuItem"; import MenuItem, { MenuAnchor } from "./MenuItem";
import Separator from "./Separator"; import Separator from "./Separator";
@ -67,7 +69,15 @@ export function filterTemplateItems(items: TMenuItem[]): TMenuItem[] {
} }
function Template({ items, ...menu }: Props): React.Node { function Template({ items, ...menu }: Props): React.Node {
return filterTemplateItems(items).map((item, index) => { const filteredTemplates = filterTemplateItems(items);
const iconIsPresentInAnyMenuItem = filteredTemplates.find(
(item) => !!item.icon
);
return filteredTemplates.map((item, index) => {
if (iconIsPresentInAnyMenuItem)
item.icon = item.icon ? item.icon : <MenuIconWrapper />;
if (item.to) { if (item.to) {
return ( return (
<MenuItem <MenuItem
@ -76,6 +86,7 @@ function Template({ items, ...menu }: Props): React.Node {
key={index} key={index}
disabled={item.disabled} disabled={item.disabled}
selected={item.selected} selected={item.selected}
icon={item.icon}
{...menu} {...menu}
> >
{item.title} {item.title}
@ -92,6 +103,7 @@ function Template({ items, ...menu }: Props): React.Node {
selected={item.selected} selected={item.selected}
level={item.level} level={item.level}
target={item.href.startsWith("#") ? undefined : "_blank"} target={item.href.startsWith("#") ? undefined : "_blank"}
icon={item.icon}
{...menu} {...menu}
> >
{item.title} {item.title}
@ -107,6 +119,7 @@ function Template({ items, ...menu }: Props): React.Node {
disabled={item.disabled} disabled={item.disabled}
selected={item.selected} selected={item.selected}
key={index} key={index}
icon={item.icon}
{...menu} {...menu}
> >
{item.title} {item.title}
@ -120,7 +133,7 @@ function Template({ items, ...menu }: Props): React.Node {
key={index} key={index}
as={Submenu} as={Submenu}
templateItems={item.items} templateItems={item.items}
title={item.title} title={<Title title={item.title} icon={item.icon} />}
{...menu} {...menu}
/> />
); );
@ -139,4 +152,13 @@ function Template({ items, ...menu }: Props): React.Node {
}); });
} }
function Title({ title, icon }) {
return (
<Flex align="center">
{icon && <MenuIconWrapper>{icon}</MenuIconWrapper>}
{title}
</Flex>
);
}
export default React.memo<Props>(Template); export default React.memo<Props>(Template);

View File

@ -0,0 +1,11 @@
// @flow
import styled from "styled-components";
const MenuIconWrapper = styled.span`
width: 24px;
height: 24px;
margin-right: 6px;
margin-left: -4px;
`;
export default MenuIconWrapper;

View File

@ -1,23 +1,19 @@
// @flow // @flow
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { SunIcon, MoonIcon } from "outline-icons"; import { MoonIcon, SunIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom"; import { MenuButton, useMenuState } from "reakit/Menu";
import { useMenuState, MenuButton } from "reakit/Menu";
import styled from "styled-components";
import { import {
developers,
changelog, changelog,
developers,
githubIssuesUrl, githubIssuesUrl,
mailToUrl, mailToUrl,
settings, settings,
} from "shared/utils/routeHelpers"; } from "shared/utils/routeHelpers";
import KeyboardShortcuts from "scenes/KeyboardShortcuts"; import KeyboardShortcuts from "scenes/KeyboardShortcuts";
import ContextMenu from "components/ContextMenu"; import ContextMenu from "components/ContextMenu";
import MenuItem, { MenuAnchor } from "components/ContextMenu/MenuItem"; import Template from "components/ContextMenu/Template";
import Separator from "components/ContextMenu/Separator";
import Flex from "components/Flex";
import Guide from "components/Guide"; import Guide from "components/Guide";
import useBoolean from "hooks/useBoolean"; import useBoolean from "hooks/useBoolean";
import usePrevious from "hooks/usePrevious"; import usePrevious from "hooks/usePrevious";
@ -27,50 +23,6 @@ type Props = {|
children: (props: any) => React.Node, children: (props: any) => React.Node,
|}; |};
const AppearanceMenu = React.forwardRef((props, ref) => {
const { ui } = useStores();
const { t } = useTranslation();
const menu = useMenuState();
return (
<>
<MenuButton ref={ref} {...menu} {...props} onClick={menu.show}>
{(props) => (
<MenuAnchor {...props}>
<ChangeTheme justify="space-between">
{t("Appearance")}
{ui.resolvedTheme === "light" ? <SunIcon /> : <MoonIcon />}
</ChangeTheme>
</MenuAnchor>
)}
</MenuButton>
<ContextMenu {...menu} aria-label={t("Appearance")}>
<MenuItem
{...menu}
onClick={() => ui.setTheme("system")}
selected={ui.theme === "system"}
>
{t("System")}
</MenuItem>
<MenuItem
{...menu}
onClick={() => ui.setTheme("light")}
selected={ui.theme === "light"}
>
{t("Light")}
</MenuItem>
<MenuItem
{...menu}
onClick={() => ui.setTheme("dark")}
selected={ui.theme === "dark"}
>
{t("Dark")}
</MenuItem>
</ContextMenu>
</>
);
});
function AccountMenu(props: Props) { function AccountMenu(props: Props) {
const menu = useMenuState({ const menu = useMenuState({
unstable_offset: [8, 0], unstable_offset: [8, 0],
@ -92,6 +44,67 @@ function AccountMenu(props: Props) {
} }
}, [menu, ui.theme, previousTheme]); }, [menu, ui.theme, previousTheme]);
const items = React.useMemo(
() => [
{
title: t("Settings"),
to: settings(),
},
{
title: t("Keyboard shortcuts"),
onClick: handleKeyboardShortcutsOpen,
},
{
title: t("API documentation"),
href: developers(),
},
{
type: "separator",
},
{
title: t("Changelog"),
href: changelog(),
},
{
title: t("Send us feedback"),
href: mailToUrl(),
},
{
title: t("Report a bug"),
href: githubIssuesUrl(),
},
{
title: t("Appearance"),
icon: ui.resolvedTheme === "light" ? <SunIcon /> : <MoonIcon />,
items: [
{
title: t("System"),
onClick: () => ui.setTheme("system"),
selected: ui.theme === "system",
},
{
title: t("Light"),
onClick: () => ui.setTheme("light"),
selected: ui.theme === "light",
},
{
title: t("Dark"),
onClick: () => ui.setTheme("dark"),
selected: ui.theme === "dark",
},
],
},
{
type: "separator",
},
{
title: t("Log out"),
onClick: auth.logout,
},
],
[auth.logout, handleKeyboardShortcutsOpen, t, ui]
);
return ( return (
<> <>
<Guide <Guide
@ -103,38 +116,10 @@ function AccountMenu(props: Props) {
</Guide> </Guide>
<MenuButton {...menu}>{props.children}</MenuButton> <MenuButton {...menu}>{props.children}</MenuButton>
<ContextMenu {...menu} aria-label={t("Account")}> <ContextMenu {...menu} aria-label={t("Account")}>
<MenuItem {...menu} as={Link} to={settings()}> <Template {...menu} items={items} />
{t("Settings")}
</MenuItem>
<MenuItem {...menu} onClick={handleKeyboardShortcutsOpen}>
{t("Keyboard shortcuts")}
</MenuItem>
<MenuItem {...menu} href={developers()} target="_blank">
{t("API documentation")}
</MenuItem>
<Separator {...menu} />
<MenuItem {...menu} href={changelog()} target="_blank">
{t("Changelog")}
</MenuItem>
<MenuItem {...menu} href={mailToUrl()} target="_blank">
{t("Send us feedback")}
</MenuItem>
<MenuItem {...menu} href={githubIssuesUrl()} target="_blank">
{t("Report a bug")}
</MenuItem>
<Separator {...menu} />
<MenuItem {...menu} as={AppearanceMenu} />
<Separator {...menu} />
<MenuItem {...menu} onClick={auth.logout}>
{t("Log out")}
</MenuItem>
</ContextMenu> </ContextMenu>
</> </>
); );
} }
const ChangeTheme = styled(Flex)`
width: 100%;
`;
export default observer(AccountMenu); export default observer(AccountMenu);

View File

@ -1,5 +1,13 @@
// @flow // @flow
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import {
NewDocumentIcon,
EditIcon,
TrashIcon,
ImportIcon,
ExportIcon,
PadlockIcon,
} from "outline-icons";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
@ -12,7 +20,7 @@ import CollectionExport from "scenes/CollectionExport";
import CollectionPermissions from "scenes/CollectionPermissions"; import CollectionPermissions from "scenes/CollectionPermissions";
import ContextMenu from "components/ContextMenu"; import ContextMenu from "components/ContextMenu";
import OverflowMenuButton from "components/ContextMenu/OverflowMenuButton"; import OverflowMenuButton from "components/ContextMenu/OverflowMenuButton";
import Template, { filterTemplateItems } from "components/ContextMenu/Template"; import Template from "components/ContextMenu/Template";
import Modal from "components/Modal"; import Modal from "components/Modal";
import useStores from "hooks/useStores"; import useStores from "hooks/useStores";
import useToasts from "hooks/useToasts"; import useToasts from "hooks/useToasts";
@ -113,17 +121,18 @@ function CollectionMenu({
const can = policies.abilities(collection.id); const can = policies.abilities(collection.id);
const items = React.useMemo( const items = React.useMemo(
() => () => [
filterTemplateItems([
{ {
title: t("New document"), title: t("New document"),
visible: can.update, visible: can.update,
onClick: handleNewDocument, onClick: handleNewDocument,
icon: <NewDocumentIcon />,
}, },
{ {
title: t("Import document"), title: t("Import document"),
visible: can.update, visible: can.update,
onClick: handleImportDocument, onClick: handleImportDocument,
icon: <ImportIcon />,
}, },
{ {
type: "separator", type: "separator",
@ -132,16 +141,19 @@ function CollectionMenu({
title: `${t("Edit")}`, title: `${t("Edit")}`,
visible: can.update, visible: can.update,
onClick: () => setShowCollectionEdit(true), onClick: () => setShowCollectionEdit(true),
icon: <EditIcon />,
}, },
{ {
title: `${t("Permissions")}`, title: `${t("Permissions")}`,
visible: can.update, visible: can.update,
onClick: () => setShowCollectionPermissions(true), onClick: () => setShowCollectionPermissions(true),
icon: <PadlockIcon />,
}, },
{ {
title: `${t("Export")}`, title: `${t("Export")}`,
visible: !!(collection && can.export), visible: !!(collection && can.export),
onClick: () => setShowCollectionExport(true), onClick: () => setShowCollectionExport(true),
icon: <ExportIcon />,
}, },
{ {
type: "separator", type: "separator",
@ -150,8 +162,9 @@ function CollectionMenu({
title: `${t("Delete")}`, title: `${t("Delete")}`,
visible: !!(collection && can.delete), visible: !!(collection && can.delete),
onClick: () => setShowCollectionDelete(true), onClick: () => setShowCollectionDelete(true),
icon: <TrashIcon />,
}, },
]), ],
[can, collection, handleNewDocument, handleImportDocument, t] [can, collection, handleNewDocument, handleImportDocument, t]
); );

View File

@ -1,5 +1,25 @@
// @flow // @flow
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import {
EditIcon,
PinIcon,
StarredIcon,
UnstarredIcon,
DuplicateIcon,
ArchiveIcon,
TrashIcon,
MoveIcon,
HistoryIcon,
UnpublishIcon,
ShapesIcon,
PrintIcon,
ImportIcon,
NewDocumentIcon,
DownloadIcon,
BuildingBlocksIcon,
RestoreIcon,
CrossIcon,
} from "outline-icons";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
@ -248,6 +268,7 @@ function DocumentMenu({
title: t("Restore"), title: t("Restore"),
visible: (!!collection && can.restore) || can.unarchive, visible: (!!collection && can.restore) || can.unarchive,
onClick: handleRestore, onClick: handleRestore,
icon: <RestoreIcon />,
}, },
{ {
title: t("Restore"), title: t("Restore"),
@ -258,6 +279,7 @@ function DocumentMenu({
position: "relative", position: "relative",
top: -40, top: -40,
}, },
icon: <RestoreIcon />,
hover: true, hover: true,
items: [ items: [
{ {
@ -271,86 +293,102 @@ function DocumentMenu({
title: t("Unpin"), title: t("Unpin"),
onClick: document.unpin, onClick: document.unpin,
visible: !!(showPin && document.pinned && can.unpin), visible: !!(showPin && document.pinned && can.unpin),
icon: <PinIcon />,
}, },
{ {
title: t("Pin to collection"), title: t("Pin to collection"),
onClick: document.pin, onClick: document.pin,
visible: !!(showPin && !document.pinned && can.pin), visible: !!(showPin && !document.pinned && can.pin),
icon: <PinIcon />,
}, },
{ {
title: t("Unstar"), title: t("Unstar"),
onClick: handleUnstar, onClick: handleUnstar,
visible: document.isStarred && !!can.unstar, visible: document.isStarred && !!can.unstar,
icon: <UnstarredIcon />,
}, },
{ {
title: t("Star"), title: t("Star"),
onClick: handleStar, onClick: handleStar,
visible: !document.isStarred && !!can.star, visible: !document.isStarred && !!can.star,
}, icon: <StarredIcon />,
{
title: t("Enable embeds"),
onClick: document.enableEmbeds,
visible: !!showToggleEmbeds && document.embedsDisabled,
},
{
title: t("Disable embeds"),
onClick: document.disableEmbeds,
visible: !!showToggleEmbeds && !document.embedsDisabled,
}, },
{ {
type: "separator", type: "separator",
}, },
{
title: t("Edit"),
to: editDocumentUrl(document),
visible: !!can.update,
icon: <EditIcon />,
},
{ {
title: t("New nested document"), title: t("New nested document"),
to: newDocumentUrl(document.collectionId, { to: newDocumentUrl(document.collectionId, {
parentDocumentId: document.id, parentDocumentId: document.id,
}), }),
visible: !!can.createChildDocument, visible: !!can.createChildDocument,
icon: <NewDocumentIcon />,
}, },
{ {
title: t("Import document"), title: t("Import document"),
visible: can.createChildDocument, visible: can.createChildDocument,
onClick: handleImportDocument, onClick: handleImportDocument,
icon: <ImportIcon />,
}, },
{ {
title: `${t("Create template")}`, title: `${t("Create template")}`,
onClick: () => setShowTemplateModal(true), onClick: () => setShowTemplateModal(true),
visible: !!can.update && !document.isTemplate, visible: !!can.update && !document.isTemplate,
}, icon: <ShapesIcon />,
{
title: t("Edit"),
to: editDocumentUrl(document),
visible: !!can.update,
}, },
{ {
title: t("Duplicate"), title: t("Duplicate"),
onClick: handleDuplicate, onClick: handleDuplicate,
visible: !!can.update, visible: !!can.update,
icon: <DuplicateIcon />,
}, },
{ {
title: t("Unpublish"), title: t("Unpublish"),
onClick: handleUnpublish, onClick: handleUnpublish,
visible: !!can.unpublish, visible: !!can.unpublish,
icon: <UnpublishIcon />,
}, },
{ {
title: t("Archive"), title: t("Archive"),
onClick: handleArchive, onClick: handleArchive,
visible: !!can.archive, visible: !!can.archive,
icon: <ArchiveIcon />,
}, },
{ {
title: `${t("Delete")}`, title: `${t("Delete")}`,
onClick: () => setShowDeleteModal(true), onClick: () => setShowDeleteModal(true),
visible: !!can.delete, visible: !!can.delete,
icon: <TrashIcon />,
}, },
{ {
title: `${t("Permanently delete")}`, title: `${t("Permanently delete")}`,
onClick: () => setShowPermanentDeleteModal(true), onClick: () => setShowPermanentDeleteModal(true),
visible: can.permanentDelete, visible: can.permanentDelete,
icon: <CrossIcon />,
}, },
{ {
title: `${t("Move")}`, title: `${t("Move")}`,
onClick: () => setShowMoveModal(true), onClick: () => setShowMoveModal(true),
visible: !!can.move, visible: !!can.move,
icon: <MoveIcon />,
},
{
title: t("Enable embeds"),
onClick: document.enableEmbeds,
visible: !!showToggleEmbeds && document.embedsDisabled,
icon: <BuildingBlocksIcon />,
},
{
title: t("Disable embeds"),
onClick: document.disableEmbeds,
visible: !!showToggleEmbeds && !document.embedsDisabled,
icon: <BuildingBlocksIcon />,
}, },
{ {
type: "separator", type: "separator",
@ -361,16 +399,19 @@ function DocumentMenu({
? documentUrl(document) ? documentUrl(document)
: documentHistoryUrl(document), : documentHistoryUrl(document),
visible: canViewHistory, visible: canViewHistory,
icon: <HistoryIcon />,
}, },
{ {
title: t("Download"), title: t("Download"),
onClick: document.download, onClick: document.download,
visible: !!can.download, visible: !!can.download,
icon: <DownloadIcon />,
}, },
{ {
title: t("Print"), title: t("Print"),
onClick: handlePrint, onClick: handlePrint,
visible: !!showPrint, visible: !!showPrint,
icon: <PrintIcon />,
}, },
]} ]}
/> />

View File

@ -11,7 +11,6 @@ import CollectionIcon from "components/CollectionIcon";
import ContextMenu from "components/ContextMenu"; import ContextMenu from "components/ContextMenu";
import Header from "components/ContextMenu/Header"; import Header from "components/ContextMenu/Header";
import Template from "components/ContextMenu/Template"; import Template from "components/ContextMenu/Template";
import Flex from "components/Flex";
import useCurrentTeam from "hooks/useCurrentTeam"; import useCurrentTeam from "hooks/useCurrentTeam";
import useStores from "hooks/useStores"; import useStores from "hooks/useStores";
import { newDocumentUrl } from "utils/routeHelpers"; import { newDocumentUrl } from "utils/routeHelpers";
@ -31,12 +30,8 @@ function NewDocumentMenu() {
if (can.update) { if (can.update) {
filtered.push({ filtered.push({
to: newDocumentUrl(collection.id), to: newDocumentUrl(collection.id),
title: ( title: <CollectionName>{collection.name}</CollectionName>,
<Flex align="center"> icon: <CollectionIcon collection={collection} />,
<CollectionIcon collection={collection} />
<CollectionName>{collection.name}</CollectionName>
</Flex>
),
}); });
} }
return filtered; return filtered;

View File

@ -3,14 +3,13 @@ import { observer } from "mobx-react";
import { PlusIcon } from "outline-icons"; import { PlusIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useMenuState, MenuButton } from "reakit/Menu"; import { MenuButton, useMenuState } from "reakit/Menu";
import styled from "styled-components"; import styled from "styled-components";
import Button from "components/Button"; import Button from "components/Button";
import CollectionIcon from "components/CollectionIcon"; import CollectionIcon from "components/CollectionIcon";
import ContextMenu from "components/ContextMenu"; import ContextMenu from "components/ContextMenu";
import Header from "components/ContextMenu/Header"; import Header from "components/ContextMenu/Header";
import Template from "components/ContextMenu/Template"; import Template from "components/ContextMenu/Template";
import Flex from "components/Flex";
import useCurrentTeam from "hooks/useCurrentTeam"; import useCurrentTeam from "hooks/useCurrentTeam";
import useStores from "hooks/useStores"; import useStores from "hooks/useStores";
import { newDocumentUrl } from "utils/routeHelpers"; import { newDocumentUrl } from "utils/routeHelpers";
@ -29,12 +28,8 @@ function NewTemplateMenu() {
if (can.update) { if (can.update) {
filtered.push({ filtered.push({
to: newDocumentUrl(collection.id, { template: true }), to: newDocumentUrl(collection.id, { template: true }),
title: ( title: <CollectionName>{collection.name}</CollectionName>,
<Flex align="center"> icon: <CollectionIcon collection={collection} />,
<CollectionIcon collection={collection} />
<CollectionName>{collection.name}</CollectionName>
</Flex>
),
}); });
} }
return filtered; return filtered;

View File

@ -1,5 +1,6 @@
// @flow // @flow
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { RestoreIcon, LinkIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
@ -10,6 +11,7 @@ import MenuItem from "components/ContextMenu/MenuItem";
import OverflowMenuButton from "components/ContextMenu/OverflowMenuButton"; import OverflowMenuButton from "components/ContextMenu/OverflowMenuButton";
import Separator from "components/ContextMenu/Separator"; import Separator from "components/ContextMenu/Separator";
import CopyToClipboard from "components/CopyToClipboard"; import CopyToClipboard from "components/CopyToClipboard";
import MenuIconWrapper from "components/MenuIconWrapper";
import useToasts from "hooks/useToasts"; import useToasts from "hooks/useToasts";
import { documentHistoryUrl } from "utils/routeHelpers"; import { documentHistoryUrl } from "utils/routeHelpers";
@ -54,11 +56,19 @@ function RevisionMenu({ document, revisionId, className }: Props) {
/> />
<ContextMenu {...menu} aria-label={t("Revision options")}> <ContextMenu {...menu} aria-label={t("Revision options")}>
<MenuItem {...menu} onClick={handleRestore}> <MenuItem {...menu} onClick={handleRestore}>
<MenuIconWrapper>
<RestoreIcon />
</MenuIconWrapper>
{t("Restore version")} {t("Restore version")}
</MenuItem> </MenuItem>
<Separator /> <Separator />
<CopyToClipboard text={url} onCopy={handleCopy}> <CopyToClipboard text={url} onCopy={handleCopy}>
<MenuItem {...menu}>{t("Copy link")}</MenuItem> <MenuItem {...menu}>
<MenuIconWrapper>
<LinkIcon />
</MenuIconWrapper>
{t("Copy link")}
</MenuItem>
</CopyToClipboard> </CopyToClipboard>
</ContextMenu> </ContextMenu>
</> </>

View File

@ -37,9 +37,9 @@ function TemplatesMenu({ document }: Props) {
<MenuItem <MenuItem
key={template.id} key={template.id}
onClick={() => document.updateFromTemplate(template)} onClick={() => document.updateFromTemplate(template)}
icon={<DocumentIcon />}
{...menu} {...menu}
> >
<DocumentIcon />
<TemplateItem> <TemplateItem>
<strong>{template.titleWithDefault}</strong> <strong>{template.titleWithDefault}</strong>
<br /> <br />

View File

@ -66,6 +66,7 @@ export type MenuItem =
visible?: boolean, visible?: boolean,
selected?: boolean, selected?: boolean,
disabled?: boolean, disabled?: boolean,
icon?: React.Node,
|} |}
| {| | {|
title: React.Node, title: React.Node,
@ -73,6 +74,7 @@ export type MenuItem =
visible?: boolean, visible?: boolean,
selected?: boolean, selected?: boolean,
disabled?: boolean, disabled?: boolean,
icon?: React.Node,
|} |}
| {| | {|
title: React.Node, title: React.Node,
@ -81,6 +83,7 @@ export type MenuItem =
selected?: boolean, selected?: boolean,
disabled?: boolean, disabled?: boolean,
level?: number, level?: number,
icon?: React.Node,
|} |}
| {| | {|
title: React.Node, title: React.Node,
@ -89,6 +92,7 @@ export type MenuItem =
style?: Object, style?: Object,
hover?: boolean, hover?: boolean,
items: MenuItem[], items: MenuItem[],
icon?: React.Node,
|} |}
| {| | {|
type: "separator", type: "separator",

View File

@ -167,14 +167,14 @@
"Previous page": "Previous page", "Previous page": "Previous page",
"Next page": "Next page", "Next page": "Next page",
"Could not import file": "Could not import file", "Could not import file": "Could not import file",
"Appearance": "Appearance",
"System": "System",
"Light": "Light",
"Dark": "Dark",
"API documentation": "API documentation", "API documentation": "API documentation",
"Changelog": "Changelog", "Changelog": "Changelog",
"Send us feedback": "Send us feedback", "Send us feedback": "Send us feedback",
"Report a bug": "Report a bug", "Report a bug": "Report a bug",
"Appearance": "Appearance",
"System": "System",
"Light": "Light",
"Dark": "Dark",
"Log out": "Log out", "Log out": "Log out",
"Show path to document": "Show path to document", "Show path to document": "Show path to document",
"Path to document": "Path to document", "Path to document": "Path to document",

View File

@ -10,7 +10,7 @@ const colors = {
slate: "#9BA6B2", slate: "#9BA6B2",
slateLight: "#DAE1E9", slateLight: "#DAE1E9",
slateDark: "#4E5C6E", slateDark: "#394351",
smoke: "#F4F7FA", smoke: "#F4F7FA",
smokeLight: "#F9FBFC", smokeLight: "#F9FBFC",