@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.
Files changed (61) hide show
  1. package/builtin/CodeBlockWrapper.vue +4 -3
  2. package/builtin/KaTexBlockWrapper.vue +4 -3
  3. package/builtin/RenderWhen.vue +3 -3
  4. package/builtin/SlideCurrentNo.vue +2 -3
  5. package/builtin/SlidesTotal.vue +3 -4
  6. package/builtin/SlidevVideo.vue +8 -6
  7. package/builtin/Toc.vue +3 -3
  8. package/builtin/TocList.vue +3 -2
  9. package/builtin/Tweet.vue +4 -15
  10. package/builtin/VClickGap.vue +3 -5
  11. package/builtin/VClicks.ts +1 -1
  12. package/composables/useClicks.ts +19 -13
  13. package/composables/useTweetScript.ts +17 -0
  14. package/constants.ts +56 -8
  15. package/context.ts +70 -0
  16. package/env.ts +3 -12
  17. package/internals/DrawingControls.vue +39 -9
  18. package/internals/DrawingLayer.vue +3 -2
  19. package/internals/Editor.vue +7 -3
  20. package/internals/Goto.vue +5 -4
  21. package/internals/IconButton.vue +4 -3
  22. package/internals/InfoDialog.vue +1 -1
  23. package/internals/Modal.vue +1 -1
  24. package/internals/NavControls.vue +2 -3
  25. package/internals/NoteDisplay.vue +1 -1
  26. package/internals/NoteEditor.vue +36 -8
  27. package/internals/NoteStatic.vue +5 -6
  28. package/internals/PrintContainer.vue +3 -2
  29. package/internals/PrintSlideClick.vue +5 -7
  30. package/internals/RecordingDialog.vue +5 -6
  31. package/internals/SlideContainer.vue +12 -9
  32. package/internals/SlideWrapper.ts +28 -12
  33. package/internals/SlidesOverview.vue +18 -7
  34. package/internals/SlidesShow.vue +7 -8
  35. package/layouts/two-cols-header.vue +9 -3
  36. package/logic/drawings.ts +6 -3
  37. package/logic/nav.ts +6 -1
  38. package/logic/note.ts +7 -7
  39. package/main.ts +8 -4
  40. package/modules/context.ts +4 -3
  41. package/modules/{directives.ts → v-click.ts} +15 -15
  42. package/modules/v-mark.ts +159 -0
  43. package/package.json +21 -13
  44. package/{internals/EntrySelect.vue → pages/entry.vue} +7 -0
  45. package/{internals/NotesView.vue → pages/notes.vue} +3 -3
  46. package/pages/overview.vue +201 -0
  47. package/{internals/Play.vue → pages/play.vue} +7 -7
  48. package/{internals/PresenterPrint.vue → pages/presenter/print.vue} +7 -5
  49. package/{internals/Presenter.vue → pages/presenter.vue} +64 -58
  50. package/{internals/Print.vue → pages/print.vue} +2 -2
  51. package/routes.ts +27 -51
  52. package/setup/codemirror.ts +7 -0
  53. package/shim-vue.d.ts +35 -0
  54. package/shim.d.ts +0 -12
  55. package/state/index.ts +10 -10
  56. package/styles/code.css +7 -3
  57. package/styles/index.css +18 -6
  58. package/styles/katex.css +1 -1
  59. package/styles/layouts-base.css +17 -12
  60. package/styles/vars.css +1 -0
  61. package/uno.config.ts +14 -2
@@ -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>
@@ -10,7 +10,7 @@ const props = defineProps({
10
10
  },
11
11
  })
12
12
 
13
- const emit = defineEmits<{ (name: 'modelValue', v: boolean): void }>()
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>
@@ -10,7 +10,7 @@ const props = defineProps({
10
10
  },
11
11
  })
12
12
 
13
- const emit = defineEmits<{ (name: 'modelValue', v: boolean): void }>()
13
+ const emit = defineEmits(['update:modelValue'])
14
14
  const value = useVModel(props, 'modelValue', emit)
15
15
 
