chore: Move collection sort control (#1762)

* feat: Move collection sort menu

* fix: Improve accessibility

* fix: Dedupe outline-icons (temporary until rme is next merged)
This commit is contained in:
Tom Moor
2021-01-02 19:11:13 -08:00
committed by GitHub
parent eda5adca2c
commit 611e9b97b3
9 changed files with 121 additions and 58 deletions

View File

@@ -27,9 +27,7 @@ const DropdownMenuItem = ({
>
{selected !== undefined && (
<>
<CheckmarkIcon
color={selected === false ? "transparent" : undefined}
/>
{selected ? <CheckmarkIcon /> : <Spacer />}
&nbsp;
</>
)}
@@ -38,6 +36,11 @@ const DropdownMenuItem = ({
);
};
const Spacer = styled.div`
width: 24px;
height: 24px;
`;
const MenuItem = styled.a`
display: flex;
margin: 0;

View File

@@ -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={
<EditableTitle
@@ -94,12 +97,22 @@ function CollectionLink({
}
exact={false}
menu={
<CollectionMenu
position="right"
collection={collection}
onOpen={() => setMenuOpen(true)}
onClose={() => setMenuOpen(false)}
/>
<>
{can.update && (
<CollectionSortMenuWithMargin
position="right"
collection={collection}
onOpen={() => setMenuOpen(true)}
onClose={() => setMenuOpen(false)}
/>
)}
<CollectionMenu
position="right"
collection={collection}
onOpen={() => setMenuOpen(true)}
onClose={() => setMenuOpen(false)}
/>
</>
}
></SidebarLink>
</DropToImport>
@@ -125,4 +138,8 @@ function CollectionLink({
);
}
const CollectionSortMenuWithMargin = styled(CollectionSortMenu)`
margin-right: 4px;
`;
export default observer(CollectionLink);

View File

@@ -237,7 +237,7 @@ function DocumentLink({
isActiveDrop={isOverReparent && canDropToReparent}
depth={depth}
exact={false}
menuOpen={menuOpen}
showActions={menuOpen}
menu={
document && !isMoving ? (
<Fade>

View File

@@ -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 && <IconWrapper>{icon}</IconWrapper>}
<Label>{label}</Label>
{menu && <Action menuOpen={menuOpen}>{menu}</Action>}
{menu && <Actions showActions={showActions}>{menu}</Actions>}
</StyledNavLink>
);
}
@@ -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;
}
}
`;

View File

@@ -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<Props> {
}
};
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<Props> {
documents,
collection,
position,
showSort,
onOpen,
onClose,
t,
@@ -187,28 +176,6 @@ class CollectionMenu extends React.Component<Props> {
{
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",
},

View File

@@ -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 (
<DropdownMenu
onOpen={onOpen}
onClose={onClose}
label={
<NudeButton aria-label={t("Sidebar sort")} aria-haspopup="true">
{alphabeticalSort ? <AlphabeticSortIcon /> : <ManualSortIcon />}
</NudeButton>
}
position={position}
{...rest}
>
<DropdownMenuItems
items={[
{
title: t("Alphabetical sort"),
onClick: () => handleChangeSort("title"),
selected: alphabeticalSort,
},
{
title: t("Manual sort"),
onClick: () => handleChangeSort("index"),
selected: !alphabeticalSort,
},
]}
/>
</DropdownMenu>
);
}
export default observer(CollectionSortMenu);

View File

@@ -164,7 +164,7 @@ class CollectionScene extends React.Component<Props> {
</>
)}
<Action>
<CollectionMenu collection={this.collection} showSort={false} />
<CollectionMenu collection={this.collection} />
</Action>
</Actions>
);

View File

@@ -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"
},

View File

@@ -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"