@slidev/client 0.48.0-beta.20 → 0.48.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/builtin/SlidevVideo.vue +1 -1
- package/builtin/Toc.vue +1 -1
- package/builtin/TocList.vue +1 -1
- package/composables/useClicks.ts +16 -15
- package/composables/useContext.ts +4 -9
- package/composables/useNav.ts +182 -44
- package/composables/useSwipeControls.ts +40 -0
- package/composables/useTocTree.ts +63 -0
- package/constants.ts +2 -3
- package/context.ts +1 -1
- package/internals/Goto.vue +2 -2
- package/internals/NavControls.vue +7 -5
- package/internals/NoteStatic.vue +1 -1
- package/internals/PrintContainer.vue +4 -3
- package/internals/PrintSlide.vue +6 -13
- package/internals/PrintSlideClick.vue +9 -11
- package/internals/QuickOverview.vue +10 -10
- package/internals/SideEditor.vue +3 -3
- package/internals/SlideLoading.vue +19 -0
- package/internals/SlideWrapper.ts +12 -12
- package/internals/SlidesShow.vue +13 -10
- package/layouts/error.vue +5 -0
- package/logic/drawings.ts +7 -7
- package/logic/nav-state.ts +20 -0
- package/logic/nav.ts +49 -259
- package/logic/note.ts +2 -2
- package/logic/overview.ts +2 -2
- package/logic/route.ts +10 -1
- package/logic/slides.ts +19 -0
- package/logic/transition.ts +50 -0
- package/modules/context.ts +3 -10
- package/package.json +5 -4
- package/pages/notes.vue +2 -3
- package/pages/overview.vue +19 -21
- package/pages/play.vue +2 -1
- package/pages/presenter/print.vue +2 -2
- package/pages/presenter.vue +15 -14
- package/routes.ts +6 -14
- package/setup/root.ts +6 -7
- package/setup/shortcuts.ts +2 -1
- package/shim-vue.d.ts +3 -0
- package/utils.ts +15 -2
package/builtin/SlidevVideo.vue
CHANGED
|
@@ -22,7 +22,7 @@ const ended = ref(false)
|
|
|
22
22
|
const matchRoute = computed(() => {
|
|
23
23
|
if (!video.value || currentContext?.value !== 'slide')
|
|
24
24
|
return false
|
|
25
|
-
return route === $slidev?.nav.
|
|
25
|
+
return route && route.no === $slidev?.nav.currentSlideNo
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
const matchClick = computed(() => {
|
package/builtin/Toc.vue
CHANGED
package/builtin/TocList.vue
CHANGED
|
@@ -48,7 +48,7 @@ const styles = computed(() => {
|
|
|
48
48
|
:class="[{ 'slidev-toc-item-active': item.active }, { 'slidev-toc-item-parent-active': item.activeParent }]"
|
|
49
49
|
>
|
|
50
50
|
<Link :to="item.path">
|
|
51
|
-
<Titles :no="item.
|
|
51
|
+
<Titles :no="item.no" />
|
|
52
52
|
</Link>
|
|
53
53
|
<TocList
|
|
54
54
|
v-if="item.children.length > 0"
|
package/composables/useClicks.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { sum } from '@antfu/utils'
|
|
2
|
-
import type { ClicksContext } from '@slidev/types'
|
|
2
|
+
import type { ClicksContext, SlideRoute } from '@slidev/types'
|
|
3
3
|
import type { Ref } from 'vue'
|
|
4
4
|
import { computed, ref, shallowReactive } from 'vue'
|
|
5
|
-
import
|
|
6
|
-
import { currentRoute, isPrintMode, isPrintWithClicks, queryClicks, routeForceRefresh } from '../logic/nav'
|
|
5
|
+
import { currentSlideNo, isPrintMode, isPrintWithClicks } from '../logic/nav'
|
|
7
6
|
import { normalizeAtProp } from '../logic/utils'
|
|
8
7
|
import { CLICKS_MAX } from '../constants'
|
|
8
|
+
import { routeForceRefresh, useRouteQuery } from '../logic/route'
|
|
9
9
|
|
|
10
10
|
function useClicksContextBase(current: Ref<number>, clicksOverrides?: number): ClicksContext {
|
|
11
11
|
const relativeOffsets: ClicksContext['relativeOffsets'] = new Map()
|
|
@@ -63,27 +63,28 @@ function useClicksContextBase(current: Ref<number>, clicksOverrides?: number): C
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
const queryClicksRaw = useRouteQuery('clicks', '0')
|
|
67
|
+
|
|
68
|
+
export function usePrimaryClicks(route: SlideRoute): ClicksContext {
|
|
67
69
|
if (route?.meta?.__clicksContext)
|
|
68
70
|
return route.meta.__clicksContext
|
|
69
|
-
const
|
|
71
|
+
const thisNo = route.no
|
|
70
72
|
const current = computed({
|
|
71
73
|
get() {
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
return
|
|
75
|
-
if (
|
|
76
|
-
return
|
|
77
|
-
else if (
|
|
74
|
+
// eslint-disable-next-line ts/no-use-before-define
|
|
75
|
+
if (context.disabled)
|
|
76
|
+
return CLICKS_MAX
|
|
77
|
+
if (currentSlideNo.value === thisNo)
|
|
78
|
+
return +(queryClicksRaw.value || 0) || 0
|
|
79
|
+
else if (currentSlideNo.value > thisNo)
|
|
78
80
|
return CLICKS_MAX
|
|
79
81
|
else
|
|
80
82
|
return 0
|
|
81
83
|
},
|
|
82
84
|
set(v) {
|
|
83
|
-
|
|
84
|
-
if (currentPath === thisPath) {
|
|
85
|
+
if (currentSlideNo.value === thisNo) {
|
|
85
86
|
// eslint-disable-next-line ts/no-use-before-define
|
|
86
|
-
|
|
87
|
+
queryClicksRaw.value = Math.min(v, context.total).toString()
|
|
87
88
|
}
|
|
88
89
|
},
|
|
89
90
|
})
|
|
@@ -96,6 +97,6 @@ export function usePrimaryClicks(route: RouteRecordRaw | undefined): ClicksConte
|
|
|
96
97
|
return context
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
export function useFixedClicks(route?:
|
|
100
|
+
export function useFixedClicks(route?: SlideRoute | undefined, currentInit = 0): ClicksContext {
|
|
100
101
|
return useClicksContextBase(ref(currentInit), route?.meta?.clicks)
|
|
101
102
|
}
|
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import type { ComputedRef } from 'vue'
|
|
2
1
|
import { computed } from 'vue'
|
|
3
|
-
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
|
4
|
-
import type { SlidevContext } from '../modules/context'
|
|
5
2
|
import { configs } from '../env'
|
|
6
|
-
import {
|
|
3
|
+
import type { SlidevContext } from '../modules/context'
|
|
4
|
+
import * as nav from '../logic/nav'
|
|
7
5
|
|
|
8
|
-
export function useContext(
|
|
9
|
-
route: ComputedRef<RouteLocationNormalizedLoaded>,
|
|
10
|
-
): SlidevContext {
|
|
11
|
-
const nav = useNav(route)
|
|
6
|
+
export function useContext(): SlidevContext {
|
|
12
7
|
return {
|
|
13
|
-
nav,
|
|
8
|
+
nav: { ...nav }, // Convert the module to a plain object
|
|
14
9
|
configs,
|
|
15
10
|
themeConfigs: computed(() => configs.themeConfig),
|
|
16
11
|
}
|
package/composables/useNav.ts
CHANGED
|
@@ -1,55 +1,193 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import type {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
1
|
+
import type { ClicksContext, SlideRoute, TocItem } from '@slidev/types'
|
|
2
|
+
import type { ComputedRef, Ref, TransitionGroupProps } from 'vue'
|
|
3
|
+
import { computed, ref, watch } from 'vue'
|
|
4
|
+
import type { Router } from 'vue-router'
|
|
5
|
+
import { getCurrentTransition } from '../logic/transition'
|
|
6
|
+
import { getSlidePath } from '../logic/slides'
|
|
7
|
+
import { useTocTree } from './useTocTree'
|
|
8
|
+
import { skipTransition } from './hmr'
|
|
9
|
+
import { slides } from '#slidev/slides'
|
|
10
|
+
|
|
11
|
+
export interface SlidevContextNav {
|
|
12
|
+
slides: Ref<SlideRoute[]>
|
|
13
|
+
total: ComputedRef<number>
|
|
14
|
+
|
|
15
|
+
currentPath: ComputedRef<string>
|
|
16
|
+
currentPage: ComputedRef<number>
|
|
17
|
+
currentSlideNo: ComputedRef<number>
|
|
18
|
+
currentSlideRoute: ComputedRef<SlideRoute>
|
|
19
|
+
currentTransition: ComputedRef<TransitionGroupProps | undefined>
|
|
20
|
+
currentLayout: ComputedRef<string>
|
|
21
|
+
|
|
22
|
+
nextRoute: ComputedRef<SlideRoute>
|
|
23
|
+
prevRoute: ComputedRef<SlideRoute>
|
|
24
|
+
hasNext: ComputedRef<boolean>
|
|
25
|
+
hasPrev: ComputedRef<boolean>
|
|
26
|
+
|
|
27
|
+
clicksContext: ComputedRef<ClicksContext>
|
|
28
|
+
clicks: ComputedRef<number>
|
|
29
|
+
clicksTotal: ComputedRef<number>
|
|
30
|
+
|
|
31
|
+
/** The table of content tree */
|
|
32
|
+
tocTree: ComputedRef<TocItem[]>
|
|
33
|
+
/** The direction of the navigation, 1 for forward, -1 for backward */
|
|
34
|
+
navDirection: Ref<number>
|
|
35
|
+
/** The direction of the clicks, 1 for forward, -1 for backward */
|
|
36
|
+
clicksDirection: Ref<number>
|
|
37
|
+
/** Utility function for open file in editor, only avaible in dev mode */
|
|
38
|
+
openInEditor: (url?: string) => Promise<boolean>
|
|
39
|
+
|
|
40
|
+
/** Go to next click */
|
|
41
|
+
next: () => Promise<void>
|
|
42
|
+
/** Go to previous click */
|
|
43
|
+
prev: () => Promise<void>
|
|
44
|
+
/** Go to next slide */
|
|
45
|
+
nextSlide: () => Promise<void>
|
|
46
|
+
/** Go to previous slide */
|
|
47
|
+
prevSlide: (lastClicks?: boolean) => Promise<void>
|
|
48
|
+
/** Go to slide */
|
|
49
|
+
go: (page: number | string, clicks?: number) => Promise<void>
|
|
50
|
+
/** Go to the first slide */
|
|
51
|
+
goFirst: () => Promise<void>
|
|
52
|
+
/** Go to the last slide */
|
|
53
|
+
goLast: () => Promise<void>
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function useNavBase(
|
|
57
|
+
currentSlideRoute: ComputedRef<SlideRoute>,
|
|
58
|
+
clicksContext: ComputedRef<ClicksContext>,
|
|
59
|
+
queryClicks: Ref<number> = ref(0),
|
|
60
|
+
router?: Router,
|
|
61
|
+
): SlidevContextNav {
|
|
62
|
+
const total = computed(() => slides.value.length)
|
|
63
|
+
|
|
64
|
+
const navDirection = ref(0)
|
|
65
|
+
const clicksDirection = ref(0)
|
|
66
|
+
|
|
67
|
+
const currentPath = computed(() => getSlidePath(currentSlideRoute.value))
|
|
68
|
+
const currentSlideNo = computed(() => currentSlideRoute.value.no)
|
|
69
|
+
const currentLayout = computed(() => currentSlideRoute.value.meta?.layout || (currentSlideNo.value === 1 ? 'cover' : 'default'))
|
|
70
|
+
|
|
71
|
+
const clicks = computed(() => clicksContext.value.current)
|
|
72
|
+
const clicksTotal = computed(() => clicksContext.value.total)
|
|
73
|
+
const nextRoute = computed(() => slides.value[Math.min(slides.value.length, currentSlideNo.value + 1) - 1])
|
|
74
|
+
const prevRoute = computed(() => slides.value[Math.max(1, currentSlideNo.value - 1) - 1])
|
|
75
|
+
const hasNext = computed(() => currentSlideNo.value < slides.value.length || clicks.value < clicksTotal.value)
|
|
76
|
+
const hasPrev = computed(() => currentSlideNo.value > 1 || clicks.value > 0)
|
|
77
|
+
|
|
78
|
+
const currentTransition = computed(() => getCurrentTransition(navDirection.value, currentSlideRoute.value, prevRoute.value))
|
|
79
|
+
|
|
80
|
+
watch(currentSlideRoute, (next, prev) => {
|
|
81
|
+
navDirection.value = next.no - prev.no
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
async function openInEditor(url?: string) {
|
|
85
|
+
if (!__DEV__)
|
|
86
|
+
return false
|
|
87
|
+
if (url == null) {
|
|
88
|
+
const slide = currentSlideRoute.value?.meta?.slide
|
|
89
|
+
if (!slide)
|
|
90
|
+
return false
|
|
91
|
+
url = `${slide.filepath}:${slide.start}`
|
|
92
|
+
}
|
|
93
|
+
await fetch(`/__open-in-editor?file=${encodeURIComponent(url)}`)
|
|
94
|
+
return true
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const tocTree = useTocTree(slides)
|
|
98
|
+
|
|
99
|
+
async function next() {
|
|
100
|
+
clicksDirection.value = 1
|
|
101
|
+
if (clicksTotal.value <= queryClicks.value)
|
|
102
|
+
await nextSlide()
|
|
103
|
+
else
|
|
104
|
+
queryClicks.value += 1
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function prev() {
|
|
108
|
+
clicksDirection.value = -1
|
|
109
|
+
if (queryClicks.value <= 0)
|
|
110
|
+
await prevSlide()
|
|
111
|
+
else
|
|
112
|
+
queryClicks.value -= 1
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function nextSlide() {
|
|
116
|
+
clicksDirection.value = 1
|
|
117
|
+
if (currentSlideNo.value < slides.value.length)
|
|
118
|
+
await go(currentSlideNo.value + 1)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function prevSlide(lastClicks = true) {
|
|
122
|
+
clicksDirection.value = -1
|
|
123
|
+
const next = Math.max(1, currentSlideNo.value - 1)
|
|
124
|
+
await go(next)
|
|
125
|
+
if (lastClicks && clicksTotal.value) {
|
|
126
|
+
router?.replace({
|
|
127
|
+
query: { ...router.currentRoute.value.query, clicks: clicksTotal.value },
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function goFirst() {
|
|
133
|
+
return go(1)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function goLast() {
|
|
137
|
+
return go(total.value)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function go(page: number | string, clicks?: number) {
|
|
141
|
+
skipTransition.value = false
|
|
142
|
+
await router?.push({
|
|
143
|
+
path: getSlidePath(page),
|
|
144
|
+
query: { ...router.currentRoute.value.query, clicks },
|
|
145
|
+
})
|
|
146
|
+
}
|
|
29
147
|
|
|
30
148
|
return {
|
|
31
|
-
|
|
32
|
-
route,
|
|
33
|
-
path,
|
|
149
|
+
slides,
|
|
34
150
|
total,
|
|
35
|
-
clicksContext,
|
|
36
|
-
clicks,
|
|
37
|
-
clicksTotal,
|
|
38
|
-
currentPage,
|
|
39
151
|
currentPath,
|
|
40
|
-
|
|
41
|
-
|
|
152
|
+
currentSlideNo,
|
|
153
|
+
currentPage: currentSlideNo,
|
|
154
|
+
currentSlideRoute,
|
|
42
155
|
currentLayout,
|
|
156
|
+
currentTransition,
|
|
157
|
+
clicksDirection,
|
|
43
158
|
nextRoute,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
159
|
+
prevRoute,
|
|
160
|
+
clicksContext,
|
|
161
|
+
clicks,
|
|
162
|
+
clicksTotal,
|
|
163
|
+
hasNext,
|
|
164
|
+
hasPrev,
|
|
165
|
+
tocTree,
|
|
166
|
+
navDirection,
|
|
51
167
|
openInEditor,
|
|
168
|
+
next,
|
|
52
169
|
prev,
|
|
170
|
+
go,
|
|
171
|
+
goLast,
|
|
172
|
+
goFirst,
|
|
173
|
+
nextSlide,
|
|
53
174
|
prevSlide,
|
|
54
175
|
}
|
|
55
176
|
}
|
|
177
|
+
|
|
178
|
+
export function useFixedNav(
|
|
179
|
+
currentSlideRoute: SlideRoute,
|
|
180
|
+
clicksContext: ClicksContext,
|
|
181
|
+
): SlidevContextNav {
|
|
182
|
+
const noop = async () => { }
|
|
183
|
+
return {
|
|
184
|
+
...useNavBase(computed(() => currentSlideRoute), computed(() => clicksContext)),
|
|
185
|
+
next: noop,
|
|
186
|
+
prev: noop,
|
|
187
|
+
nextSlide: noop,
|
|
188
|
+
prevSlide: noop,
|
|
189
|
+
goFirst: noop,
|
|
190
|
+
goLast: noop,
|
|
191
|
+
go: noop,
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Ref } from 'vue'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import { timestamp, usePointerSwipe } from '@vueuse/core'
|
|
4
|
+
import { isDrawing } from '../logic/drawings'
|
|
5
|
+
import { next, nextSlide, prev, prevSlide } from '../logic/nav'
|
|
6
|
+
|
|
7
|
+
export function useSwipeControls(root: Ref<HTMLElement | undefined>) {
|
|
8
|
+
const swipeBegin = ref(0)
|
|
9
|
+
const { direction, distanceX, distanceY } = usePointerSwipe(root, {
|
|
10
|
+
pointerTypes: ['touch'],
|
|
11
|
+
onSwipeStart() {
|
|
12
|
+
if (isDrawing.value)
|
|
13
|
+
return
|
|
14
|
+
swipeBegin.value = timestamp()
|
|
15
|
+
},
|
|
16
|
+
onSwipeEnd() {
|
|
17
|
+
if (!swipeBegin.value)
|
|
18
|
+
return
|
|
19
|
+
if (isDrawing.value)
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
const x = Math.abs(distanceX.value)
|
|
23
|
+
const y = Math.abs(distanceY.value)
|
|
24
|
+
if (x / window.innerWidth > 0.3 || x > 75) {
|
|
25
|
+
if (direction.value === 'left')
|
|
26
|
+
next()
|
|
27
|
+
|
|
28
|
+
else
|
|
29
|
+
prev()
|
|
30
|
+
}
|
|
31
|
+
else if (y / window.innerHeight > 0.4 || y > 200) {
|
|
32
|
+
if (direction.value === 'down')
|
|
33
|
+
prevSlide()
|
|
34
|
+
|
|
35
|
+
else
|
|
36
|
+
nextSlide()
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { SlideRoute, TocItem } from '@slidev/types'
|
|
2
|
+
import type { ComputedRef, Ref } from 'vue'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import { currentSlideNo, currentSlideRoute, getSlidePath } from '../logic/nav'
|
|
5
|
+
|
|
6
|
+
function addToTree(tree: TocItem[], route: SlideRoute, level = 1) {
|
|
7
|
+
const titleLevel = route.meta?.slide?.level
|
|
8
|
+
if (titleLevel && titleLevel > level && tree.length > 0) {
|
|
9
|
+
addToTree(tree[tree.length - 1].children, route, level + 1)
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
tree.push({
|
|
13
|
+
no: route.no,
|
|
14
|
+
children: [],
|
|
15
|
+
level,
|
|
16
|
+
path: getSlidePath(route.meta.slide?.frontmatter?.routeAlias ?? route.no),
|
|
17
|
+
hideInToc: Boolean(route.meta?.slide?.frontmatter?.hideInToc),
|
|
18
|
+
title: route.meta?.slide?.title,
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getTreeWithActiveStatuses(
|
|
24
|
+
tree: TocItem[],
|
|
25
|
+
currentRoute?: SlideRoute,
|
|
26
|
+
hasActiveParent = false,
|
|
27
|
+
parent?: TocItem,
|
|
28
|
+
): TocItem[] {
|
|
29
|
+
return tree.map((item: TocItem) => {
|
|
30
|
+
const clone = {
|
|
31
|
+
...item,
|
|
32
|
+
active: item.no === currentSlideNo.value,
|
|
33
|
+
hasActiveParent,
|
|
34
|
+
}
|
|
35
|
+
if (clone.children.length > 0)
|
|
36
|
+
clone.children = getTreeWithActiveStatuses(clone.children, currentRoute, clone.active || clone.hasActiveParent, clone)
|
|
37
|
+
if (parent && (clone.active || clone.activeParent))
|
|
38
|
+
parent.activeParent = true
|
|
39
|
+
return clone
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function filterTree(tree: TocItem[], level = 1): TocItem[] {
|
|
44
|
+
return tree
|
|
45
|
+
.filter((item: TocItem) => !item.hideInToc)
|
|
46
|
+
.map((item: TocItem) => ({
|
|
47
|
+
...item,
|
|
48
|
+
children: filterTree(item.children, level + 1),
|
|
49
|
+
}))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function useTocTree(slides: Ref<SlideRoute[]>): ComputedRef<TocItem[]> {
|
|
53
|
+
const rawTree = computed(() => slides.value
|
|
54
|
+
.filter((route: SlideRoute) => route.meta?.slide?.title)
|
|
55
|
+
.reduce((acc: TocItem[], route: SlideRoute) => {
|
|
56
|
+
addToTree(acc, route)
|
|
57
|
+
return acc
|
|
58
|
+
}, []))
|
|
59
|
+
|
|
60
|
+
const treeWithActiveStatuses = computed(() => getTreeWithActiveStatuses(rawTree.value, currentSlideRoute.value))
|
|
61
|
+
|
|
62
|
+
return computed(() => filterTree(treeWithActiveStatuses.value))
|
|
63
|
+
}
|
package/constants.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ComputedRef, InjectionKey, Ref, UnwrapNestedRefs } from 'vue'
|
|
2
|
-
import type {
|
|
3
|
-
import type { ClicksContext, RenderContext } from '@slidev/types'
|
|
2
|
+
import type { ClicksContext, RenderContext, SlideRoute } from '@slidev/types'
|
|
4
3
|
import type { SlidevContext } from './modules/context'
|
|
5
4
|
|
|
6
5
|
// Here we use string literal instead of symbols to make HMR more stable
|
|
@@ -9,7 +8,7 @@ export const injectionClicksContext = '$$slidev-clicks-context' as unknown as In
|
|
|
9
8
|
export const injectionCurrentPage = '$$slidev-page' as unknown as InjectionKey<Ref<number>>
|
|
10
9
|
export const injectionSlideScale = '$$slidev-slide-scale' as unknown as InjectionKey<ComputedRef<number>>
|
|
11
10
|
export const injectionSlidevContext = '$$slidev-context' as unknown as InjectionKey<UnwrapNestedRefs<SlidevContext>>
|
|
12
|
-
export const injectionRoute = '$$slidev-route' as unknown as InjectionKey<
|
|
11
|
+
export const injectionRoute = '$$slidev-route' as unknown as InjectionKey<SlideRoute>
|
|
13
12
|
export const injectionRenderContext = '$$slidev-render-context' as unknown as InjectionKey<Ref<RenderContext>>
|
|
14
13
|
export const injectionActive = '$$slidev-active' as unknown as InjectionKey<Ref<boolean>>
|
|
15
14
|
export const injectionFrontmatter = '$$slidev-fontmatter' as unknown as InjectionKey<Record<string, any>>
|
package/context.ts
CHANGED
|
@@ -51,7 +51,7 @@ export function provideFrontmatter(frontmatter: Record<string, any>) {
|
|
|
51
51
|
} = useSlideContext()
|
|
52
52
|
|
|
53
53
|
// update frontmatter in router to make HMR work better
|
|
54
|
-
const route = $slidev.nav.
|
|
54
|
+
const route = $slidev.nav.slides.find(i => i.no === $page.value)
|
|
55
55
|
if (route?.meta?.slide?.frontmatter) {
|
|
56
56
|
for (const key of Object.keys(route.meta.slide.frontmatter)) {
|
|
57
57
|
if (!(key in frontmatter))
|
package/internals/Goto.vue
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, ref, watch } from 'vue'
|
|
3
3
|
import Fuse from 'fuse.js'
|
|
4
|
-
import { go,
|
|
4
|
+
import { go, slides } from '../logic/nav'
|
|
5
5
|
import { activeElement, showGotoDialog } from '../state'
|
|
6
6
|
import Titles from '#slidev/titles.md'
|
|
7
7
|
|
|
@@ -16,7 +16,7 @@ function notNull<T>(value: T | null | undefined): value is T {
|
|
|
16
16
|
return value !== null && value !== undefined
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const fuse = computed(() => new Fuse(
|
|
19
|
+
const fuse = computed(() => new Fuse(slides.value.map(i => i.meta?.slide).filter(notNull), {
|
|
20
20
|
keys: ['no', 'title'],
|
|
21
21
|
threshold: 0.3,
|
|
22
22
|
shouldSort: true,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, ref, shallowRef } from 'vue'
|
|
3
3
|
import { isColorSchemaConfigured, isDark, toggleDark } from '../logic/dark'
|
|
4
|
-
import {
|
|
4
|
+
import { downloadPDF } from '../utils'
|
|
5
|
+
import { currentRoute, currentSlideNo, getSlidePath, hasNext, hasPrev, isEmbedded, isPresenter, isPresenterAvailable, next, prev, total } from '../logic/nav'
|
|
5
6
|
import { activeElement, breakpoints, fullscreen, presenterLayout, showEditor, showInfoDialog, showPresenterCursor, toggleOverview, togglePresenterLayout } from '../state'
|
|
6
7
|
import { brush, drawingEnabled } from '../logic/drawings'
|
|
7
8
|
import { configs } from '../env'
|
|
@@ -21,9 +22,10 @@ const props = defineProps({
|
|
|
21
22
|
const md = breakpoints.smaller('md')
|
|
22
23
|
const { isFullscreen, toggle: toggleFullscreen } = fullscreen
|
|
23
24
|
|
|
25
|
+
const presenterPassword = computed(() => currentRoute.value.query.password)
|
|
24
26
|
const query = computed(() => presenterPassword.value ? `?password=${presenterPassword.value}` : '')
|
|
25
|
-
const presenterLink = computed(() =>
|
|
26
|
-
const nonPresenterLink = computed(() =>
|
|
27
|
+
const presenterLink = computed(() => `${getSlidePath(currentSlideNo.value, true)}${query.value}`)
|
|
28
|
+
const nonPresenterLink = computed(() => `${getSlidePath(currentSlideNo.value, false)}${query.value}`)
|
|
27
29
|
|
|
28
30
|
const root = ref<HTMLDivElement>()
|
|
29
31
|
function onMouseLeave() {
|
|
@@ -107,7 +109,7 @@ if (__SLIDEV_FEATURE_DRAWINGS__)
|
|
|
107
109
|
<RouterLink v-if="isPresenter" :to="nonPresenterLink" class="slidev-icon-btn" title="Play Mode">
|
|
108
110
|
<carbon:presentation-file />
|
|
109
111
|
</RouterLink>
|
|
110
|
-
<RouterLink v-if="__SLIDEV_FEATURE_PRESENTER__ &&
|
|
112
|
+
<RouterLink v-if="__SLIDEV_FEATURE_PRESENTER__ && isPresenterAvailable" :to="presenterLink" class="slidev-icon-btn" title="Presenter Mode">
|
|
111
113
|
<carbon:user-speaker />
|
|
112
114
|
</RouterLink>
|
|
113
115
|
|
|
@@ -156,7 +158,7 @@ if (__SLIDEV_FEATURE_DRAWINGS__)
|
|
|
156
158
|
|
|
157
159
|
<div class="h-40px flex" p="l-1 t-0.5 r-2" text="sm leading-2">
|
|
158
160
|
<div class="my-auto">
|
|
159
|
-
{{
|
|
161
|
+
{{ currentSlideNo }}
|
|
160
162
|
<span class="opacity-50">/ {{ total }}</span>
|
|
161
163
|
</div>
|
|
162
164
|
</div>
|
package/internals/NoteStatic.vue
CHANGED
|
@@ -4,7 +4,7 @@ import { computed } from 'vue'
|
|
|
4
4
|
import { provideLocal } from '@vueuse/core'
|
|
5
5
|
import { configs, slideAspect, slideWidth } from '../env'
|
|
6
6
|
import { injectionSlideScale } from '../constants'
|
|
7
|
-
import {
|
|
7
|
+
import { currentRoute, slides } from '../logic/nav'
|
|
8
8
|
import PrintSlide from './PrintSlide.vue'
|
|
9
9
|
|
|
10
10
|
const props = defineProps<{
|
|
@@ -22,7 +22,8 @@ const scale = computed(() => {
|
|
|
22
22
|
return (height.value * slideAspect) / slideWidth
|
|
23
23
|
})
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
// In print mode, the routes will never change. So we don't need reactivity here.
|
|
26
|
+
let routes = slides.value
|
|
26
27
|
if (currentRoute.value.query.range) {
|
|
27
28
|
const r = parseRangeString(routes.length, currentRoute.value.query.range as string)
|
|
28
29
|
routes = r.map(i => routes[i - 1])
|
|
@@ -38,7 +39,7 @@ provideLocal(injectionSlideScale, scale)
|
|
|
38
39
|
<template>
|
|
39
40
|
<div id="print-container" :class="className">
|
|
40
41
|
<div id="print-content">
|
|
41
|
-
<PrintSlide v-for="route of routes" :key="route.
|
|
42
|
+
<PrintSlide v-for="route of routes" :key="route.no" :route="route" />
|
|
42
43
|
</div>
|
|
43
44
|
<slot name="controls" />
|
|
44
45
|
</div>
|
package/internals/PrintSlide.vue
CHANGED
|
@@ -1,30 +1,23 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type {
|
|
3
|
-
import {
|
|
4
|
-
import { useNav } from '../composables/useNav'
|
|
2
|
+
import type { SlideRoute } from '@slidev/types'
|
|
3
|
+
import { useFixedNav } from '../composables/useNav'
|
|
5
4
|
import { useFixedClicks } from '../composables/useClicks'
|
|
6
5
|
import PrintSlideClick from './PrintSlideClick.vue'
|
|
7
6
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const route = computed(() => props.route)
|
|
11
|
-
const nav = useNav(route)
|
|
12
|
-
const clicks0 = useFixedClicks(route.value, 0)
|
|
7
|
+
const { route } = defineProps<{ route: SlideRoute }>()
|
|
8
|
+
const clicks0 = useFixedClicks(route, 0)
|
|
13
9
|
</script>
|
|
14
10
|
|
|
15
11
|
<template>
|
|
16
12
|
<PrintSlideClick
|
|
17
13
|
:clicks-context="clicks0"
|
|
18
|
-
:nav="
|
|
19
|
-
:route="route"
|
|
14
|
+
:nav="useFixedNav(route, clicks0)"
|
|
20
15
|
/>
|
|
21
16
|
<template v-if="!clicks0.disabled">
|
|
22
17
|
<PrintSlideClick
|
|
23
18
|
v-for="i of clicks0.total"
|
|
24
19
|
:key="i"
|
|
25
|
-
:
|
|
26
|
-
:nav="nav"
|
|
27
|
-
:route="route"
|
|
20
|
+
:nav="useFixedNav(route, useFixedClicks(route, i))"
|
|
28
21
|
/>
|
|
29
22
|
</template>
|
|
30
23
|
</template>
|