Skip to content

Commit 7b5759b

Browse files
committed
feat: Customize Markdown rendering styles
1 parent 9eee203 commit 7b5759b

File tree

3 files changed

+80
-14
lines changed

3 files changed

+80
-14
lines changed

frontend/src/components/Confirm/index.vue

Lines changed: 78 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
<script setup lang="ts">
2-
import { computed } from 'vue'
2+
import { h, onMounted, ref, render } from 'vue'
33
import { marked } from 'marked'
44
55
import useI18n from '@/lang'
6+
import { APP_TITLE, APP_VERSION, sampleID } from '@/utils'
7+
import CodeViewer from '@/components/CodeViewer/index.vue'
8+
import Divider from '@/components/Divider/index.vue'
69
710
export type Options = {
811
type: 'text' | 'markdown'
@@ -22,34 +25,97 @@ const props = withDefaults(defineProps<Props>(), {
2225
2326
const emits = defineEmits(['confirm', 'cancel', 'finish'])
2427
28+
const content = ref<string | Record<string, any>>('')
29+
const domContainers: (() => void)[] = []
30+
2531
const { t } = useI18n.global
2632
33+
marked.setOptions({ async: true })
34+
35+
marked.use({
36+
renderer: {
37+
image({ href, title, text }) {
38+
return `<img src="${href}" alt="${title || text}" style="max-width: 100%">`
39+
},
40+
link({ href, title }) {
41+
return `<span onclick="Plugins.BrowserOpenURL('${href}')" style="color: var(--primary-color); cursor: pointer">${title || href}</span>`
42+
},
43+
blockquote({ tokens }) {
44+
const text = this.parser.parse(tokens)
45+
return `<div style="border-left: 4px solid var(--primary-color); padding: 8px; margin: 8px 0; display: flex; flex-direction: column; border-radius: 4px; background: var(--card-bg)">${text}</div>`
46+
},
47+
paragraph({ text }) {
48+
return `<p style="margin: 0">${text}</p>`
49+
},
50+
list({ ordered, items }) {
51+
const children = items
52+
.map(({ tokens }) => {
53+
const text = this.parser.parse(tokens)
54+
return `<li style="padding: 0">${text}</li>`
55+
})
56+
.join('')
57+
if (ordered) {
58+
return `<ol style="margin: 0; padding: 8px 16px">${children}</ol>`
59+
}
60+
return `<ul style="margin: 0; padding: 8px 16px">${children}</ul>`
61+
},
62+
hr() {
63+
const containerId = 'Br_' + sampleID()
64+
const comp = h(Divider, () => APP_TITLE + '/' + APP_VERSION)
65+
setTimeout(() => {
66+
const div = document.getElementById(containerId)
67+
if (!div) return
68+
render(comp, div)
69+
domContainers.push(() => render(null, div))
70+
})
71+
return `<div id="${containerId}"></div>`
72+
},
73+
code({ text, lang }) {
74+
const containerId = 'CodeViewer_' + sampleID()
75+
const comp = h(CodeViewer, { editable: false, modelValue: text, lang: lang as any })
76+
setTimeout(() => {
77+
const div = document.getElementById(containerId)
78+
if (!div) return
79+
render(comp, div)
80+
domContainers.push(() => render(null, div))
81+
})
82+
return `<div id="${containerId}"></div>`
83+
}
84+
}
85+
})
86+
87+
const renderContent = async () => {
88+
if (typeof props.message !== 'string') {
89+
content.value = props.message
90+
return
91+
}
92+
if (props.options.type === 'text') {
93+
content.value = t(props.message)
94+
return
95+
}
96+
content.value = await marked.parse(props.message)
97+
}
98+
99+
onMounted(renderContent)
100+
27101
const handleConfirm = () => {
28102
emits('confirm', true)
29103
emits('finish')
104+
domContainers.forEach((destroy) => destroy())
30105
}
31106
32107
const handleCancel = () => {
33108
emits('cancel')
34109
emits('finish')
110+
domContainers.forEach((destroy) => destroy())
35111
}
36-
37-
const message = computed(() => {
38-
if (typeof props.message !== 'string') {
39-
return props.message
40-
}
41-
if (props.options.type === 'text') {
42-
return t(props.message)
43-
}
44-
return marked.use().parse(props.message)
45-
})
46112
</script>
47113

48114
<template>
49115
<Transition name="slide-down" appear>
50116
<div class="confirm">
51117
<div class="title">{{ t(title) }}</div>
52-
<div class="message select-text" v-html="message"></div>
118+
<div class="message select-text" v-html="content"></div>
53119
<div class="form-action">
54120
<Button v-if="cancel" @click="handleCancel" size="small">{{ t('common.cancel') }}</Button>
55121
<Button @click="handleConfirm" size="small" type="primary">

frontend/src/hooks/useAlert.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { render, createVNode } from 'vue'
22

33
import ConfirmComp, { type Options } from '@/components/Confirm/index.vue'
44

5-
const createAlert = (title: string, message: string, options: Partial<Options> = {}) => {
5+
const createAlert = (title: string, message: string, options: Options = { type: 'text' }) => {
66
return new Promise((resolve) => {
77
const dom = document.createElement('div')
88
dom.style.cssText = `

frontend/src/hooks/useConfirm.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { render, createVNode } from 'vue'
22

33
import ConfirmComp, { type Options } from '@/components/Confirm/index.vue'
44

5-
const createConfirm = (title: string, message: string, options: Partial<Options> = {}) => {
5+
const createConfirm = (title: string, message: string, options: Options = { type: 'text' }) => {
66
return new Promise((resolve, reject) => {
77
const dom = document.createElement('div')
88
dom.style.cssText = `

0 commit comments

Comments
 (0)