Repository: slidevjs/slidev Branch: main Commit: 3a5f8ddf254c Files: 649 Total size: 1.3 MB Directory structure: gitextract_8zfy5w91/ ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── config.yml │ │ └── feature_request.md │ ├── stale.yml │ └── workflows/ │ ├── autofix.yml │ ├── cr.yml │ ├── release.yml │ ├── smoke.yml │ └── test.yml ├── .gitignore ├── .vscode/ │ ├── extensions.json │ ├── launch.json │ └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── cypress/ │ ├── e2e/ │ │ └── examples/ │ │ ├── basic.spec.ts │ │ ├── presenter-resizer.spec.ts │ │ └── smoke.spec.ts │ ├── fixtures/ │ │ └── basic/ │ │ ├── components/ │ │ │ ├── DecorateWithLi.vue │ │ │ ├── WrapInClicks.vue │ │ │ ├── WrapInClicksDecorate.vue │ │ │ └── WrapInComponentInClicks.vue │ │ ├── global.vue │ │ ├── package.json │ │ ├── slides.md │ │ ├── sub/ │ │ │ ├── page1.md │ │ │ └── page2.md │ │ └── vite.config.ts │ └── tsconfig.json ├── cypress.config.ts ├── demo/ │ ├── README.md │ ├── composable-vue/ │ │ ├── components/ │ │ │ ├── Connections.vue │ │ │ ├── DarkToggle.vue │ │ │ ├── Marker.vue │ │ │ ├── MarkerCore.vue │ │ │ ├── MarkerPattern.vue │ │ │ ├── MarkerTips.vue │ │ │ ├── NumBox.vue │ │ │ └── VueUse.vue │ │ ├── index.html │ │ ├── package.json │ │ ├── setup/ │ │ │ └── monaco.ts │ │ └── slides.md │ ├── starter/ │ │ ├── README.md │ │ ├── components/ │ │ │ └── Counter.vue │ │ ├── package.json │ │ ├── pages/ │ │ │ └── imported-slides.md │ │ ├── slides.md │ │ ├── snippets/ │ │ │ └── external.ts │ │ ├── style.css │ │ └── vite.config.ts │ └── vue-runner/ │ ├── package.json │ ├── setup/ │ │ ├── code-runners.ts │ │ └── shiki.ts │ └── slides.md ├── docs/ │ ├── .gitignore │ ├── .vitepress/ │ │ ├── addons.ts │ │ ├── config.ts │ │ ├── customizations.ts │ │ ├── pages.ts │ │ ├── showcases.ts │ │ ├── sidebar-gen.ts │ │ ├── theme/ │ │ │ ├── components/ │ │ │ │ ├── AddonGallery.vue │ │ │ │ ├── AddonInfo.vue │ │ │ │ ├── Demo.vue │ │ │ │ ├── DemoEditor.vue │ │ │ │ ├── DemoSlide.vue │ │ │ │ ├── Environment.vue │ │ │ │ ├── FeatureTag.vue │ │ │ │ ├── FeaturesAnimation.vue │ │ │ │ ├── FeaturesAnimationInner.vue │ │ │ │ ├── FeaturesOverview.vue │ │ │ │ ├── LandingPage.vue │ │ │ │ ├── Layout.vue │ │ │ │ ├── LinkCard.vue │ │ │ │ ├── LinkInline.vue │ │ │ │ ├── SeeAlso.vue │ │ │ │ ├── ShowCaseInfo.vue │ │ │ │ ├── ShowCases.vue │ │ │ │ ├── SlideContainer.vue │ │ │ │ ├── TheTweet.vue │ │ │ │ ├── ThemeGallery.vue │ │ │ │ └── ThemeInfo.vue │ │ │ ├── composables/ │ │ │ │ └── dark.ts │ │ │ ├── index.ts │ │ │ └── styles/ │ │ │ ├── custom.css │ │ │ ├── demo.css │ │ │ └── vars.css │ │ ├── themes.ts │ │ └── utils.ts │ ├── README.md │ ├── builtin/ │ │ ├── cli.md │ │ ├── components.md │ │ └── layouts.md │ ├── custom/ │ │ ├── config-code-runners.md │ │ ├── config-context-menu.md │ │ ├── config-fonts.md │ │ ├── config-highlighter.md │ │ ├── config-katex.md │ │ ├── config-mermaid-renderer.md │ │ ├── config-mermaid.md │ │ ├── config-monaco.md │ │ ├── config-parser.md │ │ ├── config-routes.md │ │ ├── config-shortcuts.md │ │ ├── config-transformers.md │ │ ├── config-unocss.md │ │ ├── config-vite.md │ │ ├── config-vue.md │ │ ├── directory-structure.md │ │ └── index.md │ ├── features/ │ │ ├── block-frontmatter.md │ │ ├── build-with-pdf.md │ │ ├── bundle-remote-assets.md │ │ ├── canvas-size.md │ │ ├── click-marker.md │ │ ├── code-block-line-numbers.md │ │ ├── code-block-max-height.md │ │ ├── code-groups.md │ │ ├── comark.md │ │ ├── direction-variant.md │ │ ├── draggable.md │ │ ├── drawing.md │ │ ├── eject-theme.md │ │ ├── frontmatter-merging.md │ │ ├── global-layers.md │ │ ├── icons.md │ │ ├── import-snippet.md │ │ ├── importing-slides.md │ │ ├── index.data.ts │ │ ├── index.md │ │ ├── latex.md │ │ ├── line-highlighting.md │ │ ├── mermaid.md │ │ ├── monaco-editor.md │ │ ├── monaco-run.md │ │ ├── monaco-write.md │ │ ├── notes-auto-ruby.md │ │ ├── og-image.md │ │ ├── plantuml.md │ │ ├── prettier-plugin.md │ │ ├── recording.md │ │ ├── remote-access.md │ │ ├── rough-marker.md │ │ ├── seo-meta.md │ │ ├── shiki-magic-move.md │ │ ├── side-editor.md │ │ ├── slide-hook.md │ │ ├── slide-scope-style.md │ │ ├── slot-sugar.md │ │ ├── timer.md │ │ ├── transform-component.md │ │ ├── twoslash.md │ │ ├── vscode-extension.md │ │ └── zoom-slide.md │ ├── guide/ │ │ ├── animations.md │ │ ├── component.md │ │ ├── exporting.md │ │ ├── faq.md │ │ ├── global-context.md │ │ ├── hosting.md │ │ ├── index.md │ │ ├── layout.md │ │ ├── syntax.md │ │ ├── theme-addon.md │ │ ├── ui.md │ │ ├── why.md │ │ ├── work-with-ai.md │ │ ├── write-addon.md │ │ ├── write-layout.md │ │ └── write-theme.md │ ├── index.md │ ├── netlify.toml │ ├── package.json │ ├── resources/ │ │ ├── addon-gallery.md │ │ ├── covers.md │ │ ├── learning.md │ │ ├── showcases.md │ │ └── theme-gallery.md │ ├── tsconfig.json │ ├── uno.config.ts │ └── vite.config.ts ├── eslint.config.js ├── netlify.toml ├── package.json ├── packages/ │ ├── client/ │ │ ├── .generated/ │ │ │ └── unocss-tokens.ts │ │ ├── App.vue │ │ ├── README.md │ │ ├── builtin/ │ │ │ ├── Arrow.vue │ │ │ ├── AutoFitText.vue │ │ │ ├── CodeBlockWrapper.vue │ │ │ ├── CodeGroup.vue │ │ │ ├── KaTexBlockWrapper.vue │ │ │ ├── LightOrDark.vue │ │ │ ├── Link.vue │ │ │ ├── Mermaid.vue │ │ │ ├── Monaco.vue │ │ │ ├── PlantUml.vue │ │ │ ├── PoweredBySlidev.vue │ │ │ ├── RenderWhen.vue │ │ │ ├── ShikiMagicMove.vue │ │ │ ├── SlideCurrentNo.vue │ │ │ ├── SlidesTotal.vue │ │ │ ├── SlidevVideo.vue │ │ │ ├── Toc.vue │ │ │ ├── TocList.vue │ │ │ ├── Transform.vue │ │ │ ├── Tweet.vue │ │ │ ├── VAfter.ts │ │ │ ├── VClick.ts │ │ │ ├── VClickGap.vue │ │ │ ├── VClicks.ts │ │ │ ├── VDrag.vue │ │ │ ├── VDragArrow.vue │ │ │ ├── VSwitch.ts │ │ │ └── Youtube.vue │ │ ├── composables/ │ │ │ ├── useClicks.ts │ │ │ ├── useDarkMode.ts │ │ │ ├── useDragElements.ts │ │ │ ├── useDrawings.ts │ │ │ ├── useEmbeddedCtrl.ts │ │ │ ├── useHideCursorIdle.ts │ │ │ ├── useIME.ts │ │ │ ├── useNav.ts │ │ │ ├── usePreloadImages.ts │ │ │ ├── usePrintStyles.ts │ │ │ ├── useSlideBounds.ts │ │ │ ├── useSlideInfo.ts │ │ │ ├── useSwipeControls.ts │ │ │ ├── useTimer.ts │ │ │ ├── useTocTree.ts │ │ │ ├── useViewTransition.ts │ │ │ └── useWakeLock.ts │ │ ├── constants.ts │ │ ├── context.ts │ │ ├── env.ts │ │ ├── index.html │ │ ├── index.ts │ │ ├── internals/ │ │ │ ├── Badge.vue │ │ │ ├── ClicksSlider.vue │ │ │ ├── CodeRunner.vue │ │ │ ├── ContextMenu.vue │ │ │ ├── Controls.vue │ │ │ ├── CurrentProgressBar.vue │ │ │ ├── DevicesSelectors.vue │ │ │ ├── DomElement.vue │ │ │ ├── DragControl.vue │ │ │ ├── Draggable.vue │ │ │ ├── DrawingControls.vue │ │ │ ├── DrawingLayer.vue │ │ │ ├── DrawingPreview.vue │ │ │ ├── ExportPdfTip.vue │ │ │ ├── FormCheckbox.vue │ │ │ ├── FormItem.vue │ │ │ ├── FormSlider.vue │ │ │ ├── Goto.vue │ │ │ ├── IconButton.vue │ │ │ ├── InfoDialog.vue │ │ │ ├── MenuButton.vue │ │ │ ├── Modal.vue │ │ │ ├── NavControls.vue │ │ │ ├── NoteDisplay.vue │ │ │ ├── NoteEditable.vue │ │ │ ├── NoteStatic.vue │ │ │ ├── PresenterMouse.vue │ │ │ ├── PrintContainer.vue │ │ │ ├── PrintSlide.vue │ │ │ ├── PrintSlideClick.vue │ │ │ ├── QuickOverview.vue │ │ │ ├── README.md │ │ │ ├── RecordingControls.vue │ │ │ ├── RecordingDialog.vue │ │ │ ├── ScreenCaptureMirror.vue │ │ │ ├── SegmentControl.vue │ │ │ ├── SelectList.vue │ │ │ ├── Settings.vue │ │ │ ├── ShadowRoot.vue │ │ │ ├── ShikiEditor.vue │ │ │ ├── SideEditor.vue │ │ │ ├── SlideContainer.vue │ │ │ ├── SlideLoading.vue │ │ │ ├── SlideWrapper.vue │ │ │ ├── SlidesShow.vue │ │ │ ├── SyncControls.vue │ │ │ ├── TimerBar.vue │ │ │ ├── TimerInlined.vue │ │ │ ├── TitleIcon.vue │ │ │ ├── VerticalDivider.vue │ │ │ ├── WebCamera.vue │ │ │ └── types.ts │ │ ├── layoutHelper.ts │ │ ├── layouts/ │ │ │ ├── 404.vue │ │ │ ├── center.vue │ │ │ ├── cover.vue │ │ │ ├── default.vue │ │ │ ├── end.vue │ │ │ ├── error.vue │ │ │ ├── fact.vue │ │ │ ├── full.vue │ │ │ ├── iframe-left.vue │ │ │ ├── iframe-right.vue │ │ │ ├── iframe.vue │ │ │ ├── image-left.vue │ │ │ ├── image-right.vue │ │ │ ├── image.vue │ │ │ ├── intro.vue │ │ │ ├── none.vue │ │ │ ├── quote.vue │ │ │ ├── section.vue │ │ │ ├── statement.vue │ │ │ ├── two-cols-header.vue │ │ │ └── two-cols.vue │ │ ├── logic/ │ │ │ ├── color.ts │ │ │ ├── contextMenu.ts │ │ │ ├── dark.ts │ │ │ ├── overview.ts │ │ │ ├── recording.ts │ │ │ ├── route.ts │ │ │ ├── screenshot.ts │ │ │ ├── shortcuts.ts │ │ │ ├── slides.ts │ │ │ ├── snapshot.ts │ │ │ ├── transition.ts │ │ │ └── utils.ts │ │ ├── main.ts │ │ ├── modules/ │ │ │ ├── context.ts │ │ │ ├── mermaid.ts │ │ │ ├── v-click.ts │ │ │ ├── v-drag.ts │ │ │ ├── v-mark.ts │ │ │ └── v-motion.ts │ │ ├── package.json │ │ ├── pages/ │ │ │ ├── 404.vue │ │ │ ├── entry.vue │ │ │ ├── export.vue │ │ │ ├── notes-edit.vue │ │ │ ├── notes.vue │ │ │ ├── overview.vue │ │ │ ├── play.vue │ │ │ ├── presenter/ │ │ │ │ └── print.vue │ │ │ ├── presenter.vue │ │ │ └── print.vue │ │ ├── scripts/ │ │ │ └── unocss-scan.ts │ │ ├── setup/ │ │ │ ├── code-runners.ts │ │ │ ├── context-menu.ts │ │ │ ├── main.ts │ │ │ ├── mermaid.ts │ │ │ ├── monaco.ts │ │ │ ├── root.ts │ │ │ ├── routes.ts │ │ │ ├── shiki-options.ts │ │ │ ├── shiki.ts │ │ │ └── shortcuts.ts │ │ ├── shim-vue.d.ts │ │ ├── shim.d.ts │ │ ├── state/ │ │ │ ├── drawings.ts │ │ │ ├── index.ts │ │ │ ├── shared.ts │ │ │ ├── snapshot.ts │ │ │ ├── storage.ts │ │ │ └── syncState.ts │ │ ├── styles/ │ │ │ ├── code.css │ │ │ ├── index.css │ │ │ ├── katex.css │ │ │ ├── layouts-base.css │ │ │ ├── shiki-twoslash.css │ │ │ ├── transitions.css │ │ │ └── vars.css │ │ ├── uno.config.ts │ │ └── utils.ts │ ├── create-app/ │ │ ├── README.md │ │ ├── build.mjs │ │ ├── index.mjs │ │ ├── package.json │ │ └── template/ │ │ ├── README.md │ │ ├── _gitignore │ │ ├── _npmrc │ │ ├── components/ │ │ │ └── Counter.vue │ │ ├── netlify.toml │ │ ├── package.json │ │ └── vercel.json │ ├── create-theme/ │ │ ├── README.md │ │ ├── index.mjs │ │ ├── package.json │ │ └── template/ │ │ ├── .vscode/ │ │ │ └── extensions.json │ │ ├── README.md │ │ ├── _gitignore │ │ ├── _npmrc │ │ ├── components/ │ │ │ └── .gitkeep │ │ ├── example.md │ │ ├── layouts/ │ │ │ ├── cover.vue │ │ │ └── intro.vue │ │ ├── package.json │ │ ├── setup/ │ │ │ └── shiki.ts │ │ └── styles/ │ │ ├── index.ts │ │ └── layout.css │ ├── parser/ │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── config.ts │ │ │ ├── core.ts │ │ │ ├── fs.ts │ │ │ ├── index.ts │ │ │ ├── timesplit/ │ │ │ │ ├── index.ts │ │ │ │ ├── timesplit.test.ts │ │ │ │ ├── timesplit.ts │ │ │ │ ├── timestring.test.ts │ │ │ │ └── timestring.ts │ │ │ └── utils.ts │ │ └── tsdown.config.ts │ ├── slidev/ │ │ ├── LICENSE │ │ ├── bin/ │ │ │ └── slidev.mjs │ │ ├── node/ │ │ │ ├── cli.ts │ │ │ ├── commands/ │ │ │ │ ├── build.ts │ │ │ │ ├── export.ts │ │ │ │ ├── serve.ts │ │ │ │ └── shared.ts │ │ │ ├── index.ts │ │ │ ├── integrations/ │ │ │ │ ├── addons.ts │ │ │ │ ├── drawings.ts │ │ │ │ ├── snapshots.ts │ │ │ │ └── themes.ts │ │ │ ├── options.ts │ │ │ ├── parser.ts │ │ │ ├── resolver.test.ts │ │ │ ├── resolver.ts │ │ │ ├── setups/ │ │ │ │ ├── indexHtml.ts │ │ │ │ ├── katex.ts │ │ │ │ ├── load.ts │ │ │ │ ├── preparser.ts │ │ │ │ ├── shiki.ts │ │ │ │ ├── transformers.ts │ │ │ │ ├── unocss.ts │ │ │ │ └── vite-plugins.ts │ │ │ ├── syntax/ │ │ │ │ ├── markdown-it/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── markdown-it-escape-code.ts │ │ │ │ │ ├── markdown-it-katex.ts │ │ │ │ │ ├── markdown-it-link.ts │ │ │ │ │ ├── markdown-it-shiki.ts │ │ │ │ │ └── markdown-it-v-drag.ts │ │ │ │ └── transform/ │ │ │ │ ├── code-wrapper.ts │ │ │ │ ├── in-page-css.ts │ │ │ │ ├── index.ts │ │ │ │ ├── katex-wrapper.ts │ │ │ │ ├── magic-move.ts │ │ │ │ ├── mermaid.ts │ │ │ │ ├── monaco.ts │ │ │ │ ├── plant-uml.ts │ │ │ │ ├── slot-sugar.ts │ │ │ │ ├── snippet.ts │ │ │ │ └── utils.ts │ │ │ ├── utils.ts │ │ │ ├── virtual/ │ │ │ │ ├── configs.ts │ │ │ │ ├── deprecated.ts │ │ │ │ ├── global-layers.ts │ │ │ │ ├── index.ts │ │ │ │ ├── layouts.ts │ │ │ │ ├── monaco-deps.ts │ │ │ │ ├── monaco-types.ts │ │ │ │ ├── nav-controls.ts │ │ │ │ ├── setups.ts │ │ │ │ ├── slides.ts │ │ │ │ ├── styles.ts │ │ │ │ ├── titles.ts │ │ │ │ └── types.ts │ │ │ └── vite/ │ │ │ ├── common.ts │ │ │ ├── compilerFlagsVue.ts │ │ │ ├── components.ts │ │ │ ├── contextInjection.ts │ │ │ ├── extendConfig.ts │ │ │ ├── hmrPatch.ts │ │ │ ├── icons.ts │ │ │ ├── index.ts │ │ │ ├── inspect.ts │ │ │ ├── layoutWrapper.ts │ │ │ ├── loaders.ts │ │ │ ├── markdown.ts │ │ │ ├── monacoTypes.ts │ │ │ ├── monacoWrite.ts │ │ │ ├── patchMonacoSourceMap.ts │ │ │ ├── remoteAssets.ts │ │ │ ├── serverRef.ts │ │ │ ├── staticCopy.ts │ │ │ ├── unocss.ts │ │ │ └── vue.ts │ │ ├── package.json │ │ ├── template.md │ │ ├── tsconfig.json │ │ └── tsdown.config.ts │ ├── types/ │ │ ├── README.md │ │ ├── client.d.ts │ │ ├── index.d.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── builtin-layouts.ts │ │ │ ├── cli.ts │ │ │ ├── clicks.ts │ │ │ ├── code-runner.ts │ │ │ ├── config.ts │ │ │ ├── context-menu.ts │ │ │ ├── env.ts │ │ │ ├── frontmatter.ts │ │ │ ├── hmr.ts │ │ │ ├── index.ts │ │ │ ├── options.ts │ │ │ ├── setups.ts │ │ │ ├── toc.ts │ │ │ ├── transform.ts │ │ │ ├── types.ts │ │ │ └── vite.ts │ │ └── tsdown.config.ts │ └── vscode/ │ ├── .vscodeignore │ ├── LICENSE │ ├── README.md │ ├── language-server/ │ │ ├── bin.ts │ │ ├── index.ts │ │ ├── languagePlugin.ts │ │ ├── prettierService.ts │ │ ├── protocol.ts │ │ └── volar-service-yaml.ts │ ├── package.json │ ├── schema/ │ │ ├── frontmatter.json │ │ └── headmatter.json │ ├── scripts/ │ │ ├── publish.ts │ │ └── schema.ts │ ├── src/ │ │ ├── commands.ts │ │ ├── composables/ │ │ │ ├── useDebouncedComputed.ts │ │ │ ├── useDevServer.ts │ │ │ ├── useFocusedSlide.ts │ │ │ ├── useProjectFromDoc.ts │ │ │ └── useServerDetector.ts │ │ ├── configs.ts │ │ ├── html/ │ │ │ ├── error.ts │ │ │ └── ready.ts │ │ ├── index.ts │ │ ├── languageClient.ts │ │ ├── lmTools.ts │ │ ├── projects.ts │ │ ├── utils/ │ │ │ ├── findPossibleEntries.ts │ │ │ ├── findShallowestPath.ts │ │ │ ├── getFirstDisplayedChild.ts │ │ │ ├── getSlidesTitle.ts │ │ │ └── toRelativePath.ts │ │ └── views/ │ │ ├── annotations.ts │ │ ├── foldings.ts │ │ ├── logger.ts │ │ ├── previewWebview.ts │ │ ├── projectsTree.ts │ │ └── slidesTree.ts │ ├── syntaxes/ │ │ ├── .vscode/ │ │ │ └── settings.json │ │ ├── codeblock-patch.ts │ │ ├── codeblock.json │ │ ├── language-configuration.json │ │ ├── markdown.json │ │ ├── pages.md │ │ ├── slidev.example.md │ │ ├── slidev.tmLanguage.json │ │ └── tsconfig.json │ ├── tsconfig.json │ └── tsdown.config.ts ├── patches/ │ └── @hedgedoc__markdown-it-plugins@2.1.4.patch ├── pnpm-workspace.yaml ├── scripts/ │ ├── demo.mjs │ ├── gen-layouts.ts │ ├── pack.mjs │ ├── publish.mjs │ ├── remove-overridden-deps.mjs │ └── update-versions.mjs ├── shim.d.ts ├── skills/ │ ├── GENERATION.md │ └── slidev/ │ ├── README.md │ ├── SKILL.md │ └── references/ │ ├── animation-click-marker.md │ ├── animation-drawing.md │ ├── animation-rough-marker.md │ ├── api-slide-hooks.md │ ├── build-og-image.md │ ├── build-pdf.md │ ├── build-remote-assets.md │ ├── build-seo-meta.md │ ├── code-groups.md │ ├── code-import-snippet.md │ ├── code-line-highlighting.md │ ├── code-line-numbers.md │ ├── code-magic-move.md │ ├── code-max-height.md │ ├── code-twoslash.md │ ├── core-animations.md │ ├── core-cli.md │ ├── core-components.md │ ├── core-exporting.md │ ├── core-frontmatter.md │ ├── core-global-context.md │ ├── core-headmatter.md │ ├── core-hosting.md │ ├── core-layouts.md │ ├── core-syntax.md │ ├── diagram-latex.md │ ├── diagram-mermaid.md │ ├── diagram-plantuml.md │ ├── editor-monaco-run.md │ ├── editor-monaco-write.md │ ├── editor-monaco.md │ ├── editor-prettier.md │ ├── editor-side.md │ ├── editor-vscode.md │ ├── layout-canvas-size.md │ ├── layout-draggable.md │ ├── layout-global-layers.md │ ├── layout-slots.md │ ├── layout-transform.md │ ├── layout-zoom.md │ ├── presenter-notes-ruby.md │ ├── presenter-recording.md │ ├── presenter-remote.md │ ├── presenter-timer.md │ ├── style-direction.md │ ├── style-icons.md │ ├── style-scoped.md │ ├── syntax-block-frontmatter.md │ ├── syntax-frontmatter-merging.md │ ├── syntax-importing-slides.md │ ├── syntax-mdc.md │ └── tool-eject-theme.md ├── taze.config.ts ├── test/ │ ├── __snapshots__/ │ │ ├── parser.test.ts.snap │ │ ├── transform-all.test.ts.snap │ │ ├── transform.test.ts.snap │ │ └── utils.test.ts.snap │ ├── _tutils.ts │ ├── fixtures/ │ │ ├── markdown/ │ │ │ ├── frontmatter.md │ │ │ ├── mdc.md │ │ │ ├── minimal.md │ │ │ ├── multi-entries.md │ │ │ └── sub/ │ │ │ ├── nested1-4.md │ │ │ ├── page1.md │ │ │ ├── page2.md │ │ │ └── pages3-4.md │ │ └── snippets/ │ │ └── snippet.ts │ ├── mermaid-renderer.test.ts │ ├── parser.test.ts │ ├── transform-all.test.ts │ ├── transform-magic-move.test.ts │ ├── transform.test.ts │ └── utils.test.ts ├── tsconfig.json ├── tsdown.config.ts └── vitest.config.ts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ github: antfu opencollective: slidev ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: "\U0001F41E Bug report" about: Create a report to help us improve title: '' type: Bug labels: ['pending triage'] assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **Minimal reproduction** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See the error You can use https://sli.dev/new to create a new project to reproduce the issue. **Environment** - Slidev version: - Browser: - OS: If you are using Slidev globally (i.e. `npx slidev` or `npm i -g slidev`), please try to reproduce the issue in a local project (i.e. `npm create slidev@latest`). ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ contact_links: - name: Questions & Discussions url: https://github.com/slidevjs/slidev/discussions about: Use GitHub discussions for message-board style questions and discussions. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: "\U00002728 Feature request" about: Suggest an idea for this project title: '' type: Feature assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. ================================================ FILE: .github/stale.yml ================================================ daysUntilStale: 60 daysUntilClose: 7 exemptLabels: - pinned - security - no-stale - no stale - pr welcome - help wanted staleLabel: stale markComment: > This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. closeComment: false ================================================ FILE: .github/workflows/autofix.yml ================================================ name: autofix.ci on: push: branches: - main pull_request: branches: - main permissions: contents: read jobs: autofix: runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v6 - name: Use Node.js lts/* uses: actions/setup-node@v6 with: node-version: lts/* - name: Setup run: npm i -g @antfu/ni - name: Install run: nci env: CYPRESS_INSTALL_BINARY: 0 - name: Lint run: nr lint --fix - uses: autofix-ci/action@dd55f44df8f7cdb7a6bf74c78677eb8acd40cd0a ================================================ FILE: .github/workflows/cr.yml ================================================ # Continuous Releases provided by https://pkg.pr.new name: CR (Continuous Releases) on: [push, pull_request] jobs: cr: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: node-version: lts/* - run: npm i -g @antfu/ni - run: nci - name: Build run: nr build - run: nlx pkg-pr-new publish './packages/create-app' './packages/client' './packages/create-theme' './packages/parser' './packages/slidev' './packages/types' --pnpm env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/release.yml ================================================ name: Release on: push: tags: - 'v*' jobs: release: permissions: id-token: write contents: write runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v6 with: node-version: lts/* registry-url: https://registry.npmjs.org/ - run: npx changelogithub env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - run: npm i -g npm@latest - run: pnpm i - run: pnpm run ci:publish - name: Publish to VSCE & OVSX run: pnpm run publish working-directory: ./packages/vscode env: VSCE_TOKEN: ${{secrets.VSCE_PAT}} OVSX_TOKEN: ${{secrets.OVSX_PAT}} ================================================ FILE: .github/workflows/smoke.yml ================================================ name: Production Smoke Test on: push: branches: - main - master pull_request: branches: - main - master workflow_dispatch: jobs: pack: timeout-minutes: 10 runs-on: ubuntu-latest steps: - name: Set git to use LF run: | git config --global core.autocrlf false git config --global core.eol lf - uses: actions/checkout@v6 - name: Use Node.js uses: actions/setup-node@v6 with: node-version: lts/* - name: Setup run: npm i -g @antfu/ni - name: Install run: nci env: CYPRESS_INSTALL_BINARY: 0 - name: Build run: nr build - name: Pack run: node ./scripts/pack.mjs /tmp/slidev-pkgs - name: Upload artifacts uses: actions/upload-artifact@v6 with: name: slidev-packages path: /tmp/slidev-pkgs test: needs: pack runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest] pm: [npm, pnpm] # yarn not working in this CI hoist: [true, false] steps: - name: Set git to use LF run: | git config --global core.autocrlf false git config --global core.eol lf - uses: actions/checkout@v6 - name: Use Node.js lts/* uses: actions/setup-node@v6 with: node-version: lts/* - name: Setup run: npm i -g @antfu/ni - name: Setup PNPM uses: pnpm/action-setup@v4 - name: Install run: nci - name: Download artifacts uses: actions/download-artifact@v7 with: name: slidev-packages path: /tmp/slidev-pkgs - name: Create new project run: | npm i -g /tmp/slidev-pkgs/create-app.tgz echo "N" | create-slidev ../temp/slidev-project - name: Remove npmrc run: pnpx del-cli ./.npmrc working-directory: ../temp/slidev-project if: ${{ ! matrix.hoist }} - name: Remove overridden dependencies run: node ${{ github.workspace }}/scripts/remove-overridden-deps.mjs working-directory: ../temp/slidev-project - name: Install project (npm, pnpm) run: ${{ matrix.pm }} i /tmp/slidev-pkgs/cli.tgz playwright-chromium working-directory: ../temp/slidev-project if: ${{ matrix.pm != 'yarn' }} - name: Install Playwright browsers run: pnpx playwright install chromium working-directory: ../temp/slidev-project - name: Install project (yarn) run: yarn add /tmp/slidev-pkgs/cli.tgz playwright-chromium working-directory: ../temp/slidev-project if: ${{ matrix.pm == 'yarn' }} - name: Test build command in project run: pnpm build working-directory: ../temp/slidev-project - name: E2E Smoke Test uses: cypress-io/github-action@v7 if: ${{ matrix.os != 'windows-latest' }} with: install-command: echo build: echo start: pnpm --dir ../temp/slidev-project dev --port 3041 spec: cypress/e2e/examples/smoke.spec.ts - name: Install globally run: | ${{ matrix.pm }} i -g /tmp/slidev-pkgs/cli.tgz playwright-chromium ${{ matrix.pm }} i -g @slidev/theme-seriph if: ${{ matrix.pm != 'yarn' }} - name: Create slide file run: pnpm --package=cpy-cli dlx cpy ./packages/slidev/template.md ../temp/ --flat if: ${{ matrix.pm != 'yarn' }} - name: Test build command in global mode run: slidev build template.md if: ${{ matrix.pm != 'yarn' }} working-directory: ../temp # Commented out because it's not working # - name: E2E test in global mode # uses: cypress-io/github-action@v7 # if: ${{ matrix.os != 'windows' }} # with: # project: ${{ github.workspace }} # install-command: echo # build: echo # start: ${{ 'bash -c "slidev ../template.md"' }} # spec: cypress/e2e/examples/noError.spec.ts ================================================ FILE: .github/workflows/test.yml ================================================ name: Test on: push: branches: - main - master pull_request: branches: - main - master jobs: test: timeout-minutes: 10 runs-on: ${{ matrix.os }} strategy: matrix: node-version: [lts/*] os: [ubuntu-latest, windows-latest, macos-latest] # os: [ubuntu-latest, macos-latest] fail-fast: false steps: - name: Set git to use LF run: | git config --global core.autocrlf false git config --global core.eol lf - uses: actions/checkout@v6 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} - name: Setup run: npm i -g @antfu/ni - name: Install run: nci env: CYPRESS_INSTALL_BINARY: 0 - name: Build run: nr build - name: Test run: nr test cypress: runs-on: ubuntu-latest timeout-minutes: 20 steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: node-version: lts/* - name: Setup run: npm i -g @antfu/ni - name: Install run: nci - name: Build run: nr build - name: Hack Cypress run: cp pnpm-lock.yaml package-lock.json - name: Cypress uses: cypress-io/github-action@v7 with: install-command: echo build: nr build start: nr cy:fixture ================================================ FILE: .gitignore ================================================ .DS_Store .eslintcache .idea .nuxt .output .slidev .vite-inspect *-export *.local *.pdf .env assets/demo components.d.ts composable-vue-cn dist dist-ssr docs/.vitepress/@slidev docs/.vitepress/cache node_modules cypress/downloads packages/create-app/template/pages packages/create-app/template/slides.md packages/create-app/template/snippets packages/slidev/README.md packages/slidev/skills packages/vscode/syntaxes/codeblock-patch.json slides-export.md *slides-export.pptx .agents .claude ================================================ FILE: .vscode/extensions.json ================================================ { "recommendations": [ "antfu.vite", "Vue.volar", "antfu.iconify", "dbaeumer.vscode-eslint", "antfu.unocss", "csstools.postcss", "antfu.pnpm-catalog-lens" ] } ================================================ FILE: .vscode/launch.json ================================================ { "version": "0.2.0", "configurations": [ { "name": "Run Extension", "type": "extensionHost", "request": "launch", "autoAttachChildProcesses": true, "args": [ "--extensionDevelopmentPath=${workspaceFolder}/packages/vscode", "--folder-uri=${workspaceRoot}/packages/vscode/syntaxes" ], "outFiles": [ "${workspaceFolder}/packages/vscode/dist/**/*.js" ] } ] } ================================================ FILE: .vscode/settings.json ================================================ { "typescript.tsdk": "node_modules/typescript/lib", "files.associations": { "*.css": "postcss" }, "unocss.root": [ "packages/client" ], // Enable the flat config support "eslint.experimental.useFlatConfig": true, // Disable the default formatter "prettier.enable": false, "editor.formatOnSave": false, // Auto fix "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit", "source.organizeImports": "never" }, // Silent the stylistic rules in you IDE, but still auto fix them "eslint.rules.customizations": [ { "rule": "@stylistic/*", "severity": "off" }, { "rule": "style*", "severity": "off" }, { "rule": "*-indent", "severity": "off" }, { "rule": "*-spacing", "severity": "off" }, { "rule": "*-spaces", "severity": "off" }, { "rule": "*-order", "severity": "off" }, { "rule": "*-dangle", "severity": "off" }, { "rule": "*-newline", "severity": "off" }, { "rule": "*quotes", "severity": "off" }, { "rule": "*semi", "severity": "off" } ], "eslint.validate": [ "javascript", "javascriptreact", "typescript", "typescriptreact", "vue", "html", "markdown", "json", "jsonc", "yaml" ], "vitest.disableWorkspaceWarning": true, "slidev.include": [ "**/slides.md", "packages/vscode/syntax/slidev.example.md" ], "vue.server.hybridMode": "typeScriptPluginOnly" } ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: - Demonstrating empathy and kindness toward other people - Being respectful of differing opinions, viewpoints, and experiences - Giving and gracefully accepting constructive feedback - Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience - Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: - The use of sexualized language or imagery, and sexual attention or advances of any kind - Trolling, insulting or derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or email address, without their explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at slidev@antfu.me. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing Excited to hear that you are interested in contributing to this project! Thanks! ## Documentation Documentation is now being synced from the [`/docs`](https://github.com/slidevjs/slidev/tree/main/docs) folder to the [`slidevjs/docs`](https://github.com/slidevjs/docs) repo. All Pull Requests for documentation changes should still be made to this repository. Any merged changes will be automatically mirrored to the new documentation repo. The easiest way to contribute documentation to this project is to follow these steps: 1. [Fork the repository](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo), for example to `https://github.com/octocat/slidev`, where `octocat` is your GitHub username. 2. Clone the newly forked repo from your GitHub account 3. Create a new branch to add your work to, i.e. `git checkout -b docs/update-contributing-guidelines` 4. Make your changes and commit them 5. Push the branch to your fork 6. Go to [https://github.com/slidevjs/slidev/pulls](https://github.com/slidevjs/slidev/pulls), there should be a "Compare & Pull Request" button, where you can create a PR. ## Setup (in your browser) You can contribute through a development environment in your browser by clicking the following button: [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/slidevjs/slidev) ## Setup (locally) This project uses [`pnpm`](https://pnpm.io/) to manage the dependencies, install it if you haven't via ```bash npm i -g pnpm ``` Clone this repo to your local machine and install the dependencies. ```bash pnpm install ``` ## Development To build all the packages at once, run the following command on the project root ```bash pnpm build ``` Build with watch mode ```bash pnpm dev ``` ### Run Demo To run Slidev locally, you can run ```bash pnpm demo:dev ``` Or with the real-world example `Composable Vue`: ```bash pnpm demo:composable-vue ``` The server will restart automatically every time the builds get updated. ## Project Structure ### Monorepo We use monorepo to manage multiple packages ``` packages slidev/ - main package entry, holds the code on Node.js side client/ - main frontend app parser/ - parser for Slidev's extended Markdown format create-app/ - scripts and template for `npm init slidev` create-theme/ - scripts and template for `npm init slidev-theme` vscode/ - the VSCode extension ``` ## Code Style Don't worry about the code style as long as you install the dev dependencies. Git hooks will format and fix them for you on committing. ## Thanks Thank you again for being interested in this project! You are awesome! ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2020-PRESENT Anthony Fu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================

Slidev

Presentation slides for developers 🧑‍💻👩‍💻👨‍💻

NPM version NPM Downloads Docs & Demos Themes
GitHub stars

Video Preview | Documentation


Made possible by my Sponsor Program 💖
## Features - 📝 [**Markdown-based**](https://sli.dev/guide/syntax) - focus on content and use your favorite editor - 🧑‍💻 [**Developer Friendly**](https://sli.dev/guide/syntax#code-blocks) - built-in code highlighting, live coding, etc. - 🎨 [**Themable**](https://sli.dev/resources/theme-gallery) - theme can be shared and used with npm packages - 🌈 [**Stylish**](https://sli.dev/guide/syntax#embedded-styles) - on-demand utilities via [UnoCSS](https://github.com/unocss/unocss). - 🤹 [**Interactive**](https://sli.dev/custom/directory-structure#components) - embedding Vue components seamlessly - 🎙 [**Presenter Mode**](https://sli.dev/guide/ui#presenter-mode) - use another window, or even your phone to control your slides - 🎨 [**Drawing**](https://sli.dev/features/drawing) - draw and annotate on your slides - 🧮 [**LaTeX**](https://sli.dev/features/latex) - built-in LaTeX math equations support - 📰 [**Diagrams**](https://sli.dev/guide/syntax#diagrams) - creates diagrams using textual descriptions with [Mermaid](https://mermaid.js.org/) - 🌟 [**Icons**](https://sli.dev/features/icons) - access to icons from any icon set directly - 💻 [**Editor**](https://sli.dev/guide/index#editor) - integrated editor, or the [VSCode extension](https://sli.dev/features/vscode-extension) - 🎥 [**Recording**](https://sli.dev/features/recording) - built-in recording and camera view - 📤 [**Portable**](https://sli.dev/guide/exporting) - export into PDF, PNGs, or PPTX - ⚡️ [**Fast**](https://vitejs.dev) - instant reloading powered by [Vite](https://vitejs.dev) - 🛠 [**Hackable**](https://sli.dev/custom/) - using Vite plugins, Vue components, or any npm packages ## Getting Started ### Try it Online ⚡️ [sli.dev/new](https://sli.dev/new) [![](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://sli.dev/new) ### Init Project Locally Install [Node.js >=18](https://nodejs.org/) and run the following command: ```bash npm init slidev ``` Documentation: **[English](https://sli.dev)** | [中文文档](https://cn.sli.dev) | [Français](https://fr.sli.dev) | [Español](https://es.sli.dev) | [Русский](https://ru.sli.dev) | [Português-BR](https://br.sli.dev) Discord: [chat.sli.dev](https://chat.sli.dev) For a full example, you can check the [demo](https://github.com/slidevjs/slidev/blob/main/demo) folder, which is also the source file for [my previous talk](https://antfu.me/posts/composable-vue-vueday-2021). ## Tech Stack - [Vite](https://vitejs.dev) - An extremely fast frontend tooling - [Vue 3](https://v3.vuejs.org/) powered [Markdown](https://daringfireball.net/projects/markdown/syntax) - Focus on the content while having the power of HTML and Vue components whenever needed - [UnoCSS](https://github.com/unocss/unocss) - On-demand utility-first CSS engine, style your slides at ease - [Shiki](https://github.com/shikijs/shiki), [Monaco Editor](https://github.com/Microsoft/monaco-editor) - First-class code snippets support with live coding capability - [RecordRTC](https://recordrtc.org) - Built-in recording and camera view - [VueUse](https://vueuse.org) family - [`@vueuse/core`](https://github.com/vueuse/vueuse), [`@vueuse/motion`](https://github.com/vueuse/motion), etc. - [Iconify](https://iconify.design/) - Icon sets collection. - [Drauu](https://github.com/antfu/drauu) - Drawing and annotations support - [KaTeX](https://katex.org/) - LaTeX math rendering. - [Mermaid](https://mermaid-js.github.io/mermaid) - Textual Diagrams. ## Sponsors This project is made possible by all the sponsors supporting my work:

