summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authoradamelmore <[email protected]>2026-02-23 08:23:46 -0600
committeradamelmore <[email protected]>2026-02-23 08:23:56 -0600
commit3b5b21a91e2a8f084ee8ed85aca81246880a9384 (patch)
tree0c5ad3a3998f1cc3f26a104db12eb564911f0fb1
parent8e96447960637c2371fb94ca7ce7b456048a0de6 (diff)
downloadopencode-3b5b21a91e2a8f084ee8ed85aca81246880a9384.tar.gz
opencode-3b5b21a91e2a8f084ee8ed85aca81246880a9384.zip
fix(app): duplicate markdown
-rw-r--r--packages/ui/src/components/markdown.tsx44
1 files changed, 35 insertions, 9 deletions
diff --git a/packages/ui/src/components/markdown.tsx b/packages/ui/src/components/markdown.tsx
index be43eca81..a5f440f81 100644
--- a/packages/ui/src/components/markdown.tsx
+++ b/packages/ui/src/components/markdown.tsx
@@ -115,7 +115,22 @@ function setupCodeCopy(root: HTMLDivElement, labels: CopyLabels) {
const parent = block.parentElement
if (!parent) return
const wrapped = parent.getAttribute("data-component") === "markdown-code"
- if (wrapped) return
+ if (wrapped) {
+ const buttons = Array.from(parent.querySelectorAll('[data-slot="markdown-copy-button"]')).filter(
+ (el): el is HTMLButtonElement => el instanceof HTMLButtonElement,
+ )
+
+ if (buttons.length === 0) {
+ parent.appendChild(createCopyButton(labels))
+ return
+ }
+
+ for (const button of buttons.slice(1)) {
+ button.remove()
+ }
+
+ return
+ }
const wrapper = document.createElement("div")
wrapper.setAttribute("data-component", "markdown-code")
parent.replaceChild(wrapper, block)
@@ -192,6 +207,20 @@ function setupCodeCopy(root: HTMLDivElement, labels: CopyLabels) {
}
}
+function wrapCodeBlocks(root: HTMLDivElement) {
+ const blocks = Array.from(root.querySelectorAll("pre"))
+ for (const block of blocks) {
+ const parent = block.parentElement
+ if (!parent) continue
+ const wrapped = parent.getAttribute("data-component") === "markdown-code"
+ if (wrapped) continue
+ const wrapper = document.createElement("div")
+ wrapper.setAttribute("data-component", "markdown-code")
+ parent.replaceChild(wrapper, block)
+ wrapper.appendChild(block)
+ }
+}
+
function touch(key: string, value: Entry) {
cache.delete(key)
cache.set(key, value)
@@ -255,12 +284,16 @@ export function Markdown(
const temp = document.createElement("div")
temp.innerHTML = content
+ wrapCodeBlocks(temp)
morphdom(container, temp, {
childrenOnly: true,
onBeforeElUpdated: (fromEl, toEl) => {
if (fromEl.isEqualNode(toEl)) return false
- if (fromEl.getAttribute("data-component") === "markdown-code") {
+
+ const fromWrapped = fromEl.getAttribute("data-component") === "markdown-code"
+ const toWrapped = toEl.getAttribute("data-component") === "markdown-code"
+ if (fromWrapped && toWrapped) {
const fromPre = fromEl.querySelector("pre")
const toPre = toEl.querySelector("pre")
if (fromPre && toPre && !fromPre.isEqualNode(toPre)) {
@@ -270,13 +303,6 @@ export function Markdown(
}
return true
},
- onBeforeNodeDiscarded: (node) => {
- if (node instanceof Element) {
- if (node.getAttribute("data-slot") === "markdown-copy-button") return false
- if (node.getAttribute("data-component") === "markdown-code") return false
- }
- return true
- },
})
if (copySetupTimer) clearTimeout(copySetupTimer)