fix(theme): restore article styles on doc pages
Overriding DocContent took the upstream module out of the bundle, and with it the `doc.css` it imports as a side effect. Every page rendering through DocLayout lost its article typography, table scroll container and heading anchors — while the rest of the theme stayed intact, which is why only some styles went missing. The sole reference to the upstream component was a `typeof`, erased at compile time, so the bundler saw a module it could drop. - Delegate to the upstream component when a page has no hoisted bands, which keeps that module and its stylesheet in the dependency graph. - Move the hoisting variant into its own component, so useScrollAfterNav is not called after a conditional return. DocContent survives client-side navigation, so its hook count has to stay constant.
This commit is contained in:
1 file changed
+36
-12
@@ -1,6 +1,6 @@
|
|||||||
import type { ComponentProps } from "react"
|
import type { ComponentProps } from "react"
|
||||||
import { MDXProvider } from "@mdx-js/react"
|
import { MDXProvider } from "@mdx-js/react"
|
||||||
import { Content, usePage, useSite } from "@rspress/core/runtime"
|
import { Content, useFrontmatter, usePage, useSite } from "@rspress/core/runtime"
|
||||||
import {
|
import {
|
||||||
Callout,
|
Callout,
|
||||||
DocContent as OriginalDocContent,
|
DocContent as OriginalDocContent,
|
||||||
@@ -27,23 +27,25 @@ function FallbackTitle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mirrors `@rspress/core`'s `DocContent`, with one addition: the bands a page
|
* Upstream's `DocContent`, with one addition: the bands a page marks
|
||||||
* marks `placement: top` render between the page title and the article body.
|
* `placement: top` render between the page title and the article body.
|
||||||
*
|
*
|
||||||
* Rspress has no slot for that position. `beforeDocContent` sits above the
|
* Rspress has no slot for that position. `beforeDocContent` sits above the
|
||||||
* title, and `afterDocContent` and the `Layout`'s `afterDoc` both sit below the
|
* title, and `afterDocContent` and the `Layout`'s `afterDoc` both sit below the
|
||||||
* whole article — which is why sections used to land at the foot of the
|
* whole article — which is why sections used to land at the foot of the
|
||||||
* products page. Replacing this component is the only way in, so it is a
|
* products page. Replacing the component is the only way in.
|
||||||
* deliberate copy of upstream and is worth re-diffing whenever Rspress is
|
|
||||||
* upgraded. Everything below comes straight from upstream: `useScrollAfterNav`
|
|
||||||
* restores the scroll position after a client-side navigation, and the MDX
|
|
||||||
* component map is layered as defaults, then the caller's overrides, then the
|
|
||||||
* placeholder the compiled MDX uses for callouts.
|
|
||||||
*
|
*
|
||||||
* Every page rendering through `DocLayout` goes through here, so be careful:
|
* Everything except the inserted `<HomeSections>` is copied from upstream:
|
||||||
* a mistake affects blogs and project pages as much as the marketing ones.
|
* `useScrollAfterNav` restores the scroll position after a client-side
|
||||||
|
* navigation, and the MDX component map is layered as defaults, then the
|
||||||
|
* caller's overrides, then the placeholder the compiled MDX uses for callouts.
|
||||||
|
* Worth re-diffing whenever Rspress is upgraded.
|
||||||
|
*
|
||||||
|
* A separate component rather than a branch inside `DocContent`, because the
|
||||||
|
* hook below must not be called conditionally — `DocContent` survives
|
||||||
|
* client-side navigation, so the number of hooks it calls has to stay constant.
|
||||||
*/
|
*/
|
||||||
export function DocContent({
|
function HoistedDocContent({
|
||||||
components,
|
components,
|
||||||
isOverviewPage = false,
|
isOverviewPage = false,
|
||||||
beforeDocContent,
|
beforeDocContent,
|
||||||
@@ -67,3 +69,25 @@ export function DocContent({
|
|||||||
</MDXProvider>
|
</MDXProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the page body. Pages with nothing to hoist delegate to upstream
|
||||||
|
* rather than re-rendering its markup here.
|
||||||
|
*
|
||||||
|
* That is not only about drift. Upstream's module carries `doc.css` as a
|
||||||
|
* side-effect import, and the only reference to the component above is in a
|
||||||
|
* `typeof` — which a bundler may treat as no reference at all. It then drops
|
||||||
|
* the module, and the article stylesheet is dropped with it. Keeping a real
|
||||||
|
* render path to upstream is what holds those styles in the bundle.
|
||||||
|
*/
|
||||||
|
export function DocContent(props: DocContentProps) {
|
||||||
|
const { frontmatter } = useFrontmatter()
|
||||||
|
|
||||||
|
const raw = frontmatter?.sections
|
||||||
|
const hasHoistedBands =
|
||||||
|
Array.isArray(raw) &&
|
||||||
|
raw.some((entry) => (entry as { placement?: unknown } | null)?.placement === "top")
|
||||||
|
|
||||||
|
if (!hasHoistedBands) return <OriginalDocContent {...props} />
|
||||||
|
return <HoistedDocContent {...props} />
|
||||||
|
}
|
||||||
Reference in new issue
Block a user