Logos from Sponsors

## License MIT License © 2021 [Anthony Fu](https://github.com/antfu) ================================================ FILE: cypress/e2e/examples/basic.spec.ts ================================================ export {} declare global { // eslint-disable-next-line ts/no-namespace namespace Cypress { interface Chainable { rightArrow: (n?: number) => Chainable } } } Cypress.Commands.add('rightArrow', (n = 1) => { cy.get('body').wait(500).type('{rightarrow}'.repeat(n)).wait(500) }) const BASE = 'http://localhost:3041' context('Basic', () => { beforeEach(() => { cy.visit('/') }) function goPage(no: number) { cy.get('body') .wait(100) .type('g') .wait(100) .get('#slidev-goto-input') .type(`${no}`, { force: true }) .type('{enter}', { force: true }) .url() .should('eq', `${BASE}/${no}`) .wait(500) } it('basic nav', () => { cy.url() .should('eq', `${BASE}/1`) cy.contains('Global Footer') .should('exist') cy.get('#page-root > #slide-container > #slide-content') cy.rightArrow() .url() .should('eq', `${BASE}/2`) cy.contains('Global Footer') .should('not.exist') cy.get('#page-root > #slide-container > #slide-content > #slideshow .slidev-page-2 > div > p') .should('have.css', 'border-color', 'rgb(0, 128, 0)') .should('not.have.css', 'color', 'rgb(128, 0, 0)') goPage(5) cy.get('#page-root > #slide-container > #slide-content > #slideshow .slidev-page-5 .slidev-code') .should('have.text', '
{{$slidev.nav.currentPage}}
') .get('#page-root > #slide-container > #slide-content > #slideshow .slidev-page-5 > div > p') .should('have.text', 'Current Page: 5') }) it('should nav correctly', () => { goPage(5) cy.get('body') .type('{DownArrow}') .url() .should('eq', `${BASE}/6`) cy.rightArrow() cy .url() .should('eq', `${BASE}/6?clicks=1`) cy.get('body') .type('{RightArrow}{RightArrow}{RightArrow}{RightArrow}{RightArrow}{RightArrow}') .url() .should('eq', `${BASE}/7`) cy.get('body') .type('{LeftArrow}') .url() .should('eq', `${BASE}/6?clicks=6`) cy.get('body') .type('{DownArrow}') .url() .should('eq', `${BASE}/7`) cy.get('body') .type('{UpArrow}') .url() .should('eq', `${BASE}/6`) }) it('named slots', () => { goPage(8) cy.get('.col-right') .contains('Right') }) it('clicks map', () => { goPage(9) cy .url() .should('eq', `${BASE}/9`) cy.rightArrow() cy .url() .should('eq', `${BASE}/9?clicks=1`) cy.get('#slideshow .slidev-page-9 .cy-content .slidev-vclick-target:not(.slidev-vclick-hidden)') .should('have.text', 'CD') cy.rightArrow(2) cy.get('#slideshow .slidev-page-9 .cy-content .slidev-vclick-target:not(.slidev-vclick-hidden)') .should('have.text', 'ABCD') // v-click.hide cy.rightArrow() cy.get('#slideshow .slidev-page-9 .cy-content .slidev-vclick-target:not(.slidev-vclick-hidden)') .should('have.text', 'ABC') cy .url() .should('eq', `${BASE}/9?clicks=4`) cy.rightArrow() cy .url() .should('eq', `${BASE}/10`) cy.rightArrow() cy .url() .should('eq', `${BASE}/10?clicks=1`) cy.get('#slideshow .slidev-page-10 .cy-content-hide .slidev-vclick-target:not(.slidev-vclick-hidden)') .should('have.text', 'BD') cy.rightArrow() cy.get('#slideshow .slidev-page-10 .cy-content-hide .slidev-vclick-target:not(.slidev-vclick-hidden)') .should('have.text', 'D') cy.rightArrow() cy.get('#slideshow .slidev-page-10 .cy-content-hide .slidev-vclick-target:not(.slidev-vclick-hidden)') .should('have.text', 'CD') cy.rightArrow() cy .url() .should('eq', `${BASE}/10?clicks=4`) cy.rightArrow() cy .url() .should('eq', `${BASE}/11`) }) it('overview nav', () => { goPage(2) cy.get('body') .type('o{RightArrow}{RightArrow}{Enter}') .url() .should('eq', `${BASE}/4`) cy.get('body') .type('o{LeftArrow}{LeftArrow}{LeftArrow}{Enter}') .url() .should('eq', `${BASE}/1`) cy.get('body') .type('o{DownArrow}{DownArrow}{DownArrow}{Enter}') .url() .should('not.eq', `${BASE}/1`) cy.get('body') .type('o{UpArrow}{UpArrow}{UpArrow}{Enter}') .url() .should('eq', `${BASE}/1`) }) it('deep nested lists', () => { goPage(11) cy .url() .should('eq', `${BASE}/11`) cy.get('body') .type('{RightArrow}{RightArrow}{RightArrow}') cy.get('#slideshow .slidev-page-11 .cy-depth .slidev-vclick-target:not(.slidev-vclick-hidden) .slidev-vclick-target:not(.slidev-vclick-hidden) .slidev-vclick-target:not(.slidev-vclick-hidden)') .should('have.text', 'C') cy.get('body') .type('{RightArrow}{RightArrow}{RightArrow}') cy.get('#slideshow .slidev-page-11 .cy-depth .slidev-vclick-target:not(.slidev-vclick-hidden) .slidev-vclick-target:not(.slidev-vclick-hidden) .slidev-vclick-target:not(.slidev-vclick-hidden)') .should('have.text', 'CD') cy.get('body') .type('{RightArrow}{RightArrow}{RightArrow}') cy.get('#slideshow .slidev-page-11 .cy-depth .slidev-vclick-target:not(.slidev-vclick-hidden) .slidev-vclick-target:not(.slidev-vclick-hidden) .slidev-vclick-target:not(.slidev-vclick-hidden)') .should('have.text', 'CDGH') cy.get('body') .type('{RightArrow}{RightArrow}{RightArrow}') cy.get('#slideshow .slidev-page-11 .cy-depth > ul > .slidev-vclick-target:not(.slidev-vclick-hidden)') .should('have.text', 'A B CDEF GHIJKL') }) it('slot in v-clicks', () => { goPage(12) cy .url() .should('eq', `${BASE}/12`) cy.get('body') .type('{RightArrow}{RightArrow}{RightArrow}{RightArrow}{RightArrow}{RightArrow}') .url() .should('eq', `${BASE}/12?clicks=6`) // we should still be on page 12 cy.rightArrow() .url() .should('eq', `${BASE}/13`) cy.get('#slideshow .slidev-page-13 .cy-wrapdecorate > ul > .slidev-vclick-target.slidev-vclick-hidden') .should('have.text', 'AEFZ') cy.get('body') .type('{RightArrow}{RightArrow}{RightArrow}') cy.get('#slideshow .slidev-page-13 .cy-wrapdecorate > ul > .slidev-vclick-target:not(.slidev-vclick-hidden)') .should('have.text', 'AEF') cy.rightArrow() cy.get('#slideshow .slidev-page-13 .cy-wrapdecorate > ul > .slidev-vclick-target:not(.slidev-vclick-hidden)') .should('have.text', 'AEFZ') }) }) ================================================ FILE: cypress/e2e/examples/presenter-resizer.spec.ts ================================================ const LAYOUT_KEY = 'slidev-presenter-layout' function visitPresenter(layout: 1 | 2 | 3) { cy.visit('/presenter', { onBeforeLoad(win) { win.localStorage.setItem(LAYOUT_KEY, String(layout)) }, }) } context('Presenter resizer', () => { it('shows proper resizer handles per layout', () => { // Start with a tall viewport so layout 1 is not in wide mode. cy.viewport(900, 1200) visitPresenter(1) cy.get('.note .notes-resizer').should('exist') cy.get('.note .notes-row-resizer').should('exist') cy.get('.next .notes-row-resizer').should('not.exist') cy.get('.notes-vertical-resizer').should('not.exist') // Switch to wide mode: unified vertical resizer should exist. cy.viewport(1400, 900) cy.get('.notes-vertical-resizer').should('exist') cy.get('.note .notes-resizer').should('not.exist') visitPresenter(2) cy.get('.note .notes-resizer').should('exist') cy.get('.next .notes-row-resizer').should('exist') cy.get('.note .notes-row-resizer').should('not.exist') cy.get('.notes-vertical-resizer').should('not.exist') visitPresenter(3) cy.get('.note .notes-resizer').should('not.exist') cy.get('.note .notes-row-resizer').should('exist') cy.get('.next .notes-row-resizer').should('not.exist') cy.get('.notes-vertical-resizer').should('not.exist') cy.get('.notes-vertical-resizer-left').should('exist') }) it('applies CSS variables for dynamic sizing', () => { visitPresenter(1) cy.get('.grid-container') .invoke('attr', 'style') .then((style) => { expect(style).to.include('--slidev-presenter-notes-width') expect(style).to.include('--slidev-presenter-notes-row-size') }) }) }) ================================================ FILE: cypress/e2e/examples/smoke.spec.ts ================================================ context('Smoke test', () => { async function testAllSlides() { while (1) { let oldUrl, newUrl cy.get('body') .url() .then(url => (oldUrl = url)) .type(`{RightArrow}`) .wait(1000) .url() .then(url => (newUrl = url)) if (oldUrl === newUrl) break } } it('should throw no error in Play mode', async () => { cy.visit('/').wait(4000) await testAllSlides() }) it('should throw no error in Presenter mode', async () => { cy.visit('/presenter').wait(4000) await testAllSlides() }) it('should throw no error in Overview page', async () => { cy.visit('/overview').wait(4000) }) it('should throw no error in Entry page', async () => { cy.visit('/entry').wait(4000) }) }) ================================================ FILE: cypress/fixtures/basic/components/DecorateWithLi.vue ================================================ ================================================ FILE: cypress/fixtures/basic/components/WrapInClicks.vue ================================================ ================================================ FILE: cypress/fixtures/basic/components/WrapInClicksDecorate.vue ================================================ ================================================ FILE: cypress/fixtures/basic/components/WrapInComponentInClicks.vue ================================================ ================================================ FILE: cypress/fixtures/basic/global.vue ================================================ ================================================ FILE: cypress/fixtures/basic/package.json ================================================ { "private": true, "scripts": { "dev": "nodemon -w '../../../packages/slidev/dist/*.js' --exec 'slidev --log=info --port=3041'", "build": "slidev build", "export": "slidev export" }, "devDependencies": { "@slidev/cli": "workspace:*", "@slidev/theme-default": "catalog:themes", "@slidev/theme-seriph": "catalog:themes", "@slidev/types": "workspace:*", "nodemon": "catalog:dev" } } ================================================ FILE: cypress/fixtures/basic/slides.md ================================================ # Page 1 Hello World --- # Page 2 ```html ``` `

` should have a green border, but no red text --- src: sub/page1.md --- This will be ignored --- src: sub/page2.md background: https://sli.dev/demo-cover.png --- --- # Page 5 ```html

