feat: Add navigation sidebar to shared documents (#2899)
Co-authored-by: Tom Moor <tom@getoutline.com>
This commit is contained in:
@@ -78,6 +78,7 @@ const NavLink = ({
|
||||
strict,
|
||||
})
|
||||
: null;
|
||||
|
||||
const isActive = !!(isActiveProp
|
||||
? isActiveProp(match, currentLocation)
|
||||
: match);
|
||||
|
||||
128
app/components/Sidebar/components/SharedDocumentLink.tsx
Normal file
128
app/components/Sidebar/components/SharedDocumentLink.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import { observer } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Collection from "~/models/Collection";
|
||||
import Document from "~/models/Document";
|
||||
import useStores from "~/hooks/useStores";
|
||||
import { NavigationNode } from "~/types";
|
||||
import Disclosure from "./Disclosure";
|
||||
import SidebarLink from "./SidebarLink";
|
||||
|
||||
type Props = {
|
||||
node: NavigationNode;
|
||||
collection?: Collection;
|
||||
activeDocument: Document | null | undefined;
|
||||
isDraft?: boolean;
|
||||
depth: number;
|
||||
index: number;
|
||||
shareId: string;
|
||||
parentId?: string;
|
||||
};
|
||||
|
||||
function DocumentLink(
|
||||
{ node, collection, activeDocument, isDraft, depth, shareId }: Props,
|
||||
ref: React.RefObject<HTMLAnchorElement>
|
||||
) {
|
||||
const { documents } = useStores();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const isActiveDocument = activeDocument && activeDocument.id === node.id;
|
||||
|
||||
const hasChildDocuments =
|
||||
!!node.children.length || activeDocument?.parentDocumentId === node.id;
|
||||
const document = documents.get(node.id);
|
||||
|
||||
const showChildren = React.useMemo(() => {
|
||||
return !!hasChildDocuments;
|
||||
}, [hasChildDocuments]);
|
||||
|
||||
const [expanded, setExpanded] = React.useState(showChildren);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (showChildren) {
|
||||
setExpanded(showChildren);
|
||||
}
|
||||
}, [showChildren]);
|
||||
|
||||
const handleDisclosureClick = React.useCallback(
|
||||
(ev: React.SyntheticEvent) => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
setExpanded(!expanded);
|
||||
},
|
||||
[expanded]
|
||||
);
|
||||
|
||||
// since we don't have access to the collection sort here, we just put any
|
||||
// drafts at the front of the list. this is slightly inconsistent with the
|
||||
// logged-in behavior, but it's probably better to emphasize the draft state
|
||||
// of the document in a shared context
|
||||
const nodeChildren = React.useMemo(() => {
|
||||
if (
|
||||
activeDocument?.isDraft &&
|
||||
activeDocument?.isActive &&
|
||||
activeDocument?.parentDocumentId === node.id
|
||||
) {
|
||||
return [activeDocument?.asNavigationNode, ...node.children];
|
||||
}
|
||||
|
||||
return node.children;
|
||||
}, [
|
||||
activeDocument?.isActive,
|
||||
activeDocument?.isDraft,
|
||||
activeDocument?.parentDocumentId,
|
||||
activeDocument?.asNavigationNode,
|
||||
node,
|
||||
]);
|
||||
|
||||
const title =
|
||||
(activeDocument?.id === node.id ? activeDocument.title : node.title) ||
|
||||
t("Untitled");
|
||||
|
||||
return (
|
||||
<>
|
||||
<SidebarLink
|
||||
to={{
|
||||
pathname: `/share/${shareId}${node.url}`,
|
||||
state: {
|
||||
title: node.title,
|
||||
},
|
||||
}}
|
||||
label={
|
||||
<>
|
||||
{hasChildDocuments && (
|
||||
<Disclosure expanded={expanded} onClick={handleDisclosureClick} />
|
||||
)}
|
||||
{title}
|
||||
</>
|
||||
}
|
||||
depth={depth}
|
||||
exact={false}
|
||||
scrollIntoViewIfNeeded={!document?.isStarred}
|
||||
isDraft={isDraft}
|
||||
ref={ref}
|
||||
isActive={() => {
|
||||
return !!isActiveDocument;
|
||||
}}
|
||||
/>
|
||||
{expanded &&
|
||||
nodeChildren.map((childNode, index) => (
|
||||
<ObservedDocumentLink
|
||||
shareId={shareId}
|
||||
key={childNode.id}
|
||||
collection={collection}
|
||||
node={childNode}
|
||||
activeDocument={activeDocument}
|
||||
isDraft={childNode.isDraft}
|
||||
depth={depth + 1}
|
||||
index={index}
|
||||
parentId={node.id}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const ObservedDocumentLink = observer(React.forwardRef(DocumentLink));
|
||||
|
||||
export default ObservedDocumentLink;
|
||||
Reference in New Issue
Block a user