2025-03-30 00:12:04 +08:00

79 lines
2.2 KiB
Vue

<script setup lang="ts">
import { useResizeObserver } from '@vueuse/core'
import { useTemplateRef, watch } from 'vue'
import { ClientOnly, onContentUpdated } from 'vuepress/client'
import { useExpand } from '../composables/demo.js'
import '../styles/demo.css'
const props = defineProps<{
type?: 'vue' | 'markdown'
title?: string
desc?: string
expanded?: boolean
}>()
const [showCode, toggleCode] = useExpand(props.expanded)
const draw = useTemplateRef<HTMLIFrameElement>('draw')
const vueDraw = useTemplateRef<HTMLIFrameElement>('draw-vue')
function resizeAndPositionVueDraw() {
if (!draw.value || !vueDraw.value)
return
const rect = draw.value.getBoundingClientRect()
const { scrollLeft, scrollTop } = document.documentElement
vueDraw.value.style.width = `${draw.value.offsetWidth - 48}px`
vueDraw.value.style.top = `${rect.top + scrollTop}px`
vueDraw.value.style.left = `${rect.x + scrollLeft}px`
}
if (props.type === 'vue' && !__VUEPRESS_SSR__) {
watch([draw, vueDraw], () => {
resizeAndPositionVueDraw()
if (draw.value && vueDraw.value) {
requestAnimationFrame(() => {
draw.value!.style.height = `${vueDraw.value!.offsetHeight}px`
})
}
}, { immediate: true })
useResizeObserver(draw, resizeAndPositionVueDraw)
useResizeObserver(() => document.body, resizeAndPositionVueDraw)
onContentUpdated(resizeAndPositionVueDraw)
useResizeObserver(vueDraw, () => {
if (draw.value && vueDraw.value)
draw.value.style.height = `${vueDraw.value.offsetHeight}px`
})
}
</script>
<template>
<div class="vp-demo-wrapper" :class="{ type }">
<div ref="draw" class="demo-draw">
<slot v-if="type !== 'vue'" />
<ClientOnly v-else>
<Teleport to="body">
<div ref="draw-vue" class="demo-draw-vue">
<slot />
</div>
</Teleport>
</ClientOnly>
</div>
<div v-if="title || desc" class="demo-info">
<p v-if="title" class="title">
{{ title }}
</p>
<p v-if="desc" class="desc">
{{ desc }}
</p>
</div>
<div class="demo-ctrl">
<span class="vpi-demo-code" @click="toggleCode" />
</div>
<div v-show="showCode" class="demo-code">
<slot name="code" />
</div>
</div>
</template>