Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@
"tailwindCSS.classFunctions": ["clsx"],
"editor.quickSuggestions": {
"strings": "on"
}
},
"typescript.preferences.autoImportFileExcludePatterns": [
"**/node_modules/lucide-react"
]
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"react-use-measure": "^2.1.7",
"rehype-mermaid": "^3.0.0",
"rss": "1.2.2",
"scroll-into-view-if-needed": "^3.1.0",
"server-only": "0.0.1",
"string-similarity": "^4.0.4",
"string-strip-html": "^13.4.8",
Expand Down
30 changes: 27 additions & 3 deletions patches/nextra-theme-docs.patch
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
diff --git a/dist/index.d.mts b/dist/index.d.mts
index 71f87bcd1dde49d7c19ad49fc098e715a76c5c10..6671e29326be99861058895916185910452ced17 100644
index 71f87bcd1dde49d7c19ad49fc098e715a76c5c10..aadd6228910ee3ebafccfae8672cb9ae1b0bca3c 100644
--- a/dist/index.d.mts
+++ b/dist/index.d.mts
@@ -1421,3 +1421,19 @@ declare function ThemeSwitch({ lite, className }: ThemeSwitchProps): ReactElemen
@@ -1421,3 +1421,25 @@ declare function ThemeSwitch({ lite, className }: ThemeSwitchProps): ReactElemen
declare function Layout({ children, themeConfig, pageOpts }: NextraThemeLayoutProps): ReactElement;