16
16
  function onClick() {
@@ -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
- // @ts-expect-error virtual module
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-gray-400 dark:border-opacity-10')
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__)
@@ -27,7 +27,7 @@ defineEmits(['click'])
27
27
  </div>
28
28
  <div
29
29
  v-else
30
- class="prose overflow-auto outline-none opacity-50 italic"
30
+ class="prose overflow-auto outline-none opacity-50 italic select-none"
31
31
  :class="props.class"
32
32
  @click="$emit('click')"
33
33
  >
@@ -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(currentSlideId)
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 = currentSlideId.value
41
+ const id = props.no
37
42
  clearTimeout(timer)
38
43
  timer = setTimeout(() => {
39
- update({ raw: null!, note: v }, id)
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-50']"
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-green border-2"
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"
@@ -1,20 +1,19 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue'
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 note = computed(() => currentRoute.value?.meta?.slide?.note)
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="noteHtml"
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, provide } from 'vue'
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
- provide(injectionSlideScale, scale)
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, provide, reactive, shallowRef } from 'vue'
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
- // @ts-expect-error virtual module
12
- import GlobalTop from '/@slidev/global-components/top'
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
- provide(injectionSlidevContext, reactive({
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="text"] {
112
- @apply border border-gray-400 rounded px-2 py-1;
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-gray-500;
122
- @apply bg-opacity-50 border-opacity-50;
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, provide, ref, watchEffect } from 'vue'
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
- provide(injectionSlideScale, scale as any)
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, provide, ref, toRef } from 'vue'
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
- default: undefined,
25
+ required: true,
24
26
  },
25
27
  route: {
26
- type: Object,
27
- default: undefined,
28
+ type: Object as PropType<RouteRecordRaw>,
29
+ required: true,
28
30
  },
29
31
  },
30
32
  setup(props) {
31
- provide(injectionRoute, props.route as any)
32
- provide(injectionCurrentPage, ref(+props.route?.path))
33
- provide(injectionRenderContext, ref(props.renderContext as RenderContext))
34
- provide(injectionActive, toRef(props, 'active'))
35
- provide(injectionClicksContext, toRef(props, 'clicksContext'))
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
- if (this.$props.is)
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 border-opacity-50 overflow-hidden bg-main hover:border-$slidev-theme-primary transition"
129
- :class="(focus(idx + 1) || currentOverviewPage === idx + 1) ? 'border-$slidev-theme-primary' : 'border-gray-400'"
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
- <IconButton v-if="value" title="Close" class="fixed text-2xl top-4 right-4 text-gray-400" @click="close">
167
- <carbon:close />
168
- </IconButton>
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>
@@ -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
- @apply h-full;
77
+ height: 100%;
81
78
  }
82
79
 
83
80
  #slideshow > div {
84
- @apply h-full w-full absolute;
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 { grid-area: 1 / 1 / 2 / 3; }
55
- .col-left { grid-area: 2 / 1 / 3 / 2; }
56
- .col-right { grid-area: 2 / 2 / 3 / 3; }
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
- brush.mode = 'line'
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
- brush.mode = v
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?.filepath)
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, SlideInfoExtended } from '@slidev/types'
5
+ import type { SlideInfo, SlidePatch } from '@slidev/types'
6
6
 
7
7
  export interface UseSlideInfo {
8
- info: Ref<SlideInfoExtended | undefined>
9
- update: (data: Partial<SlideInfo>) => Promise<SlideInfoExtended | void>
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<SlideInfoExtended | undefined>,
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: Partial<SlideInfo>) => {
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.trim() !== payload.note.trim())
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: Partial<SlideInfo>, newId?: number) => {
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 createDirectives from './modules/directives'
7
- import createSlidevContext from './modules/context'
8
+ import { createVClickDirectives } from './modules/v-click'
9
+ import { createVMarkDirective } from './modules/v-mark'
10
+ import { createSlidevContext } from './modules/context'
8
11
 
9
- import '/@slidev/styles'
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(createDirectives())
17
+ app.use(createVClickDirectives())
18
+ app.use(createVMarkDirective())
15
19
  app.use(createSlidevContext())
16
20
 
17
21
  setupMain({ app, router })