mirror of
https://github.com/outline/outline.git
synced 2026-05-03 16:09:52 -05:00
wip
This commit is contained in:
@@ -3,10 +3,11 @@ import { observer } from "mobx-react";
|
||||
import { PlusIcon } from "outline-icons";
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import styled from "styled-components";
|
||||
import Icon from "@shared/components/Icon";
|
||||
import { NavigationNode } from "@shared/types";
|
||||
import { ProsemirrorHelper } from "@shared/utils/ProsemirrorHelper";
|
||||
import { sortNavigationNodes } from "@shared/utils/collections";
|
||||
import { DocumentValidation } from "@shared/validations";
|
||||
import Collection from "~/models/Collection";
|
||||
@@ -18,7 +19,7 @@ import useBoolean from "~/hooks/useBoolean";
|
||||
import usePolicy from "~/hooks/usePolicy";
|
||||
import useStores from "~/hooks/useStores";
|
||||
import DocumentMenu from "~/menus/DocumentMenu";
|
||||
import { newNestedDocumentPath } from "~/utils/routeHelpers";
|
||||
import { documentEditPath } from "~/utils/routeHelpers";
|
||||
import {
|
||||
useDragDocument,
|
||||
useDropToReorderDocument,
|
||||
@@ -58,6 +59,7 @@ function InnerDocumentLink(
|
||||
) {
|
||||
const { documents, policies } = useStores();
|
||||
const { t } = useTranslation();
|
||||
const history = useHistory();
|
||||
const canUpdate = usePolicy(node.id).update;
|
||||
const isActiveDocument = activeDocument && activeDocument.id === node.id;
|
||||
const hasChildDocuments =
|
||||
@@ -216,6 +218,9 @@ function InnerDocumentLink(
|
||||
[setExpanded, setCollapsed, hasChildren, expanded]
|
||||
);
|
||||
|
||||
const [isAddingNewChild, setIsAddingNewChild, closeAddingNewChild] =
|
||||
useBoolean();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Relative ref={parentRef}>
|
||||
@@ -282,8 +287,11 @@ function InnerDocumentLink(
|
||||
<NudeButton
|
||||
type={undefined}
|
||||
aria-label={t("New nested document")}
|
||||
as={Link}
|
||||
to={newNestedDocumentPath(document.id)}
|
||||
onClick={(ev) => {
|
||||
ev.preventDefault();
|
||||
setIsAddingNewChild();
|
||||
setExpanded();
|
||||
}}
|
||||
>
|
||||
<PlusIcon />
|
||||
</NudeButton>
|
||||
@@ -308,6 +316,38 @@ function InnerDocumentLink(
|
||||
<DropCursor isActiveDrop={isOverReorder} innerRef={dropToReorder} />
|
||||
)}
|
||||
</Relative>
|
||||
{isAddingNewChild && (
|
||||
<SidebarLink
|
||||
isActive={() => true}
|
||||
depth={depth + 1}
|
||||
label={
|
||||
<EditableTitle
|
||||
title=""
|
||||
canUpdate
|
||||
isEditing
|
||||
placeholder={`${t("New doc")}…`}
|
||||
onEscape={closeAddingNewChild}
|
||||
onSubmit={async (input) => {
|
||||
const newDocument = await documents.create(
|
||||
{
|
||||
collectionId: collection?.id,
|
||||
parentDocumentId: node.id,
|
||||
fullWidth: doc?.fullWidth,
|
||||
title: input,
|
||||
data: ProsemirrorHelper.getEmptyDocument(),
|
||||
},
|
||||
{ publish: true }
|
||||
);
|
||||
collection?.addDocument(newDocument, node.id);
|
||||
|
||||
closeAddingNewChild();
|
||||
history.replace(documentEditPath(newDocument));
|
||||
}}
|
||||
maxLength={DocumentValidation.maxTitleLength}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Folder expanded={expanded && !isDragging}>
|
||||
{nodeChildren.map((childNode, index) => (
|
||||
<DocumentLink
|
||||
|
||||
@@ -3,12 +3,14 @@ import { toast } from "sonner";
|
||||
import styled from "styled-components";
|
||||
import { s } from "@shared/styles";
|
||||
|
||||
type Props = {
|
||||
onSubmit: (title: string) => Promise<void>;
|
||||
type Props = Omit<React.HTMLAttributes<HTMLInputElement>, "onSubmit"> & {
|
||||
onSubmit: (title: string) => Promise<void> | void;
|
||||
onEditing?: (isEditing: boolean) => void;
|
||||
onEscape?: () => void;
|
||||
title: string;
|
||||
canUpdate: boolean;
|
||||
maxLength?: number;
|
||||
isEditing?: boolean;
|
||||
};
|
||||
|
||||
export type RefHandle = {
|
||||
@@ -16,10 +18,10 @@ export type RefHandle = {
|
||||
};
|
||||
|
||||
function EditableTitle(
|
||||
{ title, onSubmit, canUpdate, onEditing, ...rest }: Props,
|
||||
{ title, onSubmit, canUpdate, onEditing, onEscape, ...rest }: Props,
|
||||
ref: React.RefObject<RefHandle>
|
||||
) {
|
||||
const [isEditing, setIsEditing] = React.useState(false);
|
||||
const [isEditing, setIsEditing] = React.useState(rest.isEditing || false);
|
||||
const [originalValue, setOriginalValue] = React.useState(title);
|
||||
const [value, setValue] = React.useState(title);
|
||||
|
||||
@@ -59,6 +61,7 @@ function EditableTitle(
|
||||
|
||||
if (trimmedValue === originalValue || trimmedValue.length === 0) {
|
||||
setValue(originalValue);
|
||||
onEscape?.();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -83,6 +86,7 @@ function EditableTitle(
|
||||
}
|
||||
if (ev.key === "Escape") {
|
||||
setIsEditing(false);
|
||||
onEscape?.();
|
||||
setValue(originalValue);
|
||||
}
|
||||
if (ev.key === "Enter") {
|
||||
|
||||
@@ -263,6 +263,24 @@ export default class Collection extends ParanoidModel {
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
addDocument(document: Document, parentDocumentId?: string) {
|
||||
if (!this.documents) {
|
||||
return;
|
||||
}
|
||||
|
||||
const travelNodes = (nodes: NavigationNode[]) =>
|
||||
nodes.forEach((node) => {
|
||||
if (node.id === parentDocumentId) {
|
||||
node.children = [document.asNavigationNode, ...(node.children ?? [])];
|
||||
} else {
|
||||
travelNodes(node.children);
|
||||
}
|
||||
});
|
||||
|
||||
travelNodes(this.documents);
|
||||
}
|
||||
|
||||
@action
|
||||
updateIndex(index: string) {
|
||||
this.index = index;
|
||||
|
||||
@@ -584,6 +584,7 @@ class DocumentScene extends React.Component<Props> {
|
||||
readOnly={readOnly}
|
||||
canUpdate={abilities.update}
|
||||
canComment={abilities.comment}
|
||||
autoFocus
|
||||
>
|
||||
{shareId ? (
|
||||
<ReferencesWrapper>
|
||||
|
||||
@@ -50,7 +50,7 @@ function DocumentNew({ template }: Props) {
|
||||
user.getPreference(UserPreference.FullWidthDocuments),
|
||||
templateId: query.get("templateId") ?? undefined,
|
||||
template,
|
||||
title: "",
|
||||
title: query.get("title") ?? "",
|
||||
data: ProsemirrorHelper.getEmptyDocument(),
|
||||
},
|
||||
{ publish: collection?.id || parentDocumentId ? true : undefined }
|
||||
|
||||
@@ -107,8 +107,11 @@ export function newDocumentPath(
|
||||
: `/doc/new?${queryString.stringify(params)}`;
|
||||
}
|
||||
|
||||
export function newNestedDocumentPath(parentDocumentId?: string): string {
|
||||
return `/doc/new?${queryString.stringify({ parentDocumentId })}`;
|
||||
export function newNestedDocumentPath(
|
||||
parentDocumentId?: string,
|
||||
title?: string
|
||||
): string {
|
||||
return `/doc/new?${queryString.stringify({ parentDocumentId, title })}`;
|
||||
}
|
||||
|
||||
export function searchPath(
|
||||
|
||||
Reference in New Issue
Block a user