main
vue 80 lines 1.94 KB
Raw
1 <template>
2 <div class="flex flex-col gap-0.5">
3 <n-card v-if="!showSource" content-class="p-0!" embedded class="overflow-hidden">
4 <div
5 v-shiki="{ lang, decode }"
6 class="scrollbar-styled code-bg-transparent overflow-auto"
7 :class="codeClass"
8 :style="codeBlockStyle"
9 >
10 <pre v-html="source"></pre>
11 </div>
12 </n-card>
13
14 <n-input
15 v-if="showSource"
16 :value="source"
17 type="textarea"
18 readonly
19 placeholder="Empty"
20 size="large"
21 :autosize="{
22 minRows: 3,
23 maxRows: 18
24 }"
25 />
26
27 <div v-if="showToggleButton" class="flex items-center justify-end gap-2">
28 <n-button v-if="isSupported" quaternary size="tiny" @click="copy(source)">
29 <template #icon>
30 <Icon name="carbon:copy" :size="12" />
31 </template>
32 {{ copied ? "copied!" : "copy source" }}
33 </n-button>
34
35 <n-button quaternary size="tiny" @click="showSource = !showSource">
36 <template #icon>
37 <Icon name="carbon:code" :size="14" />
38 </template>
39 toggle source view
40 </n-button>
41 </div>
42 </div>
43 </template>
44
45 <script setup lang="ts">
46 import type { HTMLAttributes } from "vue"
47 import { useClipboard } from "@vueuse/core"
48 import { NButton, NCard, NInput } from "naive-ui"
49 import { computed, ref } from "vue"
50 import Icon from "@/components/common/Icon.vue"
51 import vShiki from "@/directives/v-shiki"
52
53 const {
54 code,
55 lang,
56 decode,
57 showToggleButton = true,
58 maxHeight,
59 codeClass
60 } = defineProps<{
61 code: string | object | number
62 lang?: string
63 decode?: boolean
64 showToggleButton?: boolean
65 maxHeight?: string | number
66 codeClass?: HTMLAttributes["class"]
67 }>()
68
69 const { copy, copied, isSupported } = useClipboard()
70
71 const showSource = ref(false)
72 const source = computed(() =>
73 typeof code === "string" || typeof code === "number" ? `${code}` : JSON.stringify(code, null, "\t")
74 )
75
76 const codeBlockStyle = computed(() => {
77 if (maxHeight == null) return undefined
78 return { maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight }
79 })
80 </script>