Monorepo for Tangled tangled.org

[feature] - Add copy-to-clipboard button for markdown code blocks #1114

Summary#

  • Injects a copy button into .prose pre.chroma code blocks via client-side DOM injection in base.html
  • Scoped to .prose so blob view source code (which has its own UX) is unaffected
  • Handles HTMX-swapped content (dynamic comment loading) via htmx:afterSettle listener

Test plan#

  • go test ./appview/pages/markup/... passes (no regressions)
  • Verify button appears on hover over code blocks in rendered markdown
  • Verify clicking copies code and shows check icon briefly
  • Verify dark mode styling
  • Verify blob view code blocks do NOT get copy buttons
Labels

None yet.

assignee

None yet.

Participants 3
AT URI
at://did:plc:c7frv4rcitff3p2nh7of5bcv/sh.tangled.repo.pull/3mgbmydvrsw22
+10 -9
Interdiff #4 โ†’ #5
+5 -7
appview/pages/markup/extension/codecopy.go
··· 1 1 package extension 2 2 3 3 import ( 4 - "fmt" 5 4 "io/fs" 6 5 "path/filepath" 7 6 "strings" ··· 73 72 if entering { 74 73 _, _ = w.WriteString(`<div class="code-copy-wrapper">`) 75 74 } else { 76 - _, _ = w.WriteString(fmt.Sprintf( 77 - `<button class="code-copy-btn" type="button" aria-label="Copy code to clipboard">`+ 78 - `<span class="copy-icon">%s</span>`+ 79 - `<span class="check-icon">%s</span>`+ 75 + _, _ = w.WriteString( 76 + `<button class="code-copy-btn" type="button" aria-label="Copy code to clipboard">` + 77 + `<span class="copy-icon">` + r.copyIconSVG + `</span>` + 78 + `<span class="check-icon">` + r.checkIconSVG + `</span>` + 80 79 `</button></div>`, 81 - r.copyIconSVG, r.checkIconSVG, 82 - )) 80 + ) 83 81 } 84 82 return ast.WalkContinue, nil 85 83 }
appview/pages/markup/markdown.go

This file has not been changed.

appview/pages/markup/markdown_test.go

This file has not been changed.

appview/pages/markup/sanitizer.go

This file has not been changed.

+5 -2
appview/pages/templates/layouts/base.html
··· 104 104 if (!btn) return; 105 105 var pre = btn.closest('.code-copy-wrapper').querySelector('pre'); 106 106 if (!pre) return; 107 - var code = pre.querySelector('code'); 108 - var text = code ? code.innerText : pre.innerText; 107 + var el = pre.querySelector('code') || pre; 108 + var lines = el.querySelectorAll('.line'); 109 + var text = lines.length 110 + ? Array.prototype.map.call(lines, function(l) { return l.textContent; }).join('\n') 111 + : el.innerText; 109 112 navigator.clipboard.writeText(text).then(function() { 110 113 btn.classList.add('copied'); 111 114 setTimeout(function() { btn.classList.remove('copied'); }, 2000);
input.css

This file has not been changed.

History

6 rounds 6 comments
sign up or login to add to the discussion
1 commit
expand
appview/pages: add copy-to-clipboard button for markdown code blocks
no conflicts, ready to merge
expand 0 comments
1 commit
expand
appview/pages: add copy-to-clipboard button for markdown code blocks
expand 3 comments

works brilliantly! one nit: the copy button seems to add an extra newline for each line on my browser. do you notice the same behavior on your end?

will do a more thorough code review shortly!

I still need to look into this!! I asked Claude in the meantime, and it thinks you're right - there's an unnecessary carriage return

1 commit
expand
appview/pages: add copy-to-clipboard button for markdown code blocks
expand 0 comments
1 commit
expand
appview/pages: add copy-to-clipboard button for markdown code blocks
expand 0 comments
1 commit
expand
appview/pages: add copy-to-clipboard button for markdown code blocks
expand 3 comments

Thank you for the contribution! Few feedbacks:

  • here we can use icon template like others.
  • can we use tailwindcss for styling? using @applysyntax in css file.

i would prefer if we added this button using a goldmark extension instead of a clientside script!

Thank you for the feedback! I've updating the diff to use goldmark and apply tailwind classes.

1 commit
expand
appview/pages: add copy-to-clipboard button for markdown code blocks
expand 0 comments