@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.
Files changed (97) hide show
  1. package/App.vue +7 -0
  2. package/builtin/Arrow.vue +2 -4
  3. package/builtin/CodeBlockWrapper.vue +33 -28
  4. package/builtin/KaTexBlockWrapper.vue +1 -1
  5. package/builtin/Link.vue +3 -1
  6. package/builtin/Mermaid.vue +4 -3
  7. package/builtin/Monaco.vue +166 -93
  8. package/builtin/ShikiMagicMove.vue +103 -0
  9. package/builtin/SlidevVideo.vue +1 -1
  10. package/builtin/Toc.vue +1 -1
  11. package/builtin/TocList.vue +4 -3
  12. package/builtin/Tweet.vue +12 -9
  13. package/builtin/VClick.ts +2 -1
  14. package/composables/useClicks.ts +19 -32
  15. package/composables/useDarkMode.ts +9 -0
  16. package/composables/useDrawings.ts +181 -0
  17. package/composables/useNav.ts +346 -44
  18. package/{logic/note.ts → composables/useSlideInfo.ts} +13 -16
  19. package/composables/useSwipeControls.ts +43 -0
  20. package/composables/useTocTree.ts +81 -0
  21. package/composables/useViewTransition.ts +7 -4
  22. package/constants.ts +4 -3
  23. package/context.ts +13 -6
  24. package/env.ts +7 -16
  25. package/index.html +1 -0
  26. package/index.ts +12 -0
  27. package/internals/ClicksSlider.vue +97 -0
  28. package/internals/CodeRunner.vue +142 -0
  29. package/internals/Controls.vue +2 -2
  30. package/internals/DomElement.vue +18 -0
  31. package/internals/DrawingControls.vue +14 -15
  32. package/internals/DrawingLayer.vue +6 -5
  33. package/internals/DrawingPreview.vue +4 -2
  34. package/internals/Goto.vue +9 -6
  35. package/internals/IconButton.vue +3 -2
  36. package/internals/NavControls.vue +30 -11
  37. package/internals/NoteDisplay.vue +131 -8
  38. package/internals/NoteEditable.vue +129 -0
  39. package/internals/NoteStatic.vue +5 -2
  40. package/internals/PrintContainer.vue +11 -8
  41. package/internals/PrintSlide.vue +11 -12
  42. package/internals/PrintSlideClick.vue +14 -19
  43. package/internals/{SlidesOverview.vue → QuickOverview.vue} +27 -24
  44. package/internals/RecordingControls.vue +1 -1
  45. package/internals/RecordingDialog.vue +3 -3
  46. package/internals/{Editor.vue → SideEditor.vue} +24 -15
  47. package/internals/SlideContainer.vue +13 -9
  48. package/internals/SlideLoading.vue +19 -0
  49. package/internals/SlideWrapper.vue +79 -0
  50. package/internals/SlidesShow.vue +36 -22
  51. package/layouts/error.vue +5 -0
  52. package/layouts/two-cols-header.vue +9 -3
  53. package/logic/overview.ts +2 -2
  54. package/logic/route.ts +16 -5
  55. package/logic/slides.ts +20 -0
  56. package/logic/transition.ts +50 -0
  57. package/logic/utils.ts +24 -1
  58. package/main.ts +3 -15
  59. package/{setup → modules}/codemirror.ts +1 -3
  60. package/modules/context.ts +1 -46
  61. package/modules/mermaid.ts +9 -8
  62. package/package.json +21 -15
  63. package/pages/notes.vue +6 -3
  64. package/pages/overview.vue +139 -51
  65. package/pages/play.vue +16 -9
  66. package/pages/presenter/print.vue +10 -5
  67. package/pages/presenter.vue +122 -104
  68. package/pages/print.vue +4 -3
  69. package/routes.ts +8 -54
  70. package/setup/code-runners.ts +164 -0
  71. package/setup/main.ts +39 -9
  72. package/setup/mermaid.ts +5 -6
  73. package/setup/monaco.ts +114 -51
  74. package/setup/root.ts +62 -18
  75. package/setup/shortcuts.ts +15 -12
  76. package/shim-vue.d.ts +34 -0
  77. package/shim.d.ts +1 -13
  78. package/state/index.ts +2 -2
  79. package/styles/code.css +9 -5
  80. package/styles/index.css +63 -7
  81. package/styles/katex.css +1 -1
  82. package/styles/layouts-base.css +11 -8
  83. package/styles/shiki-twoslash.css +1 -1
  84. package/styles/vars.css +1 -1
  85. package/uno.config.ts +10 -1
  86. package/utils.ts +15 -2
  87. package/composables/useContext.ts +0 -17
  88. package/composables/useTweetScript.ts +0 -17
  89. package/iframes/monaco/index.css +0 -28
  90. package/iframes/monaco/index.html +0 -7
  91. package/iframes/monaco/index.ts +0 -260
  92. package/internals/NoteEditor.vue +0 -92
  93. package/internals/SlideWrapper.ts +0 -58
  94. package/logic/drawings.ts +0 -161
  95. package/logic/nav.ts +0 -278
  96. package/setup/prettier.ts +0 -43
  97. /package/{composables → logic}/hmr.ts +0 -0
@@ -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