From 0a668c992e6709e6737c4ac7889194acb23abd18 Mon Sep 17 00:00:00 2001 From: Kia Ishii Date: Thu, 26 May 2022 18:04:12 +0900 Subject: [PATCH] feat: display copied text on click --- .../theme-default/composables/copy-code.ts | 48 +++++++++-------- .../styles/components/vp-doc.css | 53 +++++++++++++++---- src/client/theme-default/styles/vars.css | 2 + 3 files changed, 73 insertions(+), 30 deletions(-) diff --git a/src/client/theme-default/composables/copy-code.ts b/src/client/theme-default/composables/copy-code.ts index 9a95c06d..bd5d73ab 100644 --- a/src/client/theme-default/composables/copy-code.ts +++ b/src/client/theme-default/composables/copy-code.ts @@ -1,27 +1,6 @@ import { nextTick, watch } from 'vue' import { inBrowser, useData } from 'vitepress' -const handleElement = (el: HTMLElement) => { - el.onclick = () => { - const parent = el.parentElement - if (!parent) return - - const isShell = - parent.classList.contains('language-sh') || - parent.classList.contains('language-bash') - - let { innerText: text = '' } = parent - if (isShell) text = text.replace(/^ *\$ /gm, '') - - navigator.clipboard.writeText(text).then(() => { - el.classList.add('copied') - setTimeout(() => { - el.classList.remove('copied') - }, 800) - }) - } -} - export function useCopyCode() { const { page } = useData() @@ -40,3 +19,30 @@ export function useCopyCode() { { immediate: true, flush: 'post' } ) } + +function handleElement(el: HTMLElement) { + el.onclick = () => { + const parent = el.parentElement + + if (!parent) { + return + } + + const isShell = + parent.classList.contains('language-sh') || + parent.classList.contains('language-bash') + + let { innerText: text = '' } = parent + + if (isShell) { + text = text.replace(/^ *\$ /gm, '') + } + + navigator.clipboard.writeText(text).then(() => { + el.classList.add('copied') + setTimeout(() => { + el.classList.remove('copied') + }, 3000) + }) + } +} diff --git a/src/client/theme-default/styles/components/vp-doc.css b/src/client/theme-default/styles/components/vp-doc.css index ba08d070..4f5d09aa 100644 --- a/src/client/theme-default/styles/components/vp-doc.css +++ b/src/client/theme-default/styles/components/vp-doc.css @@ -366,27 +366,58 @@ transition: border-color 0.5s, color 0.5s; } -.vp-doc [class*='language-'] > span.copy:before { +.vp-doc [class*='language-'] > span.copy { position: absolute; top: 8px; right: 8px; z-index: 2; - content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(235,235,235,0.38)' stroke-width='2' class='h-6 w-6' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2'/%3E%3C/svg%3E"); + display: block; + justify-content: center; + align-items: center; + border-radius: 4px; + width: 40px; + height: 40px; + background-color: var(--vp-code-block-bg); opacity: 0; cursor: pointer; - transition: opacity 0.5s; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(235,235,235,0.38)' stroke-width='2' class='h-6 w-6' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2'/%3E%3C/svg%3E"); + background-position: 50%; + background-size: 20px; + background-repeat: no-repeat; + transition: opacity 0.25s; } -.vp-doc [class*='language-'] > span.copied:before { - content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(235,235,235,0.38)' stroke-width='2' class='h-6 w-6' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E"); +.vp-doc [class*='language-']:hover > span.copy { + opacity: 1; } -.vp-doc [class*='language-']:hover > span.copy:before { - opacity: 1; +.vp-doc [class*='language-'] > span.copy:hover { + background-color: var(--vp-code-copy-code-hover-bg); } -.vp-doc [class*='language-']:hover:before { - opacity: 0; +.vp-doc [class*='language-'] > span.copy.copied, +.vp-doc [class*='language-'] > span.copy:hover.copied { + border-radius: 0 4px 4px 0; + background-color: var(--vp-code-copy-code-hover-bg); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(235,235,235,0.5)' stroke-width='2' class='h-6 w-6' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E"); +} + +.vp-doc [class*='language-'] > span.copy.copied::before, +.vp-doc [class*='language-'] > span.copy:hover.copied::before { + position: relative; + left: -65px; + display: block; + border-radius: 4px 0 0 4px; + padding-top: 8px; + width: 64px; + height: 40px; + text-align: center; + font-size: 12px; + font-weight: 500; + color: var(--vp-c-text-dark-2); + background-color: var(--vp-code-copy-code-hover-bg); + white-space: nowrap; + content: "Copied"; } .vp-doc [class*='language-']:before { @@ -400,6 +431,10 @@ transition: color 0.5s, opacity 0.5s; } +.vp-doc [class*='language-']:hover:before { + opacity: 0; +} + .vp-doc [class~='language-c']:before { content: 'c'; } .vp-doc [class~='language-css']:before { content: 'css'; } .vp-doc [class~='language-go']:before { content: 'go'; } diff --git a/src/client/theme-default/styles/vars.css b/src/client/theme-default/styles/vars.css index c2fbf70c..408a42d9 100644 --- a/src/client/theme-default/styles/vars.css +++ b/src/client/theme-default/styles/vars.css @@ -197,6 +197,8 @@ --vp-code-line-highlight-color: rgba(0, 0, 0, 0.5); --vp-code-line-number-color: var(--vp-c-text-dark-3); + + --vp-code-copy-code-hover-bg: rgba(255, 255, 255, 0.05); } .dark {