| 1 | <script setup lang="ts"> |
| 2 | import { useElementSize } from '@vueuse/core' |
| 3 | import { computed, ref } from 'vue' |
| 4 | |
| 5 | const slideAspect = 16 / 9 |
| 6 | const slideWidth = 980 |
| 7 | const slideHeight = 980 * 9 / 16 |
| 8 | |
| 9 | const root = ref<HTMLDivElement>() |
| 10 | const element = useElementSize(root) |
| 11 | |
| 12 | const width = computed(() => element.width.value) |
| 13 | const height = computed(() => element.height.value) |
| 14 | |
| 15 | const screenAspect = computed(() => width.value / height.value) |
| 16 | |
| 17 | const scale = computed(() => { |
| 18 | if (screenAspect.value < slideAspect) |
| 19 | return width.value / slideWidth |
| 20 | return height.value * slideAspect / slideWidth |
| 21 | }) |
| 22 | |
| 23 | const style = computed(() => ({ |
| 24 | height: `${slideHeight}px`, |
| 25 | width: `${slideWidth}px`, |
| 26 | transform: `translate(-50%, -50%) scale(${scale.value})`, |
| 27 | })) |
| 28 | </script> |
| 29 | |
| 30 | <template> |
| 31 | <div ref="root" class="slide-container"> |
| 32 | <div class="slide-content" :style="style"> |
| 33 | <slot /> |
| 34 | </div> |
| 35 | <slot name="controls" /> |
| 36 | </div> |
| 37 | </template> |
| 38 | |
| 39 | <style lang="postcss"> |
| 40 | .slide-container { |
| 41 | @apply relative overflow-hidden; |
| 42 | } |
| 43 | |
| 44 | .slide-content { |
| 45 | @apply relative overflow-hidden bg-main absolute left-1/2 top-1/2; |
| 46 | } |
| 47 | </style> |
| 48 |