返回 slidev
LaserPointer.vue
根目录 / packages / client / internals / LaserPointer.vue
1 <script setup lang="ts">
2 import { computed, onMounted, watchEffect } from 'vue'
3 import { useMousePosInSlide } from '../composables/useMousePosInSlide'
4 import { useNav } from '../composables/useNav'
5 import { cursorStyle } from '../state'
6 import { sharedState } from '../state/shared'
7
8 const selfMouse = useMousePosInSlide()
9 const { isPresenter } = useNav()
10
11 const laserPointer = computed(() => {
12 if (!isPresenter.value && sharedState.cursor?.style === 'laser') {
13 return sharedState.cursor
14 }
15 if (cursorStyle.value === 'laser') {
16 return selfMouse.value
17 }
18 return null
19 })
20
21 onMounted(() => {
22 watchEffect(() => {
23 document.body.classList.toggle('slidev-self-laser-active', cursorStyle.value === 'laser' && !!laserPointer.value)
24 })
25 })
26 </script>
27
28 <template>
29 <div
30 v-if="laserPointer"
31 class="absolute top-0 left-0 right-0 bottom-0 pointer-events-none text-xl"
32 >
33 <div
34 class="laser-pointer"
35 :style="{
36 left: `${laserPointer.x}%`,
37 top: `${laserPointer.y}%`,
38 }"
39 />
40 </div>
41 </template>
42
43 <style scoped>
44 .laser-pointer {
45 position: absolute;
46 width: 6px;
47 height: 6px;
48 border-radius: 9999px;
49 transform: translate(-50%, -50%);
50 background: radial-gradient(
51 circle at center,
52 rgba(255, 80, 80, 1) 0%,
53 rgba(255, 0, 0, 0.95) 55%,
54 rgba(255, 0, 0, 0.1) 100%
55 );
56 box-shadow:
57 0 0 10px rgba(255, 0, 0, 0.9),
58 0 0 22px rgba(255, 0, 0, 0.55);
59 }
60 </style>
61
62 <style>
63 .slidev-self-laser-active .slidev-slide-container {
64 cursor: none;
65 }
66 </style>
67
67 lines Plain Text