-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathProsePre.vue
More file actions
134 lines (123 loc) · 4.08 KB
/
Copy pathProsePre.vue
File metadata and controls
134 lines (123 loc) · 4.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<script setup lang="ts">
import { ref, watch } from 'vue'
import { textContent } from 'minimark'
const props = withDefaults(defineProps<{
// @eslint-disable-next-line vue/prop-name-casing
__node: any
language?: string
theme?: string
filename?: string
containerClass?: string
fallbackClass?: string
fallbackWithHeaderClass?: string
shikiStyle?: Record<string, string>
}>(), {
theme: 'github-dark',
containerClass: 'my-4',
fallbackClass: 'bg-neutral-100 dark:bg-neutral-800 text-neutral-800 dark:text-neutral-200 p-4 rounded-lg overflow-x-auto border border-neutral-300 dark:border-neutral-700',
})
const componentKey = ref(0)
const copied = ref(false)
const codeContent = ref('')
// Extract code content and language from node
const extractCodeFromNode = () => {
const node = props.__node
if (!node) {
codeContent.value = ''
return
}
codeContent.value = textContent(node)
}
// Initialize code extraction
extractCodeFromNode()
// Watch for code changes and force remount
watch(() => props.__node, () => {
extractCodeFromNode()
componentKey.value++
})
// Copy to clipboard functionality
async function copyCode() {
try {
const nav = navigator as Navigator & { clipboard?: { writeText: (text: string) => Promise<void> } }
if (nav.clipboard?.writeText) {
await nav.clipboard.writeText(codeContent.value)
copied.value = true
setTimeout(() => {
copied.value = false
}, 2000)
}
}
catch (error) {
console.error('Failed to copy code:', error)
}
}
</script>
<template>
<div :class="`relative ${containerClass} group rounded-lg`">
<!-- Header with language label and copy button -->
<div class="rounded-t-lg border border-b-0 border-neutral-300 dark:border-neutral-700 top-[-1.5rem] right-0 left-0 flex items-center justify-between px-4 py-2 z-10">
<!-- Language label -->
<span
class="font-mono text-sm font-semibold tracking-wider text-neutral-600 dark:text-neutral-400 bg-neutral-200/80 dark:bg-neutral-800/80 px-2.5 py-1 rounded backdrop-blur-sm"
>
{{ filename || language }}
</span>
<!-- Copy button -->
<button
type="button"
class="ml-auto px-3 py-1.5 text-xs font-medium rounded transition-all duration-200 bg-neutral-300/80 dark:bg-neutral-700/80 hover:bg-neutral-400 dark:hover:bg-neutral-600 text-neutral-700 dark:text-neutral-300 hover:text-neutral-900 dark:hover:text-white backdrop-blur-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
@click="copyCode"
>
<span
v-if="copied"
class="flex items-center gap-1.5"
>
<svg
class="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 13l4 4L19 7"
/>
</svg>
Copied!
</span>
<span
v-else
class="flex items-center gap-1.5"
>
<svg
class="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
/>
</svg>
Copy
</span>
</button>
</div>
<!-- Shiki renderer -->
<pre class="shiki-container bg-neutral-100 dark:bg-neutral-800 overflow-x-auto rounded-b-lg p-4 border border-neutral-300 dark:border-neutral-700"><slot /></pre>
</div>
</template>
<style scoped>
html.dark .shiki-container:not(.shiki-stream) :deep(span) {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
font-style: var(--shiki-dark-font-style) !important;
font-weight: var(--shiki-dark-font-weight) !important;
text-decoration: var(--shiki-dark-text-decoration) !important;
}
</style>