export { Bleed, Collapse, type PartialDocsThemeConfig as DocsThemeConfig, Link, LocaleSwitch, Navbar, NotFoundPage, SkipNavContent, SkipNavLink, ThemeSwitch, Layout as default, getComponents, useConfig, useMenu, useThemeConfig };
Expand All @@ -22,8 +22,14 @@ index 71f87bcd1dde49d7c19ad49fc098e715a76c5c10..6671e29326be99861058895916185910
+export declare const useIntersectionObserver: () => IntersectionObserver | null
+export declare const useSlugs: () => WeakMap<any, any>
+
+export declare const Breadcrumb: (props: { activePath: Item[] }) => ReactElement | null
+export declare const NavLinks: (props: NavLinkProps) => ReactElement | null
+export interface NavLinkProps {
+ currentIndex: number
+ flatDocsDirectories: Item[]
+}
diff --git a/dist/index.js b/dist/index.js
index 56201641fd965dcc5ab7c5df53e444c41293c00e..860b8cfd297e82da041c4d8287ed266691d75a0e 100644
index 56201641fd965dcc5ab7c5df53e444c41293c00e..07147c688ae75c4c7daf082833acc71de16b36ee 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -100,10 +100,10 @@ IntersectionObserverContext.displayName = "IntersectionObserver";
Expand All @@ -41,3 +47,21 @@ index 56201641fd965dcc5ab7c5df53e444c41293c00e..860b8cfd297e82da041c4d8287ed2666
var ActiveAnchorProvider = ({
children
}) => {
@@ -526,7 +526,7 @@ import NextLink2 from "next/link";
import { ArrowRightIcon } from "nextra/icons";
import { Fragment as Fragment3 } from "react";
import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
-function Breadcrumb({
+export function Breadcrumb({
activePath
}) {
return /* @__PURE__ */ jsx9("div", { className: "nextra-breadcrumb _mt-1.5 _flex _items-center _gap-1 _overflow-hidden _text-sm _text-gray-500 dark:_text-gray-400 contrast-more:_text-current", children: activePath.map((item, index, arr) => {
@@ -1255,7 +1255,7 @@ var classes = {
),
icon: cn10("_inline _h-5 _shrink-0")
};
-function NavLinks({
+export function NavLinks({
flatDocsDirectories,
currentIndex
}) {
9 changes: 6 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 54 additions & 0 deletions src/components/back-to-top.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* @file BackToTop component extracted from Nextra
*/

import { clsx } from "clsx"
import { Button } from "nextra/components"
import { ArrowRightIcon } from "nextra/icons"
import type { ComponentProps, ReactElement, ReactNode } from "react"

const SCROLL_TO_OPTIONS = { top: 0, behavior: "smooth" } as const

const scrollToTop: ComponentProps<"button">["onClick"] = event => {
const buttonElement = event.currentTarget
const tocElement = buttonElement.parentElement!.parentElement!

window.scrollTo(SCROLL_TO_OPTIONS)
tocElement.scrollTo(SCROLL_TO_OPTIONS)

// Fixes https://github.com/facebook/react/issues/20770
// Fixes https://github.com/shuding/nextra/issues/2917
buttonElement.disabled = true
}

export function BackToTop({
children,
className,
hidden,
}: {
children: ReactNode
className?: string
hidden: boolean
}): ReactElement {
return (
<Button
// elements with `aria-hidden: true` must not be focusable or contain focusable elements
aria-hidden={hidden ? "true" : undefined}
onClick={scrollToTop}
disabled={hidden}
className={({ disabled }) =>
clsx(
"flex items-center gap-1.5",
disabled ? "opacity-0" : "opacity-100",
className,
)
}
>
{children}
<ArrowRightIcon
height="16"
className="-rotate-90 rounded-full border border-current"
/>
</Button>
)
}
155 changes: 155 additions & 0 deletions src/components/nextra-mdx-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import type { ReactElement, ReactNode } from "react"
import { useMounted } from "nextra/hooks"
import { Heading } from "nextra"
import {
useConfig,
useThemeConfig,
SkipNavContent,
Breadcrumb,
NavLinks,
} from "nextra-theme-docs"
import { clsx } from "clsx"

import { Sidebar } from "./sidebar"
import { renderComponent } from "./utils"
import { TableOfContents } from "./table-of-contents"

const classes = {
toc: clsx("nextra-toc order-last max-xl:hidden w-64 shrink-0 print:hidden"),
main: clsx("w-full break-words"),
}

export interface NextraMdxWrapperProps {
toc?: Heading[]
children?: React.ReactNode
}

export function NextraMdxWrapper({
toc = [],
children,
}: NextraMdxWrapperProps) {
const config = useConfig()
const {
activeType,
activeThemeContext: themeContext,
docsDirectories,
directories,
} = config.normalizePagesResult

const tocEl =
activeType === "page" ||
!themeContext.toc ||
themeContext.layout !== "default" ? (
themeContext.layout !== "full" &&
themeContext.layout !== "raw" && (
<nav className={classes.toc} aria-label="table of contents" />
)
) : (
<nav className={classes.toc} aria-label="table of contents">
<TableOfContents toc={toc} filePath={config.filePath} />
</nav>
)
return (
<div
className={clsx(
"mx-auto flex",
themeContext.layout !== "raw" && "max-w-[90rem]",
)}
>
<Sidebar
docsDirectories={docsDirectories}
fullDirectories={directories}
toc={toc}
asPopover={config.hideSidebar}
includePlaceholder={themeContext.layout === "default"}
/>
{tocEl}
<SkipNavContent />
<Body>{children}</Body>
</div>
)
}

function Body({ children }: { children: ReactNode }): ReactElement {
const config = useConfig()
const themeConfig = useThemeConfig()
const mounted = useMounted()
const {
activeThemeContext: themeContext,
activeType,
activeIndex,
flatDocsDirectories,
activePath,
} = config.normalizePagesResult

if (themeContext.layout === "raw") {
return <div className={classes.main}>{children}</div>
}

const date =
themeContext.timestamp && themeConfig.gitTimestamp && config.timestamp
? new Date(config.timestamp)
: null
Comment on lines +89 to +92
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memoize this? usually creating new Date causes re-renders


const gitTimestampEl =
// Because a user's time zone may be different from the server page
mounted && date ? (
<div className="mb-8 mt-12 block text-xs text-neu-500 ltr:text-right rtl:text-left">
{renderComponent(themeConfig.gitTimestamp, { timestamp: date })}
</div>
) : (
<div className="mt-16" />
)

const content = (
<>
{renderComponent(themeContext.topContent)}
{children}
{gitTimestampEl}
{renderComponent(themeContext.bottomContent)}
{activeType !== "page" && themeContext.pagination && (
<NavLinks
flatDocsDirectories={flatDocsDirectories}
currentIndex={activeIndex}
/>
)}
</>
)

const body = themeConfig.main ? (
<themeConfig.main>{content}</themeConfig.main>
) : (
content
)

if (themeContext.layout === "full") {
return (
<article
className={clsx(
classes.main,
"nextra-content min-h-[calc(100vh-var(--nextra-navbar-height))] pl-[max(env(safe-area-inset-left),1.5rem)] pr-[max(env(safe-area-inset-right),1.5rem)]",
)}
>
{body}
</article>
)
}

return (
<article
className={clsx(
classes.main,
"nextra-content flex min-h-[calc(100vh-var(--nextra-navbar-height))] min-w-0 justify-center pb-8 pr-[calc(env(safe-area-inset-right)-1.5rem)]",
themeContext.typesetting === "article" &&
"nextra-body-typesetting-article",
)}
>
<main className="w-full min-w-0 max-w-6xl px-6 pt-4 md:px-12">
{activeType !== "page" && themeContext.breadcrumb && (
<Breadcrumb activePath={activePath} />
)}
{body}
</main>
</article>
)
}
Loading