mirror of
https://github.com/outline/outline.git
synced 2026-06-13 19:35:02 +03:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c584096d59 | |||
| 5a3d55bc58 | |||
| eaff7d933e | |||
| 21b378b80d | |||
| c143036374 | |||
| a773516e01 | |||
| c7045b0c00 | |||
| 53d0cdd151 | |||
| a22e50cd3d | |||
| 00f65ce29d | |||
| da8936e9d8 |
@@ -16,6 +16,7 @@ import useActionContext from "~/hooks/useActionContext";
|
||||
import useBoolean from "~/hooks/useBoolean";
|
||||
import usePolicy from "~/hooks/usePolicy";
|
||||
import useStores from "~/hooks/useStores";
|
||||
import useToasts from "~/hooks/useToasts";
|
||||
import CollectionMenu from "~/menus/CollectionMenu";
|
||||
import { NavigationNode } from "~/types";
|
||||
import DropToImport from "./DropToImport";
|
||||
@@ -48,6 +49,7 @@ const CollectionLink: React.FC<Props> = ({
|
||||
const { t } = useTranslation();
|
||||
const history = useHistory();
|
||||
const inStarredSection = useStarredContext();
|
||||
const { showToast } = useToasts();
|
||||
|
||||
const handleTitleChange = React.useCallback(
|
||||
async (name: string) => {
|
||||
@@ -62,16 +64,17 @@ const CollectionLink: React.FC<Props> = ({
|
||||
// Drop to re-parent document
|
||||
const [{ isOver, canDrop }, drop] = useDrop({
|
||||
accept: "document",
|
||||
drop: (item: DragObject, monitor) => {
|
||||
drop: async (item: DragObject, monitor) => {
|
||||
const { id, collectionId } = item;
|
||||
const document = documents.get(id);
|
||||
|
||||
if (monitor.didDrop()) {
|
||||
return;
|
||||
}
|
||||
if (!collection) {
|
||||
if (!collection || !document) {
|
||||
return;
|
||||
}
|
||||
|
||||
const document = documents.get(id);
|
||||
if (collection.id === collectionId && !document?.parentDocumentId) {
|
||||
return;
|
||||
}
|
||||
@@ -97,7 +100,21 @@ const CollectionLink: React.FC<Props> = ({
|
||||
),
|
||||
});
|
||||
} else {
|
||||
documents.move(id, collection.id);
|
||||
const undo = document.metaData;
|
||||
await document.move(collection.id);
|
||||
showToast(t("Document moved"), {
|
||||
type: "info",
|
||||
action: {
|
||||
text: "undo",
|
||||
onClick: async () => {
|
||||
await document.move(
|
||||
undo.collectionId,
|
||||
undo.parentDocumentId,
|
||||
undo.index
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
canDrop: () => canUpdate,
|
||||
|
||||
@@ -178,10 +178,13 @@ function InnerDocumentLink(
|
||||
if (monitor.didDrop()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
documents.move(item.id, collection.id, node.id);
|
||||
|
||||
const document = documents.get(item.id);
|
||||
document?.moveWithUndo(collection.id, node.id);
|
||||
},
|
||||
canDrop: (_item, monitor) =>
|
||||
!isDraft &&
|
||||
@@ -244,12 +247,14 @@ function InnerDocumentLink(
|
||||
return;
|
||||
}
|
||||
|
||||
if (expanded) {
|
||||
documents.move(item.id, collection.id, node.id, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
documents.move(item.id, collection.id, parentId, index + 1);
|
||||
const parentDocumentId = expanded ? node.id : parentId;
|
||||
const droppedDocumentIndex = expanded ? 0 : index + 1;
|
||||
const document = documents.get(item.id);
|
||||
document?.moveWithUndo(
|
||||
collection.id,
|
||||
parentDocumentId,
|
||||
droppedDocumentIndex
|
||||
);
|
||||
},
|
||||
collect: (monitor) => ({
|
||||
isOverReorder: !!monitor.isOver(),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CheckboxIcon, InfoIcon, WarningIcon } from "outline-icons";
|
||||
import { darken } from "polished";
|
||||
import { darken, lighten } from "polished";
|
||||
import * as React from "react";
|
||||
import styled, { css } from "styled-components";
|
||||
import { fadeAndScaleIn, pulse } from "~/styles/animations";
|
||||
@@ -69,17 +69,17 @@ function Toast({ closeAfterMs = 3000, onRequestClose, toast }: Props) {
|
||||
|
||||
const Action = styled.span`
|
||||
display: inline-block;
|
||||
padding: 10px 12px;
|
||||
padding: 6px 12px;
|
||||
margin-left: 8px;
|
||||
height: 100%;
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
color: ${(props) => props.theme.toastText};
|
||||
background: ${(props) => darken(0.05, props.theme.toastBackground)};
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
border-radius: 5px;
|
||||
|
||||
&:hover {
|
||||
background: ${(props) => darken(0.1, props.theme.toastBackground)};
|
||||
background: ${(props) => lighten(0.1, props.theme.toastBackground)};
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -136,6 +136,29 @@ export default class Collection extends ParanoidModel {
|
||||
return result;
|
||||
}
|
||||
|
||||
documentIndexInCollection(documentId: string) {
|
||||
let index: number | undefined;
|
||||
const findIndex = (nodes: NavigationNode[]) => {
|
||||
if (index) {
|
||||
return;
|
||||
}
|
||||
|
||||
nodes.forEach((node, i) => {
|
||||
if (node.id === documentId) {
|
||||
index = i;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
nodes.forEach((node) => {
|
||||
findIndex(node.children);
|
||||
});
|
||||
};
|
||||
|
||||
findIndex(this.documents);
|
||||
return index;
|
||||
}
|
||||
|
||||
pathToDocument(documentId: string) {
|
||||
let path: NavigationNode[] | undefined;
|
||||
const document = this.store.rootStore.documents.get(documentId);
|
||||
|
||||
+18
-2
@@ -379,10 +379,26 @@ export default class Document extends ParanoidModel {
|
||||
}
|
||||
};
|
||||
|
||||
move = (collectionId: string, parentDocumentId?: string | undefined) => {
|
||||
return this.store.move(this.id, collectionId, parentDocumentId);
|
||||
move = (
|
||||
collectionId: string,
|
||||
parentDocumentId?: string | null,
|
||||
index?: number | null
|
||||
) => {
|
||||
return this.store.move(this.id, collectionId, parentDocumentId, index);
|
||||
};
|
||||
|
||||
@computed
|
||||
get metaData() {
|
||||
const collection = this.store.rootStore.collections.get(this.collectionId);
|
||||
const undo = {
|
||||
id: this.id,
|
||||
collectionId: this.collectionId,
|
||||
parentDocumentId: this.parentDocumentId,
|
||||
index: collection?.documentIndexInCollection?.(this.id),
|
||||
};
|
||||
return undo;
|
||||
}
|
||||
|
||||
duplicate = () => {
|
||||
return this.store.duplicate(this);
|
||||
};
|
||||
|
||||
@@ -5,27 +5,13 @@ import { Trans, useTranslation } from "react-i18next";
|
||||
import Collection from "~/models/Collection";
|
||||
import Button from "~/components/Button";
|
||||
import Flex from "~/components/Flex";
|
||||
import { DragObject } from "~/components/Sidebar/components/SidebarLink";
|
||||
import Text from "~/components/Text";
|
||||
import useStores from "~/hooks/useStores";
|
||||
import useToasts from "~/hooks/useToasts";
|
||||
import { NavigationNode } from "~/types";
|
||||
|
||||
type Props = {
|
||||
item:
|
||||
| {
|
||||
active: boolean | null | undefined;
|
||||
children: Array<NavigationNode>;
|
||||
collectionId: string;
|
||||
depth: number;
|
||||
id: string;
|
||||
title: string;
|
||||
url: string;
|
||||
}
|
||||
| {
|
||||
id: string;
|
||||
collectionId: string;
|
||||
title: string;
|
||||
};
|
||||
item: DragObject;
|
||||
collection: Collection;
|
||||
onCancel: () => void;
|
||||
onSubmit: () => void;
|
||||
@@ -49,10 +35,8 @@ function DocumentReparent({ collection, item, onSubmit, onCancel }: Props) {
|
||||
setIsSaving(true);
|
||||
|
||||
try {
|
||||
await documents.move(item.id, collection.id);
|
||||
showToast(t("Document moved"), {
|
||||
type: "info",
|
||||
});
|
||||
const document = documents.get(item.id);
|
||||
document?.moveWithUndo(collection.id);
|
||||
onSubmit();
|
||||
} catch (err) {
|
||||
showToast(err.message, {
|
||||
@@ -62,7 +46,7 @@ function DocumentReparent({ collection, item, onSubmit, onCancel }: Props) {
|
||||
setIsSaving(false);
|
||||
}
|
||||
},
|
||||
[documents, item.id, collection.id, showToast, t, onSubmit]
|
||||
[documents, collection.id, showToast, item, onSubmit]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -150,6 +150,7 @@
|
||||
"Logo": "Logo",
|
||||
"Document archived": "Document archived",
|
||||
"Move document": "Move document",
|
||||
"Document moved": "Document moved",
|
||||
"You can't reorder documents in an alphabetically sorted collection": "You can't reorder documents in an alphabetically sorted collection",
|
||||
"Collections": "Collections",
|
||||
"Untitled": "Untitled",
|
||||
@@ -423,7 +424,6 @@
|
||||
"Are you sure about that? Deleting the <em>{{ documentTitle }}</em> document will delete all of its history and any nested documents.": "Are you sure about that? Deleting the <em>{{ documentTitle }}</em> document will delete all of its history and any nested documents.",
|
||||
"If you’d like the option of referencing or restoring the {{noun}} in the future, consider archiving it instead.": "If you’d like the option of referencing or restoring the {{noun}} in the future, consider archiving it instead.",
|
||||
"Archiving": "Archiving",
|
||||
"Document moved": "Document moved",
|
||||
"Current location": "Current location",
|
||||
"Choose a new location": "Choose a new location",
|
||||
"Search collections & documents": "Search collections & documents",
|
||||
|
||||
Reference in New Issue
Block a user