{{$slidev.nav.currentPage}}
``` Current Page: {{$slidev.nav.currentPage}} --- # Page 6 - A - B - C 1. C 2. B 3. A --- # Page 7 $$ \begin{aligned} \frac{D \boldsymbol{v}}{D t}=&-\frac{1}{\rho} \operatorname{grad} p+\frac{\mu}{\rho} \Delta \boldsymbol{v}+\frac{\lambda+\mu}{\rho} \operatorname{grad} \Theta+\frac{\Theta}{\rho} \operatorname{grad}(\lambda+\mu) \\ &+\frac{1}{\rho} \operatorname{grad}(\boldsymbol{v} \cdot \operatorname{grad} \mu)+\frac{1}{\rho} \operatorname{rot}(\boldsymbol{v} \times \operatorname{grad} \mu)-\frac{1}{\rho} \boldsymbol{v} \Delta \mu+\boldsymbol{g} \end{aligned} $$ --- layout: two-cols --- ::right:: # Right Right :: default :: # Left Left --- # Page 9
A
B
C
D
E
--- # Page 10
A
B
C
D
--- # Page 11
- A - B - C - D - E - F - G - H - I - J - K - L
--- # Page 12
  • A
  • B
  • A
  • B
- A - B --- # Page 13
  • E
  • F
  • (the next is kept for a future patch but not animating the nesting)
  • step i
  • step j
  • ================================================ FILE: cypress/fixtures/basic/sub/page1.md ================================================ # Sub page 1 $x+2$ ================================================ FILE: cypress/fixtures/basic/sub/page2.md ================================================ --- layout: cover --- # Sub page 2 ================================================ FILE: cypress/fixtures/basic/vite.config.ts ================================================ import { defineConfig } from 'vite' export default defineConfig({ build: { manifest: true, minify: false, }, }) ================================================ FILE: cypress/tsconfig.json ================================================ { "extends": "../tsconfig.json", "compilerOptions": { "types": ["cypress"], "noEmit": true }, "include": [ "../node_modules/cypress", "./**/*.ts" ] } ================================================ FILE: cypress.config.ts ================================================ import { defineConfig } from 'cypress' export default defineConfig({ e2e: { baseUrl: 'http://localhost:3041', chromeWebSecurity: false, specPattern: 'cypress/e2e/**/*.spec.*', supportFile: false, }, }) ================================================ FILE: demo/README.md ================================================ The best way of understanding Slidev is to try it, with the following command: ```bash npm init slidev ``` Learn more: https://sli.dev ================================================ FILE: demo/composable-vue/components/Connections.vue ================================================ ================================================ FILE: demo/composable-vue/components/DarkToggle.vue ================================================ ================================================ FILE: demo/composable-vue/components/Marker.vue ================================================ ================================================ FILE: demo/composable-vue/components/MarkerCore.vue ================================================ ================================================ FILE: demo/composable-vue/components/MarkerPattern.vue ================================================ ================================================ FILE: demo/composable-vue/components/MarkerTips.vue ================================================ ================================================ FILE: demo/composable-vue/components/NumBox.vue ================================================ ================================================ FILE: demo/composable-vue/components/VueUse.vue ================================================ ================================================ FILE: demo/composable-vue/index.html ================================================ ================================================ FILE: demo/composable-vue/package.json ================================================ { "private": true, "scripts": { "dev": "nodemon -w '../../packages/slidev/dist/*.mjs' --exec 'slidev --log=info'", "build": "slidev build", "export": "slidev export", "export:clicks": "slidev export --with-clicks" }, "devDependencies": { "@iconify-json/mdi": "catalog:icons", "@iconify-json/ri": "catalog:icons", "@slidev/cli": "workspace:*", "@slidev/theme-default": "catalog:themes", "@slidev/theme-seriph": "catalog:themes", "@slidev/types": "workspace:*", "nodemon": "catalog:dev" } } ================================================ FILE: demo/composable-vue/setup/monaco.ts ================================================ import { defineMonacoSetup } from '@slidev/types' export default defineMonacoSetup((monaco) => { monaco.languages.typescript.typescriptDefaults.addExtraLib( ` import { InjectionKey } from 'vue' export interface UserInfo { id: number; name: string } export const injectKeyUser: InjectionKey = Symbol() `, 'file:///root/context.ts', ) }) ================================================ FILE: demo/composable-vue/slides.md ================================================ --- layout: cover download: 'https://antfu.me/talks/2021-04-29' highlighter: shiki monaco: true info: | ## Composable Vue Patterns and tips for writing good composable logic in Vue [Anthony Fu](https://antfu.me/) at [VueDay 2021](https://2021.vueday.it/) - [Recording](https://www.youtube.com/watch?v=IMJjP6edHd0) - [Transcript](https://antfu.me/posts/composable-vue-vueday-2021) - [Source code](https://github.com/antfu/talks/tree/master/2021-04-29) --- # Composable Vue Patterns and tips for writing good composable logic in Vue
    Anthony Fu
    VueDay
    Apr. 29th, 2021
    --- layout: 'intro' --- # Anthony Fu
    Vue core team member and Vite team member.
    Creator of VueUse, i18n Ally and Type Challenges.
    A fanatical full-time open sourceror.
    A comic art image of Anthony Fu --- name: Sponsors layout: center --- A list of the sponsor logos
    --- layout: center --- # Composable Vue --- name: VueUse layout: center ---
    Collection of essential Vue Composition Utilities
    NPM version NPM Downloads Docs & Demos Function Count
    GitHub stars
    - Works for both Vue 2 and 3 - Tree-shakeable ESM - CDN compatible - TypeScript - Rich ecosystems
    --- layout: center class: text-center --- # Composition API a brief go-through ---
    # Ref ```ts {monaco} import { ref } from 'vue' let foo = 0 let bar = ref(0) foo = 1 bar = 1 // ts-error ```
    ### Pros - More explicit, with type checking - Less caveats ### Cons - `.value`
    # Reactive ```ts {monaco} import { reactive } from 'vue' const foo = { prop: 0 } const bar = reactive({ prop: 0 }) foo.prop = 1 bar.prop = 1 ```
    ### Pros - Auto unwrapping (a.k.a `.value` free) ### Cons - Same as plain objects on types - Destructure loses reactivity - Need to use callback for `watch`
    --- # Ref Auto Unwrapping Get rid of `.value` for most of the time.
    - `watch` accepts ref as the watch target, and returns the unwrapped value in the callback ```ts const counter = ref(0) watch(counter, (count) => { console.log(count) // same as `counter.value` }) ``` - Ref is auto unwrapped in the template ```html ``` - Reactive will auto-unwrap nested refs.
    ```ts {monaco} import { reactive, ref } from 'vue' const foo = ref('bar') const data = reactive({ foo, id: 10 }) data.foo // 'bar' ```
    --- # `unref` - Opposite of Ref - If it gets a Ref, returns the value of it. - Otherwise, returns as-is.
    ### Implementation ```ts function unref(r: Ref | T): T { return isRef(r) ? r.value : r } ```
    ### Usage ```ts {monaco} import { ref, unref } from 'vue' const foo = ref('foo') unref(foo) // 'foo' const bar = 'bar' unref(bar) // 'bar' ```
    --- layout: center class: text-center --- # Patterns & Tips of writing composable functions --- # What's Composable Functions Sets of reusable logic, separation of concerns.
    ```ts export function useDark(options: UseDarkOptions = {}) { const preferredDark = usePreferredDark() // <-- const store = useLocalStorage('vueuse-dark', 'auto') // <-- return computed({ get() { return store.value === 'auto' ? preferredDark.value : store.value === 'dark' }, set(v) { store.value = v === preferredDark.value ? 'auto' : v ? 'dark' : 'light' }, }) } ```
    --- # Think as "Connections" The `setup()` only runs **once** on component initialization, to construct the relations between your state and logic. - Input → OutputEffects - Output reflects to input's changes automatically

    SpreadSheet Formula

    --- # One Thing at a Time Just the same as authoring JavaScript functions. - Extract duplicated logics into composable functions - Have meaningful names - Consistent naming conversions - `useXX` `createXX` `onXX` - Keep function small and simple - "Do one thing, and do it well" --- # Passing Refs as Arguments
    ### Implementation ### Usage
    Plain function
    ```ts function add(a: number, b: number) { return a + b } ``` ```ts const a = 1 const b = 2 const c = add(a, b) // 3 ```
    Accepts refs,
    returns a reactive result.
    ```ts function add(a: Ref, b: Ref) { return computed(() => a.value + b.value) } ``` ```ts const a = ref(1) const b = ref(2) const c = add(a, b) c.value // 3 ```
    Accepts both refs and plain values.
    ```ts function add( a: Ref | number, b: Ref | number, ) { return computed(() => unref(a) + unref(b)) } ``` ```ts const a = ref(1) const c = add(a, 5) c.value // 6 ```
    --- # MaybeRef A custom type helper ```ts type MaybeRef = Ref | T ``` In VueUse, we use this helper heavily to support optional reactive arguments ```ts export function useTimeAgo( time: Date | number | string | Ref, ) { return computed(() => someFormating(unref(time))) } ``` ```ts {monaco} import type { Ref } from 'vue' import { computed, unref } from 'vue' type MaybeRef = Ref | T export function useTimeAgo( time: MaybeRef, ) { return computed(() => someFormating(unref(time))) } ``` --- # Make it Flexible Make your functions like LEGO, can be used with different components in different ways.
    ### Create a "Special" Ref ```ts {monaco} import { useTitle } from '@vueuse/core' const title = useTitle() title.value = 'Hello World' // now the page's title changed ```
    ### Binding an Existing Ref ```ts {monaco} import { useTitle } from '@vueuse/core' import { computed, ref } from 'vue' const name = ref('Hello') const title = computed(() => { return `${name.value} - World` }) useTitle(title) // Hello - World name.value = 'Hi' // Hi - World ```
    --- # `useTitle` Case Take a look at `useTitle`'s implementation
    ```ts {monaco} import type { MaybeRef } from '@vueuse/core' import { ref, watch } from 'vue' export function useTitle( newTitle: MaybeRef, ) { const title = ref(newTitle || document.title) watch(title, (t) => { if (t != null) document.title = t }, { immediate: true }) return title } ``` ```html <-- 1. use the user provided ref or create a new one <-- 2. sync ref changes to the document title ```
    --- # "Reuse" Ref If you pass a `ref` into `ref()`, it will return the original ref as-is. ```ts const foo = ref(1) // Ref<1> const bar = ref(foo) // Ref<1> foo === bar // true ``` ```ts function useFoo(foo: Ref | string) { // no need! const bar = isRef(foo) ? foo : ref(foo) // they are the same const bar = ref(foo) /* ... */ } ``` Extremely useful in composable functions that take uncertain argument types. --- # `ref` / `unref`
    - `MaybeRef` works well with `ref` and `unref`. - Use `ref()` when you want to normalized it as a Ref. - Use `unref()` when you want to have the value.
    ```ts type MaybeRef = Ref | T function useBala(arg: MaybeRef) { const reference = ref(arg) // get the ref const value = unref(arg) // get the value } ```
    --- # Object of Refs Getting benefits from both `ref` and `reactive` for authoring composable functions
    ```ts {monaco} import { reactive, ref } from 'vue' function useMouse() { return { x: ref(0), y: ref(0), } } const { x, y } = useMouse() const mouse = reactive(useMouse()) mouse.x === x.value // true ```
    - Destructurable as Ref - Convert to reactive object to get the auto-unwrapping when needed
    --- # Async to "Sync" With Composition API, we can actually turn async data into "sync"
    ### Async ```ts const data = await fetch('https://api.github.com/').then(r => r.json()) // use data ```
    ### Composition API ```ts const { data } = useFetch('https://api.github.com/').json() const user_url = computed(() => data.value?.user_url) ```
    Establish the "Connections" first, then wait for data to be filled up. The idea is similar to SWR (stale-while-revalidate)
    --- # `useFetch` Case ```ts export function useFetch(url: MaybeRef) { const data = shallowRef() const error = shallowRef() fetch(unref(url)) .then(r => r.json()) .then(r => data.value = r) .catch(e => error.value = e) return { data, error, } } ```
    --- # Side-effects Self Cleanup The `watch` and `computed` will stop themselves on components unmounted.
    We'd recommend following the same pattern for your custom composable functions.
    ```ts {monaco} import { onUnmounted } from 'vue' export function useEventListener(target: EventTarget, name: string, fn: any) { target.addEventListener(name, fn) onUnmounted(() => { target.removeEventListener(name, fn) // <-- }) } ```
    --- # `effectScope` RFC Upcoming A new API to collect the side effects automatically. Likely to be shipped with Vue 3.1
    https://github.com/vuejs/rfcs/pull/212 ```ts // effect, computed, watch, watchEffect created inside the scope will be collected const scope = effectScope(() => { const doubled = computed(() => counter.value * 2) watch(doubled, () => console.log(double.value)) watchEffect(() => console.log('Count: ', double.value)) }) // dispose all effects in the scope stop(scope) ``` --- disabled: true --- # Template Ref To get DOM element, you can pass a ref to it, and it will be available after component mounted
    ```ts {monaco} import { defineComponent, onMounted, ref } from 'vue' export default defineComponent({ setup() { const element = ref() onMounted(() => { element.value // now you have it }) return { element } }, }) ``` ```html {monaco} ```
    --- disabled: true --- # Template Ref Use `watch` instead of `onMounted` to unify the handling for template ref changes.
    ```ts {monaco} import { defineComponent, ref, watch } from 'vue' export default defineComponent({ setup() { const element = ref() watch(element, (el) => { // clean up previous side effect if (el) { // use the DOM element } }) return { element } }, }) ```
    --- # Typed Provide / Inject Use the `InjectionKey` helper from Vue to share types across context.
    ```ts {monaco} // context.ts import type { InjectionKey } from 'vue' export interface UserInfo { id: number name: string } export const injectKeyUser: InjectionKey = Symbol('user') ```
    --- # Typed Provide / Inject Import the key from the same module for `provide` and `inject`.
    ```ts {monaco} // parent.vue import { provide } from 'vue' import { injectKeyUser } from './context' export default { setup() { provide(injectKeyUser, { id: '7', // type error: should be number name: 'Anthony', }) }, } ``` ```ts {monaco} // child.vue import { inject } from 'vue' import { injectKeyUser } from './context' export default { setup() { const user = inject(injectKeyUser) // UserInfo | undefined if (user) console.log(user.name) // Anthony }, } ```
    --- # Shared State By the nature of Composition API, states can be created and used independently.
    ```ts // shared.ts import { reactive } from 'vue' export const state = reactive({ foo: 1, bar: 'Hello', }) ```
    ```ts // A.vue import { state } from './shared.ts' state.foo += 1 ``` ```ts // B.vue import { state } from './shared.ts' console.log(state.foo) // 2 ```

    ⚠️ But it's not SSR compatible!

    --- # Shared State (SSR friendly) Use `provide` and `inject` to share the app-level state
    ```ts export const myStateKey: InjectionKey = Symbol('state') export function createMyState() { const state = { /* ... */ } return { install(app: App) { app.provide(myStateKey, state) }, } } export function useMyState(): MyState { return inject(myStateKey)! } ```
    ```ts // main.ts const App = createApp(App) app.use(createMyState()) ``` ```ts // A.vue // use everywhere in your app const state = useMyState() ```
    - [Vue Router v4](https://github.com/vuejs/vue-router-next) is using the similar approach
    --- # useVModel A helper to make props/emit easier
    ```ts export function useVModel(props, name) { const emit = getCurrentInstance().emit return computed({ get() { return props[name] }, set(v) { emit(`update:${name}`, v) }, }) } ```
    ```ts export default defineComponent({ setup(props) { const value = useVModel(props, 'value') return { value } }, }) ```
    ```html ```
    --- disabled: true --- # useVModel (Passive) Make the model able to be updated **independently** from the parent logic ```ts export function usePassiveVModel(props, name) { const emit = getCurrentInstance().emit const data = ref(props[name]) // store the value in a ref watch(() => props.value, v => data.value = v) // sync the ref whenever the prop changes return computed({ get() { return data.value }, set(v) { data.value = v // when setting value, update the ref directly emit(`update:${name}`, v) // then emit out the changes }, }) } ``` --- layout: center --- # All of them work for both Vue 2 and 3 --- # `@vue/composition-api` Lib Composition API support for Vue 2.
    [vuejs/composition-api](https://github.com/vuejs/composition-api) ```ts import VueCompositionAPI from '@vue/composition-api' import Vue from 'vue' Vue.use(VueCompositionAPI) ``` ```ts import { reactive, ref } from '@vue/composition-api' ``` --- # Vue 2.7 Upcoming [Plans in Vue 2.7](https://github.com/vuejs/rfcs/blob/ie11/active-rfcs/0000-vue3-ie11-support.md#for-those-who-absolutely-need-ie11-support) - Backport `@vue/composition-api` into Vue 2's core. - ` ================================================ FILE: demo/starter/package.json ================================================ { "name": "slidev-demo", "private": true, "scripts": { "build": "slidev build", "dev": "nodemon -w '../../packages/slidev/dist/*.mjs' --exec \"slidev ./slides.md --open=false --log=info --inspect\"", "export": "slidev export", "export-notes": "slidev export-notes" }, "devDependencies": { "@slidev/cli": "workspace:*", "@slidev/theme-default": "catalog:themes", "@slidev/theme-seriph": "catalog:themes", "nodemon": "catalog:dev", "vue": "catalog:frontend" } } ================================================ FILE: demo/starter/pages/imported-slides.md ================================================ # Imported Slides You can split your slides.md into multiple files and organize them as you want using the `src` attribute. #### `slides.md` ```markdown # Page 1 Page 2 from main entry. --- ## src: ./subpage.md ```
    #### `subpage.md` ```markdown # Page 2 Page 2 from another file. ``` [Learn more](https://sli.dev/guide/syntax.html#importing-slides) ================================================ FILE: demo/starter/slides.md ================================================ --- # try also 'default' to start simple theme: seriph # random image from a curated Unsplash collection by Anthony # like them? see https://unsplash.com/collections/94734566/slidev background: https://cover.sli.dev # some information about your slides (markdown enabled) title: Welcome to Slidev info: | ## Slidev Starter Template Presentation slides for developers. Learn more at [Sli.dev](https://sli.dev) # apply UnoCSS classes to the current slide class: text-center # https://sli.dev/features/drawing drawings: persist: false # slide transition: https://sli.dev/guide/animations.html#slide-transitions transition: slide-left # enable Comark Syntax: https://comark.dev/syntax/markdown comark: true # duration of the presentation duration: 35min --- # Welcome to Slidev Presentation slides for developers
    Press Space for next page
    --- transition: fade-out --- # What is Slidev? Slidev is a slides maker and presenter designed for developers, consist of the following features - 📝 **Text-based** - focus on the content with Markdown, and then style them later - 🎨 **Themable** - themes can be shared and re-used as npm packages - 🧑‍💻 **Developer Friendly** - code highlighting, live coding with autocompletion - 🤹 **Interactive** - embed Vue components to enhance your expressions - 🎥 **Recording** - built-in recording and camera view - 📤 **Portable** - export to PDF, PPTX, PNGs, or even a hostable SPA - 🛠 **Hackable** - virtually anything that's possible on a webpage is possible in Slidev

    Read more about [Why Slidev?](https://sli.dev/guide/why) --- transition: slide-up level: 2 --- # Navigation Hover on the bottom-left corner to see the navigation's controls panel, [learn more](https://sli.dev/guide/ui#navigation-bar) ## Keyboard Shortcuts | | | | --------------------------------------------------- | --------------------------- | | right / space | next animation or slide | | left / shiftspace | previous animation or slide | | up | previous slide | | down | next slide |

    Here!

    --- layout: two-cols layoutClass: gap-16 --- # Table of contents You can use the `Toc` component to generate a table of contents for your slides: ```html ``` The title will be inferred from your slide content, or you can override it with `title` and `level` in your frontmatter. ::right:: --- layout: image-right image: https://cover.sli.dev --- # Code Use code snippets and get the highlighting directly, and even types hover! ```ts [filename-example.ts] {all|4|6|6-7|9|all} twoslash // TwoSlash enables TypeScript hover information // and errors in markdown code blocks // More at https://shiki.style/packages/twoslash import { computed, ref } from 'vue' const count = ref(0) const doubled = computed(() => count.value * 2) doubled.value = 2 ``` <<< @/snippets/external.ts#snippet [Learn more](https://sli.dev/features/line-highlighting) --- level: 2 --- # Shiki Magic Move Powered by [shiki-magic-move](https://shiki-magic-move.netlify.app/), Slidev supports animations across multiple code snippets. Add multiple code blocks and wrap them with ````md magic-move (four backticks) to enable the magic move. For example: ````md magic-move {lines: true} ```ts {*|2|*} // step 1 const author = reactive({ name: 'John Doe', books: [ 'Vue 2 - Advanced Guide', 'Vue 3 - Basic Guide', 'Vue 4 - The Mystery' ] }) ``` ```ts {*|1-2|3-4|3-4,8} // step 2 export default { data() { return { author: { name: 'John Doe', books: [ 'Vue 2 - Advanced Guide', 'Vue 3 - Basic Guide', 'Vue 4 - The Mystery' ] } } } } ``` ```ts // step 3 export default { data: () => ({ author: { name: 'John Doe', books: [ 'Vue 2 - Advanced Guide', 'Vue 3 - Basic Guide', 'Vue 4 - The Mystery' ] } }) } ``` Non-code blocks are ignored. ```vue ``` ```` --- # Components
    You can use Vue components directly inside your slides. We have provided a few built-in components like `` and `` that you can use directly. And adding your custom components is also super easy. ```html ``` Check out [the guides](https://sli.dev/builtin/components.html) for more.
    ```html ```
    --- class: px-20 --- # Themes Slidev comes with powerful theming support. Themes can provide styles, layouts, components, or even configurations for tools. Switching between themes by just **one edit** in your frontmatter:
    ```yaml --- theme: default --- ``` ```yaml --- theme: seriph --- ```
    Read more about [How to use a theme](https://sli.dev/guide/theme-addon#use-theme) and check out the [Awesome Themes Gallery](https://sli.dev/resources/theme-gallery). --- # Clicks Animations You can add `v-click` to elements to add a click animation.
    This shows up when you click the slide: ```html
    This shows up when you click the slide.
    ```

    The v-mark directive also allows you to add inline marks , powered by [Rough Notation](https://roughnotation.com/): ```html inline markers ```
    [Learn more](https://sli.dev/guide/animations#click-animation)
    --- # Motions Motion animations are powered by [@vueuse/motion](https://motion.vueuse.org/), triggered by `v-motion` directive. ```html
    Slidev
    ```
    Slidev
    [Learn more](https://sli.dev/guide/animations.html#motion)
    --- # $\LaTeX$ $\LaTeX$ is supported out-of-box. Powered by [$\KaTeX$](https://katex.org/).
    Inline $\sqrt{3x-1}+(1+x)^2$ Block $$ {1|3|all} \begin{aligned} \nabla \cdot \vec{E} &= \frac{\rho}{\varepsilon_0} \\ \nabla \cdot \vec{B} &= 0 \\ \nabla \times \vec{E} &= -\frac{\partial\vec{B}}{\partial t} \\ \nabla \times \vec{B} &= \mu_0\vec{J} + \mu_0\varepsilon_0\frac{\partial\vec{E}}{\partial t} \end{aligned} $$ [Learn more](https://sli.dev/features/latex) --- # Diagrams You can create diagrams / graphs from textual descriptions, directly in your Markdown.
    ```mermaid {scale: 0.5, alt: 'A simple sequence diagram'} sequenceDiagram Alice->John: Hello John, how are you? Note over Alice,John: A typical interaction ``` ```mermaid {theme: 'neutral', scale: 0.8} graph TD B[Text] --> C{Decision} C -->|One| D[Result 1] C -->|Two| E[Result 2] ``` ```mermaid mindmap root((mindmap)) Origins Long history ::icon(fa fa-book) Popularisation British popular psychology author Tony Buzan Research On effectiveness
    and features On Automatic creation Uses Creative techniques Strategic planning Argument mapping Tools Pen and paper Mermaid ``` ```plantuml {scale: 0.7} @startuml package "Some Group" { HTTP - [First Component] [Another Component] } node "Other Groups" { FTP - [Second Component] [First Component] --> FTP } cloud { [Example 1] } database "MySql" { folder "This is my folder" { [Folder 3] } frame "Foo" { [Frame 4] } } [Another Component] --> [Example 1] [Example 1] --> [Folder 3] [Folder 3] --> [Frame 4] @enduml ```
    Learn more: [Mermaid Diagrams](https://sli.dev/features/mermaid) and [PlantUML Diagrams](https://sli.dev/features/plantuml) --- foo: bar dragPos: square: 691,32,167,_,-16 --- # Draggable Elements Double-click on the draggable elements to edit their positions.
    ###### Directive Usage ```md ```
    ###### Component Usage ```md
    Use the `v-drag` component to have a draggable container! ```
    Double-click me!
    ###### Draggable Arrow ```md ``` --- src: ./pages/imported-slides.md hide: false --- --- # Monaco Editor Slidev provides built-in Monaco Editor support. Add `{monaco}` to the code block to turn it into an editor: ```ts {monaco} import { ref } from 'vue' import { emptyArray } from './external' const arr = ref(emptyArray(10)) ``` Use `{monaco-run}` to create an editor that can execute the code directly in the slide: ```ts {monaco-run} import { version } from 'vue' import { emptyArray, sayHello } from './external' sayHello() console.log(`vue ${version}`) console.log(emptyArray(10).reduce(fib => [...fib, fib.at(-1)! + fib.at(-2)!], [1, 1])) ``` --- layout: center class: text-center --- # Learn More [Documentation](https://sli.dev) · [GitHub](https://github.com/slidevjs/slidev) · [Showcases](https://sli.dev/resources/showcases) ================================================ FILE: demo/starter/snippets/external.ts ================================================ /* eslint-disable no-console */ // #region snippet // Inside ./snippets/external.ts export function emptyArray(length: number) { return Array.from({ length }) } // #endregion snippet export function sayHello() { console.log('Hello from snippets/external.ts') } ================================================ FILE: demo/starter/style.css ================================================ /* add any global style here */ ================================================ FILE: demo/starter/vite.config.ts ================================================ import { defineConfig } from 'vite' export default defineConfig({ plugins: [], }) ================================================ FILE: demo/vue-runner/package.json ================================================ { "private": true, "scripts": { "build": "slidev build", "dev": "nodemon -w '../../packages/slidev/dist/*.mjs' --exec \"slidev ./slides.md --open=false --log=info --inspect\"", "export": "slidev export", "export-notes": "slidev export-notes" }, "devDependencies": { "@slidev/cli": "workspace:*", "@slidev/theme-default": "catalog:themes", "@slidev/theme-seriph": "catalog:themes", "@vue/compiler-sfc": "catalog:demo", "nodemon": "catalog:dev", "vue": "catalog:frontend" } } ================================================ FILE: demo/vue-runner/setup/code-runners.ts ================================================ /* eslint-disable no-new-func */ import { defineCodeRunnersSetup } from '@slidev/types' export default defineCodeRunnersSetup(() => { return { // Support Vue SFC async vue(code) { const Vue = await import('vue') const { parse, compileScript } = await import('@vue/compiler-sfc') // Compile the script, note this demo does not handle Vue styles const sfc = parse(code) let scripts = compileScript(sfc.descriptor, { id: sfc.descriptor.filename, genDefaultAs: '__Component', inlineTemplate: true, }).content // Replace Vue imports to object destructuring // Only for simple demo, it doesn't work with imports from other packages scripts = scripts.replace(/import (\{[^}]+\}) from ['"]vue['"]/g, (_, imports) => `const ${imports.replace(/\sas\s/g, ':')} = Vue`) scripts += '\nreturn __Component' // Create function to evaluate the script and get the component // Note this is not sandboxed, it's NOT secure. const component = new Function(`return (Vue) => {${scripts}}`)()(Vue) // Mount the component const app = Vue.createApp(component) const el = document.createElement('div') app.mount(el) return { element: el, } }, } }) ================================================ FILE: demo/vue-runner/setup/shiki.ts ================================================ import type { ShikiSetupReturn } from '@slidev/types' import { defineShikiSetup } from '@slidev/types' export default defineShikiSetup((): ShikiSetupReturn => { return { langs: [ 'ts', 'js', 'vue', 'html', ], } }) ================================================ FILE: demo/vue-runner/slides.md ================================================ --- layout: default --- # Simple Vue SFC Runner ```vue {monaco-run} ``` --- This is a demo to prove the extensibility of Slidev Code Runners. Refer to `./setup/monaco-runner.ts` for the implementation. Note that there is a lot of edge cases that this demo is not handling. Extra work is needed to make it production ready. ================================================ FILE: docs/.gitignore ================================================ node_modules dist .vitepress/@slidev .vitepress/cache ================================================ FILE: docs/.vitepress/addons.ts ================================================ import type { ThemeInfo } from './themes' export type AddonInfo = Omit export const official: AddonInfo[] = [ { id: '', link: '#', name: 'Work in Progress', description: '', tags: [], author: { name: '', }, }, ] export const community: AddonInfo[] = [ { id: 'slidev-addon-python-runner', name: 'Python Runner', description: 'Run actual Python code in your slides', tags: ['Code runner'], author: { name: '_Kerman', link: 'https://github.com/KermanX', }, repo: 'https://github.com/KermanX/slidev-addon-python-runner', }, { id: 'slidev-addon-tldraw', name: 'tldraw', description: 'Embed tldraw diagrams directly in Slidev, with in-slide editing support', tags: ['Integration', 'Diagram'], author: { name: 'Albert Brand', link: 'https://github.com/AlbertBrand', }, repo: 'https://github.com/AlbertBrand/slidev-addon-tldraw', }, { id: 'slidev-addon-react', name: 'React Components', description: 'Use React components with JSX/TSX in your Slidev presentations.', tags: ['React', 'Component', 'Integration'], repo: 'https://github.com/Ygilany/slidev-addon-react', author: { name: 'YGilany', link: 'https://github.com/YGilany', }, }, { id: 'slidev-addon-typst', name: 'Typst', description: 'Typst addon for Slidev', tags: ['Integration', 'Diagram'], author: { name: 'Shigma', link: 'https://github.com/shigma', }, repo: 'https://github.com/shigma/slidev-addon-typst', }, { id: 'slidev-addon-fancy-arrow', name: 'Fancy Arrow', description: 'Hand drawn arrows with various styling and positioning options', tags: ['Component'], author: { name: 'whitphx', link: 'https://github.com/whitphx', }, repo: 'https://github.com/whitphx/slidev-addon-fancy-arrow', }, { id: 'slidev-addon-sync', name: 'Remote Sync', description: 'Sync component for Slidev static build that uses a SSE or WS server', tags: ['Remote control', 'Navigation'], author: { name: 'Tony Cabaye', link: 'https://github.com/tonai', }, repo: 'https://github.com/Smile-SA/slidev-addon-sync', }, { id: 'slidev-addon-tikzjax', name: 'tikzjax', description: 'Compile TikZ/Chemfig/... to SVG and display them in Slidev', tags: ['Integration', 'Diagram'], author: { name: 'Ethan Goh', link: 'https://github.com/7086cmd', }, repo: 'https://github.com/7086cmd/slidev-addon-tikzjax', }, { id: 'slidev-component-pager', name: 'Pager', description: 'Show current page and total page number', tags: ['Component', 'Navigation'], author: { name: 'Tony Cabaye', link: 'https://github.com/tonai', }, repo: 'https://github.com/Smile-SA/slidev-component-pager', }, { id: 'slidev-component-poll', name: 'Poll and Quiz', description: 'Poll and Quiz components for Slidev', tags: ['Component'], author: { name: 'Tony Cabaye', link: 'https://github.com/tonai', }, repo: 'https://github.com/Smile-SA/slidev-component-poll', }, { id: 'slidev-component-progress', name: 'Progress', description: 'Show interactive progress bar for Slidev', tags: ['Tool', 'Navigation'], author: { name: 'Tony Cabaye', link: 'https://github.com/tonai', }, repo: 'https://github.com/Smile-SA/slidev-component-progress', }, { id: 'slidev-component-scroll', name: 'Mouse Scroll', description: 'Use mouse wheel for navigating', tags: ['Navigation'], author: { name: 'Tony Cabaye', link: 'https://github.com/tonai', }, repo: 'https://github.com/Smile-SA/slidev-component-scroll', }, { id: 'slidev-component-spotlight', name: 'Spotlight', description: 'Activate a spotlight to highlight a specific region by holding a key', tags: ['Tool'], author: { name: 'Tony Cabaye', link: 'https://github.com/tonai', }, repo: 'https://github.com/Smile-SA/slidev-component-spotlight', }, { id: 'slidev-component-zoom', name: 'Zooming', description: 'Allow zooming inside the slides', tags: ['Tool'], author: { name: 'Tony Cabaye', link: 'https://github.com/tonai', }, repo: 'https://github.com/Smile-SA/slidev-component-zoom', }, { id: 'slidev-addon-rabbit', name: 'Rabbit', description: 'Presentation time management for Slidev inspired by Rabbit', tags: ['Tool', 'Navigation'], author: { name: 'kaakaa', link: 'https://github.com/kaakaa', }, repo: 'https://github.com/kaakaa/slidev-addon-rabbit', }, { id: 'slidev-addon-stem', name: 'STEM', description: 'Slidev addon for scientific presentation', tags: ['Component', 'Layout'], author: { name: 'yutaka-shoji', link: 'https://github.com/yutaka-shoji', }, repo: 'https://github.com/yutaka-shoji/slidev-addon-stem', }, { id: 'slidev-addon-naive', name: 'Naive UI', description: 'Brings Naive UI components into Slidev', tags: ['Component'], author: { name: 'Samuel Huang', link: 'https://sghuang.com', }, repo: 'https://github.com/sghuang19/slidev-addon-naive', }, { id: 'slidev-addon-hls-player', name: 'HLS player', description: 'Add a basic hls.js powered video player on your slides to show HTTP Live Streaming videos', tags: ['hls', 'video'], author: { name: 'Albert Brand', link: 'https://github.com/AlbertBrand', }, repo: 'https://github.com/AlbertBrand/slidev-addon-hls-player', }, { id: 'slidev-addon-window-mockup', name: 'Window Mockup', description: 'Styled window frames', tags: ['Component'], author: { name: 'whitphx', link: 'https://github.com/whitphx', }, repo: 'https://github.com/whitphx/slidev-addon-window-mockup', }, { id: 'slidev-addon-bpmn', name: 'BPMN viewer', description: 'Visualize bpmn-files in your slidev', tags: ['Component'], author: { name: 'emaarco', link: 'https://github.com/emaarco', }, repo: 'https://github.com/emaarco/slidev-addon-bpmn', }, { id: 'slidev-addon-p5', name: 'Runner for p5js', description: 'Display, edit and run p5js sketches in your slidev', tags: ['Component', 'Code runner'], author: { name: 'mjvo', link: 'https://github.com/mjvo', }, repo: 'https://github.com/mjvo/slidev-addon-p5', }, // Add yours here! { id: '', link: 'https://github.com/slidevjs/slidev/edit/main/docs/.vitepress/addons.ts', name: 'Yours?', description: 'Click here to submit your addon :)', tags: [], author: { name: '', }, }, ] ================================================ FILE: docs/.vitepress/config.ts ================================================ import type { DefaultTheme } from 'vitepress' import { fileURLToPath } from 'node:url' import { transformerTwoslash } from '@shikijs/vitepress-twoslash' import { defineConfig } from 'vitepress' import { groupIconMdPlugin } from 'vitepress-plugin-group-icons' import { version } from '../package.json' import Customizations from './customizations' import { Advanced, BuiltIn, Guides, Resources } from './pages' import { getSidebarObject } from './sidebar-gen' export const slidebars: DefaultTheme.SidebarItem[] = [ { text: 'Guide', items: Guides, }, { text: 'Advanced', items: Advanced, }, { text: 'Customizations', items: Customizations, }, { text: 'Built-in', items: BuiltIn, }, { text: 'Resources', items: Resources, }, ] export default defineConfig({ title: 'Slidev', description: 'Presentation slides for developers', head: [ ['link', { rel: 'icon', type: 'image/png', href: '/favicon.png' }], ['meta', { name: 'author', content: 'Anthony Fu' }], ['meta', { property: 'og:title', content: 'Slidev' }], ['meta', { property: 'og:image', content: 'https://sli.dev/og-image.png' }], ['meta', { property: 'og:description', content: 'Presentation slides for developers' }], ['meta', { name: 'twitter:card', content: 'summary_large_image' }], ['meta', { name: 'twitter:creator', content: '@slidevjs' }], ['meta', { name: 'twitter:image', content: 'https://sli.dev/og-image.png' }], ['link', { rel: 'dns-prefetch', href: 'https://fonts.gstatic.com' }], ['link', { rel: 'preconnect', crossorigin: 'anonymous', href: 'https://fonts.gstatic.com' }], ['link', { href: 'https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@200;400;500&family=Inter:wght@200;400;500;600', rel: 'stylesheet' }], ], markdown: { theme: { light: 'vitesse-light', dark: 'vitesse-dark', }, async shikiSetup(shiki) { await shiki.loadLanguage( 'html', 'xml', 'vue', 'markdown', 'mermaid', 'latex', ) }, codeTransformers: [ transformerTwoslash({ twoslashOptions: { // The @slidev/* installed in docs package are very old and should only be used in the homepage demo vfsRoot: fileURLToPath(import.meta.url), compilerOptions: { resolveJsonModule: true, moduleResolution: /* Bundler */ 100, }, }, }), ], config(md) { md.use(groupIconMdPlugin) }, }, cleanUrls: true, themeConfig: { logo: '/logo.svg', editLink: { pattern: 'https://github.com/slidevjs/slidev/edit/main/docs/:path', text: 'Suggest changes to this page', }, search: { provider: 'local', }, nav: [ { text: '📖 Guide', items: [ ...Guides, { text: 'Advanced', items: Advanced, }, ], }, { text: '✨ Features', link: '/features/', }, { text: 'Reference', items: [ { text: 'Built-in', items: BuiltIn, }, { text: 'Customize', items: Customizations, }, ], }, { text: 'Resources', items: Resources, }, ], socialLinks: [ { icon: 'github', link: 'https://github.com/slidevjs/slidev' }, { icon: 'twitter', link: 'https://twitter.com/slidevjs' }, { icon: 'discord', link: 'https://chat.sli.dev' }, ], sidebar: { '/guide/': slidebars, '/themes/': slidebars, '/addons/': slidebars, '/custom/': slidebars, '/builtin/': slidebars, '/resources/': slidebars, // eslint-disable-next-line antfu/no-top-level-await ...await getSidebarObject(), '/features/': [], '/': slidebars, }, footer: { message: 'Released under the MIT License.', copyright: 'Copyright © 2020-2025 Anthony Fu.', }, }, locales: { root: { label: `English (v${version})`, }, zh: { label: '简体中文', link: 'https://cn.sli.dev/', }, ja: { label: '日本語', link: 'https://ja.sli.dev/', }, }, }) ================================================ FILE: docs/.vitepress/customizations.ts ================================================ export default [ { text: 'Configurations', link: '/custom/', }, { text: 'Directory Structure', link: '/custom/directory-structure', }, { text: 'Configure Highlighter', link: '/custom/config-highlighter', }, { text: 'Configure Vite and Plugins', link: '/custom/config-vite', }, { text: 'Configure Vue App', link: '/custom/config-vue', }, { text: 'Configure UnoCSS', link: '/custom/config-unocss', }, { text: 'Configure Code Runners', link: '/custom/config-code-runners', }, { text: 'Configure Transformers', link: '/custom/config-transformers', }, { text: 'Configure Monaco', link: '/custom/config-monaco', }, { text: 'Configure KaTeX', link: '/custom/config-katex', }, { text: 'Configure Mermaid', link: '/custom/config-mermaid', }, { text: 'Configure Mermaid Renderer', link: '/custom/config-mermaid-renderer', }, { text: 'Configure Routes', link: '/custom/config-routes', }, { text: 'Configure Shortcuts', link: '/custom/config-shortcuts', }, { text: 'Configure Context Menu', link: '/custom/config-context-menu', }, { text: 'Configure Fonts', link: '/custom/config-fonts', }, { text: 'Configure Pre-Parser', link: '/custom/config-parser', }, ] ================================================ FILE: docs/.vitepress/pages.ts ================================================ export const Guides = [ { text: 'Why Slidev', link: '/guide/why', }, { text: 'Getting Started', link: '/guide/', }, { text: 'Syntax Guide', link: '/guide/syntax', }, { text: 'User Interface', link: '/guide/ui', }, { text: 'Animations', link: '/guide/animations', }, { text: 'Theme & Addons', link: '/guide/theme-addon', }, { text: 'Components', link: '/guide/component', }, { text: 'Layouts', link: '/guide/layout', }, { text: 'Exporting', link: '/guide/exporting', }, { text: 'Hosting', link: '/guide/hosting', }, { text: 'Work with AI', link: '/guide/work-with-ai', }, { text: 'FAQ', link: '/guide/faq', }, ] export const BuiltIn = [ { text: 'CLI', link: '/builtin/cli', }, { text: 'Components', link: '/builtin/components', }, { text: 'Layouts', link: '/builtin/layouts', }, ] export const Advanced = [ { text: 'Global Context', link: '/guide/global-context', }, { text: 'Writing Layouts', link: '/guide/write-layout', }, { text: 'Writing Themes', link: '/guide/write-theme', }, { text: 'Writing Addons', link: '/guide/write-addon', }, ] export const Resources = [ { text: 'Showcases', link: '/resources/showcases', }, { text: 'Theme Gallery', link: '/resources/theme-gallery', }, { text: 'Addon Gallery', link: '/resources/addon-gallery', }, { text: 'Learning Resources', link: '/resources/learning', }, { text: 'Curated Covers', link: '/resources/covers', }, { text: 'Release Notes', link: 'https://github.com/slidevjs/slidev/releases', }, ] ================================================ FILE: docs/.vitepress/showcases.ts ================================================ export interface ShowCaseInfo { title: string cover: string slidesLink?: string sourceLink?: string videoLink?: string at?: string datetime: string author: { name: string link?: string } } export const showcases: ShowCaseInfo[] = [ { title: 'Composable Vue', cover: `${import.meta.env.BASE_URL}showcases/composable-vue.png`, author: { name: 'Anthony Fu', link: 'https://github.com/antfu', }, slidesLink: 'https://talks.antfu.me/2021/composable-vue/', sourceLink: 'https://github.com/antfu/talks/tree/main/2021-04-29', at: 'VueDay 2021', datetime: '2021-04-29', }, { title: 'Developer Seonglae', cover: 'https://seonglae-slides.vercel.app/og.png', author: { name: 'Seonglae Cho', link: 'https://github.com/seonglae', }, slidesLink: 'https://seonglae-slides.vercel.app', sourceLink: 'https://github.com/seonglae/seonglae-slides', at: 'Seongland', datetime: '2021-05-10', }, { title: 'Vue 3 > Vue 2 + 1', cover: 'https://user-images.githubusercontent.com/11247099/122246420-1df97b80-cef9-11eb-9c57-7751c6999deb.png', author: { name: 'Thorsten Lünborg', link: 'https://github.com/LinusBorg', }, slidesLink: 'http://vueday-2021.linusb.org', sourceLink: 'https://github.com/LinusBorg/vueday-enterjs-vue3', at: 'Enter.js Vue Day', datetime: '2021-06-15', }, // { // title: 'Simply Publish Your Package to npm', // author: { // name: 'Lucky Dewa Satria', // link: 'https://github.com/lucky401', // }, // at: 'Weekly sharing', // slidesLink: 'https://masukin.link/talks/simply-publish-your-package-to-npm', // cover: 'https://masukin.link/talks-cover-npm.png', // datetime: '2021-06-12', // }, // { // title: 'Create Icon Package With Vue and Rollup', // author: { // name: 'Lucky Dewa Satria', // link: 'https://github.com/lucky401', // }, // at: 'Weekly Sharing', // slidesLink: 'https://masukin.link/talks/create-icon-package-with-vue-and-rollup', // sourceLink: 'https://github.com/lucky401/Create-Icon-Package-With-Vue-and-Rollup', // cover: 'https://masukin.link/talks-cover-create-icon-package-with-vue-and-rollup.png', // datetime: '2021-06-19', // }, { title: 'BeAPT', author: { name: 'Daniel Sousa @TutoDS', link: 'https://github.com/tutods', }, at: 'Presentation of my college final project', slidesLink: 'https://beapt-presentation.netlify.app', sourceLink: 'https://github.com/TutoDS/lei-project/tree/master/presentation', cover: 'https://raw.githubusercontent.com/TutoDS/lei-project/master/presentation/cover.png', datetime: '2021-07-20', }, { title: 'Prisma as my ORM for PostgreSQL', cover: 'https://raw.githubusercontent.com/cedric25/prisma-talk/main/cover-for-slidev.png', author: { name: 'Cedric Nicoloso', link: 'https://github.com/cedric25', }, slidesLink: 'https://prisma-talk.netlify.app/', sourceLink: 'https://github.com/cedric25/prisma-talk', at: 'LyonJS Meetup', datetime: '2021-07-21', }, { title: 'Introduction to SVG', cover: 'https://raw.githubusercontent.com/lyqht/intro-to-svg-slides/main/intro-to-svg-slides-cover.png', author: { name: 'Estee Tey', link: 'https://github.com/lyqht', }, slidesLink: 'https://lyqht.github.io/intro-to-svg-slides/', sourceLink: 'https://github.com/lyqht/intro-to-svg-slides', at: 'Thoughtworks Internal Lunch & Learn', datetime: '2021-11-12', }, { title: 'Git\'s Most Wanted', cover: 'https://cdn.jsdelivr.net/gh/alexanderdavide/git-most-wanted@assets/slides-export/01.png', author: { name: 'Alexander Eble', link: 'https://github.com/alexanderdavide', }, slidesLink: 'https://alexeble.de/talks/git-most-wanted/', sourceLink: 'https://github.com/alexanderdavide/git-most-wanted', at: 'Internal Tech Talk', datetime: '2022-03-11', }, { title: 'OpenFunction 202', cover: 'https://s2.loli.net/2022/05/22/4zsCnkQRFoAU1E5.png', author: { name: 'Haili Zhang', link: 'https://github.com/webup', }, slidesLink: 'https://openfunction-talks.netlify.app/2022/202-node-async/', sourceLink: 'https://github.com/webup/openfunction-talks/tree/main/202-node-async', at: 'OpenFunction Tutorial Sharing', datetime: '2022-05-08', }, { title: 'Is it Okay to Pursue Functional Programming on Frontend?', author: { name: 'Minsu Kim , Changhui Lee', }, at: '2022 JSConf Korea', slidesLink: 'https://moonlit-nougat-422445.netlify.app/1', sourceLink: 'https://github.com/alstn2468/2022-jsconf-presentation', cover: 'https://raw.githubusercontent.com/alstn2468/2022-jsconf-presentation/main/public/images/og.png', datetime: '2022-09-16', }, { title: 'Blazing slidev ppt template with naive-ui', author: { name: 'godkun', }, at: 'personal sharing', slidesLink: 'https://ppt.godkun.top', sourceLink: 'https://github.com/godkun/ppt-template', cover: 'https://github.com/godkun/ppt-template/raw/main/public/show.gif', datetime: '2022-10-24', }, { title: 'Building a Polite Popup with Nuxt 3', author: { name: 'Michael Hoffmann', link: 'https://github.com/mokkapps', }, at: 'Vue.js Nation 2023', slidesLink: 'https://vuejsnation-2023-talk-polite-popup.netlify.app', sourceLink: 'https://github.com/Mokkapps/vuejsnation-2023-lightning-talk-polite-popup-nuxt-3-slides', cover: 'https://raw.githubusercontent.com/Mokkapps/vuejsnation-2023-lightning-talk-polite-popup-nuxt-3-slides/main/screenshots/001.png', datetime: '2023-01-25', }, { title: 'Dev Environment as Code', cover: 'https://cdn.jsdelivr.net/gh/alexanderdavide/dev-environment-as-code@assets/slides-export/001.png', author: { name: 'Alexander Eble', link: 'https://github.com/alexanderdavide', }, slidesLink: 'https://alexeble.de/talks/dev-environment-as-code/', sourceLink: 'https://github.com/alexanderdavide/dev-environment-as-code', at: 'Internal Tech Talk', datetime: '2022-12-01', }, { title: 'Exploring Social Engineering', cover: 'https://raw.githubusercontent.com/zyf722/exploring-social-engineering-slides/main/assets/Screenshot_Cover.png', author: { name: 'zyf722', link: 'https://github.com/zyf722', }, slidesLink: 'https://zyf722.github.io/exploring-social-engineering-slides/', sourceLink: 'https://github.com/zyf722/exploring-social-engineering-slides', at: 'Presentation on Social Engineering in Computers in Society class', datetime: '2023-10-20', }, { title: 'Diablo Health Orb Shader', author: { name: 'SuneBear', link: 'https://github.com/sunebear', }, at: 'rctAI Sessions', slidesLink: 'https://rct-ai.github.io/frontend-slides/diablo-health-orb-shader/', sourceLink: 'https://github.com/rct-ai/frontend-slides', cover: 'https://github-production-user-asset-6210df.s3.amazonaws.com/7693264/284304324-db973b4c-a043-4644-932c-826169a1b4d8.gif', datetime: '2022-09-01', }, { title: 'Comparison of Packaging Tools in 2023', author: { name: 'Peacock (Yoichi Takai)', link: 'https://p3ac0ck.net', }, at: 'PyCon APAC 2023', slidesLink: 'https://slides.p3ac0ck.net/pyconapac2023/1', sourceLink: 'https://github.com/peacock0803sz/slidev-slides/blob/7d41aa5e89ad8627cb68ae2cdbfe1681017b0408/talks/pyconapac2023/pyconapac2023.md', cover: 'https://slides.p3ac0ck.net/pyconapac2023/cover.png', datetime: '2023-10-28', }, { title: 'How Rust error handling ease web development', author: { name: 'Nguyễn Hồng Quân', link: 'https://quan.hoabinh.vn', }, at: 'FOSSASIA Summit 2024', slidesLink: 'https://talk.quan.hoabinh.vn/rust-error-handling-ease-web-dev/', sourceLink: 'https://hongquan@bitbucket.org/hongquan/rust-error-handling-ease-web-dev', cover: 'https://i.imgur.com/2eBJofY.png', datetime: '2024-04-10', }, { title: 'Sit Back and Relax with Fault Awareness and Robust Instant Recovery for Large Scale AI Workloads', author: { name: 'Neko', link: 'https://github.com/nekomeowww', }, at: 'KubeCon 2024 China', slidesLink: 'https://talks.ayaka.io/nekoayaka/2024-08-21-kubecon-hk/', sourceLink: 'https://github.com/nekomeowww/talks/tree/main/packages/2024-08-21-kubecon-hk', cover: 'https://raw.githubusercontent.com/BaizeAI/talks/main/packages/2024-08-21-kubecon-hk/public/screenshot.png', datetime: '2024-08-21', }, { title: 'Hacker Numerology', author: { name: 'HD Moore', link: 'https://hdm.io', }, at: 'LASCON 2024', slidesLink: 'https://hdm.io/decks/2024-LASCON-Numerology/', sourceLink: 'https://github.com/hdm/decks-2024-lascon-numerology.git', cover: 'https://raw.githubusercontent.com/hdm/decks-2024-lascon-numerology/refs/heads/main/screenshot.png', datetime: '2024-10-25', }, { title: 'Python Zero To Hero - Episode 1', author: { name: 'Kareim Tarek', link: 'https://kareimgazer.github.io/', }, at: 'Kareem Kreates YouTube Channel', slidesLink: 'https://kareimgazer.github.io/py-intro/', sourceLink: 'https://github.com/KareimGazer/py-intro', cover: 'https://i.ytimg.com/vi/hVMaPBrWvAo/hqdefault.jpg', datetime: '2025-01-12', }, { title: 'Taming Dependency Chaos for LLM in K8s', author: { name: 'Neko', link: 'https://github.com/nekomeowww', }, at: 'KubeCon 2025 China', slidesLink: 'https://baizeai.github.io/talks/2025-06-11-kubecon-hk/', sourceLink: 'https://github.com/BaizeAI/talks/tree/main/packages/2025-06-11-kubecon-hk', cover: 'https://raw.githubusercontent.com/BaizeAI/talks/main/packages/2025-06-11-kubecon-hk/public/screenshot.png', datetime: '2025-06-11', }, { title: 'Single Image Super-Resolution Based on Capsule Neural Networks', author: { name: 'George Corrêa de Araújo', link: 'https://george-gca.github.io/', }, at: 'Brazilian Conference on Intelligent Systems 2023', slidesLink: 'https://george-gca.github.io/bracis_2023_srcaps/', sourceLink: 'https://github.com/george-gca/bracis_2023_srcaps', cover: 'https://raw.githubusercontent.com/george-gca/bracis_2023_srcaps/refs/heads/main/cover.png', datetime: '2023-09-27', }, { title: 'Threat Modeling', author: { name: 'guisso', link: 'https://github.com/fguisso', }, at: 'OWASP Meetup', slidesLink: 'https://guisso.dev/talks/threat-modeling', sourceLink: 'https://github.com/fguisso/talks/tree/main/slides/threat-modeling', cover: 'https://guisso.dev/posts/threat-modeling-intro/featured-threat-modeling_hu12396ec5bf9ecba1dda33f1443a5eb10_76776_600x0_resize_box_3.png', datetime: '2023-09-22', }, { title: 'A 14-year journey developing nCine, an open-source 2D game framework', author: { name: 'Angelo Theodorou', link: 'https://encelo.github.io', }, at: '/dev/games/2025', slidesLink: 'https://encelo.github.io/nCine_14Years_Presentation/', sourceLink: 'https://github.com/encelo/nCine_14Years_Presentation', cover: 'https://i.imgur.com/AbTdfhg.png', datetime: '2025-06-05', }, { title: 'Reverse Engineering Denuvo in Hogwarts Legacy', author: { name: 'Maurice Heumann', link: 'https://momo5502.com', }, at: 'Navaja Negra 2025', slidesLink: 'https://momo5502.com/slides/denuvo', sourceLink: 'https://github.com/momo5502/denuvo-slides', cover: 'https://raw.githubusercontent.com/momo5502/denuvo-slides/refs/heads/master/images/preview.png', datetime: '2025-10-03', }, // Add yours here! { title: 'Yours?', author: { name: '', }, at: 'Submit your talk/presentation to be list here!', slidesLink: 'https://github.com/slidevjs/slidev/edit/main/docs/.vitepress/showcases.ts', cover: `${import.meta.env.BASE_URL}theme-placeholder.png`, datetime: '2020-1-1', }, ].sort((a, b) => new Date(b.datetime).getTime() - new Date(a.datetime).getTime()) ================================================ FILE: docs/.vitepress/sidebar-gen.ts ================================================ import type { DefaultTheme } from 'vitepress' import { join } from 'node:path' import { fileURLToPath } from 'node:url' import fg from 'fast-glob' import graymatter from 'gray-matter' const root = fileURLToPath(new URL('../../', import.meta.url)) interface ParsedFile { filepath: string path: string matter: graymatter.GrayMatterFile title: string } function parseFile(file: string) { const filepath = join(root, file) const path = file.replace('docs/', '').replace('.md', '') const matter = graymatter.read(filepath) const title = matter.data.title || matter.content.match(/^#\s+(.*)/m)?.[1] || path return { filepath, path, matter, title, } } export async function getSidebarObject() { const map: Record = {} const parsedFeatures: ParsedFile[] = await fg([ 'docs/features/*.md', ], { onlyFiles: true, cwd: root, }) .then(files => files.map(parseFile)) const parsedGuides: ParsedFile[] = await fg([ 'docs/guide/*.md', ], { onlyFiles: true, cwd: root, }) .then(files => files.map(parseFile)) const parsedCustoms: ParsedFile[] = await fg([ 'docs/custom/*.md', ], { onlyFiles: true, cwd: root, }) .then(files => files.map(parseFile)) parsedFeatures.forEach(({ matter, path }) => { const items: DefaultTheme.SidebarItem[] = [ { text: 'Back to', items: [ { text: 'All Features', link: '/features', }, ], }, ] function findParsed(related: string) { related = related.replace(/#.*$/, '') const feature = parsedFeatures.find(file => file.path === related) if (feature) { return { type: 'features', item: feature, } } const guide = parsedGuides.find(file => file.path === related) if (guide) { return { type: 'guide', item: guide, } } const custom = parsedCustoms.find(file => file.path === related) if (custom) { return { type: 'custom', item: custom, } } return undefined } function frontmatterToSidebarItem(path: string | Record): DefaultTheme.SidebarItem[] { if (typeof path === 'string') { const match = findParsed(path) if (match?.type === 'features') { return [{ text: `✨ ${match.item.title}`, link: `/${path}`, }] } if (match?.type === 'guide') { return [{ text: `📖 ${match.item.title}`, link: `/${path}`, }] } if (match?.type === 'custom') { return [{ text: `🛠️ ${match.item.title}`, link: `/${path}`, }] } console.warn(`Dependent file not found: ${path}`) return [{ text: path, link: `/${path}`, }] } else { return Object.entries(path).map(([text, link]) => ({ text, link, })) } } if (matter.data.depends) { items.push({ text: 'Depends on', items: matter.data.depends.flatMap(frontmatterToSidebarItem), }) } if (matter.data.relates) { items.push({ text: 'Related to', items: matter.data.relates.flatMap(frontmatterToSidebarItem), }) } const derives = matter.data.derives ?? parsedFeatures.filter(f => f.matter.data.depends?.includes(path)).map(f => f.path) if (derives.length) { items.push({ text: 'Derives', items: derives.flatMap(frontmatterToSidebarItem), }) } map[`/${path}`] = items }) return map } ================================================ FILE: docs/.vitepress/theme/components/AddonGallery.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/AddonInfo.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/Demo.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/DemoEditor.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/DemoSlide.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/Environment.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/FeatureTag.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/FeaturesAnimation.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/FeaturesAnimationInner.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/FeaturesOverview.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/LandingPage.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/Layout.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/LinkCard.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/LinkInline.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/SeeAlso.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/ShowCaseInfo.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/ShowCases.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/SlideContainer.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/TheTweet.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/ThemeGallery.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/ThemeInfo.vue ================================================ ================================================ FILE: docs/.vitepress/theme/composables/dark.ts ================================================ import { useDark } from '@vueuse/core' export const isDark = useDark() ================================================ FILE: docs/.vitepress/theme/index.ts ================================================ import type { EnhanceAppContext } from 'vitepress' import TwoSlash from '@shikijs/vitepress-twoslash/client' import Theme from 'vitepress/theme' import Layout from './components/Layout.vue' import '@shikijs/vitepress-twoslash/style.css' import './styles/vars.css' import './styles/demo.css' import './styles/custom.css' import 'uno.css' import 'virtual:group-icons.css' export default { extends: Theme, enhanceApp({ app }: EnhanceAppContext) { app.use(TwoSlash as any) }, Layout, } ================================================ FILE: docs/.vitepress/theme/styles/custom.css ================================================ .icon-btn { --uno: inline-block cursor-pointer select-none important-outline-none; --uno: opacity-75 transition duration-200 ease-in-out align-middle rounded p-2; --uno: hover-(opacity-100 bg-gray-400 bg-opacity-10); } .icon-btn.disabled { --uno: opacity-25 pointer-events-none; } .inline-icon-btn { --uno: text-primary-deep; --uno: inline-block rounded p-0.5 text-2xl align-middle; --uno: border border-primary border-opacity-20 border-solid; } kbd { --uno: border-rounded bg-$vp-c-gray-1 bg-opacity-10 px-1 py-.5; } [data-tweet-id] { border-radius: 13px; } ================================================ FILE: docs/.vitepress/theme/styles/demo.css ================================================ html:not(.dark) { --prism-foreground: #393a34; --prism-background: #fafafa; --prism-inline-background: #f5f5f5; --prism-comment: #a0ada0; --prism-string: #b56959; --prism-literal: #2f8a89; --prism-number: #296aa3; --prism-keyword: #1c6b48; --prism-function: #6c7834; --prism-boolean: #296aa3; --prism-constant: #a65e2b; --prism-deleted: #a14f55; --prism-class: #2993a3; --prism-builtin: #ab5959; --prism-property: #b58451; --prism-namespace: #b05a78; --prism-punctuation: #8e8f8b; --prism-decorator: #bd8f8f; --prism-regex: #ab5e3f; --prism-json-property: #698c96; } html.dark { --prism-scheme: dark; --prism-foreground: #d4cfbf; --prism-background: #181818; --prism-comment: #758575; --prism-string: #d48372; --prism-literal: #429988; --prism-keyword: #4d9375; --prism-boolean: #6394bf; --prism-number: #6394bf; --prism-variable: #c2b36e; --prism-function: #a1b567; --prism-deleted: #bc6066; --prism-class: #54b1bf; --prism-builtin: #e0a569; --prism-property: #dd8e6e; --prism-namespace: #db889a; --prism-punctuation: #858585; --prism-decorator: #bd8f8f; --prism-regex: #ab5e3f; --prism-json-property: #6b8b9e; --prism-line-number: #888888; --prism-line-number-gutter: #eeeeee; --prism-line-highlight-background: #444444; --prism-selection-background: #444444; --prism-inline-background: theme('colors.dark.300'); } .token.title { color: var(--prism-keyword); } .token.comment, .token.prolog, .token.doctype, .token.cdata { color: var(--prism-comment); font-style: var(--prism-comment-style); } .token.namespace { color: var(--prism-namespace); } .token.interpolation { color: var(--prism-interpolation); } .token.string { color: var(--prism-string); } .token.punctuation { color: var(--prism-punctuation); } .token.operator { color: var(--prism-operator); } .token.keyword.module, .token.keyword.control-flow { color: var(--prism-keyword-control); } .token.url, .token.symbol, .token.inserted { color: var(--prism-symbol); } .token.constant { color: var(--prism-constant); } .token.string.url { text-decoration: var(--prism-url-decoration); } .token.boolean, .language-json .token.boolean { color: var(--prism-boolean); } .token.number, .language-json .token.number { color: var(--prism-number); } .token.variable { color: var(--prism-variable); } .token.keyword { color: var(--prism-keyword); } .token.atrule, .token.attr-value, .token.selector { color: var(--prism-selector); } .token.function { color: var(--prism-function); } .token.deleted { color: var(--prism-deleted); } .token.important, .token.bold { font-weight: bold; } .token.italic { font-style: italic; } .token.class-name { color: var(--prism-class); } .token.tag, .token.builtin { color: var(--prism-builtin); } .token.attr-name, .token.property, .token.entity { color: var(--prism-property); } .language-json .token.property { color: var(--prism-json-property); } .token.regex { color: var(--prism-regex); } .token.decorator, .token.annotation { color: var(--prism-decorator); } ================================================ FILE: docs/.vitepress/theme/styles/vars.css ================================================ /** * Customize default theme styling by overriding CSS variables: * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css */ /** * Colors * * Each colors have exact same color scale system with 3 levels of solid * colors with different brightness, and 1 soft color. * * - `XXX-1`: The most solid color used mainly for colored text. It must * satisfy the contrast ratio against when used on top of `XXX-soft`. * * - `XXX-2`: The color used mainly for hover state of the button. * * - `XXX-3`: The color for solid background, such as bg color of the button. * It must satisfy the contrast ratio with pure white (#ffffff) text on * top of it. * * - `XXX-soft`: The color used for subtle background such as custom container * or badges. It must satisfy the contrast ratio when putting `XXX-1` colors * on top of it. * * The soft color must be semi transparent alpha channel. This is crucial * because it allows adding multiple "soft" colors on top of each other * to create a accent, such as when having inline code block inside * custom containers. * * - `default`: The color used purely for subtle indication without any * special meanings attched to it such as bg color for menu hover state. * * - `brand`: Used for primary brand colors, such as link text, button with * brand theme, etc. * * - `tip`: Used to indicate useful information. The default theme uses the * brand color for this by default. * * - `warning`: Used to indicate warning to the users. Used in custom * container, badges, etc. * * - `danger`: Used to show error, or dangerous message to the users. Used * in custom container, badges, etc. * -------------------------------------------------------------------------- */ :root { --vp-c-brand-1: #3ab9d4; --vp-c-brand-2: #60c4db; --vp-c-brand-3: #6fcce1; --vp-c-brand-soft: #3ab9d450; --vp-c-bg-alt: #f9f9f9; --vp-font-family-mono: theme('fontFamily.mono'); } .dark { --vp-c-brand-1: #6fcce1; --vp-c-brand-2: #60c4db; --vp-c-brand-3: #3ab9d4; --vp-c-brand-soft: #3ab9d450; --vp-c-bg-alt: #18181b; --vp-c-gutter: #8883; } :root { --vp-c-default-1: var(--vp-c-gray-1); --vp-c-default-2: var(--vp-c-gray-2); --vp-c-default-3: var(--vp-c-gray-3); --vp-c-default-soft: var(--vp-c-gray-soft); --vp-c-tip-1: var(--vp-c-brand-1); --vp-c-tip-2: var(--vp-c-brand-2); --vp-c-tip-3: var(--vp-c-brand-3); --vp-c-tip-soft: var(--vp-c-brand-soft); } :root { -vp-c-text-1: rgba(42, 40, 47); -vp-c-text-2: rgba(42, 40, 47, 0.78); -vp-c-text-3: rgba(42, 40, 47, 0.56); --black-text-1: rgba(42, 40, 47); } .dark { --vp-c-text-1: rgba(255, 255, 245, 0.86); --vp-c-text-2: rgba(235, 235, 245, 0.6); --vp-c-text-3: rgba(235, 235, 245, 0.38); } /** * Component: Button * -------------------------------------------------------------------------- */ :root { --vp-button-brand-border: transparent; --vp-button-brand-text: var(--vp-c-white); --vp-button-brand-bg: var(--vp-c-brand-1); --vp-button-brand-hover-border: transparent; --vp-button-brand-hover-text: var(--vp-c-white); --vp-button-brand-hover-bg: var(--vp-c-brand-2); --vp-button-brand-active-border: transparent; --vp-button-brand-active-text: var(--vp-c-white); --vp-button-brand-active-bg: var(--vp-c-brand-1); } .dark { --vp-button-brand-text: var(--black-text-1); --vp-button-brand-bg: var(--vp-c-brand-2); --vp-button-brand-hover-text: var(--black-text-1); --vp-button-brand-hover-bg: var(--vp-c-brand-1); --vp-button-brand-active-text: var(--black-text-1); --vp-button-brand-active-bg: var(--vp-c-brand-3); } /** * Component: Home * -------------------------------------------------------------------------- */ :root { --vp-home-hero-name-color: var(--vp-c-brand-1); } @media (min-width: 640px) { :root { --vp-home-hero-image-filter: blur(56px); } } @media (min-width: 960px) { :root { --vp-home-hero-image-filter: blur(72px); } } /** * Component: Custom Block * -------------------------------------------------------------------------- */ :root { --vp-custom-block-tip-border: transparent; --vp-custom-block-tip-text: var(--vp-c-text-1); --vp-custom-block-tip-bg: var(--vp-c-brand-soft); --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft); } /** * Component: Algolia * -------------------------------------------------------------------------- */ .DocSearch { --docsearch-primary-color: var(--vp-c-brand-1) !important; } ================================================ FILE: docs/.vitepress/themes.ts ================================================ export interface ThemeInfo { id: string name: string description: string previews: string[] repo?: string author: { name: string link?: string } link?: string tags?: string[] } export const official: ThemeInfo[] = [ { id: '@slidev/theme-default', name: 'Default', description: 'The minimalism default theme for Slidev', author: { name: 'Anthony Fu', link: 'https://github.com/antfu', }, repo: 'https://github.com/slidevjs/themes/tree/main/packages/theme-default', previews: [ 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-default/01.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-default/02.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-default/06.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-default/08.png', ], tags: [ 'official', 'minimalism', 'dark', 'light', ], }, { id: '@slidev/theme-seriph', name: 'Seriph', description: 'A more formal looking theme using Serif fonts', author: { name: 'Anthony Fu', link: 'https://github.com/antfu', }, repo: 'https://github.com/slidevjs/themes/tree/main/packages/theme-seriph', previews: [ 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-seriph/01.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-seriph/02.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-seriph/03.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-seriph/08.png', ], tags: [ 'official', 'minimalism', 'dark', 'light', ], }, { id: '@slidev/theme-apple-basic', name: 'Apple Basic', description: 'Inspired by the Basic Black/White theme from Apple Keynote', author: { name: 'Jeremy Meissner', link: 'https://github.com/JeremyMeissner', }, repo: 'https://github.com/slidevjs/themes/tree/main/packages/theme-apple-basic', previews: [ 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-apple-basic/01.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-apple-basic/02.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-apple-basic/03.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-apple-basic/09.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-apple-basic/11.png', ], tags: [ 'minimalism', 'dark', 'light', ], }, { id: '@slidev/theme-bricks', name: 'Bricks', description: 'Building bricks', author: { name: 'iiiiiiinès', link: 'https://github.com/iiiiiiines', }, repo: 'https://github.com/slidevjs/themes/tree/main/packages/theme-bricks', previews: [ 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-bricks/01.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-bricks/04.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-bricks/06.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-bricks/05.png', ], tags: [ 'light', ], }, { id: '@slidev/theme-shibainu', name: 'Shibainu', description: 'Meow!', author: { name: 'iiiiiiinès', link: 'https://github.com/iiiiiiines', }, repo: 'https://github.com/slidevjs/themes/tree/main/packages/theme-shibainu', previews: [ 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-shibainu/01.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-shibainu/03.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-shibainu/04.png', 'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-shibainu/09.png', ], tags: [ 'dark', ], }, ] export const community: ThemeInfo[] = [ { id: 'slidev-theme-geist', name: 'Vercel', description: 'A theme based on Vercel\'s design system.', author: { name: 'Nico Bachner', link: 'https://github.com/nico-bachner', }, repo: 'https://github.com/nico-bachner/slidev-theme-geist', previews: [ 'https://cdn.jsdelivr.net/gh/nico-bachner/slidev-theme-geist@main/example-export/01.png', 'https://cdn.jsdelivr.net/gh/nico-bachner/slidev-theme-geist@main/example-export/02.png', 'https://cdn.jsdelivr.net/gh/nico-bachner/slidev-theme-geist@main/example-export/03.png', 'https://cdn.jsdelivr.net/gh/nico-bachner/slidev-theme-geist@main/example-export/04.png', 'https://cdn.jsdelivr.net/gh/nico-bachner/slidev-theme-geist@main/example-export/05.png', ], tags: [ 'dark', 'light', ], }, { id: 'slidev-theme-light-icons', name: 'Light Icons', description: 'A simple, light and elegant theme for Slidev, combined together with creative layouts, custom components & fonts', author: { name: 'Pulkit Aggarwal', link: 'https://github.com/BashCloud', }, repo: 'https://github.com/lightvue/slidev-theme-light-icons', previews: [ 'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/1-layout-intro.png', 'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/2-layout-image-header-intro-light.png', 'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/3-layout-dynamic-image-light.png', 'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/5-layout-dynamic-image-light.png', 'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/7-layout-dynamic-image-light.png', 'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/8-layout-center-image-light.png', 'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/9-layout-dynamic-image-light.png', 'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/10-layout-left-image-light.png', ], tags: [ 'dark', 'light', ], }, { id: 'slidev-theme-eloc', name: 'Eloc', description: 'Focus on writing, present in a concise style.', author: { name: 'Amio', link: 'https://github.com/amio', }, repo: 'https://github.com/zthxxx/slides/tree/master/packages/slidev-theme-eloc', previews: [ 'https://cdn.jsdelivr.net/gh/zthxxx/slides@master/packages/slidev-theme-eloc/screenshot/01.png', 'https://cdn.jsdelivr.net/gh/zthxxx/slides@master/packages/slidev-theme-eloc/screenshot/02.png', 'https://cdn.jsdelivr.net/gh/zthxxx/slides@master/packages/slidev-theme-eloc/screenshot/03.png', 'https://cdn.jsdelivr.net/gh/zthxxx/slides@master/packages/slidev-theme-eloc/screenshot/04.png', 'https://cdn.jsdelivr.net/gh/zthxxx/slides@master/packages/slidev-theme-eloc/screenshot/05.png', ], tags: [ 'dark', 'light', ], }, { id: 'slidev-theme-purplin', name: 'Purplin', description: 'Theme with bar bottom component. Based on purple color', author: { name: 'Mauricio Martínez', link: 'https://github.com/moudev', }, repo: 'https://github.com/moudev/slidev-theme-purplin', previews: [ 'https://i.imgur.com/BX3TpEc.png', 'https://i.imgur.com/mqqRi1F.png', 'https://i.imgur.com/fwm2785.png', 'https://i.imgur.com/m8eemKt.png', ], tags: [ 'dark', 'light', ], }, { id: 'slidev-theme-unicorn', name: 'Unicorn', description: 'Based on Dawntraoz website design', author: { name: 'Alba Silvente', link: 'https://github.com/dawntraoz', }, repo: 'https://github.com/dawntraoz/slidev-theme-unicorn', previews: [ 'https://cdn.jsdelivr.net/gh/Dawntraoz/slidev-theme-unicorn@master/screenshots/dark-theme-intro.png', 'https://cdn.jsdelivr.net/gh/Dawntraoz/slidev-theme-unicorn@master/screenshots/light-theme-cover.png', 'https://cdn.jsdelivr.net/gh/Dawntraoz/slidev-theme-unicorn@master/screenshots/dark-theme-image-centered.png', 'https://cdn.jsdelivr.net/gh/Dawntraoz/slidev-theme-unicorn@master/screenshots/dark-theme-center-without-header-footer.png', ], tags: [ 'dark', 'light', ], }, { id: 'slidev-theme-zhozhoba', name: 'Zhozhoba', description: 'A zhozhoba theme for Slidev', author: { name: 'Bogenbai Bayzharassov', link: 'https://github.com/thatoranzhevyy', }, repo: 'https://github.com/thatoranzhevyy/slidev-theme-zhozhoba', previews: [ 'https://cdn.jsdelivr.net/gh/thatoranzhevyy/slidev-theme-zhozhoba@master/slides-export/01.png', 'https://cdn.jsdelivr.net/gh/thatoranzhevyy/slidev-theme-zhozhoba@master/.github/dark.png', 'https://cdn.jsdelivr.net/gh/thatoranzhevyy/slidev-theme-zhozhoba@master/slides-export/02.png', 'https://cdn.jsdelivr.net/gh/thatoranzhevyy/slidev-theme-zhozhoba@master/slides-export/03.png', 'https://cdn.jsdelivr.net/gh/thatoranzhevyy/slidev-theme-zhozhoba@master/slides-export/04.png', ], tags: [ 'dark', 'light', ], }, { id: 'slidev-theme-penguin', name: 'Penguin', description: 'A Penguin theme for Slidev', author: { name: 'Alvaro Saburido', link: 'https://github.com/alvarosabu', }, repo: 'https://github.com/alvarosabu/slidev-theme-penguin', previews: [ 'https://cdn.jsdelivr.net/gh/alvarosaburido/slidev-theme-penguin@master/screenshots/dark/01.png', 'https://cdn.jsdelivr.net/gh/alvarosaburido/slidev-theme-penguin@master/screenshots/light/02.png', 'https://cdn.jsdelivr.net/gh/alvarosaburido/slidev-theme-penguin@master/screenshots/light/06.png', 'https://cdn.jsdelivr.net/gh/alvarosaburido/slidev-theme-penguin@master/screenshots/light/05.png', ], tags: [ 'dark', 'light', ], }, { id: 'slidev-theme-vuetiful', name: 'Vuetiful', description: 'A Vue-inspired theme for Slidev', author: { name: 'Thorsten Lünborg', link: 'https://github.com/LinusBorg', }, repo: 'https://github.com/LinusBorg/slidev-theme-vuetiful', previews: [ 'https://cdn.jsdelivr.net/gh/LinusBorg/slidev-theme-vuetiful@main/screenshots/cover-alt.png', 'https://cdn.jsdelivr.net/gh/LinusBorg/slidev-theme-vuetiful@main/screenshots/section.png', 'https://cdn.jsdelivr.net/gh/LinusBorg/slidev-theme-vuetiful@main/screenshots/big-points.png', 'https://cdn.jsdelivr.net/gh/LinusBorg/slidev-theme-vuetiful@main/screenshots/quote.png', ], tags: [ 'dark', 'light', ], }, { id: 'slidev-theme-takahashi', name: 'Takahashi', description: 'A simple theme for Slidev', author: { name: 'Percy M.', link: 'https://github.com/kecrily', }, repo: 'https://github.com/kecrily/slidev-theme-takahashi', previews: [ 'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/01.png', 'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/02.png', 'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/03.png', 'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/04.png', 'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/05.png', 'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/06.png', 'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/07.png', ], tags: [ 'light', ], }, { id: 'slidev-theme-academic', name: 'Academic', description: 'Academic presentations with Slidev made simple', author: { name: 'Alexander Eble', link: 'https://github.com/alexanderdavide', }, repo: 'https://github.com/alexanderdavide/slidev-theme-academic', previews: [ 'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/01.png', 'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/02.png', 'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/08.png', 'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/04.png', 'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/05.png', 'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/06.png', 'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/07.png', ], tags: [ 'dark', 'light', ], }, { id: 'slidev-theme-mokkapps', name: 'Mokkapps', description: 'A theme for my personal brand "Mokkapps"', author: { name: 'Michael Hoffmann', link: 'https://github.com/mokkapps', }, repo: 'https://github.com/mokkapps/slidev-theme-mokkapps', previews: [ 'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/001.png', 'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/002.png', 'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/003.png', 'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/004.png', 'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/005.png', 'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/006.png', 'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/007.png', 'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/008.png', 'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/009.png', 'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/010.png', 'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/011.png', ], tags: [ 'dark', 'light', ], }, { id: 'slidev-theme-the-unnamed', name: 'The unnamed', description: 'A theme based on The unnamed VS Code theme', author: { name: 'Elio Struyf', link: 'https://elio.dev', }, repo: 'https://github.com/estruyf/slidev-theme-the-unnamed', previews: [ 'https://cdn.jsdelivr.net/gh/estruyf/slidev-theme-the-unnamed@main/assets/cover.png', 'https://cdn.jsdelivr.net/gh/estruyf/slidev-theme-the-unnamed@main/assets/about-me.png', 'https://cdn.jsdelivr.net/gh/estruyf/slidev-theme-the-unnamed@main/assets/default.png', 'https://cdn.jsdelivr.net/gh/estruyf/slidev-theme-the-unnamed@main/assets/section.png', ], tags: [ 'dark', ], }, { id: 'slidev-theme-dracula', name: 'Dracula', description: 'One the best dark theme meets slidev', author: { name: 'JD Solanki', link: 'https://github.com/jd-solanki', }, repo: 'https://github.com/jd-solanki/slidev-theme-dracula', previews: [ 'https://cdn.jsdelivr.net/gh/jd-solanki/slidev-theme-dracula/screenshots/screenshot-1.png', 'https://cdn.jsdelivr.net/gh/jd-solanki/slidev-theme-dracula/screenshots/screenshot-2.png', 'https://cdn.jsdelivr.net/gh/jd-solanki/slidev-theme-dracula/screenshots/screenshot-3.png', 'https://cdn.jsdelivr.net/gh/jd-solanki/slidev-theme-dracula/screenshots/screenshot-4.png', 'https://cdn.jsdelivr.net/gh/jd-solanki/slidev-theme-dracula/screenshots/screenshot-5.png', ], tags: [ 'dark', 'minimalism', ], }, { id: 'slidev-theme-frankfurt', name: 'Frankfurt', description: 'Inspired by the Beamer theme Frankfurt', author: { name: 'Mu-Tsun Tsai', link: 'https://github.com/MuTsunTsai', }, repo: 'https://github.com/MuTsunTsai/slidev-theme-frankfurt', previews: [ 'https://cdn.jsdelivr.net/gh/MuTsunTsai/slidev-theme-frankfurt/screenshots/01.png', 'https://cdn.jsdelivr.net/gh/MuTsunTsai/slidev-theme-frankfurt/screenshots/04.png', 'https://cdn.jsdelivr.net/gh/MuTsunTsai/slidev-theme-frankfurt/screenshots/06.png', 'https://cdn.jsdelivr.net/gh/MuTsunTsai/slidev-theme-frankfurt/screenshots/07.png', ], tags: [ 'dark', 'light', ], }, { id: 'slidev-theme-hep', name: 'HEP', description: 'Academic style for High Energy Physics', author: { name: 'Yulei ZHANG', link: 'https://github.com/AvencastF', }, repo: 'https://github.com/AvencastF/slidev-theme-hep', previews: [ 'https://cdn.jsdelivr.net/gh/avencastf/slidev-theme-hep/screenshot/001.png', 'https://cdn.jsdelivr.net/gh/avencastf/slidev-theme-hep/screenshot/004.png', 'https://cdn.jsdelivr.net/gh/avencastf/slidev-theme-hep/screenshot/006.png', 'https://cdn.jsdelivr.net/gh/avencastf/slidev-theme-hep/screenshot/008.png', ], tags: [ 'light', ], }, { id: 'slidev-theme-excali-slide', name: 'Excali-slide', description: 'A theme based on Excalidraw with animated highlighter effect', author: { name: 'Filip Hric', link: 'https://github.com/filiphric', }, repo: 'https://github.com/filiphric/slidev-theme-excali-slide', previews: [ 'https://raw.githubusercontent.com/filiphric/excali-slide/main/images/default_slide.png', 'https://raw.githubusercontent.com/filiphric/excali-slide/main/images/intro_slide.png', ], tags: [ 'dark', 'light', ], }, { id: 'slidev-theme-mint', name: 'mint', description: 'Slidev Theme Mint', author: { name: 'Alfatta Rezqa', link: 'https://github.com/alfatta', }, repo: 'https://github.com/alfatta/slidev-theme-mint', previews: [ 'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/1.png', 'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/2.png', 'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/3.png', 'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/4.png', 'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/5.png', 'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/6.png', 'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/7.png', 'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/8.png', 'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/9.png', ], tags: [ 'light', 'mint', 'green', 'cool', ], }, { id: 'slidev-theme-neversink', name: 'neversink', description: 'Slidev Theme Neversink', author: { name: 'Todd M. Gureckis', link: 'https://github.com/gureckis', }, repo: 'https://github.com/gureckis/slidev-theme-neversink', previews: [ 'https://gureckis.github.io/slidev-theme-neversink/screenshots/2.png', 'https://gureckis.github.io/slidev-theme-neversink/screenshots/6.png', 'https://gureckis.github.io/slidev-theme-neversink/screenshots/8.png', 'https://gureckis.github.io/slidev-theme-neversink/screenshots/15.png', 'https://gureckis.github.io/slidev-theme-neversink/screenshots/18.png', 'https://gureckis.github.io/slidev-theme-neversink/screenshots/22.png', 'https://gureckis.github.io/slidev-theme-neversink/screenshots/26.png', 'https://gureckis.github.io/slidev-theme-neversink/screenshots/34.png', 'https://gureckis.github.io/slidev-theme-neversink/screenshots/36.png', 'https://gureckis.github.io/slidev-theme-neversink/screenshots/38.png', 'https://gureckis.github.io/slidev-theme-neversink/screenshots/35.png', ], tags: [ 'light', 'academic', 'education', ], }, { id: 'slidev-theme-ktym4a', name: 'ktym4a', description: 'Based on ktym4a website design', author: { name: 'ktym4a', link: 'https://github.com/ktym4a', }, repo: 'https://github.com/ktym4a/slidev-theme-ktym4a', previews: [ 'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/rotation/0.png', 'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/rotation/1.png', 'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/rotation/6.png', 'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/rotation/7.png', 'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/rotation/8.png', 'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/single/0.png', 'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/single/1.png', 'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/single/3.png', 'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/single/4.png', ], tags: [ 'dark', 'catppuccin', ], }, { id: 'slidev-theme-nord', name: 'Nord', description: 'Based on the Nord theme', author: { name: 'David Ollerhead', link: 'https://github.com/oller', }, repo: 'https://github.com/oller/slidev-theme-nord', previews: [ 'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/1.png', 'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/2.png', 'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/3.png', 'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/4.png', 'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/5.png', 'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/6.png', 'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/7.png', ], tags: [ 'dark', 'light', 'nord', ], }, { id: 'slidev-theme-scholarly', name: 'Scholarly', description: 'Based on the Nord theme', author: { name: 'Jiaxin Peng', link: 'https://github.com/jxpeng98', }, repo: 'https://github.com/jxpeng98/slidev-theme-scholarly', previews: [ 'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/classic-blue/1.png', 'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/oxford/1.png', 'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/cambridge/1.png', 'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/princeton/1.png', 'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/classic-blue/2.png', 'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/classic-blue/3.png', 'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/classic-blue/4.png', ], tags: [ 'dark', 'light', 'academic', 'oxford', 'cambridge', 'princeton', ], }, { id: 'slidev-theme-field-manual', name: 'Field Manual', description: 'A 24-layout theme modeled on the style of vintage military field manuals', author: { name: 'PJ Doland', link: 'https://github.com/pjdoland', }, repo: 'https://github.com/pjdoland/slidev-theme-field-manual', previews: [ 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/1.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/2.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/3.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/4.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/5.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/6.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/7.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/8.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/9.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/10.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/11.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/12.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/13.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/14.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/15.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/16.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/17.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/18.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/19.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/20.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/21.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/22.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/23.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/24.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/25.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/26.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/27.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/28.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/29.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/30.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/31.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/32.jpg', 'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/33.jpg', ], tags: [ 'light', 'dark', 'vintage', 'military', ], }, // Add yours here! { id: '', link: 'https://github.com/slidevjs/slidev/edit/main/docs/.vitepress/themes.ts', name: 'Yours?', description: 'Click here to submit your theme :)', author: { name: '', }, previews: [ '/theme-placeholder.png', ], }, ] ================================================ FILE: docs/.vitepress/utils.ts ================================================ import { data as features } from '../features/index.data.js' import { Advanced, Guides } from './pages' function removeHash(link: string) { const idx = link.lastIndexOf('#') return idx < 0 ? link : link.slice(0, idx) } function getGuideTitle(id: string) { return Guides.find(g => g.link.endsWith(`/${id}`))?.text ?? Advanced.find(g => g.link.endsWith(id))?.text ?? id } export function resolveLink(link: string): { kind: 'external' | 'features' | 'guide' url: string title?: string tags?: string[] descripton?: string } { const [kind, nameWithHash] = link.split('/') const name = removeHash(nameWithHash) switch (kind) { case 'http:': case 'https:': case 'mailto:': return { kind: 'external', url: link } case 'features': { const feature = features[name] if (!feature) throw new Error(`Feature "${name}" not found.`) return { kind: 'features', title: `✨ ${feature.title}`, tags: feature.tags, descripton: feature.description, url: `/features/${nameWithHash}`, } } case 'guide': { return { kind: 'guide', title: `📖 ${getGuideTitle(name)}`, tags: ['guide'], descripton: 'Click to read this guide', url: `/guide/${nameWithHash}`, } } default: throw new Error(`Invalid link: ${link}`) } } ================================================ FILE: docs/README.md ================================================ # [sli.dev](https://sli.dev) Documentation for [Slidev](https://github.com/slidevjs/slidev) ## Translations > [!WARNING] > > Translations with strikethroughs are no longer maintained. The content is outdated and not encouraged to refer. | | Repo | Site | Maintainers | | ------------------------- | ---------------------------------------------- | -------------------------------: | --------------------------------------------------------------------- | | English | [docs](https://github.com/slidevjs/docs) | [sli.dev](https://sli.dev) | [@antfu](https://github.com/antfu) | | 简体中文 | [docs-cn](https://github.com/slidevjs/docs-cn) | [cn.sli.dev](https://cn.sli.dev) | [@QC-L](https://github.com/QC-L) [@Ivocin](https://github.com/Ivocin) | | Français | [docs-fr](https://github.com/slidevjs/docs-fr) | [fr.sli.dev](https://fr.sli.dev) | [@ArthurDanjou](https://github.com/ArthurDanjou) | | Español | [docs-es](https://github.com/slidevjs/docs-es) | [es.sli.dev](https://es.sli.dev) | [@owlnai](https://github.com/owlnai) | | Русский | [docs-ru](https://github.com/slidevjs/docs-ru) | [ru.sli.dev](https://ru.sli.dev) | [@xesjkeee](https://github.com/xesjkeee) | | Việt Nam | [docs-vn](https://github.com/slidevjs/docs-vn) | [vn.sli.dev](https://vn.sli.dev) | [@bongudth](https://github.com/bongudth) | | Deutsch | [docs-de](https://github.com/slidevjs/docs-de) | [de.sli.dev](https://de.sli.dev) | [@fabiankachlock](https://github.com/fabiankachlock) | | Português (BR) | [docs-br](https://github.com/slidevjs/docs-br) | [br.sli.dev](https://br.sli.dev) | [@luisfelipesdn12](https://github.com/luisfelipesdn12) | | Ελληνικά | [docs-el](https://github.com/slidevjs/docs-el) | [el.sli.dev](https://el.sli.dev) | [@GeopJr](https://github.com/GeopJr) | | 日本語 | [docs-ja](https://github.com/slidevjs/docs-ja) | [ja.sli.dev](https://ja.sli.dev) | [@IkumaTadokoro](https://github.com/IkumaTadokoro) | ## Start Server Locally ``` npm i -g pnpm pnpm i pnpm run dev ``` And then visit `http://localhost:3000` Or install the [Vite extension for VS Code](https://marketplace.visualstudio.com/items?itemName=antfu.vite) to edit side-by-side. ## Help on Translating Please join our [Discord Server](https://chat.sli.dev) and contact the maintainers. ================================================ FILE: docs/builtin/cli.md ================================================ # Slidev CLI `@slidev/cli` exposes a binary called `slidev` that you can use to develop, build, and export your slides. ## Prerequisites To use the CLI, you can either install `@slidev/cli` globally or install it locally in your Node.js project. If you created your project with `npm init slidev`, the CLI is already installed locally. ::: warning Usually `npx slidev` is not supported because the package name is actually `@slidev/cli`. ::: The CLI options of the commands obey the following conventions: - the value of the option can be passed after a space or a `=` character: Example: `slidev --port 8080` is equivalent to `slidev --port=8080` - `true` can be omitted for boolean options: Example: `slidev --open` is equivalent to `slidev --open true` ::: info If you use npm, please don't forget to add `--` before the options to pass them to Slidev: ```bash npm run slidev -- --remote --port 8080 --open ``` ::: ## `slidev [entry]` {#dev} Start a local server for Slidev. - `[entry]` (`string`, default: `slides.md`): path to the markdown file containing your slides. Options: - `--port`, `-p` (`number`, default: `3030`): port number. - `--base` (`string`, default: `/`): base URL (see https://vitejs.dev/config/shared-options.html#base). - `--open`, `-o` (`boolean`, default: `false`): open in the browser. - `--remote [password]` (`string`): listen to the public host and enable remote control, if a value is passed then the presenter mode is private and only accessible by passing the given password in the URL query `password` parameter. - `--bind` (`string`, default: `0.0.0.0`): specify which IP addresses the server should listen on in the remote mode. - `--log` (`'error', 'warn', 'info', 'silent'`, default: `'warn'`): Log level. - `--force`, `-f` (`boolean`, default: `false`): force the optimizer to ignore the cache and re-bundle. - `--theme`, `-t` (`string`): override theme. ## `slidev build [entry]` {#build} Build a hostable SPA. See for more details. - `[entry]` (`string`, default: `slides.md`): path to the slides markdown file. Options: - `--out`, `-o` (`string`, default: `dist`): output directory - `--base` (`string`, default: `/`): base URL (see https://vitejs.dev/config/shared-options.html#base) - `--download` (`boolean`, default: `false`): allow the download of the slides as a PDF inside the SPA - `--theme`, `-t` (`string`): override theme - `--without-notes` (`boolean`, default: `false`): exclude speaker notes from the SPA ## `slidev export [...entry]` {#export} Export slides to PDF (or other format). See for more details. - `[entry]` (`string`, default: `slides.md`): path to the slides markdown entry. Options: - `--output` (`string`, default: use `exportFilename` (see https://sli.dev/custom/#frontmatter-configures) or use `[entry]-export`): path to the output. - `--format` (`'pdf', 'png', 'pptx', 'md'`, default: `'pdf'`): output format. - `--timeout` (`number`, default: `30000`): timeout for rendering the print page (see https://playwright.dev/docs/api/class-page#page-goto). - `--range` (`string`): page ranges to export (example: `'1,4-5,6'`). - `--dark` (`boolean`, default: `false`): export as dark theme. - `--with-clicks`, `-c` (`boolean`, default: `false`): export pages for every click animation (see https://sli.dev/guide/animations.html#click-animation). - `--theme`, `-t` (`string`): override theme. - `--omit-background` (`boolean`, default: `false`): remove the default browser background ## `slidev format [entry]` {#format} Format the markdown file. Note that this won't format the content of the slides, only the organization of the markdown file. - `[entry]` (`string`, default: `slides.md`): path to the slides markdown entry. ## `slidev theme [subcommand]` {#theme} Theme-related operations. Subcommands: - `eject [entry]`: Eject the current theme into the local file system. See . - `[entry]` (`string`, default: `slides.md`): path to the slides markdown entry. - Options: - `--dir` (`string`, default: `theme`): the output dir. - `--theme`, `-t` (`string`): override theme. ================================================ FILE: docs/builtin/components.md ================================================ # Components This page lists all the built-in components provided by Slidev. These components can be **directly** used in your slides. Note that can provide additional components. To add your own components, see . ## `Arrow` Draw an arrow. ### Usage ```md ``` Or: ```md ``` Props: - `x1` (`string | number`, required): start point x position - `y1` (`string | number`, required): start point y position - `x2` (`string | number`, required): end point x position - `y2` (`string | number`, required): end point y position - `width` (`string | number`, default: `2`): line width - `color` (`string`, default: `'currentColor'`): line color - `two-way` (`boolean`, default: `false`): draw a two-way arrow ## `VDragArrow` An `Arrow` component that can be dragged. ### Usage Props not related to position are the same as [the `Arrow` component](#arrow). ## `AutoFitText` > Experimental Box inside which the font size will automatically adapt to fit the content. Similar to PowerPoint or Keynote TextBox. ### Usage ```md ``` Props: - `max` (`string | number`, default `100`): Maximum font size - `min` (`string | number`, default `30`): Minimum font size - `modelValue` (`string`, default `''`): text content ## `LightOrDark` Use it to display one thing or another depending on the active light or dark theme. ### Usage Use it with the two named Slots `#dark` and `#light`: ```md ``` Provided props on `LightOrDark` component will be available using scoped slot props: ```md ``` You can provide markdown in the slots, but you will need to surround the content with blank lines: ```md ``` ## `Link` Insert a link you can use to navigate to a given slide. ### Usage ```md Go to slide 42 ``` Props: - `to` (`string | number`): The path of the slide to navigate to (slides path starts from `1`) - `title` (`string`): The title to display One can use a string as `to`, provided the corresponding route exists, e.g. ```md --- routeAlias: solutions --- # Now some solutions! ``` ## `PoweredBySlidev` Renders "Powered by Slidev" with a link to the Slidev website. ## `RenderWhen` Render slots depend on whether the context matches (for example whether we are in presenter view). ### Usage ```md This will only be rendered in presenter view. ``` Context type: `'main' | 'visible' | 'print' | 'slide' | 'overview' | 'presenter' | 'previewNext'` Props: - `context` (`Context | Context[]`): a context or array of contexts you want to check for - `'main'`: Render in slides and presenter view (equivalent to ['slide', 'presenter']), - `'visible'`: Render the content if it is visible - `'print'`: Render in print mode - `'slide'`: Render in slides - `'overview'`: Render in overview - `'presenter'`: Render in presenter view - `'previewNext'`: Render in presenter's next slide view Slots: - `#default`: Rendered when the context matches - `#fallback`: Rendered when the context does not match ## `SlideCurrentNo` Current slide number. ### Usage ```md ``` ## `SlidesTotal` Total number of slides. ### Usage ```md ``` ## `TitleRenderer` Insert the main title from a slide parsed as HTML. Titles and title levels get automatically retrieved from the first title element of each slide. You can override this automatic behavior for a slide by using the front matter syntax: ```yml --- title: Amazing slide title level: 2 --- ``` ### Usage The `` component is a virtual component you can import with: ```js import TitleRenderer from '#slidev/title-renderer' ``` Then you can use it with: ```md ``` Props: - `no` (`string | number`): The number of the slide to display the title from (slides starts from `1`) ## `Toc` Insert a Table Of Content. If you want a slide to not appear in the `` component, you can use the `hideInToc` option in the frontmatter of the slide: ```yml --- hideInToc: true --- ``` Titles are displayed using the [`` component](#titles) ### Usage ```md ``` Props: - `columns` (`string | number`, default: `1`): The number of columns of the display - `listClass` (`string | string[]`, default: `''`): Classes to apply to the table of contents list - `maxDepth` (`string | number`, default: `Infinity`): The maximum depth level of title to display - `minDepth` (`string | number`, default: `1`): The minimum depth level of title to display - `mode` (`'all' | 'onlyCurrentTree'| 'onlySiblings'`, default: `'all'`): - `'all'`: Display all items - `'onlyCurrentTree'`: Display only items that are in current tree (active item, parents and children of active item) - `'onlySiblings'`: Display only items that are in current tree and their direct siblings ## `Transform` Apply scaling or transforming to elements. ### Usage ```md ``` Props: - `scale` (`number | string`, default `1`): transform scale value - `origin` (`string`, default `'top left'`): transform origin value ## `Tweet` Embed a tweet. ### Usage ```md ``` Props: - `id` (`number | string`, required): id of the tweet - `scale` (`number | string`, default `1`): transform scale value - `conversation` (`string`, default `'none'`): [tweet embed parameter](https://developer.twitter.com/en/docs/twitter-for-websites/embedded-tweets/guides/embedded-tweet-parameter-reference) - `cards` (`'hidden' | 'visible'`, default `'visible'`): [tweet embed parameter](https://developer.twitter.com/en/docs/twitter-for-websites/embedded-tweets/guides/embedded-tweet-parameter-reference) ## `VAfter`, `VClick` and `VClicks` ## `VSwitch` Switch between multiple slots based on clicks. - If the `unmount` prop is set to `true`, the previous slot will be unmounted when switching to the next slot. Default is `false`. - Use the `tag` and `childTag` props to change the default tag of the component and its children. Default is `div`. - Use the `transition` prop to change the transition effect. Default is `false` (disabled). ## `VDrag` ## `SlidevVideo` Embed a video. ### Usage ```md

    Your browser does not support videos. You may download it here.

    ``` Check [HTML video element's doc](https://developer.mozilla.org/docs/Web/HTML/Element/Video) to see what can be included in this component's slot. Props: - `controls` (`boolean`, default: `false`): show the video controls - `autoplay` (`boolean | 'once'`, default: `false`): - `true` or `'once'`: start the video only once and does not restart it once ended or paused - `false`: never automatically start the video (rely on `controls` instead) - `autoreset` (`'slide' | 'click'`, default: `undefined`): - `'slide'`: go back to the start of the video when going back to the slide - `'click'`: go back to the start of the video when going back to the component's click turn - `poster` (`string | undefined`, default: `undefined`): - The source of the image to print when the video is not playing. - `printPoster` (`string | undefined`, default: `undefined`): - The override for `poster` when printing. - `timestamp` (`string | number`, default: `0`): - The starting time of the video in seconds. - `printTimestamp` (`string | number | 'last' | undefined`, default: `undefined`): - The override for `timestamp` when printing. ::: warning When exporting, the video may fail to load because Chromium does not support some video formats. In this case, you can specify the executable path of the browser. See [Chromium executable path](/guide/exporting.html#executable-path) for more information. ::: ## `Youtube` Embed a YouTube video. ### Usage ```md ``` Props: - `id` (`string`, required): id of the YouTube video - `width` (`number`): width of the video - `height` (`number`): height of the video You can also make the video start at a specific time if you add `?start=1234` to the id value (where `1234` is seconds), ================================================ FILE: docs/builtin/layouts.md ================================================ # Layouts This page lists all the built-in layouts provided by Slidev. These layouts can be used via the `layout` option in the frontmatters of your slides. Note that may provide additional layouts or override the existing ones. To add your own layouts, see . ## `center` Displays the content in the middle of the screen. ## `cover` Used to display the cover page for the presentation, may contain the presentation title, contextualization, etc. ## `default` The most basic layout, to display any kind of content. ## `end` The final page for the presentation. ## `fact` To show some fact or data with a lot of prominence on the screen. ## `full` Use all the space of the screen to display the content. ## `image-left` Shows an image on the left side of the screen, the content will be placed on the right side. ### Usage ```yaml --- layout: image-left # the image source image: /path/to/the/image # a custom class name to the content class: my-cool-content-on-the-right --- ``` ## `image-right` Shows an image on the right side of the screen, the content will be placed on the left side. ### Usage ```yaml --- layout: image-right # the image source image: /path/to/the/image # a custom class name to the content class: my-cool-content-on-the-left --- ``` ## `image` Shows an image as the main content of the page. ### Usage ```yaml --- layout: image # the image source image: /path/to/the/image --- ``` You can change the default background size (`cover`) by adding the `backgroundSize` attribute: ```yaml --- layout: image image: /path/to/the/image backgroundSize: contain --- ``` ```yaml --- layout: image-left image: /path/to/the/image backgroundSize: 20em 70% --- ``` ## `iframe-left` Shows a web page on the left side of the screen, the content will be placed on the right side. ### Usage ```yaml --- layout: iframe-left # the web page source url: https://github.com/slidevjs/slidev # a custom class name to the content class: my-cool-content-on-the-right --- ``` ## `iframe-right` Shows a web page on the right side of the screen, the content will be placed on the left side. ### Usage ```yaml --- layout: iframe-right # the web page source url: https://github.com/slidevjs/slidev # a custom class name to the content class: my-cool-content-on-the-left --- ``` ## `iframe` Shows a web page as the main content of the page. ### Usage ```yaml --- layout: iframe # the web page source url: https://github.com/slidevjs/slidev --- ``` ## `intro` To introduce the presentation, usually with the presentation title, a short description, the author, etc. ## `none` A layout without any existing styling. ## `quote` To display a quotation with prominence. ## `section` Used to mark the beginning of a new presentation section. ## `statement` Make an affirmation/statement as the main page content. ## `two-cols` Separates the page content in two columns. ### Usage ```md --- layout: two-cols --- # Left This shows on the left ::right:: # Right This shows on the right ``` ## `two-cols-header` Separates the upper and lower lines of the page content, and the second line separates the left and right columns. ### Usage ```md --- layout: two-cols-header --- This spans both ::left:: # Left This shows on the left ::right:: # Right This shows on the right ``` ================================================ FILE: docs/custom/config-code-runners.md ================================================ # Configure Code Runners Define code runners for custom languages in your Monaco Editor. By default, JavaScript, TypeScript runners are supported built-in. They run in the browser **without** a sandbox environment. If you want more advanced integrations, you can provide your own code runner that sends the code to a remote server, runs in a Web Worker, or anything, up to you. Create `./setup/code-runners.ts` with the following content: ```ts twoslash [setup/code-runners.ts] /* eslint-disable import/first */ declare const executePythonCodeRemotely: (code: string) => Promise declare const sanitizeHtml: (html: string) => string // ---cut--- import { defineCodeRunnersSetup } from '@slidev/types' export default defineCodeRunnersSetup(() => { return { async python(code, ctx) { // Somehow execute the code and return the result const result = await executePythonCodeRemotely(code) return { text: result } }, html(code, ctx) { return { html: sanitizeHtml(code) } }, // or other languages, key is the language id } }) ``` ## Runner Context The second argument `ctx` is the runner context, which contains the following properties: ```ts twoslash import type { CodeRunnerOutputs } from '@slidev/types' import type { CodeToHastOptions } from 'shiki' // ---cut--- export interface CodeRunnerContext { /** * Options passed to runner via the `runnerOptions` prop. */ options: Record /** * Highlight code with shiki. */ highlight: (code: string, lang: string, options?: Partial) => string /** * Use (other) code runner to run code. */ run: (code: string, lang: string) => Promise } ``` ## Runner Output The runner can either return a text or HTML output, or an element to be mounted. Refer to https://github.com/slidevjs/slidev/blob/main/packages/types/src/code-runner.ts for more details. ## Additional Runner Dependencies By default, Slidev will scan the Markdown source and automatically import the necessary dependencies for the code runners. If you want to manually import dependencies, you can use the `monacoRunAdditionalDeps` option in the [headmatter](./index#headmatter): ```yaml monacoRunAdditionalDeps: - ./path/to/dependency - lodash-es ``` ::: tip The paths are resolved relative to the `snippets` directory. And the names of the deps should be exactly the same as the imported ones in the code. ::: ================================================ FILE: docs/custom/config-context-menu.md ================================================ # Configure Context Menu Customize the context menu items in Slidev. Create `./setup/context-menu.ts` with the following content: ```ts twoslash [./setup/context-menu.ts] // ---cut--- import { useNav } from '@slidev/client' import { defineContextMenuSetup } from '@slidev/types' import { computed } from 'vue' // ---cut-start--- // @ts-expect-error missing types // ---cut-end--- import Icon3DCursor from '~icons/carbon/3d-cursor' export default defineContextMenuSetup((items) => { const { isPresenter } = useNav() return computed(() => [ ...items.value, { small: false, icon: Icon3DCursor, // if `small` is `true`, only the icon is shown label: 'Custom Menu Item', // or a Vue component action() { alert('Custom Menu Item Clicked!') }, disabled: isPresenter.value, }, ]) }) ``` This will append a new menu item to the context menu. To disable context menu globally, set `contextMenu` to `false` in the frontmatter. `contextMenu` can also be set to `dev` or `build` to only enable the context menu in development or build mode. ================================================ FILE: docs/custom/config-fonts.md ================================================ # Configure Fonts While you can use HTML and CSS to customize the fonts and style for your slides as you want, Slidev also provides a convenient way to use them effortlessly. In your frontmatter, configure as the following: ```yaml --- fonts: # basically the text sans: Robot # use with `font-serif` css class from UnoCSS serif: Robot Slab # for code blocks, inline code, etc. mono: Fira Code --- ``` And that's all. Fonts will be **imported automatically from a provider via CDN, by default it is [Google Fonts](https://fonts.google.com/)**. That means you can use any fonts available on Google Fonts directly. ## Local Fonts By default, Slidev assumes all the fonts specified via `fonts` configurations come from Google Fonts. If you want to use local fonts, specify the `fonts.local` to opt-out the auto-importing. ```yaml --- fonts: # like font-family in css, you can use `,` to separate multiple fonts for fallback sans: 'Helvetica Neue,Robot' # mark 'Helvetica Neue' as local font local: Helvetica Neue --- ``` ## Weights & Italic By default, Slidev imports three weights `200`,`400`,`600` for each font. You can configure them by: ```yaml --- fonts: sans: Robot # default weights: '200,400,600' # import italic fonts, default `false` italic: false --- ``` This configuration applies to all web fonts. For more fine-grained controls of each font's weights, you will need to manually import them with [HTML](/custom/directory-structure.html#index-html) and CSS. ## Fallback Fonts For most of the scenarios, you only need to specify the "special font" and Slidev will append the fallback fonts for you, for example: ```yaml --- fonts: sans: Robot serif: Robot Slab mono: Fira Code --- ``` will result in ```css .font-sans { font-family: "Robot",ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; } .font-serif { font-family: "Robot Slab",ui-serif,Georgia,Cambria,"Times New Roman",Times,serif; } .font-mono { font-family: "Fira Code",ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; } ``` If you want to disable the fallback fonts, configure as the following: ```yaml --- fonts: mono: 'Fira Code, monospace' fallbacks: false --- ``` ## Providers - Options: `google` | `coollabs` | `none` - Default: `google` Currently, only [Google Fonts](https://fonts.google.com/) and [coolLabs](https://fonts.coollabs.io/) supported, we are planning to add more providers in the future. Specify to `none` will disable the auto-importing feature entirely and treat all the fonts locally. ```yaml --- fonts: provider: none --- ``` ================================================ FILE: docs/custom/config-highlighter.md ================================================ # Configure Highlighter Slidev uses [Shiki](https://github.com/shikijs/shiki) as the code highlighter. It's a TextMate Grammar powered syntax highlighter as accurate as VS Code. It generates colored tokens so no additinal CSS is required. Shiki also comes with [a bunch of built-in themes](https://shiki.style/themes). In Slidev, we also provided the [TwoSlash](#twoslash-integration) support. ## Configure Shiki Create `./setup/shiki.ts` file with the following content: ```ts twoslash [setup/shiki.ts] import { defineShikiSetup } from '@slidev/types' export default defineShikiSetup(() => { return { themes: { dark: 'min-dark', light: 'min-light', }, transformers: [ // ... ], } }) ``` If you want to add custom theme or language (TextMate grammar/themes in JSON), you can import them in the setup file: ```ts twoslash [setup/shiki.ts] import { defineShikiSetup } from '@slidev/types' // ---cut-start--- // @ts-expect-error missing types // ---cut-end--- import customLanguage from './customLanguage.tmLanguage.json' // ---cut-start--- // @ts-expect-error missing types // ---cut-end--- import customTheme from './customTheme.tmTheme.json' export default defineShikiSetup(() => { return { themes: { dark: customTheme, light: 'min-light', }, langs: [ 'js', 'typescript', 'cpp', customLanguage, // ... ], transformers: [ // ... ], } }) ``` Check [Built-in languages](https://shiki.style/languages) and [Built-in themes](https://shiki.style/themes), and refer to [Shiki's docs](https://shiki.style) for more details. :::info For now, Shiki Magic Move does not support transformers. ::: ## Configure Prism :::warning Prism support has been removed since v0.50. Please use Shiki instead. ::: ================================================ FILE: docs/custom/config-katex.md ================================================ # Configure KaTeX Create `./setup/katex.ts` with the following content: ```ts twoslash [setup/katex.ts] import { defineKatexSetup } from '@slidev/types' export default defineKatexSetup(() => { return { maxExpand: 2000, /* ... */ } }) ``` The return value should be the custom options for KaTeX. Refer to [KaTeX's documentation](https://katex.org/docs/options.html) or the type definition for the full options list. ================================================ FILE: docs/custom/config-mermaid-renderer.md ================================================ # Configure Mermaid Renderer 1. The user installs the Mermaid library they want to use. e.g.) `npm install beautiful-mermaid` 2. Create `./setup/mermaid-renderer.ts` with the following content: ```ts // setup/mermaid-renderer.ts import { defineMermaidRendererSetup } from '@slidev/types' // example. https://github.com/lukilabs/beautiful-mermaid?tab=readme-ov-file#readme import { renderMermaid } from 'beautiful-mermaid' export default defineMermaidRendererSetup(() => { return (code, _options) => renderMermaid(code) }) ``` This setting allows you to use the 3rd party Mermaid library. Replace the `renderMermaid()` part with the render function of the library. ================================================ FILE: docs/custom/config-mermaid.md ================================================ # Configure Mermaid Create `./setup/mermaid.ts` with the following content: ```ts twoslash [setup/mermaid.ts] import { defineMermaidSetup } from '@slidev/types' export default defineMermaidSetup(() => { return { theme: 'forest', } }) ``` The return value should be the custom configs for [Mermaid](https://mermaid.js.org/). Refer to the [Mermaid documentation](https://mermaid.js.org/config/schema-docs/config.html) or the type definition for the full config list. ## Custom theme/styles In case you want to create your custom Mermaid themes or styles, you can do this by defining `themeVariables` like in the following example: ```ts twoslash import { defineMermaidSetup } from '@slidev/types' export default defineMermaidSetup(() => { return { theme: 'base', themeVariables: { // General theme variables noteBkgColor: '#181d29', noteTextColor: '#F3EFF5cc', noteBorderColor: '#404551', // Sequence diagram variables actorBkg: '#0E131F', actorBorder: '#44FFD2', actorTextColor: '#F3EFF5', actorLineColor: '#F3EFF5', signalColor: '#F3EFF5', signalTextColor: '#F3EFF5', } } }) ``` You can find all theme variables on the [Mermaid Theme Configuration](https://mermaid.js.org/config/theming.html) page. ================================================ FILE: docs/custom/config-monaco.md ================================================ # Configure Monaco Create `./setup/monaco.ts` with the following content: ```ts twoslash [./setup/monaco.ts] import { defineMonacoSetup } from '@slidev/types' export default defineMonacoSetup(async (monaco) => { // use `monaco` to configure }) ``` Learn more about [configuring Monaco](https://github.com/Microsoft/monaco-editor). ## TypeScript Types When using TypeScript with Monaco, types for dependencies will be installed to the client-side automatically. ````md ```ts {monaco} import { ref } from 'vue' import { useMouse } from '@vueuse/core' const counter = ref(0) ``` ```` In the example above, make sure `vue` and `@vueuse/core` are installed locally as dependencies / devDependencies, Slidev will handle the rest to get the types working for the editor automatically. When deployed as SPA, those types will also be bundled for static hosting. ### Additional Types Slidev will scan all the Monaco code blocks in your slides and import the types for those used libraries for you. In case it missed some, you can explicitly specify extra packages to import the types for: ```md --- monacoTypesAdditionalPackages: - lodash-es - foo --- ``` ### Auto Type Acquisition You can optionally switch to load types from CDN by setting the following headmatter: ```md --- monacoTypesSource: ata --- ``` This feature is powered by [`@typescript/ata`](https://github.com/microsoft/TypeScript-Website/tree/v2/packages/ata) and runs completely on the client-side. ## Configure Themes Since v0.48.0, Monaco will reuse the Shiki theme you configured in [Shiki's setup file](/custom/config-highlighter#configure-shiki), powered by [`@shikijs/monaco`](https://shiki.style/packages/monaco). You don't need to worry about it anymore and it will have a consistent style with the rest of your code blocks. ## Configure the Editor > Available since v0.43.0 If you would like to customize the Monaco editor you may pass an `editorOptions` object that matches the [Monaco IEditorOptions](https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IEditorOptions.html) definition. ````md ```ts {monaco} { editorOptions: { wordWrap:'on'} } console.log('HelloWorld') ``` ```` Alternatively if you would like these options to be applied to every Monaco instance, you can return them in the `defineMonacoSetup` function ```ts twoslash [./setup/monaco.ts] import { defineMonacoSetup } from '@slidev/types' export default defineMonacoSetup(() => { return { editorOptions: { wordWrap: 'on' } } }) ``` ## Disabling Since v0.48.0, the Monaco editor is enabled by default and only be bundled when you use it. If you want to disable it, you can set `monaco` to `false` in the frontmatter of your slide: ```yaml --- monaco: false # can also be `dev` or `build` to conditionally enable it --- ``` ## Strict Mode {#strict-mode} > Available since v0.52.0 By default, Monaco runnable code executes in strict mode (`"use strict"`). You can disable this if your code relies on non-strict mode behavior: ```yaml --- monacoRunUseStrict: false --- ``` ## Configure Code Runners To configure how the Monaco Runner runs the code, or to add support for custom languages, please reference [Configure Code Runners](/custom/config-code-runners). ================================================ FILE: docs/custom/config-parser.md ================================================ # Configure Pre-Parser ::: info Custom pre-parsers are not supposed to be used too often. Usually you can use [Transformers](./config-transformers) for custom syntaxes. ::: Slidev parses your presentation file (e.g. `slides.md`) in three steps: 1. A "preparsing" step is carried out: the file is split into slides using the `---` separator, and considering the possible frontmatter blocks. 2. Each slide is parsed with an external library. 3. Slidev resolves the special frontmatter property `src: ....`, which allows to include other md files. ## Markdown Parser Configuring the markdown parser used in step 2 can be done by [configuring Vite internal plugins](/custom/config-vite#configure-internal-plugins). ## Preparser Extensions > Available since v0.37.0. ::: warning Important: when modifying the preparser configuration, you need to stop and start Slidev again (restart might not be sufficient). ::: The preparser (step 1 above) is highly extensible and allows you to implement custom syntaxes for your md files. Extending the preparser is considered **an advanced feature** and is susceptible to breaking [editor integrations](../features/side-editor) due to implicit changes in the syntax. To customize it, create a `./setup/preparser.ts` file with the following content: ```ts twoslash [./setup/preparser.ts] import { definePreparserSetup } from '@slidev/types' export default definePreparserSetup(({ filepath, headmatter, mode }) => { return [ { transformRawLines(lines) { for (const i in lines) { if (lines[i] === '@@@') lines[i] = 'HELLO' } }, } ] }) ``` This example systematically replaces any `@@@` line with a line with `hello`. It illustrates the structure of a preparser configuration file and some of the main concepts the preparser involves: - `definePreparserSetup` must be called with a function as parameter. - The function receives the file path (of the root presentation file), the headmatter (from the md file) and, since v0.48.0, a mode (dev, build or export). It could use this information (e.g., enable extensions based on the presentation file or whether we are exporting a PDF). - The function must return a list of preparser extensions. - An extension can contain: - a `transformRawLines(lines)` function that runs just after parsing the headmatter of the md file and receives a list of all lines (from the md file). The function can mutate the list arbitrarily. - a `transformSlide(content, frontmatter)` function that is called for each slide, just after splitting the file, and receives the slide content as a string and the frontmatter of the slide as an object. The function can mutate the frontmatter and must return the content string (possibly modified, possibly `undefined` if no modifications have been done). - a `transformNote(note, frontmatter)` function that is called for each slide, just after splitting the file, and receives the slide note as a string or undefined and the frontmatter of the slide as an object. The function can mutate the frontmatter and must return the note string (possibly modified, possibly `undefined` if no modifications have been done). - a `name` ## Example Preparser Extensions ### Use case 1: compact syntax top-level presentation Imagine a situation where (part of) your presentation is mainly showing cover images and including other md files. You might want a compact notation where for instance (part of) `slides.md` is as follows: ```md @cover: /nice.jpg # Welcome @src: page1.md @src: page2.md @cover: /break.jpg @src: pages3-4.md @cover: https://cover.sli.dev # Questions? see you next time ``` To allow these `@src:` and `@cover:` syntaxes, create a `./setup/preparser.ts` file with the following content: ```ts twoslash [./setup/preparser.ts] import { definePreparserSetup } from '@slidev/types' export default definePreparserSetup(() => { return [ { transformRawLines(lines) { let i = 0 while (i < lines.length) { const l = lines[i] if (l.match(/^@cover:/i)) { lines.splice( i, 1, '---', 'layout: cover', `background: ${l.replace(/^@cover: */i, '')}`, '---', '' ) continue } if (l.match(/^@src:/i)) { lines.splice( i, 1, '---', `src: ${l.replace(/^@src: */i, '')}`, '---', '' ) continue } i++ } } }, ] }) ``` And that's it. ### Use case 2: using custom frontmatter to wrap slides Imagine a case where you often want to scale some of your slides but still want to use a variety of existing layouts so creating a new layout would not be suited. For instance, you might want to write your `slides.md` as follows: ```md --- layout: quote _scale: 0.75 --- # Welcome > great! --- _scale: 4 --- # Break --- # Ok --- layout: center _scale: 2.5 --- # Questions? see you next time ``` Here we used an underscore in `_scale` to avoid possible conflicts with existing frontmatter properties (indeed, the case of `scale`, without underscore would cause potential problems). To handle this `_scale: ...` syntax in the frontmatter, create a `./setup/preparser.ts` file with the following content: ```ts twoslash [./setup/preparser.ts] import { definePreparserSetup } from '@slidev/types' export default definePreparserSetup(() => { return [ { async transformSlide(content, frontmatter) { if ('_scale' in frontmatter) { return [ ``, '', content, '', '' ].join('\n') } }, }, ] }) ``` And that's it. ### Use case 3: using custom frontmatter to transform note Imagine a case where you want to replace the slides default notes with custom notes. For instance, you might want to write your `slides.md` as follows: ```md --- layout: quote _note: notes/note.md --- # Welcome > great! ``` Here we used an underscore in `_note` to avoid possible conflicts with existing frontmatter properties. To handle this `_note: ...` syntax in the frontmatter, create a `./setup/preparser.ts` file with the following content: ```ts twoslash [./setup/preparser.ts] import fs, { promises as fsp } from 'node:fs' import { definePreparserSetup } from '@slidev/types' export default definePreparserSetup(() => { return [ { async transformNote(note, frontmatter) { if ('_note' in frontmatter && fs.existsSync(frontmatter._note)) { try { const newNote = await fsp.readFile(frontmatter._note, 'utf8') return newNote } catch (err) { } } return note }, }, ] }) ``` ================================================ FILE: docs/custom/config-routes.md ================================================ # Configure Routes Add custom pages to the Slidev app. ## Usage Create `./setup/routes.ts` with the following content: ```ts twoslash [./setup/routes.ts] import { defineRoutesSetup } from '@slidev/types' export default defineRoutesSetup((routes) => { return [ ...routes, { path: '/my-page', // ---cut-start--- // @ts-expect-error missing types // ---cut-end--- component: () => import('../pages/my-page.vue'), }, ] }) ``` Learn more about routes in the [Vue Router documentation](https://router.vuejs.org/). ================================================ FILE: docs/custom/config-shortcuts.md ================================================ # Configure Shortcuts ## Getting started Create `./setup/shortcuts.ts` with the following content: ```ts twoslash [./setup/shortcuts.ts] import type { NavOperations, ShortcutOptions } from '@slidev/types' import { defineShortcutsSetup } from '@slidev/types' export default defineShortcutsSetup((nav: NavOperations, base: ShortcutOptions[]) => { return [ ...base, // keep the existing shortcuts { key: 'enter', fn: () => nav.next(), autoRepeat: true, }, { key: 'backspace', fn: () => nav.prev(), autoRepeat: true, }, ] }) ``` In the setup function, you can customize the keyboard shortcuts by returning a new array of shortcuts. The above example binds the `next` operation to enter and the `prev` operation to backspace. Please refer to [Navigation Actions](../guide/ui#navigation-actions) section for the default shortcuts and navigation operations. ## Key Binding Format The `key` of each shortcut can be either a string (e.g. `'Shift+Ctrl+A'`) or a computed boolean. Please refer to [`useMagicKeys` from VueUse](https://vueuse.org/core/useMagicKeys/) for ================================================ FILE: docs/custom/config-transformers.md ================================================ # Configure Transformers This setup function allows you to define custom transformers for the markdown content of **each slide**. This is useful when you want to add custom Markdown syntax and render custom code blocks. To start, create a `./setup/transformers.ts` file with the following content: ````ts twoslash [setup/transformers.ts] import type { MarkdownTransformContext } from '@slidev/types' import { defineTransformersSetup } from '@slidev/types' function myCodeblock(ctx: MarkdownTransformContext) { console.log('index in presentation', ctx.slide.index) ctx.s.replace( /^```myblock *(\{[^\n]*\})?\n([\s\S]+?)\n```/gm, (full, options = '', code = '') => { return `...` }, ) } export default defineTransformersSetup(() => { return { pre: [], preCodeblock: [myCodeblock], postCodeblock: [], post: [], } }) ```` The return value should be the custom options for the transformers. The `pre`, `preCodeblock`, `postCodeblock`, and `post` are arrays of functions that will be called in order to transform the markdown content. The order of the transformers is: 1. `pre` from your project 2. `pre` from addons and themes 3. Import snippets syntax and Shiki magic move 4. `preCodeblock` from your project 5. `preCodeblock` from addons and themes 6. Built-in special code blocks like Mermaid, Monaco and PlantUML 7. `postCodeblock` from addons and themes 8. `postCodeblock` from your project 9. Other built-in transformers like code block wrapping 10. `post` from addons and themes 11. `post` from your project ================================================ FILE: docs/custom/config-unocss.md ================================================ # Configure UnoCSS [UnoCSS](https://unocss.dev) is now the default CSS framework for Slidev since v0.42.0. UnoCSS is a fast atomic CSS engine that has full flexibility and extensibility. Most of the Tailwind CSS classes are supported **out-of-box**, and you can also extend it with your own configurations. By default, Slidev enables the following presets out-of-box: - [@unocss/preset-wind3](https://unocss.dev/presets/wind3) - Tailwind / Windi CSS compatible utilities - [@unocss/preset-attributify](https://unocss.dev/presets/attributify) - Attributify mode - [@unocss/preset-icons](https://unocss.dev/presets/icons) - Use any icons as class - [@unocss/preset-web-fonts](https://unocss.dev/presets/web-fonts) - Use web fonts at ease - [@unocss/transformer-directives](https://unocss.dev/transformers/directives) - Use `@apply` in CSS Slidev also adds shortcuts as can be seen in its [source code](https://github.com/slidevjs/slidev/blob/main/packages/client/uno.config.ts). You can therefore style your content the way you want. For example: ```html
    ### Name - Item 1 - Item 2
    ``` ## Configurations You can create `uno.config.ts` under the root of your project to extend the builtin configurations ```ts twoslash [uno.config.ts] import { defineConfig } from 'unocss' export default defineConfig({ shortcuts: { // custom the default background 'bg-main': 'bg-white text-[#181818] dark:(bg-[#121212] text-[#ddd])', }, // ... }) ``` Learn more about [UnoCSS configurations](https://unocss.dev/guide/config-file) ================================================ FILE: docs/custom/config-vite.md ================================================ # Configure Vite and Plugins Slidev is powered by [Vite](https://vitejs.dev/) under the hood. This means you can leverage Vite's great plugin system to customize your slides even further. The `vite.config.ts` will be respected if you have one, and will be merged with the Vite config provided by Slidev, your theme and the addons. ## Configure Internal Plugins Slidev internally adds the following plugins to Vite: - [@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue) - [unplugin-vue-components](https://github.com/unplugin/unplugin-vue-components) - [unplugin-icons](https://github.com/unplugin/unplugin-icons) - [vite-plugin-vue-markdown](https://github.com/unplugin/unplugin-vue-markdown) - [vite-plugin-remote-assets](https://github.com/antfu/vite-plugin-remote-assets) - [unocss/vite](https://github.com/unocss/unocss/tree/main/packages/vite) To configure the built-in plugins listed above, create a `vite.config.ts` with the following content. Please note that Slidev has some [default configurations](https://github.com/slidevjs/slidev/blob/main/packages/slidev/node/vite/index.ts) for those plugins, this usage will override some of them, which may potentially cause the app to break. Please treat this as **an advanced feature**, and make sure you know what you are doing before moving on. ```ts twoslash [vite.config.ts] /* eslint-disable import/first */ /// import type MarkdownExit from 'markdown-exit' declare const MyPlugin: (md: any) => void // ---cut--- import { defineConfig } from 'vite' export default defineConfig({ slidev: { vue: { /* vue options */ }, markdown: { /* markdown-exit options */ markdownSetup(md) { /* custom markdown-exit plugins */ md.use(MyPlugin) }, }, /* options for other plugins */ }, }) ``` See the [type declarations](https://github.com/slidevjs/slidev/blob/main/packages/types/src/vite.ts#L11) for more options. ::: warning It is not allowed to re-add plugins that has been used internally be Slidev. For example, instead of ```ts twoslash import Vue from '@vitejs/plugin-vue' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ Vue({ /* vue options */ }) ], }) ``` Please pass the Vue options to the `slidev.vue` field as described above ::: ## Add Custom Plugins based on Slide data Usually you can add Vite plugins into your `vite.config.ts` (see above). However, if you want to add plugins based on the slide data, you need to add a `./setup/vite-plugins.ts` with the following content: ```ts twoslash import { defineVitePluginsSetup } from '@slidev/types' export default defineVitePluginsSetup((options) => { return [ // Your plugins here // Slide data is available as options.data.slides ] }) ``` ================================================ FILE: docs/custom/config-vue.md ================================================ # Configure Vue App Slidev uses [Vue 3](https://v3.vuejs.org/) to render the application on the client side. You can extend the app to add custom plugins or configurations. Create `./setup/main.ts` with the following content: ```ts twoslash [setup/main.ts] /* eslint-disable import/first */ import type { Plugin } from 'vue' declare const YourPlugin: Plugin // ---cut--- import { defineAppSetup } from '@slidev/types' export default defineAppSetup(({ app, router }) => { // Vue App app.use(YourPlugin) }) ``` This can also be used as the main entrance of your Slidev app to do some initializations before the app starts. Learn more: [Vue Application API](https://v3.vuejs.org/api/application-api.html#component). ================================================ FILE: docs/custom/directory-structure.md ================================================ # Directory Structure Slidev employs some directory structure conventions to minimize the configuration surface and to make the functionality extensions flexible and intuitive. The conventional directory structure is: ```bash your-slidev/ ├── components/ # custom components ├── layouts/ # custom layouts ├── public/ # static assets ├── setup/ # custom setup / hooks ├── snippets/ # code snippets ├── styles/ # custom style ├── index.html # injections to index.html ├── slides.md # the main slides entry └── vite.config.ts # extending vite config ``` All of them are optional. ## Components Pattern: `./components/*.{vue,js,ts,jsx,tsx,md}` ## Layouts Pattern: `./layouts/*.{vue,js,ts,jsx,tsx}` ## Public Pattern: `./public/*` Assets in this directory will be served at root path `/` during dev, and copied to the root of the dist directory as-is. Read more about [Assets Handling](../guide/faq#assets-handling). ## Style Pattern: `./style.css` | `./styles/index.{css,js,ts}` Files following this convention will be injected to the App root. If you need to import multiple CSS entries, you can create the following structure and manage the import order yourself. :::warning Global CSS here also applies to the presenter UI. Prefer scoping styles to individual slides, or wrap your selectors under `.slidev-layout` to avoid leaking styles into presenter mode. **Example:** Use `.slidev-layout .grid { ... }` instead of just `.grid { ... }`. ::: ```bash your-slidev/ ├── ... └── styles/ ├── index.ts ├── base.css ├── code.css └── layouts.css ``` ```ts // styles/index.ts import './base.css' import './code.css' import './layouts.css' ``` Styles will be processed by [UnoCSS](https://unocss.dev/) and [PostCSS](https://postcss.org/), so you can use CSS nesting and [at-directives](https://unocss.dev/transformers/directives#apply) and Nested CSS out-of-box. For example: ```css .slidev-layout { --uno: px-14 py-10 text-[1.1rem]; h1, h2, h3, h4, p, div { --uno: select-none; } pre, code { --uno: select-text; } a { color: theme('colors.primary'); } } ``` Learn more about the syntax [here](https://unocss.dev/transformers/directives#apply). ## `index.html` Pattern: `index.html` The `index.html` provides the ability to inject meta tags and/or scripts to the main `index.html` For example, for the following custom `index.html`: ```html [index.html] ``` The final hosted `index.html` will be: ```html
    ``` ## Global Layers Pattern: `global-top.vue` | `global-bottom.vue` | `custom-nav-controls.vue` | `slide-top.vue` | `slide-bottom.vue` ================================================ FILE: docs/custom/index.md ================================================ # Customizations Slidev is fully customizable, from styling to tooling configurations. It allows you to configure the tools underneath ([Vite](/custom/config-vite), [UnoCSS](/custom/config-unocss), [Monaco](/custom/config-monaco), etc.) ## Slides Deck Configs {#headmatter} You can configure the whole slides project in the frontmatter of your **first** slide (i.e. headmatter). The following shows the default value for each option: ```yaml --- # theme id, package name, or local path # Learn more: https://sli.dev/guide/theme-addon.html#use-theme theme: default # addons, can be a list of package names or local paths # Learn more: https://sli.dev/guide/theme-addon.html#use-addon addons: [] # title of your slide, will inferred from the first header if not specified title: Slidev # titleTemplate for the webpage, `%s` will be replaced by the slides deck's title titleTemplate: '%s - Slidev' # information for your slides, can be a Markdown string info: false # author field for exported PDF or PPTX author: Your Name Here # keywords field for exported PDF, comma-delimited keywords: keyword1,keyword2 # enable presenter mode, can be boolean, 'dev' or 'build' presenter: true # enable browser exporter, can be boolean, 'dev' or 'build' browserExporter: dev # enabled pdf downloading in SPA build, can also be a custom url download: false # filename of the export file exportFilename: slidev-exported # export options # use export CLI options in camelCase format # Learn more: https://sli.dev/guide/exporting.html export: format: pdf timeout: 30000 dark: false withClicks: false withToc: false # enable twoslash, can be boolean, 'dev' or 'build' twoslash: true # show line numbers in code blocks lineNumbers: false # enable monaco editor, can be boolean, 'dev' or 'build' monaco: true # Where to load monaco types from, can be 'cdn', 'local' or 'none' monacoTypesSource: local # explicitly specify extra local packages to import the types for monacoTypesAdditionalPackages: [] # explicitly specify extra local modules as dependencies of monaco runnable monacoRunAdditionalDeps: [] # download remote assets in local using vite-plugin-remote-assets, can be boolean, 'dev' or 'build' remoteAssets: false # controls whether texts in slides are selectable selectable: true # enable slide recording, can be boolean, 'dev' or 'build' record: dev # enable Slidev's context menu, can be boolean, 'dev' or 'build' contextMenu: true # enable wake lock, can be boolean, 'dev' or 'build' wakeLock: true # take snapshot for each slide in the overview overviewSnapshots: false # force color schema for the slides, can be 'auto', 'light', or 'dark' colorSchema: auto # router mode for vue-router, can be "history" or "hash" routerMode: history # aspect ratio for the slides aspectRatio: 16/9 # real width of the canvas, unit in px canvasWidth: 980 # used for theme customization, will inject root styles as `--slidev-theme-x` for attribute `x` themeConfig: primary: '#5d8392' # favicon, can be a local file path or URL favicon: 'https://cdn.jsdelivr.net/gh/slidevjs/slidev/assets/favicon.png' # URL of PlantUML server used to render diagrams # Learn more: https://sli.dev/features/plantuml.html plantUmlServer: https://www.plantuml.com/plantuml # fonts will be auto-imported from Google fonts # Learn more: https://sli.dev/custom/config-fonts.html fonts: sans: Roboto serif: Roboto Slab mono: Fira Code # default frontmatter applies to all slides defaults: layout: default # ... # drawing options # Learn more: https://sli.dev/guide/drawing.html drawings: enabled: true persist: false presenterOnly: false syncAll: true # HTML tag attributes htmlAttrs: dir: ltr lang: en # SEO meta tags seoMeta: ogTitle: Slidev Starter Template ogDescription: Presentation slides for developers ogImage: https://cover.sli.dev ogUrl: https://example.com twitterCard: summary_large_image twitterTitle: Slidev Starter Template twitterDescription: Presentation slides for developers twitterImage: https://cover.sli.dev twitterSite: username twitterUrl: https://example.com --- ``` Check out the [type definitions](https://github.com/slidevjs/slidev/blob/main/packages/types/src/config.ts) for more details. ## Per-slide Configs {#frontmatter} Also every slide accepts the following configuration in its frontmatter block. The following shows the default value for each option: ```yaml --- # custom clicks count # Learn more: https://sli.dev/guide/animations#total clicks: 0 # custom start clicks count clicksStart: 0 # completely disable and hide the slide disabled: false # the same as `disabled` hide: false # hide the slide for the components hideInToc: false # defines the layout component applied to the slide layout: <"cover" if the slide is the first slide, otherwise "default"> # override the title level for the and components # only if `title` has also been declared level: 1 # mount this slide before entering preload: true # create a route alias that can be used in the URL or with the component routeAlias: undefined # or string # includes a markdown file # Learn more: https://sli.dev/guide/syntax.html#importing-slides src: undefined # or string # override the title for the and components # only if `title` has also been declared title: undefined # or string # defines the transition between the slide and the next one # Learn more: https://sli.dev/guide/animations.html#slide-transitions transition: undefined # or BuiltinSlideTransition | string | TransitionGroupProps | null # custom zoom scale # useful for slides with a lot of content zoom: 1 # used as positions of draggable elements # Learn more: https://sli.dev/features/draggable.html dragPos: {} # type: Record --- ``` Check out the [type definition](https://github.com/slidevjs/slidev/blob/main/packages/types/src/frontmatter.ts#L260) for more details. ## Directory Structure Slidev uses directory structure conventions to minimalize the configuration surface and make extensions in functionality flexible and intuitive. Refer to the [Directory Structure](/custom/directory-structure) section. ## Config Tools
  • {{ c.text }}
  • ================================================ FILE: docs/features/block-frontmatter.md ================================================ --- depends: - guide/syntax relates: - features/prettier-plugin tags: [syntax] description: | Use a YAML code block as the frontmatter. --- # Block Frontmatter The usual way to define frontmatters of slides is concise, but may lack of highlighting and formatter support. To solve this, you can use a YAML block at the very beginning of the slide content as the frontmatter of the slide: ````md --- theme: default --- # Slide 1 --- ```yaml layout: quote ``` # Slide 2 --- # Slide 3 ```` ::: warning About headmatter Headmatter in Slidev is exactly the usual called "frontmatter" of the a Markdown file, which is supported by most of the Markdown editors and formatters. So you can't use a YAML block as the headmatter of the whole slide deck. ::: ================================================ FILE: docs/features/build-with-pdf.md ================================================ --- depends: - guide/exporting - guide/hosting relates: - CLI export options: /builtin/cli#export - Headmatter export options: /custom/#headmatter tags: [export, build] description: | Generate a downloadable PDF along with your slides build. --- # Generate PDF when Building You can provide a downloadable PDF in your built slides with the following config in headmatter: ```md --- download: true --- ``` Slidev will generate a PDF file along with the build, and a download button will be displayed in the build. You can also provide a custom URL for the PDF. In that case, the rendering process will be skipped. ```md --- download: 'https://myside.com/my-talk.pdf' --- ``` This can also be done with the CLI option `--download` (`boolean` only). ```bash $ slidev build --download ``` When using the download option, you can also provide the export options via: - [CLI export options](/builtin/cli#export) - [Headmatter export options](/custom/#frontmatter-configures) ================================================ FILE: docs/features/bundle-remote-assets.md ================================================ --- relates: - vite-plugin-remote-assets: https://github.com/antfu/vite-plugin-remote-assets tags: [build] description: | Download and bundle remote assets when building your slides. --- # Bundle Remote Assets Just like you would do in markdown, you can use images pointing to a remote or local URL. For remote assets, the built-in [`vite-plugin-remote-assets`](https://github.com/antfu/vite-plugin-remote-assets) will cache them onto the disk at first run, ensuring instant loading even for large images later on. ```md ![Remote Image](https://sli.dev/favicon.png) ``` For local assets, put them into the [`public` folder](/custom/directory-structure.html#public) and reference them with a **leading slash** (i.e., `/pic.png`, NOT `./pic.png`, which is relative to the working file). ```md ![Local Image](/pic.png) ``` If you want to apply custom sizes or styles, you can convert them to the `` tag: ```html ``` ================================================ FILE: docs/features/canvas-size.md ================================================ --- relates: - guide/faq#adjust-size - features/zoom-slide - features/transform-component tags: [layout] description: | Set the size for all your slides. --- # Slide Canvas Size Slidev allows you to set the size of the slide canvas via the `canvasWidth` and `aspectRatio` options in the headmatter: ```md --- # aspect ratio for the slides aspectRatio: 16/9 # real width of the canvas, unit in px canvasWidth: 980 --- # Your slides here ``` To scale several slides in your presentation, you can use the `zoom` option: To adjust the size of some elements on your slides, you can use the `Transform` component: ================================================ FILE: docs/features/click-marker.md ================================================ --- depends: - guide/syntax#notes - guide/animations since: v0.48.0 tags: [presenter, animation] description: | Highlighting notes and auto-scrolling to the active section of notes. --- # Click Markers For some slides you may have longer notes that could be hard to find your place. Slidev supports click markers that allow highlighting and auto-scrolling to the section of notes from your corresponding content. Put `[click]` markers at the beginning of any line in your notes for the timing you need to go to another [click](/guide/animations#click-animation). You may skip `n` clicks by using `[click:{n+1}]`. For example: ```md ``` Slidev divides the content between the click markers and highlights it in presenter notes, synchronized with your slide progress. ================================================ FILE: docs/features/code-block-line-numbers.md ================================================ --- depends: - guide/syntax#code-block tags: [codeblock] description: | Enable line numbering for all code blocks across the slides or individually. --- # Line Numbers You can enable line numbering for all code blocks across the slides by setting `lineNumbers: true` in the headmatter, or enable each code block individually by setting `lines: true`. You can also set the starting line for each code block and highlight the lines accordingly via `{startLine: number}`, which defaults to 1. ````md ```ts {6,7}{lines:true,startLine:5} function add( a: Ref | number, b: Ref | number ) { return computed(() => unref(a) + unref(b)) } ``` ```` Note that you can use `{*}` as a placeholder of : ````md ```ts {*}{lines:true,startLine:5} // ... ``` ```` ================================================ FILE: docs/features/code-block-max-height.md ================================================ --- depends: - guide/syntax#code-block tags: [codeblock, layout] description: | Set a maximum height for a code block and enable scrolling. --- # Max Height If the code doesn't fit into one slide, you use the `maxHeight` to set a fixed height and enable scrolling: ````md ```ts {2|3|7|12}{maxHeight:'100px'} function add( a: Ref | number, b: Ref | number ) { return computed(() => unref(a) + unref(b)) } /// ...as many lines as you want const c = add(1, 2) ``` ```` Note that you can use `{*}` as a placeholder of : ````md ```ts {*}{maxHeight:'100px'} // ... ``` ```` ================================================ FILE: docs/features/code-groups.md ================================================ --- depends: - guide/syntax#code-block tags: [codeblock] description: | Group multiple code blocks and automatically match icon by the title name. --- # Code Groups > [!NOTE] > This feature requires [Comark Syntax](/features/comark#comark-syntax). Enable `comark: true` to use it. You can group multiple code blocks like this: ````md ::code-group ```sh [npm] npm i @slidev/cli ``` ```sh [yarn] yarn add @slidev/cli ``` ```sh [pnpm] pnpm add @slidev/cli ``` :: ```` ## Title Icon Matching `code groups`, `code block` and [`Shiki Magic Move`](/features/shiki-magic-move) also supports the automatically icon matching by the title name. ![code-groups-demo](/assets/code-groups-demo.png) ::: info By default, we provide some built-in icons, you can use them by install [@iconify-json/vscode-icons](https://www.npmjs.com/package/@iconify-json/vscode-icons). ::: ::: details All built-in icons ```js const builtinIcons = { // package managers 'pnpm': 'i-vscode-icons:file-type-light-pnpm', 'npm': 'i-vscode-icons:file-type-npm', 'yarn': 'i-vscode-icons:file-type-yarn', 'bun': 'i-vscode-icons:file-type-bun', 'deno': 'i-vscode-icons:file-type-deno', // frameworks 'vue': 'i-vscode-icons:file-type-vue', 'svelte': 'i-vscode-icons:file-type-svelte', 'angular': 'i-vscode-icons:file-type-angular', 'react': 'i-vscode-icons:file-type-reactjs', 'next': 'i-vscode-icons:file-type-light-next', 'nuxt': 'i-vscode-icons:file-type-nuxt', 'solid': 'logos:solidjs-icon', 'astro': 'i-vscode-icons:file-type-light-astro', // bundlers 'rollup': 'i-vscode-icons:file-type-rollup', 'webpack': 'i-vscode-icons:file-type-webpack', 'vite': 'i-vscode-icons:file-type-vite', 'esbuild': 'i-vscode-icons:file-type-esbuild', // configuration files 'package.json': 'i-vscode-icons:file-type-node', 'tsconfig.json': 'i-vscode-icons:file-type-tsconfig', '.npmrc': 'i-vscode-icons:file-type-npm', '.editorconfig': 'i-vscode-icons:file-type-editorconfig', '.eslintrc': 'i-vscode-icons:file-type-eslint', '.eslintignore': 'i-vscode-icons:file-type-eslint', 'eslint.config': 'i-vscode-icons:file-type-eslint', '.gitignore': 'i-vscode-icons:file-type-git', '.gitattributes': 'i-vscode-icons:file-type-git', '.env': 'i-vscode-icons:file-type-dotenv', '.env.example': 'i-vscode-icons:file-type-dotenv', '.vscode': 'i-vscode-icons:file-type-vscode', 'tailwind.config': 'vscode-icons:file-type-tailwind', 'uno.config': 'i-vscode-icons:file-type-unocss', 'unocss.config': 'i-vscode-icons:file-type-unocss', '.oxlintrc': 'i-vscode-icons:file-type-oxlint', 'vue.config': 'i-vscode-icons:file-type-vueconfig', // filename extensions '.mts': 'i-vscode-icons:file-type-typescript', '.cts': 'i-vscode-icons:file-type-typescript', '.ts': 'i-vscode-icons:file-type-typescript', '.tsx': 'i-vscode-icons:file-type-typescript', '.mjs': 'i-vscode-icons:file-type-js', '.cjs': 'i-vscode-icons:file-type-js', '.json': 'i-vscode-icons:file-type-json', '.js': 'i-vscode-icons:file-type-js', '.jsx': 'i-vscode-icons:file-type-js', '.md': 'i-vscode-icons:file-type-markdown', '.py': 'i-vscode-icons:file-type-python', '.ico': 'i-vscode-icons:file-type-favicon', '.html': 'i-vscode-icons:file-type-html', '.css': 'i-vscode-icons:file-type-css', '.scss': 'i-vscode-icons:file-type-scss', '.yml': 'i-vscode-icons:file-type-light-yaml', '.yaml': 'i-vscode-icons:file-type-light-yaml', '.php': 'i-vscode-icons:file-type-php', } ``` ::: ## Custom Icons You can use any name from the [iconify](https://icones.js.org) collection by using the `~icon~` syntax, for example: ````md ```js [npm ~i-uil:github~] console.log('Hello, GitHub!') ``` ```` To make it work, you need to: 1. Install the icon's collection. :::code-group ```sh [npm] npm add @iconify-json/uil ``` ```sh [yarn] yarn add @iconify-json/uil ``` ```sh [pnpm] pnpm add @iconify-json/uil ``` ```sh [bun] bun add @iconify-json/uil ``` ::: 2. Add the icon to the `uno.config.ts` file. ```ts [uno.config.ts] {4-6} import { defineConfig } from 'unocss' export default defineConfig({ safelist: [ 'i-uil:github', ], }) ``` ================================================ FILE: docs/features/comark.md ================================================ --- relates: - Comark Syntax: https://comark.dev/syntax/markdown - '@comark/markdown-it': https://github.com/comarkdown/comark since: v0.43.0 tags: [syntax, styling] description: | A powerful syntax to enhance your markdown content with components and styles. --- # Comark Syntax Slidev supports optional [Comark Syntax](https://comark.dev/syntax/markdown) (formerly known as MDC, Markdown Components) powered by [`@comark/markdown-it`](https://github.com/comarkdown/comark). You can enable it by adding `comark: true` to the frontmatter of your markdown file. ```mdc --- comark: true --- This is a [red text]{style="color:red"} :inline-component{prop="value"} ![](/image.png){width=500px lazy} ::block-component{prop="value"} The **default** slot :: ``` Learn more about [Comark Syntax](https://comark.dev/syntax/markdown). ================================================ FILE: docs/features/direction-variant.md ================================================ --- relates: - UnoCSS Variants: https://unocss.dev/config/variants#variants since: v0.48.0 tags: [navigation, styling] description: | Apply different styles and animations based on the navigation direction. --- # Navigation Direction Variants You may want to apply different classes based on whether it's navigating forward or backward. The `.slidev-nav-go-forward` or `.slidev-nav-go-backward` class will be applied to the slide container when navigating, and you can use them to apply different styles or animations: ```css /* example: delay on only forward but not backward */ .slidev-nav-go-forward .slidev-vclick-target { transition-delay: 500ms; } .slidev-nav-go-backward .slidev-vclick-target { transition-delay: 0; } ``` To make it easier, we also provided some [UnoCSS variants](https://github.com/slidevjs/slidev/blob/6adcf2016b8fb0cab65cf150221f1f67a76a2dd8/packages/client/uno.config.ts#L32-L38) for this. You can use the `forward:` or `backward:` prefix to any UnoCSS classes to only enable them in the specific navigation direction: ```html
    Element
    // [!code --]
    Element
    // [!code ++] ``` In the above example, the animation is only delayed when navigating forward. ================================================ FILE: docs/features/draggable.md ================================================ --- tags: [layout] description: | Move, resize, and rotate elements by dragging them with the mouse. --- # Draggable Elements Draggable elements give you the ability to move, resize, and rotate elements by dragging them with the mouse. This is useful for creating floating elements in your slides. ## Directive Usage ### Data from the frontmatter ```md --- dragPos: square: Left,Top,Width,Height,Rotate --- ``` ### Data from the directive value ::: warning Slidev use regex to update the position value in the slide content. If you meet problems, please use the frontmatter to define the values instead. ::: ```md ``` ## Component Usage ### Data from the frontmatter ```md --- dragPos: foo: Left,Top,Width,Height,Rotate ---
    Use the `v-drag` component to have a draggable container! ``` ### Data from props ```md
    Use the `v-drag` component to have a draggable container! ``` ## Create a Draggable Element When you create a new draggable element, you don't need to specify the position value (but you need to specify the position name if you want to use the frontmatter). Slidev will automatically generate the initial position value for you. ## Automatic Height You can set `Height` to `NaN` (in) or `_` (if you use the component) to make the height of the draggable element automatically adjust to its content. ## Controls - Double-click the draggable element to start dragging it. - You can also use the arrow keys to move the element. - Hold `Shift` while dragging to preserve its aspect ratio. - Click outside the draggable element to stop dragging it. ## Draggable Arrow The `` component creates a draggable arrow element. Simply use it like this: ```md ``` And you will get a draggable arrow element. Other props are the same as [the `Arrow` component](/builtin/components#arrow). ================================================ FILE: docs/features/drawing.md ================================================ --- depends: - guide/ui#navigation-bar relates: - drauu: https://github.com/antfu/drauu tags: [drawing] description: | Draw and annotate your slides with ease. --- # Drawing & Annotations Slidev comes with a built-in drawing and annotation feature powered by [drauu](https://github.com/antfu/drauu). It allows you to draw and annotate your slides with ease. To start, click the icon in the [navigation bar](../guide/ui#navigation-bar) to open the drawing toolbar. It's also available in the [Presenter Mode](/guide/ui#presenter-mode). Drawings and annotations you created will be **synced** automatically across all instances in real-time. ## Use with Stylus Pen When using a stylus pen on a tablet (for example, iPad with Apple Pencil), Slidev will intelligently detect the input type. You can directly draw on your slides with the pen without turning on the drawing mode while having your fingers or mouse control the navigation. ## Persist Drawings The following frontmatter configuration allows you to persist your drawings as SVGs under `.slidev/drawings` directory and have them inside your exported PDF or hosted site. ```md --- drawings: persist: true --- ``` ## Disable Drawings Entirely: ```md --- drawings: enabled: false --- ``` Only in Development: ```md --- drawings: enabled: dev --- ``` Only in Presenter Mode: ```md --- drawings: presenterOnly: true --- ``` ## Drawing Syncing By default, Slidev syncs up your drawings across all instances. If you are sharing your slides with others, you might want to disable the syncing via: ```md --- drawings: syncAll: false --- ``` With this config, only the drawing from the presenter instance will be able to sync with others. ================================================ FILE: docs/features/eject-theme.md ================================================ --- depends: - guide/theme-addon tags: [theme, cli] description: | Eject the installed theme from your project to customize it. --- # Eject Theme If you want to get full control of the current theme, you can **eject** it to your local file system and modify it as you want. By running the following command ```bash $ slidev theme eject ``` It will eject the theme you are using currently into `./theme`, and change your frontmatter to ```yaml --- theme: ./theme --- ``` This could also be helpful if you want to make a theme based on an existing one. If you do, remember to mention the original theme and the author :) For more options of the `theme` command, please refer to the [Theme Command](../builtin/cli#theme) section. ================================================ FILE: docs/features/frontmatter-merging.md ================================================ --- depends: - guide/syntax#importing-slides - features/importing-slides tags: [syntax] description: | Merge frontmatter from multiple markdown files. --- # Frontmatter Merging You can provide frontmatter instructions from both your main entry and external markdown pages. If there are duplicate keys in them, the ones from the **main entry have the higher priority**. For example: ::: code-group ```md [./slides.md] --- src: ./cover.md background: https://sli.dev/bar.png // [!code highlight] class: text-center --- ``` ```md [./cover.md] --- layout: cover background: https://sli.dev/foo.png // [!code highlight] --- # Cover Cover Page ``` ::: They will end up being equivalent to the following page: ```md --- layout: cover background: https://sli.dev/bar.png // [!code highlight] class: text-center --- # Cover Cover Page ``` ================================================ FILE: docs/features/global-layers.md ================================================ --- tags: [navigation, layout] description: | Create custom components that persist across slides. --- # Global Layers Global layers allow you to have custom components that **persist** across slides. This could be useful for having footers, cross-slide animations, global effects, etc. Slidev provides three layers for this usage, create `global-top.vue`, `global-bottom.vue`, or `custom-nav-controls.vue` under your project root and it will pick up automatically. There are also layers for **each** slide: `slide-top.vue` and `slide-bottom.vue`. The usage is similar to the global layers, but they are applied to every slide, so there may be more than one instance of them. ::: tip If you are using `global-top.vue` or `global-bottom.vue` depending on the current navigation state, when exporting, the `--per-slide` option should be used to ensure the correct state is applied to each slide. Or you can use `slide-top.vue` and `slide-bottom.vue` instead. ::: ## Layers relationship At z-axis, from top to bottom: - NavControls - Customized Navigation Controls (`custom-nav-controls.vue`) - Global Top (`global-top.vue`) - single instance - Slide Top (`slide-top.vue`) - instance per slide - Slide Content - Slide Bottom (`slide-bottom.vue`) - instance per slide - Global Bottom (`global-bottom.vue`) - single instance ## Example ```html ``` The text `Your Name` will appear on all your slides. ```html ``` The button `Next` will appear in NavControls. To enable it conditionally, you can use the ```html ``` ```html ``` ```html ``` ```html ``` ================================================ FILE: docs/features/icons.md ================================================ --- relates: - Iconify: https://iconify.design/ - Icones: https://icones.js.org/ - unplugin-icons: https://github.com/antfu/unplugin-icons tags: [components] description: | Use icons from virtually all open-source icon sets directly in your markdown. --- # Icons Slidev allows you to have access to virtually all open-source icon sets **directly** in your markdown after installing the corresponding package. Powered by [`unplugin-icons`](https://github.com/antfu/unplugin-icons) and [Iconify](https://iconify.design/). The naming follows [Iconify](https://iconify.design/)'s convention of `{collection-name}-{icon-name}`. For example: - `` - from [Material Design Icons](https://github.com/Templarian/MaterialDesign) - [`@iconify-json/mdi`](https://npmjs.com/package/@iconify-json/mdi) - `` - from [Carbon](https://github.com/carbon-design-system/carbon/tree/main/packages/icons) - [`@iconify-json/carbon`](https://npmjs.com/package/@iconify-json/carbon) - `` - from [Unicons Monochrome](https://github.com/Iconscout/unicons) - [`@iconify-json/uim`](https://npmjs.com/package/@iconify-json/uim) - `` - from [Twemoji](https://github.com/twitter/twemoji) - [`@iconify-json/twemoji`](https://npmjs.com/package/@iconify-json/twemoji) - `` - from [SVG Logos](https://github.com/gilbarbara/logos) - [`@iconify-json/logos`](https://npmjs.com/package/@iconify-json/logos) - And much more... ::: code-group ```bash [pnpm] pnpm add @iconify-json/[the-collection-you-want] ``` ```bash [npm] npm install @iconify-json/[the-collection-you-want] ``` ```bash [yarn] yarn add @iconify-json/[the-collection-you-want] ``` ```bash [bun] bun add @iconify-json/[the-collection-you-want] ``` ```bash [deno] deno add jsr:@iconify-json/[the-collection-you-want] ``` ::: We use [Iconify](https://iconify.design) as our data source of icons. You need to install the corresponding icon-set in `dependencies` by following the `@iconify-json/*` pattern. For example, `@iconify-json/mdi` for [Material Design Icons](https://materialdesignicons.com/), `@iconify-json/tabler` for [Tabler](https://tabler-icons.io/). You can refer to [Icônes](https://icones.js.org/) or [Iconify](https://icon-sets.iconify.design/) for all the collections available. ### Styling Icons You can style the icons just like other HTML elements. For example: ```html ``` ================================================ FILE: docs/features/import-snippet.md ================================================ --- relates: - features/monaco-write - features/monaco-editor since: v0.47.0 tags: [codeblock, syntax] description: | Import code snippets from existing files into your slides. --- # Import Code Snippets You can import code snippets from existing files via the following syntax: ```md <<< @/snippets/snippet.js ``` ::: tip The value of `@` corresponds to your package's root directory. It's recommended to put snippets in `@/snippets` in order to be compatible with the Monaco editor. Alternatively, you can also import from relative paths. ::: You can also use a [VS Code region](https://code.visualstudio.com/docs/editor/codebasics#_folding) to only include the corresponding part of the code file: ```md <<< @/snippets/snippet.js#region-name ``` To explicitly specify the language of the imported code, you can add a language identifier after: ```md <<< @/snippets/snippet.js ts ``` Any code block features like [line highlighting](#line-highlighting) and [Monaco editor](#monaco-editor) are also supported: ```md <<< @/snippets/snippet.js {2,3|5}{lines:true} <<< @/snippets/snippet.js ts {monaco}{height:200px} ``` Note that you can use `{*}` as a placeholder of : ```md <<< @/snippets/snippet.js {*}{lines:true} ``` ================================================ FILE: docs/features/importing-slides.md ================================================ --- relates: - features/frontmatter-merging tags: [syntax] description: | Split your `slides.md` into multiple files for better reusability and organization. --- # Importing Slides You can split your `slides.md` into multiple files for better reusability and organization. To do this, you can use the `src` frontmatter option to specify the path to the external markdown file. For example: ::: code-group ```md [./slides.md] # Title This is a normal page --- src: ./pages/toc.md // [!code highlight] --- Contents here are ignored --- # Page 4 Another normal page --- src: ./pages/toc.md # Reuse the same file // [!code highlight] --- ``` ```md [./pages/toc.md] # Table of Contents Part 1 --- # Table of Contents Part 2 ``` ::: ## Importing Specific Slides To reuse some of the slides inside another Markdown file, you can use the hash part of the import path: ```md --- src: ./another-presentation.md#2,5-7 --- ``` This will import the slides 2, 5, 6, and 7 from `./another-presentation.md`. ## Frontmatter Merging ================================================ FILE: docs/features/index.data.ts ================================================ import { basename } from 'node:path' import { createContentLoader } from 'vitepress' export interface Feature { name: string title: string link: string description: string depends: string[] relates: string[] derives: string[] tags: string[] since?: string } export default createContentLoader('features/*.md', { includeSrc: true, transform(data) { const derivesMap: Record = {} for (const md of data) { const name = basename(md.url, '.md') if (name === 'index' || name === 'features') continue for (const depend of md.frontmatter.depends ?? []) { const dependName = depend.match(/\/([\w-]+)($|#)/)?.[1] if (dependName) { derivesMap[dependName] ??= [] derivesMap[dependName].push(`features/${name}`) } } } const result: Record = {} for (const md of data) { const name = basename(md.url, '.md') if (name === 'index' || name === 'features') continue const title = md.src?.match(/^# (.*)$/m)?.[1]?.trim() ?? name const derives = md.frontmatter.derives ?? [] for (const d of derivesMap[name] ?? []) { if (!derives.includes(d)) { derives.push(d) } } result[name] = { name, title, link: `/features/${name}.html`, description: md.frontmatter.description ?? '', depends: md.frontmatter.depends ?? [], relates: md.frontmatter.relates ?? [], derives, tags: md.frontmatter.tags ?? [], since: md.frontmatter.since, } } return result }, }) export declare const data: Record ================================================ FILE: docs/features/index.md ================================================ --- editLink: false footer: false aside: false outline: false sidebar: false pageClass: all-features-page --- # Features This is a list of all the individual features that Slidev provides. Each feature can be used independently and is optional. You can also read to learn the features by topic.
    No results found
    ================================================ FILE: docs/features/latex.md ================================================ --- relates: - Demo: /demo/starter/11 - KaTeX: https://katex.org/ tags: [codeblock, syntax] description: | Slidev comes with LaTeX support out-of-box, powered by KaTeX. --- # LaTeX Slidev comes with LaTeX support out-of-box, powered by [KaTeX](https://katex.org/). ## Inline Surround your LaTeX with a single `$` on each side for inline rendering. ```md $\sqrt{3x-1}+(1+x)^2$ ``` ## Block Use two (`$$`) for block rendering. This mode uses bigger symbols and centers the result. ```latex $$ \begin{aligned} \nabla \cdot \vec{E} &= \frac{\rho}{\varepsilon_0} \\ \nabla \cdot \vec{B} &= 0 \\ \nabla \times \vec{E} &= -\frac{\partial\vec{B}}{\partial t} \\ \nabla \times \vec{B} &= \mu_0\vec{J} + \mu_0\varepsilon_0\frac{\partial\vec{E}}{\partial t} \end{aligned} $$ ``` ## Line Highlighting To highlight specific lines, simply add line numbers within bracket `{}`. Line numbers start counting from 1 by default. ```latex $$ {1|3|all} \begin{aligned} \nabla \cdot \vec{E} &= \frac{\rho}{\varepsilon_0} \\ \nabla \cdot \vec{B} &= 0 \\ \nabla \times \vec{E} &= -\frac{\partial\vec{B}}{\partial t} \\ \nabla \times \vec{B} &= \mu_0\vec{J} + \mu_0\varepsilon_0\frac{\partial\vec{E}}{\partial t} \end{aligned} $$ ``` The `at` and `finally` options of [code blocks](#line-highlighting) are also available for LaTeX blocks. ## Chemical equations To enable the rendering of chemical equations, the [mhchem](https://github.com/KaTeX/KaTeX/tree/main/contrib/mhchem) KaTeX extension needs to be loaded. Create `vite.config.ts` with the following content: ```ts import 'katex/contrib/mhchem' export default {} ``` Now chemical equations can be rendered properly. ```latex $$ \displaystyle{\ce{B(OH)3 + H2O <--> B(OH)4^- + H+}} $$ ``` Learn more: [Syntax](https://mhchem.github.io/MathJax-mhchem) --- ================================================ FILE: docs/features/line-highlighting.md ================================================ --- depends: - guide/syntax#code-block - guide/animations tags: [codeblock, animation] description: | Highlight specific lines in code blocks based on clicks. --- # Line Highlighting To highlight specific lines, simply add line numbers within brackets `{}`. Line numbers start counting from 1 by default. ````md ```ts {2,3} function add( a: Ref | number, b: Ref | number ) { return computed(() => unref(a) + unref(b)) } ``` ```` ## Dynamic Line Highlighting To change what's highlighted with multiple clicks, you can use `|` to separate each stage: ````md ```ts {2-3|5|all} function add( a: Ref | number, b: Ref | number ) { return computed(() => unref(a) + unref(b)) } ``` ```` This will first highlight `a: Ref | number` and `b: Ref | number`, and then `return computed(() => unref(a) + unref(b))` after one click, and lastly, the whole block. You can set the line number to `hide` to hide the code block or `none` to not highlight any line: ````md ```ts {hide|none} function add( a: Ref | number, b: Ref | number ) { return computed(() => unref(a) + unref(b)) } ``` ```` ::: tip Learn more in the [click animations guide](/guide/animations#positioning). ::: ================================================ FILE: docs/features/mermaid.md ================================================ --- relates: - Mermaid: https://mermaid.js.org/ - Mermaid Live Editor: https://mermaid.live/ - Demo Slide: https://sli.dev/demo/starter/12 - features/plantuml tags: [diagram] description: | Create diagrams/graphs from textual descriptions, powered by Mermaid. --- # Mermaid Diagrams You can also create diagrams/graphs from textual descriptions in your Markdown, powered by [Mermaid](https://mermaid.js.org/). Code blocks marked as `mermaid` will be converted to diagrams, for example: ````md ```mermaid sequenceDiagram Alice->John: Hello John, how are you? Note over Alice,John: A typical interaction ``` ```` You can further pass an options object to it to specify the scaling and theming. The syntax of the object is a JavaScript object literal, you will need to add quotes (`'`) for strings and use comma (`,`) between keys. ````md ```mermaid {theme: 'neutral', scale: 0.8} graph TD B[Text] --> C{Decision} C -->|One| D[Result 1] C -->|Two| E[Result 2] ``` ```` Visit the [Mermaid Website](https://mermaid.js.org/) for more information. ================================================ FILE: docs/features/monaco-editor.md ================================================ --- depends: - guide/syntax#code-block relates: - Monaco Editor: https://microsoft.github.io/monaco-editor/ - Configure Monaco Editor: /custom/config-monaco tags: [codeblock, editor] description: | Turn code blocks into fully-featured editors, or generate a diff between two code blocks. --- # Monaco Editor Whenever you want to do some modification in the presentation, simply add `{monaco}` after the language id — it turns the block into a fully-featured Monaco editor! ````md ```ts {monaco} console.log('HelloWorld') ``` ```` Learn more about [Configuring Monaco](/custom/config-monaco). ## Diff Editor Monaco can also generate a diff between two code blocks. Use `{monaco-diff}` to turn the block into a [Monaco diff editor](https://microsoft.github.io/monaco-editor/playground.html?source=v0.36.1#example-creating-the-diffeditor-multi-line-example) and use `~~~` to separate the original and modified code! ````md ```ts {monaco-diff} console.log('Original text') ~~~ console.log('Modified text') ``` ```` ## Editor Height By default, the Monaco editor has a fixed height based on the initial content. If you start with an empty or small code block and want the editor to automatically grow as you type more code, you can set `{height:'auto'}`. ````md ```ts {monaco} {height:'auto'} // The editor will automatically grow as you type more code console.log('Hello, World!') ``` ```` You can also set a specific height using CSS units like `{height:'300px'}` or `{height:'100%'}`. ================================================ FILE: docs/features/monaco-run.md ================================================ --- depends: - features/monaco-editor - guide/animations relates: - Custom Code Runners: /custom/config-code-runners since: v0.48.0 tags: [codeblock, editor] description: | Run code directly in the editor and see the result. --- # Monaco Runner Slidev also provides the Monaco Runner Editor, which allows you to run the code directly in the editor and see the result. Use `{monaco-run}` to turn the block into a Monaco Runner Editor. ````md ```ts {monaco-run} function distance(x: number, y: number) { return Math.sqrt(x ** 2 + y ** 2) } console.log(distance(3, 4)) ``` ```` It provides the editor with a "Run" button, and shows the result of the code execution right below the code block. You may also modify the code and the result will be re-evaluated on the fly. By default it will automatically run the code when the slide is loaded; if you want to instead explicitly trigger the run, you can set `{autorun:false}`. ````md ```ts {monaco-run} {autorun:false} console.log('Click the play button to run me') ``` ```` If you want to only show the output in certain clicks, you can use the `showOutputAt` prop. The value is the same as `v-click`. ````md ```ts {monaco-run} {showOutputAt:'+1'} console.log('Shown after 1 click') ``` ```` Currently, Slidev supports running JavaScript and TypeScript code out-of-box. Refer to [Custom Code Runners](/custom/config-code-runners) for custom language support. ================================================ FILE: docs/features/monaco-write.md ================================================ --- depends: - features/monaco-editor - features/import-snippet relates: - features/import-snippet - Custom Code Runners: /custom/config-code-runners since: v0.49.5 tags: [codeblock, editor] description: | A monaco editor that allows you to write code directly in the slides and save the changes back to the file. --- # Writable Monaco Editor You can also use the [Import Code Snippets](#import-code-snippets) syntax combined with the `{monaco-write}` directive, to link your Monaco Editor with a file on your filesystem. This will allow you to edit the code directly in the editor and save the changes back to the file. ```md <<< ./some-file.ts {monaco-write} ``` When using this, be sure to back up your files beforehand, as the changes will be saved directly to the file. ================================================ FILE: docs/features/notes-auto-ruby.md ================================================ --- tags: [notes, presenter] description: Automatically add `` tags to your notes. --- # Notes Auto Ruby > Available since v52.4.0 When you write notes in your slides, you might want to add some ruby text to help pronouncing the some words. You can always add `` tags to your notes manually, but Slidev also provides a convenient way to do this automatically by a global auto-replacement. In the headmatter, you can set the `notesAutoRuby` option to a map of words to their ruby text: ```md --- notesAutoRuby: 日本語: ni hon go 勉強: べんきょう --- # Your slides here ``` And the notes will be rendered as:

    私は日本語ni hon go勉強べんきょうしています。

    ================================================ FILE: docs/features/og-image.md ================================================ --- relates: - features/seo-meta tags: ['SEO', head] description: | Set the Open Graph image for your slides. --- # Open Graph Image Slidev allows you to set the Open Graph image via the `seoMeta.ogImage` option in the headmatter: ```md --- seoMeta: ogImage: https://url.to.your.image.png --- # Your slides here ``` Learn more about [SEO Meta Tags](./seo-meta). ## Local Image If you have `./og-image.png` in your project root, Slidev will grab it as the Open Graph image automatically without any configuration. ## Auto-generate Since v52.1.0, Slidev supports auto-generating the Open Graph image from the first slide. You can set `seoMeta.ogImage` to `auto` to enable this feature. ```md --- seoMeta: ogImage: auto --- ``` It will use [playwright](https://playwright.dev/) to capture the first slide and save it as `./og-image.png` (same as `slidev export`). You may also commit the generated image to your repository to avoid the auto-generation. Or if you generate it on CI, you might also want to setup the playwright environment. ================================================ FILE: docs/features/plantuml.md ================================================ --- relates: - Plant UML: https://plantuml.com/ - Plant UML Live Editor: https://plantuml.com/plantuml - Example Slide: https://sli.dev/demo/starter/12 - features/mermaid tags: [diagram] description: | Create diagrams from textual descriptions, powered by PlantUML. --- # PlantUML Diagrams You can create PlantUML diagrams easily in your slides, for example: ````md ```plantuml @startuml Alice -> Bob : Hello! @enduml ``` ```` The source code will be sent to https://www.plantuml.com/plantuml to render the diagram by default. You can also set up your own server by setting the `plantUmlServer` in the [Slidev configuration](../custom/index#headmatter). Visit the [PlantUML Website](https://plantuml.com/) for more information. ================================================ FILE: docs/features/prettier-plugin.md ================================================ --- relates: - features/block-frontmatter - GitHub Repo: https://github.com/slidevjs/prettier-plugin - Prettier: https://prettier.io/ tags: [editor] description: | Use the Prettier plugin to format your slides. --- # Prettier Plugin The Slidev's syntax may be incompatible with the default Markdown parser of [Prettier](https://prettier.io/). To solve this, Slidev provides a Prettier plugin to format your slides. You can use it with your favorite editor that supports Prettier. ## 1. Install ::: code-group ```bash [npm] npm i -D prettier prettier-plugin-slidev ``` ```bash [pnpm] pnpm i -D prettier prettier-plugin-slidev ``` ```bash [yarn] yarn add -D prettier prettier-plugin-slidev ``` ```bash [bun] bun add -D prettier prettier-plugin-slidev ``` ```bash [deno] deno add -D npm:prettier npm:prettier-plugin-slidev ``` ::: ## 2. Activate the plugin Create or modify your [prettier configuration file](https://prettier.io/docs/en/configuration) to activate the plugin: ```json { "overrides": [ { "files": ["slides.md", "pages/*.md"], "options": { "parser": "slidev", "plugins": ["prettier-plugin-slidev"] } } ] } ``` Note that only specifying `plugins` is not enough, because Slidev and common Markdown files share the same file extension `.md`. ================================================ FILE: docs/features/recording.md ================================================ --- depends: - guide/ui#navigation-bar relates: - RecordRTC: https://github.com/muaz-khan/RecordRTC - WebRTC API: https://webrtc.org/ tags: [presenter, tool] description: | Record your presentation with the built-in camera view and recording feature. --- # Recording Slidev comes with a built-in camera view and recording feature. They make it simple for you to record your presentation without having to switch between other recording tools while delivering a presentation. ## Camera View {#camera-view} Click the button in the [navigation bar](../guide/ui#navigation-bar) to show your camera view in the presentation. You can drag it to move it, and use the handler on the right bottom corner to resize it. The size and position will persist across reloads. ## Start Recording {#start-recording} Clicking the button in the [navigation bar](../guide/ui#navigation-bar) will bring up a dialog for you. Here you can choose to either record your camera output embedded in your slides or to separate them into two video files. This feature is powered by [RecordRTC](https://github.com/muaz-khan/RecordRTC) and uses the [WebRTC API](https://webrtc.org/). ![](/screenshots/recording.png) ================================================ FILE: docs/features/remote-access.md ================================================ --- relates: - guide/ui - CLI: builtin/cli - Cloudflare Quick Tunnels: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/ tags: [remote, tool] description: | Access your presentation remotely with Slidev's remote access feature. --- # Remote Access You can run your presentation with remote access by using the `--remote` flag: ::: code-group ```bash [pnpm] pnpm dev --remote # i.e. slidev --remote ``` ```bash [npm] npm run dev -- --remote # i.e. slidev --remote ``` ```bash [yarn] yarn dev --remote # i.e. slidev --remote ``` ```bash [bun] bun dev --remote # i.e. slidev --remote ``` ```bash [deno] deno run dev --remote # i.e. slidev --remote ``` ::: ## Password Protection If you want to share your slides but don't want other people to access the presenter mode, you can pass a password to the option, i.e. `--remote=your_password`. Then the password is required when accessing the presenter mode. ## Remote Tunnel You can open a [Cloudflare Quick Tunnels](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/) to expose your local server to the internet. This way, you can share your slides with others without setting up a server. ::: code-group ```bash [pnpm] pnpm dev --remote --tunnel # i.e. slidev --remote --tunnel ``` ```bash [npm] npm run dev -- --remote --tunnel # i.e. slidev --remote --tunnel ``` ```bash [yarn] yarn dev --remote --tunnel # i.e. slidev --remote --tunnel ``` ```bash [bun] bun dev --remote --tunnel # i.e. slidev --remote --tunnel ``` ```bash [deno] deno run dev --remote --tunnel # i.e. slidev --remote --tunnel ``` ::: ================================================ FILE: docs/features/rough-marker.md ================================================ --- depends: - guide/animations relates: - Rough Notation: https://github.com/slidevjs/rough-notation since: v0.48.0 tags: [drawing, animation] description: | Integrate Rough Notation to allow marking or highlighting elements in your slides. --- # Rough Markers Slidev integrates [Rough Notation](https://github.com/slidevjs/rough-notation) to allow marking or highlighting elements in your slides. --- ### `v-mark` directive Rough Notation integration comes with the `v-mark` directive. #### Type Use `v-mark.underline` for the underline mark, `v-mark.circle` for the circle mark, etc. (defaults to `underline`). #### Color `v-mark.red` makes the notation `red`. Supported built-in color themes from UnoCSS. For custom colors, use object syntax `v-mark="{ color: '#234' }"`. #### Clicks `v-mark` works like `v-click` and will trigger after a click. Same as `v-click`, it allows you to pass a custom click value, like `v-mark="5"` or `v-mark="'+1'"`. #### Options Optionally, you can pass an object to `v-mark` to specify the options, for example: ```vue Important text ``` #### Preview ================================================ FILE: docs/features/seo-meta.md ================================================ --- depends: - custom/index#headmatter relates: - features/og-image tags: [SEO, head] description: | Configure SEO meta tags for better social media sharing and search engine optimization. --- # SEO Meta Tags Slidev allows you to configure SEO meta tags in the headmatter to improve social media sharing and search engine optimization. You can set up Open Graph and Twitter Card meta tags to control how your slides appear when shared on social platforms. ## Configuration Add the `seoMeta` configuration to your slides deck frontmatter: ```yaml --- # SEO meta tags seoMeta: ogTitle: Slidev Starter Template ogDescription: Presentation slides for developers ogImage: https://cover.sli.dev ogUrl: https://example.com twitterCard: summary_large_image twitterTitle: Slidev Starter Template twitterDescription: Presentation slides for developers twitterImage: https://cover.sli.dev twitterSite: username twitterUrl: https://example.com --- ``` This feature is powered by [unhead](https://unhead.unjs.io/)'s `useHead` hook, please refer to the [documentation](https://unhead.unjs.io/docs/head/api/composables/use-seo-meta) for more details. ================================================ FILE: docs/features/shiki-magic-move.md ================================================ --- depends: - guide/syntax#code-block - guide/animations relates: - Shiki Magic Move: https://github.com/shikijs/shiki-magic-move since: v0.48.0 tags: [codeblock, animation] description: | Enable granular transition between code changes, similar to Keynote's Magic Move. --- # Shiki Magic Move [Shiki Magic Move](https://github.com/shikijs/shiki-magic-move) enables you to have a granular transition between code changes, similar to Keynote's Magic Move. You can check [the playground](https://shiki-magic-move.netlify.app/) to see how it works. In Slidev, we bind the magic-move to the [clicks system](/guide/animations#click-animation). The syntax is to wrap multiple code blocks representing each step with ````md magic-move (mind it's **4** backticks), this will be transformed into one code block, that morphs to each step as you click. `````md ````md magic-move ```js console.log(`Step ${1}`) ``` ```js console.log(`Step ${1 + 1}`) ``` ```ts console.log(`Step ${3}` as string) ``` ```` ````` It's also possible to mix Magic Move with and , for example: `````md ````md magic-move {at:4, lines: true} // [!code hl] ```js {*|1|2-5} // [!code hl] let count = 1 function add() { count++ } ``` Non-code blocks in between as ignored, you can put some comments. ```js {*}{lines: false} // [!code hl] let count = 1 const add = () => count += 1 ``` ```` ````` ## Title Bar {#title-bar} > Available since v0.52.0 You can add a title bar to magic move blocks by specifying a filename in the opening fence of each step: `````md ````md magic-move ```js [app.js] console.log('Step 1') ``` ```js [app.js] console.log('Step 2') ``` ```` ````` The title bar will also display an automatically matched icon based on the filename (see ). ## Animation Duration {#duration} > Available since v0.52.0 You can customize the animation duration for magic move transitions globally via the headmatter: ```yaml --- magicMoveDuration: 500 # duration in milliseconds, default is 800 --- ``` Or per-block by passing the `duration` option: `````md ````md magic-move {duration:500} ```js console.log('Step 1') ``` ```js console.log('Step 2') ``` ```` ````` ## Copy Button {#copy-button} > Available since v0.52.0 Magic move code blocks support a copy button that appears on hover. Configure this behavior globally with the `magicMoveCopy` headmatter option: ```yaml --- # Options: true | false | 'always' | 'final' magicMoveCopy: true # show copy button on all steps (default) magicMoveCopy: false # disable copy button magicMoveCopy: 'final' # only show copy button on the final step --- ``` The copy button respects the global `codeCopy` setting. If `codeCopy` is `false`, the magic move copy button will also be disabled. ================================================ FILE: docs/features/side-editor.md ================================================ --- depends: - guide/ui#navigation-actions relates: - features/vscode-extension tags: [editor] description: | Edit your slides source file alongside the presentation. --- # Integrated Editor Slidev comes with an integrated editor that will instantly reload and save the changes to your file. Click the button on the navigation panel to open it. ![](/screenshots/integrated-editor.png) ================================================ FILE: docs/features/slide-hook.md ================================================ --- depends: - guide/global-context tags: [client-api] description: | Hooks to manage the slide lifecycle. --- # Slide Hooks Slidev provides a set of hooks to help you manage the slide lifecycle: ```ts twoslash import { onSlideEnter, onSlideLeave, useIsSlideActive } from '@slidev/client' const isActive = useIsSlideActive() onSlideEnter(() => { /* Called whenever the slide becomes active */ }) onSlideLeave(() => { /* Called whenever the slide becomes inactive */ }) ``` You can also use to access other useful context information. ::: warning In the slide component, `onMounted` and `onUnmounted` hooks are not available, because the component instance is preserved even when the slide is not active. Use `onSlideEnter` and `onSlideLeave` instead. ::: ================================================ FILE: docs/features/slide-scope-style.md ================================================ --- relates: - Vue's Scoped CSS: https://vuejs.org/api/sfc-css-features.html#scoped-css - UnoCSS directives: https://unocss.dev/transformers/directives tags: [styling, syntax] description: | Define styles for only the current slide. --- # Slide Scope Styles You can use the ` --- # Other slides are not affected ``` The ` ``` ================================================ FILE: docs/features/slot-sugar.md ================================================ --- relates: - Vue's Named Slots: https://v3.vuejs.org/guide/component-slots.html tags: [layout, syntax] description: | A syntax sugar for named slots in layouts. --- # Slot Sugar for Layouts Some layouts can provide multiple contributing points using [Vue's named slots](https://vuejs.org/guide/components/slots.html). For example, in [`two-cols` layout](https://github.com/slidevjs/slidev/blob/main/packages/client/layouts/two-cols.vue), you can have two columns left (`default` slot) and right (`right` slot) side by side. ```md --- layout: two-cols --- ```

    Left

    This shows on the left

    Right

    This shows on the right

    We also provide a shorthand syntactical sugar `::name::` for slot name. The following works exactly the same as the previous example. ```md --- layout: two-cols --- # Left This is shown on the left ::right:: # Right This is shown on the right ``` You can also explicitly specify the default slot and provide it in the custom order. ```md --- layout: two-cols --- ::right:: # Right This shows on the right ::default:: # Left This is shown on the left ``` ================================================ FILE: docs/features/timer.md ================================================ --- tags: [presenter] description: Timer for the presenter mode. --- # Presenter Timer Slidev provides a timer for the presenter mode. You can start, pause, and reset the timer. It will show a timer (in stopwatch or countdown mode), and a progress bar in the presenter mode. ## Configuration You can set the duration of the presentation in the headmatter. Default is `30min`. ```yaml --- # duration of the presentation, default is '30min' duration: 30min # timer mode, can be 'countdown' or 'stopwatch', default is 'stopwatch' timer: stopwatch --- ``` ================================================ FILE: docs/features/transform-component.md ================================================ --- relates: - guide/faq#adjust-size - features/canvas-size - features/zoom-slide tags: [layout] description: | A component for scaling some elements. --- # The `Transform` Component The `Transform` component allows you to scale the size of the elements on your slides: ```md ``` This is useful when you want to adjust the size of some elements on your slides without affecting the layout of the entire slide. To scale all the slides in your presentation, you can set the slide canvas size: To scale several slides in your presentation, you can use the `zoom` option: ================================================ FILE: docs/features/twoslash.md ================================================ --- depends: - guide/syntax#code-block relates: - TwoSlash: https://twoslash.netlify.app/ since: v0.46.0 tags: [codeblock] description: | A powerful tool for rendering TypeScript code blocks with type information on hover or inlined. --- # TwoSlash Integration [TwoSlash](https://twoslash.netlify.app/) is a powerful tool for rendering TypeScript code blocks with type information on hover or inlined. It's quite useful for preparing slides for JavaScript/TypeScript-related topics. To use it, you can add `twoslash` to the code block's language identifier: ````md ```ts twoslash import { ref } from 'vue' const count = ref(0) // ^? ``` ```` It will be rendered as: ```ts twoslash import { ref } from 'vue' const count = ref(0) // ^? ```
    ================================================ FILE: docs/features/vscode-extension.md ================================================ --- relates: - VS Code: https://code.visualstudio.com/ - View in Marketplace: https://marketplace.visualstudio.com/items?itemName=antfu.slidev - View in OVSX: https://open-vsx.org/extension/antfu/slidev tags: [editor] description: | Help you better organize your slides and have a quick overview of them. --- # VS Code Extension

    Slidev

    Visual Studio Marketplace Version   Visual Studio Marketplace Downloads The VS Code extension provides some features to help you better organize your slides and have a quick overview of them. ### Features - Preview slides in the side panel - Slides tree view with slide numbers - Re-ordering slides via drag and drop - Folding for slide blocks - Multiple slides project support - Start the dev server with one click - AI/Copilot integration via Language Model Tools ![](https://github.com/slidevjs/slidev/assets/63178754/2c9ba01a-d21f-4b33-b6b6-4e249873f865) ### Installation You can install the extension from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=antfu.slidev) or the [Open VSX Registry](https://open-vsx.org/extension/antfu/slidev). ### Usage Click the `Slidev` icon in the activity bar to open the **Slidev panel**. In the Slidev panel, you can see the projects tree view, slides tree view, and the preview webview. In the **projects tree view**, you can see all the Slidev projects in your workspace. You can click the item to open the corresponding file, and click the icon over it to switch the active project. The icon allows you to load a slides project that wasn't scanned automatically. In the **slides tree view**, you can see all the slides in the active project. You can click the item to move your cursor to the slide in the editor, and drag and drop to reorder the slides. In the **preview webview**, you can click the icon to start the dev server and click the icon to open the slides in the browser. Toggle icon to sync/unsync the preview navigation with the editor cursor. There are also some **commands** you can use. Type `Slidev` in the command palette to see them. You can add glob patterns to the `slidev.include` configuration to include files as Slidev entries. The default value is `["**/*.md"]`. Example: ```json { "slidev.include": ["**/presentation.md"] } ``` #### Dev Command {#dev-command} You can customize the command to start dev server by setting the `slidev.dev-command` configuration. The default value is `npm exec -c 'slidev ${args}'`. The configured command can contain placeholders: - `${args}`: All CLI arguments. e.g. `slides.md --port 3000 --remote` - `${port}`: The port number. e.g. `3000` Examples: - Global installation: `slidev ${args}` - For PNPM users, you can set it to `pnpm slidev ${args}`. - For [code-server](https://coder.com/docs/code-server/) users, you can set it to `pnpm slidev ${args} --base /proxy/${port}/`. This will make the dev server accessible at `http://localhost:8080/proxy/3000/`. #### Slides Tree View {#slides-tree} > Available since v0.52.0 The slides tree view shows all slides in your presentation with their slide numbers and titles. Each slide is displayed as `{slideNo}. {title}` making it easy to navigate to specific slides. #### AI/Copilot Integration {#ai-integration} > Available since v0.52.0 The extension provides Language Model Tools that allow VSCode's Copilot and other AI assistants to interact with your Slidev project. The following tools are available: - `slidev_getActiveSlide` - Get information about the current active slide and project - `slidev_getSlideContent` - Retrieve the content of a specific slide by number - `slidev_getAllSlideTitles` - List all slide titles in the presentation - `slidev_findSlideNoByTitle` - Find a slide number by its title - `slidev_listEntries` - List all loaded Slidev project entries - `slidev_getPreviewPort` - Get the preview server port for a project - `slidev_chooseEntry` - Switch the active Slidev entry These tools enable AI assistants to help you navigate, edit, and understand your slides more effectively. ================================================ FILE: docs/features/zoom-slide.md ================================================ --- relates: - guide/faq#adjust-size - features/canvas-size - features/transform-component tags: [layout] description: | Zoom the content of a slide to a specific scale. --- # Zoom Slides You may find some slides in your presentation too spacious or too crowded. Slidev provides a `zoom` option for each slide that allows you to scale the content of a slide: ```md --- zoom: 0.8 --- # A Slide with lots of content --- # Other slides aren't affected ``` To scale all the slides in your presentation, you can set the slide canvas size: To adjust the size of some elements on your slides, you can use the `Transform` component: ================================================ FILE: docs/guide/animations.md ================================================ --- outline: deep --- # Animation Animation is an essential part of slide presentations. Slidev provides a variety of ways to animate your slides, from the simple to the complex. This guide will show you how to use them effectively. ## Click Animation {#click-animation} A "**click**" can be considered as the unit of animation steps in slides. A slide can have one or more clicks, and each click can trigger one or more animations - for example, revealing or hiding elements. > [!NOTE] > Since v0.48.0, we've rewritten the click animations system with much more consistent behaviors. It might change the behaviors of your existing slides in edge cases. While this page is showing the new click system, you can find more details about the refactor in [#1279](https://github.com/slidevjs/slidev/pull/1279). ### `v-click` {#v-click} To apply show/hide "click animations" for elements, you can use the `` component or the `v-click` directive. ```md Hello World!
    Hey!
    ``` ### `v-after` {#v-after} `v-after` will turn the element visible when the previous `v-click` is triggered. ```md
    Hello
    World
    ``` When you press "next", both `Hello` and `World` will show up together. ### Hide after clicking {#hide-after-clicking} Add a `.hide` modifier to `v-click` or `v-after` directives to make elements invisible after clicking, instead of showing up. ```md
    Visible after 1 click
    Hidden after 2 clicks
    Hidden after 2 clicks
    ``` For the components, you can use the `hide` prop to achieve the same effect: ```md Visible after 1 click Hidden after 2 clicks Also hidden after 2 clicks ``` ### `v-clicks` {#v-clicks} `v-clicks` is only provided as a component. It's a shorthand to apply the `v-click` directive to all its child elements. It is especially useful when working with lists and tables. ```md - Item 1 - Item 2 - Item 3 ``` An item will become visible each time you click "next". It accepts a `depth` prop for nested list: ```md - Item 1 - Item 1.1 - Item 1.2 - Item 2 - Item 2.1 - Item 2.2 ``` Also, you can use the `every` prop to specify the number of items to show after each click: ```md - Item 1.1 - Item 1.2 - Item 2.1 - Item 2.2 ``` ### Positioning {#positioning} By default, the clicking animations are triggered one by one. You can customize the animation "position" of elements by using the `at` prop or the `v-click` directive with value. Like the CSS layout system, click-animated elements can be "relative" or "absolute": #### Relative Position {#relative-position} This actual position of relative elements is calculated based on the previous relative elements: ````md
    visible after 1 click
    visible after 3 clicks
    hidden after 2 clicks
    ```js {none|1|2}{at:'+5'} 1 // highlighted after 7 clicks 2 // highlighted after 8 clicks ``` ```` > [!NOTE] > The default value of `v-click` is `'+1'` when you don't specify it. In fact, `v-after` are just shortcuts for `v-click` with `at` prop: ```md ``` ::: tip `at` prop value format Only string values starting with `'+'` or `'-'` like `'+1'` are treated as relative positions: | Value | Kind | | -------------- | -------- | | `'-1'`, `'+1'` | Relative | | `+1` === `1` | Absolute | | `'1'` | Absolute | So don't forget the single quotes for the relative values. ::: #### Absolute Position {#absolute-position} The given value is the exact click count to trigger this animation: ````md
    visible after 3 clicks
    visible after 2 clicks
    hidden after 1 click
    ```js {none|1|2}{at:3} 1 // highlighted after 3 clicks 2 // highlighted after 4 clicks ``` ```` #### Mixed Case {#mixed-case} You can mix the absolute and relative positions: ```md
    visible after 1 click
    visible after 3 clicks
    visible after 2 click
    visible after 1 click
    visible after 4 clicks
    ``` The following example synchronizes the highlighting of the two code blocks: ````md {1,6} ```js {1|2}{at:1} 1 + 1 'a' + 'b' ``` ```js {1|2}{at:1} = 2 = 'ab' ``` ```` ### Enter & Leave {#enter-leave} You can also specify the enter and leave index for the `v-click` directive by passing an array. The end index is exclusive. ```md
    This will be hidden at click 2 and 3 (and shown otherwise).
    This will be shown only at click 2 (and hidden otherwise).
    ``` You can also use `v-switch` to achieve the same effect: ```md ``` See [`VSwitch` Component](/builtin/components#vswitch) for more details. ### Custom Total Clicks Count {#total} By default, Slidev automatically calculates how many clicks are required before going to the next slide. You can override this via the `clicks` frontmatter option: ```yaml --- # 10 clicks in this slide, before going to the next slide clicks: 10 --- ``` ### Element Transitions {#element-transitions} When you apply the `v-click` directive to your elements, it will attach the class name `slidev-vclick-target` to it. When the elements are hidden, the class name `slidev-vclick-hidden` will also be attached. For example: ```html
    Text
    ``` After a click, it may become: ```html
    Text
    ``` By default, a subtle opacity transition is applied to those classes: ```css /* below shows the default style */ .slidev-vclick-target { transition: opacity 100ms ease; } .slidev-vclick-hidden { opacity: 0; pointer-events: none; } ``` You can override them to customize the transition effects in your custom stylesheets. For example, you can achieve the scaling up transitions by: ```css /* styles.css */ .slidev-vclick-target { transition: all 500ms ease; } .slidev-vclick-hidden { transform: scale(0); } ``` To specify animations for only certain slides or layouts: ```scss .slidev-page-7, .slidev-layout.my-custom-layout { .slidev-vclick-target { transition: all 500ms ease; } .slidev-vclick-hidden { transform: scale(0); } } ``` Learn more about [customizing styles](/custom/directory-structure#style). ## Motion {#motion} Slidev has [@vueuse/motion](https://motion.vueuse.org/) built-in. You can use the `v-motion` directive to any elements to apply motion to them. For example ```html
    Slidev
    ``` The text `Slidev` will move from `-80px` to its original position when entering the slide. When leaving, it will move to `80px`. > Before v0.48.9, you need to add `preload: false` to the slide's frontmatter to enable motion. ### Motion with Clicks {#motion-with-clicks} > Available since v0.48.9 You can also trigger the motion by clicks: ```html
    Slidev
    ``` Or combine `v-click` with `v-motion`: ```html
    Shown at click 2 and hidden at click 4.
    ``` The meanings of variants: - `initial`: When `currentPage < thisPage`, or `v-click` hides the current element because `$clicks` is too small. - `enter`: When `currentPage === thisPage`, and `v-click` shows the element. _Priority: lowest_ - `click-x`: `x` is a number representing the **absolute** click num. The variant will take effect if `$clicks >= x`. _Priority: `x`_ - `click-x-y`: The variant will take effect if `x <= $clicks < y`. _Priority: `x`_ - `leave`: `currentPage > thisPage`, or `v-click` hides the current element because `$clicks` is too large. The variants will be combined according to the priority defined above. ::: warning Due to a Vue internal [bug](https://github.com/vuejs/core/issues/10295), currently **only** `v-click` applied to the same element as `v-motion` can control the motion animation. As a workaround, you can use something like `v-if="3 < $clicks"` to achieve the same effect. ::: Learn more: [Demo](https://sli.dev/demo/starter/10) | [@vueuse/motion](https://motion.vueuse.org/) | [v-motion](https://motion.vueuse.org/features/directive-usage) | [Presets](https://motion.vueuse.org/features/presets) ## Slide Transitions {#slide-transitions}
    Slidev supports slide transitions out of the box. You can enable it by setting the `transition` frontmatter option: ```md --- transition: slide-left --- ``` This will give you a nice sliding effects on slide switching. Setting it in the headmatter will apply this to all slides. You can also set different transitions per slide in frontmatters. ### Builtin Transitions {#builtin-transitions} - `fade` - Crossfade in/out - `fade-out` - Fade out and then fade in - `slide-left` - Slides to the left (slide to right when going backward) - `slide-right` - Slides to the right (slide to left when going backward) - `slide-up` - Slides to the top (slide to bottom when going backward) - `slide-down` - Slides to the bottom (slide to top when going backward) - `view-transition` - Via the view transitions API ### View Transition API {#view-transitions} The View Transitions API provides a mechanism for easily creating animated transitions between different DOM states. Learn more about it in [View Transitions API - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API). :::warning Experimental: This is not supported by all browsers. Check the [Browser compatibility table](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API#browser_compatibility) carefully before using this. ::: You can use the `view-transition-name` CSS property to name view transitions, which creates connections between different page elements and smooth transitions when switching slides. You can enable [Comark Syntax](/guide/syntax#comark-syntax) support to conveniently name view-transitions: ```md --- transition: view-transition comark: true --- # View Transition {.inline-block.view-transition-title} --- # View Transition {.inline-block.view-transition-title} ``` ### Custom Transitions {#custom-transitions} Slidev's slide transitions are powered by [Vue Transition](https://vuejs.org/guide/built-ins/transition.html). You can provide your custom transitions by: ```md --- transition: my-transition --- ``` and then in your custom stylesheets: ```css .my-transition-enter-active, .my-transition-leave-active { transition: opacity 0.5s ease; } .my-transition-enter-from, .my-transition-leave-to { opacity: 0; } ``` Learn more about how it works in [Vue Transition](https://vuejs.org/guide/built-ins/transition.html). ### Forward & Backward Transitions {#forward-backward-transitions} You can specify different transitions for forward and backward navigation using `|` as a separator in the transition name: ```md --- transition: go-forward | go-backward --- ``` With this, when you go from slide 1 to slide 2, the `go-forward` transition will be applied. When you go from slide 2 to slide 1, the `go-backward` transition will be applied. ### Advanced Usage {#advanced-usage} The `transition` field accepts an option that will passed to the [``](https://vuejs.org/api/built-in-components.html#transition) component. For example: ```md --- transition: name: my-transition enterFromClass: custom-enter-from enterActiveClass: custom-enter-active --- ``` ================================================ FILE: docs/guide/component.md ================================================ # Components in Slides One of the most powerful features of Slidev is the ability to use Vue components directly in your slides. This allows you to create interactive and dynamic content with ease. ## Using Components {#use} With the help of [`unplugin-vue-components`](https://github.com/unplugin/unplugin-vue-components), Slidev allows you to use Vue components directly in your slides without importing them manually: ```md # My Slide ``` The components come from: - Built-in components. See [Built-in Components](../builtin/components) for reference. - Provided by the theme and addons. See . - Custom components in the `components` directory. See the next section. ## Writing Components {#write} To create a custom component, simply create a new Vue file in the `components` directory: ```bash your-slidev/ ├── ... ├── slides.md └── components/ ├── ... └── MyComponent.vue ``` Refer to the [Vue documentation](https://vuejs.org/guide/essentials/component-basics.html) for how to write Vue components. You can also to reuse and share your components with others. ================================================ FILE: docs/guide/exporting.md ================================================ --- outline: deep --- # Exporting Usually the slides are displayed in a web browser, but you can also export them to PDF, PPTX, PNG, or Markdown files for sharing or printing. This feature is available through the CLI command [`slidev export`](../builtin/cli#export). However, interactive features in your slides may not be available in the exported files. You can build and host your slides as a web application to keep the interactivity. See [Building and Hosting](./hosting) for more information. ## The Browser Exporter Recommended {#browser} > Available since v0.50.0-beta.11 Slidev provides a UI in the browser for exporting your slides. You can access it by clicking the "Export" button in "More options" menu in the [navigation bar](./ui#navigation-bar), or go to `http://localhost:/export` directly. In the UI, you can export the slides as PDF, or capture the slides as images and download them as a PPTX or zip file. Note that browsers other than **modern Chromium-based browsers** may not work well with the exporting UI. If you encounter any issues, please try use the CLI instead. > The following content of this page is for the CLI only. ## The CLI {#cli} Exporting to PDF, PPTX, or PNG relies on [Playwright](https://playwright.dev) for rendering the slides. Therefore [`playwright-chromium`](https://npmjs.com/package/playwright-chromium) is required to be installed in your project: ::: code-group ```bash [pnpm] $ pnpm add -D playwright-chromium ``` ```bash [npm] $ npm i -D playwright-chromium ``` ```bash [yarn] $ yarn add -D playwright-chromium ``` ```bash [bun] $ bun add -D playwright-chromium ``` ```bash [deno] $ deno add -D npm:playwright-chromium ``` ::: ## Formats ### PDF After installing `playwright-chromium` as described above, you can export your slides to PDF using the following command: ```bash $ slidev export ``` By default, the PDF will be placed at `./slides-export.pdf`. ### PPTX Slidev can also export your slides as a PPTX file: ```bash $ slidev export --format pptx ``` Note that all the slides in the PPTX file will be exported as images, so the text will not be selectable. Presenter notes will be conveyed into the PPTX file on a per-slide basis. In this mode, the `--with-clicks` option is enabled by default. To disable it, pass `--with-clicks false`. ### PNGs and Markdown When passing in the `--format png` option, Slidev will export PNG images for each slide instead of a PDF: ```bash $ slidev export --format png ``` You can also compile a markdown file composed of compiled png using `--format md`: ```bash $ slidev export --format md ``` ## Options Here are some common options you can use with the `slidev export` command. For a full list of options, see the [CLI documentation](../builtin/cli#export). ### Export Clicks Steps By default, Slidev exports one page per slide with clicks animations disabled. If you want to export slides with multiple steps into multiple pages, pass the `--with-clicks` option: ```bash $ slidev export --with-clicks ``` ### Output Filename You can specify the output filename with the `--output` option: ```bash $ slidev export --output my-pdf-export ``` Or in the headmatter configuration: ```yaml --- exportFilename: my-pdf-export --- ``` ### Export with Range By default, all slides in the presentation are exported. If you want to export a specific slide or a range of slides you can set the `--range` option and specify which slides you would like to export: ```bash $ slidev export --range 1,6-8,10 ``` This option accepts both specific slide numbers and ranges. The example above would export slides 1,6,7,8 and 10. ### Multiple Exports You can also export multiple slides at once: ```bash $ slidev export slides1.md slides2.md ``` Or (only available in certain shells): ```bash $ slidev export *.md ``` In this case, each input file will generate its own PDF file. ### Dark Mode In case you want to export your slides using the dark version of the theme, use the `--dark` option: ```bash $ slidev export --dark ``` ### Timeouts For big presentations, you might want to increase the Playwright timeout with `--timeout`: ```bash $ slidev export --timeout 60000 ``` ### Wait Some parts of your slides may require a longer time to render. You can use the `--wait` option to have an extra delay before exporting: ```bash $ slidev export --wait 10000 ``` There is also a `--wait-until` option to wait for a state before exporting each slide. If you keep encountering timeout issues, you can try setting this option: ```bash $ slidev export --wait-until none ``` Possible values: - `'networkidle'` - (_default_) consider operation to be finished when there are no network connections for at least `500` ms. This is the safest, but may cause timeouts. - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. - `'load'` - consider operation to be finished when the `load` event is fired. - `'none'` - do not wait for any event. ::: warning When specifying values other than `'networkidle'`, please make sure the printed slides are complete and correct. If some contents are missing, you may need to use the `--wait` option. ::: ### Executable Path Chromium may miss some features like codecs that are required to decode some videos. You can set the browser executable path for Playwright to your Chrome or Edge using `--executable-path`: ```bash $ slidev export --executable-path [path_to_chromium] ``` ### PDF Outline > Available since v0.36.10 You can generate the PDF outline by passing the `--with-toc` option: ```bash $ slidev export --with-toc ``` ### Omit Background When exporting to PNGs, you can remove the default browser background by passing `--omit-background`: ```bash $ slidev export --omit-background ``` The default browser background is the white background visible on all browser windows and is different than other backgrounds applied throughout the application using CSS styling. [See Playwright docs](https://playwright.dev/docs/api/class-page#page-screenshot-option-omit-background). You will then need to apply additional CSS styling to the application to reveal the transparency. Here is a basic example that covers all backgrounds in the application: ```css * { background: transparent !important; } ``` ## Troubleshooting ### Missing Content or Animation not Finished If you find that some content is missing or the animations are not finished in the exported PDF, you can try adding a wait time before exporting each slide: ```bash $ slidev export --wait 1000 ``` ### Broken Emojis If the PDF or PNG are missing Emojis, you are likely missing required fonts (such as. e.g. [Google's _Noto Emoji_](https://fonts.google.com/noto/specimen/Noto+Emoji)) in your environment. This can affect e.g. CI/CD-like in-container sort of Linux environments. It can be fixed e.g. like this: ```bash $ curl -L --output NotoColorEmoji.ttf https://github.com/googlefonts/noto-emoji/raw/main/fonts/NotoColorEmoji.ttf $ sudo mv NotoColorEmoji.ttf /usr/local/share/fonts/ $ fc-cache -fv ``` ### Wrong Context in Global Layers See the tip in https://sli.dev/features/global-layers. ================================================ FILE: docs/guide/faq.md ================================================ --- outline: deep --- # FAQ ## Assets Handling {#assets-handling} You may use static assets like images and videos in your slides. Since Slidev is based on Vite, you can import them directly in your markdown files. URLs that can be statically analyzed as assets can use relative paths: ```md ![alt](./image.png) ``` In the above case, the URLs will be resolved to `/BASE_URL/assets/image.png` after build. However, relative paths in frontmatter and other components will be broken after build: ```md --- background: ./image.png # Broken after build --- ``` In the above case, the URLs are not statically analyzable and will be preserved as-is, which will result in 404 errors after build. To solve this, you can place these assets in the [public folder](../custom/directory-structure#public) and use an absolute path to import them: ```md --- background: /image.png --- ``` For more details, refer to [Vite's documentation](https://vitejs.dev/guide/assets.html). ## Positioning {#positioning} Since Slidev is web-based, CSS is the primary way to position elements. Here are some useful tips for position elements: ### Grids And Flexboxes You can use CSS Grids to create complex layouts: ::: code-group ```md [Two columns]
    The first column
    The second column
    ``` ```md [Complex case]
    The first column (200px)
    The second column (auto fit)
    The third column (10% width to parent container)
    ``` ::: And use Flexboxes to create more responsive layouts: ::: code-group ```md [Horizontal]
    First block
    Second block
    ``` ```md [Vertical]
    Centered content
    ``` ::: Learn more: [CSS Grids](https://css-tricks.com/snippets/css/complete-guide-grid/), [flexboxes](https://css-tricks.com/snippets/css/a-guide-to-flexbox/), or even [Masonry](https://css-tricks.com/native-css-masonry-layout-in-css-grid/). ### Absolute Position You can use UnoCSS to position elements absolutely: ```md
    This is a left-bottom aligned footer
    ``` Or use the draggable elements feature: ## Adjust Sizes {#adjust-size} - Adjust all slides's size: - Adjust several slides' size: - Adjust some elements' size: ================================================ FILE: docs/guide/global-context.md ================================================ # Global Context Slidev injects several global context values for advanced navigation controls. ## Direct Usage {#direct-usage} You can access them directly in your slides or components: ```md [slides.md] # Page 1 Current page is: {{ $nav.currentPage }} ``` ```vue [Foo.vue] ``` ## Composable Usage {#composable-usage} > Available since v0.48.0 If you want to get the context programmatically (also type-safely), you can import composables from `@slidev/client`: ```vue ``` > [!NOTE] > Previously, you might see the usage of importing nested modules like `import { isDark } from '@slidev/client/logic/dark.ts'`, this is **NOT RECOMMENDED** as they are internal implementation details and may change in the future. Always use the public APIs from `@slidev/client` if possible. ::: warning When the `useSlideContext` composable is used in a file, the automatic injection of `$slidev` will be disabled. You need to manually get the `$slidev` object to the `useSlideContext` function. ::: ## Properties {#properties} ### `$slidev` {#slidev} The global context object. ### `$frontmatter` {#frontmatter} The frontmatter object of the current slide. Note that this is empty for components out of the slides like . ### `$clicks` {#clicks} `$clicks` hold the number of clicks on the current slide. Can be used conditionally to show different content on clicks. ```html
    Content
    ``` See the guide for more information. ### `$nav` {#nav} A reactive object holding the properties and controls of the slide navigation. For examples: ```js $nav.next() // go next step $nav.nextSlide() // go next slide (skip clicks) $nav.go(10) // go slide #10 $nav.currentPage // current slide number $nav.currentLayout // current layout name ``` For more properties available, refer to the [`SlidevContextNav` interface](https://github.com/slidevjs/slidev/blob/main/packages/client/composables/useNav.ts). ### `$page` {#page} `$page` holds the number of the current page, 1-indexed. ```md Page: {{ $page }} Is current page active: {{ $page === $nav.currentPage }} ``` > [!Note] > `$nav.clicks` is a global state while `$clicks` is the local clicks number for each slide. ### `$renderContext` {#render-context} `$renderContext` holds the current render context, which can be `slide`, `overview`, `presenter` or `previewNext` ```md
    This content will only be rendered in main slides view
    ``` You can also use the [`` component](../builtin/components#renderwhen). ### `$slidev.configs` {#configs} A reactive object holding the configurations for the slide project. For example: ```md --- title: My First Slidev! --- # Page 1 --- # Any Page {{ $slidev.configs.title }} // 'My First Slidev!' ``` ### `$slidev.themeConfigs` {#theme-configs} A reactive object holding the parsed theme configurations: ```yaml --- title: My First Slidev! themeConfig: primary: '#213435' --- ``` Then the theme can access the primary color like: ```md {{ $slidev.themeConfigs.primary }} // '#213435' ``` ## Types {#types} If you want to get a type programmatically, you can import types like `TocItem` from `@slidev/types`: ```vue ``` ================================================ FILE: docs/guide/hosting.md ================================================ --- outline: deep --- # Building and Hosting Slidev is designed to run as a web server when you are editing or presenting your slides. However, after the presentation, you may still want to share your **interactive** slides with others. This guide will show you how to build and host your slides. ## Build as a SPA {#spa} You can build the slides into a static [Single-page application (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA) via the following command: ```bash $ slidev build ``` By default, the generated files are placed in the `dist` folder. You can test the built version of you slides by running: `npx vite preview` or any other static server. ### Base Path {#base} To deploy your slides under sub-routes, you need to pass the `--base` option. The `--base` path **must begin and end with a slash `/`**. For example: ```bash $ slidev build --base /talks/my-cool-talk/ ``` Refer to [Vite's documentation](https://vitejs.dev/guide/build.html#public-base-path) for more details. ### Output directory {#output-directory} You can change the output directory using `--out`. ```bash $ slidev build --out my-build-folder ``` ### Remove speaker notes {#without-notes} If you are sharing the built slides publicly and don't want to include your speaker notes, run the build with `--without-notes`: ```bash $ slidev build --without-notes ``` ### Multiple Builds {#multiple-builds} You can build multiple slide decks in one go by passing multiple markdown files as arguments: ```bash $ slidev build slides1.md slides2.md ``` Or if your shell supports it, you can use a glob pattern: ```bash $ slidev build *.md ``` In this case, each input file will generate a folder containing the build in the output directory. ### Examples {#examples} Here are a few examples of the exported SPA: - [Demo Slides](https://sli.dev/demo/starter) - [Composable Vue](https://talks.antfu.me/2021/composable-vue) by [Anthony Fu](https://github.com/antfu) - More in [Showcases](../resources/showcases) ### Options {#options} ## Hosting {#hosting} We recommend using `npm init slidev@latest` to scaffold your project, which contains the necessary configuration files for hosting services out-of-the-box. ### GitHub Pages {#github-pages} To deploy your slides on [GitHub Pages](https://pages.github.com/) via GitHub Actions, follow these steps: 1. In your repository, go to `Settings` > `Pages`. Under `Build and deployment`, select `GitHub Actions`. (Do not choose `Deploy from a branch` and upload the `dist` directory, which is not recommended.) 2. Create `.github/workflows/deploy.yml` with the following content to deploy your slides to GitHub Pages via GitHub Actions. ::: details deploy.yml ```yaml name: Deploy pages on: workflow_dispatch: push: branches: [main] permissions: contents: read pages: write id-token: write concurrency: group: pages cancel-in-progress: false jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 'lts/*' - name: Setup @antfu/ni run: npm i -g @antfu/ni - name: Install dependencies run: nci - name: Build run: nr build --base /${{github.event.repository.name}}/ - name: Setup Pages uses: actions/configure-pages@v4 - uses: actions/upload-pages-artifact@v3 with: path: dist deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} needs: build runs-on: ubuntu-latest name: Deploy steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 ``` ::: 3. Commit and push the changes to your repository. The GitHub Actions workflow will automatically deploy your slides to GitHub Pages every time you push to the `main` branch. 4. You can access your slides at `https://.github.io//`. ### Netlify Create `netlify.toml` in your project root with the following content: ::: details netlify.toml ```toml [build] publish = 'dist' command = 'npm run build' [build.environment] NODE_VERSION = '20' [[redirects]] from = '/*' to = '/index.html' status = 200 ``` ::: Then go to your [Netlify dashboard](https://netlify.com/) and create a new site with the repository. ### Vercel Create `vercel.json` in your project root with the following content: ::: details vercel.json ```json { "rewrites": [ { "source": "/(.*)", "destination": "/index.html" } ] } ``` ::: Then go to your [Vercel dashboard](https://vercel.com/) and create a new site with the repository. ### Zephyr Cloud {#zephyr-cloud} To deploy your Slidev deck on [Zephyr Cloud](https://zephyr-cloud.io/), you can add Zephyr support to an existing Slidev project with: ```bash npx with-zephyr@latest ``` This codemod detects your bundler (Slidev uses Vite) and updates your config for Zephyr Cloud. After setup, run your normal build command, for example: ```bash npm run build ``` When the build runs with Zephyr enabled, your app is deployed and Zephyr Cloud returns a preview URL. ::: info Zephyr Cloud is a bit different from most hosting providers: every `build` run triggers a deployment. ::: ### Host on Docker {#docker} If you need a rapid way to run a presentation with containers, you can use the prebuilt [docker image](https://hub.docker.com/r/tangramor/slidev) maintained by [tangramor](https://github.com/tangramor), or build your own. ::: details Use the Docker Image Just run the following command in your work folder: ```bash docker run --name slidev --rm -it \ --user node \ -v ${PWD}:/slidev \ -p 3030:3030 \ -e NPM_MIRROR="https://registry.npmmirror.com" \ tangramor/slidev:latest ``` **_Note_**: You can use `NPM_MIRROR` to specify a npm mirror to speed up the installation process. If your work folder is empty, it will generate a template `slides.md` and other related files under your work folder, and launch the server on port `3030`. You can access your slides from `http://localhost:3030/` To create an Docker Image for your slides, you can use the following Dockerfile: ```Dockerfile FROM tangramor/slidev:latest ADD . /slidev ``` Create the docker image: `docker build -t myslides .` And run the container: `docker run --name myslides --rm --user node -p 3030:3030 myslides` You can visit your slides at `http://localhost:3030/` ::: ================================================ FILE: docs/guide/index.md ================================================ --- outline: deep --- # Getting Started Slidev (slide + dev, **/slaɪdɪv/**) is a web-based slides maker and presenter. It's designed for developers to focus on writing content in Markdown. With the power of web technologies like Vue, you are able to deliver pixel-perfect designs with interactive demos to your presentation. ::: tip You can learn more about the rationale behind this project in . ::: ## Create Slides ### Try it Online Start Slidev right in your browser with StackBlitz: [sli.dev/new](https://sli.dev/new) ### Create Locally > Requires [Node.js](https://nodejs.org) >= 18.0 installed. Run the following command to create a new Slidev project locally: ::: code-group ```bash [pnpm] # If you haven't installed pnpm npm i -g pnpm pnpm create slidev ``` ```bash [npm] # Not recommended - # NPM will download the packages each time you create a new project, # which is slow and takes up a lot of space npm init slidev@latest ``` ```bash [yarn] yarn create slidev ``` ```bash [bun] bun create slidev ``` ```bash [deno] deno init --npm slidev ``` ::: Follow the prompts to start your slides project. The slides content is in `slides.md`, which initially includes demos of most the Slidev features. For more information about the Markdown syntax, please check . :::: details Single file usage (not recommended) If you prefer to have a single Markdown file as your slides, you can install the Slidev CLI globally: ::: code-group ```bash [pnpm] pnpm i -g @slidev/cli ``` ```bash [npm] npm i -g @slidev/cli ``` ```bash [yarn] yarn global add @slidev/cli ``` ```bash [bun] bun i -g @slidev/cli ``` ```bash [deno] deno i -g npm:@slidev/cli ``` ::: Then, you can create and start a single file slides via: ```bash slidev slides.md ``` :::: ## Basic Commands Slidev provides a set of commands in its CLI. Here are some common ones: - `slidev` - Start the dev server. See [the dev command](../builtin/cli#dev). - `slidev export` - Export the slides to PDF, PPTX, or PNGs. See . - `slidev build` - Build the slides as a static web application. See . - `slidev format` - Format the slides. See [the format command](../builtin/cli#format). - `slidev --help` - Show the help message To run these commands, you can add them to your `package.json` scripts (which has been done for you if the project was created via `npm init slidev`): ```json [package.json] { "scripts": { "dev": "slidev --open", "build": "slidev build", "export": "slidev export" } } ``` Then, you can simply run `npm run dev`, `npm run build`, and `npm run export`. For more information about the CLI, please check the [CLI guide](../builtin/cli). ## Setup Your Editor {#editor} Since Slidev uses Markdown as the source entry, you can use any editor you prefer to create your slides. We also provide tools to help you edit you slides more conveniently: ## Join the Community It's recommended to join our official [Discord Server](https://chat.sli.dev/) to get help, share your slides, or discuss anything about Slidev. If you're encountering bugs, feel free to open an issue on [GitHub](https://github.com/slidevjs/slidev/issues/new/choose). ## Tech Stack Slidev is made possible by combining these tools and technologies. - [Vite](https://vitejs.dev) - An extremely fast frontend tooling - [Vue 3](https://v3.vuejs.org/) powered [Markdown](https://daringfireball.net/projects/markdown/syntax) - Focus on the content while having the power of HTML and Vue components whenever needed - [UnoCSS](https://github.com/unocss/unocss) - On-demand utility-first CSS framework, style your slides at ease - [Shiki](https://github.com/shikijs/shiki), [Monaco Editor](https://github.com/Microsoft/monaco-editor) - First-class code snippets support with live coding capability - [RecordRTC](https://recordrtc.org) - Built-in recording and camera view - [VueUse](https://vueuse.org) family - [`@vueuse/core`](https://github.com/vueuse/vueuse), [`@vueuse/head`](https://github.com/vueuse/head), [`@vueuse/motion`](https://github.com/vueuse/motion), etc. - [Iconify](https://iconify.design/) - Iconsets collection. - [Drauu](https://github.com/antfu/drauu) - Drawing and annotations support - [KaTeX](https://katex.org/) - LaTeX math rendering. - [Mermaid](https://mermaid-js.github.io/mermaid) - Textual Diagrams. ================================================ FILE: docs/guide/layout.md ================================================ # Slide Layout Layouts in Slidev are used to define the structure for each slide. They are Vue components that wrap the content of the slides. ## Using Layouts {#use} To use a layout, you can specify it in the frontmatter of the slide: ```md --- layout: quote --- A quote from someone ``` By default, the layout of the first slide is `cover`, and the rest are `default`. The layouts are loaded in the following order, and the last one loaded will override the previous ones: 1. default layouts. See [Built-in Layouts](../builtin/layouts). 2. layouts provided by the theme 3. layouts provided by the addons 4. custom layouts in the `layouts` directory ## Writing Layouts {#write} ================================================ FILE: docs/guide/syntax.md ================================================ --- outline: deep --- # Syntax Guide Slidev's slides are written as Markdown files, which are called **Slidev Markdown**s. A presentation has a Slidev Markdown as its entry, which is `./slides.md` by default, but you can change it by passing the file path as an argument to [the CLI commands](../builtin/cli). In a Slidev Markdown, not only [the basic Markdown features](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) can be used as usual, Slidev also provides additional features to enhance your slides. This section covers the syntax introduced by Slidev. Please make sure you know the basic Markdown syntax before reading this guide. ## Slide Separators {#slide-separators} Use `---` padded with a new line to separate your slides. ````md {5,15} # Title Hello, **Slidev**! --- # Slide 2 Use code blocks for highlighting: ```ts console.log('Hello, World!') ``` --- # Slide 3 Use UnoCSS classes and Vue components to style and enrich your slides:
    ```` ## Frontmatter & Headmatter {#frontmatter} At the beginning of each slide, you can add an optional [frontmatter](https://jekyllrb.com/docs/front-matter/) to configure the slide. The first frontmatter block is called **headmatter** and can configure the whole slide deck. The rest are **frontmatters** for individual slides. Texts in the headmatter or the frontmatter should be an object in [YAML](https://www.cloudbees.com/blog/yaml-tutorial-everything-you-need-get-started/) format. For example: ```md {1-4,10-14,26-28} --- theme: seriph title: Welcome to Slidev --- # Slide 1 The frontmatter of this slide is also the headmatter --- layout: center background: /background-1.png class: text-white --- # Slide 2 A page with the layout `center` and a background image --- # Slide 3 A page without frontmatter --- src: ./pages/4.md # This slide only contains a frontmatter --- --- # Slide 5 ``` Configurations you can set are described in the [Slides deck configurations](/custom/#headmatter) and [Per slide configurations](/custom/#frontmatter) sections. To make the headmatter more readable, you can install the VSCode extension: Also, there is another possible frontmatter format: ## Notes {#notes} You can also create presenter notes for each slide. They will show up in for you to reference during presentations. The comment blocks at the end of each slide are treated as the note of the slide: ```md {9,19-21} --- layout: cover --- # Slide 1 This is the cover page. --- # Slide 2 The second page ``` Basic Markdown and HTML are also supported in notes and will be rendered. ## Code Blocks {#code-block} One big reason that led to the creation of Slidev was the need to perfectly display code in slides. Consequently, you can use Markdown-flavored code blocks to highlight your code. ````md ```ts console.log('Hello, World!') ``` ```` Slidev has [Shiki](https://github.com/shikijs/shiki) built in as the syntax highlighter. Refer to [Configure Shiki](/custom/config-highlighter) for more details. More about code blocks: ## LaTeX Blocks {#latex-block} Slidev supports LaTeX blocks for mathematical and chemical formulas: ## Diagrams {#diagrams} Slidev supports [Mermaid](https://mermaid.js.org/) and [PlantUML](https://plantuml.com/) for creating diagrams from text: ## Comark Syntax {#comark-syntax} Comark Syntax is the easiest way to apply styles and classes to elements: ## Scoped CSS {#scoped-css} You can use scoped CSS to style your slides: ## Importing Slides {#importing-slides} ================================================ FILE: docs/guide/theme-addon.md ================================================ # Theme and Addons A slides project can have one theme and multiple addons. All of them can provide styles, components, layouts, and other configs to your slides project. ## Use a Theme {#use-theme} Changing the theme in Slidev is surprisingly easy. All you need to do is to add the `theme` option in your [headmatter](../custom/index#headmatter): ```md --- theme: seriph --- # The first slide ``` You can find the list of official themes and community themes in the [Themes Gallery](../resources/theme-gallery). ::: info Theme name convention - You can also pass a relative or absolute path to a local theme folder, like `../my-theme` - You can always use the full package name as the theme name - If the theme is [official](../resources/theme-gallery#official-themes) or is named like `slidev-theme-name`, you can omit the `slidev-theme-` prefix - For scoped packages like `@org/slidev-theme-name`, the full package name is required ::: You can start the server and will be prompted to install the theme after a confirmation.
    ? The theme "@slidev/theme-seriph" was not found in your project, do you want to install it now? › (Y/n)
    
    or install the theme manually via: ```bash $ npm install @slidev/theme-seriph ``` And that's all, enjoy the new theme! For more details about the usage, you can refer to the theme's README. ## Use an Addon {#use-addon} Addons are similar to themes, but they are more flexible and can be used to add extra features to your slides project. You can add multiple addons to your project, and they can be used to add extra features to your slides project. To use an addon, you can add the `addons` option in your [headmatter](../custom/index#headmatter): ```md --- addons: - excalidraw - '@slidev/plugin-notes' --- ``` You can find the list of official addons and community addons in the [Addons Gallery](../resources/addon-gallery). ================================================ FILE: docs/guide/ui.md ================================================ --- outline: deep --- # User Interface ## Navigation Bar {#navigation-bar} In Play mode, move your mouse to the bottom left corner of the page, you can see the navigation bar. ![](/screenshots/navbar.png) > You can extend the navigation bar via . ## Navigation Actions {#navigation-actions} | Keyboard Shortcut | Button in Navigation Bar | Description | | ----------------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------- | | f | | Toggle fullscreen | | right / space | | Next animation or slide | | left | | Previous animation or slide | | up | - | Previous slide | | down | - | Next slide | | o | | Toggle [Quick Overview](#quick-overview) | | d | | Toggle dark mode | | - | | Toggle [Camera View](../features/recording#camera-view) | | - | | Start | | - | | Enter [Presenter Mode](#presenter-mode) | | - | | Toggle | | - | | Enter [Browser Exporter](#exporter) | | - | | Download PDF. See | | - | | Show information about the slides | | - | | More options | | g | - | Show goto... | > You can [configure the shortcuts](../custom/config-shortcuts). ## Quick Overview {#quick-overview} By pressing o or clicking the button in the navigation bar, you can have an overview of your slides so you can jump between them easily. ![](/screenshots/slides-overview.png) ## Presenter Mode {#presenter-mode} To enter the presenter mode, you can click the button in the navigation panel, or visit `http://localhost:/presenter`. When giving a presentation, it's recommended to open two browser windows - one in the play mode for the audience, and another one in the presenter mode for you. Then you can share the first screen to the audience and keep the second screen for yourself. Whenever you navigate through the slides in the presenter mode, all other opened pages will automatically follow this navigation to stay in sync with the presenter. ![](/screenshots/presenter-mode.png) ### Presenter Layouts {#presenter-layouts} > Available since v0.50.0 The presenter view offers three different layouts that you can cycle through by clicking the layout toggle button in the navigation bar: - **Layout 1** (default): Current slide prominently displayed at the top, with notes and next slide preview below - **Layout 2**: Notes panel on the left, current slide and next slide stacked on the right - **Layout 3**: Notes and current slide on the left, larger next slide preview on the right Each layout is optimized for different screen sizes and presentation preferences. ### Screen Mirror {#screen-mirror} > Available since v0.50.0 In the presenter view, you can switch the main slide area to "Screen Mirror" mode. This allows you to capture and display another monitor or window directly in the presenter view. Click the "Screen Mirror" option in the presenter view's segment control, then select the screen or window you want to mirror. This is useful when you want to see exactly what your audience sees on the projector or external display (e.g. live coding / live demo). ## Slide Overview {#slides-overview} > Available since v0.48.0 You can visit an overview of all of your slides by first opening the [Quick Overview panel](#quick-overview) and then clicking the on the top right, or by visiting `http://localhost:/overview` directly. The overview page gives you a linear list of all your slides, with all of your notes on the side. You can double-click on the notes to edit the notes directly, and drag the clicks sliders to preview the steps in your slides. ## Notes Editor {#notes-editor} > Available since v0.52.0 Slidev provides a batch notes editor at `http://localhost:/notes-edit` where you can edit notes for all slides in a single text area. Notes for each slide are separated by `--- #[slide-number]` markers. Changes are automatically saved as you type with debouncing. This is useful when you want to write or review all your speaker notes in one place without switching between slides. ## Drawing UI {#drawing} See: ## Recording UI {#recording} See: ## Browser Exporter {#exporter} See: ## Settings {#settings} Click the button in the navigation bar to access additional settings. ### CSS Filters {#css-filters} > Available since v0.50.0 When presenting on different projectors or displays, colors may appear differently than expected. Slidev provides CSS filter controls to adjust the display in real-time: - **Invert**: Flip all colors - **Brightness**: Adjust overall brightness (0.5 - 1.5) - **Contrast**: Adjust contrast levels (0.5 - 1.5) - **Saturation**: Adjust color saturation (0.5 - 1.5) - **Sepia**: Add sepia tone effect - **Hue Rotate**: Shift all colors by degrees (-180 to 180) These settings are stored locally and persist across sessions. A dot indicator appears on the settings button when any filter is active. ### Hide Idle Cursor {#hide-idle-cursor} > Available since v0.50.0 When enabled, the cursor will automatically hide after a period of inactivity during the presentation. This provides a cleaner viewing experience for your audience. ### Slide Scale {#slide-scale} Choose between "Fit" mode (scales slides to fit the viewport) or "1:1" mode (displays slides at their native resolution). ### Wake Lock {#wake-lock} When enabled, prevents the screen from dimming or locking during your presentation. Requires browser support for the Wake Lock API. ## Global Layers {#global-layers} You can add any custom UI below or above your slides for the whole presentation or per-slide: ================================================ FILE: docs/guide/why.md ================================================ --- outline: deep --- # Why Slidev There have been lots of feature-rich WYSIWYG slides makers like [Microsoft PowerPoint](https://www.microsoft.com/en-us/microsoft-365/powerpoint) and [Apple Keynote](https://www.apple.com/keynote/) _(see [Comparisons](#comparisons))_. They are intuitive and easy to learn. So why bother making Slidev? Slidev aims to provide flexibility and interactivity for **developers** to make their presentations much more interesting, expressive, and attractive by using technologies they are familiar with. Slidev is also open source with a strong community. Slidev is Markdown-based, which helps you **focus on the content**. Slidev is also Web-based, which means **nothing is impossible** - everything you can do in a web app can apply to your slides. Slidev is also **progressive**. You can start with a super simple Markdown file, and then use the [built-in features](../features/) when you need them without any configuration. There are also [themes and addons](./theme-addon) you can optionally install to enhance your slides. ![demo slide](/screenshots/cover.png) {#welcome} ## Features ### 📝 Markdown-based Slidev uses an extended Markdown format to organize your slides in a single plain text file. This helps you focus on the content while allowing you to use Git and any editor you like. > Learn more: . ### 🧑‍💻 Developer Friendly Slidev provides first-class support for code snippets for developers. It uses [Shiki](https://github.com/shikijs/shiki) to get the most accurate syntax highlighting. Slidev also supports and . These make Slidev the best choice for tech talks. ### 🎨 Themable Themes for Slidev can be shared via npm packages. You apply a theme within one line of code. Check out the [Theme Gallery](../resources/theme-gallery) for the beautiful themes made by the official team and the community. ### ⚡ Fast Every change you make in the editor will be updated to your slides in the browser **instantly** without reloading, thanks to [Vite's HMR feature](https://vitejs.dev/guide/features.html#hot-module-replacement). ### 🤹 Interactive & Expressive You can write Vue components and use them in your slides, which you can then interact with during the presentation to express your idea in a more interesting and intuitive way. Slidev also has built-in support of , which empowers you to do live coding in your presentation with auto-completion and hover messages. ### 🎥 Recording Support Slidev provides built-in recording and camera view. You can share your presentation with your camera view inside, or record and save your screen and camera separately. > Learn more: . ### 📤 Portable You can export your slides into PDF, PPTX, PNGs, or even a single-page application (SPA) via a single command. Then you can share or host it anywhere you like. > Learn more: and . ### 🛠 Hackable Because Slidev is web-based, everything that can be done in a normal web app can be applied to your slides. For example, WebGL, API requests, iframes, or even live sharing. It's up to your imagination! > Learn more: [Customization](../custom/). ## Comparisons ::: details Slidev vs. Microsoft PowerPoint / Apple Keynote [Microsoft PowerPoint](https://www.microsoft.com/en-us/microsoft-365/powerpoint) and [Apple Keynote](https://www.apple.com/keynote/) are feature-rich WYSIWYG slides makers. They are intuitive and easy to learn, which makes them one of the best choices for non-developers. Compared to them, Slidev has the following advantages: - Developer-friendly: Code snippets are first-class citizens in Slidev. - Markdown-based: Focus on the content, and version control your slides with Git. - Web-based: Everything you can do in a web app can apply to your slides. - Hackable: Customize anything you like with web technologies. - Open source: Slidev is completely open source, and has a strong community. ::: ::: details Slidev vs. Reveal.js [Reveal.js](https://revealjs.com/) is a popular HTML presentation framework. It is also open source and supports Markdown. Compared to Reveal.js, Slidev has the following advantages: - More concise: Slidev uses an extended Markdown format, while Reveal.js encourages you to write HTML to organize your slides. - Vue support: You can use Vue components in Slidev to make your slides interactive. - Vite-based: Slidev is built on top of Vite, which provides instant HMR and flexible plugin API. - Atomatic CSS: You can [UnoCSS](https://unocss.dev/) out of the box to style your slides. ::: ::: details Slidev vs. Marp [Marp](https://marp.app/) is a Markdown presentation tool that focuses on simplicity and portability. It is also open source and supports Markdown. Compared to Marp, Slidev has the following advantages: - The same simplicity: Slidev's slides can start as simple as Marp's. - More features: Slidev supports many features that Marp doesn't. - Vue support: You can use Vue components in Slidev to make your slides interactive. - Vite-based: Slidev is built on top of Vite, which provides instant HMR and flexible plugin API. - Atomatic CSS: You can [UnoCSS](https://unocss.dev/) out of the box to style your slides. ::: ## Give it a Try Playing around with Slidev will tell you more than thousands of words. Check the guide to create your first Slidev project in one click or one command. Or you can have a quick preview of it: ================================================ FILE: docs/guide/work-with-ai.md ================================================ # Work with AI Thanks to Slidev being markdown-based, it works great with AI coding agents. ## Skills Slidev provides official [skills](https://code.claude.com/docs/en/skills) for AI coding agents, enabling them to understand Slidev's syntax, features, and best practices when helping you create presentations. ### Installation Install the Slidev skill to your AI coding agent: ```bash npx skills add slidevjs/slidev ``` The source code of the skill is [here](https://github.com/slidevjs/slidev/tree/main/skills/slidev). ### Example Prompts Once installed, you can ask agents to help with various Slidev tasks: ``` Create a Slidev presentation about TypeScript generics with code examples ``` ``` Add a two-column slide with code on the left and explanation on the right ``` ``` Set up click animations to reveal bullet points one by one ``` ``` Configure the presentation for PDF export with speaker notes ``` ### What's Included The Slidev skill provides knowledge about: - Markdown syntax, slide separators, and frontmatter - Click animations and transitions - Code highlighting, Monaco editor, and magic-move - Diagrams (Mermaid, PlantUML) and LaTeX math - Built-in layouts and components - Exporting and hosting options ## VS Code Extension The provides Language Model Tools that allow VS Code's Copilot and other AI assistants to interact with your Slidev project directly. These tools enable AI to: - Get information about the active slide and project - Retrieve content of specific slides - List and search slides by title - Navigate between slides See for more details. ================================================ FILE: docs/guide/write-addon.md ================================================ # Writing Addons > Please read and first. Each slides project can only have one theme, but can have multiple addons. ## Capability Theoretically, all the capabilities of a theme can be done in an addon. However, an addon is more like a plugin that extends the functionalities of Slidev. It's recommended to implement one or more of the following points in an addon: - Provide custom components - Provide _new_ layouts - Provide new code snippets - Provide new code runners - Configure tools like UnoCSS, Vite, etc. However, the following points are **not** recommended to be done in an addon, and may be better [implemented as a theme](./write-theme): - Wildcard global styles - Overriding existing layouts - Overriding configurations - Other things that may be incompatible with the theme and other addons An addon can also specify its required Slidev version in the same way as themes. ## Previewing The same as themes, you can preview your addon via a `./slides.md` like this: ```md [slides.md] --- addons: - ./ --- ``` ## Publishing When publishing the addon, non-JS files like `.vue` and `.ts` files can be published directly without compiling. Slidev will automatically compile them when using the addon. Addons should follow the following conventions: - Package name should start with `slidev-addon-`. For example, `slidev-addon-name` or `@scope/slidev-addon-name` - Add `"slidev-addon"` and `"slidev"` in the `keywords` field of your `package.json` Theme can be used locally without publishing to NPM. If your addon is only for personal use, you can simply use it as a local addon, or publish it as a private scoped package. However, it is recommended to publish it to the NPM registry if you want to share it with others. ================================================ FILE: docs/guide/write-layout.md ================================================ # Writing Layouts > Please read first. To create a custom layout, simply create a new Vue file in the `layouts` directory: ```bash your-slidev/ ├── ... ├── slides.md └── layouts/ ├── ... └── MyLayout.vue ``` Layouts are Vue components, so you can use all the features of Vue in them. In the layout component, use `` (the default slot) for the slide content: ```vue [default.vue] ``` You can also have [named slots](https://vuejs.org/guide/components/slots.html) for more complex layouts: ```vue [split.vue] ``` And then use it with . ================================================ FILE: docs/guide/write-theme.md ================================================ # Writing Themes > Please read first. Each slides project can only have one theme. Themes should focus on providing the appearance of slides. If the feature isn't related to the appearance and can be used separately, it should be implemented as an [addon](./write-addon). To get started, we recommend you use our generator for scaffolding your first theme ::: code-group ```bash [pnpm] $ pnpm create slidev-theme ``` ```bash [npm] $ npm init slidev-theme@latest ``` ```bash [yarn] $ yarn create slidev-theme ``` ```bash [bun] $ bun create slidev-theme ``` ```bash [deno] $ deno init --npm slidev-theme ``` ::: Then you can modify and play with it. You can also refer to the [official themes](../resources/theme-gallery#official-themes) as examples. ## Capability A theme can contribute to the following points: - Global styles - Provide default configurations - Provide custom layouts or override the existing ones - Provide custom components - Configure tools like UnoCSS, Shiki, etc. However, the following points are **not** recommended to be done in a theme, and may be better implemented as an [addon](./write-addon): - New code snippets - New code runners - Other things that can be used separately Basically, the way to provide global styles, layouts, components and configure tools is the same as doing these in a slides project. For example, to configure Shiki, you can create a `./setup/shiki.ts` as described in [Configure Highlighter](../custom/config-highlighter). You can refer to the [customization guide](/custom/) for more information. To provide default Slidev configurations, you can add a `slidev.defaults` field in the `package.json` file, which will be merged with the user's configurations: ```json [package.json] { "slidev": { "defaults": { "transition": "slide-left", "aspectRatio": "4/3" } } } ``` ### Require Slidev Version If the theme is relying on a specific feature of Slidev that is newly introduced, you can set the minimal Slidev version required to have your theme working properly: ```json { "engines": { "slidev": ">=0.48.0" } } ``` An error message will be shown when the an incompatible version is used. ### Theme Metadata By default, Slidev assumes themes support both light mode and dark mode. If you only want your theme to be presented in a specific color schema, you need to specify it explicitly in the `package.json`: ```json [package.json] { "slidev": { "colorSchema": "light" // or "dark" or "both" } } ``` ## Previewing You can preview your theme when developing by using a demo slide deck. To do so, create a `./slides.md` file with the following headmatter: ```md [slides.md] --- theme: ./ # Use the theme in the current directory --- ``` Then you can start the demo slides as usual. ## Publishing When publishing the theme, non-JS files like `.vue` and `.ts` files can be published directly without compiling. Slidev will automatically compile them when using the theme. Themes should follow the following conventions: - Package name should start with `slidev-theme-`. For example, `slidev-theme-name` or `@scope/slidev-theme-name` - Add `"slidev-theme"` and `"slidev"` in the `keywords` field of your `package.json` Theme can be used locally without publishing to NPM. If your theme is only for personal use, you can simply use it as a local theme, or publish it as a private scoped package. However, it is recommended to publish it to the NPM registry if you want to share it with others. ================================================ FILE: docs/index.md ================================================ --- layout: home markdownStyles: false --- ================================================ FILE: docs/netlify.toml ================================================ [build] publish = ".vitepress/dist" command = "pnpm run build" [build.environment] NODE_VERSION = "20" PLAYWRIGHT_BROWSERS_PATH = "0" [[redirects]] from = "/new" to = "https://stackblitz.com/github/slidevjs/new?file=slides.md" status = 302 force = true [[redirects]] from = "https://slidev.antfu.me/*" to = "https://sli.dev/:splat" status = 301 force = true [[redirects]] from = "/demo/composable-vue/*" to = "https://demo.sli.dev/composable-vue" status = 301 force = true [[redirects]] from = "/demo/starter/*" to = "https://demo.sli.dev/starter" status = 301 force = true [[redirects]] from = "/*" to = "/index.html" status = 200 ================================================ FILE: docs/package.json ================================================ { "name": "@slidev/docs", "type": "module", "version": "52.14.1", "license": "MIT", "funding": "https://github.com/sponsors/antfu", "homepage": "https://sli.dev", "repository": { "type": "git", "url": "https://github.com/slidevjs/slidev", "directory": "docs" }, "bugs": "https://github.com/slidevjs/slidev/issues", "files": [ "**/*.md", "!.vitepress/**" ], "scripts": { "dev": "vitepress", "build": "vitepress build", "preview": "vitepress preview" }, "devDependencies": { "@antfu/utils": "catalog:frontend", "@iconify/json": "catalog:icons", "@shikijs/vitepress-twoslash": "catalog:prod", "@slidev/client": "workspace:*", "@slidev/parser": "workspace:*", "@slidev/types": "workspace:*", "@types/node": "catalog:types", "@unocss/reset": "catalog:frontend", "@vueuse/core": "catalog:frontend", "fast-glob": "catalog:prod", "gray-matter": "catalog:prod", "shiki": "catalog:frontend", "typeit": "catalog:docs", "typescript": "catalog:dev", "unocss": "catalog:prod", "unplugin-icons": "catalog:prod", "unplugin-vue-components": "catalog:prod", "vite-plugin-inspect": "catalog:prod", "vitepress": "catalog:docs", "vitepress-plugin-group-icons": "catalog:docs", "vitepress-plugin-llms": "catalog:docs", "vue": "catalog:frontend" } } ================================================ FILE: docs/resources/addon-gallery.md ================================================ --- aside: false --- # Addon Gallery Browse awesome addons available for Slidev here. Read more about to use them, and to create your own addon. ## Official Addons ## Community Addons Here are the curated addons made by the community. ## More Addons Find all the [addons available on NPM](https://www.npmjs.com/search?q=keywords%3Aslidev-addon). ================================================ FILE: docs/resources/covers.md ================================================ # Curated Covers We curated a few cover images to demonstrate our starter template. ![](/screenshots/covers.png) ```yaml --- # random image from the curated collection background: https://cover.sli.dev --- ``` If you enjoy any of them, check out our [Unsplash collection](https://unsplash.com/collections/94734566/slidev) and find out their authors. [cover.sli.dev](https://cover.sli.dev) is hosted from [`slidevjs/slidev-covers`](https://github.com/slidevjs/slidev-covers). ================================================ FILE: docs/resources/learning.md ================================================ # Learning Resources ## English ### Videos - [Slidev - one of the best presentation software and it is free!](https://www.youtube.com/watch?v=oSgM6GoSwyY) - by [Federico Tartarini](https://www.youtube.com/@FedericoTartarini) - [Slides + developers = slidev](https://www.youtube.com/watch?v=nleqgO38pPU) by Murilo Cunha ### Articles - [Tips To Turn R Markdown Into Slidev Presentation](https://yutani.rbind.io/post/2021-06-05-tips-to-turn-r-markdown-into-slidev-presentation/) by Hiroaki Yutani ## 中文 - [Slidev:一个用Markdown写slides的神器](https://zhuanlan.zhihu.com/p/372729473) by [梦里风林](https://www.zhihu.com/people/meng-li-feng-lin) - [神器!这款开源项目可以让你使用 Markdown 来做 PPT!](https://zhuanlan.zhihu.com/p/377567327) by [Github掘金计划](https://www.zhihu.com/people/github-stars) ## 日本語 - [開発者のためのスライド作成ツール Slidev がすごい](https://zenn.dev/ryo_kawamata/articles/introduce-slidev) by [ryo_kawamata](https://zenn.dev/ryo_kawamata) - [Markdownでオシャレなスライドを作るSli.dev](https://qiita.com/e99h2121/items/a115f8865a0dc21bb462) by [Nobuko YAMADA](https://qiita.com/e99h2121) - [【Slidev 超入門】エンジニアだからこそ作れるつよつよスライドの作り方!](https://zenn.dev/takumaru/articles/3faa75c2f09493) by [takuma-ru](https://zenn.dev/takumaru) ================================================ FILE: docs/resources/showcases.md ================================================ --- aside: false --- # Showcases Talks / Presentations using Slidev. ================================================ FILE: docs/resources/theme-gallery.md ================================================ --- aside: false --- # Theme Gallery Browse awesome themes available for Slidev here. Read more about to use them, and to create your own theme. ## Official Themes {#official-themes} ## Community Themes {#community-themes} Here are the curated themes made by the community. ## More Themes {#more-themes} Find all the [themes available on NPM](https://www.npmjs.com/search?q=keywords%3Aslidev-theme). ================================================ FILE: docs/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "jsx": "preserve", "lib": ["DOM", "ESNext"], "baseUrl": ".", "module": "ESNext", "moduleResolution": "bundler", "resolveJsonModule": true, "types": [ "vite/client", "node" ], "strict": true, "strictNullChecks": true, "noUnusedLocals": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true }, "include": [ "./*.ts", "./.vitepress/**/*.ts", "./.vitepress/**/*.vue" ], "exclude": ["**/dist/**", "node_modules"] } ================================================ FILE: docs/uno.config.ts ================================================ import { defineConfig, presetAttributify, presetIcons, presetWebFonts, presetWind3, transformerDirectives } from 'unocss' export default defineConfig({ presets: [ presetWind3(), presetAttributify(), presetWebFonts({ fonts: { mono: ['IBM Plex Mono', 'monospace'], }, }), presetIcons(), ], transformers: [ transformerDirectives(), ], shortcuts: { 'bg-main': 'bg-white dark:bg-[#111]', }, theme: { colors: { primary: { DEFAULT: '#3AB9D4', deep: '#2082A6', }, }, }, }) ================================================ FILE: docs/vite.config.ts ================================================ import { slidebars } from '.vitepress/config' import UnoCSS from 'unocss/vite' import IconsResolver from 'unplugin-icons/resolver' import Icons from 'unplugin-icons/vite' import Components from 'unplugin-vue-components/vite' import { defineConfig } from 'vite' import Inspect from 'vite-plugin-inspect' import { groupIconVitePlugin } from 'vitepress-plugin-group-icons' import llmstxt from 'vitepress-plugin-llms' import config from './.vitepress/config' const IS_ROOT_ENGLISH_DOC = config.locales?.root.label.includes('English') || false export default defineConfig({ optimizeDeps: { exclude: [ 'vue-demi', '@vueuse/shared', '@vueuse/core', ], }, server: { hmr: { overlay: false, }, }, plugins: [ IS_ROOT_ENGLISH_DOC && llmstxt({ ignoreFiles: [ 'index.md', 'README.md', ], sidebar: slidebars, }), Components({ dirs: [ './.vitepress/theme/components', './node_modules/@slidev/client/builtin', ], extensions: ['vue', 'md'], include: [/\.vue$/, /\.vue\?vue/, /\.md$/, /\.md\?vue/], resolvers: [ IconsResolver({ prefix: '', }), ], }), Icons({ defaultStyle: 'display: inline-block;', }), Inspect(), UnoCSS(), groupIconVitePlugin(), ], }) ================================================ FILE: eslint.config.js ================================================ import antfu from '@antfu/eslint-config' export default antfu({ pnpm: true, formatters: { markdown: true, css: true, slidev: { files: [ '**/slides.md', '**/template.md', '**/example.md', 'test/fixtures/markdown/**/*.md', 'packages/vscode/syntaxes/slidev.example.md', ], }, }, ignores: [ 'skills/**/*.md', ], }) .removeRules( 'vue/no-v-text-v-html-on-component', 'vue/component-name-in-template-casing', 'jsonc/sort-array-values', 'pnpm/yaml-no-duplicate-catalog-item', ) .override('antfu/pnpm/package-json', { ignores: [ 'packages/create-theme/template/package.json', 'packages/create-app/template/package.json', // VSCE and OVSX do not support pnpm catalog when reading `@types/vscode`'s version. 'packages/vscode/package.json', ], }) .remove('antfu/markdown/rules') ================================================ FILE: netlify.toml ================================================ [build] publish = "docs/.vitepress/dist" command = "pnpm run build && pnpm run docs:build" [build.environment] NODE_VERSION = "24" NODE_OPTIONS = "--max-old-space-size=8192" PLAYWRIGHT_BROWSERS_PATH = "0" [[redirects]] from = "/new" to = "https://stackblitz.com/github/slidevjs/new?file=slides.md" status = 302 force = true [[redirects]] from = "/demo/composable-vue/*" to = "/demo/composable-vue/index.html" status = 200 [[redirects]] from = "/demo/starter/*" to = "/demo/starter/index.html" status = 200 [[redirects]] from = "/demo/vue-runner/*" to = "/demo/vue-runner/index.html" status = 200 [[redirects]] from = "https://slidev.antfu.me/*" to = "https://sli.dev/:splat" status = 301 force = true [[redirects]] from = "/*" to = "/index.html" status = 200 ================================================ FILE: package.json ================================================ { "type": "module", "version": "52.14.1", "private": true, "packageManager": "pnpm@10.30.3", "engines": { "node": ">=18.0.0" }, "scripts": { "build": "pnpm -r --filter=\"./packages/**\" --parallel run build", "ci:publish": "zx scripts/publish.mjs", "cy": "cypress open", "cy:fixture": "pnpm -C cypress/fixtures/basic run dev", "demo:build": "zx ./scripts/demo.mjs", "demo:composable-vue": "pnpm -C demo/composable-vue run dev", "demo:vue-runner": "pnpm -C demo/vue-runner run dev", "demo:dev": "pnpm -C demo/starter run dev", "vscode:dev": "pnpm -C packages/vscode run dev", "play": "pnpm demo:dev", "dev": "pnpm -r --filter=\"./packages/**\" --parallel run dev", "lint": "eslint . --cache", "lint:fix": "nr lint --fix", "typecheck": "vue-tsc --noEmit", "docs": "pnpm -C docs run dev", "docs:build": "pnpm run --filter=\"./docs...\" build && pnpm demo:build", "release": "bumpp package.json packages/*/package.json docs/package.json --all -x \"zx scripts/update-versions.mjs\"", "test": "vitest test", "prepare": "simple-git-hooks" }, "devDependencies": { "@antfu/eslint-config": "catalog:dev", "@antfu/ni": "catalog:prod", "@antfu/utils": "catalog:frontend", "@shikijs/markdown-it": "catalog:frontend", "@slidev/cli": "workspace:*", "@slidev/parser": "workspace:*", "@slidev/types": "workspace:*", "@types/cli-progress": "catalog:types", "@types/connect": "catalog:types", "@types/file-saver": "catalog:types", "@types/js-yaml": "catalog:types", "@types/katex": "catalog:types", "@types/node": "catalog:types", "@types/prompts": "catalog:types", "@types/recordrtc": "catalog:types", "@types/resolve": "catalog:types", "@types/semver": "catalog:types", "@types/yargs": "catalog:types", "@vueuse/core": "catalog:frontend", "bumpp": "catalog:dev", "cypress": "catalog:dev", "eslint": "catalog:dev", "eslint-plugin-format": "catalog:dev", "katex": "catalog:frontend", "lint-staged": "catalog:dev", "mermaid": "catalog:frontend", "playwright-chromium": "catalog:dev", "prettier": "catalog:dev", "prettier-plugin-slidev": "catalog:dev", "rimraf": "catalog:dev", "shiki": "catalog:frontend", "simple-git-hooks": "catalog:dev", "taze": "catalog:dev", "tinyexec": "catalog:prod", "tsdown": "catalog:dev", "tsx": "catalog:dev", "typescript": "catalog:dev", "vite": "catalog:prod", "vitest": "catalog:dev", "vue-tsc": "catalog:dev", "zx": "catalog:dev" }, "resolutions": { "chokidar": "catalog:prod", "semver": "catalog:dev", "typescript": "catalog:dev", "undici": "catalog:dev", "undici-types": "catalog:dev", "vite": "catalog:prod" }, "simple-git-hooks": { "pre-commit": "npx lint-staged" }, "lint-staged": { "**/*.{js,ts,vue,json}": [ "eslint --fix --cache" ] } } ================================================ FILE: packages/client/.generated/unocss-tokens.ts ================================================ /* eslint-disable eslint-comments/no-unlimited-disable */ /* eslint-disable */ export default [ "!backdrop-blur-0px", "!bg-opacity-75", "!bg-transparent", "!border-none", "!hidden", "!opacity-0", "!opacity-100", "!p-4", "!px-0", "!text-current", "!text-sm", "-mt-0.5", "-mt-1", "-rotate-45", "-top-15px", "-top-20", "-translate-y-1/2", "-z-1", " import { watchEffect } from 'vue' import { themeVars } from './env' import setupRoot from './setup/root' setupRoot() watchEffect(() => { for (const [key, value] of Object.entries(themeVars.value)) document.body.style.setProperty(key, value.toString()) }) ================================================ FILE: packages/client/README.md ================================================ # @slidev/client [![NPM version](https://img.shields.io/npm/v/@slidev/client?color=3AB9D4&label=)](https://www.npmjs.com/package/@slidev/client) Client code for [Slidev](https://sli.dev). Shipped with [`@slidev/cli`](https://www.npmjs.com/package/@slidev/cli). ## License MIT License © 2021 [Anthony Fu](https://github.com/antfu) ================================================ FILE: packages/client/builtin/Arrow.vue ================================================ ================================================ FILE: packages/client/builtin/AutoFitText.vue ================================================ ================================================ FILE: packages/client/builtin/CodeBlockWrapper.vue ================================================ ================================================ FILE: packages/client/builtin/CodeGroup.vue ================================================ ================================================ FILE: packages/client/builtin/KaTexBlockWrapper.vue ================================================ ================================================ FILE: packages/client/builtin/LightOrDark.vue ================================================ ================================================ FILE: packages/client/builtin/Link.vue ================================================ ================================================ FILE: packages/client/builtin/Mermaid.vue ================================================ ================================================ FILE: packages/client/builtin/Monaco.vue ================================================ ================================================ FILE: packages/client/builtin/PlantUml.vue ================================================ ================================================ FILE: packages/client/builtin/PoweredBySlidev.vue ================================================ ================================================ FILE: packages/client/builtin/RenderWhen.vue ================================================ ================================================ FILE: packages/client/builtin/ShikiMagicMove.vue ================================================ ================================================ FILE: packages/client/builtin/SlideCurrentNo.vue ================================================ ================================================ FILE: packages/client/builtin/SlidesTotal.vue ================================================ ================================================ FILE: packages/client/builtin/SlidevVideo.vue ================================================ ================================================ FILE: packages/client/builtin/Toc.vue ================================================ ================================================ FILE: packages/client/builtin/TocList.vue ================================================ ================================================ FILE: packages/client/builtin/Transform.vue ================================================ ================================================ FILE: packages/client/builtin/Tweet.vue ================================================ ================================================ FILE: packages/client/builtin/VAfter.ts ================================================ /** * click animations component * * Learn more: https://sli.dev/guide/animations.html#click-animation */ import type { Directive, VNode } from 'vue' import { toArray } from '@antfu/utils' import { defineComponent, h, resolveDirective, withDirectives } from 'vue' export default defineComponent({ render() { const after = resolveDirective('after')! function applyDirective(node: VNode, directive: Directive) { return withDirectives(node, [[directive]]) } let defaults = this.$slots.default?.() if (!defaults) return defaults = toArray(defaults) return defaults.map(i => applyDirective(h(i), after)) }, }) ================================================ FILE: packages/client/builtin/VClick.ts ================================================ /** * click animations component * * Learn more: https://sli.dev/guide/animations.html#click-animation */ import type { PropType, VNode } from 'vue' import { defineComponent, h, Text } from 'vue' import { CLICKS_MAX } from '../constants' import VClicks from './VClicks' export default defineComponent({ props: { at: { type: [Number, String], default: '+1', }, hide: { type: Boolean, default: false, }, fade: { type: Boolean, default: false, }, wrapText: { type: Function as PropType<(text: VNode) => VNode>, default: (text: VNode) => h('span', text), }, }, render() { return h( VClicks, { every: CLICKS_MAX, at: this.at, hide: this.hide, fade: this.fade, handleSpecialElements: false, }, { default: () => this.$slots.default?.().map(v => v.type === Text ? this.wrapText(v) : v, ), }, ) }, }) ================================================ FILE: packages/client/builtin/VClickGap.vue ================================================ ================================================ FILE: packages/client/builtin/VClicks.ts ================================================ /** * click animations component * * Learn more: https://sli.dev/guide/animations.html#click-animation */ import type { VNode, VNodeArrayChildren } from 'vue' import { toArray } from '@antfu/utils' import { Comment, createVNode, defineComponent, h, isVNode, resolveDirective, withDirectives } from 'vue' import { normalizeSingleAtValue } from '../composables/useClicks' import VClickGap from './VClickGap.vue' const listTags = ['ul', 'ol'] export default defineComponent({ props: { depth: { type: [Number, String], default: 1, }, every: { type: [Number, String], default: 1, }, at: { type: [Number, String], default: '+1', }, hide: { type: Boolean, default: false, }, fade: { type: Boolean, default: false, }, handleSpecialElements: { type: Boolean, default: true, }, }, render() { const every = +this.every const at = normalizeSingleAtValue(this.at) const isRelative = typeof at === 'string' let elements = this.$slots.default?.() if (at == null || !elements) { return elements } const click = resolveDirective('click')! const applyDirective = (node: VNode, value: number | string) => { return withDirectives(node, [[ click, value, '', { hide: this.hide, fade: this.fade, }, ]]) } const openAllTopLevelSlots = (children: T): T => { return children.flatMap((i) => { if (isVNode(i) && typeof i.type === 'symbol' && Array.isArray(i.children)) return openAllTopLevelSlots(i.children) else return [i] }) as T } elements = openAllTopLevelSlots(toArray(elements)) const mapSubList = (children: VNodeArrayChildren, depth = 1): VNodeArrayChildren => { const vNodes = openAllTopLevelSlots(children).map((i) => { if (!isVNode(i)) return i if (listTags.includes(i.type as string) && Array.isArray(i.children)) { // eslint-disable-next-line ts/no-use-before-define const vNodes = mapChildren(i.children, depth + 1) return h(i, {}, vNodes) } return h(i) }) return vNodes } let globalIdx = 1 let execIdx = 0 const mapChildren = (children: VNodeArrayChildren, depth = 1): VNodeArrayChildren => { const vNodes = openAllTopLevelSlots(children).map((i) => { if (!isVNode(i) || i.type === Comment) return i const thisShowIdx = +at + Math.ceil(globalIdx++ / every) - 1 let vNode if (depth < +this.depth && Array.isArray(i.children)) vNode = h(i, {}, mapSubList(i.children, depth)) else vNode = h(i) const delta = thisShowIdx - execIdx execIdx = thisShowIdx return applyDirective( vNode, isRelative ? delta >= 0 ? `+${delta}` : `${delta}` : thisShowIdx, ) }) return vNodes } const lastGap = () => createVNode(VClickGap, { size: +at + Math.ceil((globalIdx - 1) / every) - 1 - execIdx, }) if (this.handleSpecialElements) { // handle ul, ol list if (elements.length === 1 && listTags.includes(elements[0].type as string) && Array.isArray(elements[0].children)) return h(elements[0], {}, [...mapChildren(elements[0].children), lastGap()]) if (elements.length === 1 && elements[0].type as string === 'table') { const tableNode = elements[0] if (Array.isArray(tableNode.children)) { return h(tableNode, {}, tableNode.children.map((i) => { if (!isVNode(i)) return i else if (i.type === 'tbody' && Array.isArray(i.children)) return h(i, {}, [...mapChildren(i.children), lastGap()]) else return h(i) })) } } } return [...mapChildren(elements), lastGap()] }, }) ================================================ FILE: packages/client/builtin/VDrag.vue ================================================ ================================================ FILE: packages/client/builtin/VDragArrow.vue ================================================ ================================================ FILE: packages/client/builtin/VSwitch.ts ================================================ import type { PropType, Ref, Slot, TransitionGroupProps, VNode } from 'vue' import { recomputeAllPoppers } from 'floating-vue' import { defineComponent, h, onMounted, onUnmounted, ref, TransitionGroup, watchEffect } from 'vue' import { CLASS_VCLICK_CURRENT, CLASS_VCLICK_DISPLAY_NONE, CLASS_VCLICK_PRIOR, CLASS_VCLICK_TARGET, CLICKS_MAX } from '../constants' import { useSlideContext } from '../context' import { resolveTransition } from '../logic/transition' import { makeId } from '../logic/utils' import { hmrSkipTransition } from '../state' export default defineComponent({ props: { at: { type: [Number, String], default: '+1', }, /** * unmount or hide the content when it's not visible */ unmount: { type: Boolean, default: false, }, transition: { type: [Object, String, Boolean] as PropType, default: false, }, tag: { type: String, default: 'div', }, childTag: { type: String, default: 'div', }, }, setup({ at, unmount, transition, tag, childTag }, { slots }) { const slotEntries = Object.entries(slots).sort((a, b) => -a[0].split('-')[0] + +b[0].split('-')[0]) const contents: [start: number, end: number, slot: Slot | undefined, elRef: Ref][] = [] let lastStart: number | undefined for (const [range, slot] of slotEntries) { const elRef = ref() if (Number.isFinite(+range)) { contents.push([+range, lastStart ?? +range + 1, slot, elRef]) lastStart = +range } else { const [start, end] = range.split('-').map(Number) if (!Number.isFinite(start) || !Number.isFinite(end)) throw new Error(`Invalid range for v-switch: ${range}`) contents.push([start, end, slot, elRef]) lastStart = start } } const size = Math.max(...contents.map(c => c[1])) - 1 const id = makeId() const offset = ref(0) const { $clicksContext: clicks, $nav: nav } = useSlideContext() onMounted(() => { const clicksInfo = clicks.calculateSince(at, size) if (!clicksInfo) { offset.value = CLICKS_MAX return } clicks.register(id, clicksInfo) watchEffect(() => { offset.value = clicksInfo.currentOffset.value + 1 }) }) onUnmounted(() => { clicks.unregister(id) }) function onAfterLeave() { // Refer to SlidesShow.vue hmrSkipTransition.value = true recomputeAllPoppers() } const transitionProps = transition && { ...resolveTransition(transition, nav.value.navDirection < 0), tag, onAfterLeave, } return () => { const children: VNode[] = [] for (let i = contents.length - 1; i >= 0; i--) { const [start, end, slot, ref] = contents[i] const visible = start <= offset.value && offset.value < end if (unmount && !visible) continue children.push(h(childTag, { 'key': i, ref, 'class': [ CLASS_VCLICK_TARGET, offset.value === start && CLASS_VCLICK_CURRENT, offset.value >= end && CLASS_VCLICK_PRIOR, !visible && CLASS_VCLICK_DISPLAY_NONE, ].filter(Boolean), 'data-slidev-clicks-start': start, 'data-slidev-clicks-end': end, }, slot?.())) } return transitionProps ? h(TransitionGroup, hmrSkipTransition.value ? {} : transitionProps, () => children) : h(tag, children) } }, }) ================================================ FILE: packages/client/builtin/Youtube.vue ================================================