@slidev/client 0.28.10 → 0.29.2

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/builtin/Toc.vue CHANGED
@@ -15,12 +15,14 @@ import { tree } from '../logic/nav'
15
15
  const props = withDefaults(
16
16
  defineProps<{
17
17
  columns?: string | number
18
+ listClass?: string | string[]
18
19
  maxDepth?: string | number
19
20
  minDepth?: string | number
20
21
  mode?: 'all' | 'onlyCurrentTree' | 'onlySiblings'
21
22
  }>(),
22
23
  {
23
24
  columns: 1,
25
+ listClass: '',
24
26
  maxDepth: Infinity,
25
27
  minDepth: 1,
26
28
  mode: 'all',
@@ -78,6 +80,6 @@ const toc = computed(() => {
78
80
 
79
81
  <template>
80
82
  <div class="slidev-toc" :style="`column-count:${columns}`">
81
- <TocList :level="1" :list="toc" />
83
+ <TocList :level="1" :list="toc" :list-class="listClass" />
82
84
  </div>
83
85
  </template>
@@ -7,19 +7,30 @@ Usage:
7
7
  <TocList :list="list"/>
8
8
  -->
9
9
  <script setup lang="ts">
10
+ import { computed } from 'vue'
11
+ import { toArray } from '@antfu/utils'
10
12
  import type { TocItem } from '../logic/nav'
11
13
 
12
- withDefaults(defineProps<{
14
+ const props = withDefaults(defineProps<{
13
15
  level: number
14
16
  list: TocItem[]
17
+ listClass?: string | string[]
15
18
  }>(), { level: 1 })
19
+
20
+ const classes = computed(() => {
21
+ return [
22
+ ...toArray(props.listClass || []),
23
+ 'slidev-toc-list',
24
+ `slidev-toc-list-level-${props.level}`,
25
+ ]
26
+ })
16
27
  </script>
17
28
 
18
29
  <template>
19
- <ul v-if="list && list.length > 0" :class="['slidev-toc-list', `slidev-toc-list-level-${level}`]">
30
+ <ol v-if="list && list.length > 0" :class="classes">
20
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}]">
21
32
  <RouterLink :to="item.path" v-html="item.title" />
22
- <TocList :level="level + 1" :list="item.children" />
33
+ <TocList :level="level + 1" :list="item.children" :list-class="listClass" />
23
34
  </li>
24
- </ul>
35
+ </ol>
25
36
  </template>
@@ -1,7 +1,14 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from 'vue'
3
3
  import { currentCamera, currentMic } from '../state'
4
- import { cameras, ensureDevicesListPermissions, microphones } from '../logic/recording'
4
+ import {
5
+ cameras,
6
+ ensureDevicesListPermissions,
7
+ microphones,
8
+ mimeExtMap,
9
+ mimeType,
10
+ supportedMimeTypes,
11
+ } from '../logic/recording'
5
12
  import SelectList from './SelectList.vue'
6
13
  import type { SelectionItem } from './types'
7
14
 
@@ -27,6 +34,11 @@ const microphonesItems = computed<SelectionItem<string>[]>(() => [
27
34
  })),
28
35
  ])
29
36
 
37
+ const mimeTypeItems = supportedMimeTypes.map(mime => ({
38
+ value: mime,
39
+ display: mimeExtMap[mime].toUpperCase(),
40
+ }))
41
+
30
42
  ensureDevicesListPermissions()
31
43
  </script>
32
44
 
@@ -34,5 +46,11 @@ ensureDevicesListPermissions()
34
46
  <div class="text-sm">
35
47
  <SelectList v-model="currentCamera" title="Camera" :items="camerasItems" />
36
48
  <SelectList v-model="currentMic" title="Microphone" :items="microphonesItems" />
49
+ <SelectList
50
+ v-if="mimeTypeItems.length"
51
+ v-model="mimeType"
52
+ title="mimeType"
53
+ :items="mimeTypeItems"
54
+ />
37
55
  </div>
38
56
  </template>
@@ -8,6 +8,8 @@ import { configs } from '../env'
8
8
  import Settings from './Settings.vue'
9
9
  import MenuButton from './MenuButton.vue'
10
10
  import VerticalDivider from './VerticalDivider.vue'
11
+ // @ts-expect-error virtual module
12
+ import CustomNavControls from '/@slidev/custom-nav-controls'
11
13
 
12
14
  const props = defineProps({
13
15
  persist: {
@@ -153,6 +155,8 @@ if (__SLIDEV_FEATURE_DRAWINGS__)
153
155
  <span class="opacity-50">/ {{ total }}</span>
154
156
  </div>
155
157
  </div>
158
+
159
+ <CustomNavControls />
156
160
  </div>
157
161
  </nav>
158
162
  </template>
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { useVModel } from '@vueuse/core'
3
3
  import { nextTick } from 'vue'
4
- import { getFilename, recordCamera, recorder, recordingName } from '../logic/recording'
4
+ import { getFilename, mimeType, recordCamera, recorder, recordingName } from '../logic/recording'
5
5
  import Modal from './Modal.vue'
6
6
  import DevicesList from './DevicesList.vue'
7
7
 
@@ -25,7 +25,9 @@ function close() {
25
25
  async function start() {
26
26
  close()
27
27
  await nextTick()
28
- startRecording()
28
+ startRecording({
29
+ mimeType: mimeType.value,
30
+ })
29
31
  }
30
32
  </script>
31
33
 
@@ -46,7 +48,7 @@ async function start() {
46
48
  placeholder="Enter the title..."
47
49
  >
48
50
  <div class="text-xs w-full opacity-50 py-2">
49
- <div>This will be used in the output filename that might <br>help you better orangize your recording chips.</div>
51
+ <div>This will be used in the output filename that might <br>help you better organize your recording chips.</div>
50
52
  </div>
51
53
  </div>
52
54
  <div class="form-check">
@@ -57,15 +59,16 @@ async function start() {
57
59
  >
58
60
  <label for="record-camera" @click="recordCamera = !recordCamera">Record camera separately</label>
59
61
  </div>
62
+
60
63
  <div class="text-xs w-full opacity-50">
61
64
  <div class="mt-2 opacity-50">
62
65
  Enumerated filenames
63
66
  </div>
64
67
  <div class="font-mono">
65
- {{ getFilename('screen') }}
68
+ {{ getFilename('screen', mimeType) }}
66
69
  </div>
67
70
  <div v-if="recordCamera" class="font-mono">
68
- {{ getFilename('camera') }}
71
+ {{ getFilename('camera', mimeType) }}
69
72
  </div>
70
73
  </div>
71
74
  </div>
@@ -1,24 +1,44 @@
1
1
  import type { Ref } from 'vue'
2
2
  import { nextTick, ref, shallowRef, watch } from 'vue'
3
- import { useDevicesList, useEventListener } from '@vueuse/core'
3
+ import { useDevicesList, useEventListener, useStorage } from '@vueuse/core'
4
4
  import { isTruthy } from '@antfu/utils'
5
5
  import type RecorderType from 'recordrtc'
6
6
  import type { Options as RecorderOptions } from 'recordrtc'
7
7
  import { currentCamera, currentMic } from '../state'
8
8
 
9
+ type Defined<T> = T extends undefined ? never : T
10
+ type MimeType = Defined<RecorderOptions['mimeType']>
11
+
9
12
  export const recordingName = ref('')
10
13
  export const recordCamera = ref(true)
14
+ export const mimeType = useStorage<MimeType>('slidev-record-mimetype', 'video/webm')
15
+
16
+ export const mimeExtMap: Record<string, string> = {
17
+ 'video/webm': 'webm',
18
+ 'video/webm;codecs=h264': 'mp4',
19
+ 'video/x-matroska;codecs=avc1': 'mkv',
20
+ }
11
21
 
12
- export function getFilename(media?: string) {
22
+ export function getFilename(media?: string, mimeType?: string) {
13
23
  const d = new Date()
14
24
 
15
25
  const pad = (v: number) => `${v}`.padStart(2, '0')
16
26
 
17
27
  const date = `${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}`
18
28
 
19
- return `${[media, recordingName.value, date].filter(isTruthy).join('-')}.webm`
29
+ const ext = mimeType ? mimeExtMap[mimeType] : 'webm'
30
+
31
+ return `${[media, recordingName.value, date].filter(isTruthy).join('-')}.${ext}`
20
32
  }
21
33
 
34
+ function getSupportedMimeTypes() {
35
+ if (MediaRecorder && typeof MediaRecorder.isTypeSupported === 'function')
36
+ return Object.keys(mimeExtMap).filter(mime => MediaRecorder.isTypeSupported(mime))
37
+ return []
38
+ }
39
+
40
+ export const supportedMimeTypes = getSupportedMimeTypes()
41
+
22
42
  export const {
23
43
  devices,
24
44
  videoInputs: cameras,
@@ -115,7 +135,7 @@ export function useRecording() {
115
135
  }
116
136
  })
117
137
 
118
- async function startRecording() {
138
+ async function startRecording(customConfig?: RecorderOptions) {
119
139
  await ensureDevicesListPermissions()
120
140
  const { default: Recorder } = await import('recordrtc')
121
141
  await startCameraStream()
@@ -132,6 +152,9 @@ export function useRecording() {
132
152
  },
133
153
  })
134
154
 
155
+ // merge config
156
+ Object.assign(config, customConfig)
157
+
135
158
  if (streamCamera.value) {
136
159
  const audioTrack = streamCamera.value!.getAudioTracks()?.[0]
137
160
  if (audioTrack)
@@ -159,7 +182,7 @@ export function useRecording() {
159
182
  if (recordCamera.value) {
160
183
  const blob = recorderCamera.value!.getBlob()
161
184
  const url = URL.createObjectURL(blob)
162
- download(getFilename('camera'), url)
185
+ download(getFilename('camera', config.mimeType), url)
163
186
  window.URL.revokeObjectURL(url)
164
187
  }
165
188
  recorderCamera.value = undefined
@@ -169,7 +192,7 @@ export function useRecording() {
169
192
  recorderSlides.value?.stopRecording(() => {
170
193
  const blob = recorderSlides.value!.getBlob()
171
194
  const url = URL.createObjectURL(blob)
172
- download(getFilename('screen'), url)
195
+ download(getFilename('screen', config.mimeType), url)
173
196
  window.URL.revokeObjectURL(url)
174
197
  closeStream(streamSlides)
175
198
  recorderSlides.value = undefined
package/package.json CHANGED
@@ -1,38 +1,38 @@
1
1
  {
2
2
  "name": "@slidev/client",
3
- "version": "0.28.10",
3
+ "version": "0.29.2",
4
4
  "description": "Presentation slides for developers",
5
5
  "homepage": "https://sli.dev",
6
6
  "bugs": "https://github.com/slidevjs/slidev/issues",
7
7
  "license": "MIT",
8
+ "author": "antfu <anthonyfu117@hotmail.com>",
8
9
  "repository": {
9
10
  "type": "git",
10
11
  "url": "https://github.com/slidevjs/slidev"
11
12
  },
12
13
  "funding": "https://github.com/sponsors/antfu",
13
- "author": "antfu <anthonyfu117@hotmail.com>",
14
14
  "dependencies": {
15
15
  "@antfu/utils": "^0.5.0",
16
- "@slidev/parser": "0.28.10",
17
- "@slidev/types": "0.28.10",
18
- "@vueuse/core": "^7.7.0",
16
+ "@slidev/parser": "0.29.2",
17
+ "@slidev/types": "0.29.2",
18
+ "@vueuse/core": "^8.1.2",
19
19
  "@vueuse/head": "^0.7.5",
20
- "@vueuse/motion": "^2.0.0-beta.9",
20
+ "@vueuse/motion": "^2.0.0-beta.12",
21
21
  "codemirror": "^5.65.2",
22
22
  "drauu": "^0.3.0",
23
23
  "file-saver": "^2.0.5",
24
24
  "js-base64": "^3.7.2",
25
25
  "js-yaml": "^4.1.0",
26
- "katex": "^0.15.2",
26
+ "katex": "^0.15.3",
27
27
  "mermaid": "^8.14.0",
28
- "monaco-editor": "^0.32.1",
28
+ "monaco-editor": "^0.33.0",
29
29
  "nanoid": "^3.3.1",
30
- "prettier": "^2.5.1",
30
+ "prettier": "^2.6.0",
31
31
  "recordrtc": "^5.6.2",
32
32
  "resolve": "^1.22.0",
33
- "vite-plugin-windicss": "^1.8.2",
33
+ "vite-plugin-windicss": "^1.8.3",
34
34
  "vue": "^3.2.31",
35
- "vue-router": "^4.0.13",
35
+ "vue-router": "^4.0.14",
36
36
  "windicss": "^3.5.1"
37
37
  },
38
38
  "engines": {