@slidev/client 0.29.2 → 0.30.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 CHANGED
@@ -6,4 +6,5 @@ setupRoot()
6
6
 
7
7
  <template>
8
8
  <RouterView />
9
+ <StarportCarrier />
9
10
  </template>
@@ -0,0 +1,26 @@
1
+ <!--
2
+ Create a link in the presentation
3
+
4
+ Usage:
5
+
6
+ <Link :to="5" >Go to slide 5</Link>
7
+
8
+ <Link :to="5" title="Go to slide 5" />
9
+ -->
10
+ <script setup lang="ts">
11
+ import { isPrintMode } from '../logic/nav'
12
+
13
+ defineProps<{
14
+ to: number | string
15
+ title?: string
16
+ }>()
17
+ </script>
18
+
19
+ <template>
20
+ <RouterLink v-if="!isPrintMode && title" :to="to" v-html="title" />
21
+ <RouterLink v-else-if="!isPrintMode && !title" :to="to">
22
+ <slot />
23
+ </RouterLink>
24
+ <a v-else-if="isPrintMode && title" :href="'#' + to" v-html="title" />
25
+ <a v-else :href="'#' + to"><slot /></a>
26
+ </template>
package/builtin/Toc.vue CHANGED
@@ -8,9 +8,11 @@ Usage:
8
8
  <Toc columns='2' maxDepth='3' mode='onlySiblings'/>
9
9
  -->
10
10
  <script setup lang='ts'>
11
- import { computed } from 'vue'
11
+ import { computed, inject } from 'vue'
12
12
  import type { TocItem } from '../logic/nav'
13
- import { tree } from '../logic/nav'
13
+ import { injectionSlidevContext } from '../constants'
14
+
15
+ const $slidev = inject(injectionSlidevContext)
14
16
 
