Skip to content

Commit 926c84a

Browse files
committed
feat: preload next slide
1 parent 2f82ecd commit 926c84a

File tree

9 files changed

+126
-45
lines changed

9 files changed

+126
-45
lines changed

.eslintrc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@
44
"jest": true
55
},
66
"extends": "@antfu",
7-
"plugins": ["jest"]
7+
"plugins": ["jest"],
8+
"rules": {
9+
"vue/no-lone-template": "off"
10+
}
811
}

packages/client/internals/Play.vue

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
<script setup lang="ts">
2-
import { ref, computed } from 'vue'
2+
import { ref, computed, watch } from 'vue'
3+
import type { RouteRecordRaw } from 'vue-router'
34
import { isPrintMode, showEditor, windowSize, isScreenVertical, slideScale } from '../state'
4-
import { next, prev, currentRoute, clicks, clicksElements, useSwipeControls } from '../logic/nav'
5+
import { next, prev, currentRoute, clicks, clicksElements, useSwipeControls, rawRoutes, nextRoute } from '../logic/nav'
56
import { registerShotcuts } from '../logic/shortcuts'
67
import Controls from './Controls.vue'
78
import SlideContainer from './SlideContainer.vue'
89
import Editor from './Editor.vue'
910
import NavControls from './NavControls.vue'
11+
import SlideWrapper from './SlideWrapper.vue'
1012
1113
registerShotcuts()
1214
15+
// preload next route
16+
watch(currentRoute, () => {
17+
if (currentRoute.value?.meta)
18+
currentRoute.value.meta.loaded = true
19+
if (nextRoute.value?.meta)
20+
nextRoute.value.meta.loaded = true
21+
}, { immediate: true })
22+
1323
const root = ref<HTMLDivElement>()
1424
function onClick(e: MouseEvent) {
1525
if (showEditor.value)
@@ -27,20 +37,36 @@ function onClick(e: MouseEvent) {
2737
useSwipeControls(root)
2838
2939
const presistNav = computed(() => isScreenVertical.value || showEditor.value)
40+
41+
const getClass = (route: RouteRecordRaw) => {
42+
const no = route?.meta?.slide?.no
43+
if (no != null)
44+
return `slidev-page-${no}`
45+
return ''
46+
}
3047
</script>
3148

3249
<template>
3350
<div id="page-root" ref="root" class="grid grid-cols-[1fr,max-content]">
3451
<SlideContainer
35-
v-model:clicks="clicks"
36-
v-model:clicks-elements="clicksElements"
3752
class="w-full h-full bg-black"
3853
:width="isPrintMode ? windowSize.width.value : undefined"
39-
:route="currentRoute"
40-
:clicks-disabled="false"
4154
:scale="slideScale"
4255
@click="onClick"
4356
>
57+
<template #>
58+
<template v-for="route of rawRoutes" :key="route.path">
59+
<SlideWrapper
60+
:is="route?.component"
61+
v-show="route === currentRoute"
62+
v-if="route.meta.loaded"
63+
:clicks="route === currentRoute ? clicks : 0"
64+
:clicks-elements="route.meta.clicksElements"
65+
:clicks-disabled="false"
66+
:class="getClass(route)"
67+
/>
68+
</template>
69+
</template>
4470
<template #controls>
4571
<div
4672
class="absolute bottom-0 left-0 transition duration-300 opacity-0 hover:opacity-100"

packages/client/internals/Presenter.vue

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<script setup lang="ts">
22
import { useHead } from '@vueuse/head'
3-
import { ref, computed } from 'vue'
3+
import { ref, computed, watch } from 'vue'
44
import { useTimestamp } from '@vueuse/core'
5-
import { total, currentPage, currentRoute, nextRoute, clicks, clicksElements, useSwipeControls, clicksTotal, hasNext } from '../logic/nav'
5+
import type { RouteRecordRaw } from 'vue-router'
6+
import { total, currentPage, currentRoute, nextRoute, clicks, clicksElements, useSwipeControls, clicksTotal, hasNext, rawRoutes } from '../logic/nav'
67
import { showOverview } from '../state'
78
import { configs } from '../env'
89
import { registerShotcuts } from '../logic/shortcuts'
@@ -11,9 +12,18 @@ import NavControls from './NavControls.vue'
1112
import SlidesOverview from './SlidesOverview.vue'
1213
import NoteEditor from './NoteEditor.vue'
1314
import Goto from './Goto.vue'
15+
import SlideWrapper from './SlideWrapper.vue'
1416
1517
registerShotcuts()
1618
19+
// preload next route
20+
watch(currentRoute, () => {
21+
if (currentRoute.value?.meta)
22+
currentRoute.value.meta.loaded = true
23+
if (nextRoute.value?.meta)
24+
nextRoute.value.meta.loaded = true
25+
}, { immediate: true })
26+
1727
useHead({
1828
title: configs.title ? `Presenter - ${configs.title} - Slidev` : 'Presenter - Slidev',
1929
})
@@ -56,6 +66,13 @@ const nextSlide = computed(() => {
5666
})
5767
5868
useSwipeControls(main)
69+
70+
const getClass = (route: RouteRecordRaw) => {
71+
const no = route?.meta?.slide?.no
72+
if (no != null)
73+
return `slidev-page-${no}`
74+
return ''
75+
}
5976
</script>
6077

6178
<template>
@@ -79,23 +96,37 @@ useSwipeControls(main)
7996
<div ref="main" class="grid-section main flex flex-col p-4">
8097
<SlideContainer
8198
key="main"
82-
v-model:clicks="clicks"
83-
v-model:clicks-elements="clicksElements"
8499
class="h-full w-full"
85-
:route="currentRoute"
86-
:clicks-disabled="false"
87-
/>
100+
>
101+
<template #>
102+
<template v-for="route of rawRoutes" :key="route.path">
103+
<SlideWrapper
104+
:is="route?.component"
105+
v-if="route.meta.loaded"
106+
:style="{ display: route === currentRoute ? null : 'none' }"
107+
:clicks="route === currentRoute ? clicks : 0"
108+
:clicks-elements="route.meta.clicksElements"
109+
:clicks-disabled="false"
110+
:class="getClass(route)"
111+
/>
112+
</template>
113+
</template>
114+
</SlideContainer>
88115
</div>
89116
<div class="grid-section next flex flex-col p-4">
90117
<SlideContainer
91118
v-if="nextSlide"
92119
key="next"
93-
v-model:clicks-elements="nextTabElements"
94120
class="h-full w-full"
95-
:clicks="nextSlide.clicks"
96-
:route="nextSlide.route"
97-
:clicks-disabled="false"
98-
/>
121+
>
122+
<SlideWrapper
123+
:is="nextSlide.route?.component"
124+
v-model:clicks-elements="nextTabElements"
125+
:clicks="nextSlide.clicks"
126+
:clicks-disabled="false"
127+
:class="getClass(nextSlide.route)"
128+
/>
129+
</SlideContainer>
99130
</div>
100131
<div class="grid-section note">
101132
<NoteEditor class="w-full h-full p-4 overflow-auto" />

packages/client/internals/SlideContainer.vue

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,16 @@ import { computed, defineProps, ref, watchEffect, provide, defineEmit } from 'vu
44
import type { RouteRecordRaw } from 'vue-router'
55
import { slideAspect, slideWidth, slideHeight } from '../constants'
66
import { injectionClicks, injectionClicksDisabled, injectionClicksElements } from '../modules/directives'
7+
import SlideWrapper from './SlideWrapper.vue'
78
89
const emit = defineEmit()
910
const props = defineProps({
1011
width: {
1112
type: Number,
1213
},
13-
clicks: {
14-
default: 0,
15-
},
16-
clicksElements: {
17-
default: () => [] as Element[],
18-
},
19-
clicksDisabled: {
20-
default: false,
21-
},
2214
meta: {
2315
default: () => ({}) as any,
2416
},
25-
route: {
26-
default: () => ({}) as any as RouteRecordRaw,
27-
},
2817
scale: {
2918
type: Number,
3019
},
@@ -36,16 +25,6 @@ const props = defineProps({
3625
},
3726
})
3827
39-
const clicks = useVModel(props, 'clicks', emit)
40-
const clicksElements = useVModel(props, 'clicksElements', emit)
41-
const clicksDisabled = useVModel(props, 'clicksDisabled', emit)
42-
43-
clicksElements.value = []
44-
45-
provide(injectionClicks, clicks)
46-
provide(injectionClicksDisabled, clicksDisabled)
47-
provide(injectionClicksElements, clicksElements)
48-
4928
const root = ref<HTMLDivElement>()
5029
const element = useElementSize(root)
5130
@@ -78,7 +57,7 @@ const style = computed(() => ({
7857
}))
7958
8059
const classes = computed(() => {
81-
const no = props.no ?? props.route?.meta?.slide?.no
60+
const no = props.no
8261
if (no != null)
8362
return `slidev-page-${no}`
8463
return ''
@@ -89,7 +68,7 @@ const classes = computed(() => {
8968
<div id="slide-container" ref="root">
9069
<div id="slide-content" :style="style">
9170
<slot>
92-
<component :is="props.is || route.component" :class="classes" />
71+
<SlideWrapper :is="props.is" :class="classes" :clicks-disabled="true" />
9372
</slot>
9473
</div>
9574
<slot name="controls" />
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<script setup lang="ts">
2+
import { useElementSize, useVModel } from '@vueuse/core'
3+
import { computed, defineProps, ref, watchEffect, provide, defineEmit } from 'vue'
4+
import type { RouteRecordRaw } from 'vue-router'
5+
import { slideAspect, slideWidth, slideHeight } from '../constants'
6+
import { injectionClicks, injectionClicksDisabled, injectionClicksElements } from '../modules/directives'
7+
8+
const emit = defineEmit()
9+
const props = defineProps({
10+
clicks: {
11+
default: 0,
12+
},
13+
clicksElements: {
14+
default: () => [] as Element[],
15+
},
16+
clicksDisabled: {
17+
default: false,
18+
},
19+
is: {
20+
type: Object,
21+
},
22+
})
23+
24+
const clicks = useVModel(props, 'clicks', emit)
25+
const clicksElements = useVModel(props, 'clicksElements', emit)
26+
const clicksDisabled = useVModel(props, 'clicksDisabled', emit)
27+
28+
clicksElements.value.length = 0
29+
30+
provide(injectionClicks, clicks)
31+
provide(injectionClicksDisabled, clicksDisabled)
32+
provide(injectionClicksElements, clicksElements)
33+
</script>
34+
35+
<template>
36+
<component :is="props.is" />
37+
</template>

packages/client/internals/SlidesOverview.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,10 @@ const cardWidth = computed(() => {
5252
@click="go(+route.path)"
5353
>
5454
<SlideContainer
55+
:is="route?.component"
5556
:key="route.path"
5657
:width="cardWidth"
57-
:route="route"
58+
:no="route?.meta?.slide?.no"
5859
:clicks-disabled="true"
5960
class="pointer-events-none"
6061
/>

packages/client/logic/nav.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const hasNext = computed(() => currentPage.value < rawRoutes.length - 1)
2222
export const hasPrev = computed(() => currentPage.value > 1)
2323
export const nextRoute = computed(() => rawRoutes.find(i => i.path === `${Math.min(rawRoutes.length, currentPage.value + 1)}`))
2424

25-
export const clicksElements = ref<HTMLElement[]>([])
25+
export const clicksElements = computed<HTMLElement[]>(() => currentRoute.value?.meta?.clicksElements || [])
2626
export const clicks = computed<number>({
2727
get() {
2828
let clicks = +query.clicks || 0

packages/client/routes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ export const router = createRouter({
4040
declare module 'vue-router' {
4141
interface RouteMeta {
4242
layout: string
43+
clicksElements: HTMLElement[]
44+
loaded?: boolean
4345
name?: string
4446
class?: string
4547
clicks?: number

packages/slidev/node/plugins/loaders.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,8 @@ export function createSlidesLoader(
361361
id: idx,
362362
no,
363363
},
364+
clicksElements: [],
365+
loaded: false,
364366
}
365367
const meta = Object.assign({}, i.frontmatter, additions)
366368
const route = `{ path: '${no}', name: 'page-${no}', component: n${no}, meta: ${JSON.stringify(meta)} }`

0 commit comments

Comments
 (0)