@slidev/client 0.47.4 → 0.48.0-beta.0
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/CodeBlockWrapper.vue +38 -27
- package/builtin/KaTexBlockWrapper.vue +37 -26
- package/builtin/Mermaid.vue +18 -10
- package/builtin/SlidevVideo.vue +4 -7
- package/builtin/VClick.ts +16 -4
- package/builtin/VClickGap.vue +38 -0
- package/builtin/VClicks.ts +44 -47
- package/composables/useClicks.ts +83 -0
- package/composables/useContext.ts +2 -8
- package/composables/useNav.ts +5 -2
- package/constants.ts +2 -5
- package/internals/Editor.vue +1 -1
- package/internals/Presenter.vue +22 -27
- package/internals/PrintSlide.vue +10 -8
- package/internals/PrintSlideClick.vue +7 -16
- package/internals/SlideWrapper.ts +9 -42
- package/internals/SlidesOverview.vue +2 -1
- package/internals/SlidesShow.vue +3 -10
- package/logic/nav.ts +26 -28
- package/logic/note.ts +4 -0
- package/logic/utils.ts +18 -0
- package/modules/context.ts +5 -8
- package/modules/directives.ts +124 -167
- package/package.json +7 -7
- package/routes.ts +2 -1
- package/setup/codemirror.ts +3 -1
- package/setup/root.ts +5 -5
- package/composables/useNavClicks.ts +0 -38
package/composables/useNav.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { computed } from 'vue'
|
|
|
3
3
|
import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
|
|
4
4
|
import type { TocItem } from '@slidev/types'
|
|
5
5
|
import type { SlidevContextNav } from '../modules/context'
|
|
6
|
-
import { addToTree, downloadPDF, filterTree, getPath, getTreeWithActiveStatuses, go, next, nextSlide, openInEditor, prev, prevSlide } from '../logic/nav'
|
|
6
|
+
import { addToTree, clicks, clicksContext, clicksTotal, downloadPDF, filterTree, getPath, getTreeWithActiveStatuses, go, next, nextSlide, openInEditor, prev, prevSlide } from '../logic/nav'
|
|
7
7
|
import { rawRoutes } from '../routes'
|
|
8
8
|
|
|
9
9
|
export function useNav(route: ComputedRef<RouteRecordRaw | RouteLocationNormalizedLoaded>): SlidevContextNav {
|
|
@@ -12,7 +12,7 @@ export function useNav(route: ComputedRef<RouteRecordRaw | RouteLocationNormaliz
|
|
|
12
12
|
|
|
13
13
|
const currentPage = computed(() => Number.parseInt(path.value.split(/\//g).slice(-1)[0]) || 1)
|
|
14
14
|
const currentPath = computed(() => getPath(currentPage.value))
|
|
15
|
-
const currentRoute = computed(() => rawRoutes.find(i => i.path === `${currentPage.value}`))
|
|
15
|
+
const currentRoute = computed(() => rawRoutes.find(i => i.path === `${currentPage.value}`) ?? rawRoutes.at(-1) ?? rawRoutes[0])
|
|
16
16
|
const currentSlideId = computed(() => currentRoute.value?.meta?.slide?.id)
|
|
17
17
|
const currentLayout = computed(() => currentRoute.value?.meta?.layout || (currentPage.value === 1 ? 'cover' : 'default'))
|
|
18
18
|
|
|
@@ -32,6 +32,9 @@ export function useNav(route: ComputedRef<RouteRecordRaw | RouteLocationNormaliz
|
|
|
32
32
|
route,
|
|
33
33
|
path,
|
|
34
34
|
total,
|
|
35
|
+
clicksContext,
|
|
36
|
+
clicks,
|
|
37
|
+
clicksTotal,
|
|
35
38
|
currentPage,
|
|
36
39
|
currentPath,
|
|
37
40
|
currentRoute,
|
package/constants.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import type { ComputedRef, InjectionKey, Ref, UnwrapNestedRefs } from 'vue'
|
|
2
2
|
import type { RouteRecordRaw } from 'vue-router'
|
|
3
|
-
import type { RenderContext } from '@slidev/types'
|
|
3
|
+
import type { ClicksContext, RenderContext } from '@slidev/types'
|
|
4
4
|
import type { SlidevContext } from './modules/context'
|
|
5
5
|
|
|
6
|
-
export const
|
|
7
|
-
export const injectionClicksElements: InjectionKey<Ref<(Element | string)[]>> = Symbol('v-click-clicks-elements')
|
|
8
|
-
export const injectionClicksDisabled: InjectionKey<Ref<boolean>> = Symbol('v-click-clicks-disabled')
|
|
9
|
-
export const injectionOrderMap: InjectionKey<Ref<Map<number, HTMLElement[]>>> = Symbol('v-click-clicks-order-map')
|
|
6
|
+
export const injectionClicksContext: InjectionKey<Ref<ClicksContext>> = Symbol('slidev-clicks-context')
|
|
10
7
|
export const injectionCurrentPage: InjectionKey<Ref<number>> = Symbol('slidev-page')
|
|
11
8
|
export const injectionSlideScale: InjectionKey<ComputedRef<number>> = Symbol('slidev-slide-scale')
|
|
12
9
|
export const injectionSlidevContext: InjectionKey<UnwrapNestedRefs<SlidevContext>> = Symbol('slidev-slidev-context')
|
package/internals/Editor.vue
CHANGED
package/internals/Presenter.vue
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { useHead } from '@unhead/vue'
|
|
3
3
|
import { computed, onMounted, reactive, ref, shallowRef, watch } from 'vue'
|
|
4
4
|
import { useMouse, useWindowFocus } from '@vueuse/core'
|
|
5
|
-
import {
|
|
5
|
+
import { clicksContext, currentPage, currentRoute, hasNext, nextRoute, queryClicks, rawRoutes, total, useSwipeControls } from '../logic/nav'
|
|
6
6
|
import { decreasePresenterFontSize, increasePresenterFontSize, presenterLayout, presenterNotesFontSize, showEditor, showOverview, showPresenterCursor } from '../state'
|
|
7
7
|
import { configs, themeVars } from '../env'
|
|
8
8
|
import { sharedState } from '../state/shared'
|
|
@@ -10,6 +10,7 @@ import { registerShortcuts } from '../logic/shortcuts'
|
|
|
10
10
|
import { getSlideClass } from '../utils'
|
|
11
11
|
import { useTimer } from '../logic/utils'
|
|
12
12
|
import { isDrawing } from '../logic/drawings'
|
|
13
|
+
import { useFixedClicks } from '../composables/useClicks'
|
|
13
14
|
import SlideContainer from './SlideContainer.vue'
|
|
14
15
|
import NavControls from './NavControls.vue'
|
|
15
16
|
import SlidesOverview from './SlidesOverview.vue'
|
|
@@ -35,26 +36,21 @@ const notesEditing = ref(false)
|
|
|
35
36
|
|
|
36
37
|
const { timer, resetTimer } = useTimer()
|
|
37
38
|
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
if (
|
|
41
|
-
return
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
route: nextRoute.value,
|
|
50
|
-
clicks: 0,
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
return null
|
|
55
|
-
}
|
|
56
|
-
}
|
|
39
|
+
const clicksCtxMap = rawRoutes.map(route => useFixedClicks(route))
|
|
40
|
+
const nextFrame = computed(() => {
|
|
41
|
+
if (clicksContext.value.current < clicksContext.value.total)
|
|
42
|
+
return [currentRoute.value!, clicksContext.value.current + 1] as const
|
|
43
|
+
else if (hasNext.value)
|
|
44
|
+
return [nextRoute.value!, 0] as const
|
|
45
|
+
else
|
|
46
|
+
return null
|
|
47
|
+
})
|
|
48
|
+
const nextFrameClicksCtx = computed(() => {
|
|
49
|
+
return nextFrame.value && clicksCtxMap[+nextFrame.value[0].path - 1]
|
|
57
50
|
})
|
|
51
|
+
watch([currentRoute, queryClicks], () => {
|
|
52
|
+
nextFrameClicksCtx.value && (nextFrameClicksCtx.value[0].value = nextFrame.value![1])
|
|
53
|
+
}, { immediate: true })
|
|
58
54
|
|
|
59
55
|
const Editor = shallowRef<any>()
|
|
60
56
|
if (__DEV__ && __SLIDEV_FEATURE_EDITOR__)
|
|
@@ -120,17 +116,16 @@ onMounted(() => {
|
|
|
120
116
|
</div>
|
|
121
117
|
<div class="relative grid-section next flex flex-col p-2 lg:p-4" :style="themeVars">
|
|
122
118
|
<SlideContainer
|
|
123
|
-
v-if="
|
|
119
|
+
v-if="nextFrame && nextFrameClicksCtx"
|
|
124
120
|
key="next"
|
|
125
121
|
class="h-full w-full"
|
|
126
122
|
>
|
|
127
123
|
<SlideWrapper
|
|
128
|
-
:is="
|
|
129
|
-
|
|
130
|
-
:clicks="
|
|
131
|
-
:
|
|
132
|
-
:
|
|
133
|
-
:route="nextSlide.route"
|
|
124
|
+
:is="nextFrame[0].component as any"
|
|
125
|
+
:key="nextFrame[0].path"
|
|
126
|
+
:clicks-context="nextFrameClicksCtx[1]"
|
|
127
|
+
:class="getSlideClass(nextFrame[0])"
|
|
128
|
+
:route="nextFrame[0]"
|
|
134
129
|
render-context="previewNext"
|
|
135
130
|
/>
|
|
136
131
|
</SlideContainer>
|
package/internals/PrintSlide.vue
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { RouteRecordRaw } from 'vue-router'
|
|
3
|
-
import { computed
|
|
3
|
+
import { computed } from 'vue'
|
|
4
4
|
import { useNav } from '../composables/useNav'
|
|
5
|
-
import {
|
|
5
|
+
import { useFixedClicks } from '../composables/useClicks'
|
|
6
6
|
import PrintSlideClick from './PrintSlideClick.vue'
|
|
7
7
|
|
|
8
8
|
const props = defineProps<{ route: RouteRecordRaw }>()
|
|
9
9
|
|
|
10
|
-
const clicksElements = ref(props.route.meta?.__clicksElements || [])
|
|
11
|
-
const clicks = computed(() => props.route.meta?.clicks ?? clicksElements.value.length)
|
|
12
|
-
|
|
13
10
|
const route = computed(() => props.route)
|
|
14
11
|
const nav = useNav(route)
|
|
12
|
+
const clicks0 = useFixedClicks(route.value, 0)[1]
|
|
15
13
|
</script>
|
|
16
14
|
|
|
17
15
|
<template>
|
|
18
|
-
<PrintSlideClick
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
<PrintSlideClick
|
|
17
|
+
:clicks-context="clicks0"
|
|
18
|
+
:nav="nav"
|
|
19
|
+
:route="route"
|
|
20
|
+
/>
|
|
21
|
+
<template v-if="!clicks0.disabled">
|
|
22
|
+
<PrintSlideClick v-for="i of clicks0.total" :key="i" :clicks-context="useFixedClicks(route, i)[1]" :nav="nav" :route="route" />
|
|
21
23
|
</template>
|
|
22
24
|
</template>
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { RouteRecordRaw } from 'vue-router'
|
|
3
3
|
import { computed, provide, reactive, shallowRef } from 'vue'
|
|
4
|
-
import {
|
|
5
|
-
import { useNavClicks } from '../composables/useNavClicks'
|
|
4
|
+
import type { ClicksContext } from '@slidev/types'
|
|
6
5
|
import { injectionSlidevContext } from '../constants'
|
|
7
|
-
import { isClicksDisabled } from '../logic/nav'
|
|
8
6
|
import { configs, slideHeight, slideWidth } from '../env'
|
|
9
7
|
import { getSlideClass } from '../utils'
|
|
10
8
|
import type { SlidevContextNav } from '../modules/context'
|
|
@@ -17,16 +15,11 @@ import GlobalTop from '/@slidev/global-components/top'
|
|
|
17
15
|
import GlobalBottom from '/@slidev/global-components/bottom'
|
|
18
16
|
|
|
19
17
|
const props = defineProps<{
|
|
20
|
-
|
|
21
|
-
clicksElements?: HTMLElement[]
|
|
18
|
+
clicksContext: ClicksContext
|
|
22
19
|
nav: SlidevContextNav
|
|
23
20
|
route: RouteRecordRaw
|
|
24
21
|
}>()
|
|
25
22
|
|
|
26
|
-
const emit = defineEmits(['update:clicksElements'])
|
|
27
|
-
|
|
28
|
-
const clicksElements = useVModel(props, 'clicksElements', emit)
|
|
29
|
-
|
|
30
23
|
const style = computed(() => ({
|
|
31
24
|
height: `${slideHeight}px`,
|
|
32
25
|
width: `${slideWidth}px`,
|
|
@@ -36,12 +29,12 @@ const DrawingPreview = shallowRef<any>()
|
|
|
36
29
|
if (__SLIDEV_FEATURE_DRAWINGS__ || __SLIDEV_FEATURE_DRAWINGS_PERSIST__)
|
|
37
30
|
import('./DrawingPreview.vue').then(v => (DrawingPreview.value = v.default))
|
|
38
31
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
const id = computed(() =>
|
|
33
|
+
`${props.route.path.toString().padStart(3, '0')}-${(props.nav.clicks.value + 1).toString().padStart(2, '0')}`,
|
|
34
|
+
)
|
|
42
35
|
|
|
43
36
|
provide(injectionSlidevContext, reactive({
|
|
44
|
-
nav:
|
|
37
|
+
nav: props.nav,
|
|
45
38
|
configs,
|
|
46
39
|
themeConfigs: computed(() => configs.themeConfig),
|
|
47
40
|
}))
|
|
@@ -53,9 +46,7 @@ provide(injectionSlidevContext, reactive({
|
|
|
53
46
|
|
|
54
47
|
<SlideWrapper
|
|
55
48
|
:is="route?.component!"
|
|
56
|
-
|
|
57
|
-
:clicks="isClicksDisabled ? undefined : clicks"
|
|
58
|
-
:clicks-disabled="isClicksDisabled"
|
|
49
|
+
:clicks-context="clicksContext"
|
|
59
50
|
:class="getSlideClass(route)"
|
|
60
51
|
:route="route"
|
|
61
52
|
/>
|
|
@@ -1,26 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import type { RenderContext } from '@slidev/types'
|
|
4
|
-
import { injectionActive,
|
|
1
|
+
import { defineComponent, h, provide, ref, toRef } from 'vue'
|
|
2
|
+
import type { PropType } from 'vue'
|
|
3
|
+
import type { ClicksContext, RenderContext } from '@slidev/types'
|
|
4
|
+
import { injectionActive, injectionClicksContext, injectionCurrentPage, injectionRenderContext, injectionRoute } from '../constants'
|
|
5
5
|
|
|
6
6
|
export default defineComponent({
|
|
7
7
|
name: 'SlideWrapper',
|
|
8
8
|
props: {
|
|
9
|
-
|
|
10
|
-
type:
|
|
11
|
-
|
|
12
|
-
},
|
|
13
|
-
clicksElements: {
|
|
14
|
-
type: Array,
|
|
15
|
-
default: () => [] as Element[],
|
|
16
|
-
},
|
|
17
|
-
clicksOrderMap: {
|
|
18
|
-
type: Map,
|
|
19
|
-
default: () => new Map<number, HTMLElement[]>(),
|
|
20
|
-
},
|
|
21
|
-
clicksDisabled: {
|
|
22
|
-
type: Boolean,
|
|
23
|
-
default: false,
|
|
9
|
+
clicksContext: {
|
|
10
|
+
type: Object as PropType<ClicksContext>,
|
|
11
|
+
required: true,
|
|
24
12
|
},
|
|
25
13
|
renderContext: {
|
|
26
14
|
type: String,
|
|
@@ -39,33 +27,12 @@ export default defineComponent({
|
|
|
39
27
|
default: undefined,
|
|
40
28
|
},
|
|
41
29
|
},
|
|
42
|
-
setup(props
|
|
43
|
-
const clicks = useVModel(props, 'clicks', emit)
|
|
44
|
-
const clicksElements = useVModel(props, 'clicksElements', emit)
|
|
45
|
-
const clicksDisabled = useVModel(props, 'clicksDisabled', emit)
|
|
46
|
-
const clicksOrderMap = useVModel(props, 'clicksOrderMap', emit)
|
|
47
|
-
|
|
48
|
-
clicksElements.value.length = 0
|
|
49
|
-
|
|
50
|
-
const clicksWithDisable = computed({
|
|
51
|
-
get() {
|
|
52
|
-
if (clicksDisabled.value)
|
|
53
|
-
return 9999999
|
|
54
|
-
return +clicks.value
|
|
55
|
-
},
|
|
56
|
-
set(value) {
|
|
57
|
-
clicks.value = value
|
|
58
|
-
},
|
|
59
|
-
})
|
|
60
|
-
|
|
30
|
+
setup(props) {
|
|
61
31
|
provide(injectionRoute, props.route as any)
|
|
62
32
|
provide(injectionCurrentPage, ref(+props.route?.path))
|
|
63
33
|
provide(injectionRenderContext, ref(props.renderContext as RenderContext))
|
|
64
34
|
provide(injectionActive, toRef(props, 'active'))
|
|
65
|
-
provide(
|
|
66
|
-
provide(injectionClicksDisabled, clicksDisabled)
|
|
67
|
-
provide(injectionClicksElements, clicksElements as any)
|
|
68
|
-
provide(injectionOrderMap, clicksOrderMap as any)
|
|
35
|
+
provide(injectionClicksContext, toRef(props, 'clicksContext'))
|
|
69
36
|
},
|
|
70
37
|
render() {
|
|
71
38
|
if (this.$props.is)
|
|
@@ -5,6 +5,7 @@ import { themeVars } from '../env'
|
|
|
5
5
|
import { breakpoints, showOverview, windowSize } from '../state'
|
|
6
6
|
import { currentPage, go as goSlide, rawRoutes } from '../logic/nav'
|
|
7
7
|
import { currentOverviewPage, overviewRowCount } from '../logic/overview'
|
|
8
|
+
import { useFixedClicks } from '../composables/useClicks'
|
|
8
9
|
import { getSlideClass } from '../utils'
|
|
9
10
|
import SlideContainer from './SlideContainer.vue'
|
|
10
11
|
import SlideWrapper from './SlideWrapper'
|
|
@@ -138,7 +139,7 @@ watchEffect(() => {
|
|
|
138
139
|
<SlideWrapper
|
|
139
140
|
:is="route.component"
|
|
140
141
|
v-if="route?.component"
|
|
141
|
-
:clicks-
|
|
142
|
+
:clicks-context="useFixedClicks(route, 99999)[1]"
|
|
142
143
|
:class="getSlideClass(route)"
|
|
143
144
|
:route="route"
|
|
144
145
|
render-context="overview"
|
package/internals/SlidesShow.vue
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { TransitionGroup, computed, shallowRef, watch } from 'vue'
|
|
3
|
-
import {
|
|
3
|
+
import { currentRoute, isPresenter, nextRoute, rawRoutes, transition } from '../logic/nav'
|
|
4
4
|
import { getSlideClass } from '../utils'
|
|
5
5
|
import { useViewTransition } from '../composables/useViewTransition'
|
|
6
6
|
import { skipTransition } from '../composables/hmr'
|
|
7
|
+
import { usePrimaryClicks } from '../composables/useClicks'
|
|
7
8
|
import SlideWrapper from './SlideWrapper'
|
|
8
9
|
|
|
9
10
|
// @ts-expect-error virtual module
|
|
@@ -27,12 +28,6 @@ watch(currentRoute, () => {
|
|
|
27
28
|
|
|
28
29
|
const hasViewTransition = useViewTransition()
|
|
29
30
|
|
|
30
|
-
// preserve the clicks count for previous slide to avoid flash on transition
|
|
31
|
-
let previousClicks: [string | undefined, number] = [] as any
|
|
32
|
-
router.beforeEach(() => {
|
|
33
|
-
previousClicks = [currentRoute.value?.path, clicks.value]
|
|
34
|
-
})
|
|
35
|
-
|
|
36
31
|
const DrawingLayer = shallowRef<any>()
|
|
37
32
|
if (__SLIDEV_FEATURE_DRAWINGS__ || __SLIDEV_FEATURE_DRAWINGS_PERSIST__)
|
|
38
33
|
import('./DrawingLayer.vue').then(v => DrawingLayer.value = v.default)
|
|
@@ -62,9 +57,7 @@ function onAfterLeave() {
|
|
|
62
57
|
<SlideWrapper
|
|
63
58
|
:is="route?.component as any"
|
|
64
59
|
v-show="route === currentRoute"
|
|
65
|
-
:clicks="route
|
|
66
|
-
:clicks-elements="route.meta?.__clicksElements || []"
|
|
67
|
-
:clicks-disabled="false"
|
|
60
|
+
:clicks-context="usePrimaryClicks(route)"
|
|
68
61
|
:class="getSlideClass(route)"
|
|
69
62
|
:route="route"
|
|
70
63
|
:render-context="renderContext"
|
package/logic/nav.ts
CHANGED
|
@@ -6,19 +6,21 @@ import { timestamp, usePointerSwipe } from '@vueuse/core'
|
|
|
6
6
|
import { rawRoutes, router } from '../routes'
|
|
7
7
|
import { configs } from '../env'
|
|
8
8
|
import { skipTransition } from '../composables/hmr'
|
|
9
|
+
import { usePrimaryClicks } from '../composables/useClicks'
|
|
9
10
|
import { useRouteQuery } from './route'
|
|
10
11
|
import { isDrawing } from './drawings'
|
|
11
12
|
|
|
12
13
|
export { rawRoutes, router }
|
|
13
14
|
|
|
14
15
|
// force update collected elements when the route is fully resolved
|
|
15
|
-
const routeForceRefresh = ref(0)
|
|
16
|
+
export const routeForceRefresh = ref(0)
|
|
16
17
|
nextTick(() => {
|
|
17
18
|
router.afterEach(async () => {
|
|
18
19
|
await nextTick()
|
|
19
20
|
routeForceRefresh.value += 1
|
|
20
21
|
})
|
|
21
22
|
})
|
|
23
|
+
|
|
22
24
|
export const navDirection = ref(0)
|
|
23
25
|
|
|
24
26
|
export const route = computed(() => router.currentRoute.value)
|
|
@@ -28,11 +30,25 @@ export const isPrintWithClicks = computed(() => route.value.query.print === 'cli
|
|
|
28
30
|
export const isEmbedded = computed(() => route.value.query.embedded !== undefined)
|
|
29
31
|
export const isPresenter = computed(() => route.value.path.startsWith('/presenter'))
|
|
30
32
|
export const isNotesViewer = computed(() => route.value.path.startsWith('/notes'))
|
|
31
|
-
export const isClicksDisabled = computed(() => isPrintMode.value && !isPrintWithClicks.value)
|
|
32
33
|
export const presenterPassword = computed(() => route.value.query.password)
|
|
33
34
|
export const showPresenter = computed(() => !isPresenter.value && (!configs.remote || presenterPassword.value === configs.remote))
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
const queryClicksRaw = useRouteQuery('clicks', '0')
|
|
37
|
+
export const queryClicks = computed({
|
|
38
|
+
get() {
|
|
39
|
+
// eslint-disable-next-line ts/no-use-before-define
|
|
40
|
+
if (clicksContext.value.disabled)
|
|
41
|
+
return 99999
|
|
42
|
+
let v = +(queryClicksRaw.value || 0)
|
|
43
|
+
if (Number.isNaN(v))
|
|
44
|
+
v = 0
|
|
45
|
+
return v
|
|
46
|
+
},
|
|
47
|
+
set(v) {
|
|
48
|
+
queryClicksRaw.value = v.toString()
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
|
|
36
52
|
export const total = computed(() => rawRoutes.length)
|
|
37
53
|
export const path = computed(() => route.value.path)
|
|
38
54
|
|
|
@@ -45,27 +61,9 @@ export const currentLayout = computed(() => currentRoute.value?.meta?.layout ||
|
|
|
45
61
|
export const nextRoute = computed(() => rawRoutes.find(i => i.path === `${Math.min(rawRoutes.length, currentPage.value + 1)}`))
|
|
46
62
|
export const prevRoute = computed(() => rawRoutes.find(i => i.path === `${Math.max(1, currentPage.value - 1)}`))
|
|
47
63
|
|
|
48
|
-
export const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return currentRoute.value?.meta?.__clicksElements || []
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
export const clicks = computed<number>({
|
|
55
|
-
get() {
|
|
56
|
-
if (isClicksDisabled.value)
|
|
57
|
-
return 99999
|
|
58
|
-
let clicks = +(queryClicks.value || 0)
|
|
59
|
-
if (Number.isNaN(clicks))
|
|
60
|
-
clicks = 0
|
|
61
|
-
return clicks
|
|
62
|
-
},
|
|
63
|
-
set(v) {
|
|
64
|
-
queryClicks.value = v.toString()
|
|
65
|
-
},
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
export const clicksTotal = computed(() => +(currentRoute.value?.meta?.clicks ?? clicksElements.value.length))
|
|
64
|
+
export const clicksContext = computed(() => usePrimaryClicks(currentRoute.value))
|
|
65
|
+
export const clicks = computed(() => clicksContext.value.current)
|
|
66
|
+
export const clicksTotal = computed(() => clicksContext.value.total)
|
|
69
67
|
|
|
70
68
|
export const hasNext = computed(() => currentPage.value < rawRoutes.length || clicks.value < clicksTotal.value)
|
|
71
69
|
export const hasPrev = computed(() => currentPage.value > 1 || clicks.value > 0)
|
|
@@ -86,17 +84,17 @@ watch(currentRoute, (next, prev) => {
|
|
|
86
84
|
})
|
|
87
85
|
|
|
88
86
|
export function next() {
|
|
89
|
-
if (clicksTotal.value <=
|
|
87
|
+
if (clicksTotal.value <= queryClicks.value)
|
|
90
88
|
nextSlide()
|
|
91
89
|
else
|
|
92
|
-
|
|
90
|
+
queryClicks.value += 1
|
|
93
91
|
}
|
|
94
92
|
|
|
95
93
|
export async function prev() {
|
|
96
|
-
if (
|
|
94
|
+
if (queryClicks.value <= 0)
|
|
97
95
|
await prevSlide()
|
|
98
96
|
else
|
|
99
|
-
|
|
97
|
+
queryClicks.value -= 1
|
|
100
98
|
}
|
|
101
99
|
|
|
102
100
|
export function getPath(no: number | string) {
|
package/logic/note.ts
CHANGED
|
@@ -40,6 +40,10 @@ export function useSlideInfo(id: number | undefined): UseSlideInfo {
|
|
|
40
40
|
if (payload.id === id)
|
|
41
41
|
info.value = payload.data
|
|
42
42
|
})
|
|
43
|
+
import.meta.hot?.on('slidev-update-note', (payload) => {
|
|
44
|
+
if (payload.id === id && info.value.note.trim() !== payload.note.trim())
|
|
45
|
+
info.value = { ...info.value, ...payload }
|
|
46
|
+
})
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
return {
|
package/logic/utils.ts
CHANGED
|
@@ -30,3 +30,21 @@ export function makeId(length = 5) {
|
|
|
30
30
|
result.push(characters.charAt(Math.floor(Math.random() * charactersLength)))
|
|
31
31
|
return result.join('')
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* '+3' => '+3'
|
|
36
|
+
* '-3' => '-3'
|
|
37
|
+
* '3' => 3
|
|
38
|
+
* 3 => 3
|
|
39
|
+
*/
|
|
40
|
+
export function normalizeAtProp(at: string | number = '+1'): [isRelative: boolean, value: number] {
|
|
41
|
+
let n = +at
|
|
42
|
+
if (Number.isNaN(n)) {
|
|
43
|
+
console.warn('[slidev] Invalid click position:', at)
|
|
44
|
+
n = 0
|
|
45
|
+
}
|
|
46
|
+
return [
|
|
47
|
+
typeof at === 'string' && '+-'.includes(at[0]),
|
|
48
|
+
n,
|
|
49
|
+
]
|
|
50
|
+
}
|
package/modules/context.ts
CHANGED
|
@@ -4,21 +4,19 @@ import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
|
|
|
4
4
|
import type { ComputedRef } from '@vue/reactivity'
|
|
5
5
|
import type { configs } from '../env'
|
|
6
6
|
import * as nav from '../logic/nav'
|
|
7
|
-
import {
|
|
7
|
+
import { route } from '../logic/nav'
|
|
8
8
|
import { isDark } from '../logic/dark'
|
|
9
|
-
import {
|
|
9
|
+
import { injectionCurrentPage, injectionSlidevContext } from '../constants'
|
|
10
10
|
import { useContext } from '../composables/useContext'
|
|
11
11
|
|
|
12
|
-
export type SlidevContextNavKey = 'path' | 'total' | 'currentPage' | 'currentPath' | 'currentRoute' | 'currentSlideId' | 'currentLayout' | 'nextRoute' | 'rawTree' | 'treeWithActiveStatuses' | 'tree' | 'downloadPDF' | 'next' | 'nextSlide' | 'openInEditor' | 'prev' | 'prevSlide' | 'rawRoutes' | 'go'
|
|
13
|
-
export type SlidevContextNavClicksKey = 'clicks' | 'clicksElements' | 'clicksTotal' | 'hasNext' | 'hasPrev'
|
|
12
|
+
export type SlidevContextNavKey = 'path' | 'total' | 'clicksContext' | 'clicks' | 'clicksTotal' | 'currentPage' | 'currentPath' | 'currentRoute' | 'currentSlideId' | 'currentLayout' | 'nextRoute' | 'rawTree' | 'treeWithActiveStatuses' | 'tree' | 'downloadPDF' | 'next' | 'nextSlide' | 'openInEditor' | 'prev' | 'prevSlide' | 'rawRoutes' | 'go'
|
|
14
13
|
|
|
15
14
|
export interface SlidevContextNav extends Pick<typeof nav, SlidevContextNavKey> {
|
|
16
15
|
route: ComputedRef<RouteRecordRaw | RouteLocationNormalizedLoaded>
|
|
17
16
|
}
|
|
18
|
-
export type SlidevContextNavClicks = Pick<typeof nav, SlidevContextNavClicksKey>
|
|
19
17
|
|
|
20
18
|
export interface SlidevContext {
|
|
21
|
-
nav: SlidevContextNav
|
|
19
|
+
nav: SlidevContextNav
|
|
22
20
|
configs: typeof configs
|
|
23
21
|
themeConfigs: ComputedRef<typeof configs['themeConfig']>
|
|
24
22
|
}
|
|
@@ -26,10 +24,9 @@ export interface SlidevContext {
|
|
|
26
24
|
export default function createSlidevContext() {
|
|
27
25
|
return {
|
|
28
26
|
install(app: App) {
|
|
29
|
-
const context = reactive(useContext(route
|
|
27
|
+
const context = reactive(useContext(route))
|
|
30
28
|
app.provide(injectionSlidevContext, context)
|
|
31
29
|
app.provide(injectionCurrentPage, computed(() => context.nav.currentPage))
|
|
32
|
-
app.provide(injectionClicks, computed(() => context.nav.clicks))
|
|
33
30
|
|
|
34
31
|
// allows controls from postMessages
|
|
35
32
|
if (__DEV__) {
|