15
17
  const props = withDefaults(
16
18
  defineProps<{
@@ -69,7 +71,10 @@ function filterOnlySiblings(tree: TocItem[]): TocItem[] {
69
71
  }
70
72
 
71
73
  const toc = computed(() => {
72
- let tocTree = filterTreeDepth(tree.value)
74
+ const tree = $slidev?.nav.tree
75
+ if (!tree)
76
+ return []
77
+ let tocTree = filterTreeDepth(tree)
73
78
  if (props.mode === 'onlyCurrentTree')
74
79
  tocTree = filterOnlyCurrentTree(tocTree)
75
80
  else if (props.mode === 'onlySiblings')
@@ -29,7 +29,7 @@ const classes = computed(() => {
29
29
  <template>
30
30
  <ol v-if="list && list.length > 0" :class="classes">
31
31
  <li v-for="item in list" :key="item.path" :class="['slidev-toc-item', {'slidev-toc-item-active': item.active}, {'slidev-toc-item-parent-active': item.activeParent}]">
32
- <RouterLink :to="item.path" v-html="item.title" />
32
+ <Link :to="item.path" :title="item.title" />
33
33
  <TocList :level="level + 1" :list="item.children" :list-class="listClass" />
34
34
  </li>
35
35
  </ol>
package/builtin/Tweet.vue CHANGED
@@ -55,7 +55,7 @@ else {
55
55
 
56
56
  <template>
57
57
  <Transform :scale="scale || 1">
58
- <div ref="tweet">
58
+ <div ref="tweet" class="tweet" data-waitfor="iframe">
59
59
  <div v-if="!loaded" class="w-30 h-30 my-10px bg-gray-400 bg-opacity-10 rounded-lg flex opacity-50">
60
60
  <div class="m-auto animate-pulse text-4xl">
61
61
  <carbon:logo-twitter />
@@ -16,6 +16,7 @@ defineProps<{
16
16
 
17
17
  <template>
18
18
  <iframe
19
+ class="youtube"
19
20
  :width="width"
20
21
  :height="height"
21
22
  :src="`https://www.youtube.com/embed/${id}`"
@@ -0,0 +1,29 @@
1
+ import type { ComputedRef, WritableComputedRef } from 'vue'
2
+ import { computed } from 'vue'
3
+ import type { RouteLocationNormalizedLoaded } from 'vue-router'
4
+ import { downloadPDF, next, nextSlide, openInEditor, prev, prevSlide } from '../logic/nav'
5
+ import { configs } from '../env'
6
+ import { useNav } from './useNav'
7
+ import { useNavClicks } from './useNavClicks'
8
+
9
+ export function useContext(
10
+ route: ComputedRef<RouteLocationNormalizedLoaded>,
11
+ clicks: WritableComputedRef<number>,
12
+ ) {
13
+ const nav = useNav(route)
14
+ const navClicks = useNavClicks(clicks, nav.currentRoute, nav.currentPage)
15
+ return {
16
+ nav: {
17
+ ...nav,
18
+ ...navClicks,
19
+ downloadPDF,
20
+ next,
21
+ nextSlide,
22
+ openInEditor,
23
+ prev,
24
+ prevSlide,
25
+ },
26
+ configs,
27
+ themeConfigs: computed(() => configs.themeConfig),
28
+ }
29
+ }
@@ -0,0 +1,43 @@
1
+ import type { ComputedRef } from 'vue'
2
+ import { computed } from 'vue'
3
+ import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
4
+ import type { TocItem } from '../logic/nav'
5
+ import { addToTree, filterTree, getPath, getTreeWithActiveStatuses } from '../logic/nav'
6
+ import { rawRoutes } from '../routes'
7
+
8
+ export function useNav(route: ComputedRef<RouteLocationNormalizedLoaded>) {
9
+ const path = computed(() => route.value.path)
10
+ const total = computed(() => rawRoutes.length - 1)
11
+
12
+ const currentPage = computed(() => parseInt(path.value.split(/\//g).slice(-1)[0]) || 1)
13
+ const currentPath = computed(() => getPath(currentPage.value))
14
+ const currentRoute = computed(() => rawRoutes.find(i => i.path === `${currentPage.value}`))
15
+ const currentSlideId = computed(() => currentRoute.value?.meta?.slide?.id)
16
+ const currentLayout = computed(() => currentRoute.value?.meta?.layout)
17
+
18
+ const nextRoute = computed(() => rawRoutes.find(i => i.path === `${Math.min(rawRoutes.length, currentPage.value + 1)}`))
19
+
20
+ const rawTree = computed(() => rawRoutes
21
+ .filter((route: RouteRecordRaw) => route.meta?.slide?.title)
22
+ .reduce((acc: TocItem[], route: RouteRecordRaw) => {
23
+ addToTree(acc, route)
24
+ return acc
25
+ }, []))
26
+ const treeWithActiveStatuses = computed(() => getTreeWithActiveStatuses(rawTree.value, currentRoute.value))
27
+ const tree = computed(() => filterTree(treeWithActiveStatuses.value))
28
+
29
+ return {
30
+ route,
31
+ path,
32
+ total,
33
+ currentPage,
34
+ currentPath,
35
+ currentRoute,
36
+ currentSlideId,
37
+ currentLayout,
38
+ nextRoute,
39
+ rawTree,
40
+ treeWithActiveStatuses,
41
+ tree,
42
+ }
43
+ }
@@ -0,0 +1,37 @@
1
+ import type { ComputedRef, WritableComputedRef } from 'vue'
2
+ import { computed, nextTick, ref } from 'vue'
3
+ import type { RouteRecordRaw } from 'vue-router'
4
+ import { rawRoutes, router } from '../routes'
5
+
6
+ export function useNavClicks(
7
+ clicks: WritableComputedRef<number>,
8
+ currentRoute: ComputedRef<RouteRecordRaw | undefined>,
9
+ currentPage: ComputedRef<number>,
10
+ ) {
11
+ // force update collected elements when the route is fully resolved
12
+ const routeForceRefresh = ref(0)
13
+ nextTick(() => {
14
+ router.afterEach(async() => {
15
+ await nextTick()
16
+ routeForceRefresh.value += 1
17
+ })
18
+ })
19
+
20
+ const clicksElements = computed<HTMLElement[]>(() => {
21
+ // eslint-disable-next-line no-unused-expressions
22
+ routeForceRefresh.value
23
+ return currentRoute.value?.meta?.__clicksElements || []
24
+ })
25
+
26
+ const clicksTotal = computed(() => +(currentRoute.value?.meta?.clicks ?? clicksElements.value.length))
27
+
28
+ const hasNext = computed(() => currentPage.value < rawRoutes.length - 1 || clicks.value < clicksTotal.value)
29
+ const hasPrev = computed(() => currentPage.value > 1 || clicks.value > 0)
30
+ return {
31
+ clicks,
32
+ clicksElements,
33
+ clicksTotal,
34
+ hasNext,
35
+ hasPrev,
36
+ }
37
+ }
package/constants.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import type { ComputedRef, InjectionKey, Ref } from 'vue'
2
+ import type { SlidevContext } from './modules/context'
2
3
 
3
4
  export const injectionClicks: InjectionKey<Ref<number>> = Symbol('v-click-clicks')
4
5
  export const injectionClicksElements: InjectionKey<Ref<(Element | string)[]>> = Symbol('v-click-clicks-elements')
5
6
  export const injectionOrderMap: InjectionKey<Ref<Map<number, HTMLElement[]>>> = Symbol('v-click-clicks-order-map')
6
7
  export const injectionClicksDisabled: InjectionKey<Ref<boolean>> = Symbol('v-click-clicks-disabled')
7
8
  export const injectionSlideScale: InjectionKey<ComputedRef<number>> = Symbol('slidev-slide-scale')
9
+ export const injectionSlidevContext: InjectionKey<SlidevContext> = Symbol('slidev-slidev-context')
8
10
 
9
11
  export const CLASS_VCLICK_TARGET = 'slidev-vclick-target'
10
12
  export const CLASS_VCLICK_HIDDEN = 'slidev-vclick-hidden'
@@ -0,0 +1,63 @@
1
+ <script setup lang="ts">
2
+ import type { ComponentCustomProps, Slots } from 'vue'
3
+ import { h, watchEffect } from 'vue'
4
+ import _configs from '/@slidev/configs'
5
+ import { slideScale, windowSize } from '../state'
6
+ import { isPrintMode } from '../logic/nav'
7
+ import { themeVars } from '../env'
8
+ import PrintContainer from './PrintContainer.vue'
9
+
10
+ const width = _configs.canvasWidth
11
+ const height = Math.round(width / _configs.aspectRatio) + 1
12
+
13
+ function vStyle<Props>(props: Props, { slots }: { slots: Slots }) {
14
+ if (slots.default)
15
+ return h('style', slots.default())
16
+ }
17
+
18
+ watchEffect(() => {
19
+ if (isPrintMode)
20
+ document.body.parentNode.classList.add('print')
21
+ else
22
+ document.body.parentNode.classList.remove('print')
23
+ })
24
+ </script>
25
+
26
+ <template>
27
+ <vStyle>
28
+ @page { size: {{ width }}px {{ height }}px; margin: 0px; }
29
+ </vStyle>
30
+ <div id="page-root" class="grid grid-cols-[1fr,max-content]" :style="themeVars">
31
+ <PrintContainer
32
+ class="w-full h-full"
33
+ :style="{ background: 'var(--slidev-slide-container-background, black)'}"
34
+ :width="windowSize.width.value"
35
+ />
36
+ </div>
37
+ </template>
38
+
39
+ <style lang="postcss">
40
+ html.print,
41
+ html.print body,
42
+ html.print #app,
43
+ html.print #page-root {
44
+ height: auto;
45
+ overflow: auto;
46
+ }
47
+
48
+ html.print * {
49
+ -webkit-print-color-adjust: exact;
50
+ }
51
+ html.print {
52
+ width: 100%;
53
+ height: 100%;
54
+ overflow: visible;
55
+ }
56
+ html.print body {
57
+ margin: 0 auto;
58
+ border: 0;
59
+ padding: 0;
60
+ float: none;
61
+ overflow: visible;
62
+ }
63
+ </style>
@@ -0,0 +1,53 @@
1
+ <script setup lang="ts">
2
+ import { computed, provide } from 'vue'
3
+ import { configs, slideAspect, slideWidth } from '../env'
4
+ import { injectionSlideScale } from '../constants'
5
+ import { rawRoutes } from '../logic/nav'
6
+ import PrintSlide from './PrintSlide.vue'
7
+
8
+ const props = defineProps<{
9
+ width: number
10
+ }>()
11
+
12
+ const width = computed(() => props.width)
13
+ const height = computed(() => props.width / slideAspect)
14
+
15
+ const screenAspect = computed(() => width.value / height.value)
16
+
17
+ const scale = computed(() => {
18
+ if (screenAspect.value < slideAspect) return width.value / slideWidth
19
+ return (height.value * slideAspect) / slideWidth
20
+ })
21
+
22
+ // Remove the "end" slide
23
+ const routes = rawRoutes.slice(0, -1)
24
+
25
+ const className = computed(() => ({
26
+ 'select-none': !configs.selectable,
27
+ 'slidev-code-line-numbers': configs.lineNumbers,
28
+ }))
29
+
30
+ provide(injectionSlideScale, scale)
31
+ </script>
32
+
33
+ <template>
34
+ <div id="print-container" :class="className">
35
+ <div id="print-content">
36
+ <PrintSlide v-for="route of routes" :key="route.path" :route="route" />
37
+ </div>
38
+ <slot name="controls" />
39
+ </div>
40
+ </template>
41
+
42
+ <style lang="postcss">
43
+ #print-content {
44
+ @apply bg-main;
45
+ }
46
+
47
+ .slide-container {
48
+ @apply relative;
49
+ position: relative;
50
+ overflow: hidden;
51
+ page-break-before: always;
52
+ }
53
+ </style>
@@ -0,0 +1,21 @@
1
+ <script setup lang="ts">
2
+ import type { RouteRecordRaw } from 'vue-router'
3
+ import { computed, reactive } from 'vue'
4
+ import { useNav } from '../composables/useNav'
5
+ import { isClicksDisabled } from '../logic/nav'
6
+ import PrintSlideClick from './PrintSlideClick.vue'
7
+
8
+ const props = defineProps<{ route: RouteRecordRaw }>()
9
+
10
+ const clicksElements = reactive(props.route.meta?.__clicksElements || [])
11
+
12
+ const route = computed(() => props.route)
13
+ const nav = useNav(route)
14
+ </script>
15
+
16
+ <template>
17
+ <PrintSlideClick v-model:clicks-elements="clicksElements" :clicks="0" :nav="nav" :route="route" />
18
+ <template v-if="!isClicksDisabled">
19
+ <PrintSlideClick v-for="i of (clicksElements.length)" :key="i" :clicks="i" :nav="nav" :route="route" />
20
+ </template>
21
+ </template>
@@ -0,0 +1,69 @@
1
+ <script setup lang="ts">
2
+ import type { RouteRecordRaw } from 'vue-router'
3
+ import { computed, provide, reactive, shallowRef } from 'vue'
4
+ import { useVModel } from '@vueuse/core'
5
+ import { useNavClicks } from '../composables/useNavClicks'
6
+ import { injectionSlidevContext } from '../constants'
7
+ import { configs, slideHeight, slideWidth } from '../env'
8
+ import { getSlideClass } from '../utils'
9
+ import type { SlidevContextNav } from '../modules/context'
10
+ import SlideWrapper from './SlideWrapper'
11
+ // @ts-expect-error virtual module
12
+ import GlobalTop from '/@slidev/global-components/top'
13
+ // @ts-expect-error virtual module
14
+ import GlobalBottom from '/@slidev/global-components/bottom'
15
+
16
+ const props = defineProps<{
17
+ clicks: number
18
+ clicksElements?: HTMLElement[]
19
+ nav: SlidevContextNav
20
+ route: RouteRecordRaw
21
+ }>()
22
+
23
+ const emit = defineEmits(['update:clicksElements'])
24
+
25
+ const clicksElements = useVModel(props, 'clicksElements', emit)
26
+
27
+ const style = computed(() => ({
28
+ height: `${slideHeight}px`,
29
+ width: `${slideWidth}px`,
30
+ }))
31
+
32
+ const DrawingPreview = shallowRef<any>()
33
+ if (__SLIDEV_FEATURE_DRAWINGS__ || __SLIDEV_FEATURE_DRAWINGS_PERSIST__)
34
+ import('./DrawingPreview.vue').then(v => (DrawingPreview.value = v.default))
35
+
36
+ const clicks = computed(() => props.clicks)
37
+ const navClicks = useNavClicks(clicks, props.nav.currentRoute, props.nav.currentPage)
38
+
39
+ provide(injectionSlidevContext, reactive({
40
+ nav: { ...props.nav, ...navClicks },
41
+ configs,
42
+ themeConfigs: computed(() => configs.themeConfig),
43
+ }))
44
+ </script>
45
+
46
+ <template>
47
+ <div :id="route.path" class="slide-container" :style="style">
48
+ <GlobalBottom />
49
+
50
+ <SlideWrapper
51
+ :is="route?.component"
52
+ v-model:clicks-elements="clicksElements"
53
+ :clicks="clicks"
54
+ :clicks-disabled="false"
55
+ :class="getSlideClass(route)"
56
+ />
57
+ <template
58
+ v-if="
59
+ (__SLIDEV_FEATURE_DRAWINGS__ ||
60
+ __SLIDEV_FEATURE_DRAWINGS_PERSIST__) &&
61
+ DrawingPreview
62
+ "
63
+ >
64
+ <DrawingPreview :page="+route.path" />
65
+ </template>
66
+
67
+ <GlobalTop />
68
+ </div>
69
+ </template>
package/logic/drawings.ts CHANGED
@@ -65,9 +65,9 @@ export function updateState() {
65
65
  canClear.value = !!drauu.el?.children.length
66
66
  }
67
67
 
68
- export function loadCanvas() {
68
+ export function loadCanvas(page?: number) {
69
69
  disableDump = true
70
- const data = drawingState[currentPage.value]
70
+ const data = drawingState[page || currentPage.value]
71
71
  if (data != null)
72
72
  drauu.load(data)
73
73
  else
package/logic/nav.ts CHANGED
@@ -80,7 +80,7 @@ export const rawTree = computed(() => rawRoutes
80
80
  addToTree(acc, route)
81
81
  return acc
82
82
  }, []))
83
- export const treeWithActiveStatuses = computed(() => getTreeWithActiveStatuses(rawTree.value))
83
+ export const treeWithActiveStatuses = computed(() => getTreeWithActiveStatuses(rawTree.value, currentRoute.value))
84
84
  export const tree = computed(() => filterTree(treeWithActiveStatuses.value))
85
85
 
86
86
  export function next() {
@@ -192,24 +192,25 @@ export function addToTree(tree: TocItem[], route: RouteRecordRaw, level = 1) {
192
192
 
193
193
  export function getTreeWithActiveStatuses(
194
194
  tree: TocItem[],
195
+ currentRoute?: RouteRecordRaw,
195
196
  hasActiveParent = false,
196
197
  parent?: TocItem,
197
198
  ): TocItem[] {
198
199
  return tree.map((item: TocItem) => {
199
200
  const clone = {
200
201
  ...item,
201
- active: item.path === currentRoute.value?.path,
202
+ active: item.path === currentRoute?.path,
202
203
  hasActiveParent,
203
204
  }
204
205
  if (clone.children.length > 0)
205
- clone.children = getTreeWithActiveStatuses(clone.children, clone.active || clone.hasActiveParent, clone)
206
+ clone.children = getTreeWithActiveStatuses(clone.children, currentRoute, clone.active || clone.hasActiveParent, clone)
206
207
  if (parent && (clone.active || clone.activeParent))
207
208
  parent.activeParent = true
208
209
  return clone
209
210
  })
210
211
  }
211
212
 
212
- function filterTree(tree: TocItem[], level = 1): TocItem[] {
213
+ export function filterTree(tree: TocItem[], level = 1): TocItem[] {
213
214
  return tree
214
215
  .filter((item: TocItem) => !item.hideInToc)
215
216
  .map((item: TocItem) => ({
@@ -73,6 +73,7 @@ export function useRecording() {
73
73
  const recorderCamera: Ref<RecorderType | undefined> = shallowRef()
74
74
  const recorderSlides: Ref<RecorderType | undefined> = shallowRef()
75
75
  const streamCamera: Ref<MediaStream | undefined> = shallowRef()
76
+ const streamCapture: Ref<MediaStream | undefined> = shallowRef()
76
77
  const streamSlides: Ref<MediaStream | undefined> = shallowRef()
77
78
 
78
79
  const config: RecorderOptions = {
@@ -140,7 +141,7 @@ export function useRecording() {
140
141
  const { default: Recorder } = await import('recordrtc')
141
142
  await startCameraStream()
142
143
 
143
- streamSlides.value = await navigator.mediaDevices.getDisplayMedia({
144
+ streamCapture.value = await navigator.mediaDevices.getDisplayMedia({
144
145
  video: {
145
146
  // aspectRatio: 1.6,
146
147
  frameRate: 15,
@@ -151,6 +152,11 @@ export function useRecording() {
151
152
  resizeMode: 'crop-and-scale',
152
153
  },
153
154
  })
155
+ streamCapture.value.addEventListener('inactive', stopRecording)
156
+
157
+ // We need to create a new Stream to merge video and audio to have the inactive event working on streamCapture
158
+ streamSlides.value = new MediaStream()
159
+ streamCapture.value!.getVideoTracks().forEach(videoTrack => streamSlides.value!.addTrack(videoTrack))
154
160
 
155
161
  // merge config
156
162
  Object.assign(config, customConfig)
@@ -194,6 +200,7 @@ export function useRecording() {
194
200
  const url = URL.createObjectURL(blob)
195
201
  download(getFilename('screen', config.mimeType), url)
196
202
  window.URL.revokeObjectURL(url)
203
+ closeStream(streamCapture)
197
204
  closeStream(streamSlides)
198
205
  recorderSlides.value = undefined
199
206
  })
@@ -237,6 +244,7 @@ export function useRecording() {
237
244
  recorderCamera,
238
245
  recorderSlides,
239
246
  streamCamera,
247
+ streamCapture,
240
248
  streamSlides,
241
249
  }
242
250
  }
@@ -1,37 +1,30 @@
1
1
  import type { App } from 'vue'
2
- import { computed, reactive, readonly } from 'vue'
3
- import { objectKeys } from '@antfu/utils'
2
+ import { reactive } from 'vue'
4
3
  import type { UnwrapNestedRefs } from '@vue/reactivity'
4
+ import type { configs } from '../env'
5
5
  import * as nav from '../logic/nav'
6
+ import { clicks, route } from '../logic/nav'
6
7
  import { isDark } from '../logic/dark'
7
- import { configs } from '../env'
8
+ import { injectionSlidevContext } from '../constants'
9
+ import { useContext } from '../composables/useContext'
8
10
 
9
- declare module '@vue/runtime-core' {
10
- interface ComponentCustomProperties {
11
- $slidev: {
12
- nav: UnwrapNestedRefs<typeof nav>
13
- configs: typeof configs
14
- themeConfigs: typeof configs['themeConfig']
15
- }
16
- }
11
+ export type SlidevContextNavKey = 'route' | 'path' | 'total' | 'currentPage' | 'currentPath' | 'currentRoute' | 'currentSlideId' | 'currentLayout' | 'nextRoute'| 'rawTree' | 'treeWithActiveStatuses' | 'tree' | 'downloadPDF' | 'next' | 'nextSlide' | 'openInEditor' | 'prev' | 'prevSlide'
12
+ export type SlidevContextNavClicksKey = 'clicks' | 'clicksElements' | 'clicksTotal' | 'hasNext' | 'hasPrev'
13
+
14
+ export type SlidevContextNav = Pick<typeof nav, SlidevContextNavKey>
15
+ export type SlidevContextNavClicks = Pick<typeof nav, SlidevContextNavClicksKey>
16
+
17
+ export interface SlidevContext {
18
+ nav: UnwrapNestedRefs<SlidevContextNav & SlidevContextNavClicks>
19
+ configs: typeof configs
20
+ themeConfigs: typeof configs['themeConfig']
17
21
  }
18
22
 
19
23
  export default function createSlidevContext() {
20
24
  return {
21
25
  install(app: App) {
22
- const navObj: typeof nav = {} as any
23
- // need to copy over to get rid of the "Module" object type (will not unwrap)
24
- for (const key of objectKeys(nav)) {
25
- if (typeof key === 'string')
26
- // @ts-expect-error I know :)
27
- navObj[key] = nav[key]
28
- }
29
- const context = reactive({
30
- nav: navObj,
31
- configs,
32
- themeConfigs: computed(() => configs.themeConfig),
33
- })
34
- app.config.globalProperties.$slidev = readonly(context)
26
+ const context = useContext(route, clicks)
27
+ app.provide(injectionSlidevContext, reactive(context))
35
28
 
36
29
  // allows controls from postMessages
37
30
  if (__DEV__) {
@@ -40,7 +33,7 @@ export default function createSlidevContext() {
40
33
  window.addEventListener('message', ({ data }) => {
41
34
  if (data && data.target === 'slidev') {
42
35
  if (data.type === 'navigate') {
43
- context.nav.go(+data.no, +data.clicks || 0)
36
+ nav.go(+data.no, +data.clicks || 0)
44
37
  }
45
38
  else if (data.type === 'css-vars') {
46
39
  const root = document.documentElement
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slidev/client",
3
- "version": "0.29.2",
3
+ "version": "0.30.0",
4
4
  "description": "Presentation slides for developers",
5
5
  "homepage": "https://sli.dev",
6
6
  "bugs": "https://github.com/slidevjs/slidev/issues",
@@ -12,27 +12,29 @@
12
12
  },
13
13
  "funding": "https://github.com/sponsors/antfu",
14
14
  "dependencies": {
15
- "@antfu/utils": "^0.5.0",
16
- "@slidev/parser": "0.29.2",
17
- "@slidev/types": "0.29.2",
18
- "@vueuse/core": "^8.1.2",
15
+ "@antfu/utils": "^0.5.1",
16
+ "@slidev/parser": "0.30.0",
17
+ "@slidev/types": "0.30.0",
18
+ "@vueuse/core": "^8.2.5",
19
19
  "@vueuse/head": "^0.7.5",
20
- "@vueuse/motion": "^2.0.0-beta.12",
20
+ "@vueuse/motion": "^2.0.0-beta.18",
21
21
  "codemirror": "^5.65.2",
22
+ "defu": "^6.0.0",
22
23
  "drauu": "^0.3.0",
23
24
  "file-saver": "^2.0.5",
24
25
  "js-base64": "^3.7.2",
25
26
  "js-yaml": "^4.1.0",
26
27
  "katex": "^0.15.3",
27
- "mermaid": "^8.14.0",
28
+ "mermaid": "^9.0.0",
28
29
  "monaco-editor": "^0.33.0",
29
- "nanoid": "^3.3.1",
30
- "prettier": "^2.6.0",
30
+ "nanoid": "^3.3.2",
31
+ "prettier": "^2.6.2",
31
32
  "recordrtc": "^5.6.2",
32
33
  "resolve": "^1.22.0",
33
- "vite-plugin-windicss": "^1.8.3",
34
- "vue": "^3.2.31",
34
+ "vite-plugin-windicss": "^1.8.4",
35
+ "vue": "^3.2.32",
35
36
  "vue-router": "^4.0.14",
37
+ "vue-starport": "^0.2.4",
36
38
  "windicss": "^3.5.1"
37
39
  },
38
40
  "engines": {
package/routes.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { RouteRecordRaw } from 'vue-router'
2
2
  import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
3
3
  import Play from './internals/Play.vue'
4
+ import Print from './internals/Print.vue'
4
5
  // @ts-expect-error missing types
5
6
  import _rawRoutes from '/@slidev/routes'
6
7
 
@@ -15,6 +16,7 @@ export const routes: RouteRecordRaw[] = [
15
16
  ...rawRoutes,
16
17
  ],
17
18
  },
19
+ { name: 'print', path: '/print', component: Print },
18
20
  { path: '', redirect: { path: '/1' } },
19
21
  { path: '/:pathMatch(.*)', redirect: { path: '/1' } },
20
22
  ]
package/setup/main.ts CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type { AppContext } from '@slidev/types'
4
4
  import { MotionPlugin } from '@vueuse/motion'
5
+ import StarportPlugin from 'vue-starport'
5
6
 
6
7
  export default function setupMain(context: AppContext) {
7
8
  function setMaxHeight() {
@@ -13,6 +14,7 @@ export default function setupMain(context: AppContext) {
13
14
  window.addEventListener('resize', setMaxHeight)
14
15
 
15
16
  context.app.use(MotionPlugin)
17
+ context.app.use(StarportPlugin({ keepAlive: true }))
16
18
 
17
19
  // @ts-expect-error inject in runtime
18
20
  // eslint-disable-next-line @typescript-eslint/no-unused-vars