diff --git a/packages/gitbook/src/components/DocumentView/InlineLink/InlineLinkTooltip.tsx b/packages/gitbook/src/components/DocumentView/InlineLink/InlineLinkTooltip.tsx index 15ec1c514a..5f548e085c 100644 --- a/packages/gitbook/src/components/DocumentView/InlineLink/InlineLinkTooltip.tsx +++ b/packages/gitbook/src/components/DocumentView/InlineLink/InlineLinkTooltip.tsx @@ -1,37 +1,9 @@ 'use client'; -import dynamic from 'next/dynamic'; -import React from 'react'; +import { tcls } from '@/lib/tailwind'; +import { Icon } from '@gitbook/icons'; +import { Fragment } from 'react'; +import { Button, HoverCard, HoverCardRoot, HoverCardTrigger, StyledLink } from '../../primitives'; -const LoadingValueContext = React.createContext(null); - -// To avoid polluting the RSC payload with the tooltip implementation, -// we lazily load it on the client side. This way, the tooltip is only loaded -// when the user interacts with the link, and it doesn't block the initial render. - -const InlineLinkTooltipImpl = dynamic( - () => import('./InlineLinkTooltipImpl').then((mod) => mod.InlineLinkTooltipImpl), - { - // Disable server-side rendering for this component, it's only - // visible on user interaction. - ssr: false, - loading: () => { - // The fallback should be the children (the content of the link), - // but as next/dynamic is aiming for feature parity with React.lazy, - // it doesn't support passing children to the loading component. - // https://github.com/vercel/next.js/issues/7906 - const children = React.useContext(LoadingValueContext); - return <>{children}; - }, - } -); - -/** - * Tooltip for inline links. It's lazily loaded to avoid blocking the initial render - * and polluting the RSC payload. - * - * The link text and href have already been rendered on the server for good SEO, - * so we can be as lazy as possible with the tooltip. - */ export function InlineLinkTooltip(props: { isSamePage: boolean; isExternal: boolean; @@ -45,28 +17,79 @@ export function InlineLinkTooltip(props: { openInNewTabLabel: string; children: React.ReactNode; }) { - const { children, ...rest } = props; - const [shouldLoad, setShouldLoad] = React.useState(false); + const { isSamePage, isExternal, openInNewTabLabel, target, breadcrumbs, children } = props; - // Once the browser is idle, we set shouldLoad to true. - // NOTE: to be slightly more performant, we could load when a link is hovered. - // But I found this was too much of a delay for the tooltip to appear. - // Loading on idle is a good compromise, as it allows the initial render to be fast, - // while still loading the tooltip in the background and not polluting the RSC payload. - React.useEffect(() => { - if ('requestIdleCallback' in window) { - (window as globalThis.Window).requestIdleCallback(() => setShouldLoad(true)); - } else { - // fallback for old browsers - setTimeout(() => setShouldLoad(true), 2000); - } - }, []); + return ( + + {children} + +
+
+ {breadcrumbs && breadcrumbs.length > 0 ? ( +
+ {breadcrumbs.map((crumb, index) => { + const Tag = crumb.href ? StyledLink : 'div'; - return shouldLoad ? ( - - {children} - - ) : ( - children + return ( + + {index !== 0 ? ( + + ) : null} + + {crumb.icon ? ( + + {crumb.icon} + + ) : null} + {crumb.label} + + + ); + })} +
+ ) : null} +
+ {target.icon ? ( +
+ {target.icon} +
+ ) : null} +
{target.text}
+
+
+ {!isSamePage && target.href ? ( +
+ {target.subText ?

{target.subText}

: null} +
+
); } diff --git a/packages/gitbook/src/components/DocumentView/InlineLink/InlineLinkTooltipImpl.tsx b/packages/gitbook/src/components/DocumentView/InlineLink/InlineLinkTooltipImpl.tsx deleted file mode 100644 index 5244c0a0b9..0000000000 --- a/packages/gitbook/src/components/DocumentView/InlineLink/InlineLinkTooltipImpl.tsx +++ /dev/null @@ -1,95 +0,0 @@ -'use client'; -import { tcls } from '@/lib/tailwind'; -import { Icon } from '@gitbook/icons'; -import { Fragment } from 'react'; -import { Button, HoverCard, HoverCardRoot, HoverCardTrigger, StyledLink } from '../../primitives'; - -export function InlineLinkTooltipImpl(props: { - isSamePage: boolean; - isExternal: boolean; - breadcrumbs: Array<{ href?: string; label: string; icon?: React.ReactNode }>; - target: { - href: string; - text: string; - subText?: string; - icon?: React.ReactNode; - }; - openInNewTabLabel: string; - children: React.ReactNode; -}) { - const { isSamePage, isExternal, openInNewTabLabel, target, breadcrumbs, children } = props; - - return ( - - {children} - -
-
- {breadcrumbs && breadcrumbs.length > 0 ? ( -
- {breadcrumbs.map((crumb, index) => { - const Tag = crumb.href ? StyledLink : 'div'; - - return ( - - {index !== 0 ? ( - - ) : null} - - {crumb.icon ? ( - - {crumb.icon} - - ) : null} - {crumb.label} - - - ); - })} -
- ) : null} -
- {target.icon ? ( -
- {target.icon} -
- ) : null} -
{target.text}
-
-
- {!isSamePage && target.href ? ( -
- {target.subText ?

{target.subText}

: null} -
-
- ); -} diff --git a/packages/gitbook/src/components/PageBody/PageBody.tsx b/packages/gitbook/src/components/PageBody/PageBody.tsx index 6f1e8bfca9..adbe4de322 100644 --- a/packages/gitbook/src/components/PageBody/PageBody.tsx +++ b/packages/gitbook/src/components/PageBody/PageBody.tsx @@ -18,7 +18,7 @@ import { PageFooterNavigation } from './PageFooterNavigation'; import { PageHeader } from './PageHeader'; import { PreservePageLayout } from './PreservePageLayout'; -const LINK_PREVIEW_MAX_COUNT = 100; +const LINK_PREVIEW_MAX_COUNT = 500; export function PageBody(props: { context: GitBookSiteContext; diff --git a/packages/gitbook/src/components/PageIcon/PageIcon.tsx b/packages/gitbook/src/components/PageIcon/PageIcon.tsx index f935df7824..881bc803e2 100644 --- a/packages/gitbook/src/components/PageIcon/PageIcon.tsx +++ b/packages/gitbook/src/components/PageIcon/PageIcon.tsx @@ -27,4 +27,6 @@ export function PageIcon(props: { if (page.icon) { return ; } + + return null; } diff --git a/packages/gitbook/src/lib/references.tsx b/packages/gitbook/src/lib/references.tsx index 4d08c7646d..b6abe60836 100644 --- a/packages/gitbook/src/lib/references.tsx +++ b/packages/gitbook/src/lib/references.tsx @@ -130,7 +130,13 @@ export async function resolveContentRef( const ancestors = resolvePageResult?.ancestors.map((ancestor) => ({ label: ancestor.title, - icon: , + icon: + ancestor.emoji || ancestor.icon ? ( + + ) : null, href: linker.toPathForPage({ page: ancestor, pages: revision.pages }), })) ?? []; if (!page) {