mirror of
https://github.com/outline/outline.git
synced 2026-06-13 03:14:59 +03:00
fix: Flashing of sidebar on initial load (#11607)
* fix: Flashing of sidebar on initial load * refactor * refactor * Remove toggleComments * fix: Skip animation on page load * feedback
This commit is contained in:
@@ -1381,7 +1381,7 @@ export const openDocumentComments = createAction({
|
||||
return;
|
||||
}
|
||||
|
||||
stores.ui.toggleComments();
|
||||
stores.ui.set({ rightSidebar: "comments" });
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
import { AnimatePresence } from "framer-motion";
|
||||
import { observer } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import {
|
||||
Switch,
|
||||
Route,
|
||||
useLocation,
|
||||
matchPath,
|
||||
Redirect,
|
||||
} from "react-router-dom";
|
||||
import { TeamPreference } from "@shared/types";
|
||||
import { Switch, Route, Redirect } from "react-router-dom";
|
||||
import ErrorSuspended from "~/scenes/Errors/ErrorSuspended";
|
||||
import Layout from "~/components/Layout";
|
||||
import RegisterKeyDown from "~/components/RegisterKeyDown";
|
||||
import { RightSidebarProvider } from "~/components/RightSidebarContext";
|
||||
import Sidebar from "~/components/Sidebar";
|
||||
import useCurrentTeam from "~/hooks/useCurrentTeam";
|
||||
import { usePostLoginPath } from "~/hooks/useLastVisitedPath";
|
||||
@@ -23,8 +16,6 @@ import {
|
||||
searchPath,
|
||||
newDocumentPath,
|
||||
settingsPath,
|
||||
matchDocumentHistory,
|
||||
matchDocumentSlug as slug,
|
||||
} from "~/utils/routeHelpers";
|
||||
import { DocumentContextProvider } from "./DocumentContext";
|
||||
import Fade from "./Fade";
|
||||
@@ -32,12 +23,6 @@ import NotificationBadge from "./NotificationBadge";
|
||||
import { PortalContext } from "./Portal";
|
||||
import CommandBar from "./CommandBar";
|
||||
|
||||
const DocumentComments = lazyWithRetry(
|
||||
() => import("~/scenes/Document/components/Comments/Comments")
|
||||
);
|
||||
const DocumentHistory = lazyWithRetry(
|
||||
() => import("~/scenes/Document/components/History")
|
||||
);
|
||||
const SettingsSidebar = lazyWithRetry(
|
||||
() => import("~/components/Sidebar/Settings")
|
||||
);
|
||||
@@ -48,9 +33,7 @@ type Props = {
|
||||
|
||||
const AuthenticatedLayout: React.FC = ({ children }: Props) => {
|
||||
const { ui, auth } = useStores();
|
||||
const location = useLocation();
|
||||
const layoutRef = React.useRef<HTMLDivElement>(null);
|
||||
const can = usePolicy(ui.activeDocumentId);
|
||||
const canCollection = usePolicy(ui.activeCollectionId);
|
||||
const team = useCurrentTeam();
|
||||
const [spendPostLoginPath] = usePostLoginPath();
|
||||
@@ -92,50 +75,20 @@ const AuthenticatedLayout: React.FC = ({ children }: Props) => {
|
||||
</Fade>
|
||||
);
|
||||
|
||||
const showHistory =
|
||||
!!matchPath(location.pathname, {
|
||||
path: matchDocumentHistory,
|
||||
}) && can.listRevisions;
|
||||
const showComments =
|
||||
!showHistory &&
|
||||
can.comment &&
|
||||
ui.activeDocumentId &&
|
||||
ui.commentsExpanded &&
|
||||
!!team.getPreference(TeamPreference.Commenting);
|
||||
|
||||
const sidebarRight = (
|
||||
<AnimatePresence
|
||||
initial={false}
|
||||
key={ui.activeDocumentId ? "active" : "inactive"}
|
||||
>
|
||||
{(showHistory || showComments) && (
|
||||
<Route path={`/doc/${slug}`}>
|
||||
<React.Suspense fallback={null}>
|
||||
{showHistory && <DocumentHistory />}
|
||||
{showComments && <DocumentComments />}
|
||||
</React.Suspense>
|
||||
</Route>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
|
||||
return (
|
||||
<DocumentContextProvider>
|
||||
<PortalContext.Provider value={layoutRef.current}>
|
||||
<Layout
|
||||
title={team.name}
|
||||
sidebar={sidebar}
|
||||
sidebarRight={sidebarRight}
|
||||
ref={layoutRef}
|
||||
>
|
||||
<RegisterKeyDown trigger="n" handler={goToNewDocument} />
|
||||
<RegisterKeyDown trigger="t" handler={goToSearch} />
|
||||
<RegisterKeyDown trigger="/" handler={goToSearch} />
|
||||
{children}
|
||||
<CommandBar />
|
||||
<NotificationBadge />
|
||||
</Layout>
|
||||
</PortalContext.Provider>
|
||||
<RightSidebarProvider>
|
||||
<PortalContext.Provider value={layoutRef.current}>
|
||||
<Layout title={team.name} sidebar={sidebar} ref={layoutRef}>
|
||||
<RegisterKeyDown trigger="n" handler={goToNewDocument} />
|
||||
<RegisterKeyDown trigger="t" handler={goToSearch} />
|
||||
<RegisterKeyDown trigger="/" handler={goToSearch} />
|
||||
{children}
|
||||
<CommandBar />
|
||||
<NotificationBadge />
|
||||
</Layout>
|
||||
</PortalContext.Provider>
|
||||
</RightSidebarProvider>
|
||||
</DocumentContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { AnimatePresence } from "framer-motion";
|
||||
import { observer } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
@@ -7,6 +8,7 @@ import breakpoint from "styled-components-breakpoint";
|
||||
import { s } from "@shared/styles";
|
||||
import Flex from "~/components/Flex";
|
||||
import { LoadingIndicatorBar } from "~/components/LoadingIndicator";
|
||||
import { useRightSidebarContent } from "~/components/RightSidebarContext";
|
||||
import SkipNavContent from "~/components/SkipNavContent";
|
||||
import SkipNavLink from "~/components/SkipNavLink";
|
||||
import env from "~/env";
|
||||
@@ -19,16 +21,15 @@ type Props = {
|
||||
title?: string;
|
||||
/** Left sidebar content. */
|
||||
sidebar?: React.ReactNode;
|
||||
/** Right sidebar content. */
|
||||
sidebarRight?: React.ReactNode;
|
||||
};
|
||||
|
||||
const Layout = React.forwardRef(function Layout_(
|
||||
{ title, children, sidebar, sidebarRight }: Props,
|
||||
{ title, children, sidebar }: Props,
|
||||
ref: React.RefObject<HTMLDivElement>
|
||||
) {
|
||||
const { ui } = useStores();
|
||||
const sidebarCollapsed = !sidebar || ui.sidebarIsClosed;
|
||||
const sidebarRight = useRightSidebarContent();
|
||||
|
||||
return (
|
||||
<Container column auto ref={ref}>
|
||||
@@ -61,7 +62,7 @@ const Layout = React.forwardRef(function Layout_(
|
||||
{children}
|
||||
</Content>
|
||||
|
||||
{sidebarRight}
|
||||
<AnimatePresence initial={false}>{sidebarRight}</AnimatePresence>
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import * as React from "react";
|
||||
|
||||
type SetSidebarFn = (content: React.ReactNode) => void;
|
||||
|
||||
const RightSidebarSetterContext = React.createContext<SetSidebarFn | null>(
|
||||
null
|
||||
);
|
||||
const RightSidebarContentContext = React.createContext<React.ReactNode>(null);
|
||||
|
||||
/**
|
||||
* Provider that holds right sidebar content state. Wrap at the layout level
|
||||
* so that scenes can set sidebar content via the setter hook.
|
||||
*/
|
||||
export function RightSidebarProvider({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const [content, setContent] = React.useState<React.ReactNode>(null);
|
||||
|
||||
return (
|
||||
<RightSidebarSetterContext.Provider value={setContent}>
|
||||
<RightSidebarContentContext.Provider value={content}>
|
||||
{children}
|
||||
</RightSidebarContentContext.Provider>
|
||||
</RightSidebarSetterContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stable setter function to set the right sidebar content.
|
||||
* Used by scenes (e.g. Document) to populate the sidebar.
|
||||
*/
|
||||
export function useSetRightSidebar(): SetSidebarFn {
|
||||
const setter = React.useContext(RightSidebarSetterContext);
|
||||
if (!setter) {
|
||||
throw new Error(
|
||||
"useSetRightSidebar must be used within a RightSidebarProvider"
|
||||
);
|
||||
}
|
||||
return setter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current right sidebar content. Used by Layout to render
|
||||
* the sidebar.
|
||||
*/
|
||||
export function useRightSidebarContent(): React.ReactNode {
|
||||
return React.useContext(RightSidebarContentContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Context indicating whether the Right sidebar wrapper is already rendered
|
||||
* by an ancestor. When true, SidebarLayout skips rendering its own Right
|
||||
* wrapper to avoid duplicate animated containers.
|
||||
*/
|
||||
export const RightSidebarWrappedContext = React.createContext(false);
|
||||
@@ -14,9 +14,11 @@ import { sidebarAppearDuration } from "~/styles/animations";
|
||||
interface Props extends React.HTMLAttributes<HTMLDivElement> {
|
||||
children: React.ReactNode;
|
||||
border?: boolean;
|
||||
/** When true, skip the entrance animation and render at full width immediately. */
|
||||
skipInitialAnimation?: boolean;
|
||||
}
|
||||
|
||||
function Right({ children, border, className }: Props) {
|
||||
function Right({ children, border, className, skipInitialAnimation }: Props) {
|
||||
const theme = useTheme();
|
||||
const { ui } = useStores();
|
||||
const [isResizing, setResizing] = React.useState(false);
|
||||
@@ -77,10 +79,12 @@ function Right({ children, border, className }: Props) {
|
||||
);
|
||||
|
||||
const animationProps = {
|
||||
initial: {
|
||||
width: 0,
|
||||
opacity: 0.9,
|
||||
},
|
||||
initial: skipInitialAnimation
|
||||
? false
|
||||
: {
|
||||
width: 0,
|
||||
opacity: 0.9,
|
||||
},
|
||||
animate: {
|
||||
transition: isResizing
|
||||
? { duration: 0 }
|
||||
|
||||
@@ -312,25 +312,27 @@ function CommentForm({
|
||||
{highlightedText && (
|
||||
<HighlightedText>{highlightedText}</HighlightedText>
|
||||
)}
|
||||
<CommentEditor
|
||||
key={`${forceRender}`}
|
||||
ref={mergeRefs([editorRef, handleMounted])}
|
||||
defaultValue={draft}
|
||||
onChange={handleChange}
|
||||
onSave={handleSave}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
onUpArrowAtStart={handleUpArrowAtStart}
|
||||
maxLength={CommentValidation.maxLength}
|
||||
placeholder={
|
||||
placeholder ||
|
||||
// isNew is only the case for comments that exist in draft state,
|
||||
// they are marks in the document, but not yet saved to the db.
|
||||
(thread?.isNew
|
||||
? `${t("Add a comment")}…`
|
||||
: `${t("Add a reply")}…`)
|
||||
}
|
||||
/>
|
||||
<React.Suspense fallback={<div style={{ height: 24 }} />}>
|
||||
<CommentEditor
|
||||
key={`${forceRender}`}
|
||||
ref={mergeRefs([editorRef, handleMounted])}
|
||||
defaultValue={draft}
|
||||
onChange={handleChange}
|
||||
onSave={handleSave}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
onUpArrowAtStart={handleUpArrowAtStart}
|
||||
maxLength={CommentValidation.maxLength}
|
||||
placeholder={
|
||||
placeholder ||
|
||||
// isNew is only the case for comments that exist in draft state,
|
||||
// they are marks in the document, but not yet saved to the db.
|
||||
(thread?.isNew
|
||||
? `${t("Add a comment")}…`
|
||||
: `${t("Add a reply")}…`)
|
||||
}
|
||||
/>
|
||||
</React.Suspense>
|
||||
{(inputFocused || draft) && (
|
||||
<Flex justify="space-between" reverse={dir === "rtl"} gap={8}>
|
||||
<HStack>
|
||||
|
||||
@@ -233,16 +233,18 @@ function CommentThreadItem({
|
||||
<HighlightedText>{highlightedText}</HighlightedText>
|
||||
)}
|
||||
<Body ref={formRef} onSubmit={handleSubmit}>
|
||||
<StyledCommentEditor
|
||||
key={String(isEditing)}
|
||||
readOnly={!isEditing}
|
||||
value={comment.data}
|
||||
defaultValue={data}
|
||||
onChange={handleChange}
|
||||
onSave={handleSave}
|
||||
onCancel={handleCancel}
|
||||
autoFocus
|
||||
/>
|
||||
<React.Suspense fallback={null}>
|
||||
<StyledCommentEditor
|
||||
key={String(isEditing)}
|
||||
readOnly={!isEditing}
|
||||
value={comment.data}
|
||||
defaultValue={data}
|
||||
onChange={handleChange}
|
||||
onSave={handleSave}
|
||||
onCancel={handleCancel}
|
||||
autoFocus
|
||||
/>
|
||||
</React.Suspense>
|
||||
{isEditing && (
|
||||
<Flex align="flex-end" gap={8}>
|
||||
<ButtonSmall type="submit" borderOnHover>
|
||||
|
||||
@@ -48,7 +48,7 @@ function Comments() {
|
||||
const isAtBottom = useRef(true);
|
||||
const [showJumpToRecentBtn, setShowJumpToRecentBtn] = useState(false);
|
||||
|
||||
useKeyDown("Escape", () => document && ui.set({ commentsExpanded: false }));
|
||||
useKeyDown("Escape", () => document && ui.set({ rightSidebar: null }));
|
||||
|
||||
// Account for the resolved status of the comment changing
|
||||
useEffect(() => {
|
||||
@@ -203,7 +203,7 @@ function Comments() {
|
||||
/>
|
||||
</Flex>
|
||||
}
|
||||
onClose={() => ui.set({ commentsExpanded: false })}
|
||||
onClose={() => ui.set({ rightSidebar: null })}
|
||||
scrollable={false}
|
||||
>
|
||||
{content}
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
} from "~/utils/errors";
|
||||
import history from "~/utils/history";
|
||||
import { matchDocumentEdit, settingsPath } from "~/utils/routeHelpers";
|
||||
import useDocumentSidebar from "../hooks/useDocumentSidebar";
|
||||
import Loading from "./Loading";
|
||||
import MarkAsViewed from "./MarkAsViewed";
|
||||
|
||||
@@ -89,6 +90,8 @@ function DataLoader({ match, children }: Props) {
|
||||
const location = useLocation<LocationState>();
|
||||
const missingPolicy = !can || Object.keys(can).length === 0;
|
||||
|
||||
useDocumentSidebar();
|
||||
|
||||
React.useEffect(() => {
|
||||
async function fetchDocument() {
|
||||
try {
|
||||
|
||||
@@ -60,7 +60,7 @@ function TitleDocumentMeta({ to, document, revision, ...rest }: Props) {
|
||||
pathname: documentPath(document as Document),
|
||||
state: { sidebarContext },
|
||||
}}
|
||||
onClick={() => ui.toggleComments()}
|
||||
onClick={() => ui.set({ rightSidebar: "comments" })}
|
||||
>
|
||||
<CommentIcon size={18} />
|
||||
{commentsCount
|
||||
|
||||
@@ -101,7 +101,7 @@ function DocumentEditor(props: Props, ref: React.RefObject<any>) {
|
||||
) {
|
||||
setFocusedCommentId(focusedComment.id);
|
||||
}
|
||||
ui.set({ commentsExpanded: true });
|
||||
ui.set({ rightSidebar: "comments" });
|
||||
}
|
||||
}, [focusedComment, ui, document.id, params]);
|
||||
|
||||
@@ -250,7 +250,9 @@ function DocumentEditor(props: Props, ref: React.RefObject<any>) {
|
||||
commentingEnabled && can.comment ? handleRemoveComment : undefined
|
||||
}
|
||||
onOpenCommentsSidebar={
|
||||
commentingEnabled ? ui.toggleComments : undefined
|
||||
commentingEnabled
|
||||
? () => ui.set({ rightSidebar: "comments" })
|
||||
: undefined
|
||||
}
|
||||
onInit={handleInit}
|
||||
onDestroy={handleDestroy}
|
||||
|
||||
@@ -6,17 +6,18 @@ import styled from "styled-components";
|
||||
import { s, ellipsis } from "@shared/styles";
|
||||
import Button from "~/components/Button";
|
||||
import Flex from "~/components/Flex";
|
||||
import { PortalContext } from "~/components/Portal";
|
||||
import { RightSidebarWrappedContext } from "~/components/RightSidebarContext";
|
||||
import Scrollable from "~/components/Scrollable";
|
||||
import Tooltip from "~/components/Tooltip";
|
||||
import useMobile from "~/hooks/useMobile";
|
||||
import { draggableOnDesktop } from "~/styles";
|
||||
import RightSidebar from "~/components/Sidebar/Right";
|
||||
import Tooltip from "~/components/Tooltip";
|
||||
import {
|
||||
Drawer,
|
||||
DrawerContent,
|
||||
DrawerTitle,
|
||||
} from "~/components/primitives/Drawer";
|
||||
import { PortalContext } from "~/components/Portal";
|
||||
import useMobile from "~/hooks/useMobile";
|
||||
import { draggableOnDesktop } from "~/styles";
|
||||
|
||||
type Props = Omit<React.HTMLAttributes<HTMLDivElement>, "title"> & {
|
||||
/* The title of the sidebar */
|
||||
@@ -24,7 +25,7 @@ type Props = Omit<React.HTMLAttributes<HTMLDivElement>, "title"> & {
|
||||
/* The content of the sidebar */
|
||||
children: React.ReactNode;
|
||||
/* Called when the sidebar is closed */
|
||||
onClose: () => void;
|
||||
onClose?: () => void;
|
||||
/* Whether the sidebar should be scrollable */
|
||||
scrollable?: boolean;
|
||||
};
|
||||
@@ -32,6 +33,7 @@ type Props = Omit<React.HTMLAttributes<HTMLDivElement>, "title"> & {
|
||||
function SidebarLayout({ title, onClose, children, scrollable = true }: Props) {
|
||||
const { t } = useTranslation();
|
||||
const isMobile = useMobile();
|
||||
const isWrapped = React.useContext(RightSidebarWrappedContext);
|
||||
const [drawerElement, setDrawerElement] =
|
||||
React.useState<HTMLDivElement | null>(null);
|
||||
|
||||
@@ -43,17 +45,21 @@ function SidebarLayout({ title, onClose, children, scrollable = true }: Props) {
|
||||
children
|
||||
);
|
||||
|
||||
return isMobile ? (
|
||||
<Drawer onClose={onClose} defaultOpen>
|
||||
<DrawerContent ref={setDrawerElement}>
|
||||
<DrawerTitle>{title}</DrawerTitle>
|
||||
<PortalContext.Provider value={drawerElement}>
|
||||
{content}
|
||||
</PortalContext.Provider>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
) : (
|
||||
<RightSidebar>
|
||||
if (isMobile) {
|
||||
return (
|
||||
<Drawer onClose={onClose} defaultOpen>
|
||||
<DrawerContent ref={setDrawerElement}>
|
||||
<DrawerTitle>{title}</DrawerTitle>
|
||||
<PortalContext.Provider value={drawerElement}>
|
||||
{content}
|
||||
</PortalContext.Provider>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
|
||||
const inner = (
|
||||
<>
|
||||
<Header>
|
||||
<Title>{title}</Title>
|
||||
<Tooltip content={t("Close")} shortcut="Esc">
|
||||
@@ -66,8 +72,14 @@ function SidebarLayout({ title, onClose, children, scrollable = true }: Props) {
|
||||
</Tooltip>
|
||||
</Header>
|
||||
{content}
|
||||
</RightSidebar>
|
||||
</>
|
||||
);
|
||||
|
||||
if (isWrapped) {
|
||||
return inner;
|
||||
}
|
||||
|
||||
return <RightSidebar>{inner}</RightSidebar>;
|
||||
}
|
||||
|
||||
const ForwardIcon = styled(BackIcon)`
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
import { observer } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import { Route, matchPath, useLocation } from "react-router-dom";
|
||||
import {
|
||||
RightSidebarWrappedContext,
|
||||
useSetRightSidebar,
|
||||
} from "~/components/RightSidebarContext";
|
||||
import RightSidebar from "~/components/Sidebar/Right";
|
||||
import PlaceholderText from "~/components/PlaceholderText";
|
||||
import useMobile from "~/hooks/useMobile";
|
||||
import useStores from "~/hooks/useStores";
|
||||
import lazyWithRetry from "~/utils/lazyWithRetry";
|
||||
import { matchDocumentHistory, matchDocumentSlug } from "~/utils/routeHelpers";
|
||||
import SidebarLayout from "~/scenes/Document/components/SidebarLayout";
|
||||
|
||||
const DocumentComments = lazyWithRetry(
|
||||
() => import("~/scenes/Document/components/Comments/Comments")
|
||||
);
|
||||
const DocumentHistory = lazyWithRetry(
|
||||
() => import("~/scenes/Document/components/History")
|
||||
);
|
||||
|
||||
interface DocumentSidebarContentProps {
|
||||
skipInitialAnimation?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stable component that reads `ui.rightSidebar` and renders the appropriate
|
||||
* sidebar content. On desktop, wraps content in a single Right sidebar that
|
||||
* stays mounted across panel switches to avoid re-triggering the open/close
|
||||
* animation.
|
||||
*/
|
||||
const DocumentSidebarContent = observer(function DocumentSidebarContent({
|
||||
skipInitialAnimation,
|
||||
}: DocumentSidebarContentProps) {
|
||||
const { ui } = useStores();
|
||||
const isMobile = useMobile();
|
||||
|
||||
const inner = (
|
||||
<Route path={`/doc/${matchDocumentSlug}`}>
|
||||
<React.Suspense
|
||||
fallback={
|
||||
<SidebarLayout title={<PlaceholderText width={100} />}>
|
||||
{null}
|
||||
</SidebarLayout>
|
||||
}
|
||||
>
|
||||
{ui.rightSidebar === "comments" && <DocumentComments />}
|
||||
{ui.rightSidebar === "history" && <DocumentHistory />}
|
||||
</React.Suspense>
|
||||
</Route>
|
||||
);
|
||||
|
||||
if (isMobile) {
|
||||
return inner;
|
||||
}
|
||||
|
||||
return (
|
||||
<RightSidebar skipInitialAnimation={skipInitialAnimation}>
|
||||
<RightSidebarWrappedContext.Provider value={true}>
|
||||
{inner}
|
||||
</RightSidebarWrappedContext.Provider>
|
||||
</RightSidebar>
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* Manages the right sidebar for the Document scene. Syncs the history route
|
||||
* to store state, sets a stable component into the sidebar context when open,
|
||||
* and clears it when closed or on unmount.
|
||||
*/
|
||||
export default function useDocumentSidebar() {
|
||||
const { ui } = useStores();
|
||||
const location = useLocation();
|
||||
const setSidebar = useSetRightSidebar();
|
||||
const isHistoryRoute = !!matchPath(location.pathname, {
|
||||
path: matchDocumentHistory,
|
||||
});
|
||||
const isOpen = ui.rightSidebar !== null;
|
||||
const isInitialOpenRef = React.useRef(isOpen);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isHistoryRoute) {
|
||||
ui.set({ rightSidebar: "history" });
|
||||
} else if (ui.rightSidebar === "history") {
|
||||
ui.set({ rightSidebar: null });
|
||||
}
|
||||
}, [isHistoryRoute, ui]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isOpen) {
|
||||
setSidebar(
|
||||
<DocumentSidebarContent
|
||||
skipInitialAnimation={isInitialOpenRef.current}
|
||||
/>
|
||||
);
|
||||
isInitialOpenRef.current = false;
|
||||
} else {
|
||||
setSidebar(null);
|
||||
}
|
||||
}, [isOpen, setSidebar]);
|
||||
|
||||
React.useEffect(
|
||||
() => () => {
|
||||
setSidebar(null);
|
||||
},
|
||||
[setSidebar]
|
||||
);
|
||||
}
|
||||
@@ -28,7 +28,7 @@ export enum SystemTheme {
|
||||
type PersistedData = Pick<
|
||||
UiStore,
|
||||
| "languagePromptDismissed"
|
||||
| "commentsExpanded"
|
||||
| "rightSidebar"
|
||||
| "theme"
|
||||
| "sidebarWidth"
|
||||
| "sidebarRightWidth"
|
||||
@@ -78,7 +78,7 @@ class UiStore {
|
||||
sidebarCollapsed = false;
|
||||
|
||||
@observable
|
||||
commentsExpanded = false;
|
||||
rightSidebar: "comments" | "history" | null = null;
|
||||
|
||||
@observable
|
||||
sidebarIsResizing = false;
|
||||
@@ -111,7 +111,7 @@ class UiStore {
|
||||
this.sidebarRightWidth =
|
||||
data.sidebarRightWidth || defaultTheme.sidebarRightWidth;
|
||||
this.tocVisible = data.tocVisible;
|
||||
this.commentsExpanded = !!data.commentsExpanded;
|
||||
this.rightSidebar = data.rightSidebar ?? null;
|
||||
this.theme = data.theme || Theme.System;
|
||||
|
||||
// system theme listeners
|
||||
@@ -340,11 +340,6 @@ class UiStore {
|
||||
this.persist();
|
||||
};
|
||||
|
||||
@action
|
||||
toggleComments = () => {
|
||||
this.set({ commentsExpanded: !this.commentsExpanded });
|
||||
};
|
||||
|
||||
@action
|
||||
toggleCollapsedSidebar = () => {
|
||||
sidebarHidden = false;
|
||||
@@ -433,7 +428,7 @@ class UiStore {
|
||||
sidebarWidth: this.sidebarWidth,
|
||||
sidebarRightWidth: this.sidebarRightWidth,
|
||||
languagePromptDismissed: this.languagePromptDismissed,
|
||||
commentsExpanded: this.commentsExpanded,
|
||||
rightSidebar: this.rightSidebar,
|
||||
theme: this.theme,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user