mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
130 lines
3.0 KiB
Vue
130 lines
3.0 KiB
Vue
<script setup lang="ts">
|
|
import type { CSSProperties } from 'vue'
|
|
import { onClickOutside, useMediaQuery, useToggle } from '@vueuse/core'
|
|
import { nextTick, ref, useTemplateRef, watch } from 'vue'
|
|
|
|
import '@vuepress/helper/transition/fade-in.css'
|
|
|
|
const [show, toggle] = useToggle(false)
|
|
|
|
const el = useTemplateRef<HTMLSpanElement>('el')
|
|
const tooltip = useTemplateRef<HTMLSpanElement>('tooltip')
|
|
const styles = ref<CSSProperties>()
|
|
|
|
const isMobile = useMediaQuery('(max-width: 768px)')
|
|
const showTooltip = () => toggle(true)
|
|
const hiddenTooltip = () => toggle(false)
|
|
|
|
onClickOutside(el, () => {
|
|
if (isMobile.value)
|
|
hiddenTooltip()
|
|
}, {
|
|
ignore: [tooltip],
|
|
})
|
|
|
|
watch(show, () => nextTick(() => {
|
|
if (__VUEPRESS_SSR__)
|
|
return
|
|
|
|
if (show.value && tooltip.value) {
|
|
const { x, width } = tooltip.value.getBoundingClientRect()
|
|
const innerWidth = window.innerWidth
|
|
const space = 16
|
|
let translate = 0
|
|
if (x - space < 0)
|
|
translate = Math.abs(x) + space
|
|
|
|
else if (x + width + space > innerWidth)
|
|
translate = innerWidth - x - width - space
|
|
|
|
if (translate !== 0) {
|
|
styles.value = {
|
|
'--vp-abbr-transform': `translateX(${translate}px) translateX(-50%)`,
|
|
'--vp-abbr-space-transform': `translateX(${-translate}px) translateX(-50%)`,
|
|
}
|
|
}
|
|
}
|
|
}))
|
|
</script>
|
|
|
|
<template>
|
|
<span
|
|
ref="el"
|
|
class="vp-abbr"
|
|
role="tooltip"
|
|
tabindex="0"
|
|
v-bind="isMobile ? {
|
|
onClick: showTooltip,
|
|
} : {
|
|
onMouseenter: showTooltip,
|
|
onMouseleave: hiddenTooltip,
|
|
onFocus: showTooltip,
|
|
onBlur: hiddenTooltip,
|
|
}"
|
|
>
|
|
<slot />
|
|
<ClientOnly>
|
|
<Transition name="fade-in">
|
|
<span v-show="show" ref="tooltip" class="vp-abbr-tooltip ignore-header" :style="styles" aria-hidden="true">
|
|
<slot name="tooltip" />
|
|
</span>
|
|
</Transition>
|
|
</ClientOnly>
|
|
</span>
|
|
</template>
|
|
|
|
<style>
|
|
:root {
|
|
--vp-abbr-bg: var(--vp-c-bg);
|
|
--vp-abbr-text: var(--vp-c-text-1);
|
|
--vp-abbr-border: var(--vp-c-divider);
|
|
--vp-abbr-transform: translateX(-50%);
|
|
--vp-abbr-space-transform: translateX(-50%);
|
|
}
|
|
|
|
.vp-abbr {
|
|
position: relative;
|
|
text-decoration: underline dotted currentcolor;
|
|
text-underline-offset: 4px;
|
|
cursor: help;
|
|
}
|
|
|
|
.vp-abbr .vp-abbr-tooltip {
|
|
position: absolute;
|
|
top: calc(100% + 12px);
|
|
left: 50%;
|
|
z-index: 3;
|
|
width: max-content;
|
|
max-width: min(calc(100vw - 32px), 360px);
|
|
padding: 8px 14px;
|
|
font-size: 14px;
|
|
line-height: 1.7;
|
|
color: var(--vp-abbr-text);
|
|
cursor: auto;
|
|
background-color: var(--vp-abbr-bg);
|
|
border: solid 1px var(--vp-abbr-border);
|
|
border-radius: 4px;
|
|
box-shadow: var(--vp-shadow-2);
|
|
transform: var(--vp-abbr-transform);
|
|
}
|
|
|
|
.vp-abbr .vp-abbr-tooltip::before,
|
|
.vp-abbr .vp-abbr-tooltip::after {
|
|
position: absolute;
|
|
top: -16px;
|
|
left: 50%;
|
|
display: block;
|
|
width: 0;
|
|
height: 0;
|
|
content: "";
|
|
border: 8px solid transparent;
|
|
border-bottom-color: var(--vp-abbr-bg);
|
|
transform: var(--vp-abbr-space-transform);
|
|
}
|
|
|
|
.vp-abbr .vp-abbr-tooltip::before {
|
|
top: -17px;
|
|
border-bottom-color: var(--vp-abbr-border);
|
|
}
|
|
</style>
|