Change "Move" dialog appearance to match that of "Publish" dialog (#4787)
* refactor: receive items as props in DocumentExplore * refactor: leverage DocumentExplorer for DocumentMove * fix: keyboard shortcut for moving document * refactor: cleanup * Revert "refactor: cleanup" This reverts commit 9a0a98eff22934aeffa48d0bf899629b6e61617c. * fix: get rid of extra parent container * Revert "fix: get rid of extra parent container" This reverts commit 908eaf2bba5c8d6d1f4eeeaeb9674bc906af08f4. * refactor: remove PathToDocument component
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import FuzzySearch from "fuzzy-search";
|
||||
import { includes, difference, concat, filter, flatten } from "lodash";
|
||||
import { includes, difference, concat, filter } from "lodash";
|
||||
import { observer } from "mobx-react";
|
||||
import { StarredIcon, DocumentIcon } from "outline-icons";
|
||||
import * as React from "react";
|
||||
@@ -18,11 +18,10 @@ import EmojiIcon from "~/components/Icons/EmojiIcon";
|
||||
import { Outline } from "~/components/Input";
|
||||
import InputSearch from "~/components/InputSearch";
|
||||
import Text from "~/components/Text";
|
||||
import useCollectionTrees from "~/hooks/useCollectionTrees";
|
||||
import useMobile from "~/hooks/useMobile";
|
||||
import useStores from "~/hooks/useStores";
|
||||
import { isModKey } from "~/utils/keyboard";
|
||||
import { flattenTree, ancestors, descendants } from "~/utils/tree";
|
||||
import { ancestors, descendants } from "~/utils/tree";
|
||||
|
||||
type Props = {
|
||||
/** Action taken upon submission of selected item, could be publish, move etc. */
|
||||
@@ -30,14 +29,16 @@ type Props = {
|
||||
|
||||
/** A side-effect of item selection */
|
||||
onSelect: (item: NavigationNode | null) => void;
|
||||
|
||||
/** Items to be shown in explorer */
|
||||
items: NavigationNode[];
|
||||
};
|
||||
|
||||
function DocumentExplorer({ onSubmit, onSelect }: Props) {
|
||||
function DocumentExplorer({ onSubmit, onSelect, items }: Props) {
|
||||
const isMobile = useMobile();
|
||||
const { collections, documents } = useStores();
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const collectionTrees = useCollectionTrees();
|
||||
|
||||
const [searchTerm, setSearchTerm] = React.useState<string>();
|
||||
const [selectedNode, selectNode] = React.useState<NavigationNode | null>(
|
||||
@@ -58,16 +59,11 @@ function DocumentExplorer({ onSubmit, onSelect }: Props) {
|
||||
const VERTICAL_PADDING = 6;
|
||||
const HORIZONTAL_PADDING = 24;
|
||||
|
||||
const allNodes = React.useMemo(
|
||||
() => flatten(collectionTrees.map(flattenTree)),
|
||||
[collectionTrees]
|
||||
);
|
||||
|
||||
const searchIndex = React.useMemo(() => {
|
||||
return new FuzzySearch(allNodes, ["title"], {
|
||||
return new FuzzySearch(items, ["title"], {
|
||||
caseSensitive: false,
|
||||
});
|
||||
}, [allNodes]);
|
||||
}, [items]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (searchTerm) {
|
||||
@@ -83,12 +79,12 @@ function DocumentExplorer({ onSubmit, onSelect }: Props) {
|
||||
if (searchTerm) {
|
||||
results = searchIndex.search(searchTerm);
|
||||
} else {
|
||||
results = allNodes.filter((r) => r.type === "collection");
|
||||
results = items.filter((item) => item.type === "collection");
|
||||
}
|
||||
|
||||
setInitialScrollOffset(0);
|
||||
setNodes(results);
|
||||
}, [searchTerm, allNodes, searchIndex]);
|
||||
}, [searchTerm, items, searchIndex]);
|
||||
|
||||
React.useEffect(() => {
|
||||
onSelect(selectedNode);
|
||||
@@ -148,7 +144,14 @@ function DocumentExplorer({ onSubmit, onSelect }: Props) {
|
||||
return selectedNodeId === nodeId;
|
||||
};
|
||||
|
||||
const hasChildren = (node: number) => {
|
||||
return nodes[node].children.length > 0;
|
||||
};
|
||||
|
||||
const toggleCollapse = (node: number) => {
|
||||
if (!hasChildren(node)) {
|
||||
return;
|
||||
}
|
||||
if (isExpanded(node)) {
|
||||
collapse(node);
|
||||
} else {
|
||||
@@ -237,7 +240,7 @@ function DocumentExplorer({ onSubmit, onSelect }: Props) {
|
||||
icon={icon}
|
||||
title={title}
|
||||
depth={node.depth as number}
|
||||
hasChildren={node.children.length > 0}
|
||||
hasChildren={hasChildren(index)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
import { observer } from "mobx-react";
|
||||
import { GoToIcon } from "outline-icons";
|
||||
import * as React from "react";
|
||||
import styled from "styled-components";
|
||||
import { DocumentPath } from "~/stores/CollectionsStore";
|
||||
import Collection from "~/models/Collection";
|
||||
import Document from "~/models/Document";
|
||||
import Flex from "~/components/Flex";
|
||||
import CollectionIcon from "~/components/Icons/CollectionIcon";
|
||||
|
||||
type Props = {
|
||||
result: DocumentPath;
|
||||
document?: Document | null | undefined;
|
||||
collection: Collection | null | undefined;
|
||||
onSuccess?: () => void;
|
||||
style?: React.CSSProperties;
|
||||
ref?: (element: React.ElementRef<"div"> | null | undefined) => void;
|
||||
};
|
||||
|
||||
@observer
|
||||
class PathToDocument extends React.Component<Props> {
|
||||
handleClick = async (ev: React.SyntheticEvent) => {
|
||||
ev.preventDefault();
|
||||
const { document, result, onSuccess } = this.props;
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.type === "document") {
|
||||
await document.move(result.collectionId, result.id);
|
||||
} else {
|
||||
await document.move(result.collectionId);
|
||||
}
|
||||
|
||||
if (onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { result, collection, document, ref, style } = this.props;
|
||||
const Component = document ? ResultWrapperLink : ResultWrapper;
|
||||
if (!result) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
return (
|
||||
// @ts-expect-error ts-migrate(2604) FIXME: JSX element type 'Component' does not have any con... Remove this comment to see the full error message
|
||||
<Component
|
||||
ref={ref}
|
||||
onClick={this.handleClick}
|
||||
href=""
|
||||
style={style}
|
||||
role="option"
|
||||
selectable
|
||||
>
|
||||
{collection && <CollectionIcon collection={collection} />}
|
||||
|
||||
{result.path
|
||||
.map((doc) => <Title key={doc.id}>{doc.title}</Title>)
|
||||
// @ts-expect-error ts-migrate(2739) FIXME: Type 'Element[]' is missing the following properti... Remove this comment to see the full error message
|
||||
.reduce((prev, curr) => [prev, <StyledGoToIcon />, curr])}
|
||||
{document && (
|
||||
<DocumentTitle>
|
||||
{" "}
|
||||
<StyledGoToIcon /> <Title>{document.title}</Title>
|
||||
</DocumentTitle>
|
||||
)}
|
||||
</Component>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const DocumentTitle = styled(Flex)``;
|
||||
|
||||
const Title = styled.span`
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
`;
|
||||
|
||||
const StyledGoToIcon = styled(GoToIcon)`
|
||||
fill: ${(props) => props.theme.divider};
|
||||
`;
|
||||
|
||||
const ResultWrapper = styled.div`
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
user-select: none;
|
||||
|
||||
color: ${(props) => props.theme.text};
|
||||
cursor: default;
|
||||
|
||||
svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const ResultWrapperLink = styled(ResultWrapper.withComponent("a"))`
|
||||
padding: 8px 4px;
|
||||
|
||||
${DocumentTitle} {
|
||||
display: none;
|
||||
}
|
||||
|
||||
svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
background: ${(props) => props.theme.listItemHoverBackground};
|
||||
outline: none;
|
||||
|
||||
${DocumentTitle} {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default PathToDocument;
|
||||
Reference in New Issue
Block a user