Add code copy button
This commit is contained in:
@@ -1,6 +1,11 @@
|
|||||||
/*----------------------------------------*/
|
/*----------------------------------------*/
|
||||||
/* General */
|
/* General */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--w-code-background-color: #818b981f;
|
||||||
|
--w-pre-background-color: #f6f8fa;
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font-family: "Segoe UI", "DejaVu Sans", sans-serif;
|
font-family: "Segoe UI", "DejaVu Sans", sans-serif;
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<div class="position-relative">
|
||||||
|
<div @click="copyCode" class="position-absolute" style="top: 10px; right: 10px;">
|
||||||
|
<template v-if="copied">
|
||||||
|
<code>Copied!</code>
|
||||||
|
</template>
|
||||||
|
<button class="copy text-secondary" title="Copy code">
|
||||||
|
<IFaClone />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<pre :class="$props.class"><code class="language-{{ language }}"><slot /></code></pre>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
pre code .line {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.copy {
|
||||||
|
background: 0;
|
||||||
|
border: 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.copy:hover {
|
||||||
|
background-color: var(--w-code-background-color);
|
||||||
|
border-radius: var(--bs-border-radius);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue"
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
code: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
language: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
filename: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
highlights: {
|
||||||
|
type: Array as () => number[],
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
meta: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
class: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const copied = ref(false);
|
||||||
|
|
||||||
|
const copyCode = async (e: Event) => {
|
||||||
|
try {
|
||||||
|
const target = e.currentTarget as HTMLElement;
|
||||||
|
const element = target.nextElementSibling as HTMLPreElement | null;
|
||||||
|
const textToCopy = element ? element.textContent.trim() : "";
|
||||||
|
|
||||||
|
await navigator.clipboard.writeText(textToCopy);
|
||||||
|
copied.value = true;
|
||||||
|
setTimeout(() => (copied.value = false), 2000);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to copy:', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background-color: #f6f8fa;
|
background-color: var(--w-pre-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Select <code> and <code class="shiki"> */
|
/* Select <code> and <code class="shiki"> */
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 85%;
|
font-size: 85%;
|
||||||
white-space: break-spaces;
|
white-space: break-spaces;
|
||||||
background-color: #818b981f;
|
background-color: var(--w-code-background-color);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user