| 1 | <script setup lang="ts"> |
| 2 | import type { SlideRoute } from '@slidev/types' |
| 3 | import { recomputeAllPoppers } from 'floating-vue' |
| 4 | import { computed, shallowRef, TransitionGroup, watchEffect } from 'vue' |
| 5 | import { GlobalBottom, GlobalTop } from '#slidev/global-layers' |
| 6 | import { createFixedClicks } from '../composables/useClicks' |
| 7 | import { useNav } from '../composables/useNav' |
| 8 | import { usePreloadImages } from '../composables/usePreloadImages' |
| 9 | import { useViewTransition } from '../composables/useViewTransition' |
| 10 | import { CLICKS_MAX } from '../constants' |
| 11 | import { activeDragElement, disableTransition, hmrSkipTransition } from '../state' |
| 12 | import DragControl from './DragControl.vue' |
| 13 | import SlideWrapper from './SlideWrapper.vue' |
| 14 | |
| 15 | defineProps<{ |
| 16 | renderContext: 'slide' | 'presenter' |
| 17 | }>() |
| 18 | |
| 19 | const { |
| 20 | currentSlideRoute, |
| 21 | currentTransition, |
| 22 | getPrimaryClicks, |
| 23 | prevRoute, |
| 24 | nextRoute, |
| 25 | slides, |
| 26 | isPrintMode, |
| 27 | isPrintWithClicks, |
| 28 | clicksDirection, |
| 29 | printRange, |
| 30 | } = useNav() |
| 31 | |
| 32 | function preloadRoute(route: SlideRoute) { |
| 33 | if (route.meta.preload !== false) { |
| 34 | route.meta.__preloaded = true |
| 35 | route.load() |
| 36 | } |
| 37 | } |
| 38 | // preload current, prev and next slides |
| 39 | watchEffect(() => { |
| 40 | preloadRoute(currentSlideRoute.value) |
| 41 | preloadRoute(prevRoute.value) |
| 42 | preloadRoute(nextRoute.value) |
| 43 | }) |
| 44 | // preload all slides after 3s |
| 45 | watchEffect((onCleanup) => { |
| 46 | const routes = slides.value |
| 47 | const timeout = setTimeout(() => { |
| 48 | routes.forEach(preloadRoute) |
| 49 | }, 3000) |
| 50 | onCleanup(() => clearTimeout(timeout)) |
| 51 | }) |
| 52 | |
| 53 | // preload images for nearby slides |
| 54 | usePreloadImages(currentSlideRoute, prevRoute, nextRoute, slides) |
| 55 | |
| 56 | const hasViewTransition = useViewTransition() |
| 57 | |
| 58 | const DrawingLayer = shallowRef<any>() |
| 59 | if (__SLIDEV_FEATURE_DRAWINGS__ || __SLIDEV_FEATURE_DRAWINGS_PERSIST__) |
| 60 | import('./DrawingLayer.vue').then(v => DrawingLayer.value = v.default) |
| 61 | |
| 62 | const loadedRoutes = computed(() => isPrintMode.value |
| 63 | ? printRange.value.map(no => slides.value[no - 1]) |
| 64 | : slides.value.filter(r => r.meta?.__preloaded || r === currentSlideRoute.value), |
| 65 | ) |
| 66 | |
| 67 | function onAfterLeave() { |
| 68 | // After transition, we disable it so HMR won't trigger it again |
| 69 | // We will turn it back on `nav.go` so the normal navigation would still work |
| 70 | hmrSkipTransition.value = true |
| 71 | // recompute poppers after transition |
| 72 | recomputeAllPoppers() |
| 73 | } |
| 74 | </script> |
| 75 | |
| 76 | <template> |
| 77 | <!-- Global Bottom --> |
| 78 | <GlobalBottom /> |
| 79 | |
| 80 | <!-- Slides --> |
| 81 | <component |
| 82 | :is="(hasViewTransition && !isPrintMode && !hmrSkipTransition && !disableTransition) ? 'div' : TransitionGroup" |
| 83 | v-bind="(hmrSkipTransition || disableTransition || isPrintMode) ? {} : currentTransition" |
| 84 | id="slideshow" |
| 85 | tag="div" |
| 86 | :class="{ |
| 87 | 'slidev-nav-go-forward': clicksDirection > 0, |
| 88 | 'slidev-nav-go-backward': clicksDirection < 0, |
| 89 | }" |
| 90 | @after-leave="onAfterLeave" |
| 91 | > |
| 92 | <template v-for="route of loadedRoutes" :key="route.no"> |
| 93 | <SlideWrapper |
| 94 | v-show="route === currentSlideRoute" |
| 95 | :clicks-context="isPrintMode && !isPrintWithClicks ? createFixedClicks(route, CLICKS_MAX) : getPrimaryClicks(route)" |
| 96 | :route="route" |
| 97 | :render-context="renderContext" |
| 98 | /> |
| 99 | </template> |
| 100 | </component> |
| 101 | |
| 102 | <DragControl v-if="activeDragElement" :data="activeDragElement" /> |
| 103 | |
| 104 | <!-- Global Top --> |
| 105 | <GlobalTop /> |
| 106 | |
| 107 | <template v-if="(__SLIDEV_FEATURE_DRAWINGS__ || __SLIDEV_FEATURE_DRAWINGS_PERSIST__) && DrawingLayer"> |
| 108 | <DrawingLayer /> |
| 109 | </template> |
| 110 | </template> |
| 111 | |
| 112 | <style scoped> |
| 113 | #slideshow { |
| 114 | height: 100%; |
| 115 | } |
| 116 | </style> |
| 117 |