commit 10617301013d021ffe8bc7106cbc2ceb0b454a3d
parent c0f78d7df78d462df1ad045bfd935ab7db4056c9
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Tue, 6 Oct 2026 19:48:50 -0400
reports: a #<id> link in report markdown stays in the tab
CitedMarkdown sent every non-citation link to a new tab, so a summary line
linking to a section on the same page opened a second copy of the page.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/common/components/citations/CitedMarkdown.tsx b/common/components/citations/CitedMarkdown.tsx
@@ -7,7 +7,8 @@ import { InlineCite } from "./InlineCite";
// Report markdown with its citations live: every `[label](cite:<id>)` link
// (lib/citations/inline.ts) becomes an InlineCite for that id; every other
-// link renders as Markdown's own external link. The house markdown setup
+// link renders as Markdown's own external link, except a `#<id>` link to a
+// place on the same page, which stays in the tab. The house markdown setup
// (Markdown.tsx — markdown-to-jsx, raw HTML escaped, token-styled) is
// unchanged; this only swaps its link component. A `cite:` link inside code is
// code, never a citation: markdown-to-jsx makes no link there.
@@ -28,6 +29,13 @@ type Citations = Readonly<Record<string, CitationView>>;
function CiteLink({ href, children: label, ...rest }: AnchorHTMLAttributes<HTMLAnchorElement>) {
const id = citeIdOf(href);
if (id !== null) return <InlineCite id={id}>{label}</InlineCite>;
+ if (href?.startsWith("#")) {
+ return (
+ <a {...rest} href={href} className={EXTERNAL_LINK_CLASS}>
+ {label}
+ </a>
+ );
+ }
return (
<a {...rest} href={href} target="_blank" rel="noopener noreferrer" className={EXTERNAL_LINK_CLASS}>
{label}
diff --git a/common/components/citations/citations.test.ts b/common/components/citations/citations.test.ts
@@ -194,6 +194,10 @@ test("cited markdown: cite links become inline cites, other links stay links, co
assert.match(html, /\[5\]/);
assert.match(html, /<a [^>]*href="https:\/\/example.org\/z" target="_blank" rel="noopener noreferrer"[^>]*>elsewhere<\/a>/);
assert.match(html, /<code[^>]*>\[x\]\(cite:c01\)<\/code>/);
+ // a link to a place on the same page stays in the tab
+ const jump = render(h(CitedMarkdown, { citations: {}, children: "[the claims](#claims)" }));
+ assert.match(jump, /<a [^>]*href="#claims"[^>]*>the claims<\/a>/);
+ assert.doesNotMatch(jump, /target=/);
// an id the map lacks renders as its label
assert.ok(render(h(CitedMarkdown, { citations: {}, children: "[gone](cite:zz)" })).includes("gone"));
assert.equal(citeIdOf("cite:c01"), "c01");