52 lines
1.6 KiB
Vue
52 lines
1.6 KiB
Vue
<template>
|
|
<Teleport to="#teleports">
|
|
<div v-show="display" :class="$attrs.class" class="absolute border-2 border-light-35 dark:border-dark-35 max-w-[550px] max-h-[450px] bg-light-0 dark:bg-dark-0 text-light-100 dark:text-dark-100" :style="pos"
|
|
@mouseenter="debounce(show, 250)" @mouseleave="debounce(() => { emit('beforeHide'); display = false }, 250)">
|
|
<slot name="content"></slot>
|
|
</div>
|
|
</Teleport>
|
|
<span ref="el" @mouseenter="debounce(show, 250)" @mouseleave="debounce(() => { emit('beforeHide'); display = false }, 250)">
|
|
<slot name="default"></slot>
|
|
</span>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useTemplateRef } from 'vue';
|
|
|
|
const display = ref(false), fetched = ref(false);
|
|
const el = useTemplateRef('el'), pos = ref<Record<string, string>>();
|
|
const emit = defineEmits(['beforeShow', 'beforeHide']);
|
|
|
|
async function show()
|
|
{
|
|
if(display.value)
|
|
return;
|
|
|
|
emit('beforeShow');
|
|
|
|
const rect = (el.value as HTMLDivElement)?.getBoundingClientRect();
|
|
|
|
if(!rect)
|
|
return;
|
|
|
|
const r: Record<string, string> = {};
|
|
if (rect.bottom + 450 < window.innerHeight)
|
|
r.top = (rect.bottom + 4) + "px";
|
|
else
|
|
r.bottom = (window.innerHeight - rect.top + 4) + "px";
|
|
if (rect.right + 550 < window.innerWidth)
|
|
r.left = rect.left + "px";
|
|
else
|
|
r.right = (window.innerWidth - rect.right + 4) + "px";
|
|
|
|
pos.value = r;
|
|
display.value = true;
|
|
}
|
|
let debounceFn: () => void, timeout: NodeJS.Timeout;
|
|
function debounce(fn: () => void, ms: number)
|
|
{
|
|
debounceFn = fn;
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(debounceFn, ms);
|
|
}
|
|
</script> |