@slidev/client 0.49.29 → 0.50.0-beta.10
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/Arrow.vue +1 -1
- package/builtin/CodeBlockWrapper.vue +3 -3
- package/builtin/KaTexBlockWrapper.vue +3 -3
- package/builtin/Mermaid.vue +1 -1
- package/builtin/Monaco.vue +6 -5
- package/builtin/RenderWhen.vue +2 -2
- package/builtin/ShikiMagicMove.vue +5 -5
- package/builtin/SlidevVideo.vue +2 -2
- package/builtin/Toc.vue +1 -1
- package/builtin/TocList.vue +6 -3
- package/builtin/Tweet.vue +1 -1
- package/builtin/VAfter.ts +1 -1
- package/builtin/VClick.ts +1 -1
- package/builtin/VClickGap.vue +1 -1
- package/builtin/VClicks.ts +1 -1
- package/builtin/VDrag.vue +1 -1
- package/builtin/VDragArrow.vue +1 -1
- package/builtin/VSwitch.ts +4 -4
- package/composables/useClicks.ts +1 -1
- package/composables/useDragElements.ts +3 -3
- package/composables/useDrawings.ts +3 -3
- package/composables/useNav.ts +8 -8
- package/composables/useSlideInfo.ts +2 -2
- package/composables/useSwipeControls.ts +1 -1
- package/composables/useTimer.ts +20 -0
- package/composables/useViewTransition.ts +2 -3
- package/constants.ts +3 -1
- package/context.ts +2 -2
- package/env.ts +2 -2
- package/index.ts +23 -5
- package/internals/ClicksSlider.vue +1 -1
- package/internals/CodeRunner.vue +5 -5
- package/internals/ContextMenu.vue +8 -6
- package/internals/Controls.vue +6 -6
- package/internals/DevicesList.vue +2 -2
- package/internals/DragControl.vue +2 -2
- package/internals/Draggable.vue +1 -1
- package/internals/DrawingControls.vue +140 -139
- package/internals/DrawingLayer.vue +1 -1
- package/internals/Goto.vue +3 -3
- package/internals/NavControls.vue +21 -21
- package/internals/NoteDisplay.vue +1 -1
- package/internals/NoteEditable.vue +2 -2
- package/internals/PrintContainer.vue +4 -4
- package/internals/PrintSlide.vue +1 -1
- package/internals/PrintSlideClick.vue +3 -3
- package/internals/QuickOverview.vue +11 -9
- package/internals/RecordingControls.vue +5 -5
- package/internals/RecordingDialog.vue +2 -2
- package/internals/SelectList.vue +6 -4
- package/internals/Settings.vue +1 -1
- package/internals/ShikiEditor.vue +1 -1
- package/internals/SideEditor.vue +7 -7
- package/internals/SlideContainer.vue +31 -3
- package/internals/SlideWrapper.vue +5 -4
- package/internals/SlidesShow.vue +6 -6
- package/internals/WebCamera.vue +1 -1
- package/layouts/error.vue +5 -1
- package/logic/contextMenu.ts +3 -3
- package/logic/recording.ts +4 -4
- package/logic/shortcuts.ts +3 -3
- package/logic/slides.ts +2 -2
- package/logic/snapshot.ts +86 -0
- package/logic/utils.ts +0 -23
- package/main.ts +7 -3
- package/modules/context.ts +1 -1
- package/modules/mermaid.ts +3 -3
- package/modules/v-click.ts +1 -1
- package/modules/v-drag.ts +1 -1
- package/modules/v-mark.ts +2 -2
- package/modules/v-motion.ts +3 -3
- package/package.json +26 -25
- package/pages/entry.vue +4 -4
- package/pages/notes.vue +11 -11
- package/pages/overview.vue +27 -14
- package/pages/play.vue +14 -12
- package/pages/presenter/print.vue +2 -2
- package/pages/presenter.vue +38 -39
- package/pages/print.vue +3 -3
- package/setup/code-runners.ts +4 -4
- package/setup/context-menu.ts +15 -24
- package/setup/main.ts +4 -4
- package/setup/mermaid.ts +1 -1
- package/setup/monaco.ts +18 -18
- package/setup/root.ts +9 -9
- package/setup/shortcuts.ts +6 -7
- package/state/drawings.ts +1 -0
- package/state/index.ts +1 -1
- package/state/shared.ts +2 -1
- package/state/snapshot.ts +13 -0
- package/state/syncState.ts +76 -24
- package/styles/index.css +5 -0
- package/uno.config.ts +5 -2
package/internals/SideEditor.vue
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { throttledWatch, useEventListener } from '@vueuse/core'
|
|
3
3
|
import { computed, ref, watch } from 'vue'
|
|
4
|
-
import { activeElement, editorHeight, editorWidth, isInputting, showEditor, isEditorVertical as vertical } from '../state'
|
|
5
4
|
import { useNav } from '../composables/useNav'
|
|
6
5
|
import { useDynamicSlideInfo } from '../composables/useSlideInfo'
|
|
6
|
+
import { activeElement, editorHeight, editorWidth, isInputting, showEditor, isEditorVertical as vertical } from '../state'
|
|
7
7
|
import IconButton from './IconButton.vue'
|
|
8
8
|
import ShikiEditor from './ShikiEditor.vue'
|
|
9
9
|
|
|
@@ -143,13 +143,13 @@ throttledWatch(
|
|
|
143
143
|
title="Switch to content tab" :class="tab === 'content' ? 'text-primary' : ''"
|
|
144
144
|
@click="switchTab('content')"
|
|
145
145
|
>
|
|
146
|
-
<carbon:account />
|
|
146
|
+
<div class="i-carbon:account" />
|
|
147
147
|
</IconButton>
|
|
148
148
|
<IconButton
|
|
149
149
|
title="Switch to notes tab" :class="tab === 'note' ? 'text-primary' : ''"
|
|
150
150
|
@click="switchTab('note')"
|
|
151
151
|
>
|
|
152
|
-
<carbon:align-box-bottom-right />
|
|
152
|
+
<div class="i-carbon:align-box-bottom-right" />
|
|
153
153
|
</IconButton>
|
|
154
154
|
</div>
|
|
155
155
|
<span class="text-2xl pt-1">
|
|
@@ -158,17 +158,17 @@ throttledWatch(
|
|
|
158
158
|
<div class="flex-auto" />
|
|
159
159
|
<template v-if="resize">
|
|
160
160
|
<IconButton v-if="vertical" title="Dock to right" @click="vertical = false">
|
|
161
|
-
<carbon:open-panel-right />
|
|
161
|
+
<div class="i-carbon:open-panel-right" />
|
|
162
162
|
</IconButton>
|
|
163
163
|
<IconButton v-else title="Dock to bottom" @click="vertical = true">
|
|
164
|
-
<carbon:open-panel-bottom />
|
|
164
|
+
<div class="i-carbon:open-panel-bottom" />
|
|
165
165
|
</IconButton>
|
|
166
166
|
</template>
|
|
167
167
|
<IconButton title="Open in editor" @click="openInEditor()">
|
|
168
|
-
<carbon:launch />
|
|
168
|
+
<div class="i-carbon:launch" />
|
|
169
169
|
</IconButton>
|
|
170
170
|
<IconButton title="Close" @click="close">
|
|
171
|
-
<carbon:close />
|
|
171
|
+
<div class="i-carbon:close" />
|
|
172
172
|
</IconButton>
|
|
173
173
|
</div>
|
|
174
174
|
<div class="relative overflow-hidden rounded" style="background-color: var(--slidev-code-background)">
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { provideLocal, useElementSize, useStyleTag } from '@vueuse/core'
|
|
3
|
-
import { computed, ref } from 'vue'
|
|
3
|
+
import { computed, onMounted, ref } from 'vue'
|
|
4
|
+
import { useNav } from '../composables/useNav'
|
|
4
5
|
import { injectionSlideElement, injectionSlideScale } from '../constants'
|
|
5
6
|
import { slideAspect, slideHeight, slideWidth } from '../env'
|
|
6
|
-
import {
|
|
7
|
+
import { snapshotManager } from '../logic/snapshot'
|
|
7
8
|
import { slideScale } from '../state'
|
|
8
9
|
|
|
9
10
|
const props = defineProps({
|
|
@@ -17,6 +18,14 @@ const props = defineProps({
|
|
|
17
18
|
type: Boolean,
|
|
18
19
|
default: false,
|
|
19
20
|
},
|
|
21
|
+
no: {
|
|
22
|
+
type: Number,
|
|
23
|
+
required: false,
|
|
24
|
+
},
|
|
25
|
+
useSnapshot: {
|
|
26
|
+
type: Boolean,
|
|
27
|
+
default: false,
|
|
28
|
+
},
|
|
20
29
|
})
|
|
21
30
|
|
|
22
31
|
const { isPrintMode } = useNav()
|
|
@@ -54,15 +63,34 @@ if (props.isMain)
|
|
|
54
63
|
|
|
55
64
|
provideLocal(injectionSlideScale, scale)
|
|
56
65
|
provideLocal(injectionSlideElement, slideElement)
|
|
66
|
+
|
|
67
|
+
const snapshot = computed(() => {
|
|
68
|
+
if (!props.useSnapshot || props.no == null)
|
|
69
|
+
return undefined
|
|
70
|
+
return snapshotManager.getSnapshot(props.no)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
onMounted(() => {
|
|
74
|
+
if (container.value && props.useSnapshot && props.no != null) {
|
|
75
|
+
snapshotManager.captureSnapshot(props.no, container.value)
|
|
76
|
+
}
|
|
77
|
+
})
|
|
57
78
|
</script>
|
|
58
79
|
|
|
59
80
|
<template>
|
|
60
|
-
<div :id="isMain ? 'slide-container' : undefined" ref="container" class="slidev-slide-container" :style="containerStyle">
|
|
81
|
+
<div v-if="!snapshot" :id="isMain ? 'slide-container' : undefined" ref="container" class="slidev-slide-container" :style="containerStyle">
|
|
61
82
|
<div :id="isMain ? 'slide-content' : undefined" ref="slideElement" class="slidev-slide-content" :style="contentStyle">
|
|
62
83
|
<slot />
|
|
63
84
|
</div>
|
|
64
85
|
<slot name="controls" />
|
|
65
86
|
</div>
|
|
87
|
+
<!-- Image preview -->
|
|
88
|
+
<img
|
|
89
|
+
v-else
|
|
90
|
+
:src="snapshot"
|
|
91
|
+
class="w-full object-cover"
|
|
92
|
+
:style="containerStyle"
|
|
93
|
+
>
|
|
66
94
|
</template>
|
|
67
95
|
|
|
68
96
|
<style scoped lang="postcss">
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import type { ClicksContext, RenderContext, SlideRoute } from '@slidev/types'
|
|
3
3
|
import type { CSSProperties, PropType } from 'vue'
|
|
4
|
+
import { SlideBottom, SlideTop } from '#slidev/global-layers'
|
|
4
5
|
import { provideLocal } from '@vueuse/core'
|
|
5
|
-
import
|
|
6
|
+
import { computed, ref, toRef } from 'vue'
|
|
6
7
|
import { injectionClicksContext, injectionCurrentPage, injectionFrontmatter, injectionRenderContext, injectionRoute, injectionSlideZoom } from '../constants'
|
|
7
|
-
import { getSlideClass } from '../utils'
|
|
8
8
|
import { configs } from '../env'
|
|
9
|
-
import {
|
|
9
|
+
import { getSlideClass } from '../utils'
|
|
10
10
|
|
|
11
11
|
const props = defineProps({
|
|
12
12
|
clicksContext: {
|
|
@@ -53,6 +53,7 @@ const style = computed<CSSProperties>(() => ({
|
|
|
53
53
|
:data-slidev-no="props.route.no"
|
|
54
54
|
:class="getSlideClass(route, ['slide', 'presenter'].includes(props.renderContext) ? '' : 'disable-view-transition')"
|
|
55
55
|
:style="style"
|
|
56
|
+
:lang="props.route.meta.slide.frontmatter.lang"
|
|
56
57
|
>
|
|
57
58
|
<SlideBottom />
|
|
58
59
|
<component :is="props.route.component" />
|
package/internals/SlidesShow.vue
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { TransitionGroup, computed, shallowRef, watchEffect } from 'vue'
|
|
3
|
-
import { recomputeAllPoppers } from 'floating-vue'
|
|
4
2
|
import type { SlideRoute } from '@slidev/types'
|
|
3
|
+
import { GlobalBottom, GlobalTop } from '#slidev/global-layers'
|
|
4
|
+
import { recomputeAllPoppers } from 'floating-vue'
|
|
5
|
+
import { computed, shallowRef, TransitionGroup, watchEffect } from 'vue'
|
|
6
|
+
import { createFixedClicks } from '../composables/useClicks'
|
|
5
7
|
import { useNav } from '../composables/useNav'
|
|
6
8
|
import { useViewTransition } from '../composables/useViewTransition'
|
|
9
|
+
import { CLICKS_MAX } from '../constants'
|
|
7
10
|
import { skipTransition } from '../logic/hmr'
|
|
8
|
-
import { createFixedClicks } from '../composables/useClicks'
|
|
9
11
|
import { activeDragElement } from '../state'
|
|
10
|
-
import { CLICKS_MAX } from '../constants'
|
|
11
|
-
import SlideWrapper from './SlideWrapper.vue'
|
|
12
12
|
import DragControl from './DragControl.vue'
|
|
13
|
-
import
|
|
13
|
+
import SlideWrapper from './SlideWrapper.vue'
|
|
14
14
|
|
|
15
15
|
defineProps<{
|
|
16
16
|
renderContext: 'slide' | 'presenter'
|
package/internals/WebCamera.vue
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useDraggable, useEventListener, useLocalStorage } from '@vueuse/core'
|
|
3
3
|
import { computed, onMounted, ref, watchEffect } from 'vue'
|
|
4
|
-
import { currentCamera } from '../state'
|
|
5
4
|
import { recorder } from '../logic/recording'
|
|
5
|
+
import { currentCamera } from '../state'
|
|
6
6
|
|
|
7
7
|
const size = useLocalStorage('slidev-webcam-size', Math.round(Math.min(window.innerHeight, (window.innerWidth) / 8)))
|
|
8
8
|
const position = useLocalStorage('slidev-webcam-pos', {
|
package/layouts/error.vue
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="px-4 py-10 text-center text-red-700 dark:text-red-500 font-bold font-mono">
|
|
3
|
-
|
|
3
|
+
{{
|
|
4
|
+
__SLIDEV_HAS_SERVER__
|
|
5
|
+
? 'An error occurred on this slide. Check the terminal for more information.'
|
|
6
|
+
: 'Failed to fetch this slide. Please check your network connection.'
|
|
7
|
+
}}
|
|
4
8
|
</div>
|
|
5
9
|
</template>
|
package/logic/contextMenu.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { ContextMenuItem } from '@slidev/types'
|
|
2
2
|
import type { ComputedRef } from 'vue'
|
|
3
3
|
import { shallowRef } from 'vue'
|
|
4
|
-
import setupContextMenu from '../setup/context-menu'
|
|
5
|
-
import { configs, mode } from '../env'
|
|
6
4
|
import { useNav } from '../composables/useNav'
|
|
5
|
+
import { configs, mode } from '../env'
|
|
6
|
+
import setupContextMenu from '../setup/context-menu'
|
|
7
7
|
|
|
8
8
|
export const currentContextMenu = shallowRef<null | {
|
|
9
9
|
x: number
|
|
@@ -24,7 +24,7 @@ export function closeContextMenu() {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export function onContextMenu(ev: MouseEvent) {
|
|
27
|
-
if (configs.contextMenu !== true && configs.contextMenu
|
|
27
|
+
if (configs.contextMenu !== true && configs.contextMenu != null && configs.contextMenu !== mode)
|
|
28
28
|
return
|
|
29
29
|
if (ev.shiftKey || ev.defaultPrevented)
|
|
30
30
|
return
|
package/logic/recording.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { Ref } from 'vue'
|
|
2
|
-
import { nextTick, ref, shallowRef, watch } from 'vue'
|
|
3
|
-
import { useDevicesList, useEventListener, useLocalStorage } from '@vueuse/core'
|
|
4
|
-
import { isTruthy } from '@antfu/utils'
|
|
5
1
|
import type RecorderType from 'recordrtc'
|
|
6
2
|
import type { Options as RecorderOptions } from 'recordrtc'
|
|
3
|
+
import type { Ref } from 'vue'
|
|
4
|
+
import { isTruthy } from '@antfu/utils'
|
|
5
|
+
import { useDevicesList, useEventListener, useLocalStorage } from '@vueuse/core'
|
|
6
|
+
import { nextTick, ref, shallowRef, watch } from 'vue'
|
|
7
7
|
import { currentCamera, currentMic } from '../state'
|
|
8
8
|
|
|
9
9
|
type Defined<T> = T extends undefined ? never : T
|
package/logic/shortcuts.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import type { ShortcutOptions } from '@slidev/types'
|
|
1
2
|
import type { Fn, KeyFilter } from '@vueuse/core'
|
|
3
|
+
import type { Ref } from 'vue'
|
|
2
4
|
import { onKeyStroke } from '@vueuse/core'
|
|
3
5
|
import { and, not } from '@vueuse/math'
|
|
4
|
-
import type { Ref } from 'vue'
|
|
5
6
|
import { watch } from 'vue'
|
|
6
|
-
import type { ShortcutOptions } from '@slidev/types'
|
|
7
|
-
import { fullscreen, isInputting, isOnFocus, magicKeys, shortcutsEnabled } from '../state'
|
|
8
7
|
import setupShortcuts from '../setup/shortcuts'
|
|
8
|
+
import { fullscreen, isInputting, isOnFocus, magicKeys, shortcutsEnabled } from '../state'
|
|
9
9
|
|
|
10
10
|
const _shortcut = and(not(isInputting), not(isOnFocus), shortcutsEnabled)
|
|
11
11
|
|
package/logic/slides.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { SlideRoute } from '@slidev/types'
|
|
2
|
+
import { slides } from '#slidev/slides'
|
|
2
3
|
import { computed, watch, watchEffect } from 'vue'
|
|
3
|
-
import { useSlideContext } from '../context'
|
|
4
4
|
import { useNav } from '../composables/useNav'
|
|
5
|
-
import {
|
|
5
|
+
import { useSlideContext } from '../context'
|
|
6
6
|
|
|
7
7
|
export { slides }
|
|
8
8
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { snapshotState } from '../state/snapshot'
|
|
2
|
+
import { getSlide } from './slides'
|
|
3
|
+
|
|
4
|
+
export class SlideSnapshotManager {
|
|
5
|
+
private _capturePromises = new Map<number, Promise<void>>()
|
|
6
|
+
|
|
7
|
+
getSnapshot(slideNo: number) {
|
|
8
|
+
const data = snapshotState.state[slideNo]
|
|
9
|
+
if (!data) {
|
|
10
|
+
return
|
|
11
|
+
}
|
|
12
|
+
const slide = getSlide(slideNo)
|
|
13
|
+
if (!slide) {
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
if (data?.revision === slide?.meta.slide.revision) {
|
|
17
|
+
return data.image
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async captureSnapshot(slideNo: number, el: HTMLElement, delay = 1000) {
|
|
22
|
+
if (!__DEV__)
|
|
23
|
+
return
|
|
24
|
+
if (this.getSnapshot(slideNo)) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
if (this._capturePromises.has(slideNo)) {
|
|
28
|
+
await this._capturePromises.get(slideNo)
|
|
29
|
+
}
|
|
30
|
+
const promise = this._captureSnapshot(slideNo, el, delay)
|
|
31
|
+
.finally(() => {
|
|
32
|
+
this._capturePromises.delete(slideNo)
|
|
33
|
+
})
|
|
34
|
+
this._capturePromises.set(slideNo, promise)
|
|
35
|
+
await promise
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private async _captureSnapshot(slideNo: number, el: HTMLElement, delay: number) {
|
|
39
|
+
if (!__DEV__)
|
|
40
|
+
return
|
|
41
|
+
const slide = getSlide(slideNo)
|
|
42
|
+
if (!slide)
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
const revision = slide.meta.slide.revision
|
|
46
|
+
|
|
47
|
+
// Retry until the slide is loaded
|
|
48
|
+
let retries = 100
|
|
49
|
+
while (retries-- > 0) {
|
|
50
|
+
if (!el.querySelector('.slidev-slide-loading'))
|
|
51
|
+
break
|
|
52
|
+
await new Promise(r => setTimeout(r, 100))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Artificial delay for the content to be loaded
|
|
56
|
+
await new Promise(r => setTimeout(r, delay))
|
|
57
|
+
|
|
58
|
+
// Capture the snapshot
|
|
59
|
+
const toImage = await import('html-to-image')
|
|
60
|
+
try {
|
|
61
|
+
const dataUrl = await toImage.toPng(el, {
|
|
62
|
+
width: el.offsetWidth,
|
|
63
|
+
height: el.offsetHeight,
|
|
64
|
+
skipFonts: true,
|
|
65
|
+
cacheBust: true,
|
|
66
|
+
pixelRatio: 1.5,
|
|
67
|
+
})
|
|
68
|
+
if (revision !== slide.meta.slide.revision) {
|
|
69
|
+
// eslint-disable-next-line no-console
|
|
70
|
+
console.info('[Slidev] Slide', slideNo, 'changed, discarding the snapshot')
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
snapshotState.patch(slideNo, {
|
|
74
|
+
revision,
|
|
75
|
+
image: dataUrl,
|
|
76
|
+
})
|
|
77
|
+
// eslint-disable-next-line no-console
|
|
78
|
+
console.info('[Slidev] Snapshot captured for slide', slideNo)
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
console.error('[Slidev] Failed to capture snapshot for slide', slideNo, e)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const snapshotManager = new SlideSnapshotManager()
|
package/logic/utils.ts
CHANGED
|
@@ -1,27 +1,4 @@
|
|
|
1
1
|
import { parseRangeString } from '@slidev/parser/core'
|
|
2
|
-
import { useTimestamp } from '@vueuse/core'
|
|
3
|
-
import { computed, ref } from 'vue'
|
|
4
|
-
|
|
5
|
-
export function useTimer() {
|
|
6
|
-
const tsStart = ref(Date.now())
|
|
7
|
-
const now = useTimestamp({
|
|
8
|
-
interval: 1000,
|
|
9
|
-
})
|
|
10
|
-
const timer = computed(() => {
|
|
11
|
-
const passed = (now.value - tsStart.value) / 1000
|
|
12
|
-
const sec = Math.floor(passed % 60).toString().padStart(2, '0')
|
|
13
|
-
const min = Math.floor(passed / 60).toString().padStart(2, '0')
|
|
14
|
-
return `${min}:${sec}`
|
|
15
|
-
})
|
|
16
|
-
function resetTimer() {
|
|
17
|
-
tsStart.value = now.value
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return {
|
|
21
|
-
timer,
|
|
22
|
-
resetTimer,
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
2
|
|
|
26
3
|
export function makeId(length = 5) {
|
|
27
4
|
const result = []
|
package/main.ts
CHANGED
|
@@ -4,6 +4,10 @@ import { createApp } from 'vue'
|
|
|
4
4
|
import App from './App.vue'
|
|
5
5
|
import setupMain from './setup/main'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
async function main() {
|
|
8
|
+
const app = createApp(App)
|
|
9
|
+
await setupMain(app)
|
|
10
|
+
app.mount('#app')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
main()
|
package/modules/context.ts
CHANGED
package/modules/mermaid.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import mermaid from 'mermaid/dist/mermaid.esm.mjs'
|
|
2
|
-
import lz from 'lz-string'
|
|
3
1
|
import { clearUndefined } from '@antfu/utils'
|
|
4
|
-
import
|
|
2
|
+
import lz from 'lz-string'
|
|
3
|
+
import mermaid from 'mermaid/dist/mermaid.esm.mjs'
|
|
5
4
|
import { makeId } from '../logic/utils'
|
|
5
|
+
import setupMermaid from '../setup/mermaid'
|
|
6
6
|
|
|
7
7
|
mermaid.startOnLoad = false
|
|
8
8
|
mermaid.initialize({ startOnLoad: false })
|
package/modules/v-click.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import type { ClicksElement, RawAtValue } from '@slidev/types'
|
|
1
2
|
import type { App, DirectiveBinding } from 'vue'
|
|
2
3
|
import { computed, watchEffect } from 'vue'
|
|
3
|
-
import type { ClicksElement, RawAtValue } from '@slidev/types'
|
|
4
4
|
import {
|
|
5
5
|
CLASS_VCLICK_CURRENT,
|
|
6
6
|
CLASS_VCLICK_FADE,
|
package/modules/v-drag.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { App } from 'vue'
|
|
2
|
-
import { watch } from 'vue'
|
|
3
2
|
import type { DragElementState } from '../composables/useDragElements'
|
|
3
|
+
import { watch } from 'vue'
|
|
4
4
|
import { useDragElement } from '../composables/useDragElements'
|
|
5
5
|
|
|
6
6
|
export function createVDragDirective() {
|
package/modules/v-mark.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { RoughAnnotationConfig } from '@slidev/rough-notation'
|
|
2
|
-
import {
|
|
2
|
+
import type { RawAtValue } from '@slidev/types'
|
|
3
3
|
import type { App } from 'vue'
|
|
4
|
+
import { annotate } from '@slidev/rough-notation'
|
|
4
5
|
import { computed, watchEffect } from 'vue'
|
|
5
|
-
import type { RawAtValue } from '@slidev/types'
|
|
6
6
|
import { resolveClick } from './v-click'
|
|
7
7
|
|
|
8
8
|
export interface RoughDirectiveOptions extends Partial<RoughAnnotationConfig> {
|
package/modules/v-motion.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import type { ClicksInfo } from '@slidev/types'
|
|
1
2
|
import type { App, ObjectDirective } from 'vue'
|
|
2
|
-
import { watch } from 'vue'
|
|
3
3
|
import { MotionDirective } from '@vueuse/motion'
|
|
4
|
-
import
|
|
5
|
-
import { injectionClicksContext, injectionCurrentPage, injectionRenderContext } from '../constants'
|
|
4
|
+
import { watch } from 'vue'
|
|
6
5
|
import { useNav } from '../composables/useNav'
|
|
6
|
+
import { injectionClicksContext, injectionCurrentPage, injectionRenderContext } from '../constants'
|
|
7
7
|
import { makeId } from '../logic/utils'
|
|
8
8
|
import { directiveInject } from '../utils'
|
|
9
9
|
import { resolvedClickMap } from './v-click'
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slidev/client",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.50.0-beta.10",
|
|
5
5
|
"description": "Presentation slides for developers",
|
|
6
6
|
"author": "antfu <anthonyfu117@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -29,39 +29,40 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@antfu/utils": "^0.7.10",
|
|
32
|
-
"@iconify-json/carbon": "^1.
|
|
33
|
-
"@iconify-json/ph": "^1.1
|
|
34
|
-
"@iconify-json/svg-spinners": "^1.1
|
|
35
|
-
"@shikijs/monaco": "^1.
|
|
36
|
-
"@shikijs/vitepress-twoslash": "^1.
|
|
32
|
+
"@iconify-json/carbon": "^1.2.4",
|
|
33
|
+
"@iconify-json/ph": "^1.2.1",
|
|
34
|
+
"@iconify-json/svg-spinners": "^1.2.1",
|
|
35
|
+
"@shikijs/monaco": "^1.24.0",
|
|
36
|
+
"@shikijs/vitepress-twoslash": "^1.24.0",
|
|
37
37
|
"@slidev/rough-notation": "^0.1.0",
|
|
38
38
|
"@typescript/ata": "^0.9.7",
|
|
39
|
-
"@unhead/vue": "^1.
|
|
40
|
-
"@unocss/reset": "^0.
|
|
41
|
-
"@vueuse/core": "^
|
|
42
|
-
"@vueuse/math": "^
|
|
43
|
-
"@vueuse/motion": "^2.2.
|
|
44
|
-
"drauu": "^0.4.
|
|
39
|
+
"@unhead/vue": "^1.11.13",
|
|
40
|
+
"@unocss/reset": "^0.65.0",
|
|
41
|
+
"@vueuse/core": "^12.0.0",
|
|
42
|
+
"@vueuse/math": "^12.0.0",
|
|
43
|
+
"@vueuse/motion": "^2.2.6",
|
|
44
|
+
"drauu": "^0.4.2",
|
|
45
45
|
"file-saver": "^2.0.5",
|
|
46
46
|
"floating-vue": "^5.2.2",
|
|
47
47
|
"fuse.js": "^7.0.0",
|
|
48
|
+
"html-to-image": "^1.11.11",
|
|
48
49
|
"katex": "^0.16.11",
|
|
49
50
|
"lz-string": "^1.5.0",
|
|
50
|
-
"mermaid": "^11.
|
|
51
|
-
"monaco-editor": "
|
|
52
|
-
"prettier": "^3.
|
|
51
|
+
"mermaid": "^11.4.1",
|
|
52
|
+
"monaco-editor": "0.51.0",
|
|
53
|
+
"prettier": "^3.4.1",
|
|
53
54
|
"recordrtc": "^5.6.2",
|
|
54
|
-
"shiki": "^1.
|
|
55
|
-
"shiki-magic-move": "^0.
|
|
56
|
-
"typescript": "
|
|
57
|
-
"unocss": "^0.
|
|
58
|
-
"vue": "^3.
|
|
59
|
-
"vue-router": "^4.
|
|
60
|
-
"yaml": "^2.
|
|
61
|
-
"@slidev/types": "0.
|
|
62
|
-
"@slidev/parser": "0.
|
|
55
|
+
"shiki": "^1.24.0",
|
|
56
|
+
"shiki-magic-move": "^0.5.0",
|
|
57
|
+
"typescript": "5.6.3",
|
|
58
|
+
"unocss": "^0.65.0",
|
|
59
|
+
"vue": "^3.5.13",
|
|
60
|
+
"vue-router": "^4.5.0",
|
|
61
|
+
"yaml": "^2.6.1",
|
|
62
|
+
"@slidev/types": "0.50.0-beta.10",
|
|
63
|
+
"@slidev/parser": "0.50.0-beta.10"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
|
-
"vite": "^
|
|
66
|
+
"vite": "^6.0.2"
|
|
66
67
|
}
|
|
67
68
|
}
|
package/pages/entry.vue
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="h-full w-full flex items-center justify-center gap-5 lt-md:flex-col">
|
|
3
3
|
<RouterLink to="/" class="page-link">
|
|
4
|
-
<carbon:presentation-file /> Slides
|
|
4
|
+
<div class="i-carbon:presentation-file" /> Slides
|
|
5
5
|
</RouterLink>
|
|
6
6
|
<RouterLink to="/presenter" class="page-link">
|
|
7
|
-
<carbon:user-speaker /> Presenter
|
|
7
|
+
<div class="i-carbon:user-speaker" /> Presenter
|
|
8
8
|
</RouterLink>
|
|
9
9
|
<RouterLink to="/notes" class="page-link">
|
|
10
|
-
<carbon:catalog /> Notes
|
|
10
|
+
<div class="i-carbon:catalog" /> Notes
|
|
11
11
|
</RouterLink>
|
|
12
12
|
<RouterLink to="/overview" class="page-link">
|
|
13
|
-
<carbon:list-boxes /> Overview
|
|
13
|
+
<div class="i-carbon:list-boxes" /> Overview
|
|
14
14
|
</RouterLink>
|
|
15
15
|
</div>
|
|
16
16
|
</template>
|
package/pages/notes.vue
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useHead } from '@unhead/vue'
|
|
3
|
-
import { computed, ref, watch } from 'vue'
|
|
4
3
|
import { useLocalStorage } from '@vueuse/core'
|
|
4
|
+
import { computed, ref, watch } from 'vue'
|
|
5
|
+
import { createClicksContextBase } from '../composables/useClicks'
|
|
6
|
+
import { useNav } from '../composables/useNav'
|
|
5
7
|
import { slidesTitle } from '../env'
|
|
6
|
-
import { sharedState } from '../state/shared'
|
|
7
|
-
import { fullscreen } from '../state'
|
|
8
8
|
|
|
9
|
-
import NoteDisplay from '../internals/NoteDisplay.vue'
|
|
10
|
-
import IconButton from '../internals/IconButton.vue'
|
|
11
9
|
import ClicksSlider from '../internals/ClicksSlider.vue'
|
|
12
|
-
import
|
|
13
|
-
import
|
|
10
|
+
import IconButton from '../internals/IconButton.vue'
|
|
11
|
+
import NoteDisplay from '../internals/NoteDisplay.vue'
|
|
12
|
+
import { fullscreen } from '../state'
|
|
13
|
+
import { sharedState } from '../state/shared'
|
|
14
14
|
|
|
15
15
|
useHead({ title: `Notes - ${slidesTitle}` })
|
|
16
16
|
|
|
@@ -67,14 +67,14 @@ const clicksContext = computed(() => {
|
|
|
67
67
|
<div class="flex-none border-t border-main">
|
|
68
68
|
<div class="flex gap-1 items-center px-6 py-3">
|
|
69
69
|
<IconButton :title="isFullscreen ? 'Close fullscreen' : 'Enter fullscreen'" @click="toggleFullscreen">
|
|
70
|
-
<
|
|
71
|
-
<
|
|
70
|
+
<div v-if="isFullscreen" class="i-carbon:minimize" />
|
|
71
|
+
<div v-else class="i-carbon:maximize" />
|
|
72
72
|
</IconButton>
|
|
73
73
|
<IconButton title="Increase font size" @click="increaseFontSize">
|
|
74
|
-
<carbon:zoom-in />
|
|
74
|
+
<div class="i-carbon:zoom-in" />
|
|
75
75
|
</IconButton>
|
|
76
76
|
<IconButton title="Decrease font size" @click="decreaseFontSize">
|
|
77
|
-
<carbon:zoom-out />
|
|
77
|
+
<div class="i-carbon:zoom-out" />
|
|
78
78
|
</IconButton>
|
|
79
79
|
<div class="flex-auto" />
|
|
80
80
|
<div class="p2 text-center">
|