@slidev/client 0.48.0-beta.9 → 0.48.1
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 +97 -0
- package/internals/CodeRunner.vue +142 -0
- package/internals/Controls.vue +2 -2
- package/internals/DomElement.vue +18 -0
- package/internals/DrawingControls.vue +14 -15
- package/internals/DrawingLayer.vue +6 -5
- package/internals/DrawingPreview.vue +4 -2
- package/internals/Goto.vue +9 -6
- package/internals/IconButton.vue +3 -2
- package/internals/NavControls.vue +30 -11
- package/internals/NoteDisplay.vue +131 -8
- package/internals/NoteEditable.vue +129 -0
- package/internals/NoteStatic.vue +5 -2
- package/internals/PrintContainer.vue +11 -8
- package/internals/PrintSlide.vue +11 -12
- package/internals/PrintSlideClick.vue +14 -19
- package/internals/{SlidesOverview.vue → QuickOverview.vue} +27 -24
- package/internals/RecordingControls.vue +1 -1
- package/internals/RecordingDialog.vue +3 -3
- package/internals/{Editor.vue → SideEditor.vue} +24 -15
- 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/pages/notes.vue +6 -3
- package/pages/overview.vue +139 -51
- package/pages/play.vue +16 -9
- package/pages/presenter/print.vue +10 -5
- package/pages/presenter.vue +122 -104
- package/pages/print.vue +4 -3
- package/routes.ts +8 -54
- 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 +11 -8
- package/styles/shiki-twoslash.css +1 -1
- package/styles/vars.css +1 -1
- package/uno.config.ts +10 -1
- 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 -92
- 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
package/App.vue
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { watchEffect } from 'vue'
|
|
3
|
+
import { themeVars } from './env'
|
|
2
4
|
import setupRoot from './setup/root'
|
|
3
5
|
|
|
4
6
|
setupRoot()
|
|
7
|
+
|
|
8
|
+
watchEffect(() => {
|
|
9
|
+
for (const [key, value] of Object.entries(themeVars.value))
|
|
10
|
+
document.body.style.setProperty(key, value.toString())
|
|
11
|
+
})
|
|
5
12
|
</script>
|
|
6
13
|
|
|
7
14
|
<template>
|
package/builtin/Arrow.vue
CHANGED
|
@@ -9,7 +9,7 @@ Simple Arrow
|
|
|
9
9
|
-->
|
|
10
10
|
|
|
11
11
|
<script setup lang="ts">
|
|
12
|
-
import {
|
|
12
|
+
import { makeId } from '../logic/utils'
|
|
13
13
|
|
|
14
14
|
defineProps<{
|
|
15
15
|
x1: number | string
|
|
@@ -20,9 +20,7 @@ defineProps<{
|
|
|
20
20
|
color?: string
|
|
21
21
|
}>()
|
|
22
22
|
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
const id = nanoid()
|
|
23
|
+
const id = makeId()
|
|
26
24
|
</script>
|
|
27
25
|
|
|
28
26
|
<template>
|
|
@@ -12,13 +12,12 @@ Learn more: https://sli.dev/guide/syntax.html#line-highlighting
|
|
|
12
12
|
-->
|
|
13
13
|
|
|
14
14
|
<script setup lang="ts">
|
|
15
|
-
import { parseRangeString } from '@slidev/parser/core'
|
|
16
15
|
import { useClipboard } from '@vueuse/core'
|
|
17
16
|
import { computed, onMounted, onUnmounted, ref, watchEffect } from 'vue'
|
|
18
17
|
import type { PropType } from 'vue'
|
|
19
18
|
import { configs } from '../env'
|
|
20
|
-
import { makeId } from '../logic/utils'
|
|
21
|
-
import { CLASS_VCLICK_HIDDEN
|
|
19
|
+
import { makeId, updateCodeHighlightRange } from '../logic/utils'
|
|
20
|
+
import { CLASS_VCLICK_HIDDEN } from '../constants'
|
|
22
21
|
import { useSlideContext } from '../context'
|
|
23
22
|
|
|
24
23
|
const props = defineProps({
|
|
@@ -56,8 +55,12 @@ onUnmounted(() => {
|
|
|
56
55
|
clicks!.unregister(id)
|
|
57
56
|
})
|
|
58
57
|
|
|
58
|
+
watchEffect(() => {
|
|
59
|
+
el.value?.classList.toggle('slidev-code-line-numbers', props.lines)
|
|
60
|
+
})
|
|
61
|
+
|
|
59
62
|
onMounted(() => {
|
|
60
|
-
if (!clicks || clicks.disabled)
|
|
63
|
+
if (!clicks || clicks.disabled || !props.ranges?.length)
|
|
61
64
|
return
|
|
62
65
|
|
|
63
66
|
const { start, end, delta } = clicks.resolve(props.at, props.ranges.length - 1)
|
|
@@ -83,28 +86,27 @@ onMounted(() => {
|
|
|
83
86
|
if (hide)
|
|
84
87
|
rangeStr = props.ranges[index.value + 1] ?? finallyRange.value
|
|
85
88
|
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
89
|
+
const pre = el.value.querySelector('.shiki')!
|
|
90
|
+
const lines = Array.from(pre.querySelectorAll('code > .line'))
|
|
91
|
+
const linesCount = lines.length
|
|
92
|
+
|
|
93
|
+
updateCodeHighlightRange(
|
|
94
|
+
rangeStr,
|
|
95
|
+
linesCount,
|
|
96
|
+
props.startLine,
|
|
97
|
+
no => [lines[no]],
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
// Scroll to the highlighted line if `maxHeight` is set
|
|
101
|
+
if (props.maxHeight) {
|
|
102
|
+
const highlightedEls = Array.from(pre.querySelectorAll('.line.highlighted')) as HTMLElement[]
|
|
103
|
+
const height = highlightedEls.reduce((acc, el) => el.offsetHeight + acc, 0)
|
|
104
|
+
if (height > el.value.offsetHeight) {
|
|
105
|
+
highlightedEls[0].scrollIntoView({ behavior: 'smooth', block: 'start' })
|
|
106
|
+
}
|
|
107
|
+
else if (highlightedEls.length > 0) {
|
|
108
|
+
const middleEl = highlightedEls[Math.round((highlightedEls.length - 1) / 2)]
|
|
109
|
+
middleEl.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
})
|
|
@@ -121,9 +123,12 @@ function copyCode() {
|
|
|
121
123
|
|
|
122
124
|
<template>
|
|
123
125
|
<div
|
|
124
|
-
ref="el"
|
|
126
|
+
ref="el"
|
|
127
|
+
class="slidev-code-wrapper relative group"
|
|
128
|
+
:class="{
|
|
125
129
|
'slidev-code-line-numbers': props.lines,
|
|
126
|
-
}"
|
|
130
|
+
}"
|
|
131
|
+
:style="{
|
|
127
132
|
'max-height': props.maxHeight,
|
|
128
133
|
'overflow-y': props.maxHeight ? 'scroll' : undefined,
|
|
129
134
|
'--start': props.startLine,
|
package/builtin/Link.vue
CHANGED
|
@@ -8,12 +8,14 @@ Usage:
|
|
|
8
8
|
<Link :to="5" title="Go to slide 5" />
|
|
9
9
|
-->
|
|
10
10
|
<script setup lang="ts">
|
|
11
|
-
import {
|
|
11
|
+
import { useNav } from '../composables/useNav'
|
|
12
12
|
|
|
13
13
|
defineProps<{
|
|
14
14
|
to: number | string
|
|
15
15
|
title?: string
|
|
16
16
|
}>()
|
|
17
|
+
|
|
18
|
+
const { isPrintMode } = useNav()
|
|
17
19
|
</script>
|
|
18
20
|
|
|
19
21
|
<template>
|
package/builtin/Mermaid.vue
CHANGED
|
@@ -19,7 +19,7 @@ import ShadowRoot from '../internals/ShadowRoot.vue'
|
|
|
19
19
|
import { isDark } from '../logic/dark'
|
|
20
20
|
|
|
21
21
|
const props = defineProps<{
|
|
22
|
-
|
|
22
|
+
codeLz: string
|
|
23
23
|
scale?: number
|
|
24
24
|
theme?: string
|
|
25
25
|
}>()
|
|
@@ -37,7 +37,7 @@ watchEffect(async (onCleanup) => {
|
|
|
37
37
|
error.value = null
|
|
38
38
|
try {
|
|
39
39
|
const svg = await renderMermaid(
|
|
40
|
-
props.
|
|
40
|
+
props.codeLz || '',
|
|
41
41
|
{
|
|
42
42
|
theme: props.theme || (isDark.value ? 'dark' : undefined),
|
|
43
43
|
...vm!.attrs,
|
|
@@ -48,6 +48,7 @@ watchEffect(async (onCleanup) => {
|
|
|
48
48
|
}
|
|
49
49
|
catch (e) {
|
|
50
50
|
error.value = `${e}`
|
|
51
|
+
console.warn(e)
|
|
51
52
|
}
|
|
52
53
|
})
|
|
53
54
|
|
|
@@ -76,6 +77,6 @@ watchEffect(() => {
|
|
|
76
77
|
</script>
|
|
77
78
|
|
|
78
79
|
<template>
|
|
79
|
-
<pre v-if="error" border="1 red rounded" class="pa-3">{{ error }}</pre>
|
|
80
|
+
<pre v-if="error" border="1 red rounded" class="pa-3 text-wrap">{{ error }}</pre>
|
|
80
81
|
<ShadowRoot v-else class="mermaid" :inner-html="html" @shadow="el = $event" />
|
|
81
82
|
</template>
|
package/builtin/Monaco.vue
CHANGED
|
@@ -12,122 +12,195 @@ Learn more: https://sli.dev/guide/syntax.html#monaco-editor
|
|
|
12
12
|
-->
|
|
13
13
|
|
|
14
14
|
<script setup lang="ts">
|
|
15
|
-
import {
|
|
16
|
-
import
|
|
17
|
-
import { decode } from 'js-base64'
|
|
18
|
-
import { nanoid } from 'nanoid'
|
|
15
|
+
import { debounce } from '@antfu/utils'
|
|
16
|
+
import lz from 'lz-string'
|
|
19
17
|
import type * as monaco from 'monaco-editor'
|
|
20
|
-
import {
|
|
18
|
+
import { computed, nextTick, onMounted, ref } from 'vue'
|
|
19
|
+
import { makeId } from '../logic/utils'
|
|
20
|
+
import CodeRunner from '../internals/CodeRunner.vue'
|
|
21
21
|
|
|
22
22
|
const props = withDefaults(defineProps<{
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
codeLz: string
|
|
24
|
+
diffLz?: string
|
|
25
25
|
lang?: string
|
|
26
26
|
readonly?: boolean
|
|
27
27
|
lineNumbers?: 'on' | 'off' | 'relative' | 'interval'
|
|
28
|
-
height?: number | string
|
|
28
|
+
height?: number | string // Posible values: 'initial', 'auto', '100%', '200px', etc.
|
|
29
29
|
editorOptions?: monaco.editor.IEditorOptions
|
|
30
|
+
ata?: boolean
|
|
31
|
+
runnable?: boolean
|
|
32
|
+
autorun?: boolean | 'once'
|
|
33
|
+
outputHeight?: string
|
|
34
|
+
highlightOutput?: boolean
|
|
35
|
+
runnerOptions?: Record<string, unknown>
|
|
30
36
|
}>(), {
|
|
31
|
-
|
|
37
|
+
codeLz: '',
|
|
32
38
|
lang: 'typescript',
|
|
33
39
|
readonly: false,
|
|
34
40
|
lineNumbers: 'off',
|
|
35
|
-
height: '
|
|
41
|
+
height: 'initial',
|
|
42
|
+
ata: true,
|
|
43
|
+
runnable: false,
|
|
44
|
+
autorun: true,
|
|
45
|
+
highlightOutput: true,
|
|
36
46
|
})
|
|
37
47
|
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const diff = ref(props.diff ? decode(props.diff).trimEnd() : null)
|
|
41
|
-
const lineHeight = +(getComputedStyle(document.body).getPropertyValue('--slidev-code-line-height') || '18').replace('px', '') || 18
|
|
42
|
-
const editorHeight = ref(0)
|
|
43
|
-
const calculatedHeight = computed(() => code.value.split(/\r?\n/g).length * lineHeight)
|
|
44
|
-
const height = computed(() => {
|
|
45
|
-
return props.height === 'auto' ? `${Math.max(calculatedHeight.value, editorHeight.value) + 20}px` : props.height
|
|
46
|
-
})
|
|
48
|
+
const code = ref(lz.decompressFromBase64(props.codeLz).trimEnd())
|
|
49
|
+
const diff = props.diffLz && ref(lz.decompressFromBase64(props.diffLz).trimEnd())
|
|
47
50
|
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
'
|
|
55
|
-
'
|
|
56
|
-
'
|
|
57
|
-
'
|
|
58
|
-
]
|
|
59
|
-
|
|
60
|
-
function getStyleObject(el: Element) {
|
|
61
|
-
const object: Record<string, string> = {}
|
|
62
|
-
const style = getComputedStyle(el)
|
|
63
|
-
for (const v of cssVars)
|
|
64
|
-
object[v] = style.getPropertyValue(v)
|
|
65
|
-
return object
|
|
51
|
+
const langMap: Record<string, string> = {
|
|
52
|
+
ts: 'typescript',
|
|
53
|
+
js: 'javascript',
|
|
54
|
+
}
|
|
55
|
+
const lang = langMap[props.lang] ?? props.lang
|
|
56
|
+
const extMap: Record<string, string> = {
|
|
57
|
+
typescript: 'mts',
|
|
58
|
+
javascript: 'mjs',
|
|
59
|
+
ts: 'mts',
|
|
60
|
+
js: 'mjs',
|
|
66
61
|
}
|
|
62
|
+
const ext = extMap[props.lang] ?? props.lang
|
|
67
63
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
let src = __DEV__
|
|
81
|
-
? `${location.origin}${__SLIDEV_CLIENT_ROOT__}/`
|
|
82
|
-
: import.meta.env.BASE_URL
|
|
83
|
-
src += `iframes/monaco/index.html?id=${id}&lineNumbers=${props.lineNumbers}&lang=${props.lang}`
|
|
84
|
-
if (diff.value)
|
|
85
|
-
src += '&diff=1'
|
|
86
|
-
frame.src = src
|
|
87
|
-
|
|
88
|
-
frame.style.backgroundColor = 'transparent'
|
|
64
|
+
const outer = ref<HTMLDivElement>()
|
|
65
|
+
const container = ref<HTMLDivElement>()
|
|
66
|
+
|
|
67
|
+
const contentHeight = ref(0)
|
|
68
|
+
const initialHeight = ref<number>()
|
|
69
|
+
const height = computed(() => {
|
|
70
|
+
if (props.height === 'auto')
|
|
71
|
+
return `${contentHeight.value}px`
|
|
72
|
+
if (props.height === 'initial')
|
|
73
|
+
return `${initialHeight.value}px`
|
|
74
|
+
return props.height
|
|
89
75
|
})
|
|
90
76
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
77
|
+
onMounted(async () => {
|
|
78
|
+
// Lazy load monaco, so it will be bundled in async chunk
|
|
79
|
+
const { default: setup } = await import('../setup/monaco')
|
|
80
|
+
const { ata, monaco } = await setup()
|
|
81
|
+
const model = monaco.editor.createModel(code.value, lang, monaco.Uri.parse(`file:///${makeId()}.${ext}`))
|
|
82
|
+
model.onDidChangeContent(() => code.value = model.getValue())
|
|
83
|
+
const commonOptions = {
|
|
84
|
+
automaticLayout: true,
|
|
85
|
+
readOnly: props.readonly,
|
|
86
|
+
lineNumbers: props.lineNumbers,
|
|
87
|
+
minimap: { enabled: false },
|
|
88
|
+
overviewRulerBorder: false,
|
|
89
|
+
overviewRulerLanes: 0,
|
|
90
|
+
padding: { top: 10, bottom: 10 },
|
|
91
|
+
lineNumbersMinChars: 3,
|
|
92
|
+
bracketPairColorization: { enabled: false },
|
|
93
|
+
tabSize: 2,
|
|
94
|
+
fontSize: 11.5,
|
|
95
|
+
fontFamily: 'var(--slidev-code-font-family)',
|
|
96
|
+
scrollBeyondLastLine: false,
|
|
97
|
+
...props.editorOptions,
|
|
98
|
+
} satisfies monaco.editor.IStandaloneEditorConstructionOptions & monaco.editor.IDiffEditorConstructionOptions
|
|
101
99
|
|
|
102
|
-
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
100
|
+
let editableEditor: monaco.editor.IStandaloneCodeEditor
|
|
101
|
+
if (diff) {
|
|
102
|
+
const diffModel = monaco.editor.createModel(diff.value, lang, monaco.Uri.parse(`file:///${makeId()}.${ext}`))
|
|
103
|
+
diffModel.onDidChangeContent(() => code.value = model.getValue())
|
|
104
|
+
const editor = monaco.editor.createDiffEditor(container.value!, {
|
|
105
|
+
renderOverviewRuler: false,
|
|
106
|
+
...commonOptions,
|
|
107
|
+
})
|
|
108
|
+
editor.setModel({
|
|
109
|
+
original: model,
|
|
110
|
+
modified: diffModel,
|
|
111
|
+
})
|
|
112
|
+
const originalEditor = editor.getOriginalEditor()
|
|
113
|
+
const modifiedEditor = editor.getModifiedEditor()
|
|
114
|
+
const onContentSizeChange = () => {
|
|
115
|
+
const newHeight = Math.max(originalEditor.getContentHeight(), modifiedEditor.getContentHeight()) + 4
|
|
116
|
+
initialHeight.value ??= newHeight
|
|
117
|
+
contentHeight.value = newHeight
|
|
118
|
+
nextTick(() => editor.layout())
|
|
117
119
|
}
|
|
118
|
-
|
|
120
|
+
originalEditor.onDidContentSizeChange(onContentSizeChange)
|
|
121
|
+
modifiedEditor.onDidContentSizeChange(onContentSizeChange)
|
|
122
|
+
editableEditor = modifiedEditor
|
|
119
123
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
else {
|
|
125
|
+
const editor = monaco.editor.create(container.value!, {
|
|
126
|
+
model,
|
|
127
|
+
lineDecorationsWidth: 0,
|
|
128
|
+
...commonOptions,
|
|
129
|
+
})
|
|
130
|
+
editor.onDidContentSizeChange((e) => {
|
|
131
|
+
const newHeight = e.contentHeight + 4
|
|
132
|
+
initialHeight.value ??= newHeight
|
|
133
|
+
contentHeight.value = newHeight
|
|
134
|
+
nextTick(() => editableEditor.layout())
|
|
135
|
+
})
|
|
136
|
+
editableEditor = editor
|
|
137
|
+
}
|
|
138
|
+
if (props.ata) {
|
|
139
|
+
ata(editableEditor.getValue())
|
|
140
|
+
editableEditor.onDidChangeModelContent(debounce(1000, () => {
|
|
141
|
+
ata(editableEditor.getValue())
|
|
142
|
+
}))
|
|
143
|
+
}
|
|
144
|
+
const originalLayoutContentWidget = editableEditor.layoutContentWidget.bind(editableEditor)
|
|
145
|
+
editableEditor.layoutContentWidget = (widget: any) => {
|
|
146
|
+
originalLayoutContentWidget(widget)
|
|
147
|
+
const id = widget.getId()
|
|
148
|
+
if (id === 'editor.contrib.resizableContentHoverWidget') {
|
|
149
|
+
widget._resizableNode.domNode.style.transform = widget._positionPreference === 1
|
|
150
|
+
? /* ABOVE */ `translateY(calc(100% * (var(--slidev-slide-scale) - 1)))`
|
|
151
|
+
: /* BELOW */ `` // reset
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
nextTick(() => monaco.editor.remeasureFonts())
|
|
128
155
|
})
|
|
129
156
|
</script>
|
|
130
157
|
|
|
131
158
|
<template>
|
|
132
|
-
<
|
|
159
|
+
<div class="relative slidev-monaco-container">
|
|
160
|
+
<div ref="outer" class="relative slidev-monaco-container-inner" :style="{ height }">
|
|
161
|
+
<div ref="container" class="absolute inset-0.5" />
|
|
162
|
+
</div>
|
|
163
|
+
<CodeRunner
|
|
164
|
+
v-if="props.runnable"
|
|
165
|
+
v-model="code"
|
|
166
|
+
:lang="lang"
|
|
167
|
+
:autorun="props.autorun"
|
|
168
|
+
:height="props.outputHeight"
|
|
169
|
+
:highlight-output="props.highlightOutput"
|
|
170
|
+
:runner-options="props.runnerOptions"
|
|
171
|
+
/>
|
|
172
|
+
</div>
|
|
133
173
|
</template>
|
|
174
|
+
|
|
175
|
+
<style>
|
|
176
|
+
div[widgetid='messageoverlay'] {
|
|
177
|
+
transform: translateY(calc(100% * (var(--slidev-slide-scale) - 1)));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.slidev-monaco-container {
|
|
181
|
+
position: relative;
|
|
182
|
+
margin: var(--slidev-code-margin);
|
|
183
|
+
line-height: var(--slidev-code-line-height);
|
|
184
|
+
border-radius: var(--slidev-code-radius);
|
|
185
|
+
background: var(--slidev-code-background);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.slidev-monaco-container-inner {
|
|
189
|
+
padding: var(--slidev-code-padding);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.slidev-monaco-container .monaco-editor {
|
|
193
|
+
--monaco-monospace-font: var(--slidev-code-font-family);
|
|
194
|
+
--vscode-editor-background: var(--slidev-code-background);
|
|
195
|
+
--vscode-editorGutter-background: var(--slidev-code-background);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Revert styles */
|
|
199
|
+
.slidev-monaco-container .monaco-editor a {
|
|
200
|
+
border-bottom: none;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.slidev-monaco-container .monaco-editor a:hover {
|
|
204
|
+
border-bottom: none;
|
|
205
|
+
}
|
|
206
|
+
</style>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ShikiMagicMovePrecompiled } from 'shiki-magic-move/vue'
|
|
3
|
+
import type { KeyedTokensInfo } from 'shiki-magic-move/types'
|
|
4
|
+
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
5
|
+
import lz from 'lz-string'
|
|
6
|
+
import { useSlideContext } from '../context'
|
|
7
|
+
import { makeId, updateCodeHighlightRange } from '../logic/utils'
|
|
8
|
+
|
|
9
|
+
const props = defineProps<{
|
|
10
|
+
at?: string | number
|
|
11
|
+
stepsLz: string
|
|
12
|
+
stepRanges: string[][]
|
|
13
|
+
}>()
|
|
14
|
+
|
|
15
|
+
const steps = JSON.parse(lz.decompressFromBase64(props.stepsLz)) as KeyedTokensInfo[]
|
|
16
|
+
const { $clicksContext: clicks, $scale: scale } = useSlideContext()
|
|
17
|
+
const id = makeId()
|
|
18
|
+
|
|
19
|
+
const stepIndex = ref(0)
|
|
20
|
+
const container = ref<HTMLElement>()
|
|
21
|
+
|
|
22
|
+
// Normalized the ranges, to at least have one range
|
|
23
|
+
const ranges = computed(() => props.stepRanges.map(i => i.length ? i : ['all']))
|
|
24
|
+
|
|
25
|
+
onUnmounted(() => {
|
|
26
|
+
clicks!.unregister(id)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
onMounted(() => {
|
|
30
|
+
if (!clicks || clicks.disabled)
|
|
31
|
+
return
|
|
32
|
+
|
|
33
|
+
if (ranges.value.length !== steps.length)
|
|
34
|
+
throw new Error('[slidev] The length of stepRanges does not match the length of steps, this is an internal error.')
|
|
35
|
+
|
|
36
|
+
const clickCounts = ranges.value.map(s => s.length).reduce((a, b) => a + b, 0)
|
|
37
|
+
const { start, end, delta } = clicks.resolve(props.at ?? '+1', clickCounts - 1)
|
|
38
|
+
clicks.register(id, { max: end, delta })
|
|
39
|
+
|
|
40
|
+
watch(
|
|
41
|
+
() => clicks.current,
|
|
42
|
+
() => {
|
|
43
|
+
// Calculate the step and rangeStr based on the current click count
|
|
44
|
+
const clickCount = clicks.current - start
|
|
45
|
+
let step = steps.length - 1
|
|
46
|
+
let _currentClickSum = 0
|
|
47
|
+
let rangeStr = 'all'
|
|
48
|
+
for (let i = 0; i < ranges.value.length; i++) {
|
|
49
|
+
const current = ranges.value[i]
|
|
50
|
+
if (clickCount < _currentClickSum + current.length - 1) {
|
|
51
|
+
step = i
|
|
52
|
+
rangeStr = current[clickCount - _currentClickSum + 1]
|
|
53
|
+
break
|
|
54
|
+
}
|
|
55
|
+
_currentClickSum += current.length || 1
|
|
56
|
+
}
|
|
57
|
+
stepIndex.value = step
|
|
58
|
+
|
|
59
|
+
const pre = container.value?.querySelector('.shiki') as HTMLElement
|
|
60
|
+
if (!pre)
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
const children = (Array.from(pre.children) as HTMLElement[])
|
|
64
|
+
.slice(1) // Remove the first anchor
|
|
65
|
+
.filter(i => !i.className.includes('shiki-magic-move-leave')) // Filter the leaving elements
|
|
66
|
+
|
|
67
|
+
// Group to lines between `<br>`
|
|
68
|
+
const lines = children.reduce((acc, el) => {
|
|
69
|
+
if (el.tagName === 'BR')
|
|
70
|
+
acc.push([])
|
|
71
|
+
else
|
|
72
|
+
acc[acc.length - 1].push(el)
|
|
73
|
+
return acc
|
|
74
|
+
}, [[]] as HTMLElement[][])
|
|
75
|
+
|
|
76
|
+
// Update highlight range
|
|
77
|
+
updateCodeHighlightRange(
|
|
78
|
+
rangeStr,
|
|
79
|
+
lines.length,
|
|
80
|
+
1,
|
|
81
|
+
no => lines[no],
|
|
82
|
+
)
|
|
83
|
+
},
|
|
84
|
+
{ immediate: true },
|
|
85
|
+
)
|
|
86
|
+
})
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
<template>
|
|
90
|
+
<div ref="container" class="slidev-code-wrapper slidev-code-magic-move relative">
|
|
91
|
+
<ShikiMagicMovePrecompiled
|
|
92
|
+
class="slidev-code relative shiki overflow-visible"
|
|
93
|
+
:steps="steps"
|
|
94
|
+
:step="stepIndex"
|
|
95
|
+
:options="{
|
|
96
|
+
globalScale: scale,
|
|
97
|
+
// TODO: make this configurable later
|
|
98
|
+
duration: 800,
|
|
99
|
+
stagger: 1,
|
|
100
|
+
}"
|
|
101
|
+
/>
|
|
102
|
+
</div>
|
|
103
|
+
</template>
|
package/builtin/SlidevVideo.vue
CHANGED
|
@@ -22,7 +22,7 @@ const ended = ref(false)
|
|
|
22
22
|
const matchRoute = computed(() => {
|
|
23
23
|
if (!video.value || currentContext?.value !== 'slide')
|
|
24
24
|
return false
|
|
25
|
-
return route === $slidev?.nav.
|
|
25
|
+
return route && route.no === $slidev?.nav.currentSlideNo
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
const matchClick = computed(() => {
|
package/builtin/Toc.vue
CHANGED
package/builtin/TocList.vue
CHANGED
|
@@ -10,7 +10,7 @@ Usage:
|
|
|
10
10
|
import { computed } from 'vue'
|
|
11
11
|
import { toArray } from '@antfu/utils'
|
|
12
12
|
import type { TocItem } from '@slidev/types'
|
|
13
|
-
import
|
|
13
|
+
import TitleRenderer from '#slidev/title-renderer'
|
|
14
14
|
|
|
15
15
|
const props = withDefaults(defineProps<{
|
|
16
16
|
level: number
|
|
@@ -48,7 +48,7 @@ const styles = computed(() => {
|
|
|
48
48
|
:class="[{ 'slidev-toc-item-active': item.active }, { 'slidev-toc-item-parent-active': item.activeParent }]"
|
|
49
49
|
>
|
|
50
50
|
<Link :to="item.path">
|
|
51
|
-
<
|
|
51
|
+
<TitleRenderer :no="item.no" />
|
|
52
52
|
</Link>
|
|
53
53
|
<TocList
|
|
54
54
|
v-if="item.children.length > 0"
|
|
@@ -65,7 +65,8 @@ const styles = computed(() => {
|
|
|
65
65
|
.slidev-layout .slidev-toc-item p {
|
|
66
66
|
margin: 0;
|
|
67
67
|
}
|
|
68
|
-
.slidev-layout .slidev-toc-item div,
|
|
68
|
+
.slidev-layout .slidev-toc-item div,
|
|
69
|
+
.slidev-layout .slidev-toc-item div p {
|
|
69
70
|
display: initial;
|
|
70
71
|
}
|
|
71
72
|
</style>
|
package/builtin/Tweet.vue
CHANGED
|
@@ -7,9 +7,8 @@ Usage:
|
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
<script setup lang="ts">
|
|
10
|
-
import {
|
|
10
|
+
import { onMounted, ref } from 'vue'
|
|
11
11
|
import { isDark } from '../logic/dark'
|
|
12
|
-
import { useTweetScript } from '../composables/useTweetScript'
|
|
13
12
|
|
|
14
13
|
const props = defineProps<{
|
|
15
14
|
id: string | number
|
|
@@ -20,11 +19,17 @@ const props = defineProps<{
|
|
|
20
19
|
|
|
21
20
|
const tweet = ref<HTMLElement | null>()
|
|
22
21
|
|
|
23
|
-
const vm = getCurrentInstance()!
|
|
24
22
|
const loaded = ref(false)
|
|
25
23
|
const tweetNotFound = ref(false)
|
|
26
24
|
|
|
27
|
-
async function create() {
|
|
25
|
+
async function create(retries = 10) {
|
|
26
|
+
// @ts-expect-error global
|
|
27
|
+
if (!window.twttr?.widgets?.createTweet) {
|
|
28
|
+
if (retries <= 0)
|
|
29
|
+
return console.error('Failed to load Twitter widget after 10 retries.')
|
|
30
|
+
setTimeout(() => create(retries - 1), 1000)
|
|
31
|
+
return
|
|
32
|
+
}
|
|
28
33
|
// @ts-expect-error global
|
|
29
34
|
const element = await window.twttr.widgets.createTweet(
|
|
30
35
|
props.id.toString(),
|
|
@@ -40,11 +45,9 @@ async function create() {
|
|
|
40
45
|
tweetNotFound.value = true
|
|
41
46
|
}
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
else
|
|
47
|
-
useTweetScript(vm, create)
|
|
48
|
+
onMounted(() => {
|
|
49
|
+
create()
|
|
50
|
+
})
|
|
48
51
|
</script>
|
|
49
52
|
|
|
50
53
|
<template>
|