File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -39,6 +39,8 @@ interface ReviewSummaryCardProps {
3939function useFindingAnchors ( summary : ReviewSummary ) : Map < number , string > {
4040 return useMemo ( ( ) => {
4141 const slugger = new GithubSlugger ( ) ;
42+ // Keyed by source line, which is unique per finding (the parser emits at
43+ // most one finding per line).
4244 const map = new Map < number , string > ( ) ;
4345 for ( const f of summary . findings ) {
4446 if ( ! f . title ) continue ;
Original file line number Diff line number Diff line change 11import { describe , expect , it } from "vitest" ;
22import { wrapRichTextBody } from "./copyRichText" ;
3+ import { cloneWithoutInjectedChrome } from "./export" ;
4+
5+ describe ( "cloneWithoutInjectedChrome" , ( ) => {
6+ it ( "strips the injected review card but keeps document content" , ( ) => {
7+ const body = document . createElement ( "div" ) ;
8+ body . className = "markdown-body" ;
9+ body . innerHTML =
10+ '<aside class="review-card">SUMMARY</aside><h1>Real Title</h1><p>Body text</p>' ;
11+ const cleaned = cloneWithoutInjectedChrome ( body ) ;
12+ expect ( cleaned . querySelector ( ".review-card" ) ) . toBeNull ( ) ;
13+ expect ( cleaned . innerHTML ) . toContain ( "<h1>Real Title</h1>" ) ;
14+ expect ( cleaned . innerHTML ) . toContain ( "Body text" ) ;
15+ // The original element is untouched (we clone, not mutate in place).
16+ expect ( body . querySelector ( ".review-card" ) ) . not . toBeNull ( ) ;
17+ } ) ;
18+
19+ it ( "is a no-op for a body with no injected chrome" , ( ) => {
20+ const body = document . createElement ( "div" ) ;
21+ body . innerHTML = "<h1>Doc</h1><p>x</p>" ;
22+ expect ( cloneWithoutInjectedChrome ( body ) . innerHTML ) . toBe ( "<h1>Doc</h1><p>x</p>" ) ;
23+ } ) ;
24+ } ) ;
325
426describe ( "wrapRichTextBody" , ( ) => {
527 it ( "wraps body markup in an inline-styled div" , ( ) => {
Original file line number Diff line number Diff line change 2222import DOMPurify from "dompurify" ;
2323import { useDocumentStore } from "../store/documentStore" ;
2424import { toast } from "../store/toastStore" ;
25- import { buildStandaloneHtml } from "./export" ;
25+ import { buildStandaloneHtml , cloneWithoutInjectedChrome } from "./export" ;
2626import { waitForElement } from "./waitForElement" ;
2727
2828/**
@@ -73,7 +73,10 @@ export function buildRichTextHtml(bodyInnerHtml: string): string {
7373 */
7474function captureRenderedBodyHtml ( ) : string {
7575 const el = document . querySelector ( ".markdown-body" ) ;
76- if ( el ) return el . innerHTML ;
76+ // Strip injected chrome (the review card) so the clipboard gets the document,
77+ // not Ashlr's rendering overlay. The fallback below routes through
78+ // buildStandaloneHtml → captureMarkdownBody, which already strips it.
79+ if ( el ) return cloneWithoutInjectedChrome ( el ) . innerHTML ;
7780
7881 // Fallback: reuse the export pipeline, then extract just the rendered body.
7982 try {
Original file line number Diff line number Diff line change @@ -39,6 +39,18 @@ function currentLayoutVars(): string {
3939 return `--content-width:${ width } ;--content-font-size:${ fontSize } ;` ;
4040}
4141
42+ /**
43+ * Clone an element and strip Ashlr-injected UI chrome that lives inside
44+ * `.markdown-body` but is NOT part of the document — currently the review
45+ * summary card. Exports and rich-text copies should contain the document, not
46+ * the app's rendering overlay.
47+ */
48+ export function cloneWithoutInjectedChrome ( el : Element ) : Element {
49+ const clone = el . cloneNode ( true ) as Element ;
50+ for ( const node of clone . querySelectorAll ( ".review-card" ) ) node . remove ( ) ;
51+ return clone ;
52+ }
53+
4254/**
4355 * Reads the live `.markdown-body` element and returns its `outerHTML`.
4456 * Throws a descriptive string (shown in the dialog) when the element is
@@ -49,7 +61,7 @@ function captureMarkdownBody(): string {
4961 if ( ! el ) {
5062 throw "Switch to Read view before exporting." ;
5163 }
52- return el . outerHTML ;
64+ return cloneWithoutInjectedChrome ( el ) . outerHTML ;
5365}
5466
5567/**
You can’t perform that action at this time.
0 commit comments