main
vue 106 lines 2.44 KB
Raw
1 <template>
2 <div>
3 <vue-markdown-it
4 v-if="highlighter"
5 :source
6 :plugins="[
7 [
8 fromHighlighter(highlighter, {
9 themes: codeThemes
10 })
11 ],
12 markdownItLinkTargetBlank
13 ]"
14 class="markdown-style scrollbar-styled"
15 :class="{ 'code-bg-transparent': codeBgTransparent }"
16 @click="emit('click', $event)"
17 />
18 <div v-else>
19 {{ source }}
20 </div>
21 </div>
22 </template>
23
24 <script setup lang="ts">
25 import type MarkdownIt from "markdown-it/lib/index.mjs"
26 import type Token from "markdown-it/lib/token.mjs"
27 import type { HighlighterGeneric } from "shiki/core"
28 import { VueMarkdownIt } from "@f3ve/vue-markdown-it"
29 import { fromHighlighter } from "@shikijs/markdown-it/core"
30 import { onMounted, ref, toRefs } from "vue"
31 import { codeThemes, getHighlighter } from "@/utils/highlighter"
32 import "@/assets/scss/overrides/vue-md-it-override.scss"
33
34 const props = defineProps<{
35 source: string
36 codeBgTransparent?: boolean
37 }>()
38
39 const emit = defineEmits<{
40 (e: "click", value: PointerEvent): void
41 (e: "mounted"): void
42 }>()
43
44 const highlighter = ref<HighlighterGeneric<string, string> | null>(null)
45
46 function markdownItLinkTargetBlank(md: MarkdownIt): void {
47 const defaultRender =
48 md.renderer.rules.link_open ||
49 function (tokens: Token[], idx: number, options, _env, self) {
50 return self.renderToken(tokens, idx, options)
51 }
52
53 md.renderer.rules.link_open = function (tokens: Token[], idx: number, options, env, self) {
54 const token = tokens[idx]
55
56 if (token) {
57 // Aggiungi target="_blank"
58 const targetIndex = token.attrIndex("target")
59 const target = token.attrs?.[targetIndex]
60 if (targetIndex < 0) {
61 token.attrPush(["target", "_blank"])
62 } else if (target?.[1]) {
63 target[1] = "_blank"
64 }
65
66 // Aggiungi rel="noopener noreferrer"
67 const relIndex = token.attrIndex("rel")
68 const rel = token.attrs?.[relIndex]
69 if (relIndex < 0) {
70 token.attrPush(["rel", "noopener noreferrer"])
71 } else if (rel?.[1]) {
72 rel[1] = "noopener noreferrer"
73 }
74 }
75
76 return defaultRender(tokens, idx, options, env, self)
77 }
78 }
79
80 const { source, codeBgTransparent } = toRefs(props)
81
82 onMounted(async () => {
83 highlighter.value = (await getHighlighter()) as unknown as HighlighterGeneric<string, string>
84 emit("mounted")
85 })
86 </script>
87
88 <style lang="scss" scoped>
89 .markdown-style {
90 :deep() {
91 & > * {
92 margin-bottom: 15px;
93 }
94 }
95
96 &.code-bg-transparent {
97 :deep() {
98 & > pre {
99 & > code {
100 background-color: transparent;
101 }
102 }
103 }
104 }
105 }
106 </style>