@slidev/client 0.48.0-beta.8 → 0.48.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/App.vue +7 -0
- package/builtin/Arrow.vue +2 -4
- package/builtin/CodeBlockWrapper.vue +33 -28
- package/builtin/KaTexBlockWrapper.vue +1 -1
- package/builtin/Link.vue +3 -1
- package/builtin/Mermaid.vue +4 -3
- package/builtin/Monaco.vue +166 -93
- package/builtin/ShikiMagicMove.vue +103 -0
- package/builtin/SlidevVideo.vue +1 -1
- package/builtin/Toc.vue +1 -1
- package/builtin/TocList.vue +4 -3
- package/builtin/Tweet.vue +12 -9
- package/builtin/VClick.ts +2 -1
- package/composables/useClicks.ts +19 -32
- package/composables/useDarkMode.ts +9 -0
- package/composables/useDrawings.ts +181 -0
- package/composables/useNav.ts +346 -44
- package/{logic/note.ts → composables/useSlideInfo.ts} +13 -16
- package/composables/useSwipeControls.ts +43 -0
- package/composables/useTocTree.ts +81 -0
- package/composables/useViewTransition.ts +7 -4
- package/constants.ts +4 -3
- package/context.ts +13 -6
- package/env.ts +7 -16
- package/index.html +1 -0
- package/index.ts +12 -0
- package/internals/ClicksSlider.vue +93 -0
- package/internals/CodeRunner.vue +142 -0
- package/internals/Controls.vue +2 -2
- package/internals/DomElement.vue +18 -0
- package/internals/DrawingControls.vue +15 -17
- package/internals/DrawingLayer.vue +6 -5
- package/internals/DrawingPreview.vue +4 -2
- package/internals/Goto.vue +9 -6
- package/internals/IconButton.vue +7 -3
- package/internals/NavControls.vue +31 -12
- package/internals/NoteDisplay.vue +131 -8
- package/internals/NoteEditable.vue +129 -0
- package/internals/NoteStatic.vue +8 -6
- package/internals/PrintContainer.vue +11 -8
- package/internals/PrintSlide.vue +11 -12
- package/internals/PrintSlideClick.vue +14 -19
- package/internals/{SlidesOverview.vue → QuickOverview.vue} +35 -22
- package/internals/RecordingControls.vue +1 -1
- package/internals/RecordingDialog.vue +5 -6
- package/internals/{Editor.vue → SideEditor.vue} +26 -17
- package/internals/SlideContainer.vue +13 -9
- package/internals/SlideLoading.vue +19 -0
- package/internals/SlideWrapper.vue +79 -0
- package/internals/SlidesShow.vue +36 -22
- package/layouts/error.vue +5 -0
- package/layouts/two-cols-header.vue +9 -3
- package/logic/overview.ts +2 -2
- package/logic/route.ts +16 -5
- package/logic/slides.ts +20 -0
- package/logic/transition.ts +50 -0
- package/logic/utils.ts +24 -1
- package/main.ts +3 -15
- package/{setup → modules}/codemirror.ts +1 -3
- package/modules/context.ts +1 -46
- package/modules/mermaid.ts +9 -8
- package/package.json +21 -15
- package/{internals/EntrySelect.vue → pages/entry.vue} +7 -0
- package/{internals/NotesView.vue → pages/notes.vue} +9 -6
- package/pages/overview.vue +231 -0
- package/{internals/Play.vue → pages/play.vue} +22 -15
- package/{internals/PresenterPrint.vue → pages/presenter/print.vue} +15 -8
- package/{internals/Presenter.vue → pages/presenter.vue} +129 -107
- package/{internals/Print.vue → pages/print.vue} +6 -5
- package/routes.ts +26 -57
- package/setup/code-runners.ts +164 -0
- package/setup/main.ts +39 -9
- package/setup/mermaid.ts +5 -6
- package/setup/monaco.ts +114 -51
- package/setup/root.ts +62 -18
- package/setup/shortcuts.ts +15 -12
- package/shim-vue.d.ts +34 -0
- package/shim.d.ts +1 -13
- package/state/index.ts +2 -2
- package/styles/code.css +9 -5
- package/styles/index.css +63 -7
- package/styles/katex.css +1 -1
- package/styles/layouts-base.css +17 -12
- package/styles/shiki-twoslash.css +1 -1
- package/styles/vars.css +1 -0
- package/uno.config.ts +14 -2
- package/utils.ts +15 -2
- package/composables/useContext.ts +0 -17
- package/composables/useTweetScript.ts +0 -17
- package/iframes/monaco/index.css +0 -28
- package/iframes/monaco/index.html +0 -7
- package/iframes/monaco/index.ts +0 -260
- package/internals/NoteEditor.vue +0 -88
- package/internals/SlideWrapper.ts +0 -58
- package/logic/drawings.ts +0 -161
- package/logic/nav.ts +0 -278
- package/setup/prettier.ts +0 -43
- /package/{composables → logic}/hmr.ts +0 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { createSingletonPromise } from '@antfu/utils'
|
|
2
|
+
import type { CodeRunner, CodeRunnerContext, CodeRunnerOutput, CodeRunnerOutputText, CodeRunnerOutputs } from '@slidev/types'
|
|
3
|
+
import type { CodeToHastOptions } from 'shiki'
|
|
4
|
+
import { isDark } from '../logic/dark'
|
|
5
|
+
import setups from '#slidev/setups/code-runners'
|
|
6
|
+
|
|
7
|
+
export default createSingletonPromise(async () => {
|
|
8
|
+
const runners: Record<string, CodeRunner> = {
|
|
9
|
+
javascript: runJavaScript,
|
|
10
|
+
js: runJavaScript,
|
|
11
|
+
typescript: runTypeScript,
|
|
12
|
+
ts: runTypeScript,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { shiki, themes } = await import('#slidev/shiki')
|
|
16
|
+
const highlighter = await shiki
|
|
17
|
+
const highlight = (code: string, lang: string, options: Partial<CodeToHastOptions> = {}) => highlighter.codeToHtml(code, {
|
|
18
|
+
lang,
|
|
19
|
+
theme: typeof themes === 'string'
|
|
20
|
+
? themes
|
|
21
|
+
: isDark.value
|
|
22
|
+
? themes.dark || 'vitesse-dark'
|
|
23
|
+
: themes.light || 'vitesse-light',
|
|
24
|
+
...options,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const run = async (code: string, lang: string, options: Record<string, unknown>): Promise<CodeRunnerOutputs> => {
|
|
28
|
+
try {
|
|
29
|
+
const runner = runners[lang]
|
|
30
|
+
if (!runner)
|
|
31
|
+
throw new Error(`Runner for language "${lang}" not found`)
|
|
32
|
+
return await runner(
|
|
33
|
+
code,
|
|
34
|
+
{
|
|
35
|
+
options,
|
|
36
|
+
highlight,
|
|
37
|
+
run: async (code, lang) => {
|
|
38
|
+
return await run(code, lang, options)
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
console.error(e)
|
|
45
|
+
return {
|
|
46
|
+
error: `${e}`,
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
for (const setup of setups) {
|
|
52
|
+
const result = await setup(runners)
|
|
53
|
+
Object.assign(runners, result)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
highlight,
|
|
58
|
+
run,
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
// Ported from https://github.com/microsoft/TypeScript-Website/blob/v2/packages/playground/src/sidebar/runtime.ts
|
|
63
|
+
export async function runJavaScript(code: string): Promise<CodeRunnerOutputs> {
|
|
64
|
+
const allLogs: CodeRunnerOutput[] = []
|
|
65
|
+
|
|
66
|
+
const replace = {} as any
|
|
67
|
+
const logger = function (...objs: any[]) {
|
|
68
|
+
allLogs.push(objs.map(printObject))
|
|
69
|
+
}
|
|
70
|
+
replace.info = replace.log = replace.debug = replace.warn = replace.error = logger
|
|
71
|
+
replace.clear = () => allLogs.length = 0
|
|
72
|
+
const vmConsole = Object.assign({}, console, replace)
|
|
73
|
+
try {
|
|
74
|
+
const safeJS = `return async (console) => {${sanitizeJS(code)}}`
|
|
75
|
+
// eslint-disable-next-line no-new-func
|
|
76
|
+
await (new Function(safeJS)())(vmConsole)
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return {
|
|
80
|
+
error: `ERROR: ${error}`,
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function printObject(arg: any): CodeRunnerOutputText {
|
|
85
|
+
if (typeof arg === 'string') {
|
|
86
|
+
return {
|
|
87
|
+
text: arg,
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
text: objectToText(arg),
|
|
92
|
+
highlightLang: 'javascript',
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function objectToText(arg: any): string {
|
|
97
|
+
let textRep = ''
|
|
98
|
+
if (arg instanceof Error) {
|
|
99
|
+
textRep = `Error: ${JSON.stringify(arg.message)}`
|
|
100
|
+
}
|
|
101
|
+
else if (arg === null || arg === undefined || typeof arg === 'symbol') {
|
|
102
|
+
textRep = String(arg)
|
|
103
|
+
}
|
|
104
|
+
else if (Array.isArray(arg)) {
|
|
105
|
+
textRep = `[${arg.map(objectToText).join(', ')}]`
|
|
106
|
+
}
|
|
107
|
+
else if (arg instanceof Set) {
|
|
108
|
+
const setIter = [...arg]
|
|
109
|
+
textRep = `Set (${arg.size}) {${setIter.map(objectToText).join(', ')}}`
|
|
110
|
+
}
|
|
111
|
+
else if (arg instanceof Map) {
|
|
112
|
+
const mapIter = [...arg.entries()]
|
|
113
|
+
textRep
|
|
114
|
+
= `Map (${arg.size}) {${mapIter
|
|
115
|
+
.map(([k, v]) => `${objectToText(k)} => ${objectToText(v)}`)
|
|
116
|
+
.join(', ')
|
|
117
|
+
}}`
|
|
118
|
+
}
|
|
119
|
+
else if (arg instanceof RegExp) {
|
|
120
|
+
textRep = arg.toString()
|
|
121
|
+
}
|
|
122
|
+
else if (typeof arg === 'string') {
|
|
123
|
+
textRep = JSON.stringify(arg)
|
|
124
|
+
}
|
|
125
|
+
else if (typeof arg === 'object') {
|
|
126
|
+
const name = arg.constructor?.name ?? ''
|
|
127
|
+
// No one needs to know an obj is an obj
|
|
128
|
+
const nameWithoutObject = name && name === 'Object' ? '' : name
|
|
129
|
+
const prefix = nameWithoutObject ? `${nameWithoutObject}: ` : ''
|
|
130
|
+
|
|
131
|
+
// JSON.stringify omits any keys with a value of undefined. To get around this, we replace undefined with the text __undefined__ and then do a global replace using regex back to keyword undefined
|
|
132
|
+
textRep
|
|
133
|
+
= prefix
|
|
134
|
+
+ JSON.stringify(arg, (_, value) => (value === undefined ? '__undefined__' : value), 2).replace(
|
|
135
|
+
/"__undefined__"/g,
|
|
136
|
+
'undefined',
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
textRep = String(textRep)
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
textRep = String(arg)
|
|
143
|
+
}
|
|
144
|
+
return textRep
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// The reflect-metadata runtime is available, so allow that to go through
|
|
148
|
+
function sanitizeJS(code: string) {
|
|
149
|
+
return code.replace(`import "reflect-metadata"`, '').replace(`require("reflect-metadata")`, '')
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return allLogs
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let tsModule: typeof import('typescript') | undefined
|
|
156
|
+
|
|
157
|
+
export async function runTypeScript(code: string, context: CodeRunnerContext) {
|
|
158
|
+
const { transpile } = tsModule ??= await import('typescript')
|
|
159
|
+
code = transpile(code, {
|
|
160
|
+
module: tsModule.ModuleKind.ESNext,
|
|
161
|
+
target: tsModule.ScriptTarget.ES2022,
|
|
162
|
+
})
|
|
163
|
+
return await context.run(code, 'javascript')
|
|
164
|
+
}
|
package/setup/main.ts
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
|
-
/* __imports__ */
|
|
2
|
-
|
|
3
1
|
import type { AppContext } from '@slidev/types'
|
|
4
2
|
import { MotionPlugin } from '@vueuse/motion'
|
|
5
3
|
import TwoSlashFloatingVue from '@shikijs/vitepress-twoslash/client'
|
|
4
|
+
import type { App } from 'vue'
|
|
5
|
+
import { nextTick } from 'vue'
|
|
6
|
+
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
|
|
7
|
+
import { createHead } from '@unhead/vue'
|
|
8
|
+
import { routeForceRefresh } from '../logic/route'
|
|
9
|
+
import { createVClickDirectives } from '../modules/v-click'
|
|
10
|
+
import { createVMarkDirective } from '../modules/v-mark'
|
|
11
|
+
import { routes } from '../routes'
|
|
12
|
+
import setups from '#slidev/setups/main'
|
|
13
|
+
|
|
14
|
+
import '#slidev/styles'
|
|
15
|
+
import 'shiki-magic-move/style.css'
|
|
6
16
|
|
|
7
|
-
export default function setupMain(
|
|
17
|
+
export default async function setupMain(app: App) {
|
|
8
18
|
function setMaxHeight() {
|
|
9
19
|
// disable the mobile navbar scroll
|
|
10
20
|
// see https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
|
|
@@ -13,12 +23,32 @@ export default function setupMain(context: AppContext) {
|
|
|
13
23
|
setMaxHeight()
|
|
14
24
|
window.addEventListener('resize', setMaxHeight)
|
|
15
25
|
|
|
16
|
-
|
|
17
|
-
|
|
26
|
+
const router = createRouter({
|
|
27
|
+
history: __SLIDEV_HASH_ROUTE__
|
|
28
|
+
? createWebHashHistory(import.meta.env.BASE_URL)
|
|
29
|
+
: createWebHistory(import.meta.env.BASE_URL),
|
|
30
|
+
routes,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
app.use(router)
|
|
34
|
+
app.use(createHead())
|
|
35
|
+
app.use(createVClickDirectives())
|
|
36
|
+
app.use(createVMarkDirective())
|
|
37
|
+
app.use(MotionPlugin)
|
|
38
|
+
app.use(TwoSlashFloatingVue as any, { container: '#slideshow' })
|
|
39
|
+
|
|
40
|
+
const context: AppContext = {
|
|
41
|
+
app,
|
|
42
|
+
router,
|
|
43
|
+
}
|
|
18
44
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
45
|
+
nextTick(() => {
|
|
46
|
+
router.afterEach(async () => {
|
|
47
|
+
await nextTick()
|
|
48
|
+
routeForceRefresh.value += 1
|
|
49
|
+
})
|
|
50
|
+
})
|
|
22
51
|
|
|
23
|
-
|
|
52
|
+
for (const setup of setups)
|
|
53
|
+
await setup(context)
|
|
24
54
|
}
|
package/setup/mermaid.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
/* __imports__ */
|
|
2
|
-
|
|
3
1
|
import type { MermaidOptions } from '@slidev/types'
|
|
4
2
|
import { defineMermaidSetup } from '@slidev/types'
|
|
3
|
+
import setups from '#slidev/setups/mermaid'
|
|
5
4
|
|
|
6
5
|
export default defineMermaidSetup(() => {
|
|
7
|
-
|
|
8
|
-
let injection_return: MermaidOptions = {
|
|
6
|
+
const setupReturn: MermaidOptions = {
|
|
9
7
|
theme: 'default',
|
|
10
8
|
}
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
for (const setup of setups)
|
|
11
|
+
Object.assign(setupReturn, setup())
|
|
13
12
|
|
|
14
|
-
return
|
|
13
|
+
return setupReturn
|
|
15
14
|
})
|
package/setup/monaco.ts
CHANGED
|
@@ -1,70 +1,133 @@
|
|
|
1
|
-
import { getCurrentInstance, onMounted } from 'vue'
|
|
2
|
-
import * as monaco from 'monaco-editor'
|
|
3
1
|
import { createSingletonPromise } from '@antfu/utils'
|
|
4
2
|
import type { MonacoSetupReturn } from '@slidev/types'
|
|
3
|
+
import * as monaco from 'monaco-editor'
|
|
4
|
+
import { watchEffect } from 'vue'
|
|
5
|
+
import { setupTypeAcquisition } from '@typescript/ata'
|
|
6
|
+
import ts from 'typescript'
|
|
7
|
+
|
|
8
|
+
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
|
|
9
|
+
import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
|
|
10
|
+
import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
|
|
11
|
+
import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
|
|
12
|
+
import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
|
|
13
|
+
|
|
14
|
+
// @ts-expect-error missing types
|
|
15
|
+
import { ContextViewService } from 'monaco-editor/esm/vs/platform/contextview/browser/contextViewService'
|
|
16
|
+
|
|
17
|
+
// @ts-expect-error missing types
|
|
18
|
+
import { SyncDescriptor } from 'monaco-editor/esm/vs/platform/instantiation/common/descriptors'
|
|
5
19
|
|
|
6
|
-
|
|
20
|
+
// @ts-expect-error missing types
|
|
21
|
+
import { StandaloneServices } from 'monaco-editor/esm/vs/editor/standalone/browser/standaloneServices'
|
|
22
|
+
|
|
23
|
+
import { isDark } from '../logic/dark'
|
|
24
|
+
import configs from '#slidev/configs'
|
|
25
|
+
import setups from '#slidev/setups/monaco'
|
|
26
|
+
|
|
27
|
+
window.MonacoEnvironment = {
|
|
28
|
+
getWorker(_, label) {
|
|
29
|
+
if (label === 'json')
|
|
30
|
+
return new JsonWorker()
|
|
31
|
+
if (label === 'css' || label === 'scss' || label === 'less')
|
|
32
|
+
return new CssWorker()
|
|
33
|
+
if (label === 'html' || label === 'handlebars' || label === 'razor')
|
|
34
|
+
return new HtmlWorker()
|
|
35
|
+
if (label === 'typescript' || label === 'javascript')
|
|
36
|
+
return new TsWorker()
|
|
37
|
+
return new EditorWorker()
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class ContextViewService2 extends ContextViewService {
|
|
42
|
+
showContextView(...args: any) {
|
|
43
|
+
super.showContextView(...args)
|
|
44
|
+
// @ts-expect-error missing types
|
|
45
|
+
const contextView = this.contextView.view as HTMLElement
|
|
46
|
+
contextView.style.left = `calc(${contextView.style.left} / var(--slidev-slide-scale))`
|
|
47
|
+
contextView.style.top = `calc(${contextView.style.top} / var(--slidev-slide-scale))`
|
|
48
|
+
// Reset the scale to 1. Otherwise, the sub-menu will be in the wrong position.
|
|
49
|
+
contextView.style.transform = `scale(calc(1 / var(--slidev-slide-scale)))`
|
|
50
|
+
contextView.style.transformOrigin = '0 0'
|
|
51
|
+
}
|
|
52
|
+
}
|
|
7
53
|
|
|
8
54
|
const setup = createSingletonPromise(async () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
55
|
+
// Initialize services first, otherwise we can't override them.
|
|
56
|
+
StandaloneServices.initialize({
|
|
57
|
+
contextViewService: new SyncDescriptor(ContextViewService2, [], true),
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const defaults = monaco.languages.typescript.typescriptDefaults
|
|
61
|
+
|
|
62
|
+
defaults.setCompilerOptions({
|
|
63
|
+
...defaults.getCompilerOptions(),
|
|
15
64
|
strict: true,
|
|
65
|
+
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
|
|
66
|
+
module: monaco.languages.typescript.ModuleKind.ESNext,
|
|
16
67
|
})
|
|
17
68
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
import('monaco-editor/esm/vs/language/typescript/ts.worker?worker'),
|
|
33
|
-
])
|
|
34
|
-
|
|
35
|
-
window.MonacoEnvironment = {
|
|
36
|
-
getWorker(_: any, label: string) {
|
|
37
|
-
if (label === 'json')
|
|
38
|
-
return new JsonWorker()
|
|
39
|
-
if (label === 'css' || label === 'scss' || label === 'less')
|
|
40
|
-
return new CssWorker()
|
|
41
|
-
if (label === 'html' || label === 'handlebars' || label === 'razor')
|
|
42
|
-
return new HtmlWorker()
|
|
43
|
-
if (label === 'typescript' || label === 'javascript')
|
|
44
|
-
return new TsWorker()
|
|
45
|
-
return new EditorWorker()
|
|
69
|
+
// Load types from server
|
|
70
|
+
import('#slidev/monaco-types')
|
|
71
|
+
|
|
72
|
+
const ata = configs.monacoTypesSource === 'cdn'
|
|
73
|
+
? setupTypeAcquisition({
|
|
74
|
+
projectName: 'TypeScript Playground',
|
|
75
|
+
typescript: ts as any, // Version mismatch. No problem found so far.
|
|
76
|
+
logger: console,
|
|
77
|
+
delegate: {
|
|
78
|
+
receivedFile: (code: string, path: string) => {
|
|
79
|
+
defaults.addExtraLib(code, `file://${path}`)
|
|
80
|
+
const uri = monaco.Uri.file(path)
|
|
81
|
+
if (monaco.editor.getModel(uri) === null)
|
|
82
|
+
monaco.editor.createModel(code, 'javascript', uri)
|
|
46
83
|
},
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
84
|
+
progress: (downloaded: number, total: number) => {
|
|
85
|
+
// eslint-disable-next-line no-console
|
|
86
|
+
console.debug(`[Typescript ATA] ${downloaded} / ${total}`)
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
: () => { }
|
|
91
|
+
|
|
92
|
+
monaco.languages.register({ id: 'vue' })
|
|
93
|
+
monaco.languages.register({ id: 'html' })
|
|
94
|
+
monaco.languages.register({ id: 'css' })
|
|
95
|
+
monaco.languages.register({ id: 'typescript' })
|
|
96
|
+
monaco.languages.register({ id: 'javascript' })
|
|
50
97
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const injection_arg = monaco
|
|
54
|
-
// eslint-disable-next-line prefer-const
|
|
55
|
-
let injection_return: MonacoSetupReturn = {}
|
|
98
|
+
const { shiki, themes, shikiToMonaco } = await import('#slidev/shiki')
|
|
99
|
+
const highlighter = await shiki
|
|
56
100
|
|
|
57
|
-
|
|
101
|
+
const setupReturn: MonacoSetupReturn = {}
|
|
102
|
+
for (const setup of setups) {
|
|
103
|
+
const result = await setup(monaco)
|
|
104
|
+
Object.assign(setupReturn, result)
|
|
105
|
+
}
|
|
58
106
|
|
|
59
|
-
|
|
60
|
-
|
|
107
|
+
// Use Shiki to highlight Monaco
|
|
108
|
+
shikiToMonaco(highlighter, monaco)
|
|
109
|
+
if (typeof themes === 'string') {
|
|
110
|
+
monaco.editor.setTheme(themes)
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
watchEffect(() => {
|
|
114
|
+
monaco.editor.setTheme(isDark.value
|
|
115
|
+
? themes.dark || 'vitesse-dark'
|
|
116
|
+
: themes.light || 'vitesse-light')
|
|
117
|
+
})
|
|
118
|
+
}
|
|
61
119
|
|
|
62
120
|
return {
|
|
63
121
|
monaco,
|
|
64
|
-
|
|
122
|
+
ata,
|
|
123
|
+
...setupReturn,
|
|
65
124
|
}
|
|
66
125
|
})
|
|
67
126
|
|
|
68
|
-
export default
|
|
127
|
+
export async function addFile(raw: Promise<{ default: string }>, path: string) {
|
|
128
|
+
const code = (await raw).default
|
|
129
|
+
monaco.languages.typescript.typescriptDefaults.addExtraLib(code, `file:///${path}`)
|
|
130
|
+
monaco.editor.createModel(code, 'javascript', monaco.Uri.file(path))
|
|
131
|
+
}
|
|
69
132
|
|
|
70
|
-
setup
|
|
133
|
+
export default setup
|
package/setup/root.ts
CHANGED
|
@@ -1,31 +1,75 @@
|
|
|
1
|
-
|
|
2
|
-
import { watch } from 'vue'
|
|
1
|
+
import { computed, getCurrentInstance, reactive, ref, shallowRef, watch } from 'vue'
|
|
3
2
|
import { useHead } from '@unhead/vue'
|
|
4
|
-
import {
|
|
3
|
+
import { useRouter } from 'vue-router'
|
|
5
4
|
import { configs } from '../env'
|
|
6
5
|
import { initSharedState, onPatch, patch } from '../state/shared'
|
|
7
6
|
import { initDrawingState } from '../state/drawings'
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
7
|
+
import { TRUST_ORIGINS, injectionClicksContext, injectionCurrentPage, injectionRenderContext, injectionSlidevContext } from '../constants'
|
|
8
|
+
import { skipTransition } from '../logic/hmr'
|
|
9
|
+
import { makeId } from '../logic/utils'
|
|
10
|
+
import { getSlidePath } from '../logic/slides'
|
|
11
|
+
import { createFixedClicks } from '../composables/useClicks'
|
|
12
|
+
import { isDark } from '../logic/dark'
|
|
13
|
+
import { useNav } from '../composables/useNav'
|
|
14
|
+
import setups from '#slidev/setups/root'
|
|
12
15
|
|
|
13
16
|
export default function setupRoot() {
|
|
14
|
-
|
|
15
|
-
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
16
|
-
const injection_arg = undefined
|
|
17
|
+
const app = getCurrentInstance()!.appContext.app
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
const context = reactive({
|
|
20
|
+
nav: useNav(),
|
|
21
|
+
configs,
|
|
22
|
+
themeConfigs: computed(() => configs.themeConfig),
|
|
23
|
+
})
|
|
24
|
+
app.provide(injectionRenderContext, ref('none'))
|
|
25
|
+
app.provide(injectionSlidevContext, context)
|
|
26
|
+
app.provide(injectionCurrentPage, computed(() => context.nav.currentSlideNo))
|
|
27
|
+
app.provide(injectionClicksContext, shallowRef(createFixedClicks()))
|
|
28
|
+
|
|
29
|
+
// allows controls from postMessages
|
|
30
|
+
if (__DEV__) {
|
|
31
|
+
// @ts-expect-error expose global
|
|
32
|
+
window.__slidev__ = context
|
|
33
|
+
window.addEventListener('message', ({ data }) => {
|
|
34
|
+
if (data && data.target === 'slidev') {
|
|
35
|
+
if (data.type === 'navigate') {
|
|
36
|
+
context.nav.go(+data.no, +data.clicks || 0)
|
|
37
|
+
}
|
|
38
|
+
else if (data.type === 'css-vars') {
|
|
39
|
+
const root = document.documentElement
|
|
40
|
+
for (const [key, value] of Object.entries(data.vars || {}))
|
|
41
|
+
root.style.setProperty(key, value as any)
|
|
42
|
+
}
|
|
43
|
+
else if (data.type === 'color-schema') {
|
|
44
|
+
isDark.value = data.color === 'dark'
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// User Setups
|
|
51
|
+
for (const setup of setups)
|
|
52
|
+
setup()
|
|
19
53
|
|
|
20
54
|
const title = configs.titleTemplate.replace('%s', configs.title || 'Slidev')
|
|
55
|
+
|
|
56
|
+
const {
|
|
57
|
+
clicksContext,
|
|
58
|
+
currentSlideNo,
|
|
59
|
+
hasPrimarySlide,
|
|
60
|
+
isNotesViewer,
|
|
61
|
+
isPresenter,
|
|
62
|
+
} = useNav()
|
|
63
|
+
|
|
21
64
|
useHead({
|
|
22
65
|
title,
|
|
23
66
|
htmlAttrs: configs.htmlAttrs,
|
|
24
67
|
})
|
|
68
|
+
|
|
25
69
|
initSharedState(`${title} - shared`)
|
|
26
70
|
initDrawingState(`${title} - drawings`)
|
|
27
71
|
|
|
28
|
-
const id = `${location.origin}_${
|
|
72
|
+
const id = `${location.origin}_${makeId()}`
|
|
29
73
|
|
|
30
74
|
// update shared state
|
|
31
75
|
function updateSharedState() {
|
|
@@ -37,11 +81,11 @@ export default function setupRoot() {
|
|
|
37
81
|
return
|
|
38
82
|
|
|
39
83
|
if (isPresenter.value) {
|
|
40
|
-
patch('page', +
|
|
84
|
+
patch('page', +currentSlideNo.value)
|
|
41
85
|
patch('clicks', clicksContext.value.current)
|
|
42
86
|
}
|
|
43
87
|
else {
|
|
44
|
-
patch('viewerPage', +
|
|
88
|
+
patch('viewerPage', +currentSlideNo.value)
|
|
45
89
|
patch('viewerClicks', clicksContext.value.current)
|
|
46
90
|
}
|
|
47
91
|
|
|
@@ -51,17 +95,17 @@ export default function setupRoot() {
|
|
|
51
95
|
time: new Date().getTime(),
|
|
52
96
|
})
|
|
53
97
|
}
|
|
98
|
+
const router = useRouter()
|
|
54
99
|
router.afterEach(updateSharedState)
|
|
55
100
|
watch(clicksContext, updateSharedState)
|
|
56
101
|
|
|
57
102
|
onPatch((state) => {
|
|
58
|
-
|
|
59
|
-
if (!routePath.match(/^\/(\d+|presenter)\/?/))
|
|
103
|
+
if (!hasPrimarySlide.value)
|
|
60
104
|
return
|
|
61
|
-
if (state.lastUpdate?.type === 'presenter' && (+state.page !== +
|
|
105
|
+
if (state.lastUpdate?.type === 'presenter' && (+state.page !== +currentSlideNo.value || +clicksContext.value.current !== +state.clicks)) {
|
|
62
106
|
skipTransition.value = false
|
|
63
107
|
router.replace({
|
|
64
|
-
path:
|
|
108
|
+
path: getSlidePath(state.page, isPresenter.value),
|
|
65
109
|
query: {
|
|
66
110
|
...router.currentRoute.value.query,
|
|
67
111
|
clicks: state.clicks || 0,
|
package/setup/shortcuts.ts
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
/* __imports__ */
|
|
2
1
|
import { and, not, or } from '@vueuse/math'
|
|
3
2
|
import type { NavOperations, ShortcutOptions } from '@slidev/types'
|
|
4
|
-
import { downloadPDF
|
|
3
|
+
import { downloadPDF } from '../utils'
|
|
5
4
|
import { toggleDark } from '../logic/dark'
|
|
6
5
|
import { magicKeys, showGotoDialog, showOverview, toggleOverview } from '../state'
|
|
7
|
-
import {
|
|
6
|
+
import { useNav } from '../composables/useNav'
|
|
7
|
+
import { useDrawings } from '../composables/useDrawings'
|
|
8
8
|
import { currentOverviewPage, downOverviewPage, nextOverviewPage, prevOverviewPage, upOverviewPage } from './../logic/overview'
|
|
9
|
+
import setups from '#slidev/setups/shortcuts'
|
|
9
10
|
|
|
10
11
|
export default function setupShortcuts() {
|
|
12
|
+
const { go, goFirst, goLast, next, nextSlide, prev, prevSlide } = useNav()
|
|
13
|
+
const { drawingEnabled } = useDrawings()
|
|
11
14
|
const { escape, space, shift, left, right, up, down, enter, d, g, o, '`': backtick } = magicKeys
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
15
|
-
const injection_arg: NavOperations = {
|
|
16
|
+
const context: NavOperations = {
|
|
16
17
|
next,
|
|
17
18
|
prev,
|
|
18
19
|
nextSlide,
|
|
@@ -28,8 +29,7 @@ export default function setupShortcuts() {
|
|
|
28
29
|
showGotoDialog: () => showGotoDialog.value = !showGotoDialog.value,
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
let injection_return: ShortcutOptions[] = [
|
|
32
|
+
let shortcuts: ShortcutOptions[] = [
|
|
33
33
|
{ name: 'next_space', key: and(space, not(shift)), fn: next, autoRepeat: true },
|
|
34
34
|
{ name: 'prev_space', key: and(space, shift), fn: prev, autoRepeat: true },
|
|
35
35
|
{ name: 'next_right', key: and(right, not(shift), not(showOverview)), fn: next, autoRepeat: true },
|
|
@@ -58,11 +58,14 @@ export default function setupShortcuts() {
|
|
|
58
58
|
},
|
|
59
59
|
]
|
|
60
60
|
|
|
61
|
-
const baseShortcutNames = new Set(
|
|
61
|
+
const baseShortcutNames = new Set(shortcuts.map(s => s.name))
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
for (const setup of setups) {
|
|
64
|
+
const result = setup(context, shortcuts)
|
|
65
|
+
shortcuts = shortcuts.concat(result)
|
|
66
|
+
}
|
|
64
67
|
|
|
65
|
-
const remainingBaseShortcutNames =
|
|
68
|
+
const remainingBaseShortcutNames = shortcuts.filter(s => s.name && baseShortcutNames.has(s.name))
|
|
66
69
|
if (remainingBaseShortcutNames.length === 0) {
|
|
67
70
|
const message = [
|
|
68
71
|
'========== WARNING ==========',
|
|
@@ -76,5 +79,5 @@ export default function setupShortcuts() {
|
|
|
76
79
|
console.warn(message)
|
|
77
80
|
}
|
|
78
81
|
|
|
79
|
-
return
|
|
82
|
+
return shortcuts
|
|
80
83
|
}
|
package/shim-vue.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
declare module 'vue' {
|
|
2
|
+
type SlideContext = import('./context').SlideContext
|
|
3
|
+
interface ComponentCustomProperties extends SlideContext {
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
declare module 'vue-router' {
|
|
8
|
+
import type { TransitionGroupProps } from 'vue'
|
|
9
|
+
|
|
10
|
+
interface RouteMeta {
|
|
11
|
+
// inherited from frontmatter
|
|
12
|
+
layout: string
|
|
13
|
+
name?: string
|
|
14
|
+
class?: string
|
|
15
|
+
clicks?: number
|
|
16
|
+
transition?: string | TransitionGroupProps | undefined
|
|
17
|
+
preload?: boolean
|
|
18
|
+
|
|
19
|
+
// slide info
|
|
20
|
+
slide?: Omit<import('@slidev/types').SlideInfo, 'source'> & {
|
|
21
|
+
noteHTML: string
|
|
22
|
+
filepath: string
|
|
23
|
+
start: number
|
|
24
|
+
id: number
|
|
25
|
+
no: number
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// private fields
|
|
29
|
+
__clicksContext: import('@slidev/types').ClicksContext | undefined
|
|
30
|
+
__preloaded?: boolean
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export {}
|
package/shim.d.ts
CHANGED
|
@@ -1,23 +1,11 @@
|
|
|
1
|
-
declare interface Window {
|
|
2
|
-
// extend the window
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
declare module '*.vue';
|
|
6
|
-
|
|
7
|
-
// with unplugin-vue-markdown, markdowns can be treat as Vue components
|
|
8
1
|
declare module '*.md' {
|
|
2
|
+
// with unplugin-vue-markdown, markdowns can be treat as Vue components
|
|
9
3
|
import type { ComponentOptions } from 'vue'
|
|
10
4
|
|
|
11
5
|
const component: ComponentOptions
|
|
12
6
|
export default component
|
|
13
7
|
}
|
|
14
8
|
|
|
15
|
-
declare module '/@slidev/configs' {
|
|
16
|
-
import { SlidevConfig } from '@slidev/types'
|
|
17
|
-
|
|
18
|
-
export default SlidevConfig
|
|
19
|
-
}
|
|
20
|
-
|
|
21
9
|
declare module 'mermaid/dist/mermaid.esm.mjs' {
|
|
22
10
|
import Mermaid from 'mermaid/dist/mermaid.d.ts'
|
|
23
11
|
|