返回 slidev
snapshot.ts
根目录 / packages / client / logic / snapshot.ts
1 import type { SlidevContextNavFull } from '../composables/useNav'
2 import type { ScreenshotSession } from './screenshot'
3 import { sleep } from '@antfu/utils'
4 import { slideHeight, slideWidth } from '../env'
5 import { captureDelay, disableTransition } from '../state'
6 import { snapshotState } from '../state/snapshot'
7 import { isDark } from './dark'
8 import { startScreenshotSession } from './screenshot'
9 import { getSlide } from './slides'
10
11 const chromeVersion = window.navigator.userAgent.match(/Chrome\/(\d+)/)?.[1]
12 export const isScreenshotSupported = chromeVersion ? Number(chromeVersion) >= 94 : false
13
14 const initialWait = 100
15
16 export class SlideSnapshotManager {
17 private _screenshotSession: ScreenshotSession | null = null
18
19 getSnapshot(slideNo: number, isDark: boolean) {
20 const id = slideNo + (isDark ? '-dark' : '-light')
21 const data = snapshotState.state[id]
22 if (!data) {
23 return
24 }
25 const slide = getSlide(slideNo)
26 if (!slide) {
27 return
28 }
29 if (data?.revision === slide?.meta.slide.revision) {
30 return data.image
31 }
32 }
33
34 private async saveSnapshot(slideNo: number, dataUrl: string, isDark: boolean) {
35 if (!__DEV__)
36 return false
37 const slide = getSlide(slideNo)
38 if (!slide)
39 return false
40
41 const id = slideNo + (isDark ? '-dark' : '-light')
42 const revision = slide.meta.slide.revision
43 snapshotState.patch(id, {
44 revision,
45 image: dataUrl,
46 })
47 }
48
49 async startCapturing(nav: SlidevContextNavFull) {
50 if (!__DEV__)
51 return false
52
53 // TODO: show a dialog to confirm
54
55 if (this._screenshotSession) {
56 this._screenshotSession.dispose()
57 this._screenshotSession = null
58 }
59
60 try {
61 this._screenshotSession = await startScreenshotSession(
62 slideWidth.value,
63 slideHeight.value,
64 )
65
66 disableTransition.value = true
67 nav.go(1, 0, true)
68
69 await sleep(initialWait + captureDelay.value)
70 while (true) {
71 if (!this._screenshotSession) {
72 break
73 }
74 this.saveSnapshot(
75 nav.currentSlideNo.value,
76 this._screenshotSession.screenshot(document.getElementById('slide-content')!),
77 isDark.value,
78 )
79 if (nav.hasNext.value) {
80 await sleep(captureDelay.value)
81 nav.nextSlide(true)
82 await sleep(captureDelay.value)
83 }
84 else {
85 break
86 }
87 }
88
89 // TODO: show a message when done
90
91 return true
92 }
93 catch (e) {
94 console.error(e)
95 return false
96 }
97 finally {
98 disableTransition.value = false
99 if (this._screenshotSession) {
100 this._screenshotSession.dispose()
101 this._screenshotSession = null
102 }
103 }
104 }
105 }
106
107 export const snapshotManager = new SlideSnapshotManager()
108
108 lines TYPESCRIPT