From 53887c5592c49dc36d02357dee3240040be9a4b4 Mon Sep 17 00:00:00 2001 From: nejcc Date: Mon, 26 Oct 2026 22:20:14 +0100 Subject: [PATCH] fix: copy the whole code block from a folded commit A folded commit shows only the first lines of a code block that starts it, and the copy button copied just those. The folded body now gives that block the whole block's html to copy. --- resources/js/components/code-block.tsx | 12 +++++++++++- resources/js/components/commit-body.tsx | 17 ++++++++++++++++- resources/js/types/commit.ts | 8 +++++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/resources/js/components/code-block.tsx b/resources/js/components/code-block.tsx index cf04563d3..ddcb41c13 100644 --- a/resources/js/components/code-block.tsx +++ b/resources/js/components/code-block.tsx @@ -7,10 +7,12 @@ import { cn } from '@/lib/utils'; export function CodeBlock({ html, + wholeHtml, language, isCopyable = true, }: { html: string; + wholeHtml?: string; language: string | null; isCopyable?: boolean; }) { @@ -34,7 +36,15 @@ export function CodeBlock({ return; } - if (await copy(codeRef.current.textContent ?? '')) { + // A template's content is inert: nothing in it loads or runs. + const whole = document.createElement('template'); + whole.innerHTML = wholeHtml ?? ''; + const code = + wholeHtml === undefined + ? codeRef.current.textContent + : whole.content.textContent; + + if (await copy(code ?? '')) { setIsCopied(true); return; diff --git a/resources/js/components/commit-body.tsx b/resources/js/components/commit-body.tsx index fac23d0a0..13745fe46 100644 --- a/resources/js/components/commit-body.tsx +++ b/resources/js/components/commit-body.tsx @@ -91,6 +91,7 @@ export function BodySegments({ @@ -128,6 +129,20 @@ export function FoldedCommitBody({ ); } + // The preview only ever cuts a code block that starts the body, and what comes before it is the same in both, so + // its first block copies the whole block at the same place. + const firstBlock = previewSegments.findIndex( + (segment) => segment.type === 'block', + ); + const whole = segments[firstBlock]; + const preview = previewSegments.map((segment, index) => + index === firstBlock && + segment.type === 'block' && + whole?.type === 'block' + ? { ...segment, wholeHtml: whole.html } + : segment, + ); + // The button goes away, so focus moves to what was unfolded: the commit card, which the keyboard shortcuts walk, // or the body itself inside a reply, which they don't. const unfold = (button: HTMLButtonElement) => { @@ -147,7 +162,7 @@ export function FoldedCommitBody({ return (
diff --git a/resources/js/types/commit.ts b/resources/js/types/commit.ts index 8af6a4e68..079052a93 100644 --- a/resources/js/types/commit.ts +++ b/resources/js/types/commit.ts @@ -50,7 +50,13 @@ export type CommitImage = { export type BodySegment = | { type: 'text'; text: string } | { type: 'code'; code: string } - | { type: 'block'; language: string | null; html: string }; + | { + type: 'block'; + language: string | null; + html: string; + // The whole block, when a folded body shows only its first lines. + wholeHtml?: string; + }; export type CommitTranslation = { language: string;