diff --git a/app/components/DropdownMenu/DropdownMenuItem.js b/app/components/DropdownMenu/DropdownMenuItem.js index d455ffdae..95269e1d2 100644 --- a/app/components/DropdownMenu/DropdownMenuItem.js +++ b/app/components/DropdownMenu/DropdownMenuItem.js @@ -27,9 +27,7 @@ const DropdownMenuItem = ({ > {selected !== undefined && ( <> - + {selected ? : }   )} @@ -38,6 +36,11 @@ const DropdownMenuItem = ({ ); }; +const Spacer = styled.div` + width: 24px; + height: 24px; +`; + const MenuItem = styled.a` display: flex; margin: 0; diff --git a/app/components/Sidebar/components/CollectionLink.js b/app/components/Sidebar/components/CollectionLink.js index 6a2759cab..7852ae59e 100644 --- a/app/components/Sidebar/components/CollectionLink.js +++ b/app/components/Sidebar/components/CollectionLink.js @@ -2,6 +2,7 @@ import { observer } from "mobx-react"; import * as React from "react"; import { useDrop } from "react-dnd"; +import styled from "styled-components"; import UiStore from "stores/UiStore"; import Collection from "models/Collection"; import Document from "models/Document"; @@ -13,6 +14,7 @@ import EditableTitle from "./EditableTitle"; import SidebarLink from "./SidebarLink"; import useStores from "hooks/useStores"; import CollectionMenu from "menus/CollectionMenu"; +import CollectionSortMenu from "menus/CollectionSortMenu"; type Props = {| collection: Collection, @@ -41,6 +43,7 @@ function CollectionLink({ const { documents, policies } = useStores(); const expanded = collection.id === ui.activeCollectionId; const manualSort = collection.sort.field === "index"; + const can = policies.abilities(collection.id); // Drop to re-parent const [{ isOver, canDrop }, drop] = useDrop({ @@ -83,7 +86,7 @@ function CollectionLink({ } iconColor={collection.color} expanded={expanded} - menuOpen={menuOpen} + showActions={menuOpen || expanded} isActiveDrop={isOver && canDrop} label={ setMenuOpen(true)} - onClose={() => setMenuOpen(false)} - /> + <> + {can.update && ( + setMenuOpen(true)} + onClose={() => setMenuOpen(false)} + /> + )} + setMenuOpen(true)} + onClose={() => setMenuOpen(false)} + /> + } > @@ -125,4 +138,8 @@ function CollectionLink({ ); } +const CollectionSortMenuWithMargin = styled(CollectionSortMenu)` + margin-right: 4px; +`; + export default observer(CollectionLink); diff --git a/app/components/Sidebar/components/DocumentLink.js b/app/components/Sidebar/components/DocumentLink.js index d94d2cd4a..c245e9269 100644 --- a/app/components/Sidebar/components/DocumentLink.js +++ b/app/components/Sidebar/components/DocumentLink.js @@ -237,7 +237,7 @@ function DocumentLink({ isActiveDrop={isOverReparent && canDropToReparent} depth={depth} exact={false} - menuOpen={menuOpen} + showActions={menuOpen} menu={ document && !isMoving ? ( diff --git a/app/components/Sidebar/components/SidebarLink.js b/app/components/Sidebar/components/SidebarLink.js index b31c68d0a..6b670d521 100644 --- a/app/components/Sidebar/components/SidebarLink.js +++ b/app/components/Sidebar/components/SidebarLink.js @@ -14,7 +14,7 @@ type Props = { icon?: React.Node, label?: React.Node, menu?: React.Node, - menuOpen?: boolean, + showActions?: boolean, iconColor?: string, active?: boolean, isActiveDrop?: boolean, @@ -33,7 +33,7 @@ function SidebarLink({ active, isActiveDrop, menu, - menuOpen, + showActions, theme, exact, href, @@ -73,7 +73,7 @@ function SidebarLink({ > {icon && {icon}} - {menu && {menu}} + {menu && {menu}} ); } @@ -85,12 +85,14 @@ const IconWrapper = styled.span` height: 24px; `; -const Action = styled.span` - display: ${(props) => (props.menuOpen ? "inline" : "none")}; +const Actions = styled.span` + display: ${(props) => (props.showActions ? "inline-flex" : "none")}; position: absolute; top: 4px; right: 4px; color: ${(props) => props.theme.textTertiary}; + opacity: 0.75; + transition: opacity 50ms; svg { opacity: 0.75; @@ -133,9 +135,11 @@ const StyledNavLink = styled(NavLink)` background: ${(props) => props.theme.black05}; } - &:hover { - > ${Action} { - display: inline; + &:hover, + &:active { + > ${Actions} { + opacity: 1; + display: inline-flex; } } `; diff --git a/app/menus/CollectionMenu.js b/app/menus/CollectionMenu.js index 4d29bb70b..0dc69b56d 100644 --- a/app/menus/CollectionMenu.js +++ b/app/menus/CollectionMenu.js @@ -26,7 +26,6 @@ type Props = { documents: DocumentsStore, collection: Collection, history: RouterHistory, - showSort?: boolean, onOpen?: () => void, onClose?: () => void, t: TFunction, @@ -71,15 +70,6 @@ class CollectionMenu extends React.Component { } }; - handleChangeSort = (field: string) => { - return this.props.collection.save({ - sort: { - field, - direction: "asc", - }, - }); - }; - handleEditCollectionOpen = (ev: SyntheticEvent<>) => { ev.preventDefault(); this.showCollectionEdit = true; @@ -122,7 +112,6 @@ class CollectionMenu extends React.Component { documents, collection, position, - showSort, onOpen, onClose, t, @@ -187,28 +176,6 @@ class CollectionMenu extends React.Component { { type: "separator", }, - { - title: t("Sort in sidebar"), - visible: can.update && showSort, - hover: true, - style: { - left: 170, - position: "relative", - top: -40, - }, - items: [ - { - title: t("Alphabetical"), - onClick: () => this.handleChangeSort("title"), - selected: collection.sort.field === "title", - }, - { - title: t("Manual sort"), - onClick: () => this.handleChangeSort("index"), - selected: collection.sort.field === "index", - }, - ], - }, { type: "separator", }, diff --git a/app/menus/CollectionSortMenu.js b/app/menus/CollectionSortMenu.js new file mode 100644 index 000000000..ef35ec2c3 --- /dev/null +++ b/app/menus/CollectionSortMenu.js @@ -0,0 +1,71 @@ +// @flow +import { observer } from "mobx-react"; +import { AlphabeticSortIcon, ManualSortIcon } from "outline-icons"; +import * as React from "react"; +import { useTranslation } from "react-i18next"; +import Collection from "models/Collection"; +import { DropdownMenu } from "components/DropdownMenu"; +import DropdownMenuItems from "components/DropdownMenu/DropdownMenuItems"; +import NudeButton from "components/NudeButton"; + +type Props = { + position?: "left" | "right" | "center", + collection: Collection, + onOpen?: () => void, + onClose?: () => void, +}; + +function CollectionSortMenu({ + collection, + position, + onOpen, + onClose, + ...rest +}: Props) { + const { t } = useTranslation(); + + const handleChangeSort = React.useCallback( + (field: string) => { + return collection.save({ + sort: { + field, + direction: "asc", + }, + }); + }, + [collection] + ); + + const alphabeticalSort = collection.sort.field === "title"; + + return ( + + {alphabeticalSort ? : } + + } + position={position} + {...rest} + > + handleChangeSort("title"), + selected: alphabeticalSort, + }, + { + title: t("Manual sort"), + onClick: () => handleChangeSort("index"), + selected: !alphabeticalSort, + }, + ]} + /> + + ); +} + +export default observer(CollectionSortMenu); diff --git a/app/scenes/Collection.js b/app/scenes/Collection.js index c9468f987..69e3b07e2 100644 --- a/app/scenes/Collection.js +++ b/app/scenes/Collection.js @@ -164,7 +164,7 @@ class CollectionScene extends React.Component { )} - + ); diff --git a/package.json b/package.json index 450ee6e9e..3e9abbe1c 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,7 @@ "mobx-react": "^6.2.5", "natural-sort": "^1.0.0", "nodemailer": "^4.4.0", - "outline-icons": "^1.21.0", + "outline-icons": "^1.23.0-1", "oy-vey": "^0.10.0", "pg": "^8.5.1", "pg-hstore": "^2.3.3", @@ -205,6 +205,7 @@ "webpack-manifest-plugin": "^2.2.0" }, "resolutions": { + "outline-icons": "1.23.0-1", "dot-prop": "^5.2.0", "js-yaml": "^3.13.1" }, diff --git a/yarn.lock b/yarn.lock index 539012a30..e1b2d12bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8861,10 +8861,10 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -outline-icons@^1.21.0: - version "1.21.0" - resolved "https://registry.yarnpkg.com/outline-icons/-/outline-icons-1.21.0.tgz#3e85b7959d0864adbf9a0362ded8fb64bcdcb10f" - integrity sha512-EHLv1cpIKzFiGdavSbn5VD3MQRTKpHINFQktm4ZZL42Me2cDj30WMBeMmXjHqOZls0WJNuhCQSYfa7E5ECKR+g== +outline-icons@1.23.0-1, outline-icons@^1.21.0, outline-icons@^1.23.0-1: + version "1.23.0-1" + resolved "https://registry.yarnpkg.com/outline-icons/-/outline-icons-1.23.0-1.tgz#40811d54d55d43751128853ee87babafb0ae42ee" + integrity sha512-E/XYmLj/2AS7iR+CtD8IAMIeQPaZoiFLNYGXuKbJIYzjmkmdxWUAIHoWJ8lzBs8rWT4FMmEsv8VOWnmPjH5eig== oy-vey@^0.10.0: version "0.10.0"