From fdabb6aaf78ae2452620ddc39e14038b14e7a422 Mon Sep 17 00:00:00 2001 From: imrofayel Date: Sun, 1 Feb 2026 17:05:55 +0500 Subject: [PATCH 1/5] feat: add copy button functionality to code blocks in README --- app/components/Readme.vue | 80 ++++++++++++++++++++++++++++++++++++++- server/utils/readme.ts | 11 +++++- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/app/components/Readme.vue b/app/components/Readme.vue index 43004a1af..e32072124 100644 --- a/app/components/Readme.vue +++ b/app/components/Readme.vue @@ -1,6 +1,40 @@ - + + @@ -96,6 +130,48 @@ box-sizing: border-box; } +.readme :deep(.readme-code-block) { + display: block; + width: 100%; + position: relative; +} + +.readme :deep(.readme-copy-button) { + position: absolute; + top: 0.4rem; + right: 0.4rem; + left: auto; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.25rem; + border-radius: 6px; + background: color-mix(in srgb, var(--bg-subtle) 80%, transparent); + border: 1px solid var(--border); + color: var(--fg-subtle); + opacity: 0; + transition: + opacity 0.2s ease, + color 0.2s ease, + border-color 0.2s ease; +} + +.readme :deep(.readme-code-block:hover .readme-copy-button) { + opacity: 1; +} + +.readme :deep(.readme-copy-button:hover) { + color: var(--fg); + border-color: var(--border-hover); +} + +.readme :deep(.readme-copy-button > span) { + width: 1.05rem; + height: 1.05rem; + display: inline-block; + pointer-events: none; +} + .readme :deep(pre code), .readme :deep(.shiki code) { background: transparent !important; diff --git a/server/utils/readme.ts b/server/utils/readme.ts index c2792de19..75b1ba62f 100644 --- a/server/utils/readme.ts +++ b/server/utils/readme.ts @@ -135,12 +135,14 @@ const ALLOWED_TAGS = [ 'sub', 'kbd', 'mark', + 'button', ] const ALLOWED_ATTR: Record = { a: ['href', 'title', 'target', 'rel'], img: ['src', 'alt', 'title', 'width', 'height'], source: ['src', 'srcset', 'type', 'media'], + button: ['class', 'title', 'type', 'aria-label', 'data-copy'], th: ['colspan', 'rowspan', 'align'], td: ['colspan', 'rowspan', 'align'], h3: ['id', 'data-level'], @@ -305,7 +307,14 @@ export async function renderReadmeHtml( // Syntax highlighting for code blocks (uses shared highlighter) renderer.code = ({ text, lang }: Tokens.Code) => { - return highlightCodeSync(shiki, text, lang || 'text') + const html = highlightCodeSync(shiki, text, lang || 'text') + // Add copy button + return `
+ +${html} +
` } // Resolve image URLs (with GitHub blob → raw conversion) From 683ea2b2a4553db599e9be63179aa43659f4956f Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 1 Feb 2026 12:24:02 +0000 Subject: [PATCH 2/5] [autofix.ci] apply automated fixes --- app/components/Readme.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/components/Readme.vue b/app/components/Readme.vue index c020f5a3b..450e86e8a 100644 --- a/app/components/Readme.vue +++ b/app/components/Readme.vue @@ -148,7 +148,10 @@ const handleCopy = async (e: MouseEvent) => { border: 1px solid var(--border); color: var(--fg-subtle); opacity: 0; - transition: opacity 0.2s ease, color 0.2s ease, border-color 0.2s ease; + transition: + opacity 0.2s ease, + color 0.2s ease, + border-color 0.2s ease; } .readme :deep(.readme-code-block:hover .readme-copy-button) { From 6880564854b10dd0e9a0c4a08f2975a86e56f89e Mon Sep 17 00:00:00 2001 From: imrofayel Date: Sun, 1 Feb 2026 18:52:56 +0500 Subject: [PATCH 3/5] fix: improve accessibility of copy button in README component --- app/components/Readme.vue | 25 +++++++++++++++++++------ server/utils/readme.ts | 5 +++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/app/components/Readme.vue b/app/components/Readme.vue index 450e86e8a..80a44791e 100644 --- a/app/components/Readme.vue +++ b/app/components/Readme.vue @@ -137,8 +137,7 @@ const handleCopy = async (e: MouseEvent) => { .readme :deep(.readme-copy-button) { position: absolute; top: 0.4rem; - right: 0.4rem; - left: auto; + inset-inline-end: 0.4rem; display: inline-flex; align-items: center; justify-content: center; @@ -154,7 +153,8 @@ const handleCopy = async (e: MouseEvent) => { border-color 0.2s ease; } -.readme :deep(.readme-code-block:hover .readme-copy-button) { +.readme :deep(.readme-code-block:hover .readme-copy-button), +.readme :deep(.readme-copy-button:focus-visible) { opacity: 1; } @@ -179,8 +179,7 @@ const handleCopy = async (e: MouseEvent) => { .readme :deep(.readme-copy-button) { position: absolute; top: 0.4rem; - right: 0.4rem; - left: auto; + inset-inline-end: 0.4rem; display: inline-flex; align-items: center; justify-content: center; @@ -196,7 +195,8 @@ const handleCopy = async (e: MouseEvent) => { border-color 0.2s ease; } -.readme :deep(.readme-code-block:hover .readme-copy-button) { +.readme :deep(.readme-code-block:hover .readme-copy-button), +.readme :deep(.readme-copy-button:focus-visible) { opacity: 1; } @@ -421,4 +421,17 @@ const handleCopy = async (e: MouseEvent) => { margin: 0 0.25rem 0.25rem 0; border-radius: 4px; } + +/* Screen reader only text */ +.readme :deep(.sr-only) { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} diff --git a/server/utils/readme.ts b/server/utils/readme.ts index 1f9e85249..a581c497b 100644 --- a/server/utils/readme.ts +++ b/server/utils/readme.ts @@ -310,9 +310,10 @@ export async function renderReadmeHtml( renderer.code = ({ text, lang }: Tokens.Code) => { const html = highlightCodeSync(shiki, text, lang || 'text') // Add copy button - return `
- ${html}
` From 71f6b69c12036de9b0994783ada733d121c7f2a6 Mon Sep 17 00:00:00 2001 From: imrofayel Date: Sun, 1 Feb 2026 18:54:28 +0500 Subject: [PATCH 4/5] fix: update cache version in readme handler to v6 --- server/api/registry/readme/[...pkg].get.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/api/registry/readme/[...pkg].get.ts b/server/api/registry/readme/[...pkg].get.ts index b892b93ad..c523bbd01 100644 --- a/server/api/registry/readme/[...pkg].get.ts +++ b/server/api/registry/readme/[...pkg].get.ts @@ -126,7 +126,7 @@ export default defineCachedEventHandler( swr: true, getKey: event => { const pkg = getRouterParam(event, 'pkg') ?? '' - return `readme:v5:${pkg.replace(/\/+$/, '').trim()}` + return `readme:v6:${pkg.replace(/\/+$/, '').trim()}` }, }, ) From 4f5177d6fe0fbc6d7c927532d2e0e1386d210627 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 1 Feb 2026 18:11:37 +0000 Subject: [PATCH 5/5] [autofix.ci] apply automated fixes --- app/components/Readme.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/components/Readme.vue b/app/components/Readme.vue index 173652297..ee673e1e9 100644 --- a/app/components/Readme.vue +++ b/app/components/Readme.vue @@ -34,7 +34,11 @@ const handleCopy = async (e: MouseEvent) => {