@slidev/client 0.48.0-beta.1 → 0.48.0-beta.11
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 +4 -3
- package/builtin/KaTexBlockWrapper.vue +4 -3
- package/builtin/RenderWhen.vue +3 -3
- package/builtin/SlideCurrentNo.vue +2 -3
- package/builtin/SlidesTotal.vue +3 -4
- package/builtin/SlidevVideo.vue +8 -6
- package/builtin/Toc.vue +3 -3
- package/builtin/TocList.vue +3 -2
- package/builtin/Tweet.vue +4 -15
- package/builtin/VClickGap.vue +3 -5
- package/builtin/VClicks.ts +1 -1
- package/composables/useClicks.ts +19 -13
- package/composables/useTweetScript.ts +17 -0
- package/constants.ts +56 -8
- package/context.ts +70 -0
- package/env.ts +3 -12
- package/internals/DrawingControls.vue +39 -9
- package/internals/DrawingLayer.vue +3 -2
- package/internals/Editor.vue +7 -3
- package/internals/Goto.vue +5 -4
- package/internals/IconButton.vue +4 -3
- package/internals/InfoDialog.vue +1 -1
- package/internals/Modal.vue +1 -1
- package/internals/NavControls.vue +2 -3
- package/internals/NoteDisplay.vue +1 -1
- package/internals/NoteEditor.vue +36 -8
- package/internals/NoteStatic.vue +5 -6
- package/internals/PrintContainer.vue +3 -2
- package/internals/PrintSlideClick.vue +5 -7
- package/internals/RecordingDialog.vue +5 -6
- package/internals/SlideContainer.vue +12 -9
- package/internals/SlideWrapper.ts +28 -12
- package/internals/SlidesOverview.vue +18 -7
- package/internals/SlidesShow.vue +7 -8
- package/layouts/two-cols-header.vue +9 -3
- package/logic/drawings.ts +6 -3
- package/logic/nav.ts +6 -1
- package/logic/note.ts +7 -7
- package/main.ts +8 -4
- package/modules/context.ts +4 -3
- package/modules/{directives.ts → v-click.ts} +15 -15
- package/modules/v-mark.ts +159 -0
- package/package.json +21 -13
- package/{internals/EntrySelect.vue → pages/entry.vue} +7 -0
- package/{internals/NotesView.vue → pages/notes.vue} +3 -3
- package/pages/overview.vue +201 -0
- package/{internals/Play.vue → pages/play.vue} +7 -7
- package/{internals/PresenterPrint.vue → pages/presenter/print.vue} +7 -5
- package/{internals/Presenter.vue → pages/presenter.vue} +64 -58
- package/{internals/Print.vue → pages/print.vue} +2 -2
- package/routes.ts +27 -51
- package/setup/codemirror.ts +7 -0
- package/shim-vue.d.ts +35 -0
- package/shim.d.ts +0 -12
- package/state/index.ts +10 -10
- package/styles/code.css +7 -3
- package/styles/index.css +18 -6
- package/styles/katex.css +1 -1
- package/styles/layouts-base.css +17 -12
- package/styles/vars.css +1 -0
- package/uno.config.ts +14 -2
package/internals/IconButton.vue
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { defineProps } from 'vue'
|
|
3
|
-
|
|
4
2
|
defineProps<{
|
|
5
3
|
title: string
|
|
4
|
+
icon?: string
|
|
6
5
|
}>()
|
|
7
6
|
</script>
|
|
8
7
|
|
|
9
8
|
<template>
|
|
10
9
|
<button class="slidev-icon-btn" :title="title" v-bind="$attrs">
|
|
11
10
|
<span class="sr-only">{{ title }}</span>
|
|
12
|
-
<slot
|
|
11
|
+
<slot>
|
|
12
|
+
<div :class="icon" />
|
|
13
|
+
</slot>
|
|
13
14
|
</button>
|
|
14
15
|
</template>
|
package/internals/InfoDialog.vue
CHANGED
|
@@ -10,7 +10,7 @@ const props = defineProps({
|
|
|
10
10
|
},
|
|
11
11
|
})
|
|
12
12
|
|
|
13
|
-
const emit = defineEmits
|
|
13
|
+
const emit = defineEmits(['update:modelValue'])
|
|
14
14
|
const value = useVModel(props, 'modelValue', emit)
|
|
15
15
|
const hasInfo = computed(() => typeof configs.info === 'string')
|
|
16
16
|
</script>
|
package/internals/Modal.vue
CHANGED
|
@@ -10,8 +10,7 @@ import MenuButton from './MenuButton.vue'
|
|
|
10
10
|
import VerticalDivider from './VerticalDivider.vue'
|
|
11
11
|
import IconButton from './IconButton.vue'
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
import CustomNavControls from '/@slidev/custom-nav-controls'
|
|
13
|
+
import CustomNavControls from '#slidev/custom-nav-controls'
|
|
15
14
|
|
|
16
15
|
const props = defineProps({
|
|
17
16
|
persist: {
|
|
@@ -34,7 +33,7 @@ function onMouseLeave() {
|
|
|
34
33
|
|
|
35
34
|
const barStyle = computed(() => props.persist
|
|
36
35
|
? 'text-$slidev-controls-foreground bg-transparent'
|
|
37
|
-
: 'rounded-md bg-main shadow dark:border dark:border-
|
|
36
|
+
: 'rounded-md bg-main shadow dark:border dark:border-main')
|
|
38
37
|
|
|
39
38
|
const RecordingControls = shallowRef<any>()
|
|
40
39
|
if (__SLIDEV_FEATURE_RECORD__)
|
package/internals/NoteEditor.vue
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { nextTick, ref, watch, watchEffect } from 'vue'
|
|
2
3
|
import { ignorableWatch, onClickOutside, useVModel } from '@vueuse/core'
|
|
3
|
-
import { ref, watch, watchEffect } from 'vue'
|
|
4
|
-
import { currentSlideId } from '../logic/nav'
|
|
5
4
|
import { useDynamicSlideInfo } from '../logic/note'
|
|
6
5
|
import NoteDisplay from './NoteDisplay.vue'
|
|
7
6
|
|
|
8
7
|
const props = defineProps({
|
|
8
|
+
no: {
|
|
9
|
+
type: Number,
|
|
10
|
+
},
|
|
9
11
|
class: {
|
|
10
12
|
default: '',
|
|
11
13
|
},
|
|
@@ -18,6 +20,9 @@ const props = defineProps({
|
|
|
18
20
|
placeholder: {
|
|
19
21
|
default: 'No notes for this slide',
|
|
20
22
|
},
|
|
23
|
+
autoHeight: {
|
|
24
|
+
default: false,
|
|
25
|
+
},
|
|
21
26
|
})
|
|
22
27
|
|
|
23
28
|
const emit = defineEmits([
|
|
@@ -25,7 +30,7 @@ const emit = defineEmits([
|
|
|
25
30
|
])
|
|
26
31
|
const editing = useVModel(props, 'editing', emit, { passive: true })
|
|
27
32
|
|
|
28
|
-
const { info, update } = useDynamicSlideInfo(
|
|
33
|
+
const { info, update } = useDynamicSlideInfo(props.no)
|
|
29
34
|
|
|
30
35
|
const note = ref('')
|
|
31
36
|
let timer: any
|
|
@@ -33,10 +38,10 @@ let timer: any
|
|
|
33
38
|
const { ignoreUpdates } = ignorableWatch(
|
|
34
39
|
note,
|
|
35
40
|
(v) => {
|
|
36
|
-
const id =
|
|
41
|
+
const id = props.no
|
|
37
42
|
clearTimeout(timer)
|
|
38
43
|
timer = setTimeout(() => {
|
|
39
|
-
update({
|
|
44
|
+
update({ note: v }, id)
|
|
40
45
|
}, 500)
|
|
41
46
|
},
|
|
42
47
|
)
|
|
@@ -44,6 +49,8 @@ const { ignoreUpdates } = ignorableWatch(
|
|
|
44
49
|
watch(
|
|
45
50
|
info,
|
|
46
51
|
(v) => {
|
|
52
|
+
if (editing.value)
|
|
53
|
+
return
|
|
47
54
|
clearTimeout(timer)
|
|
48
55
|
ignoreUpdates(() => {
|
|
49
56
|
note.value = v?.note || ''
|
|
@@ -62,13 +69,34 @@ watchEffect(() => {
|
|
|
62
69
|
onClickOutside(input, () => {
|
|
63
70
|
editing.value = false
|
|
64
71
|
})
|
|
72
|
+
|
|
73
|
+
function calculateHeight() {
|
|
74
|
+
if (!props.autoHeight || !input.value || !editing.value)
|
|
75
|
+
return
|
|
76
|
+
if (input.value.scrollHeight > input.value.clientHeight)
|
|
77
|
+
input.value.style.height = `${input.value.scrollHeight}px`
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const inputHeight = ref<number | null>()
|
|
81
|
+
watchEffect(() => {
|
|
82
|
+
calculateHeight()
|
|
83
|
+
})
|
|
84
|
+
watch(
|
|
85
|
+
note,
|
|
86
|
+
() => {
|
|
87
|
+
nextTick(() => {
|
|
88
|
+
calculateHeight()
|
|
89
|
+
})
|
|
90
|
+
},
|
|
91
|
+
{ flush: 'post' },
|
|
92
|
+
)
|
|
65
93
|
</script>
|
|
66
94
|
|
|
67
95
|
<template>
|
|
68
96
|
<NoteDisplay
|
|
69
97
|
v-if="!editing"
|
|
70
98
|
class="my--4 border-transparent border-2"
|
|
71
|
-
:class="[props.class, note ? '' : 'opacity-
|
|
99
|
+
:class="[props.class, note ? '' : 'opacity-25 italic select-none']"
|
|
72
100
|
:style="props.style"
|
|
73
101
|
:note="note || placeholder"
|
|
74
102
|
:note-html="info?.noteHTML"
|
|
@@ -77,9 +105,9 @@ onClickOutside(input, () => {
|
|
|
77
105
|
v-else
|
|
78
106
|
ref="input"
|
|
79
107
|
v-model="note"
|
|
80
|
-
class="prose resize-none overflow-auto outline-none bg-transparent block border-
|
|
108
|
+
class="prose resize-none overflow-auto outline-none bg-transparent block border-primary border-2"
|
|
81
109
|
style="line-height: 1.75;"
|
|
82
|
-
:style="props.style"
|
|
110
|
+
:style="[props.style, inputHeight != null ? { height: `${inputHeight}px` } : {}]"
|
|
83
111
|
:class="props.class"
|
|
84
112
|
:placeholder="placeholder"
|
|
85
113
|
@keydown.esc=" editing = false"
|
package/internals/NoteStatic.vue
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import { currentRoute } from '../logic/nav'
|
|
2
|
+
import { useSlideInfo } from '../logic/note'
|
|
4
3
|
import NoteDisplay from './NoteDisplay.vue'
|
|
5
4
|
|
|
6
5
|
const props = defineProps<{
|
|
6
|
+
no?: number
|
|
7
7
|
class?: string
|
|
8
8
|
}>()
|
|
9
9
|
|
|
10
|
-
const
|
|
11
|
-
const noteHtml = computed(() => currentRoute.value?.meta?.slide?.noteHTML)
|
|
10
|
+
const { info } = useSlideInfo(props.no)
|
|
12
11
|
</script>
|
|
13
12
|
|
|
14
13
|
<template>
|
|
15
14
|
<NoteDisplay
|
|
16
15
|
:class="props.class"
|
|
17
|
-
:note="note"
|
|
18
|
-
:note-html="
|
|
16
|
+
:note="info?.note"
|
|
17
|
+
:note-html="info?.noteHTML"
|
|
19
18
|
/>
|
|
20
19
|
</template>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { parseRangeString } from '@slidev/parser/core'
|
|
3
|
-
import { computed
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import { provideLocal } from '@vueuse/core'
|
|
4
5
|
import { configs, slideAspect, slideWidth } from '../env'
|
|
5
6
|
import { injectionSlideScale } from '../constants'
|
|
6
7
|
import { route as currentRoute, rawRoutes } from '../logic/nav'
|
|
@@ -31,7 +32,7 @@ const className = computed(() => ({
|
|
|
31
32
|
'select-none': !configs.selectable,
|
|
32
33
|
}))
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
provideLocal(injectionSlideScale, scale)
|
|
35
36
|
</script>
|
|
36
37
|
|
|
37
38
|
<template>
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { RouteRecordRaw } from 'vue-router'
|
|
3
|
-
import { computed,
|
|
3
|
+
import { computed, reactive, shallowRef } from 'vue'
|
|
4
4
|
import type { ClicksContext } from '@slidev/types'
|
|
5
|
+
import { provideLocal } from '@vueuse/core'
|
|
5
6
|
import { injectionSlidevContext } from '../constants'
|
|
6
7
|
import { configs, slideHeight, slideWidth } from '../env'
|
|
7
8
|
import { getSlideClass } from '../utils'
|
|
8
9
|
import type { SlidevContextNav } from '../modules/context'
|
|
9
10
|
import SlideWrapper from './SlideWrapper'
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
// @ts-expect-error virtual module
|
|
15
|
-
import GlobalBottom from '/@slidev/global-components/bottom'
|
|
12
|
+
import GlobalTop from '#slidev/global-components/top'
|
|
13
|
+
import GlobalBottom from '#slidev/global-components/bottom'
|
|
16
14
|
|
|
17
15
|
const props = defineProps<{
|
|
18
16
|
clicksContext: ClicksContext
|
|
@@ -33,7 +31,7 @@ const id = computed(() =>
|
|
|
33
31
|
`${props.route.path.toString().padStart(3, '0')}-${(props.nav.clicks.value + 1).toString().padStart(2, '0')}`,
|
|
34
32
|
)
|
|
35
33
|
|
|
36
|
-
|
|
34
|
+
provideLocal(injectionSlidevContext, reactive({
|
|
37
35
|
nav: props.nav,
|
|
38
36
|
configs,
|
|
39
37
|
themeConfigs: computed(() => configs.themeConfig),
|
|
@@ -108,19 +108,18 @@ async function start() {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
input[type=
|
|
112
|
-
@apply border border-
|
|
111
|
+
input[type='text'] {
|
|
112
|
+
@apply border border-main rounded px-2 py-1;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
button {
|
|
116
116
|
@apply bg-orange-400 text-white px-4 py-1 rounded border-b-2 border-orange-600;
|
|
117
|
-
@apply hover:(bg-orange-500 border-orange-700)
|
|
117
|
+
@apply hover:(bg-orange-500 border-orange-700);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
button.cancel {
|
|
121
|
-
@apply bg-gray-400 text-white px-4 py-1 rounded border-b-2 border-
|
|
122
|
-
@apply bg-opacity-
|
|
123
|
-
@apply hover:(bg-opacity-75 border-opacity-75)
|
|
121
|
+
@apply bg-gray-400 bg-opacity-50 text-white px-4 py-1 rounded border-b-2 border-main;
|
|
122
|
+
@apply hover:(bg-opacity-75 border-opacity-75);
|
|
124
123
|
}
|
|
125
124
|
}
|
|
126
125
|
</style>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { useElementSize, useStyleTag } from '@vueuse/core'
|
|
3
|
-
import { computed,
|
|
2
|
+
import { provideLocal, useElementSize, useStyleTag } from '@vueuse/core'
|
|
3
|
+
import { computed, ref, watchEffect } from 'vue'
|
|
4
4
|
import { configs, slideAspect, slideHeight, slideWidth } from '../env'
|
|
5
5
|
import { injectionSlideScale } from '../constants'
|
|
6
|
-
import { isPrintMode } from '../logic/nav'
|
|
6
|
+
import { clicksDirection, isPrintMode } from '../logic/nav'
|
|
7
7
|
|
|
8
8
|
const props = defineProps({
|
|
9
9
|
width: {
|
|
@@ -47,13 +47,16 @@ const scale = computed(() => {
|
|
|
47
47
|
})
|
|
48
48
|
|
|
49
49
|
const style = computed(() => ({
|
|
50
|
-
height: `${slideHeight}px`,
|
|
51
|
-
width: `${slideWidth}px`,
|
|
52
|
-
transform: `translate(-50%, -50%) scale(${scale.value})`,
|
|
50
|
+
'height': `${slideHeight}px`,
|
|
51
|
+
'width': `${slideWidth}px`,
|
|
52
|
+
'transform': `translate(-50%, -50%) scale(${scale.value})`,
|
|
53
|
+
'--slidev-slide-scale': scale.value,
|
|
53
54
|
}))
|
|
54
55
|
|
|
55
56
|
const className = computed(() => ({
|
|
56
57
|
'select-none': !configs.selectable,
|
|
58
|
+
'slidev-nav-go-forward': clicksDirection.value > 0,
|
|
59
|
+
'slidev-nav-go-backward': clicksDirection.value < 0,
|
|
57
60
|
}))
|
|
58
61
|
|
|
59
62
|
if (props.isMain) {
|
|
@@ -64,12 +67,12 @@ if (props.isMain) {
|
|
|
64
67
|
`))
|
|
65
68
|
}
|
|
66
69
|
|
|
67
|
-
|
|
70
|
+
provideLocal(injectionSlideScale, scale as any)
|
|
68
71
|
</script>
|
|
69
72
|
|
|
70
73
|
<template>
|
|
71
|
-
<div id="slide-container" ref="root" :class="className">
|
|
72
|
-
<div id="slide-content" :style="style">
|
|
74
|
+
<div id="slide-container" ref="root" class="slidev-slides-container" :class="className">
|
|
75
|
+
<div id="slide-content" class="slidev-slide-content" :style="style">
|
|
73
76
|
<slot />
|
|
74
77
|
</div>
|
|
75
78
|
<slot name="controls" />
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { defineComponent, h,
|
|
1
|
+
import { computed, defineComponent, h, ref, toRef } from 'vue'
|
|
2
2
|
import type { PropType } from 'vue'
|
|
3
|
+
import { provideLocal } from '@vueuse/core'
|
|
3
4
|
import type { ClicksContext, RenderContext } from '@slidev/types'
|
|
5
|
+
import type { RouteRecordRaw } from 'vue-router'
|
|
4
6
|
import { injectionActive, injectionClicksContext, injectionCurrentPage, injectionRenderContext, injectionRoute } from '../constants'
|
|
5
7
|
|
|
6
8
|
export default defineComponent({
|
|
@@ -20,23 +22,37 @@ export default defineComponent({
|
|
|
20
22
|
},
|
|
21
23
|
is: {
|
|
22
24
|
type: Object,
|
|
23
|
-
|
|
25
|
+
required: true,
|
|
24
26
|
},
|
|
25
27
|
route: {
|
|
26
|
-
type: Object
|
|
27
|
-
|
|
28
|
+
type: Object as PropType<RouteRecordRaw>,
|
|
29
|
+
required: true,
|
|
28
30
|
},
|
|
29
31
|
},
|
|
30
32
|
setup(props) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
provideLocal(injectionRoute, props.route)
|
|
34
|
+
provideLocal(injectionCurrentPage, ref(+props.route.path))
|
|
35
|
+
provideLocal(injectionRenderContext, ref(props.renderContext as RenderContext))
|
|
36
|
+
provideLocal(injectionActive, toRef(props, 'active'))
|
|
37
|
+
provideLocal(injectionClicksContext, toRef(props, 'clicksContext'))
|
|
38
|
+
|
|
39
|
+
const style = computed(() => {
|
|
40
|
+
const zoom = props.route.meta?.slide?.frontmatter.zoom ?? 1
|
|
41
|
+
return zoom === 1
|
|
42
|
+
? undefined
|
|
43
|
+
: {
|
|
44
|
+
width: `${100 / zoom}%`,
|
|
45
|
+
height: `${100 / zoom}%`,
|
|
46
|
+
transformOrigin: 'top left',
|
|
47
|
+
transform: `scale(${zoom})`,
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
style,
|
|
53
|
+
}
|
|
36
54
|
},
|
|
37
55
|
render() {
|
|
38
|
-
|
|
39
|
-
return h(this.$props.is)
|
|
40
|
-
return this.$slots?.default?.()
|
|
56
|
+
return h(this.$props.is, { style: this.style })
|
|
41
57
|
},
|
|
42
58
|
})
|
|
@@ -14,7 +14,7 @@ import IconButton from './IconButton.vue'
|
|
|
14
14
|
|
|
15
15
|
const props = defineProps<{ modelValue: boolean }>()
|
|
16
16
|
|
|
17
|
-
const emit = defineEmits([])
|
|
17
|
+
const emit = defineEmits(['update:modelValue'])
|
|
18
18
|
const value = useVModel(props, 'modelValue', emit)
|
|
19
19
|
|
|
20
20
|
function close() {
|
|
@@ -112,7 +112,7 @@ watchEffect(() => {
|
|
|
112
112
|
>
|
|
113
113
|
<div
|
|
114
114
|
v-show="value"
|
|
115
|
-
class="bg-main !bg-opacity-75 p-16 overflow-y-auto backdrop-blur-5px fixed left-0 right-0 top-0 h-[calc(var(--vh,1vh)*100)]"
|
|
115
|
+
class="bg-main !bg-opacity-75 p-16 py-20 overflow-y-auto backdrop-blur-5px fixed left-0 right-0 top-0 h-[calc(var(--vh,1vh)*100)]"
|
|
116
116
|
@click="close()"
|
|
117
117
|
>
|
|
118
118
|
<div
|
|
@@ -125,8 +125,8 @@ watchEffect(() => {
|
|
|
125
125
|
class="relative"
|
|
126
126
|
>
|
|
127
127
|
<div
|
|
128
|
-
class="inline-block border rounded
|
|
129
|
-
:class="(focus(idx + 1) || currentOverviewPage === idx + 1) ? 'border
|
|
128
|
+
class="inline-block border rounded overflow-hidden bg-main hover:border-primary transition"
|
|
129
|
+
:class="(focus(idx + 1) || currentOverviewPage === idx + 1) ? 'border-primary' : 'border-main'"
|
|
130
130
|
:style="themeVars"
|
|
131
131
|
@click="go(+route.path)"
|
|
132
132
|
>
|
|
@@ -163,7 +163,18 @@ watchEffect(() => {
|
|
|
163
163
|
</div>
|
|
164
164
|
</div>
|
|
165
165
|
</Transition>
|
|
166
|
-
<
|
|
167
|
-
<
|
|
168
|
-
|
|
166
|
+
<div v-if="value" class="fixed top-4 right-4 text-gray-400 flex items-center gap-4">
|
|
167
|
+
<RouterLink
|
|
168
|
+
v-if="__DEV__"
|
|
169
|
+
target="_blank"
|
|
170
|
+
to="/overview"
|
|
171
|
+
tab-index="-1"
|
|
172
|
+
class="border-main border px3 py1 rounded hover:bg-gray/5 hover:text-primary"
|
|
173
|
+
>
|
|
174
|
+
List overview
|
|
175
|
+
</RouterLink>
|
|
176
|
+
<IconButton title="Close" class="text-2xl" @click="close">
|
|
177
|
+
<carbon:close />
|
|
178
|
+
</IconButton>
|
|
179
|
+
</div>
|
|
169
180
|
</template>
|
package/internals/SlidesShow.vue
CHANGED
|
@@ -6,14 +6,11 @@ import { useViewTransition } from '../composables/useViewTransition'
|
|
|
6
6
|
import { skipTransition } from '../composables/hmr'
|
|
7
7
|
import { usePrimaryClicks } from '../composables/useClicks'
|
|
8
8
|
import SlideWrapper from './SlideWrapper'
|
|
9
|
-
|
|
10
|
-
// @ts-expect-error virtual module
|
|
11
|
-
import GlobalTop from '/@slidev/global-components/top'
|
|
12
|
-
|
|
13
|
-
// @ts-expect-error virtual module
|
|
14
|
-
import GlobalBottom from '/@slidev/global-components/bottom'
|
|
15
9
|
import PresenterMouse from './PresenterMouse.vue'
|
|
16
10
|
|
|
11
|
+
import GlobalTop from '#slidev/global-components/top'
|
|
12
|
+
import GlobalBottom from '#slidev/global-components/bottom'
|
|
13
|
+
|
|
17
14
|
defineProps<{
|
|
18
15
|
renderContext: 'slide' | 'presenter'
|
|
19
16
|
}>()
|
|
@@ -77,10 +74,12 @@ function onAfterLeave() {
|
|
|
77
74
|
|
|
78
75
|
<style scoped>
|
|
79
76
|
#slideshow {
|
|
80
|
-
|
|
77
|
+
height: 100%;
|
|
81
78
|
}
|
|
82
79
|
|
|
83
80
|
#slideshow > div {
|
|
84
|
-
|
|
81
|
+
position: absolute;
|
|
82
|
+
height: 100%;
|
|
83
|
+
width: 100%;
|
|
85
84
|
}
|
|
86
85
|
</style>
|
|
@@ -51,9 +51,15 @@ const props = defineProps({
|
|
|
51
51
|
grid-template-rows: repeat(2, 1fr);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
.col-header {
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
.col-header {
|
|
55
|
+
grid-area: 1 / 1 / 2 / 3;
|
|
56
|
+
}
|
|
57
|
+
.col-left {
|
|
58
|
+
grid-area: 2 / 1 / 3 / 2;
|
|
59
|
+
}
|
|
60
|
+
.col-right {
|
|
61
|
+
grid-area: 2 / 2 / 3 / 3;
|
|
62
|
+
}
|
|
57
63
|
.col-bottom {
|
|
58
64
|
align-self: end;
|
|
59
65
|
grid-area: 3 / 1 / 3 / 3;
|
package/logic/drawings.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { createDrauu } from 'drauu'
|
|
|
4
4
|
import { toReactive, useLocalStorage } from '@vueuse/core'
|
|
5
5
|
import { drawingState, onPatch, patch } from '../state/drawings'
|
|
6
6
|
import { configs } from '../env'
|
|
7
|
+
import { isInputting } from '../state'
|
|
7
8
|
import { currentPage, isPresenter } from './nav'
|
|
8
9
|
|
|
9
10
|
export const brushColors = [
|
|
@@ -40,11 +41,13 @@ export const drawingMode = computed({
|
|
|
40
41
|
set(v: DrawingMode | 'arrow') {
|
|
41
42
|
_mode.value = v
|
|
42
43
|
if (v === 'arrow') {
|
|
43
|
-
|
|
44
|
+
// eslint-disable-next-line ts/no-use-before-define
|
|
45
|
+
drauu.mode = 'line'
|
|
44
46
|
brush.arrowEnd = true
|
|
45
47
|
}
|
|
46
48
|
else {
|
|
47
|
-
|
|
49
|
+
// eslint-disable-next-line ts/no-use-before-define
|
|
50
|
+
drauu.mode = v
|
|
48
51
|
brush.arrowEnd = false
|
|
49
52
|
}
|
|
50
53
|
},
|
|
@@ -110,7 +113,7 @@ drauu.on('start', () => isDrawing.value = true)
|
|
|
110
113
|
drauu.on('end', () => isDrawing.value = false)
|
|
111
114
|
|
|
112
115
|
window.addEventListener('keydown', (e) => {
|
|
113
|
-
if (!drawingEnabled.value)
|
|
116
|
+
if (!drawingEnabled.value || isInputting.value)
|
|
114
117
|
return
|
|
115
118
|
|
|
116
119
|
const noModifier = !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey
|
package/logic/nav.ts
CHANGED
|
@@ -22,6 +22,7 @@ nextTick(() => {
|
|
|
22
22
|
})
|
|
23
23
|
|
|
24
24
|
export const navDirection = ref(0)
|
|
25
|
+
export const clicksDirection = ref(0)
|
|
25
26
|
|
|
26
27
|
export const route = computed(() => router.currentRoute.value)
|
|
27
28
|
|
|
@@ -84,6 +85,7 @@ watch(currentRoute, (next, prev) => {
|
|
|
84
85
|
})
|
|
85
86
|
|
|
86
87
|
export async function next() {
|
|
88
|
+
clicksDirection.value = 1
|
|
87
89
|
if (clicksTotal.value <= queryClicks.value)
|
|
88
90
|
await nextSlide()
|
|
89
91
|
else
|
|
@@ -91,6 +93,7 @@ export async function next() {
|
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
export async function prev() {
|
|
96
|
+
clicksDirection.value = -1
|
|
94
97
|
if (queryClicks.value <= 0)
|
|
95
98
|
await prevSlide()
|
|
96
99
|
else
|
|
@@ -102,11 +105,13 @@ export function getPath(no: number | string) {
|
|
|
102
105
|
}
|
|
103
106
|
|
|
104
107
|
export async function nextSlide() {
|
|
108
|
+
clicksDirection.value = 1
|
|
105
109
|
if (currentPage.value < rawRoutes.length)
|
|
106
110
|
await go(currentPage.value + 1)
|
|
107
111
|
}
|
|
108
112
|
|
|
109
113
|
export async function prevSlide(lastClicks = true) {
|
|
114
|
+
clicksDirection.value = -1
|
|
110
115
|
const next = Math.max(1, currentPage.value - 1)
|
|
111
116
|
await go(next)
|
|
112
117
|
if (lastClicks && clicksTotal.value)
|
|
@@ -177,7 +182,7 @@ export async function downloadPDF() {
|
|
|
177
182
|
export async function openInEditor(url?: string) {
|
|
178
183
|
if (url == null) {
|
|
179
184
|
const slide = currentRoute.value?.meta?.slide
|
|
180
|
-
if (!slide
|
|
185
|
+
if (!slide)
|
|
181
186
|
return false
|
|
182
187
|
url = `${slide.filepath}:${slide.start}`
|
|
183
188
|
}
|
package/logic/note.ts
CHANGED
|
@@ -2,17 +2,17 @@ import type { MaybeRef } from '@vueuse/core'
|
|
|
2
2
|
import { useFetch } from '@vueuse/core'
|
|
3
3
|
import type { Ref } from 'vue'
|
|
4
4
|
import { computed, ref, unref } from 'vue'
|
|
5
|
-
import type { SlideInfo,
|
|
5
|
+
import type { SlideInfo, SlidePatch } from '@slidev/types'
|
|
6
6
|
|
|
7
7
|
export interface UseSlideInfo {
|
|
8
|
-
info: Ref<
|
|
9
|
-
update: (data:
|
|
8
|
+
info: Ref<SlideInfo | undefined>
|
|
9
|
+
update: (data: SlidePatch) => Promise<SlideInfo | void>
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export function useSlideInfo(id: number | undefined): UseSlideInfo {
|
|
13
13
|
if (id == null) {
|
|
14
14
|
return {
|
|
15
|
-
info: ref() as Ref<
|
|
15
|
+
info: ref() as Ref<SlideInfo | undefined>,
|
|
16
16
|
update: async () => {},
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -21,7 +21,7 @@ export function useSlideInfo(id: number | undefined): UseSlideInfo {
|
|
|
21
21
|
|
|
22
22
|
execute()
|
|
23
23
|
|
|
24
|
-
const update = async (data:
|
|
24
|
+
const update = async (data: SlidePatch) => {
|
|
25
25
|
return await fetch(
|
|
26
26
|
url,
|
|
27
27
|
{
|
|
@@ -41,7 +41,7 @@ export function useSlideInfo(id: number | undefined): UseSlideInfo {
|
|
|
41
41
|
info.value = payload.data
|
|
42
42
|
})
|
|
43
43
|
import.meta.hot?.on('slidev-update-note', (payload) => {
|
|
44
|
-
if (payload.id === id && info.value.note
|
|
44
|
+
if (payload.id === id && info.value.note?.trim() !== payload.note?.trim())
|
|
45
45
|
info.value = { ...info.value, ...payload }
|
|
46
46
|
})
|
|
47
47
|
}
|
|
@@ -64,7 +64,7 @@ export function useDynamicSlideInfo(id: MaybeRef<number | undefined>) {
|
|
|
64
64
|
|
|
65
65
|
return {
|
|
66
66
|
info: computed(() => get(unref(id)).info.value),
|
|
67
|
-
update: async (data:
|
|
67
|
+
update: async (data: SlidePatch, newId?: number) => {
|
|
68
68
|
const info = get(newId ?? unref(id))
|
|
69
69
|
const newData = await info.update(data)
|
|
70
70
|
if (newData)
|
package/main.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
+
/// <reference types="@slidev/types/client" />
|
|
2
|
+
|
|
1
3
|
import { createApp } from 'vue'
|
|
2
4
|
import { createHead } from '@unhead/vue'
|
|
3
5
|
import App from './App.vue'
|
|
4
6
|
import setupMain from './setup/main'
|
|
5
7
|
import { router } from './routes'
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
+
import { createVClickDirectives } from './modules/v-click'
|
|
9
|
+
import { createVMarkDirective } from './modules/v-mark'
|
|
10
|
+
import { createSlidevContext } from './modules/context'
|
|
8
11
|
|
|
9
|
-
import '
|
|
12
|
+
import '#slidev/styles'
|
|
10
13
|
|
|
11
14
|
const app = createApp(App)
|
|
12
15
|
app.use(router)
|
|
13
16
|
app.use(createHead())
|
|
14
|
-
app.use(
|
|
17
|
+
app.use(createVClickDirectives())
|
|
18
|
+
app.use(createVMarkDirective())
|
|
15
19
|
app.use(createSlidevContext())
|
|
16
20
|
|
|
17
21
|
setupMain({ app, router })
|