+
-
+
diff --git a/packages/client/internals/SlidesShow.vue b/packages/client/internals/SlidesShow.vue
index 4c8e6d5f9c..6883945fb2 100644
--- a/packages/client/internals/SlidesShow.vue
+++ b/packages/client/internals/SlidesShow.vue
@@ -26,6 +26,7 @@ const {
isPrintMode,
isPrintWithClicks,
clicksDirection,
+ printRange,
} = useNav()
function preloadRoute(route: SlideRoute) {
@@ -55,7 +56,10 @@ const DrawingLayer = shallowRef
()
if (__SLIDEV_FEATURE_DRAWINGS__ || __SLIDEV_FEATURE_DRAWINGS_PERSIST__)
import('./DrawingLayer.vue').then(v => DrawingLayer.value = v.default)
-const loadedRoutes = computed(() => slides.value.filter(r => r.meta?.__preloaded || r === currentSlideRoute.value))
+const loadedRoutes = computed(() => isPrintMode.value
+ ? printRange.value.map(no => slides.value[no - 1])
+ : slides.value.filter(r => r.meta?.__preloaded || r === currentSlideRoute.value),
+)
function onAfterLeave() {
// After transition, we disable it so HMR won't trigger it again
@@ -72,8 +76,8 @@ function onAfterLeave() {
+import type { ScreenshotSession } from '../logic/screenshot'
+import { sleep } from '@antfu/utils'
+import { parseRangeString } from '@slidev/parser/utils'
+import { useHead } from '@unhead/vue'
+import { provideLocal, useElementSize, useLocalStorage, useStyleTag, watchDebounced } from '@vueuse/core'
+
+import { computed, ref, useTemplateRef, watch } from 'vue'
+import { useRouter } from 'vue-router'
+import { useDarkMode } from '../composables/useDarkMode'
+import { useNav } from '../composables/useNav'
+import { patchMonacoColors } from '../composables/usePrintStyles'
+import { injectionSlideScale } from '../constants'
+import { configs, slideHeight, slidesTitle, slideWidth } from '../env'
+import ExportPdfTip from '../internals/ExportPdfTip.vue'
+import FormCheckbox from '../internals/FormCheckbox.vue'
+import FormItem from '../internals/FormItem.vue'
+import PrintSlide from '../internals/PrintSlide.vue'
+import { isScreenshotSupported, startScreenshotSession } from '../logic/screenshot'
+import { skipExportPdfTip } from '../state'
+import Play from './play.vue'
+
+const { slides, isPrintWithClicks, hasNext, go, next, currentSlideNo, clicks, printRange } = useNav()
+const router = useRouter()
+const { isColorSchemaConfigured, isDark } = useDarkMode()
+const { width: containerWidth } = useElementSize(useTemplateRef('export-container'))
+const { height: contentHeight } = useElementSize(useTemplateRef('export-content'))
+const scale = computed(() => containerWidth.value / slideWidth.value)
+const contentMarginBottom = computed(() => `${contentHeight.value * (scale.value - 1)}px`)
+const rangesRaw = ref('')
+const initialWait = ref(1000)
+const delay = useLocalStorage('slidev-export-capture-delay', 400, { listenToStorageChanges: false })
+type ScreenshotResult = { slideIndex: number, clickIndex: number, dataUrl: string }[]
+const screenshotSession = ref(null)
+const capturedImages = ref(null)
+const title = ref(configs.exportFilename || slidesTitle)
+
+useHead({
+ title,
+})
+
+provideLocal(injectionSlideScale, scale)
+
+const showExportPdfTip = ref(false)
+function pdf() {
+ if (skipExportPdfTip.value) {
+ doPrint()
+ }
+ else {
+ showExportPdfTip.value = true
+ }
+}
+
+function doPrint() {
+ patchMonacoColors()
+ setTimeout(window.print, 100)
+}
+
+async function capturePngs() {
+ if (screenshotSession.value) {
+ screenshotSession.value.dispose()
+ screenshotSession.value = null
+ }
+ if (capturedImages.value)
+ return capturedImages.value
+ try {
+ const scale = 2
+ screenshotSession.value = await startScreenshotSession(slideWidth.value * scale, slideHeight.value * scale)
+ const result: ScreenshotResult = []
+
+ go(1, 0, true)
+
+ await sleep(initialWait.value + delay.value)
+ while (true) {
+ if (!screenshotSession.value) {
+ break
+ }
+ result.push({
+ slideIndex: currentSlideNo.value - 1,
+ clickIndex: clicks.value,
+ dataUrl: screenshotSession.value.screenshot(document.getElementById('slide-content')!),
+ })
+ if (hasNext.value) {
+ await sleep(delay.value)
+ next()
+ await sleep(delay.value)
+ }
+ else {
+ break
+ }
+ }
+
+ if (screenshotSession.value) {
+ screenshotSession.value.dispose()
+ capturedImages.value = result
+ screenshotSession.value = null
+ }
+ }
+ catch (e) {
+ console.error(e)
+ capturedImages.value = null
+ }
+ finally {
+ router.push('/export')
+ }
+ return capturedImages.value
+}
+
+async function pptx() {
+ const pngs = await capturePngs()
+ if (!pngs)
+ return
+ const pptx = await import('pptxgenjs')
+ .then(r => r.default)
+ .then(PptxGen => new PptxGen())
+
+ const layoutName = `${slideWidth.value}x${slideHeight.value}`
+ pptx.defineLayout({
+ name: layoutName,
+ width: slideWidth.value / 96,
+ height: slideHeight.value / 96,
+ })
+ pptx.layout = layoutName
+ if (configs.author)
+ pptx.author = configs.author
+ pptx.company = 'Created using Slidev'
+ pptx.title = title.value
+ if (typeof configs.info === 'string')
+ pptx.subject = configs.info
+
+ pngs.forEach(({ slideIndex, dataUrl }) => {
+ const slide = pptx.addSlide()
+ slide.background = {
+ data: dataUrl,
+ }
+
+ const note = slides.value[slideIndex].meta.slide.note
+ if (note)
+ slide.addNotes(note)
+ })
+
+ const blob = await pptx.write({
+ outputType: 'blob',
+ compression: true,
+ }) as Blob
+ const url = URL.createObjectURL(blob)
+ const a = document.createElement('a')
+ a.href = url
+ a.download = `${title.value}.pptx`
+ a.click()
+}
+
+async function pngsGz() {
+ const pngs = await capturePngs()
+ if (!pngs)
+ return
+ const { createTarGzip } = await import('nanotar')
+ const data = await createTarGzip(
+ pngs.map(({ slideIndex, dataUrl }) => ({
+ name: `${slideIndex}.png`,
+ data: new Uint8Array(atob(dataUrl.split(',')[1]).split('').map(char => char.charCodeAt(0))),
+ })),
+ )
+ const a = document.createElement('a')
+ const blob = new Blob([data], { type: 'application/gzip' })
+ a.href = URL.createObjectURL(blob)
+ a.download = `${title.value}.tar.gz`
+ a.click()
+}
+
+useStyleTag(computed(() => screenshotSession.value?.isActive
+ ? `
+html {
+ cursor: none;
+ margin-bottom: 20px;
+}
+body {
+ pointer-events: none;
+}`
+ : `
+:root {
+ --slidev-slide-scale: ${scale.value};
+}
+`))
+
+// clear captured images when settings changed
+watch(
+ [
+ isDark,
+ printRange,
+ isPrintWithClicks,
+ ],
+ () => capturedImages.value = null,
+)
+
+watchDebounced(
+ [slides, rangesRaw],
+ () => printRange.value = parseRangeString(slides.value.length, rangesRaw.value),
+ { debounce: 300 },
+)
+
+// clear captured images when HMR
+if (import.meta.hot) {
+ import.meta.hot.on('vite:beforeUpdate', () => {
+ capturedImages.value = null
+ })
+}
+
+
+
+
+
+
+
+
+ Browser Exporter
+ Experimental
+
+
+
Options
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Export as Vector File
+
+
+
+
+
+
+
Export as Images
+
+
+ Your browser may not support image capturing.
+ If you encounter issues, please use a modern Chromium-based browser,
+ or export via the CLI.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rendering as {{ capturedImages ? 'Captured Images' : 'DOM' }}
+
+
+
+
+
![]()
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/client/pages/play.vue b/packages/client/pages/play.vue
index 1ac216bd9d..71ad63098e 100644
--- a/packages/client/pages/play.vue
+++ b/packages/client/pages/play.vue
@@ -8,12 +8,11 @@ import { useWakeLock } from '../composables/useWakeLock'
import Controls from '../internals/Controls.vue'
import NavControls from '../internals/NavControls.vue'
import PresenterMouse from '../internals/PresenterMouse.vue'
-import PrintStyle from '../internals/PrintStyle.vue'
import SlideContainer from '../internals/SlideContainer.vue'
import SlidesShow from '../internals/SlidesShow.vue'
import { onContextMenu } from '../logic/contextMenu'
import { registerShortcuts } from '../logic/shortcuts'
-import { editorHeight, editorWidth, isEditorVertical, isScreenVertical, showEditor, windowSize } from '../state'
+import { editorHeight, editorWidth, isEditorVertical, isScreenVertical, showEditor } from '../state'
const { next, prev, isPrintMode } = useNav()
const { isDrawing } = useDrawings()
@@ -63,14 +62,12 @@ if (__DEV__ && __SLIDEV_FEATURE_EDITOR__)
-
{
-
{
- if (!hasPrimarySlide.value)
+ if (!hasPrimarySlide.value || isPrintMode.value)
return
if (state.lastUpdate?.type === 'presenter' && (+state.page !== +currentSlideNo.value || +clicksContext.value.current !== +state.clicks)) {
skipTransition.value = false
diff --git a/packages/client/setup/routes.ts b/packages/client/setup/routes.ts
index c6d626e81a..16c546d288 100644
--- a/packages/client/setup/routes.ts
+++ b/packages/client/setup/routes.ts
@@ -5,21 +5,21 @@ import setups from '#slidev/setups/routes'
export default function setupRoutes() {
const routes: RouteRecordRaw[] = []
- if (__SLIDEV_FEATURE_PRESENTER__) {
- function passwordGuard(to: RouteLocationNormalized) {
- if (!configs.remote || configs.remote === to.query.password)
+ function passwordGuard(to: RouteLocationNormalized) {
+ if (!configs.remote || configs.remote === to.query.password)
+ return true
+ if (configs.remote && to.query.password === undefined) {
+ // eslint-disable-next-line no-alert
+ const password = prompt('Enter password')
+ if (configs.remote === password)
return true
- if (configs.remote && to.query.password === undefined) {
- // eslint-disable-next-line no-alert
- const password = prompt('Enter password')
- if (configs.remote === password)
- return true
- }
- if (to.params.no)
- return { path: `/${to.params.no}` }
- return { path: '' }
}
+ if (to.params.no)
+ return { path: `/${to.params.no}` }
+ return { path: '' }
+ }
+ if (__SLIDEV_FEATURE_PRESENTER__) {
routes.push(
{
name: 'entry',
@@ -64,6 +64,17 @@ export default function setupRoutes() {
)
}
+ if (__SLIDEV_FEATURE_BROWSER_EXPORTER__) {
+ routes.push(
+ {
+ name: 'export',
+ path: '/export/:no?',
+ component: () => import('../pages/export.vue'),
+ beforeEnter: passwordGuard,
+ },
+ )
+ }
+
routes.push(
{
name: 'play',
diff --git a/packages/client/state/index.ts b/packages/client/state/index.ts
index a5b606d6f9..e48cd120db 100644
--- a/packages/client/state/index.ts
+++ b/packages/client/state/index.ts
@@ -26,6 +26,7 @@ export const currentCamera = useLocalStorage('slidev-camera', 'default',
export const currentMic = useLocalStorage('slidev-mic', 'default', { listenToStorageChanges: false })
export const slideScale = useLocalStorage('slidev-scale', 0)
export const wakeLockEnabled = useLocalStorage('slidev-wake-lock', true)
+export const skipExportPdfTip = useLocalStorage('slidev-skip-export-pdf-tip', false)
export const showPresenterCursor = useLocalStorage('slidev-presenter-cursor', true, { listenToStorageChanges: false })
export const showEditor = useLocalStorage('slidev-show-editor', false, { listenToStorageChanges: false })
diff --git a/packages/client/styles/index.css b/packages/client/styles/index.css
index 4beee5de47..ff624519ba 100644
--- a/packages/client/styles/index.css
+++ b/packages/client/styles/index.css
@@ -8,6 +8,8 @@ body,
height: 100vh;
height: calc(var(--vh, 1vh) * 100);
overflow: hidden;
+ print-color-adjust: exact;
+ -webkit-print-color-adjust: exact;
@apply font-sans;
}
@@ -17,11 +19,10 @@ html {
.slidev-icon-btn {
aspect-ratio: 1;
- display: inline-block;
user-select: none;
outline: none;
cursor: pointer;
- @apply opacity-75 transition duration-200 ease-in-out align-middle rounded p-1;
+ @apply inline-flex items-center justify-center opacity-75 transition duration-200 ease-in-out align-middle rounded p-1;
@apply hover:(opacity-100 bg-gray-400 bg-opacity-10);
@apply focus-visible:(opacity-100 outline outline-2 outline-offset-2 outline-black dark:outline-white);
@apply md:p-2;
@@ -129,7 +130,7 @@ html {
position: fixed;
}
-#twoslash-container .v-popper__wrapper {
+#twoslash-container .v-popper__wrapper:not(.no-slide-scale > *) {
transform: scale(calc(1 * var(--slidev-slide-scale)));
transform-origin: 30px top;
}
diff --git a/packages/parser/src/config.ts b/packages/parser/src/config.ts
index e48470ba47..dcc0f13c87 100644
--- a/packages/parser/src/config.ts
+++ b/packages/parser/src/config.ts
@@ -32,9 +32,11 @@ export function getDefaultConfig(): SlidevConfig {
drawings: {} as ResolvedDrawingsOptions,
plantUmlServer: 'https://www.plantuml.com/plantuml',
codeCopy: true,
+ author: '',
record: 'dev',
css: 'unocss',
presenter: true,
+ browserExporter: 'dev',
htmlAttrs: {},
transition: null,
editor: true,
diff --git a/packages/parser/src/utils.ts b/packages/parser/src/utils.ts
index 9433ecf8b4..0586f3b28d 100644
--- a/packages/parser/src/utils.ts
+++ b/packages/parser/src/utils.ts
@@ -10,20 +10,20 @@ export function parseRangeString(total: number, rangeStr?: string) {
if (rangeStr === 'none')
return []
- const pages: number[] = []
+ const indexes: number[] = []
for (const part of rangeStr.split(/[,;]/g)) {
if (!part.includes('-')) {
- pages.push(+part)
+ indexes.push(+part)
}
else {
const [start, end] = part.split('-', 2)
- pages.push(
+ indexes.push(
...range(+start, !end ? (total + 1) : (+end + 1)),
)
}
}
- return uniq(pages).filter(i => i <= total).sort((a, b) => a - b)
+ return uniq(indexes).filter(i => i <= total).sort((a, b) => a - b)
}
/**
diff --git a/packages/slidev/node/cli.ts b/packages/slidev/node/cli.ts
index 8cdc34e8e3..48bc8ce9be 100644
--- a/packages/slidev/node/cli.ts
+++ b/packages/slidev/node/cli.ts
@@ -10,7 +10,7 @@ import { verifyConfig } from '@slidev/parser'
import equal from 'fast-deep-equal'
import fs from 'fs-extra'
import { getPort } from 'get-port-please'
-import { blue, bold, cyan, dim, gray, green, underline, yellow } from 'kolorist'
+import { blue, bold, cyan, dim, gray, green, lightCyan, underline, yellow } from 'kolorist'
import openBrowser from 'open'
import yargs from 'yargs'
import { version } from '../package.json'
@@ -443,8 +443,19 @@ cli.command(
const { exportSlides, getExportOptions } = await import('./commands/export')
const port = await getPort(12445)
+ let warned = false
for (const entryFile of entry as unknown as string) {
const options = await resolveOptions({ entry: entryFile, theme }, 'export')
+
+ if (options.data.config.browserExporter !== false && !warned) {
+ warned = true
+ console.log(lightCyan('[Slidev] Try the new browser exporter!'))
+ console.log(
+ lightCyan('You can use the browser exporter instead by starting the dev server as normal and visit'),
+ `${blue('localhost:')}${dim('')}${blue('/export')}\n`,
+ )
+ }
+
const server = await createServer(
options,
{
@@ -633,8 +644,11 @@ function printInfo(
console.log(`${dim(' public slide show ')} > ${cyan(`http://localhost:${bold(port)}/`)}`)
if (query)
console.log(`${dim(' private slide show ')} > ${cyan(`http://localhost:${bold(port)}/${query}`)}`)
- console.log(`${dim(' presenter mode ')} > ${blue(`http://localhost:${bold(port)}${presenterPath}`)}`)
+ if (options.utils.define.__SLIDEV_FEATURE_PRESENTER__)
+ console.log(`${dim(' presenter mode ')} > ${blue(`http://localhost:${bold(port)}${presenterPath}`)}`)
console.log(`${dim(' slides overview ')} > ${blue(`http://localhost:${bold(port)}${overviewPath}`)}`)
+ if (options.utils.define.__SLIDEV_FEATURE_BROWSER_EXPORTER__)
+ console.log(`${dim(' export slides')} > ${blue(`http://localhost:${bold(port)}/export/`)}`)
if (options.inspect)
console.log(`${dim(' vite inspector')} > ${yellow(`http://localhost:${bold(port)}/__inspect/`)}`)
diff --git a/packages/slidev/node/options.ts b/packages/slidev/node/options.ts
index 38b041ea98..e17d469604 100644
--- a/packages/slidev/node/options.ts
+++ b/packages/slidev/node/options.ts
@@ -1,6 +1,6 @@
import type { ResolvedSlidevOptions, ResolvedSlidevUtils, SlidevData, SlidevEntryOptions } from '@slidev/types'
import path from 'node:path'
-import { uniq } from '@antfu/utils'
+import { objectMap, uniq } from '@antfu/utils'
import Debug from 'debug'
import fg from 'fast-glob'
import mm from 'micromatch'
@@ -115,17 +115,22 @@ export async function createDataUtils(resolved: Omit): Record {
- return {
- __DEV__: options.mode === 'dev' ? 'true' : 'false',
- __SLIDEV_CLIENT_ROOT__: JSON.stringify(toAtFS(options.clientRoot)),
- __SLIDEV_HASH_ROUTE__: JSON.stringify(options.data.config.routerMode === 'hash'),
- __SLIDEV_FEATURE_DRAWINGS__: JSON.stringify(options.data.config.drawings.enabled === true || options.data.config.drawings.enabled === options.mode),
- __SLIDEV_FEATURE_EDITOR__: JSON.stringify(options.mode === 'dev' && options.data.config.editor !== false),
- __SLIDEV_FEATURE_DRAWINGS_PERSIST__: JSON.stringify(!!options.data.config.drawings.persist === true),
- __SLIDEV_FEATURE_RECORD__: JSON.stringify(options.data.config.record === true || options.data.config.record === options.mode),
- __SLIDEV_FEATURE_PRESENTER__: JSON.stringify(options.data.config.presenter === true || options.data.config.presenter === options.mode),
- __SLIDEV_FEATURE_PRINT__: JSON.stringify(options.mode === 'export' || (options.mode === 'build' && [true, 'true', 'auto'].includes(options.data.config.download))),
- __SLIDEV_FEATURE_WAKE_LOCK__: JSON.stringify(options.data.config.wakeLock === true || options.data.config.wakeLock === options.mode),
- __SLIDEV_HAS_SERVER__: options.mode !== 'build' ? 'true' : 'false',
- }
+ const matchMode = (mode: string | boolean) => mode === true || mode === options.mode
+ return objectMap(
+ {
+ __DEV__: options.mode === 'dev',
+ __SLIDEV_CLIENT_ROOT__: toAtFS(options.clientRoot),
+ __SLIDEV_HASH_ROUTE__: options.data.config.routerMode === 'hash',
+ __SLIDEV_FEATURE_DRAWINGS__: matchMode(options.data.config.drawings.enabled),
+ __SLIDEV_FEATURE_EDITOR__: options.mode === 'dev' && options.data.config.editor !== false,
+ __SLIDEV_FEATURE_DRAWINGS_PERSIST__: !!options.data.config.drawings.persist,
+ __SLIDEV_FEATURE_RECORD__: matchMode(options.data.config.record),
+ __SLIDEV_FEATURE_PRESENTER__: matchMode(options.data.config.presenter),
+ __SLIDEV_FEATURE_PRINT__: options.mode === 'export' || (options.mode === 'build' && [true, 'true', 'auto'].includes(options.data.config.download)),
+ __SLIDEV_FEATURE_BROWSER_EXPORTER__: matchMode(options.data.config.browserExporter),
+ __SLIDEV_FEATURE_WAKE_LOCK__: matchMode(options.data.config.wakeLock),
+ __SLIDEV_HAS_SERVER__: options.mode !== 'build',
+ },
+ (v, k) => [v, JSON.stringify(k)],
+ )
}
diff --git a/packages/types/src/frontmatter.ts b/packages/types/src/frontmatter.ts
index 1c5171dc9c..a9ae54f123 100644
--- a/packages/types/src/frontmatter.ts
+++ b/packages/types/src/frontmatter.ts
@@ -52,6 +52,10 @@ export interface HeadmatterConfig extends TransitionOptions {
* @default true
*/
codeCopy?: boolean
+ /**
+ * The author of the slides
+ */
+ author?: string
/**
* Information shows on the built SPA
* Can be a markdown string
@@ -172,6 +176,12 @@ export interface HeadmatterConfig extends TransitionOptions {
* @default true
*/
presenter?: boolean | 'dev' | 'build'
+ /**
+ * Enable browser exporter
+ *
+ * @default 'dev'
+ */
+ browserExporter?: boolean | 'dev' | 'build'
/**
* Attributes to apply to the HTML element
*
diff --git a/packages/vscode/schema/headmatter.json b/packages/vscode/schema/headmatter.json
index dccb3d450c..ea664d20f4 100644
--- a/packages/vscode/schema/headmatter.json
+++ b/packages/vscode/schema/headmatter.json
@@ -177,6 +177,11 @@
"markdownDescription": "Show a copy button in code blocks",
"default": true
},
+ "author": {
+ "type": "string",
+ "description": "The author of the slides",
+ "markdownDescription": "The author of the slides"
+ },
"info": {
"type": [
"string",
@@ -340,6 +345,24 @@
"markdownDescription": "Enable presenter mode",
"default": true
},
+ "browserExporter": {
+ "anyOf": [
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "string",
+ "const": "dev"
+ },
+ {
+ "type": "string",
+ "const": "build"
+ }
+ ],
+ "description": "Enable browser exporter",
+ "markdownDescription": "Enable browser exporter",
+ "default": "dev"
+ },
"htmlAttrs": {
"type": "object",
"additionalProperties": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index accc8d77e7..92b6aff6b0 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -261,6 +261,9 @@ catalogs:
monaco-editor:
specifier: 0.51.0
version: 0.51.0
+ nanotar:
+ specifier: ^0.1.1
+ version: 0.1.1
nodemon:
specifier: ^3.1.9
version: 3.1.9
@@ -789,6 +792,12 @@ importers:
monaco-editor:
specifier: 'catalog:'
version: 0.51.0
+ nanotar:
+ specifier: 'catalog:'
+ version: 0.1.1
+ pptxgenjs:
+ specifier: 'catalog:'
+ version: 3.12.0
prettier:
specifier: 'catalog:'
version: 3.4.2
@@ -1955,9 +1964,6 @@ packages:
'@iconify/types@2.0.0':
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
- '@iconify/utils@2.1.33':
- resolution: {integrity: sha512-jP9h6v/g0BIZx0p7XGJJVtkVnydtbgTgt9mVNcGDYwaa7UhdHdI9dvoq+gKj9sijMSJKxUPEG2JyjsgXjxL7Kw==}
-
'@iconify/utils@2.2.0':
resolution: {integrity: sha512-9A5eZQV9eKlNCXlI/SgYsGRS7YmGmB1oAsRpNVIYBmIzGJRgH+hfG+lo4069s+GFWFNnBAtDg10c53vQZBLfnA==}
@@ -5126,6 +5132,9 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
+ nanotar@0.1.1:
+ resolution: {integrity: sha512-AiJsGsSF3O0havL1BydvI4+wR76sKT+okKRwWIaK96cZUnXqH0uNBOsHlbwZq3+m2BR1VKqHDVudl3gO4mYjpQ==}
+
napi-build-utils@1.0.2:
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
@@ -7536,18 +7545,6 @@ snapshots:
'@iconify/types@2.0.0': {}
- '@iconify/utils@2.1.33':
- dependencies:
- '@antfu/install-pkg': 0.4.1
- '@antfu/utils': 0.7.10
- '@iconify/types': 2.0.0
- debug: 4.4.0(supports-color@8.1.1)
- kolorist: 1.8.0
- local-pkg: 0.5.1
- mlly: 1.7.3
- transitivePeerDependencies:
- - supports-color
-
'@iconify/utils@2.2.0':
dependencies:
'@antfu/install-pkg': 0.4.1
@@ -8302,7 +8299,7 @@ snapshots:
'@unocss/preset-icons@0.65.1':
dependencies:
- '@iconify/utils': 2.1.33
+ '@iconify/utils': 2.2.0
'@unocss/core': 0.65.1
ofetch: 1.4.1
transitivePeerDependencies:
@@ -11149,7 +11146,7 @@ snapshots:
mermaid@11.4.1:
dependencies:
'@braintree/sanitize-url': 7.1.0
- '@iconify/utils': 2.1.33
+ '@iconify/utils': 2.2.0
'@mermaid-js/parser': 0.3.0
'@types/d3': 7.4.3
cytoscape: 3.30.2
@@ -11457,6 +11454,8 @@ snapshots:
nanoid@3.3.7: {}
+ nanotar@0.1.1: {}
+
napi-build-utils@1.0.2:
optional: true
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 9e76de2cf5..e0364db212 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -89,6 +89,7 @@ catalog:
minimist: ^1.2.8
mlly: ^1.7.3
monaco-editor: 0.51.0
+ nanotar: ^0.1.1
nodemon: ^3.1.9
open: ^10.1.0
ovsx: ^0.10.1
diff --git a/shim.d.ts b/shim.d.ts
index 65d3b5a602..2d618a0f27 100644
--- a/shim.d.ts
+++ b/shim.d.ts
@@ -9,6 +9,7 @@ declare global {
const __SLIDEV_FEATURE_RECORD__: boolean
const __SLIDEV_FEATURE_PRESENTER__: boolean
const __SLIDEV_FEATURE_PRINT__: boolean
+ const __SLIDEV_FEATURE_BROWSER_EXPORTER__: boolean
const __SLIDEV_FEATURE_WAKE_LOCK__: boolean
const __SLIDEV_HAS_SERVER__: boolean
}
@@ -24,6 +25,7 @@ declare module '@vue/runtime-core' {
__SLIDEV_FEATURE_RECORD__: boolean
__SLIDEV_FEATURE_PRESENTER__: boolean
__SLIDEV_FEATURE_PRINT__: boolean
+ __SLIDEV_FEATURE_BROWSER_EXPORTER__: boolean
__SLIDEV_FEATURE_WAKE_LOCK__: boolean
__SLIDEV_HAS_SERVER__: boolean
}