Skip to content

Commit 3c56e00

Browse files
authored
feat: Support Sup referencing tags (#4925)
1 parent 2d17b08 commit 3c56e00

5 files changed

Lines changed: 84 additions & 1 deletion

File tree

ui/src/App.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
<script setup lang="ts"></script>
1+
<script setup lang="ts">
2+
import PopoverManager from '@/components/popover-manager/index.vue'
3+
</script>
24

35
<template>
46
<RouterView />
7+
<PopoverManager></PopoverManager>
58
</template>

ui/src/chat.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ config({
5757
video: ['src', 'controls', 'width', 'height', 'preload', 'playsinline'],
5858
source: ['src', 'type'],
5959
input: ['class', 'disabled', 'type', 'checked'],
60+
sup: ['data-title'],
6061
iframe: [
6162
'class',
6263
'width',
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<template>
2+
<ElPopover
3+
ref="popoverRef"
4+
:virtual-ref="currentTarget"
5+
virtual-triggering
6+
placement="top"
7+
:width="240"
8+
:show-after="0"
9+
:hide-after="80"
10+
trigger="hover"
11+
>
12+
<!-- 富文本内容,data-title 支持 HTML -->
13+
<div v-html="currentContent" class="sup-popover__content" />
14+
</ElPopover>
15+
</template>
16+
17+
<script setup lang="ts">
18+
import { ref, onMounted, onUnmounted } from 'vue'
19+
import { ElPopover } from 'element-plus'
20+
21+
const popoverRef = ref<any>()
22+
const currentTarget = ref<any>()
23+
const currentContent = ref<any>('')
24+
let hideTimer: any = null
25+
let lastSup: any = null
26+
27+
function onMouseOver(e: any) {
28+
const sup = e.target.closest('sup[data-title]')
29+
if (!sup || sup === lastSup) return
30+
31+
clearTimeout(hideTimer)
32+
lastSup = sup
33+
currentContent.value = sup.dataset.title
34+
currentTarget.value = sup
35+
popoverRef.value?.onOpen?.()
36+
}
37+
38+
function onMouseOut(e: any) {
39+
const sup = e.target.closest('sup[data-title]')
40+
if (!sup) return
41+
42+
hideTimer = setTimeout(() => {
43+
popoverRef.value?.onClose?.()
44+
lastSup = null
45+
}, 80)
46+
}
47+
48+
onMounted(() => {
49+
document.addEventListener('mouseover', onMouseOver)
50+
document.addEventListener('mouseout', onMouseOut)
51+
})
52+
53+
onUnmounted(() => {
54+
document.removeEventListener('mouseover', onMouseOver)
55+
document.removeEventListener('mouseout', onMouseOut)
56+
clearTimeout(hideTimer)
57+
})
58+
</script>

ui/src/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ config({
5757
video: ['src', 'controls', 'width', 'height', 'preload', 'playsinline'],
5858
source: ['src', 'type'],
5959
input: ['class', 'disabled', 'type', 'checked'],
60+
sup: ['data-title'],
6061
iframe: [
6162
'class',
6263
'width',

ui/src/styles/md-editor.scss

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,26 @@
2929
ul {
3030
list-style: circle;
3131
}
32+
sup[data-title] {
33+
display: inline-flex;
34+
align-items: center;
35+
vertical-align: super;
36+
font-size: 10px;
37+
font-weight: 500;
38+
line-height: 1;
39+
padding: 2px 4px;
40+
border-radius: 4px;
41+
background-color: var(--el-color-primary-light-9);
42+
color: var(--el-color-primary);
43+
border: 1px solid var(--el-color-primary-light-7);
44+
cursor: default;
45+
white-space: nowrap;
46+
letter-spacing: 0.02em;
47+
transition:
48+
background-color 0.15s,
49+
color 0.15s;
50+
cursor: pointer;
51+
}
3252
}
3353

3454
@media only screen and (max-width: 768px) {

0 commit comments

Comments
 (0)