diff --git a/app/actions/definitions/collections.tsx b/app/actions/definitions/collections.tsx index 06039e0c34..e2a850823d 100644 --- a/app/actions/definitions/collections.tsx +++ b/app/actions/definitions/collections.tsx @@ -22,7 +22,6 @@ import { CollectionNew } from "~/components/Collection/CollectionNew"; import CollectionDeleteDialog from "~/components/CollectionDeleteDialog"; import ConfirmationDialog from "~/components/ConfirmationDialog"; import DynamicCollectionIcon from "~/components/Icons/CollectionIcon"; -import SharePopover from "~/components/Sharing/Collection/SharePopover"; import { getHeaderExpandedKey } from "~/components/Sidebar/components/Header"; import { createAction, @@ -37,10 +36,14 @@ import { searchPath, } from "~/utils/routeHelpers"; import ExportDialog from "~/components/ExportDialog"; +import lazyWithRetry from "~/utils/lazyWithRetry"; const ColorCollectionIcon = ({ collection }: { collection: Collection }) => ( ); +const SharePopover = lazyWithRetry( + () => import("~/components/Sharing/Collection/SharePopover") +); export const openCollection = createAction({ name: ({ t }) => t("Open collection"), diff --git a/app/actions/definitions/documents.tsx b/app/actions/definitions/documents.tsx index 9bdb5dae8d..eb4b5e08dd 100644 --- a/app/actions/definitions/documents.tsx +++ b/app/actions/definitions/documents.tsx @@ -50,7 +50,6 @@ import DeleteDocumentsInTrash from "~/scenes/Trash/components/DeleteDocumentsInT import ConfirmationDialog from "~/components/ConfirmationDialog"; import DocumentCopy from "~/components/DocumentCopy"; import MarkdownIcon from "~/components/Icons/MarkdownIcon"; -import SharePopover from "~/components/Sharing/Document"; import { getHeaderExpandedKey } from "~/components/Sidebar/components/Header"; import DocumentTemplatizeDialog from "~/components/TemplatizeDialog"; import { @@ -82,7 +81,14 @@ import { import capitalize from "lodash/capitalize"; import CollectionIcon from "~/components/Icons/CollectionIcon"; import { ActionV2, ActionV2Group, ActionV2Separator } from "~/types"; -import Insights from "~/scenes/Document/components/Insights"; +import lazyWithRetry from "~/utils/lazyWithRetry"; + +const Insights = lazyWithRetry( + () => import("~/scenes/Document/components/Insights") +); +const SharePopover = lazyWithRetry( + () => import("~/components/Sharing/Document/SharePopover") +); export const openDocument = createAction({ name: ({ t }) => t("Open document"), @@ -593,12 +599,15 @@ export const copyDocumentAsMarkdown = createActionV2({ iconInContextMenu: false, visible: ({ activeDocumentId, stores }) => !!activeDocumentId && stores.policies.abilities(activeDocumentId).download, - perform: ({ stores, activeDocumentId, t }) => { + perform: async ({ stores, activeDocumentId, t }) => { const document = activeDocumentId ? stores.documents.get(activeDocumentId) : undefined; if (document) { - copy(document.toMarkdown()); + const { ProsemirrorHelper } = await import( + "~/models/helpers/ProsemirrorHelper" + ); + copy(ProsemirrorHelper.toMarkdown(document)); toast.success(t("Markdown copied to clipboard")); } }, @@ -612,12 +621,15 @@ export const copyDocumentAsPlainText = createActionV2({ iconInContextMenu: false, visible: ({ activeDocumentId, stores }) => !!activeDocumentId && stores.policies.abilities(activeDocumentId).download, - perform: ({ stores, activeDocumentId, t }) => { + perform: async ({ stores, activeDocumentId, t }) => { const document = activeDocumentId ? stores.documents.get(activeDocumentId) : undefined; if (document) { - copy(document.toPlainText()); + const { ProsemirrorHelper } = await import( + "~/models/helpers/ProsemirrorHelper" + ); + copy(ProsemirrorHelper.toPlainText(document)); toast.success(t("Text copied to clipboard")); } }, diff --git a/app/components/AuthenticatedLayout.tsx b/app/components/AuthenticatedLayout.tsx index 2289b74242..5cd459dcac 100644 --- a/app/components/AuthenticatedLayout.tsx +++ b/app/components/AuthenticatedLayout.tsx @@ -13,7 +13,6 @@ import ErrorSuspended from "~/scenes/Errors/ErrorSuspended"; import Layout from "~/components/Layout"; import RegisterKeyDown from "~/components/RegisterKeyDown"; import Sidebar from "~/components/Sidebar"; -import SettingsSidebar from "~/components/Sidebar/Settings"; import useCurrentTeam from "~/hooks/useCurrentTeam"; import { usePostLoginPath } from "~/hooks/useLastVisitedPath"; import usePolicy from "~/hooks/usePolicy"; @@ -30,6 +29,7 @@ import { import { DocumentContextProvider } from "./DocumentContext"; import Fade from "./Fade"; import { PortalContext } from "./Portal"; +import CommandBar from "./CommandBar"; const DocumentComments = lazyWithRetry( () => import("~/scenes/Document/components/Comments") @@ -37,8 +37,9 @@ const DocumentComments = lazyWithRetry( const DocumentHistory = lazyWithRetry( () => import("~/scenes/Document/components/History") ); - -const CommandBar = lazyWithRetry(() => import("~/components/CommandBar")); +const SettingsSidebar = lazyWithRetry( + () => import("~/components/Sidebar/Settings") +); type Props = { children?: React.ReactNode; @@ -130,9 +131,7 @@ const AuthenticatedLayout: React.FC = ({ children }: Props) => { {children} - - - + diff --git a/app/components/Branding.tsx b/app/components/Branding.tsx index b7f70dca06..96f03fa74a 100644 --- a/app/components/Branding.tsx +++ b/app/components/Branding.tsx @@ -1,3 +1,4 @@ +import * as React from "react"; import styled from "styled-components"; import { depths, s } from "@shared/styles"; import env from "~/env"; @@ -44,4 +45,4 @@ const Link = styled.a` } `; -export default Branding; +export default React.memo(Branding); diff --git a/app/components/Dialogs.tsx b/app/components/Dialogs.tsx index b136566ca5..8306906312 100644 --- a/app/components/Dialogs.tsx +++ b/app/components/Dialogs.tsx @@ -1,7 +1,10 @@ import { observer } from "mobx-react"; -import Guide from "~/components/Guide"; -import Modal from "~/components/Modal"; +import { Suspense } from "react"; import useStores from "~/hooks/useStores"; +import lazyWithRetry from "~/utils/lazyWithRetry"; + +const Guide = lazyWithRetry(() => import("~/components/Guide")); +const Modal = lazyWithRetry(() => import("~/components/Modal")); function Dialogs() { const { dialogs } = useStores(); @@ -9,7 +12,7 @@ function Dialogs() { const modals = [...modalStack]; return ( - <> + {guide ? ( ))} - + ); } diff --git a/app/components/DocumentCard.tsx b/app/components/DocumentCard.tsx index ac470336ea..ec904c4dd5 100644 --- a/app/components/DocumentCard.tsx +++ b/app/components/DocumentCard.tsx @@ -3,8 +3,8 @@ import { CSS } from "@dnd-kit/utilities"; import { subDays } from "date-fns"; import { m } from "framer-motion"; import { observer } from "mobx-react"; -import { CloseIcon, DocumentIcon, ClockIcon, EyeIcon } from "outline-icons"; -import { useRef, useCallback, useMemo } from "react"; +import { CloseIcon, DocumentIcon, ClockIcon } from "outline-icons"; +import { useRef, useCallback, Suspense } from "react"; import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; import styled, { useTheme } from "styled-components"; @@ -19,10 +19,12 @@ import Flex from "~/components/Flex"; import NudeButton from "~/components/NudeButton"; import Time from "~/components/Time"; import useStores from "~/hooks/useStores"; -import { useTextStats } from "~/hooks/useTextStats"; import CollectionIcon from "./Icons/CollectionIcon"; import Text from "./Text"; import Tooltip from "./Tooltip"; +import lazyWithRetry from "~/utils/lazyWithRetry"; + +const ReadingTime = lazyWithRetry(() => import("./ReadingTime")); type Props = { /** The pin record */ @@ -76,6 +78,13 @@ function DocumentCard(props: Props) { const isRecentlyUpdated = new Date(document.updatedAt) > subDays(new Date(), 7); + const updatedAt = ( + <> + +