@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
package/internals/NoteEditor.vue
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ignorableWatch, onClickOutside, useVModel } from '@vueuse/core'
|
|
3
|
-
import { ref, watch, watchEffect } from 'vue'
|
|
4
|
-
import { currentSlideId } from '../logic/nav'
|
|
5
|
-
import { useDynamicSlideInfo } from '../logic/note'
|
|
6
|
-
import NoteDisplay from './NoteDisplay.vue'
|
|
7
|
-
|
|
8
|
-
const props = defineProps({
|
|
9
|
-
class: {
|
|
10
|
-
default: '',
|
|
11
|
-
},
|
|
12
|
-
editing: {
|
|
13
|
-
default: false,
|
|
14
|
-
},
|
|
15
|
-
style: {
|
|
16
|
-
default: () => ({}),
|
|
17
|
-
},
|
|
18
|
-
placeholder: {
|
|
19
|
-
default: 'No notes for this slide',
|
|
20
|
-
},
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
const emit = defineEmits([
|
|
24
|
-
'update:editing',
|
|
25
|
-
])
|
|
26
|
-
const editing = useVModel(props, 'editing', emit, { passive: true })
|
|
27
|
-
|
|
28
|
-
const { info, update } = useDynamicSlideInfo(currentSlideId)
|
|
29
|
-
|
|
30
|
-
const note = ref('')
|
|
31
|
-
let timer: any
|
|
32
|
-
|
|
33
|
-
const { ignoreUpdates } = ignorableWatch(
|
|
34
|
-
note,
|
|
35
|
-
(v) => {
|
|
36
|
-
const id = currentSlideId.value
|
|
37
|
-
clearTimeout(timer)
|
|
38
|
-
timer = setTimeout(() => {
|
|
39
|
-
update({ note: v }, id)
|
|
40
|
-
}, 500)
|
|
41
|
-
},
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
watch(
|
|
45
|
-
info,
|
|
46
|
-
(v) => {
|
|
47
|
-
clearTimeout(timer)
|
|
48
|
-
ignoreUpdates(() => {
|
|
49
|
-
note.value = v?.note || ''
|
|
50
|
-
})
|
|
51
|
-
},
|
|
52
|
-
{ immediate: true, flush: 'sync' },
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
const input = ref<HTMLTextAreaElement>()
|
|
56
|
-
|
|
57
|
-
watchEffect(() => {
|
|
58
|
-
if (editing.value)
|
|
59
|
-
input.value?.focus()
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
onClickOutside(input, () => {
|
|
63
|
-
editing.value = false
|
|
64
|
-
})
|
|
65
|
-
</script>
|
|
66
|
-
|
|
67
|
-
<template>
|
|
68
|
-
<NoteDisplay
|
|
69
|
-
v-if="!editing"
|
|
70
|
-
class="my--4 border-transparent border-2"
|
|
71
|
-
:class="[props.class, note ? '' : 'opacity-50']"
|
|
72
|
-
:style="props.style"
|
|
73
|
-
:note="note || placeholder"
|
|
74
|
-
:note-html="info?.noteHTML"
|
|
75
|
-
/>
|
|
76
|
-
<textarea
|
|
77
|
-
v-else
|
|
78
|
-
ref="input"
|
|
79
|
-
v-model="note"
|
|
80
|
-
class="prose resize-none overflow-auto outline-none bg-transparent block border-green border-2"
|
|
81
|
-
style="line-height: 1.75;"
|
|
82
|
-
:style="props.style"
|
|
83
|
-
:class="props.class"
|
|
84
|
-
:placeholder="placeholder"
|
|
85
|
-
@keydown.esc=" editing = false"
|
|
86
|
-
@focus="editing = true"
|
|
87
|
-
/>
|
|
88
|
-
</template>
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { computed, defineComponent, h, ref, toRef } from 'vue'
|
|
2
|
-
import type { PropType } from 'vue'
|
|
3
|
-
import { provideLocal } from '@vueuse/core'
|
|
4
|
-
import type { ClicksContext, RenderContext } from '@slidev/types'
|
|
5
|
-
import type { RouteRecordRaw } from 'vue-router'
|
|
6
|
-
import { injectionActive, injectionClicksContext, injectionCurrentPage, injectionRenderContext, injectionRoute } from '../constants'
|
|
7
|
-
|
|
8
|
-
export default defineComponent({
|
|
9
|
-
name: 'SlideWrapper',
|
|
10
|
-
props: {
|
|
11
|
-
clicksContext: {
|
|
12
|
-
type: Object as PropType<ClicksContext>,
|
|
13
|
-
required: true,
|
|
14
|
-
},
|
|
15
|
-
renderContext: {
|
|
16
|
-
type: String,
|
|
17
|
-
default: 'main',
|
|
18
|
-
},
|
|
19
|
-
active: {
|
|
20
|
-
type: Boolean,
|
|
21
|
-
default: false,
|
|
22
|
-
},
|
|
23
|
-
is: {
|
|
24
|
-
type: Object,
|
|
25
|
-
required: true,
|
|
26
|
-
},
|
|
27
|
-
route: {
|
|
28
|
-
type: Object as PropType<RouteRecordRaw>,
|
|
29
|
-
required: true,
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
setup(props) {
|
|
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
|
-
}
|
|
54
|
-
},
|
|
55
|
-
render() {
|
|
56
|
-
return h(this.$props.is, { style: this.style })
|
|
57
|
-
},
|
|
58
|
-
})
|
package/logic/drawings.ts
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { computed, markRaw, nextTick, reactive, ref, watch } from 'vue'
|
|
2
|
-
import type { Brush, Options as DrauuOptions, DrawingMode } from 'drauu'
|
|
3
|
-
import { createDrauu } from 'drauu'
|
|
4
|
-
import { toReactive, useLocalStorage } from '@vueuse/core'
|
|
5
|
-
import { drawingState, onPatch, patch } from '../state/drawings'
|
|
6
|
-
import { configs } from '../env'
|
|
7
|
-
import { isInputting } from '../state'
|
|
8
|
-
import { currentPage, isPresenter } from './nav'
|
|
9
|
-
|
|
10
|
-
export const brushColors = [
|
|
11
|
-
'#ff595e',
|
|
12
|
-
'#ffca3a',
|
|
13
|
-
'#8ac926',
|
|
14
|
-
'#1982c4',
|
|
15
|
-
'#6a4c93',
|
|
16
|
-
'#ffffff',
|
|
17
|
-
'#000000',
|
|
18
|
-
]
|
|
19
|
-
|
|
20
|
-
export const drawingEnabled = useLocalStorage('slidev-drawing-enabled', false)
|
|
21
|
-
export const drawingPinned = useLocalStorage('slidev-drawing-pinned', false)
|
|
22
|
-
export const canUndo = ref(false)
|
|
23
|
-
export const canRedo = ref(false)
|
|
24
|
-
export const canClear = ref(false)
|
|
25
|
-
export const isDrawing = ref(false)
|
|
26
|
-
|
|
27
|
-
export const brush = toReactive(useLocalStorage<Brush>('slidev-drawing-brush', {
|
|
28
|
-
color: brushColors[0],
|
|
29
|
-
size: 4,
|
|
30
|
-
mode: 'stylus',
|
|
31
|
-
}))
|
|
32
|
-
|
|
33
|
-
const _mode = ref<DrawingMode | 'arrow'>('stylus')
|
|
34
|
-
const syncUp = computed(() => configs.drawings.syncAll || isPresenter.value)
|
|
35
|
-
let disableDump = false
|
|
36
|
-
|
|
37
|
-
export const drawingMode = computed({
|
|
38
|
-
get() {
|
|
39
|
-
return _mode.value
|
|
40
|
-
},
|
|
41
|
-
set(v: DrawingMode | 'arrow') {
|
|
42
|
-
_mode.value = v
|
|
43
|
-
if (v === 'arrow') {
|
|
44
|
-
// eslint-disable-next-line ts/no-use-before-define
|
|
45
|
-
drauu.mode = 'line'
|
|
46
|
-
brush.arrowEnd = true
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
// eslint-disable-next-line ts/no-use-before-define
|
|
50
|
-
drauu.mode = v
|
|
51
|
-
brush.arrowEnd = false
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
export const drauuOptions: DrauuOptions = reactive({
|
|
57
|
-
brush,
|
|
58
|
-
acceptsInputTypes: computed(() => (drawingEnabled.value && (!configs.drawings.presenterOnly || isPresenter.value)) ? undefined : ['pen' as const]),
|
|
59
|
-
coordinateTransform: false,
|
|
60
|
-
})
|
|
61
|
-
export const drauu = markRaw(createDrauu(drauuOptions))
|
|
62
|
-
|
|
63
|
-
export function clearDrauu() {
|
|
64
|
-
drauu.clear()
|
|
65
|
-
if (syncUp.value)
|
|
66
|
-
patch(currentPage.value, '')
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function updateState() {
|
|
70
|
-
canRedo.value = drauu.canRedo()
|
|
71
|
-
canUndo.value = drauu.canUndo()
|
|
72
|
-
canClear.value = !!drauu.el?.children.length
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function loadCanvas(page?: number) {
|
|
76
|
-
disableDump = true
|
|
77
|
-
const data = drawingState[page || currentPage.value]
|
|
78
|
-
if (data != null)
|
|
79
|
-
drauu.load(data)
|
|
80
|
-
else
|
|
81
|
-
drauu.clear()
|
|
82
|
-
updateState()
|
|
83
|
-
disableDump = false
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
drauu.on('changed', () => {
|
|
87
|
-
updateState()
|
|
88
|
-
if (!disableDump) {
|
|
89
|
-
const dump = drauu.dump()
|
|
90
|
-
const key = currentPage.value
|
|
91
|
-
if ((drawingState[key] || '') !== dump && syncUp.value)
|
|
92
|
-
patch(key, drauu.dump())
|
|
93
|
-
}
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
onPatch((state) => {
|
|
97
|
-
disableDump = true
|
|
98
|
-
if (state[currentPage.value] != null)
|
|
99
|
-
drauu.load(state[currentPage.value] || '')
|
|
100
|
-
disableDump = false
|
|
101
|
-
updateState()
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
nextTick(() => {
|
|
105
|
-
watch(currentPage, () => {
|
|
106
|
-
if (!drauu.mounted)
|
|
107
|
-
return
|
|
108
|
-
loadCanvas()
|
|
109
|
-
}, { immediate: true })
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
drauu.on('start', () => isDrawing.value = true)
|
|
113
|
-
drauu.on('end', () => isDrawing.value = false)
|
|
114
|
-
|
|
115
|
-
window.addEventListener('keydown', (e) => {
|
|
116
|
-
if (!drawingEnabled.value || isInputting.value)
|
|
117
|
-
return
|
|
118
|
-
|
|
119
|
-
const noModifier = !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey
|
|
120
|
-
let handled = true
|
|
121
|
-
if (e.code === 'KeyZ' && (e.ctrlKey || e.metaKey)) {
|
|
122
|
-
if (e.shiftKey)
|
|
123
|
-
drauu.redo()
|
|
124
|
-
else
|
|
125
|
-
drauu.undo()
|
|
126
|
-
}
|
|
127
|
-
else if (e.code === 'Escape') {
|
|
128
|
-
drawingEnabled.value = false
|
|
129
|
-
}
|
|
130
|
-
else if (e.code === 'KeyL' && noModifier) {
|
|
131
|
-
drawingMode.value = 'line'
|
|
132
|
-
}
|
|
133
|
-
else if (e.code === 'KeyA' && noModifier) {
|
|
134
|
-
drawingMode.value = 'arrow'
|
|
135
|
-
}
|
|
136
|
-
else if (e.code === 'KeyS' && noModifier) {
|
|
137
|
-
drawingMode.value = 'stylus'
|
|
138
|
-
}
|
|
139
|
-
else if (e.code === 'KeyR' && noModifier) {
|
|
140
|
-
drawingMode.value = 'rectangle'
|
|
141
|
-
}
|
|
142
|
-
else if (e.code === 'KeyE' && noModifier) {
|
|
143
|
-
drawingMode.value = 'ellipse'
|
|
144
|
-
}
|
|
145
|
-
else if (e.code === 'KeyC' && noModifier) {
|
|
146
|
-
clearDrauu()
|
|
147
|
-
}
|
|
148
|
-
else if (e.code.startsWith('Digit') && noModifier && +e.code[5] <= brushColors.length) {
|
|
149
|
-
brush.color = brushColors[+e.code[5] - 1]
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
handled = false
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (handled) {
|
|
156
|
-
e.preventDefault()
|
|
157
|
-
e.stopPropagation()
|
|
158
|
-
}
|
|
159
|
-
}, false)
|
|
160
|
-
|
|
161
|
-
export { drawingState }
|
package/logic/nav.ts
DELETED
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import type { Ref, TransitionGroupProps } from 'vue'
|
|
2
|
-
import type { RouteRecordRaw } from 'vue-router'
|
|
3
|
-
import { computed, nextTick, ref, watch } from 'vue'
|
|
4
|
-
import type { TocItem } from '@slidev/types'
|
|
5
|
-
import { timestamp, usePointerSwipe } from '@vueuse/core'
|
|
6
|
-
import { rawRoutes, router } from '../routes'
|
|
7
|
-
import { configs } from '../env'
|
|
8
|
-
import { skipTransition } from '../composables/hmr'
|
|
9
|
-
import { usePrimaryClicks } from '../composables/useClicks'
|
|
10
|
-
import { useRouteQuery } from './route'
|
|
11
|
-
import { isDrawing } from './drawings'
|
|
12
|
-
|
|
13
|
-
export { rawRoutes, router }
|
|
14
|
-
|
|
15
|
-
// force update collected elements when the route is fully resolved
|
|
16
|
-
export const routeForceRefresh = ref(0)
|
|
17
|
-
nextTick(() => {
|
|
18
|
-
router.afterEach(async () => {
|
|
19
|
-
await nextTick()
|
|
20
|
-
routeForceRefresh.value += 1
|
|
21
|
-
})
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
export const navDirection = ref(0)
|
|
25
|
-
|
|
26
|
-
export const route = computed(() => router.currentRoute.value)
|
|
27
|
-
|
|
28
|
-
export const isPrintMode = computed(() => route.value.query.print !== undefined)
|
|
29
|
-
export const isPrintWithClicks = computed(() => route.value.query.print === 'clicks')
|
|
30
|
-
export const isEmbedded = computed(() => route.value.query.embedded !== undefined)
|
|
31
|
-
export const isPresenter = computed(() => route.value.path.startsWith('/presenter'))
|
|
32
|
-
export const isNotesViewer = computed(() => route.value.path.startsWith('/notes'))
|
|
33
|
-
export const presenterPassword = computed(() => route.value.query.password)
|
|
34
|
-
export const showPresenter = computed(() => !isPresenter.value && (!configs.remote || presenterPassword.value === configs.remote))
|
|
35
|
-
|
|
36
|
-
const queryClicksRaw = useRouteQuery('clicks', '0')
|
|
37
|
-
export const queryClicks = computed({
|
|
38
|
-
get() {
|
|
39
|
-
// eslint-disable-next-line ts/no-use-before-define
|
|
40
|
-
if (clicksContext.value.disabled)
|
|
41
|
-
return 99999
|
|
42
|
-
let v = +(queryClicksRaw.value || 0)
|
|
43
|
-
if (Number.isNaN(v))
|
|
44
|
-
v = 0
|
|
45
|
-
return v
|
|
46
|
-
},
|
|
47
|
-
set(v) {
|
|
48
|
-
queryClicksRaw.value = v.toString()
|
|
49
|
-
},
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
export const total = computed(() => rawRoutes.length)
|
|
53
|
-
export const path = computed(() => route.value.path)
|
|
54
|
-
|
|
55
|
-
export const currentPage = computed(() => Number.parseInt(path.value.split(/\//g).slice(-1)[0]) || 1)
|
|
56
|
-
export const currentPath = computed(() => getPath(currentPage.value))
|
|
57
|
-
export const currentRoute = computed(() => rawRoutes.find(i => i.path === `${currentPage.value}`))
|
|
58
|
-
export const currentSlideId = computed(() => currentRoute.value?.meta?.slide?.id)
|
|
59
|
-
export const currentLayout = computed(() => currentRoute.value?.meta?.layout || (currentPage.value === 1 ? 'cover' : 'default'))
|
|
60
|
-
|
|
61
|
-
export const nextRoute = computed(() => rawRoutes.find(i => i.path === `${Math.min(rawRoutes.length, currentPage.value + 1)}`))
|
|
62
|
-
export const prevRoute = computed(() => rawRoutes.find(i => i.path === `${Math.max(1, currentPage.value - 1)}`))
|
|
63
|
-
|
|
64
|
-
export const clicksContext = computed(() => usePrimaryClicks(currentRoute.value))
|
|
65
|
-
export const clicks = computed(() => clicksContext.value.current)
|
|
66
|
-
export const clicksTotal = computed(() => clicksContext.value.total)
|
|
67
|
-
|
|
68
|
-
export const hasNext = computed(() => currentPage.value < rawRoutes.length || clicks.value < clicksTotal.value)
|
|
69
|
-
export const hasPrev = computed(() => currentPage.value > 1 || clicks.value > 0)
|
|
70
|
-
|
|
71
|
-
export const rawTree = computed(() => rawRoutes
|
|
72
|
-
.filter((route: RouteRecordRaw) => route.meta?.slide?.title)
|
|
73
|
-
.reduce((acc: TocItem[], route: RouteRecordRaw) => {
|
|
74
|
-
addToTree(acc, route)
|
|
75
|
-
return acc
|
|
76
|
-
}, []))
|
|
77
|
-
export const treeWithActiveStatuses = computed(() => getTreeWithActiveStatuses(rawTree.value, currentRoute.value))
|
|
78
|
-
export const tree = computed(() => filterTree(treeWithActiveStatuses.value))
|
|
79
|
-
|
|
80
|
-
export const transition = computed(() => getCurrentTransition(navDirection.value, currentRoute.value, prevRoute.value))
|
|
81
|
-
|
|
82
|
-
watch(currentRoute, (next, prev) => {
|
|
83
|
-
navDirection.value = Number(next?.path) - Number(prev?.path)
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
export async function next() {
|
|
87
|
-
if (clicksTotal.value <= queryClicks.value)
|
|
88
|
-
await nextSlide()
|
|
89
|
-
else
|
|
90
|
-
queryClicks.value += 1
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export async function prev() {
|
|
94
|
-
if (queryClicks.value <= 0)
|
|
95
|
-
await prevSlide()
|
|
96
|
-
else
|
|
97
|
-
queryClicks.value -= 1
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function getPath(no: number | string) {
|
|
101
|
-
return isPresenter.value ? `/presenter/${no}` : `/${no}`
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export async function nextSlide() {
|
|
105
|
-
if (currentPage.value < rawRoutes.length)
|
|
106
|
-
await go(currentPage.value + 1)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export async function prevSlide(lastClicks = true) {
|
|
110
|
-
const next = Math.max(1, currentPage.value - 1)
|
|
111
|
-
await go(next)
|
|
112
|
-
if (lastClicks && clicksTotal.value)
|
|
113
|
-
router.replace({ query: { ...route.value.query, clicks: clicksTotal.value } })
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function goFirst() {
|
|
117
|
-
return go(1)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function goLast() {
|
|
121
|
-
return go(total.value)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export function go(page: number | string, clicks?: number) {
|
|
125
|
-
skipTransition.value = false
|
|
126
|
-
return router.push({ path: getPath(page), query: { ...route.value.query, clicks } })
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export function useSwipeControls(root: Ref<HTMLElement | undefined>) {
|
|
130
|
-
const swipeBegin = ref(0)
|
|
131
|
-
const { direction, distanceX, distanceY } = usePointerSwipe(root, {
|
|
132
|
-
onSwipeStart(e) {
|
|
133
|
-
if (e.pointerType !== 'touch')
|
|
134
|
-
return
|
|
135
|
-
if (isDrawing.value)
|
|
136
|
-
return
|
|
137
|
-
swipeBegin.value = timestamp()
|
|
138
|
-
},
|
|
139
|
-
onSwipeEnd(e) {
|
|
140
|
-
if (e.pointerType !== 'touch')
|
|
141
|
-
return
|
|
142
|
-
if (!swipeBegin.value)
|
|
143
|
-
return
|
|
144
|
-
if (isDrawing.value)
|
|
145
|
-
return
|
|
146
|
-
|
|
147
|
-
const x = Math.abs(distanceX.value)
|
|
148
|
-
const y = Math.abs(distanceY.value)
|
|
149
|
-
if (x / window.innerWidth > 0.3 || x > 75) {
|
|
150
|
-
if (direction.value === 'left')
|
|
151
|
-
next()
|
|
152
|
-
else
|
|
153
|
-
prev()
|
|
154
|
-
}
|
|
155
|
-
else if (y / window.innerHeight > 0.4 || y > 200) {
|
|
156
|
-
if (direction.value === 'down')
|
|
157
|
-
prevSlide()
|
|
158
|
-
else
|
|
159
|
-
nextSlide()
|
|
160
|
-
}
|
|
161
|
-
},
|
|
162
|
-
})
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export async function downloadPDF() {
|
|
166
|
-
const { saveAs } = await import('file-saver')
|
|
167
|
-
saveAs(
|
|
168
|
-
typeof configs.download === 'string'
|
|
169
|
-
? configs.download
|
|
170
|
-
: configs.exportFilename
|
|
171
|
-
? `${configs.exportFilename}.pdf`
|
|
172
|
-
: `${import.meta.env.BASE_URL}slidev-exported.pdf`,
|
|
173
|
-
`${configs.title}.pdf`,
|
|
174
|
-
)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export async function openInEditor(url?: string) {
|
|
178
|
-
if (url == null) {
|
|
179
|
-
const slide = currentRoute.value?.meta?.slide
|
|
180
|
-
if (!slide)
|
|
181
|
-
return false
|
|
182
|
-
url = `${slide.filepath}:${slide.start}`
|
|
183
|
-
}
|
|
184
|
-
await fetch(`/__open-in-editor?file=${encodeURIComponent(url)}`)
|
|
185
|
-
return true
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export function addToTree(tree: TocItem[], route: RouteRecordRaw, level = 1) {
|
|
189
|
-
const titleLevel = route.meta?.slide?.level
|
|
190
|
-
if (titleLevel && titleLevel > level && tree.length > 0) {
|
|
191
|
-
addToTree(tree[tree.length - 1].children, route, level + 1)
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
tree.push({
|
|
195
|
-
children: [],
|
|
196
|
-
level,
|
|
197
|
-
path: route.path,
|
|
198
|
-
hideInToc: Boolean(route.meta?.slide?.frontmatter?.hideInToc),
|
|
199
|
-
title: route.meta?.slide?.title,
|
|
200
|
-
})
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
export function getTreeWithActiveStatuses(
|
|
205
|
-
tree: TocItem[],
|
|
206
|
-
currentRoute?: RouteRecordRaw,
|
|
207
|
-
hasActiveParent = false,
|
|
208
|
-
parent?: TocItem,
|
|
209
|
-
): TocItem[] {
|
|
210
|
-
return tree.map((item: TocItem) => {
|
|
211
|
-
const clone = {
|
|
212
|
-
...item,
|
|
213
|
-
active: item.path === currentRoute?.path,
|
|
214
|
-
hasActiveParent,
|
|
215
|
-
}
|
|
216
|
-
if (clone.children.length > 0)
|
|
217
|
-
clone.children = getTreeWithActiveStatuses(clone.children, currentRoute, clone.active || clone.hasActiveParent, clone)
|
|
218
|
-
if (parent && (clone.active || clone.activeParent))
|
|
219
|
-
parent.activeParent = true
|
|
220
|
-
return clone
|
|
221
|
-
})
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export function filterTree(tree: TocItem[], level = 1): TocItem[] {
|
|
225
|
-
return tree
|
|
226
|
-
.filter((item: TocItem) => !item.hideInToc)
|
|
227
|
-
.map((item: TocItem) => ({
|
|
228
|
-
...item,
|
|
229
|
-
children: filterTree(item.children, level + 1),
|
|
230
|
-
}))
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const transitionResolveMap: Record<string, string | undefined> = {
|
|
234
|
-
'slide-left': 'slide-left | slide-right',
|
|
235
|
-
'slide-right': 'slide-right | slide-left',
|
|
236
|
-
'slide-up': 'slide-up | slide-down',
|
|
237
|
-
'slide-down': 'slide-down | slide-up',
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
export function resolveTransition(transition?: string | TransitionGroupProps, isBackward = false): TransitionGroupProps | undefined {
|
|
241
|
-
if (!transition)
|
|
242
|
-
return undefined
|
|
243
|
-
if (typeof transition === 'string') {
|
|
244
|
-
transition = {
|
|
245
|
-
name: transition,
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (!transition.name)
|
|
250
|
-
return undefined
|
|
251
|
-
|
|
252
|
-
let name = transition.name.includes('|')
|
|
253
|
-
? transition.name
|
|
254
|
-
: (transitionResolveMap[transition.name] || transition.name)
|
|
255
|
-
|
|
256
|
-
if (name.includes('|')) {
|
|
257
|
-
const [forward, backward] = name.split('|').map(i => i.trim())
|
|
258
|
-
name = isBackward ? backward : forward
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (!name)
|
|
262
|
-
return undefined
|
|
263
|
-
|
|
264
|
-
return {
|
|
265
|
-
...transition,
|
|
266
|
-
name,
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export function getCurrentTransition(direction: number, currentRoute?: RouteRecordRaw, prevRoute?: RouteRecordRaw) {
|
|
271
|
-
let transition = direction > 0
|
|
272
|
-
? prevRoute?.meta?.transition
|
|
273
|
-
: currentRoute?.meta?.transition
|
|
274
|
-
if (!transition)
|
|
275
|
-
transition = configs.transition
|
|
276
|
-
|
|
277
|
-
return resolveTransition(transition, direction < 0)
|
|
278
|
-
}
|
package/setup/prettier.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { format } from 'prettier'
|
|
2
|
-
|
|
3
|
-
export async function formatCode(code: string, lang: string) {
|
|
4
|
-
try {
|
|
5
|
-
let parser = 'babel'
|
|
6
|
-
let plugins: any[] = []
|
|
7
|
-
|
|
8
|
-
switch (lang) {
|
|
9
|
-
case 'ts':
|
|
10
|
-
case 'typescript':
|
|
11
|
-
parser = 'typescript'
|
|
12
|
-
plugins = [
|
|
13
|
-
(await import('prettier/plugins/babel')).default,
|
|
14
|
-
(await import('prettier/plugins/typescript')).default,
|
|
15
|
-
]
|
|
16
|
-
break
|
|
17
|
-
case 'html':
|
|
18
|
-
parser = 'html'
|
|
19
|
-
plugins = [
|
|
20
|
-
(await import('prettier/plugins/html')).default,
|
|
21
|
-
]
|
|
22
|
-
break
|
|
23
|
-
default:
|
|
24
|
-
parser = 'babel'
|
|
25
|
-
plugins = [
|
|
26
|
-
(await import('prettier/plugins/babel')).default,
|
|
27
|
-
]
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return format(code, {
|
|
31
|
-
semi: false,
|
|
32
|
-
singleQuote: true,
|
|
33
|
-
tabWidth: 2,
|
|
34
|
-
useTabs: false,
|
|
35
|
-
parser,
|
|
36
|
-
plugins,
|
|
37
|
-
})
|
|
38
|
-
}
|
|
39
|
-
catch (e) {
|
|
40
|
-
console.error(e)
|
|
41
|
-
return code
|
|
42
|
-
}
|
|
43
|
-
}
|
|
File without changes
|