diff --git a/app/actions/index.ts b/app/actions/index.ts index 6abb8ad87..cd7a554ad 100644 --- a/app/actions/index.ts +++ b/app/actions/index.ts @@ -70,7 +70,7 @@ export function actionToKBar( return []; } - const resolvedIcon = resolve>(action.icon, context); + const resolvedIcon = resolve(action.icon, context); const resolvedChildren = resolve(action.children, context); const resolvedSection = resolve(action.section, context); const resolvedName = resolve(action.name, context); diff --git a/app/components/ContextMenu/MenuItem.tsx b/app/components/ContextMenu/MenuItem.tsx index 681be9e5d..dcc39fc5f 100644 --- a/app/components/ContextMenu/MenuItem.tsx +++ b/app/components/ContextMenu/MenuItem.tsx @@ -1,6 +1,7 @@ import { LocationDescriptor } from "history"; import { CheckmarkIcon } from "outline-icons"; import * as React from "react"; +import { mergeRefs } from "react-merge-refs"; import { MenuItem as BaseMenuItem } from "reakit/Menu"; import styled, { css } from "styled-components"; import breakpoint from "styled-components-breakpoint"; @@ -8,6 +9,7 @@ import MenuIconWrapper from "../MenuIconWrapper"; type Props = { onClick?: (event: React.SyntheticEvent) => void | Promise; + active?: boolean; selected?: boolean; disabled?: boolean; dangerous?: boolean; @@ -18,18 +20,23 @@ type Props = { hide?: () => void; level?: number; icon?: React.ReactElement; + children?: React.ReactNode; }; -const MenuItem: React.FC = ({ - onClick, - children, - selected, - disabled, - as, - hide, - icon, - ...rest -}) => { +const MenuItem = ( + { + onClick, + children, + active, + selected, + disabled, + as, + hide, + icon, + ...rest + }: Props, + ref: React.Ref +) => { const handleClick = React.useCallback( (ev) => { if (onClick) { @@ -63,10 +70,14 @@ const MenuItem: React.FC = ({ {(props) => ( , + ])} > {selected !== undefined && ( <> @@ -97,6 +108,7 @@ type MenuAnchorProps = { disabled?: boolean; dangerous?: boolean; disclosure?: boolean; + $active?: boolean; }; export const MenuAnchorCSS = css` @@ -104,6 +116,7 @@ export const MenuAnchorCSS = css` margin: 0; border: 0; padding: 12px; + border-radius: 4px; padding-left: ${(props) => 12 + (props.level || 0) * 10}px; width: 100%; min-height: 32px; @@ -146,6 +159,20 @@ export const MenuAnchorCSS = css` } } } + + ${ + props.$active && + ` + color: ${props.theme.white}; + background: ${props.dangerous ? props.theme.danger : props.theme.primary}; + box-shadow: none; + cursor: var(--pointer); + + svg { + fill: ${props.theme.white}; + } + ` + } `}; ${breakpoint("tablet")` @@ -160,4 +187,4 @@ export const MenuAnchor = styled.a` ${MenuAnchorCSS} `; -export default MenuItem; +export default React.forwardRef(MenuItem); diff --git a/app/components/ContextMenu/Separator.tsx b/app/components/ContextMenu/Separator.tsx index 60f7d9c03..17a2299d3 100644 --- a/app/components/ContextMenu/Separator.tsx +++ b/app/components/ContextMenu/Separator.tsx @@ -11,5 +11,5 @@ export default function Separator(rest: React.HTMLAttributes) { } const HorizontalRule = styled.hr` - margin: 0.5em 12px; + margin: 6px 0; `; diff --git a/app/components/ContextMenu/index.tsx b/app/components/ContextMenu/index.tsx index 787601306..24c2ebc3c 100644 --- a/app/components/ContextMenu/index.tsx +++ b/app/components/ContextMenu/index.tsx @@ -205,7 +205,7 @@ export const Background = styled(Scrollable)` max-width: 100%; background: ${(props) => props.theme.menuBackground}; border-radius: 6px; - padding: 6px 0; + padding: 6px; min-width: 180px; min-height: 44px; max-height: 75vh; diff --git a/app/editor/components/BlockMenu.tsx b/app/editor/components/BlockMenu.tsx index b88ca222c..1d82ba6c1 100644 --- a/app/editor/components/BlockMenu.tsx +++ b/app/editor/components/BlockMenu.tsx @@ -1,8 +1,8 @@ import { findParentNode } from "prosemirror-utils"; import React from "react"; import getMenuItems from "../menus/block"; -import BlockMenuItem from "./BlockMenuItem"; import CommandMenu, { Props } from "./CommandMenu"; +import CommandMenuItem from "./CommandMenuItem"; type BlockMenuProps = Omit< Props, @@ -26,7 +26,7 @@ function BlockMenu(props: BlockMenuProps) { filterable={true} onClearSearch={clearSearch} renderMenuItem={(item, _index, options) => ( - extends React.Component, State> { +class CommandMenu extends React.Component, State> { menuRef = React.createRef(); inputRef = React.createRef(); @@ -79,7 +79,7 @@ class CommandMenu extends React.Component, State> { window.addEventListener("keydown", this.handleKeyDown); } - shouldComponentUpdate(nextProps: Props, nextState: State) { + shouldComponentUpdate(nextProps: Props, nextState: State) { return ( nextProps.search !== this.props.search || nextProps.isActive !== this.props.isActive || @@ -87,7 +87,7 @@ class CommandMenu extends React.Component, State> { ); } - componentDidUpdate(prevProps: Props) { + componentDidUpdate(prevProps: Props) { if (!prevProps.isActive && this.props.isActive) { // reset scroll position to top when opening menu as the contents are // hidden, not unrendered @@ -575,7 +575,7 @@ const LinkInputWrapper = styled.div` `; const LinkInput = styled(Input)` - height: 36px; + height: 32px; width: 100%; color: ${(props) => props.theme.textSecondary}; `; @@ -584,7 +584,7 @@ const List = styled.ol` list-style: none; text-align: left; height: 100%; - padding: 8px 0; + padding: 6px; margin: 0; `; @@ -599,7 +599,7 @@ const Empty = styled.div` color: ${(props) => props.theme.textSecondary}; font-weight: 500; font-size: 14px; - height: 36px; + height: 32px; padding: 0 16px; `; @@ -630,7 +630,7 @@ export const Wrapper = styled(Scrollable)<{ box-sizing: border-box; pointer-events: none; white-space: nowrap; - width: 300px; + width: 280px; height: auto; max-height: 324px; diff --git a/app/editor/components/BlockMenuItem.tsx b/app/editor/components/CommandMenuItem.tsx similarity index 50% rename from app/editor/components/BlockMenuItem.tsx rename to app/editor/components/CommandMenuItem.tsx index ca886a34f..bda2af47e 100644 --- a/app/editor/components/BlockMenuItem.tsx +++ b/app/editor/components/CommandMenuItem.tsx @@ -1,18 +1,19 @@ import * as React from "react"; import scrollIntoView from "smooth-scroll-into-view-if-needed"; import styled from "styled-components"; +import MenuItem from "~/components/ContextMenu/MenuItem"; export type Props = { selected: boolean; disabled?: boolean; onClick: () => void; - icon?: typeof React.Component | React.FC; + icon?: React.ReactElement; title: React.ReactNode; shortcut?: string; containerId?: string; }; -function BlockMenuItem({ +function CommandMenuItem({ selected, disabled, onClick, @@ -21,8 +22,6 @@ function BlockMenuItem({ icon, containerId = "block-menu-container", }: Props) { - const Icon = icon; - const ref = React.useCallback( (node) => { if (selected && node) { @@ -43,56 +42,22 @@ function BlockMenuItem({ return ( - {Icon && ( - <> - -    - - )} {title} - {shortcut && {shortcut}} + {shortcut && {shortcut}} ); } -const Shortcut = styled.span` - color: ${(props) => props.theme.textTertiary}; +const Shortcut = styled.span<{ $active?: boolean }>` + color: ${(props) => + props.$active ? props.theme.white50 : props.theme.textTertiary}; flex-grow: 1; text-align: right; `; -const MenuItem = styled.button<{ - selected: boolean; -}>` - display: flex; - align-items: center; - justify-content: flex-start; - font-weight: 500; - font-size: 14px; - line-height: 1; - width: 100%; - height: 36px; - cursor: var(--pointer); - border: none; - opacity: ${(props) => (props.disabled ? ".5" : "1")}; - color: ${(props) => - props.selected ? props.theme.white : props.theme.textSecondary}; - background: ${(props) => (props.selected ? props.theme.primary : "none")}; - padding: 0 16px; - outline: none; - - &:active { - color: ${(props) => props.theme.white}; - background: ${(props) => (props.selected ? props.theme.primary : "none")}; - - ${Shortcut} { - color: ${(props) => props.theme.textSecondary}; - } - } -`; - -export default BlockMenuItem; +export default CommandMenuItem; diff --git a/app/editor/components/EmojiMenuItem.tsx b/app/editor/components/EmojiMenuItem.tsx index e86c0dddc..9464b21c5 100644 --- a/app/editor/components/EmojiMenuItem.tsx +++ b/app/editor/components/EmojiMenuItem.tsx @@ -1,35 +1,23 @@ import * as React from "react"; import styled from "styled-components"; -import BlockMenuItem, { Props as BlockMenuItemProps } from "./BlockMenuItem"; +import CommandMenuItem, { + Props as CommandMenuItemProps, +} from "./CommandMenuItem"; const Emoji = styled.span` font-size: 16px; + line-height: 1.6em; `; -type Props = { - emoji: React.ReactNode; - title: React.ReactNode; -}; - -const EmojiTitle = ({ emoji, title }: Props) => { - return ( -

- {emoji} -    - {title} -

- ); -}; - -type EmojiMenuItemProps = Omit & { +type EmojiMenuItemProps = Omit & { emoji: string; }; -export default function EmojiMenuItem(props: EmojiMenuItemProps) { +export default function EmojiMenuItem({ emoji, ...rest }: EmojiMenuItemProps) { return ( - } + {emoji}} /> ); } diff --git a/app/editor/components/ToolbarMenu.tsx b/app/editor/components/ToolbarMenu.tsx index 8826e34da..0b41e66cf 100644 --- a/app/editor/components/ToolbarMenu.tsx +++ b/app/editor/components/ToolbarMenu.tsx @@ -30,7 +30,6 @@ function ToolbarMenu(props: Props) { if (item.visible === false || !item.icon) { return null; } - const Icon = item.icon; const isActive = item.active ? item.active(state) : false; return ( @@ -39,7 +38,7 @@ function ToolbarMenu(props: Props) { onClick={() => item.name && commands[item.name](item.attrs)} active={isActive} > - + {React.cloneElement(item.icon, { color: "currentColor" })} ); diff --git a/app/editor/menus/block.tsx b/app/editor/menus/block.tsx index 143c28309..291526aa1 100644 --- a/app/editor/menus/block.tsx +++ b/app/editor/menus/block.tsx @@ -41,7 +41,7 @@ export default function blockMenuItems(dictionary: Dictionary): MenuItem[] { name: "heading", title: dictionary.h1, keywords: "h1 heading1 title", - icon: Heading1Icon, + icon: , shortcut: "^ ⇧ 1", attrs: { level: 1 }, }, @@ -49,7 +49,7 @@ export default function blockMenuItems(dictionary: Dictionary): MenuItem[] { name: "heading", title: dictionary.h2, keywords: "h2 heading2", - icon: Heading2Icon, + icon: , shortcut: "^ ⇧ 2", attrs: { level: 2 }, }, @@ -57,7 +57,7 @@ export default function blockMenuItems(dictionary: Dictionary): MenuItem[] { name: "heading", title: dictionary.h3, keywords: "h3 heading3", - icon: Heading3Icon, + icon: , shortcut: "^ ⇧ 3", attrs: { level: 3 }, }, @@ -67,20 +67,20 @@ export default function blockMenuItems(dictionary: Dictionary): MenuItem[] { { name: "checkbox_list", title: dictionary.checkboxList, - icon: TodoListIcon, + icon: , keywords: "checklist checkbox task", shortcut: "^ ⇧ 7", }, { name: "bullet_list", title: dictionary.bulletList, - icon: BulletedListIcon, + icon: , shortcut: "^ ⇧ 8", }, { name: "ordered_list", title: dictionary.orderedList, - icon: OrderedListIcon, + icon: , shortcut: "^ ⇧ 9", }, { @@ -89,52 +89,52 @@ export default function blockMenuItems(dictionary: Dictionary): MenuItem[] { { name: "image", title: dictionary.image, - icon: ImageIcon, + icon: , keywords: "picture photo", }, { name: "link", title: dictionary.link, - icon: LinkIcon, + icon: , shortcut: `${metaDisplay} k`, keywords: "link url uri href", }, { name: "attachment", title: dictionary.file, - icon: AttachmentIcon, + icon: , keywords: "file upload attach", }, { name: "table", title: dictionary.table, - icon: TableIcon, + icon: , attrs: { rowsCount: 3, colsCount: 3 }, }, { name: "blockquote", title: dictionary.quote, - icon: BlockQuoteIcon, + icon: , shortcut: `${metaDisplay} ]`, }, { name: "code_block", title: dictionary.codeBlock, - icon: CodeIcon, + icon: , shortcut: "^ ⇧ \\", keywords: "script", }, { name: "hr", title: dictionary.hr, - icon: HorizontalRuleIcon, + icon: , shortcut: `${metaDisplay} _`, keywords: "horizontal rule break line", }, { name: "hr", title: dictionary.pageBreak, - icon: PageBreakIcon, + icon: , keywords: "page print break line", attrs: { markup: "***" }, }, @@ -142,19 +142,19 @@ export default function blockMenuItems(dictionary: Dictionary): MenuItem[] { name: "date", title: dictionary.insertDate, keywords: "clock", - icon: CalendarIcon, + icon: , }, { name: "time", title: dictionary.insertTime, keywords: "clock", - icon: ClockIcon, + icon: , }, { name: "datetime", title: dictionary.insertDateTime, keywords: "clock", - icon: CalendarIcon, + icon: , }, { name: "separator", @@ -162,21 +162,21 @@ export default function blockMenuItems(dictionary: Dictionary): MenuItem[] { { name: "container_notice", title: dictionary.infoNotice, - icon: InfoIcon, + icon: , keywords: "notice card information", attrs: { style: "info" }, }, { name: "container_notice", title: dictionary.warningNotice, - icon: WarningIcon, + icon: , keywords: "notice card error", attrs: { style: "warning" }, }, { name: "container_notice", title: dictionary.tipNotice, - icon: StarredIcon, + icon: , keywords: "notice card suggestion", attrs: { style: "tip" }, }, @@ -186,7 +186,7 @@ export default function blockMenuItems(dictionary: Dictionary): MenuItem[] { { name: "code_block", title: "Mermaid Diagram", - icon: () => Mermaid Diagram, + icon: Mermaid Diagram, keywords: "diagram flowchart", attrs: { language: "mermaidjs" }, }, diff --git a/app/editor/menus/divider.tsx b/app/editor/menus/divider.tsx index 5747300e8..8a9576004 100644 --- a/app/editor/menus/divider.tsx +++ b/app/editor/menus/divider.tsx @@ -1,5 +1,6 @@ import { PageBreakIcon, HorizontalRuleIcon } from "outline-icons"; import { EditorState } from "prosemirror-state"; +import * as React from "react"; import isNodeActive from "@shared/editor/queries/isNodeActive"; import { MenuItem } from "@shared/editor/types"; import { Dictionary } from "~/hooks/useDictionary"; @@ -16,14 +17,14 @@ export default function dividerMenuItems( tooltip: dictionary.pageBreak, attrs: { markup: "***" }, active: isNodeActive(schema.nodes.hr, { markup: "***" }), - icon: PageBreakIcon, + icon: , }, { name: "hr", tooltip: dictionary.hr, attrs: { markup: "---" }, active: isNodeActive(schema.nodes.hr, { markup: "---" }), - icon: HorizontalRuleIcon, + icon: , }, ]; } diff --git a/app/editor/menus/formatting.ts b/app/editor/menus/formatting.tsx similarity index 85% rename from app/editor/menus/formatting.ts rename to app/editor/menus/formatting.tsx index 369506461..b603642d2 100644 --- a/app/editor/menus/formatting.ts +++ b/app/editor/menus/formatting.tsx @@ -11,9 +11,11 @@ import { TodoListIcon, InputIcon, HighlightIcon, + ItalicIcon, } from "outline-icons"; import { EditorState } from "prosemirror-state"; import { isInTable } from "prosemirror-tables"; +import * as React from "react"; import isInCode from "@shared/editor/queries/isInCode"; import isInList from "@shared/editor/queries/isInList"; import isMarkActive from "@shared/editor/queries/isMarkActive"; @@ -36,7 +38,7 @@ export default function formattingMenuItems( { name: "placeholder", tooltip: dictionary.placeholder, - icon: InputIcon, + icon: , active: isMarkActive(schema.marks.placeholder), visible: isTemplate, }, @@ -47,28 +49,35 @@ export default function formattingMenuItems( { name: "strong", tooltip: dictionary.strong, - icon: BoldIcon, + icon: , active: isMarkActive(schema.marks.strong), visible: !isCode, }, + { + name: "em", + tooltip: dictionary.em, + icon: , + active: isMarkActive(schema.marks.em), + visible: !isCode, + }, { name: "strikethrough", tooltip: dictionary.strikethrough, - icon: StrikethroughIcon, + icon: , active: isMarkActive(schema.marks.strikethrough), visible: !isCode, }, { name: "highlight", tooltip: dictionary.mark, - icon: HighlightIcon, + icon: , active: isMarkActive(schema.marks.highlight), visible: !isTemplate && !isCode, }, { name: "code_inline", tooltip: dictionary.codeInline, - icon: CodeIcon, + icon: , active: isMarkActive(schema.marks.code_inline), }, { @@ -78,7 +87,7 @@ export default function formattingMenuItems( { name: "heading", tooltip: dictionary.heading, - icon: Heading1Icon, + icon: , active: isNodeActive(schema.nodes.heading, { level: 1 }), attrs: { level: 1 }, visible: allowBlocks && !isCode, @@ -86,7 +95,7 @@ export default function formattingMenuItems( { name: "heading", tooltip: dictionary.subheading, - icon: Heading2Icon, + icon: , active: isNodeActive(schema.nodes.heading, { level: 2 }), attrs: { level: 2 }, visible: allowBlocks && !isCode, @@ -94,7 +103,7 @@ export default function formattingMenuItems( { name: "blockquote", tooltip: dictionary.quote, - icon: BlockQuoteIcon, + icon: , active: isNodeActive(schema.nodes.blockquote), attrs: { level: 2 }, visible: allowBlocks && !isCode, @@ -106,7 +115,7 @@ export default function formattingMenuItems( { name: "checkbox_list", tooltip: dictionary.checkboxList, - icon: TodoListIcon, + icon: , keywords: "checklist checkbox task", active: isNodeActive(schema.nodes.checkbox_list), visible: (allowBlocks || isList) && !isCode, @@ -114,14 +123,14 @@ export default function formattingMenuItems( { name: "bullet_list", tooltip: dictionary.bulletList, - icon: BulletedListIcon, + icon: , active: isNodeActive(schema.nodes.bullet_list), visible: (allowBlocks || isList) && !isCode, }, { name: "ordered_list", tooltip: dictionary.orderedList, - icon: OrderedListIcon, + icon: , active: isNodeActive(schema.nodes.ordered_list), visible: (allowBlocks || isList) && !isCode, }, @@ -132,7 +141,7 @@ export default function formattingMenuItems( { name: "link", tooltip: dictionary.createLink, - icon: LinkIcon, + icon: , active: isMarkActive(schema.marks.link), attrs: { href: "" }, visible: !isCode, diff --git a/app/editor/menus/image.tsx b/app/editor/menus/image.tsx index a7c9947d8..0518addd4 100644 --- a/app/editor/menus/image.tsx +++ b/app/editor/menus/image.tsx @@ -7,6 +7,7 @@ import { AlignImageCenterIcon, } from "outline-icons"; import { EditorState } from "prosemirror-state"; +import * as React from "react"; import isNodeActive from "@shared/editor/queries/isNodeActive"; import { MenuItem } from "@shared/editor/types"; import { Dictionary } from "~/hooks/useDictionary"; @@ -27,14 +28,14 @@ export default function imageMenuItems( { name: "alignLeft", tooltip: dictionary.alignLeft, - icon: AlignImageLeftIcon, + icon: , visible: true, active: isLeftAligned, }, { name: "alignCenter", tooltip: dictionary.alignCenter, - icon: AlignImageCenterIcon, + icon: , visible: true, active: (state) => isNodeActive(schema.nodes.image)(state) && @@ -44,7 +45,7 @@ export default function imageMenuItems( { name: "alignRight", tooltip: dictionary.alignRight, - icon: AlignImageRightIcon, + icon: , visible: true, active: isRightAligned, }, @@ -55,21 +56,21 @@ export default function imageMenuItems( { name: "downloadImage", tooltip: dictionary.downloadImage, - icon: DownloadIcon, + icon: , visible: !!fetch, active: () => false, }, { name: "replaceImage", tooltip: dictionary.replaceImage, - icon: ReplaceIcon, + icon: , visible: true, active: () => false, }, { name: "deleteImage", tooltip: dictionary.deleteImage, - icon: TrashIcon, + icon: , visible: true, active: () => false, }, diff --git a/app/editor/menus/table.tsx b/app/editor/menus/table.tsx index 0e38a8239..dc0cd649c 100644 --- a/app/editor/menus/table.tsx +++ b/app/editor/menus/table.tsx @@ -1,4 +1,5 @@ import { TrashIcon } from "outline-icons"; +import * as React from "react"; import { MenuItem } from "@shared/editor/types"; import { Dictionary } from "~/hooks/useDictionary"; @@ -7,7 +8,7 @@ export default function tableMenuItems(dictionary: Dictionary): MenuItem[] { { name: "deleteTable", tooltip: dictionary.deleteTable, - icon: TrashIcon, + icon: , active: () => false, }, ]; diff --git a/app/editor/menus/tableCol.tsx b/app/editor/menus/tableCol.tsx index 3fa0774f4..b2511016c 100644 --- a/app/editor/menus/tableCol.tsx +++ b/app/editor/menus/tableCol.tsx @@ -7,6 +7,7 @@ import { InsertRightIcon, } from "outline-icons"; import { EditorState } from "prosemirror-state"; +import * as React from "react"; import isNodeActive from "@shared/editor/queries/isNodeActive"; import { MenuItem } from "@shared/editor/types"; import { Dictionary } from "~/hooks/useDictionary"; @@ -23,7 +24,7 @@ export default function tableColMenuItems( { name: "setColumnAttr", tooltip: dictionary.alignLeft, - icon: AlignLeftIcon, + icon: , attrs: { index, alignment: "left" }, active: isNodeActive(schema.nodes.th, { colspan: 1, @@ -34,7 +35,7 @@ export default function tableColMenuItems( { name: "setColumnAttr", tooltip: dictionary.alignCenter, - icon: AlignCenterIcon, + icon: , attrs: { index, alignment: "center" }, active: isNodeActive(schema.nodes.th, { colspan: 1, @@ -45,7 +46,7 @@ export default function tableColMenuItems( { name: "setColumnAttr", tooltip: dictionary.alignRight, - icon: AlignRightIcon, + icon: , attrs: { index, alignment: "right" }, active: isNodeActive(schema.nodes.th, { colspan: 1, @@ -59,13 +60,13 @@ export default function tableColMenuItems( { name: rtl ? "addColumnAfter" : "addColumnBefore", tooltip: rtl ? dictionary.addColumnAfter : dictionary.addColumnBefore, - icon: InsertLeftIcon, + icon: , active: () => false, }, { name: rtl ? "addColumnBefore" : "addColumnAfter", tooltip: rtl ? dictionary.addColumnBefore : dictionary.addColumnAfter, - icon: InsertRightIcon, + icon: , active: () => false, }, { @@ -74,7 +75,7 @@ export default function tableColMenuItems( { name: "deleteColumn", tooltip: dictionary.deleteColumn, - icon: TrashIcon, + icon: , active: () => false, }, ]; diff --git a/app/editor/menus/tableRow.tsx b/app/editor/menus/tableRow.tsx index cc2cb3df7..38852e21a 100644 --- a/app/editor/menus/tableRow.tsx +++ b/app/editor/menus/tableRow.tsx @@ -1,5 +1,6 @@ import { TrashIcon, InsertAboveIcon, InsertBelowIcon } from "outline-icons"; import { EditorState } from "prosemirror-state"; +import * as React from "react"; import { MenuItem } from "@shared/editor/types"; import { Dictionary } from "~/hooks/useDictionary"; @@ -12,7 +13,7 @@ export default function tableRowMenuItems( { name: "addRowAfter", tooltip: dictionary.addRowBefore, - icon: InsertAboveIcon, + icon: , attrs: { index: index - 1 }, active: () => false, visible: index !== 0, @@ -20,7 +21,7 @@ export default function tableRowMenuItems( { name: "addRowAfter", tooltip: dictionary.addRowAfter, - icon: InsertBelowIcon, + icon: , attrs: { index }, active: () => false, }, @@ -30,7 +31,7 @@ export default function tableRowMenuItems( { name: "deleteRow", tooltip: dictionary.deleteRow, - icon: TrashIcon, + icon: , active: () => false, }, ]; diff --git a/app/scenes/Document/components/Document.tsx b/app/scenes/Document/components/Document.tsx index 632ae139a..091a7b027 100644 --- a/app/scenes/Document/components/Document.tsx +++ b/app/scenes/Document/components/Document.tsx @@ -677,7 +677,6 @@ const MaxWidth = styled(Flex)` padding-bottom: 16px; ${breakpoint("tablet")` - padding: 0 44px; margin: 4px auto 12px; max-width: ${(props: MaxWidthProps) => props.isFullWidth diff --git a/shared/editor/components/DisabledEmbed.tsx b/shared/editor/components/DisabledEmbed.tsx index 71576cadd..409667b75 100644 --- a/shared/editor/components/DisabledEmbed.tsx +++ b/shared/editor/components/DisabledEmbed.tsx @@ -9,7 +9,7 @@ export default function DisabledEmbed(props: Props & ThemeProps) { ; + icon?: React.ReactNode; name?: string; title?: string; shortcut?: string; @@ -127,264 +127,262 @@ const embeds: EmbedDescriptor[] = [ title: "Abstract", keywords: "design", defaultHidden: true, - icon: () => Abstract, + icon: Abstract, component: Abstract, }), new EmbedDescriptor({ title: "Airtable", keywords: "spreadsheet", - icon: () => Airtable, + icon: Airtable, component: Airtable, }), new EmbedDescriptor({ title: "Berrycast", keywords: "video", defaultHidden: true, - icon: () => Berrycast, + icon: Berrycast, component: Berrycast, }), new EmbedDescriptor({ title: "Bilibili", keywords: "video", defaultHidden: true, - icon: () => Bilibili, + icon: Bilibili, component: Bilibili, }), new EmbedDescriptor({ title: "Cawemo", keywords: "bpmn process", defaultHidden: true, - icon: () => Cawemo, + icon: Cawemo, component: Cawemo, }), new EmbedDescriptor({ title: "ClickUp", keywords: "project", - icon: () => ClickUp, + icon: ClickUp, component: ClickUp, }), new EmbedDescriptor({ title: "Codepen", keywords: "code editor", - icon: () => Codepen, + icon: Codepen, component: Codepen, }), new EmbedDescriptor({ title: "DBDiagram", keywords: "diagrams database", - icon: () => DBDiagram, + icon: DBDiagram, component: DBDiagram, }), new EmbedDescriptor({ title: "Descript", keywords: "audio", - icon: () => Descript, + icon: Descript, component: Descript, }), new EmbedDescriptor({ title: "Figma", keywords: "design svg vector", - icon: () => Figma, + icon: Figma, component: Figma, }), new EmbedDescriptor({ title: "Framer", keywords: "design prototyping", - icon: () => Framer, + icon: Framer, component: Framer, }), new EmbedDescriptor({ title: "GitHub Gist", keywords: "code", - icon: () => GitHub, + icon: GitHub, component: Gist, }), new EmbedDescriptor({ title: "Gliffy", keywords: "diagram", - icon: () => Gliffy, + icon: Gliffy, component: Gliffy, }), new EmbedDescriptor({ title: "Diagrams.net", keywords: "diagrams drawio", - icon: () => Diagrams.net, + icon: Diagrams.net, component: Diagrams, }), new EmbedDescriptor({ title: "Google Drawings", keywords: "drawings", - icon: () => Google Drawings, + icon: Google Drawings, component: GoogleDrawings, }), new EmbedDescriptor({ title: "Google Drive", keywords: "drive", - icon: () => Google Drive, + icon: Google Drive, component: GoogleDrive, }), new EmbedDescriptor({ title: "Google Docs", keywords: "documents word", - icon: () => Google Docs, + icon: Google Docs, component: GoogleDocs, }), new EmbedDescriptor({ title: "Google Sheets", keywords: "excel spreadsheet", - icon: () => Google Sheets, + icon: Google Sheets, component: GoogleSheets, }), new EmbedDescriptor({ title: "Google Slides", keywords: "presentation slideshow", - icon: () => Google Slides, + icon: Google Slides, component: GoogleSlides, }), new EmbedDescriptor({ title: "Google Calendar", keywords: "calendar", - icon: () => Google Calendar, + icon: Google Calendar, component: GoogleCalendar, }), new EmbedDescriptor({ title: "Google Data Studio", keywords: "bi business intelligence", - icon: () => ( - Google Data Studio - ), + icon: Google Data Studio, component: GoogleDataStudio, }), new EmbedDescriptor({ title: "Google Forms", keywords: "form survey", - icon: () => Google Forms, + icon: Google Forms, component: GoogleForms, }), new EmbedDescriptor({ title: "Grist", keywords: "spreadsheet", - icon: () => Grist, + icon: Grist, component: Grist, }), new EmbedDescriptor({ title: "InVision", keywords: "design prototype", defaultHidden: true, - icon: () => InVision, + icon: InVision, component: InVision, }), new EmbedDescriptor({ title: "JSFiddle", keywords: "code", defaultHidden: true, - icon: () => JSFiddle, + icon: JSFiddle, component: JSFiddle, }), new EmbedDescriptor({ title: "Loom", keywords: "video screencast", - icon: () => Loom, + icon: Loom, component: Loom, }), new EmbedDescriptor({ title: "Lucidchart", keywords: "chart", - icon: () => Lucidchart, + icon: Lucidchart, component: Lucidchart, }), new EmbedDescriptor({ title: "Marvel", keywords: "design prototype", - icon: () => Marvel, + icon: Marvel, component: Marvel, }), new EmbedDescriptor({ title: "Mindmeister", keywords: "mindmap", - icon: () => Mindmeister, + icon: Mindmeister, component: Mindmeister, }), new EmbedDescriptor({ title: "Miro", keywords: "whiteboard", - icon: () => Miro, + icon: Miro, component: Miro, }), new EmbedDescriptor({ title: "Mode", keywords: "analytics", defaultHidden: true, - icon: () => Mode, + icon: Mode, component: ModeAnalytics, }), new EmbedDescriptor({ title: "Otter.ai", keywords: "audio transcription meeting notes", defaultHidden: true, - icon: () => Otter.ai, + icon: Otter.ai, component: Otter, }), new EmbedDescriptor({ title: "Pitch", keywords: "presentation", defaultHidden: true, - icon: () => Pitch, + icon: Pitch, component: Pitch, }), new EmbedDescriptor({ title: "Prezi", keywords: "presentation", - icon: () => Prezi, + icon: Prezi, component: Prezi, }), new EmbedDescriptor({ title: "Scribe", keywords: "screencast", - icon: () => Scribe, + icon: Scribe, component: Scribe, }), new EmbedDescriptor({ title: "Spotify", keywords: "music", - icon: () => Spotify, + icon: Spotify, component: Spotify, }), new EmbedDescriptor({ title: "Tldraw", keywords: "draw schematics diagrams", visible: false, - icon: () => Tldraw, + icon: Tldraw, component: Tldraw, }), new EmbedDescriptor({ title: "Trello", keywords: "kanban", - icon: () => Trello, + icon: Trello, component: Trello, }), new EmbedDescriptor({ title: "Typeform", keywords: "form survey", - icon: () => Typeform, + icon: Typeform, component: Typeform, }), new EmbedDescriptor({ title: "Vimeo", keywords: "video", - icon: () => Vimeo, + icon: Vimeo, component: Vimeo, }), new EmbedDescriptor({ title: "Whimsical", keywords: "whiteboard", - icon: () => Whimsical, + icon: Whimsical, component: Whimsical, }), new EmbedDescriptor({ title: "YouTube", keywords: "google video", - icon: () => YouTube, + icon: YouTube, component: YouTube, }), ]; diff --git a/shared/editor/lib/filterExcessSeparators.ts b/shared/editor/lib/filterExcessSeparators.ts index 0f92e9131..ec2684332 100644 --- a/shared/editor/lib/filterExcessSeparators.ts +++ b/shared/editor/lib/filterExcessSeparators.ts @@ -3,7 +3,9 @@ import { MenuItem } from "../types"; type Item = MenuItem | EmbedDescriptor; -export default function filterExcessSeparators(items: Item[]): Item[] { +export default function filterExcessSeparators( + items: T[] +): T[] { return items .reduce((acc, item) => { // trim separator if the previous item was a separator @@ -14,7 +16,7 @@ export default function filterExcessSeparators(items: Item[]): Item[] { return acc; } return [...acc, item]; - }, [] as Item[]) + }, [] as T[]) .filter((item, index, arr) => { if ( item.name === "separator" && diff --git a/shared/editor/types/index.ts b/shared/editor/types/index.ts index 0f6bf5f77..6b75544ef 100644 --- a/shared/editor/types/index.ts +++ b/shared/editor/types/index.ts @@ -15,7 +15,7 @@ export enum EventType { } export type MenuItem = { - icon?: typeof React.Component | React.FC; + icon?: React.ReactElement; name?: string; title?: string; shortcut?: string;