diff --git a/src/site/docs.tsx b/src/site/docs.tsx index 502d557..1bb3335 100644 --- a/src/site/docs.tsx +++ b/src/site/docs.tsx @@ -85,6 +85,7 @@ const inlineCode = "relative rounded-md bg-muted px-[0.3rem] py-[0.2rem] font-mo const linkClass = "font-medium underline underline-offset-4" function Prose({ children }: { children: string }) { + const { search } = useLocation() return ( { const target = resolveHref(href) return target.to ? ( - + {label} ) : ( @@ -358,14 +359,21 @@ function DocShell({ title, description, url, toc, children }: { title: string; d export function DocPage({ section }: { section: "docs" | "components" }) { const { slug = "introduction" } = useParams() - const { hash } = useLocation() + const { hash, key } = useLocation() const page = pages.find((entry) => entry.slug === slug && (section === "docs" ? entry.section === "docs" : entry.section !== "docs")) const manager = React.useState("pnpm") // A link to a heading lands on it once the page is there. React.useEffect(() => { - if (hash) document.getElementById(decodeURIComponent(hash.slice(1)))?.scrollIntoView() - }, [hash, page]) + if (!hash) return + let id = hash.slice(1) + try { + id = decodeURIComponent(id) + } catch { + // A malformed escape can still be a literal heading ID. + } + document.getElementById(id)?.scrollIntoView() + }, [hash, key, page]) if (!page) return return ( diff --git a/src/site/pages.ts b/src/site/pages.ts index 8ccb6c4..ea99da4 100644 --- a/src/site/pages.ts +++ b/src/site/pages.ts @@ -47,7 +47,8 @@ export const ordered: { title: string; url: string }[] = [ * other page of theirs stays theirs. */ export function resolveHref(href: string): { to?: string; href?: string } { - if (/^([a-z]+:|#)/i.test(href)) return { href } + if (href.startsWith("#")) return { to: href } + if (/^[a-z]+:/i.test(href)) return { href } const [path, hash = ""] = href.split("#") const component = path.match(/^\/docs\/components\/(?:base\/|radix\/)?([a-z0-9-]+)\/?$/)?.[1] const tail = hash ? `#${hash}` : ""