├── .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
├── .gitpod.yml
├── .npmrc
├── .vscode
├── extensions.json
├── launch.json
└── settings.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── assets
├── assets
│ └── arrow-bottom-left.svg
├── demo-cover.png
├── favicon.png
├── logo-circle.png
├── logo-for-vscode.png
├── logo-mono-dark.svg
├── logo-mono.svg
├── logo-square.png
├── logo-title.png
├── logo-triangle.png
├── logo.png
├── logo.svg
├── og-image.png
├── screenshots
│ ├── cover.png
│ ├── covers.png
│ ├── integrated-editor.png
│ ├── navbar.png
│ ├── presenter-mode.png
│ ├── recording.png
│ └── slides-overview.png
├── showcases
│ └── composable-vue.png
└── themes
│ ├── default-1.png
│ ├── default-2.png
│ ├── default.png
│ ├── placeholder.png
│ └── seriph.png
├── cypress.config.ts
├── cypress
├── e2e
│ └── examples
│ │ ├── basic.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
├── 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
├── .npmrc
├── .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
├── components.d.ts
├── custom
│ ├── config-code-runners.md
│ ├── config-context-menu.md
│ ├── config-fonts.md
│ ├── config-highlighter.md
│ ├── config-katex.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
│ ├── 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
│ ├── mdc.md
│ ├── mermaid.md
│ ├── monaco-editor.md
│ ├── monaco-run.md
│ ├── monaco-write.md
│ ├── plantuml.md
│ ├── prettier-plugin.md
│ ├── recording.md
│ ├── remote-access.md
│ ├── rough-marker.md
│ ├── shiki-magic-move.md
│ ├── side-editor.md
│ ├── slide-hook.md
│ ├── slide-scope-style.md
│ ├── slot-sugar.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
│ ├── write-addon.md
│ ├── write-layout.md
│ └── write-theme.md
├── index.md
├── netlify.toml
├── package.json
├── public
│ ├── assets
│ │ ├── arrow-bottom-left.svg
│ │ └── code-groups-demo.png
│ ├── demo-cover.png
│ ├── favicon.png
│ ├── logo-circle.png
│ ├── logo-for-vscode.png
│ ├── logo-square.png
│ ├── logo-title.png
│ ├── logo-triangle.png
│ ├── logo.png
│ ├── logo.svg
│ ├── og-image.png
│ ├── screenshots
│ │ ├── cover.png
│ │ ├── covers.png
│ │ ├── integrated-editor.png
│ │ ├── navbar.png
│ │ ├── presenter-mode.png
│ │ ├── recording.png
│ │ └── slides-overview.png
│ ├── showcases
│ │ └── composable-vue.png
│ └── theme-placeholder.png
├── 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
│ ├── App.vue
│ ├── README.md
│ ├── assets
│ │ ├── favicon.png
│ │ ├── logo-title-horizontal.png
│ │ ├── logo.png
│ │ └── logo.svg
│ ├── 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
│ │ ├── useNav.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
│ │ ├── 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
│ │ ├── 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.vue
│ │ ├── overview.vue
│ │ ├── play.vue
│ │ ├── presenter.vue
│ │ ├── presenter
│ │ │ └── print.vue
│ │ └── print.vue
│ ├── setup
│ │ ├── code-runners.ts
│ │ ├── context-menu.ts
│ │ ├── main.ts
│ │ ├── mermaid.ts
│ │ ├── monaco.ts
│ │ ├── root.ts
│ │ ├── routes.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
│ │ └── 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.ts
│ │ ├── setups
│ │ │ ├── indexHtml.ts
│ │ │ ├── katex.ts
│ │ │ ├── load.ts
│ │ │ ├── preparser.ts
│ │ │ ├── shiki.ts
│ │ │ ├── transformers.ts
│ │ │ └── unocss.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
│ │ │ ├── shiki.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
│ │ │ ├── remoteAssets.ts
│ │ │ ├── serverRef.ts
│ │ │ ├── staticCopy.ts
│ │ │ ├── unocss.ts
│ │ │ ├── userPlugins.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
│ ├── import-meta-url.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
│ │ ├── useDevServer.ts
│ │ ├── useEditingSlideSource.ts
│ │ ├── useFocusedSlideNo.ts
│ │ ├── usePreviewState.ts
│ │ ├── useProjectFromDoc.ts
│ │ └── useServerDetector.ts
│ ├── configs.ts
│ ├── html
│ │ ├── error.ts
│ │ └── ready.ts
│ ├── index.ts
│ ├── languageClient.ts
│ ├── projects.ts
│ ├── utils
│ │ ├── findPossibleEntries.ts
│ │ ├── findShallowestPath.ts
│ │ ├── getFirstDisplayedChild.ts
│ │ ├── getSlideNo.ts
│ │ ├── getSlidesTitle.ts
│ │ └── toRelativePath.ts
│ └── views
│ │ ├── annotations.ts
│ │ ├── foldings.ts
│ │ ├── logger.ts
│ │ ├── previewWebview.ts
│ │ ├── projectsTree.ts
│ │ ├── serverTerminal.ts
│ │ └── slidesTree.ts
│ ├── syntaxes
│ ├── .vscode
│ │ └── settings.json
│ ├── codeblock-patch.ts
│ ├── codeblock.json
│ ├── language-configuration.json
│ ├── markdown.json
│ ├── slidev.example.md
│ ├── slidev.tmLanguage.json
│ └── tsconfig.json
│ ├── tsconfig.json
│ └── tsdown.config.ts
├── patches
└── @hedgedoc__markdown-it-plugins@2.1.4.patch
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── scripts
├── demo.mjs
├── gen-layouts.ts
├── pack.mjs
├── publish.mjs
├── remove-overridden-deps.mjs
└── update-versions.mjs
├── shim.d.ts
├── 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
├── parser.test.ts
├── transform-all.test.ts
├── transform-magic-move.test.ts
├── transform.test.ts
└── utils.test.ts
├── tsconfig.json
└── tsdown.config.ts
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: antfu
2 | opencollective: slidev
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F41E Bug report"
3 | about: Create a report to help us improve
4 | title: ''
5 | type: Bug
6 | labels: ['pending triage']
7 | assignees: ''
8 | ---
9 |
10 |
11 |
12 |
13 |
14 | **Describe the bug**
15 |
16 | A clear and concise description of what the bug is.
17 |
18 | **Minimal reproduction**
19 |
20 | Steps to reproduce the behavior:
21 |
22 | 1. Go to '...'
23 | 2. Click on '....'
24 | 3. Scroll down to '....'
25 | 4. See the error
26 |
27 | You can use https://sli.dev/new to create a new project to reproduce the issue.
28 |
29 | **Environment**
30 |
31 | - Slidev version:
32 | - Browser:
33 | - OS:
34 |
35 | 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`).
36 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | contact_links:
2 | - name: Questions & Discussions
3 | url: https://github.com/slidevjs/slidev/discussions
4 | about: Use GitHub discussions for message-board style questions and discussions.
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U00002728 Feature request"
3 | about: Suggest an idea for this project
4 | title: ''
5 | type: Feature
6 | assignees: ''
7 | ---
8 |
9 | **Is your feature request related to a problem? Please describe.**
10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
11 |
12 | **Describe the solution you'd like**
13 | A clear and concise description of what you want to happen.
14 |
15 | **Describe alternatives you've considered**
16 | A clear and concise description of any alternative solutions or features you've considered.
17 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | daysUntilStale: 60
2 | daysUntilClose: 7
3 | exemptLabels:
4 | - pinned
5 | - security
6 | - no-stale
7 | - no stale
8 | - pr welcome
9 | - help wanted
10 | staleLabel: stale
11 | markComment: >
12 | This issue has been automatically marked as stale because it has not had
13 | recent activity. It will be closed if no further activity occurs. Thank you
14 | for your contributions.
15 | closeComment: false
16 |
--------------------------------------------------------------------------------
/.github/workflows/autofix.yml:
--------------------------------------------------------------------------------
1 | name: autofix.ci
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 | permissions:
11 | contents: read
12 |
13 | jobs:
14 | autofix:
15 | runs-on: ubuntu-latest
16 | timeout-minutes: 10
17 |
18 | steps:
19 | - uses: actions/checkout@v4
20 |
21 | - name: Use Node.js lts/*
22 | uses: actions/setup-node@v4
23 | with:
24 | node-version: lts/*
25 |
26 | - name: Setup
27 | run: npm i -g @antfu/ni
28 |
29 | - name: Install
30 | run: nci
31 | env:
32 | CYPRESS_INSTALL_BINARY: 0
33 |
34 | - name: Lint
35 | run: nr lint --fix
36 |
37 | - uses: autofix-ci/action@dd55f44df8f7cdb7a6bf74c78677eb8acd40cd0a
38 |
--------------------------------------------------------------------------------
/.github/workflows/cr.yml:
--------------------------------------------------------------------------------
1 | # Continuous Releases provided by https://pkg.pr.new
2 | name: CR (Continuous Releases)
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | cr:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - name: Checkout code
11 | uses: actions/checkout@v2
12 |
13 | - uses: actions/setup-node@v4
14 | with:
15 | node-version: lts/*
16 |
17 | - run: npm i -g @antfu/ni
18 | - run: nci
19 |
20 | - name: Build
21 | run: nr build
22 |
23 | - run: nlx pkg-pr-new publish './packages/create-app' './packages/client' './packages/create-theme' './packages/parser' './packages/slidev' './packages/types' --pnpm
24 | env:
25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v*'
7 |
8 | jobs:
9 | release:
10 | permissions:
11 | id-token: write
12 | contents: write
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v4
16 | with:
17 | fetch-depth: 0
18 | - uses: actions/setup-node@v4
19 | with:
20 | node-version: lts/*
21 | registry-url: https://registry.npmjs.org/
22 | - run: npx changelogithub
23 | env:
24 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
25 | - run: npm i -g @antfu/ni
26 | - run: nci
27 | - run: nr ci:publish
28 | env:
29 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
30 | NPM_CONFIG_PROVENANCE: true
31 |
32 | - name: Publish to VSCE & OVSX
33 | run: npm run publish
34 | working-directory: ./packages/vscode
35 | env:
36 | VSCE_TOKEN: ${{secrets.VSCE_TOKEN}}
37 | OVSX_TOKEN: ${{secrets.OVSX_TOKEN}}
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .eslintcache
3 | .idea
4 | .nuxt
5 | .output
6 | .slidev
7 | .vite-inspect
8 | *-export
9 | *.local
10 | *.pdf
11 | assets/demo
12 | components.d.ts
13 | composable-vue-cn
14 | dist
15 | dist-ssr
16 | docs/.vitepress/@slidev
17 | docs/.vitepress/cache
18 | node_modules
19 | cypress/downloads
20 | packages/create-app/template/pages
21 | packages/create-app/template/slides.md
22 | packages/create-app/template/snippets
23 | packages/slidev/README.md
24 | packages/vscode/syntaxes/codeblock-patch.json
25 | slides-export.md
26 | *slides-export.pptx
27 |
--------------------------------------------------------------------------------
/.gitpod.yml:
--------------------------------------------------------------------------------
1 | # List the start up tasks. Learn more https://www.gitpod.io/docs/config-start-tasks/
2 | tasks:
3 | - before: npm i -g pnpm
4 | init: |
5 | pnpm install
6 | pnpm build
7 | command: pnpm demo:dev
8 |
9 | # List the ports to expose. Learn more https://www.gitpod.io/docs/config-ports/
10 | ports:
11 | - port: 3030
12 | onOpen: open-preview
13 |
14 | # List the VS Code extensions to install. Learn more https://www.gitpod.io/docs/vscode-extensions/
15 | vscode:
16 | extensions:
17 | - antfu.vite
18 | - Vue.volar
19 | - antfu.iconify
20 | - dbaeumer.vscode-eslint
21 | - csstools.postcss
22 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | shamefully-hoist=true
2 | ignore-workspace-root-check=true
3 | strict-peer-dependencies=false
4 | link-workspace-packages=true
5 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "antfu.vite",
4 | "Vue.volar",
5 | "antfu.iconify",
6 | "dbaeumer.vscode-eslint",
7 | "antfu.unocss",
8 | "csstools.postcss",
9 | "antfu.pnpm-catalog-lens"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Run Extension",
6 | "type": "extensionHost",
7 | "request": "launch",
8 | "autoAttachChildProcesses": true,
9 | "args": [
10 | "--extensionDevelopmentPath=${workspaceFolder}/packages/vscode",
11 | "--folder-uri=${workspaceRoot}/packages/vscode/syntaxes"
12 | ],
13 | "outFiles": [
14 | "${workspaceFolder}/packages/vscode/dist/**/*.js"
15 | ]
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020-PRESENT Anthony Fu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/assets/demo-cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/demo-cover.png
--------------------------------------------------------------------------------
/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/favicon.png
--------------------------------------------------------------------------------
/assets/logo-circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/logo-circle.png
--------------------------------------------------------------------------------
/assets/logo-for-vscode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/logo-for-vscode.png
--------------------------------------------------------------------------------
/assets/logo-square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/logo-square.png
--------------------------------------------------------------------------------
/assets/logo-title.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/logo-title.png
--------------------------------------------------------------------------------
/assets/logo-triangle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/logo-triangle.png
--------------------------------------------------------------------------------
/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/logo.png
--------------------------------------------------------------------------------
/assets/og-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/og-image.png
--------------------------------------------------------------------------------
/assets/screenshots/cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/screenshots/cover.png
--------------------------------------------------------------------------------
/assets/screenshots/covers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/screenshots/covers.png
--------------------------------------------------------------------------------
/assets/screenshots/integrated-editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/screenshots/integrated-editor.png
--------------------------------------------------------------------------------
/assets/screenshots/navbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/screenshots/navbar.png
--------------------------------------------------------------------------------
/assets/screenshots/presenter-mode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/screenshots/presenter-mode.png
--------------------------------------------------------------------------------
/assets/screenshots/recording.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/screenshots/recording.png
--------------------------------------------------------------------------------
/assets/screenshots/slides-overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/screenshots/slides-overview.png
--------------------------------------------------------------------------------
/assets/showcases/composable-vue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/showcases/composable-vue.png
--------------------------------------------------------------------------------
/assets/themes/default-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/themes/default-1.png
--------------------------------------------------------------------------------
/assets/themes/default-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/themes/default-2.png
--------------------------------------------------------------------------------
/assets/themes/default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/themes/default.png
--------------------------------------------------------------------------------
/assets/themes/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/themes/placeholder.png
--------------------------------------------------------------------------------
/assets/themes/seriph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/assets/themes/seriph.png
--------------------------------------------------------------------------------
/cypress.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'cypress'
2 |
3 | export default defineConfig({
4 | e2e: {
5 | baseUrl: 'http://localhost:3041',
6 | chromeWebSecurity: false,
7 | specPattern: 'cypress/e2e/**/*.spec.*',
8 | supportFile: false,
9 | },
10 | })
11 |
--------------------------------------------------------------------------------
/cypress/e2e/examples/smoke.spec.ts:
--------------------------------------------------------------------------------
1 | context('Smoke test', () => {
2 | async function testAllSlides() {
3 | while (1) {
4 | let oldUrl, newUrl
5 | cy.get('body')
6 | .url()
7 | .then(url => (oldUrl = url))
8 | .type(`{RightArrow}`)
9 | .wait(1000)
10 | .url()
11 | .then(url => (newUrl = url))
12 | if (oldUrl === newUrl)
13 | break
14 | }
15 | }
16 |
17 | it('should throw no error in Play mode', async () => {
18 | cy.visit('/').wait(4000)
19 | await testAllSlides()
20 | })
21 |
22 | it('should throw no error in Presenter mode', async () => {
23 | cy.visit('/presenter').wait(4000)
24 | await testAllSlides()
25 | })
26 |
27 | it('should throw no error in Overview page', async () => {
28 | cy.visit('/overview').wait(4000)
29 | })
30 |
31 | it('should throw no error in Entry page', async () => {
32 | cy.visit('/entry').wait(4000)
33 | })
34 | })
35 |
--------------------------------------------------------------------------------
/cypress/fixtures/basic/components/DecorateWithLi.vue:
--------------------------------------------------------------------------------
1 |
2 | Step b
3 |
4 | Step y
5 |
6 |
--------------------------------------------------------------------------------
/cypress/fixtures/basic/components/WrapInClicks.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/cypress/fixtures/basic/components/WrapInClicksDecorate.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/cypress/fixtures/basic/components/WrapInComponentInClicks.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Point a
5 |
6 |
7 |
8 | Point z
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/cypress/fixtures/basic/global.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 | Global Footer (appear only on odd page)
7 |
8 |
9 |
--------------------------------------------------------------------------------
/cypress/fixtures/basic/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "nodemon -w '../../../packages/slidev/dist/*.js' --exec 'slidev --log=info --port=3041'",
5 | "build": "slidev build",
6 | "export": "slidev export"
7 | },
8 | "devDependencies": {
9 | "@slidev/cli": "workspace:*",
10 | "@slidev/theme-default": "catalog:themes",
11 | "@slidev/theme-seriph": "catalog:themes",
12 | "@slidev/types": "workspace:*",
13 | "nodemon": "catalog:dev"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/cypress/fixtures/basic/sub/page1.md:
--------------------------------------------------------------------------------
1 | # Sub page 1
2 |
3 | $x+2$
4 |
--------------------------------------------------------------------------------
/cypress/fixtures/basic/sub/page2.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: cover
3 | ---
4 |
5 | # Sub page 2
6 |
7 |
8 |
--------------------------------------------------------------------------------
/cypress/fixtures/basic/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 |
3 | export default defineConfig({
4 | build: {
5 | manifest: true,
6 | minify: false,
7 | },
8 | })
9 |
--------------------------------------------------------------------------------
/cypress/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "types": ["cypress"],
5 | "noEmit": true
6 | },
7 | "include": [
8 | "../node_modules/cypress",
9 | "./**/*.ts"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/demo/README.md:
--------------------------------------------------------------------------------
1 | The best way of understanding Slidev is to try it, with the following command:
2 |
3 | ```bash
4 | npm init slidev
5 | ```
6 |
7 | Learn more: https://sli.dev
8 |
--------------------------------------------------------------------------------
/demo/composable-vue/components/DarkToggle.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
{{ isDark ? 'Dark' : 'Light' }}
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/demo/composable-vue/components/Marker.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/demo/composable-vue/components/MarkerCore.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Core
4 |
5 |
6 |
--------------------------------------------------------------------------------
/demo/composable-vue/components/MarkerPattern.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Pattern
4 |
5 |
6 |
--------------------------------------------------------------------------------
/demo/composable-vue/components/MarkerTips.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Tips
4 |
5 |
6 |
--------------------------------------------------------------------------------
/demo/composable-vue/components/VueUse.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/demo/composable-vue/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/demo/composable-vue/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "nodemon -w '../../packages/slidev/dist/*.mjs' --exec 'slidev --log=info'",
5 | "build": "slidev build",
6 | "export": "slidev export",
7 | "export:clicks": "slidev export --with-clicks"
8 | },
9 | "devDependencies": {
10 | "@iconify-json/mdi": "catalog:icons",
11 | "@iconify-json/ri": "catalog:icons",
12 | "@slidev/cli": "workspace:*",
13 | "@slidev/theme-default": "catalog:themes",
14 | "@slidev/theme-seriph": "catalog:themes",
15 | "@slidev/types": "workspace:*",
16 | "nodemon": "catalog:dev"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/composable-vue/setup/monaco.ts:
--------------------------------------------------------------------------------
1 | import { defineMonacoSetup } from '@slidev/types'
2 |
3 | export default defineMonacoSetup((monaco) => {
4 | monaco.languages.typescript.typescriptDefaults.addExtraLib(
5 | `
6 | import { InjectionKey } from 'vue'
7 | export interface UserInfo { id: number; name: string }
8 | export const injectKeyUser: InjectionKey = Symbol()
9 | `,
10 | 'file:///root/context.ts',
11 | )
12 | })
13 |
--------------------------------------------------------------------------------
/demo/starter/README.md:
--------------------------------------------------------------------------------
1 | See [../../packages/create-app/template/README.md](../../packages/create-app/template/README.md)
2 |
--------------------------------------------------------------------------------
/demo/starter/components/Counter.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
23 | -
24 |
25 | {{ counter }}
26 |
34 | +
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/demo/starter/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "slidev-demo",
3 | "private": true,
4 | "scripts": {
5 | "build": "slidev build",
6 | "dev": "nodemon -w '../../packages/slidev/dist/*.mjs' --exec \"slidev ./slides.md --open=false --log=info --inspect\"",
7 | "export": "slidev export",
8 | "export-notes": "slidev export-notes"
9 | },
10 | "devDependencies": {
11 | "@slidev/cli": "workspace:*",
12 | "@slidev/theme-default": "catalog:themes",
13 | "@slidev/theme-seriph": "catalog:themes",
14 | "nodemon": "catalog:dev",
15 | "vue": "catalog:frontend"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/demo/starter/pages/imported-slides.md:
--------------------------------------------------------------------------------
1 | # Imported Slides
2 |
3 | You can split your slides.md into multiple files and organize them as you want using the `src` attribute.
4 |
5 | #### `slides.md`
6 |
7 | ```markdown
8 | # Page 1
9 |
10 | Page 2 from main entry.
11 |
12 | ---
13 |
14 | ## src: ./subpage.md
15 | ```
16 |
17 |
18 |
19 | #### `subpage.md`
20 |
21 | ```markdown
22 | # Page 2
23 |
24 | Page 2 from another file.
25 | ```
26 |
27 | [Learn more](https://sli.dev/guide/syntax.html#importing-slides)
28 |
--------------------------------------------------------------------------------
/demo/starter/snippets/external.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | // #region snippet
4 | // Inside ./snippets/external.ts
5 | export function emptyArray(length: number) {
6 | return Array.from({ length })
7 | }
8 | // #endregion snippet
9 |
10 | export function sayHello() {
11 | console.log('Hello from snippets/external.ts')
12 | }
13 |
--------------------------------------------------------------------------------
/demo/starter/style.css:
--------------------------------------------------------------------------------
1 | /* add any global style here */
2 |
--------------------------------------------------------------------------------
/demo/starter/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 |
3 | export default defineConfig({
4 | plugins: [],
5 | })
6 |
--------------------------------------------------------------------------------
/demo/vue-runner/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "build": "slidev build",
5 | "dev": "nodemon -w '../../packages/slidev/dist/*.mjs' --exec \"slidev ./slides.md --open=false --log=info --inspect\"",
6 | "export": "slidev export",
7 | "export-notes": "slidev export-notes"
8 | },
9 | "devDependencies": {
10 | "@slidev/cli": "workspace:*",
11 | "@slidev/theme-default": "catalog:themes",
12 | "@slidev/theme-seriph": "catalog:themes",
13 | "@vue/compiler-sfc": "catalog:demo",
14 | "nodemon": "catalog:dev",
15 | "vue": "catalog:frontend"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/demo/vue-runner/setup/shiki.ts:
--------------------------------------------------------------------------------
1 | import type { ShikiSetupReturn } from '@slidev/types'
2 | import { defineShikiSetup } from '@slidev/types'
3 |
4 | export default defineShikiSetup((): ShikiSetupReturn => {
5 | return {
6 | langs: [
7 | 'ts',
8 | 'js',
9 | 'vue',
10 | 'html',
11 | ],
12 | }
13 | })
14 |
--------------------------------------------------------------------------------
/demo/vue-runner/slides.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | ---
4 |
5 | # Simple Vue SFC Runner
6 |
7 |
8 |
9 | ```vue {monaco-run}
10 |
16 |
17 |
18 |
19 |
20 | {{ counter }}
21 | * 2 =
22 | {{ doubled }}
23 |
24 | +1
25 | -1
26 |
27 |
28 | ```
29 |
30 | ---
31 |
32 | This is a demo to prove the extensibility of Slidev Code Runners.
33 |
34 | Refer to `./setup/monaco-runner.ts` for the implementation.
35 |
36 | Note that there is a lot of edge cases that this demo is not handling. Extra work is needed to make it production ready.
37 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | .vitepress/@slidev
4 | .vitepress/cache
5 |
--------------------------------------------------------------------------------
/docs/.npmrc:
--------------------------------------------------------------------------------
1 | shamefully-hoist=true
2 | strict-peer-dependencies=false
3 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/AddonGallery.vue:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/DemoEditor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
40 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/DemoSlide.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
27 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/Environment.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 | Environment:
9 | {{ type }}
10 |
11 |
12 |
13 |
14 | This setup function will run on both Node.js and client side. Avoid using Node.js or DOM API to prevent runtime errors.
15 |
16 |
17 | This setup function will only run on Node.js environment, you can have access to Node's API.
18 |
19 |
20 | This setup function will only run on client side. Make sure the browser compatibility when importing packages.
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/FeaturesAnimation.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/LandingPage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Slidev
6 |
7 |
8 |
9 | Presentation Slides for Developers
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/SeeAlso.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 | See also:
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/ShowCases.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/ThemeGallery.vue:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/composables/dark.ts:
--------------------------------------------------------------------------------
1 | import { useDark } from '@vueuse/core'
2 |
3 | export const isDark = useDark()
4 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/index.ts:
--------------------------------------------------------------------------------
1 | import type { EnhanceAppContext } from 'vitepress'
2 | import TwoSlash from '@shikijs/vitepress-twoslash/client'
3 | import Theme from 'vitepress/theme'
4 | import Layout from './components/Layout.vue'
5 |
6 | import '@shikijs/vitepress-twoslash/style.css'
7 | import './styles/vars.css'
8 | import './styles/demo.css'
9 | import './styles/custom.css'
10 | import 'uno.css'
11 | import 'virtual:group-icons.css'
12 |
13 | export default {
14 | extends: Theme,
15 | enhanceApp({ app }: EnhanceAppContext) {
16 | app.use(TwoSlash as any)
17 | },
18 | Layout,
19 | }
20 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/styles/custom.css:
--------------------------------------------------------------------------------
1 | .icon-btn {
2 | --uno: inline-block cursor-pointer select-none important-outline-none;
3 | --uno: opacity-75 transition duration-200 ease-in-out align-middle rounded p-2;
4 | --uno: hover-(opacity-100 bg-gray-400 bg-opacity-10);
5 | }
6 |
7 | .icon-btn.disabled {
8 | --uno: opacity-25 pointer-events-none;
9 | }
10 |
11 | .inline-icon-btn {
12 | --uno: text-primary-deep;
13 | --uno: inline-block rounded p-0.5 text-2xl align-middle;
14 | --uno: border border-primary border-opacity-20 border-solid;
15 | }
16 |
17 | kbd {
18 | --uno: border-rounded bg-$vp-c-gray-1 bg-opacity-10 px-1 py-.5;
19 | }
20 |
21 | [data-tweet-id] {
22 | border-radius: 13px;
23 | }
24 |
--------------------------------------------------------------------------------
/docs/custom/config-katex.md:
--------------------------------------------------------------------------------
1 | # Configure KaTeX
2 |
3 |
4 |
5 | Create `./setup/katex.ts` with the following content:
6 |
7 | ```ts twoslash [setup/katex.ts]
8 | import { defineKatexSetup } from '@slidev/types'
9 |
10 | export default defineKatexSetup(() => {
11 | return {
12 | maxExpand: 2000,
13 | /* ... */
14 | }
15 | })
16 | ```
17 |
18 | 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.
19 |
--------------------------------------------------------------------------------
/docs/custom/config-routes.md:
--------------------------------------------------------------------------------
1 | # Configure Routes
2 |
3 |
4 |
5 | Add custom pages to the Slidev app.
6 |
7 | ## Usage
8 |
9 | Create `./setup/routes.ts` with the following content:
10 |
11 | ```ts twoslash [./setup/routes.ts]
12 | import { defineRoutesSetup } from '@slidev/types'
13 |
14 | export default defineRoutesSetup((routes) => {
15 | return [
16 | ...routes,
17 | {
18 | path: '/my-page',
19 | // ---cut-start---
20 | // @ts-expect-error missing types
21 | // ---cut-end---
22 | component: () => import('../pages/my-page.vue'),
23 | },
24 | ]
25 | })
26 | ```
27 |
28 | Learn more about routes in the [Vue Router documentation](https://router.vuejs.org/).
29 |
--------------------------------------------------------------------------------
/docs/custom/config-vue.md:
--------------------------------------------------------------------------------
1 | # Configure Vue App
2 |
3 |
4 |
5 | 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.
6 |
7 | Create `./setup/main.ts` with the following content:
8 |
9 |
10 |
11 | ```ts twoslash [setup/main.ts]
12 | import type { Plugin } from 'vue'
13 | declare const YourPlugin: Plugin
14 | // ---cut---
15 | import { defineAppSetup } from '@slidev/types'
16 |
17 | export default defineAppSetup(({ app, router }) => {
18 | // Vue App
19 | app.use(YourPlugin)
20 | })
21 | ```
22 |
23 | This can also be used as the main entrance of your Slidev app to do some initializations before the app starts.
24 |
25 | Learn more: [Vue Application API](https://v3.vuejs.org/api/application-api.html#component).
26 |
--------------------------------------------------------------------------------
/docs/features/block-frontmatter.md:
--------------------------------------------------------------------------------
1 | ---
2 | depends:
3 | - guide/syntax
4 | relates:
5 | - features/prettier-plugin
6 | tags: [syntax]
7 | description: |
8 | Use a YAML code block as the frontmatter.
9 | ---
10 |
11 | # Block Frontmatter
12 |
13 | 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:
14 |
15 | ````md
16 | ---
17 | theme: default
18 | ---
19 |
20 | # Slide 1
21 |
22 | ---
23 |
24 | ```yaml
25 | layout: quote
26 | ```
27 |
28 | # Slide 2
29 |
30 | ---
31 |
32 | # Slide 3
33 | ````
34 |
35 | ::: warning About headmatter
36 |
37 | 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.
38 |
39 | :::
40 |
--------------------------------------------------------------------------------
/docs/features/build-with-pdf.md:
--------------------------------------------------------------------------------
1 | ---
2 | depends:
3 | - guide/exporting
4 | - guide/hosting
5 | relates:
6 | - CLI export options: /builtin/cli#export
7 | - Headmatter export options: /custom/#headmatter
8 | tags: [export, build]
9 | description: |
10 | Generate a downloadable PDF along with your slides build.
11 | ---
12 |
13 | # Generate PDF when Building
14 |
15 | You can provide a downloadable PDF in your built slides with the following config in headmatter:
16 |
17 | ```md
18 | ---
19 | download: true
20 | ---
21 | ```
22 |
23 | Slidev will generate a PDF file along with the build, and a download button will be displayed in the build.
24 |
25 | You can also provide a custom URL for the PDF. In that case, the rendering process will be skipped.
26 |
27 | ```md
28 | ---
29 | download: 'https://myside.com/my-talk.pdf'
30 | ---
31 | ```
32 |
33 | This can also be done with the CLI option `--download` (`boolean` only).
34 |
35 | ```bash
36 | $ slidev build --download
37 | ```
38 |
39 | When using the download option, you can also provide the export options via:
40 |
41 | - [CLI export options](/builtin/cli#export)
42 | - [Headmatter export options](/custom/#frontmatter-configures)
43 |
--------------------------------------------------------------------------------
/docs/features/bundle-remote-assets.md:
--------------------------------------------------------------------------------
1 | ---
2 | relates:
3 | - vite-plugin-remote-assets: https://github.com/antfu/vite-plugin-remote-assets
4 | tags: [build]
5 | description: |
6 | Download and bundle remote assets when building your slides.
7 | ---
8 |
9 | # Bundle Remote Assets
10 |
11 | Just like you would do in markdown, you can use images pointing to a remote or local URL.
12 |
13 | 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.
14 |
15 | ```md
16 | 
17 | ```
18 |
19 | 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).
20 |
21 | ```md
22 | 
23 | ```
24 |
25 | If you want to apply custom sizes or styles, you can convert them to the ` ` tag:
26 |
27 | ```html
28 |
29 | ```
30 |
--------------------------------------------------------------------------------
/docs/features/canvas-size.md:
--------------------------------------------------------------------------------
1 | ---
2 | relates:
3 | - guide/faq#adjust-size
4 | - features/zoom-slide
5 | - features/transform-component
6 | tags: [layout]
7 | description: |
8 | Set the size for all your slides.
9 | ---
10 |
11 | # Slide Canvas Size
12 |
13 | Slidev allows you to set the size of the slide canvas via the `canvasWidth` and `aspectRatio` options in the headmatter:
14 |
15 | ```md
16 | ---
17 | # aspect ratio for the slides
18 | aspectRatio: 16/9
19 | # real width of the canvas, unit in px
20 | canvasWidth: 980
21 | ---
22 |
23 | # Your slides here
24 | ```
25 |
26 | To scale several slides in your presentation, you can use the `zoom` option:
27 |
28 |
29 |
30 | To adjust the size of some elements on your slides, you can use the `Transform` component:
31 |
32 |
33 |
--------------------------------------------------------------------------------
/docs/features/code-block-line-numbers.md:
--------------------------------------------------------------------------------
1 | ---
2 | depends:
3 | - guide/syntax#code-block
4 | tags: [codeblock]
5 | description: |
6 | Enable line numbering for all code blocks across the slides or individually.
7 | ---
8 |
9 | # Line Numbers
10 |
11 | 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`.
12 |
13 | You can also set the starting line for each code block and highlight the lines accordingly via `{startLine: number}`, which defaults to 1.
14 |
15 | ````md
16 | ```ts {6,7}{lines:true,startLine:5}
17 | function add(
18 | a: Ref | number,
19 | b: Ref | number
20 | ) {
21 | return computed(() => unref(a) + unref(b))
22 | }
23 | ```
24 | ````
25 |
26 | Note that you can use `{*}` as a placeholder of :
27 |
28 | ````md
29 | ```ts {*}{lines:true,startLine:5}
30 | // ...
31 | ```
32 | ````
33 |
--------------------------------------------------------------------------------
/docs/features/code-block-max-height.md:
--------------------------------------------------------------------------------
1 | ---
2 | depends:
3 | - guide/syntax#code-block
4 | tags: [codeblock, layout]
5 | description: |
6 | Set a maximum height for a code block and enable scrolling.
7 | ---
8 |
9 | # Max Height
10 |
11 | If the code doesn't fit into one slide, you use the `maxHeight` to set a fixed height and enable scrolling:
12 |
13 | ````md
14 | ```ts {2|3|7|12}{maxHeight:'100px'}
15 | function add(
16 | a: Ref | number,
17 | b: Ref | number
18 | ) {
19 | return computed(() => unref(a) + unref(b))
20 | }
21 | /// ...as many lines as you want
22 | const c = add(1, 2)
23 | ```
24 | ````
25 |
26 | Note that you can use `{*}` as a placeholder of :
27 |
28 | ````md
29 | ```ts {*}{maxHeight:'100px'}
30 | // ...
31 | ```
32 | ````
33 |
--------------------------------------------------------------------------------
/docs/features/eject-theme.md:
--------------------------------------------------------------------------------
1 | ---
2 | depends:
3 | - guide/theme-addon
4 | tags: [theme, cli]
5 | description: |
6 | Eject the installed theme from your project to customize it.
7 | ---
8 |
9 | # Eject Theme
10 |
11 | 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
12 |
13 | ```bash
14 | $ slidev theme eject
15 | ```
16 |
17 | It will eject the theme you are using currently into `./theme`, and change your frontmatter to
18 |
19 | ```yaml
20 | ---
21 | theme: ./theme
22 | ---
23 | ```
24 |
25 | 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 :)
26 |
27 | For more options of the `theme` command, please refer to the [Theme Command](../builtin/cli#theme) section.
28 |
--------------------------------------------------------------------------------
/docs/features/frontmatter-merging.md:
--------------------------------------------------------------------------------
1 | ---
2 | depends:
3 | - guide/syntax#importing-slides
4 | - features/importing-slides
5 | tags: [syntax]
6 | description: |
7 | Merge frontmatter from multiple markdown files.
8 | ---
9 |
10 | # Frontmatter Merging
11 |
12 | 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:
13 |
14 | ::: code-group
15 |
16 | ```md [./slides.md]
17 | ---
18 | src: ./cover.md
19 | background: https://sli.dev/bar.png // [!code highlight]
20 | class: text-center
21 | ---
22 | ```
23 |
24 | ```md [./cover.md]
25 | ---
26 | layout: cover
27 | background: https://sli.dev/foo.png // [!code highlight]
28 | ---
29 |
30 | # Cover
31 |
32 | Cover Page
33 | ```
34 |
35 | :::
36 |
37 | They will end up being equivalent to the following page:
38 |
39 | ```md
40 | ---
41 | layout: cover
42 | background: https://sli.dev/bar.png // [!code highlight]
43 | class: text-center
44 | ---
45 |
46 | # Cover
47 |
48 | Cover Page
49 | ```
50 |
--------------------------------------------------------------------------------
/docs/features/mdc.md:
--------------------------------------------------------------------------------
1 | ---
2 | relates:
3 | - Nuxt's MDC Syntax: https://content.nuxt.com/docs/files/markdown#mdc-syntax
4 | - markdown-it-mdc: https://github.com/antfu/markdown-it-mdc
5 | since: v0.43.0
6 | tags: [syntax, styling]
7 | description: |
8 | A powerful syntax to enhance your markdown content with components and styles.
9 | ---
10 |
11 | # MDC Syntax
12 |
13 | Slidev supports optional [MDC (Markdown Components) Syntax](https://content.nuxt.com/docs/files/markdown#mdc-syntax) powered by [`markdown-it-mdc`](https://github.com/antfu/markdown-it-mdc).
14 |
15 | You can enable it by adding `mdc: true` to the frontmatter of your markdown file.
16 |
17 | ```mdc
18 | ---
19 | mdc: true
20 | ---
21 |
22 | This is a [red text]{style="color:red"} :inline-component{prop="value"}
23 |
24 | {width=500px lazy}
25 |
26 | ::block-component{prop="value"}
27 | The **default** slot
28 | ::
29 | ```
30 |
31 | Learn more about [MDC Syntax](https://content.nuxt.com/docs/files/markdown#mdc-syntax).
32 |
--------------------------------------------------------------------------------
/docs/features/mermaid.md:
--------------------------------------------------------------------------------
1 | ---
2 | relates:
3 | - Mermaid: https://mermaid.js.org/
4 | - Mermaid Live Editor: https://mermaid.live/
5 | - Demo Slide: https://sli.dev/demo/starter/12
6 | - features/plantuml
7 | tags: [diagram]
8 | description: |
9 | Create diagrams/graphs from textual descriptions, powered by Mermaid.
10 | ---
11 |
12 | # Mermaid Diagrams
13 |
14 | You can also create diagrams/graphs from textual descriptions in your Markdown, powered by [Mermaid](https://mermaid.js.org/).
15 |
16 | Code blocks marked as `mermaid` will be converted to diagrams, for example:
17 |
18 | ````md
19 | ```mermaid
20 | sequenceDiagram
21 | Alice->John: Hello John, how are you?
22 | Note over Alice,John: A typical interaction
23 | ```
24 | ````
25 |
26 | 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.
27 |
28 | ````md
29 | ```mermaid {theme: 'neutral', scale: 0.8}
30 | graph TD
31 | B[Text] --> C{Decision}
32 | C -->|One| D[Result 1]
33 | C -->|Two| E[Result 2]
34 | ```
35 | ````
36 |
37 | Visit the [Mermaid Website](https://mermaid.js.org/) for more information.
38 |
--------------------------------------------------------------------------------
/docs/features/monaco-write.md:
--------------------------------------------------------------------------------
1 | ---
2 | depends:
3 | - features/monaco-editor
4 | - features/import-snippet
5 | relates:
6 | - features/import-snippet
7 | - Custom Code Runners: /custom/config-code-runners
8 | since: v0.49.5
9 | tags: [codeblock, editor]
10 | description: |
11 | A monaco editor that allows you to write code directly in the slides and save the changes back to the file.
12 | ---
13 |
14 | # Writable Monaco Editor
15 |
16 | 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.
17 |
18 | ```md
19 | <<< ./some-file.ts {monaco-write}
20 | ```
21 |
22 | When using this, be sure to back up your files beforehand, as the changes will be saved directly to the file.
23 |
--------------------------------------------------------------------------------
/docs/features/plantuml.md:
--------------------------------------------------------------------------------
1 | ---
2 | relates:
3 | - Plant UML: https://plantuml.com/
4 | - Plant UML Live Editor: https://plantuml.com/plantuml
5 | - Example side: https://sli.dev/demo/starter/12
6 | - features/mermaid
7 | tags: [diagram]
8 | description: |
9 | Create diagrams from textual descriptions, powered by PlantUML.
10 | ---
11 |
12 | # PlantUML Diagrams
13 |
14 | You can create PlantUML diagrams easily in your slides, for example:
15 |
16 | ````md
17 | ```plantuml
18 | @startuml
19 | Alice -> Bob : Hello!
20 | @enduml
21 | ```
22 | ````
23 |
24 | 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).
25 |
26 | Visit the [PlantUML Website](https://plantuml.com/) for more information.
27 |
--------------------------------------------------------------------------------
/docs/features/side-editor.md:
--------------------------------------------------------------------------------
1 | ---
2 | depends:
3 | - guide/ui#navigation-actions
4 | relates:
5 | - features/vscode-extension
6 | tags: [editor]
7 | description: |
8 | Edit your slides source file alongside the presentation.
9 | ---
10 |
11 | # Integrated Editor
12 |
13 | Slidev comes with an integrated editor that will instantly reload and save the changes to your file.
14 |
15 | Click the button on the navigation panel to open it.
16 |
17 | 
18 |
--------------------------------------------------------------------------------
/docs/features/slide-hook.md:
--------------------------------------------------------------------------------
1 | ---
2 | depends:
3 | - guide/global-context
4 | tags: [client-api]
5 | description: |
6 | Hooks to manage the slide lifecycle.
7 | ---
8 |
9 | # Slide Hooks
10 |
11 | Slidev provides a set of hooks to help you manage the slide lifecycle:
12 |
13 | ```ts twoslash
14 | import { onSlideEnter, onSlideLeave, useIsSlideActive } from '@slidev/client'
15 |
16 | const isActive = useIsSlideActive()
17 |
18 | onSlideEnter(() => {
19 | /* Called whenever the slide becomes active */
20 | })
21 |
22 | onSlideLeave(() => {
23 | /* Called whenever the slide becomes inactive */
24 | })
25 | ```
26 |
27 | You can also use to access other useful context information.
28 |
29 | ::: warning
30 |
31 | 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.
32 |
33 | :::
34 |
--------------------------------------------------------------------------------
/docs/features/slide-scope-style.md:
--------------------------------------------------------------------------------
1 | ---
2 | relates:
3 | - Vue's Scoped CSS: https://vuejs.org/api/sfc-css-features.html#scoped-css
4 | - UnoCSS directives: https://unocss.dev/transformers/directives
5 | tags: [styling, syntax]
6 | description: |
7 | Define styles for only the current slide.
8 | ---
9 |
10 | # Slide Scope Styles
11 |
12 | You can use the `
22 |
23 | ---
24 |
25 | # Other slides are not affected
26 | ```
27 |
28 | The `
44 | ```
45 |
--------------------------------------------------------------------------------
/docs/features/transform-component.md:
--------------------------------------------------------------------------------
1 | ---
2 | relates:
3 | - guide/faq#adjust-size
4 | - features/canvas-size
5 | - features/zoom-slide
6 | tags: [layout]
7 | description: |
8 | A component for scaling some elements.
9 | ---
10 |
11 | # The `Transform` Component
12 |
13 | The `Transform` component allows you to scale the size of the elements on your slides:
14 |
15 | ```md
16 |
17 |
18 |
19 | ```
20 |
21 | This is useful when you want to adjust the size of some elements on your slides without affecting the layout of the entire slide.
22 |
23 | To scale all the slides in your presentation, you can set the slide canvas size:
24 |
25 |
26 |
27 | To scale several slides in your presentation, you can use the `zoom` option:
28 |
29 |
30 |
--------------------------------------------------------------------------------
/docs/features/twoslash.md:
--------------------------------------------------------------------------------
1 | ---
2 | depends:
3 | - guide/syntax#code-block
4 | relates:
5 | - TwoSlash: https://twoslash.netlify.app/
6 | since: v0.46.0
7 | tags: [codeblock]
8 | description: |
9 | A powerful tool for rendering TypeScript code blocks with type information on hover or inlined.
10 | ---
11 |
12 | # TwoSlash Integration
13 |
14 | [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.
15 |
16 | To use it, you can add `twoslash` to the code block's language identifier:
17 |
18 | ````md
19 | ```ts twoslash
20 | import { ref } from 'vue'
21 |
22 | const count = ref(0)
23 | // ^?
24 | ```
25 | ````
26 |
27 | It will be rendered as:
28 |
29 | ```ts twoslash
30 | import { ref } from 'vue'
31 |
32 | const count = ref(0)
33 | // ^?
34 | ```
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/docs/features/zoom-slide.md:
--------------------------------------------------------------------------------
1 | ---
2 | relates:
3 | - guide/faq#adjust-size
4 | - features/canvas-size
5 | - features/transform-component
6 | tags: [layout]
7 | description: |
8 | Zoom the content of a slide to a specific scale.
9 | ---
10 |
11 | # Zoom Slides
12 |
13 | 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:
14 |
15 | ```md
16 | ---
17 | zoom: 0.8
18 | ---
19 |
20 | # A Slide with lots of content
21 |
22 | ---
23 |
24 | # Other slides aren't affected
25 | ```
26 |
27 | To scale all the slides in your presentation, you can set the slide canvas size:
28 |
29 |
30 |
31 | To adjust the size of some elements on your slides, you can use the `Transform` component:
32 |
33 |
34 |
--------------------------------------------------------------------------------
/docs/guide/layout.md:
--------------------------------------------------------------------------------
1 | # Slide Layout
2 |
3 | Layouts in Slidev are used to define the structure for each slides. They are Vue components that wrap the content of the slides.
4 |
5 | ## Using Layouts {#use}
6 |
7 | To use a layout, you can specify it in the frontmatter of the slide:
8 |
9 | ```md
10 | ---
11 | layout: quote
12 | ---
13 |
14 | A quote from someone
15 | ```
16 |
17 | By default, the layout of the first slide is `cover`, and the rest are `default`.
18 |
19 | The layouts are loaded in the following order, and the last one loaded will override the previous ones:
20 |
21 | 1. default layouts. See [Built-in Layouts](../builtin/layouts).
22 | 2. layouts provided by the theme
23 | 3. layouts provided by the addons
24 | 4. custom layouts in the `layouts` directory
25 |
26 |
29 |
30 | ## Writing Layouts {#write}
31 |
32 |
33 |
--------------------------------------------------------------------------------
/docs/guide/write-layout.md:
--------------------------------------------------------------------------------
1 | # Writing Layouts
2 |
3 | > Please read first.
4 |
5 | To create a custom layout, simply create a new Vue file in the `layouts` directory:
6 |
7 | ```bash
8 | your-slidev/
9 | ├── ...
10 | ├── slides.md
11 | └── layouts/
12 | ├── ...
13 | └── MyLayout.vue
14 | ```
15 |
16 | Layouts are Vue components, so you can use all the features of Vue in them.
17 |
18 | In the layout component, use ` ` (the default slot) for the slide content:
19 |
20 | ```vue [default.vue]
21 |
22 |
23 |
24 |
25 |
26 | ```
27 |
28 | You can also have [named slots](https://vuejs.org/guide/components/slots.html) for more complex layouts:
29 |
30 | ```vue [split.vue]
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | ```
42 |
43 | And then use it with .
44 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 | markdownStyles: false
4 | ---
5 |
6 |
7 |
--------------------------------------------------------------------------------
/docs/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = ".vitepress/dist"
3 | command = "pnpm run build"
4 |
5 | [build.environment]
6 | NODE_VERSION = "20"
7 | PLAYWRIGHT_BROWSERS_PATH = "0"
8 |
9 | [[redirects]]
10 | from = "/new"
11 | to = "https://stackblitz.com/github/slidevjs/new?file=slides.md"
12 | status = 302
13 | force = true
14 |
15 | [[redirects]]
16 | from = "https://slidev.antfu.me/*"
17 | to = "https://sli.dev/:splat"
18 | status = 301
19 | force = true
20 |
21 | [[redirects]]
22 | from = "/demo/composable-vue/*"
23 | to = "https://demo.sli.dev/composable-vue"
24 | status = 301
25 | force = true
26 |
27 | [[redirects]]
28 | from = "/demo/starter/*"
29 | to = "https://demo.sli.dev/starter"
30 | status = 301
31 | force = true
32 |
33 | [[redirects]]
34 | from = "/*"
35 | to = "/index.html"
36 | status = 200
37 |
--------------------------------------------------------------------------------
/docs/public/assets/code-groups-demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/assets/code-groups-demo.png
--------------------------------------------------------------------------------
/docs/public/demo-cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/demo-cover.png
--------------------------------------------------------------------------------
/docs/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/favicon.png
--------------------------------------------------------------------------------
/docs/public/logo-circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/logo-circle.png
--------------------------------------------------------------------------------
/docs/public/logo-for-vscode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/logo-for-vscode.png
--------------------------------------------------------------------------------
/docs/public/logo-square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/logo-square.png
--------------------------------------------------------------------------------
/docs/public/logo-title.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/logo-title.png
--------------------------------------------------------------------------------
/docs/public/logo-triangle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/logo-triangle.png
--------------------------------------------------------------------------------
/docs/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/logo.png
--------------------------------------------------------------------------------
/docs/public/og-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/og-image.png
--------------------------------------------------------------------------------
/docs/public/screenshots/cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/screenshots/cover.png
--------------------------------------------------------------------------------
/docs/public/screenshots/covers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/screenshots/covers.png
--------------------------------------------------------------------------------
/docs/public/screenshots/integrated-editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/screenshots/integrated-editor.png
--------------------------------------------------------------------------------
/docs/public/screenshots/navbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/screenshots/navbar.png
--------------------------------------------------------------------------------
/docs/public/screenshots/presenter-mode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/screenshots/presenter-mode.png
--------------------------------------------------------------------------------
/docs/public/screenshots/recording.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/screenshots/recording.png
--------------------------------------------------------------------------------
/docs/public/screenshots/slides-overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/screenshots/slides-overview.png
--------------------------------------------------------------------------------
/docs/public/showcases/composable-vue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/showcases/composable-vue.png
--------------------------------------------------------------------------------
/docs/public/theme-placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/docs/public/theme-placeholder.png
--------------------------------------------------------------------------------
/docs/resources/addon-gallery.md:
--------------------------------------------------------------------------------
1 | ---
2 | aside: false
3 | ---
4 |
5 |
8 |
9 | # Addon Gallery
10 |
11 | Browse awesome addons available for Slidev here.
12 |
13 | Read more about to use them, and to create your own addon.
14 |
15 | ## Official Addons
16 |
17 |
18 |
19 |
20 |
21 | ## Community Addons
22 |
23 | Here are the curated addons made by the community.
24 |
25 |
26 |
27 |
28 |
29 |
30 | ## More Addons
31 |
32 | Find all the [addons available on NPM](https://www.npmjs.com/search?q=keywords%3Aslidev-addon).
33 |
--------------------------------------------------------------------------------
/docs/resources/covers.md:
--------------------------------------------------------------------------------
1 | # Curated Covers
2 |
3 | We curated a few cover images to demonstrate our starter template.
4 |
5 | 
6 |
7 | ```yaml
8 | ---
9 | # random image from the curated collection
10 | background: https://cover.sli.dev
11 | ---
12 | ```
13 |
14 | If you enjoy any of them, check out our [Unsplash collection](https://unsplash.com/collections/94734566/slidev) and find out their authors.
15 |
16 | [cover.sli.dev](https://cover.sli.dev) is hosted from [`slidevjs/slidev-covers`](https://github.com/slidevjs/slidev-covers).
17 |
--------------------------------------------------------------------------------
/docs/resources/learning.md:
--------------------------------------------------------------------------------
1 | # Learning Resources
2 |
3 | ## English
4 |
5 | ### Videos
6 |
7 | - [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)
8 |
9 | ### Articles
10 |
11 | - [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
12 |
13 | ## 中文
14 |
15 | - [Slidev:一个用Markdown写slides的神器](https://zhuanlan.zhihu.com/p/372729473) by [梦里风林](https://www.zhihu.com/people/meng-li-feng-lin)
16 | - [神器!这款开源项目可以让你使用 Markdown 来做 PPT!](https://zhuanlan.zhihu.com/p/377567327) by [Github掘金计划](https://www.zhihu.com/people/github-stars)
17 |
18 | ## 日本語
19 |
20 | - [開発者のためのスライド作成ツール Slidev がすごい](https://zenn.dev/ryo_kawamata/articles/introduce-slidev) by [ryo_kawamata](https://zenn.dev/ryo_kawamata)
21 | - [Markdownでオシャレなスライドを作るSli.dev](https://qiita.com/e99h2121/items/a115f8865a0dc21bb462) by [Nobuko YAMADA](https://qiita.com/e99h2121)
22 | - [【Slidev 超入門】エンジニアだからこそ作れるつよつよスライドの作り方!](https://zenn.dev/takumaru/articles/3faa75c2f09493) by [takuma-ru](https://zenn.dev/takumaru)
23 |
--------------------------------------------------------------------------------
/docs/resources/showcases.md:
--------------------------------------------------------------------------------
1 | ---
2 | aside: false
3 | ---
4 |
5 | # Showcases
6 |
7 | Talks / Presentations using Slidev.
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/resources/theme-gallery.md:
--------------------------------------------------------------------------------
1 | ---
2 | aside: false
3 | ---
4 |
5 |
8 |
9 | # Theme Gallery
10 |
11 | Browse awesome themes available for Slidev here.
12 |
13 | Read more about to use them, and to create your own theme.
14 |
15 | ## Official Themes {#official-themes}
16 |
17 |
18 |
19 |
20 |
21 | ## Community Themes {#community-themes}
22 |
23 | Here are the curated themes made by the community.
24 |
25 |
26 |
27 |
28 |
29 |
30 | ## More Themes {#more-themes}
31 |
32 | Find all the [themes available on NPM](https://www.npmjs.com/search?q=keywords%3Aslidev-theme).
33 |
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "jsx": "preserve",
5 | "lib": ["DOM", "ESNext"],
6 | "baseUrl": ".",
7 | "module": "ESNext",
8 | "moduleResolution": "bundler",
9 | "resolveJsonModule": true,
10 | "types": [
11 | "vite/client",
12 | "node"
13 | ],
14 | "strict": true,
15 | "strictNullChecks": true,
16 | "noUnusedLocals": true,
17 | "esModuleInterop": true,
18 | "forceConsistentCasingInFileNames": true,
19 | "skipLibCheck": true
20 | },
21 | "include": [
22 | "./*.ts",
23 | "./.vitepress/**/*.ts",
24 | "./.vitepress/**/*.vue"
25 | ],
26 | "exclude": ["**/dist/**", "node_modules"]
27 | }
28 |
--------------------------------------------------------------------------------
/docs/uno.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, presetAttributify, presetIcons, presetWebFonts, presetWind3, transformerDirectives } from 'unocss'
2 |
3 | export default defineConfig({
4 | presets: [
5 | presetWind3(),
6 | presetAttributify(),
7 | presetWebFonts({
8 | fonts: {
9 | mono: ['IBM Plex Mono', 'monospace'],
10 | },
11 | }),
12 | presetIcons(),
13 | ],
14 | transformers: [
15 | transformerDirectives(),
16 | ],
17 | shortcuts: {
18 | 'bg-main': 'bg-white dark:bg-[#111]',
19 | },
20 | theme: {
21 | colors: {
22 | primary: {
23 | DEFAULT: '#3AB9D4',
24 | deep: '#2082A6',
25 | },
26 | },
27 | },
28 | })
29 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import antfu from '@antfu/eslint-config'
2 |
3 | export default antfu({
4 | pnpm: true,
5 | formatters: {
6 | markdown: true,
7 | css: true,
8 | slidev: {
9 | files: [
10 | '**/slides.md',
11 | '**/template.md',
12 | '**/example.md',
13 | 'test/fixtures/markdown/**/*.md',
14 | 'packages/vscode/syntaxes/slidev.example.md',
15 | ],
16 | },
17 | },
18 | })
19 | .removeRules(
20 | 'vue/no-v-text-v-html-on-component',
21 | 'vue/component-name-in-template-casing',
22 | 'jsonc/sort-array-values',
23 | )
24 | .override('antfu/pnpm/package-json', {
25 | ignores: [
26 | 'packages/create-theme/template/package.json',
27 | 'packages/create-app/template/package.json',
28 | ],
29 | })
30 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = "docs/.vitepress/dist"
3 | command = "pnpm run docs:build"
4 |
5 | [build.environment]
6 | NODE_VERSION = "22"
7 | NODE_OPTIONS = "--max-old-space-size=8192"
8 | PLAYWRIGHT_BROWSERS_PATH = "0"
9 |
10 | [[redirects]]
11 | from = "/new"
12 | to = "https://stackblitz.com/github/slidevjs/new?file=slides.md"
13 | status = 302
14 | force = true
15 |
16 | [[redirects]]
17 | from = "/demo/composable-vue/*"
18 | to = "/demo/composable-vue/index.html"
19 | status = 200
20 |
21 | [[redirects]]
22 | from = "/demo/starter/*"
23 | to = "/demo/starter/index.html"
24 | status = 200
25 |
26 | [[redirects]]
27 | from = "/demo/vue-runner/*"
28 | to = "/demo/vue-runner/index.html"
29 | status = 200
30 |
31 | [[redirects]]
32 | from = "https://slidev.antfu.me/*"
33 | to = "https://sli.dev/:splat"
34 | status = 301
35 | force = true
36 |
37 | [[redirects]]
38 | from = "/*"
39 | to = "/index.html"
40 | status = 200
41 |
--------------------------------------------------------------------------------
/packages/client/App.vue:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/packages/client/README.md:
--------------------------------------------------------------------------------
1 | # @slidev/client
2 |
3 | [](https://www.npmjs.com/package/@slidev/client)
4 |
5 | Client code for [Slidev](https://sli.dev). Shipped with [`@slidev/cli`](https://www.npmjs.com/package/@slidev/cli).
6 |
7 | ## License
8 |
9 | MIT License © 2021 [Anthony Fu](https://github.com/antfu)
10 |
--------------------------------------------------------------------------------
/packages/client/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/packages/client/assets/favicon.png
--------------------------------------------------------------------------------
/packages/client/assets/logo-title-horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/packages/client/assets/logo-title-horizontal.png
--------------------------------------------------------------------------------
/packages/client/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/packages/client/assets/logo.png
--------------------------------------------------------------------------------
/packages/client/builtin/LightOrDark.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/packages/client/builtin/Link.vue:
--------------------------------------------------------------------------------
1 |
10 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/packages/client/builtin/PlantUml.vue:
--------------------------------------------------------------------------------
1 |
13 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/packages/client/builtin/PoweredBySlidev.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Powered by
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/packages/client/builtin/SlideCurrentNo.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | {{ $page }}
9 |
10 |
--------------------------------------------------------------------------------
/packages/client/builtin/SlidesTotal.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | {{ $nav.total }}
9 |
10 |
--------------------------------------------------------------------------------
/packages/client/builtin/Transform.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/packages/client/builtin/VAfter.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * click animations component
3 | *
4 | * Learn more: https://sli.dev/guide/animations.html#click-animation
5 | */
6 |
7 | import type { Directive, VNode } from 'vue'
8 | import { toArray } from '@antfu/utils'
9 | import { defineComponent, h, resolveDirective, withDirectives } from 'vue'
10 |
11 | export default defineComponent({
12 | render() {
13 | const after = resolveDirective('after')!
14 |
15 | function applyDirective(node: VNode, directive: Directive) {
16 | return withDirectives(node, [[directive]])
17 | }
18 |
19 | let defaults = this.$slots.default?.()
20 |
21 | if (!defaults)
22 | return
23 |
24 | defaults = toArray(defaults)
25 |
26 | return defaults.map(i => applyDirective(h(i), after))
27 | },
28 | })
29 |
--------------------------------------------------------------------------------
/packages/client/builtin/VClick.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * click animations component
3 | *
4 | * Learn more: https://sli.dev/guide/animations.html#click-animation
5 | */
6 |
7 | import type { PropType, VNode } from 'vue'
8 | import { defineComponent, h, Text } from 'vue'
9 | import { CLICKS_MAX } from '../constants'
10 | import VClicks from './VClicks'
11 |
12 | export default defineComponent({
13 | props: {
14 | at: {
15 | type: [Number, String],
16 | default: '+1',
17 | },
18 | hide: {
19 | type: Boolean,
20 | default: false,
21 | },
22 | fade: {
23 | type: Boolean,
24 | default: false,
25 | },
26 | wrapText: {
27 | type: Function as PropType<(text: VNode) => VNode>,
28 | default: (text: VNode) => h('span', text),
29 | },
30 | },
31 | render() {
32 | return h(
33 | VClicks,
34 | {
35 | every: CLICKS_MAX,
36 | at: this.at,
37 | hide: this.hide,
38 | fade: this.fade,
39 | handleSpecialElements: false,
40 | },
41 | {
42 | default: () =>
43 | this.$slots.default?.().map(v =>
44 | v.type === Text
45 | ? this.wrapText(v)
46 | : v,
47 | ),
48 | },
49 | )
50 | },
51 | })
52 |
--------------------------------------------------------------------------------
/packages/client/builtin/VClickGap.vue:
--------------------------------------------------------------------------------
1 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/client/builtin/VDrag.vue:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/packages/client/builtin/VDragArrow.vue:
--------------------------------------------------------------------------------
1 |
25 |
26 |
27 |
36 |
37 |
--------------------------------------------------------------------------------
/packages/client/builtin/Youtube.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
16 |
17 |
18 |
28 |
29 |
--------------------------------------------------------------------------------
/packages/client/composables/useDarkMode.ts:
--------------------------------------------------------------------------------
1 | import { isColorSchemaConfigured, isDark, toggleDark } from '../logic/dark'
2 |
3 | export function useDarkMode() {
4 | return {
5 | isColorSchemaConfigured,
6 | isDark,
7 | toggleDark,
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/packages/client/composables/usePrintStyles.ts:
--------------------------------------------------------------------------------
1 | import { useStyleTag } from '@vueuse/core'
2 | import { computed } from 'vue'
3 | import { slideHeight, slideWidth } from '../env'
4 | import { useNav } from './useNav'
5 |
6 | export function usePrintStyles() {
7 | const { isPrintMode } = useNav()
8 |
9 | useStyleTag(computed(() => isPrintMode.value
10 | ? `
11 | @page {
12 | size: ${slideWidth.value}px ${slideHeight.value}px;
13 | margin: 0px;
14 | }
15 |
16 | * {
17 | transition: none !important;
18 | transition-duration: 0s !important;
19 | }`
20 | : ''))
21 | }
22 |
23 | // Monaco uses `
12 |
--------------------------------------------------------------------------------
/packages/client/layouts/error.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{
4 | __SLIDEV_HAS_SERVER__
5 | ? 'An error occurred on this slide. Check the terminal for more information.'
6 | : 'Failed to fetch this slide. Please check your network connection.'
7 | }}
8 |
9 |
10 |
--------------------------------------------------------------------------------
/packages/client/layouts/fact.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/packages/client/layouts/full.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/packages/client/layouts/iframe-left.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/packages/client/layouts/iframe-right.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/packages/client/layouts/iframe.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
22 |
23 |
--------------------------------------------------------------------------------
/packages/client/layouts/image-left.vue:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
28 |
29 |
--------------------------------------------------------------------------------
/packages/client/layouts/image-right.vue:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
28 |
29 |
--------------------------------------------------------------------------------
/packages/client/layouts/image.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/packages/client/layouts/intro.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/packages/client/layouts/none.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/packages/client/layouts/quote.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/packages/client/layouts/section.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/packages/client/layouts/statement.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/packages/client/layouts/two-cols.vue:
--------------------------------------------------------------------------------
1 |
21 |
22 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/packages/client/logic/contextMenu.ts:
--------------------------------------------------------------------------------
1 | import type { ContextMenuItem } from '@slidev/types'
2 | import type { ComputedRef } from 'vue'
3 | import { shallowRef } from 'vue'
4 | import { useNav } from '../composables/useNav'
5 | import { configs, mode } from '../env'
6 | import setupContextMenu from '../setup/context-menu'
7 |
8 | export const currentContextMenu = shallowRef
12 | }>(null)
13 |
14 | export function openContextMenu(x: number, y: number) {
15 | currentContextMenu.value = {
16 | x,
17 | y,
18 | items: setupContextMenu(),
19 | }
20 | }
21 |
22 | export function closeContextMenu() {
23 | currentContextMenu.value = null
24 | }
25 |
26 | export function onContextMenu(ev: MouseEvent) {
27 | if (configs.contextMenu !== true && configs.contextMenu != null && configs.contextMenu !== mode)
28 | return
29 | if (ev.shiftKey || ev.defaultPrevented)
30 | return
31 |
32 | const { isEmbedded } = useNav()
33 | if (isEmbedded.value)
34 | return
35 |
36 | openContextMenu(ev.pageX, ev.pageY)
37 | ev.preventDefault()
38 | ev.stopPropagation()
39 | }
40 |
--------------------------------------------------------------------------------
/packages/client/logic/overview.ts:
--------------------------------------------------------------------------------
1 | import { computed, ref } from 'vue'
2 | import { slides } from './slides'
3 |
4 | // To have same format(.value) as max, wrap it with ref.
5 | const min = ref(1)
6 | const max = computed(() => slides.value.length)
7 |
8 | export const currentOverviewPage = ref(0)
9 | export const overviewRowCount = ref(0)
10 |
11 | export function prevOverviewPage() {
12 | if (currentOverviewPage.value > min.value)
13 | currentOverviewPage.value -= 1
14 | }
15 |
16 | export function nextOverviewPage() {
17 | if (currentOverviewPage.value < max.value)
18 | currentOverviewPage.value += 1
19 | }
20 |
21 | export function upOverviewPage() {
22 | if (currentOverviewPage.value > min.value) {
23 | let current = currentOverviewPage.value - overviewRowCount.value
24 | if (current < min.value)
25 | current = min.value
26 |
27 | currentOverviewPage.value = current
28 | }
29 | }
30 |
31 | export function downOverviewPage() {
32 | if (currentOverviewPage.value < max.value) {
33 | let current = currentOverviewPage.value + overviewRowCount.value
34 | if (current > max.value)
35 | current = max.value
36 |
37 | currentOverviewPage.value = current
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/client/logic/route.ts:
--------------------------------------------------------------------------------
1 | import type { WritableComputedRef } from 'vue'
2 | import { computed, nextTick, unref } from 'vue'
3 | import { useRouter } from 'vue-router'
4 |
5 | export function useRouteQuery(
6 | name: string,
7 | defaultValue?: T,
8 | {
9 | mode = 'replace',
10 | } = {},
11 | ): WritableComputedRef {
12 | const router = useRouter()
13 |
14 | return computed({
15 | get() {
16 | const data = router.currentRoute.value.query[name]
17 | if (data == null)
18 | return defaultValue ?? null
19 | if (Array.isArray(data))
20 | return data.filter(Boolean)
21 | return data
22 | },
23 | set(v) {
24 | nextTick(() => {
25 | const oldValue = router.currentRoute.value.query[name]
26 | if ((oldValue ?? defaultValue?.toString()) === v.toString())
27 | return
28 | router[unref(mode) as 'replace' | 'push']({
29 | query: {
30 | ...router.currentRoute.value.query,
31 | [name]: `${v}` === defaultValue ? undefined : v,
32 | },
33 | })
34 | })
35 | },
36 | })
37 | }
38 |
--------------------------------------------------------------------------------
/packages/client/main.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import { createApp } from 'vue'
4 | import App from './App.vue'
5 | import setupMain from './setup/main'
6 |
7 | async function main() {
8 | const app = createApp(App)
9 | await setupMain(app)
10 | app.mount('#app')
11 | }
12 |
13 | main()
14 |
--------------------------------------------------------------------------------
/packages/client/modules/context.ts:
--------------------------------------------------------------------------------
1 | import type { ComputedRef } from '@vue/reactivity'
2 | import type { SlidevContextNav } from '../composables/useNav'
3 | import type { configs } from '../env'
4 |
5 | export interface SlidevContext {
6 | nav: SlidevContextNav
7 | configs: typeof configs
8 | themeConfigs: ComputedRef
9 | }
10 |
--------------------------------------------------------------------------------
/packages/client/modules/mermaid.ts:
--------------------------------------------------------------------------------
1 | import { clearUndefined } from '@antfu/utils'
2 | import lz from 'lz-string'
3 | import mermaid from 'mermaid/dist/mermaid.esm.mjs'
4 | import { makeId } from '../logic/utils'
5 | import setupMermaid from '../setup/mermaid'
6 |
7 | mermaid.startOnLoad = false
8 | mermaid.initialize({ startOnLoad: false })
9 |
10 | const cache = new Map()
11 | let containerElement: Element | undefined
12 |
13 | export async function renderMermaid(lzEncoded: string, options: any) {
14 | containerElement ??= document.getElementById('mermaid-rendering-container')!
15 | const key = lzEncoded + JSON.stringify(options)
16 | const _cache = cache.get(key)
17 | if (_cache)
18 | return _cache
19 |
20 | mermaid.initialize({
21 | startOnLoad: false,
22 | ...clearUndefined(await setupMermaid() || {}),
23 | ...clearUndefined(options),
24 | })
25 | const code = lz.decompressFromBase64(lzEncoded)
26 | const id = makeId()
27 | const { svg } = await mermaid.render(id, code, containerElement)
28 | cache.set(key, svg)
29 | return svg
30 | }
31 |
--------------------------------------------------------------------------------
/packages/client/pages/entry.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Slides
5 |
6 |
7 |
Presenter
8 |
9 |
10 |
Notes
11 |
12 |
13 |
Overview
14 |
15 |
16 |
17 |
18 |
27 |
--------------------------------------------------------------------------------
/packages/client/setup/mermaid.ts:
--------------------------------------------------------------------------------
1 | import type { MermaidConfig } from 'mermaid'
2 | import setups from '#slidev/setups/mermaid'
3 | import { createSingletonPromise } from '@antfu/utils'
4 |
5 | export default createSingletonPromise(async () => {
6 | const setupReturn: MermaidConfig = {
7 | theme: 'default',
8 | }
9 |
10 | for (const setup of setups)
11 | Object.assign(setupReturn, await setup())
12 |
13 | return setupReturn
14 | })
15 |
--------------------------------------------------------------------------------
/packages/client/shim-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'vue' {
2 | type SlideContext = import('./context').SlideContext
3 | interface ComponentCustomProperties extends SlideContext {
4 | }
5 | }
6 |
7 | declare module 'vue-router' {
8 | import type { TransitionGroupProps } from 'vue'
9 |
10 | interface RouteMeta {
11 | // inherited from frontmatter
12 | layout?: string
13 | name?: string
14 | class?: string
15 | clicks?: number
16 | transition?: string | TransitionGroupProps | undefined
17 | preload?: boolean
18 |
19 | // slide info
20 | slide?: Omit & {
21 | noteHTML: string
22 | filepath: string
23 | start: number
24 | id: number
25 | no: number
26 | }
27 |
28 | // private fields
29 | __clicksContext: import('@slidev/types').ClicksContext | null
30 | __preloaded?: boolean
31 | }
32 | }
33 |
34 | export {}
35 |
--------------------------------------------------------------------------------
/packages/client/shim.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.md' {
2 | // with unplugin-vue-markdown, markdowns can be treat as Vue components
3 | import type { ComponentOptions } from 'vue'
4 |
5 | const component: ComponentOptions
6 | export default component
7 | }
8 |
9 | declare module 'mermaid/dist/mermaid.esm.mjs' {
10 | import Mermaid from 'mermaid/dist/mermaid.d.ts'
11 |
12 | export default Mermaid
13 | }
14 |
--------------------------------------------------------------------------------
/packages/client/state/drawings.ts:
--------------------------------------------------------------------------------
1 | // @ts-expect-error - virtual module
2 | import serverDrawingState from 'server-reactive:drawings?diff'
3 | import { createSyncState } from './syncState'
4 |
5 | export type DrawingsState = Record
6 |
7 | export const {
8 | init: initDrawingState,
9 | onPatch: onPatchDrawingState,
10 | onUpdate: onDrawingUpdate,
11 | patch: patchDrawingState,
12 | state: drawingState,
13 | } = createSyncState(
14 | serverDrawingState,
15 | serverDrawingState,
16 | __SLIDEV_FEATURE_DRAWINGS_PERSIST__,
17 | )
18 |
--------------------------------------------------------------------------------
/packages/client/state/index.ts:
--------------------------------------------------------------------------------
1 | export * from './storage'
2 |
--------------------------------------------------------------------------------
/packages/client/state/shared.ts:
--------------------------------------------------------------------------------
1 | // @ts-expect-error - virtual module
2 | import serverState from 'server-reactive:nav'
3 | import { createSyncState } from './syncState'
4 |
5 | export interface SharedState {
6 | page: number
7 | clicks: number
8 | clicksTotal: number
9 |
10 | cursor?: {
11 | x: number
12 | y: number
13 | }
14 |
15 | lastUpdate?: {
16 | id: string
17 | type: 'presenter' | 'viewer'
18 | time: number
19 | }
20 | }
21 |
22 | const { init, onPatch, onUpdate, patch, state } = createSyncState(serverState, {
23 | page: 1,
24 | clicks: 0,
25 | clicksTotal: 0,
26 | })
27 |
28 | export {
29 | init as initSharedState,
30 | onPatch,
31 | onUpdate as onSharedUpdate,
32 | patch,
33 | state as sharedState,
34 | }
35 |
--------------------------------------------------------------------------------
/packages/client/state/snapshot.ts:
--------------------------------------------------------------------------------
1 | // @ts-expect-error - virtual module
2 | import serverSnapshotState from 'server-reactive:snapshots?diff'
3 | import { createSyncState } from './syncState'
4 |
5 | export type SnapshotState = Record
9 |
10 | export const snapshotState = createSyncState(
11 | serverSnapshotState,
12 | serverSnapshotState,
13 | true,
14 | )
15 |
--------------------------------------------------------------------------------
/packages/client/styles/katex.css:
--------------------------------------------------------------------------------
1 | .slidev-katex-wrapper .mord.highlighted {
2 | }
3 | .slidev-katex-wrapper .mord.dishonored {
4 | opacity: 0.3;
5 | }
6 |
--------------------------------------------------------------------------------
/packages/client/styles/shiki-twoslash.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --twoslash-popup-bg: var(--slidev-code-background);
3 | --twoslash-popup-color: var(--slidev-code-foreground);
4 | --twoslash-docs-color: inherit;
5 | --twoslash-docs-font: inherit;
6 | --twoslash-code-font: theme('fontFamily.mono');
7 | --twoslash-underline-color: #8888;
8 | --twoslash-border-color: #8888;
9 | --twoslash-cursor-color: var(--slidev-theme-primary);
10 | --twoslash-matched-color: var(--slidev-theme-primary);
11 | }
12 |
13 | .twoslash-popup-container {
14 | font-size: 13px;
15 | }
16 |
17 | .twoslash-popup-container .twoslash-popup-code {
18 | font-size: 0.85em;
19 | }
20 |
21 | .twoslash-floating .twoslash-popup-docs-tags .twoslash-popup-docs-tag-name {
22 | color: inherit;
23 | opacity: 0.5;
24 | }
25 |
--------------------------------------------------------------------------------
/packages/client/styles/vars.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --slidev-code-background: #f5f5f5;
3 | --slidev-code-foreground: #1b1b1b;
4 | --slidev-code-font-family: theme('fontFamily.mono');
5 | --slidev-code-padding: 8px;
6 | --slidev-code-font-size: 12px;
7 | --slidev-code-line-height: 18px;
8 | --slidev-code-radius: 4px;
9 | --slidev-code-margin: 4px 0;
10 | --slidev-theme-primary: #3ab9d5;
11 |
12 | --slidev-transition-duration: 0.5s;
13 | --slidev-slide-container-background: black;
14 | --slidev-controls-foreground: white;
15 |
16 | --slidev-code-tab-divider: #e5e5e5;
17 | --slidev-code-tab-text-color: #67676c;
18 | --slidev-code-tab-font-size: 12px;
19 | --slidev-code-tab-active-text-color: #3c3c43;
20 | }
21 |
22 | html.dark {
23 | --slidev-code-background: #1b1b1b;
24 | --slidev-code-foreground: #eee;
25 | --slidev-code-tab-divider: #222222;
26 | --slidev-code-tab-text-color: #98989f;
27 | --slidev-code-tab-active-text-color: #dfdfd6;
28 | }
29 |
--------------------------------------------------------------------------------
/packages/create-app/README.md:
--------------------------------------------------------------------------------
1 | # create-slidev
2 |
3 | [](https://www.npmjs.com/package/create-slidev)
4 |
5 | Starter template generater for [Slidev](https://sli.dev).
6 |
7 | ## Usage
8 |
9 | ```bash
10 | npm init slidev
11 | ```
12 |
13 | or
14 |
15 | ```bash
16 | yarn create slidev
17 | ```
18 |
19 | ## License
20 |
21 | MIT License © 2021 [Anthony Fu](https://github.com/antfu)
22 |
--------------------------------------------------------------------------------
/packages/create-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "create-slidev",
3 | "type": "module",
4 | "version": "51.8.1",
5 | "description": "Create starter template for Slidev",
6 | "author": "Anthony Fu ",
7 | "license": "MIT",
8 | "funding": "https://github.com/sponsors/antfu",
9 | "homepage": "https://sli.dev",
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/slidevjs/slidev"
13 | },
14 | "bugs": "https://github.com/slidevjs/slidev/issues",
15 | "main": "index.mjs",
16 | "bin": {
17 | "create-slidev": "index.mjs"
18 | },
19 | "files": [
20 | "index.mjs",
21 | "template"
22 | ],
23 | "engines": {
24 | "node": ">=18.0.0"
25 | },
26 | "scripts": {
27 | "build": "node build.mjs",
28 | "prepublishOnly": "npm run build"
29 | },
30 | "dependencies": {
31 | "ansis": "catalog:prod",
32 | "minimist": "catalog:prod",
33 | "prompts": "catalog:prod",
34 | "tinyexec": "catalog:prod"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/packages/create-app/template/README.md:
--------------------------------------------------------------------------------
1 | # Welcome to [Slidev](https://github.com/slidevjs/slidev)!
2 |
3 | To start the slide show:
4 |
5 | - `pnpm install`
6 | - `pnpm dev`
7 | - visit
8 |
9 | Edit the [slides.md](./slides.md) to see the changes.
10 |
11 | Learn more about Slidev at the [documentation](https://sli.dev/).
12 |
--------------------------------------------------------------------------------
/packages/create-app/template/_gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | dist
4 | *.local
5 | .vite-inspect
6 | .remote-assets
7 | components.d.ts
8 |
--------------------------------------------------------------------------------
/packages/create-app/template/_npmrc:
--------------------------------------------------------------------------------
1 | # for pnpm
2 | shamefully-hoist=true
3 | auto-install-peers=true
4 |
--------------------------------------------------------------------------------
/packages/create-app/template/components/Counter.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
23 | -
24 |
25 | {{ counter }}
26 |
34 | +
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/packages/create-app/template/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = "dist"
3 | command = "npm run build"
4 |
5 | [build.environment]
6 | NODE_VERSION = "20"
7 |
8 | [[redirects]]
9 | from = "/.well-known/*"
10 | to = "/.well-known/:splat"
11 | status = 200
12 |
13 | [[redirects]]
14 | from = "/*"
15 | to = "/index.html"
16 | status = 200
17 |
--------------------------------------------------------------------------------
/packages/create-app/template/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "untitled",
3 | "type": "module",
4 | "private": true,
5 | "scripts": {
6 | "build": "slidev build",
7 | "dev": "slidev --open",
8 | "export": "slidev export"
9 | },
10 | "dependencies": {
11 | "@slidev/cli": "^51.8.1",
12 | "@slidev/theme-default": "latest",
13 | "@slidev/theme-seriph": "latest",
14 | "vue": "^3.5.16"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/create-app/template/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "rewrites": [
3 | { "source": "/(.*)", "destination": "/index.html" }
4 | ],
5 | "buildCommand": "npm run build",
6 | "outputDirectory": "dist"
7 | }
8 |
--------------------------------------------------------------------------------
/packages/create-theme/README.md:
--------------------------------------------------------------------------------
1 | # create-slidev-theme
2 |
3 | [](https://www.npmjs.com/package/create-slidev-theme)
4 |
5 | [Slidev](https://sli.dev) theme template generater.
6 |
7 | ## Usage
8 |
9 | ```bash
10 | npm init slidev-theme
11 | ```
12 |
13 | or
14 |
15 | ```bash
16 | yarn create slidev-theme
17 | ```
18 |
19 | ## License
20 |
21 | MIT License © 2021 [Anthony Fu](https://github.com/antfu)
22 |
--------------------------------------------------------------------------------
/packages/create-theme/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "create-slidev-theme",
3 | "type": "module",
4 | "version": "51.8.1",
5 | "description": "Create starter theme template for Slidev",
6 | "author": "Anthony Fu ",
7 | "license": "MIT",
8 | "funding": "https://github.com/sponsors/antfu",
9 | "homepage": "https://sli.dev",
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/slidevjs/slidev"
13 | },
14 | "bugs": "https://github.com/slidevjs/slidev/issues",
15 | "main": "index.mjs",
16 | "bin": {
17 | "create-slidev-theme": "index.mjs"
18 | },
19 | "engines": {
20 | "node": ">=18.0.0"
21 | },
22 | "dependencies": {
23 | "ansis": "catalog:prod",
24 | "minimist": "catalog:prod",
25 | "prompts": "catalog:prod"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/packages/create-theme/template/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["antfu.slidev"]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/create-theme/template/_gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | dist
4 | *.local
5 | .vite-inspect
6 | .remote-assets
7 | .idea/
8 | components.d.ts
9 |
--------------------------------------------------------------------------------
/packages/create-theme/template/_npmrc:
--------------------------------------------------------------------------------
1 | # for pnpm
2 | shamefully-hoist=true
3 |
--------------------------------------------------------------------------------
/packages/create-theme/template/components/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slidevjs/slidev/4645273d037f1265f9c1af525626ebe9b3ad5610/packages/create-theme/template/components/.gitkeep
--------------------------------------------------------------------------------
/packages/create-theme/template/layouts/cover.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/packages/create-theme/template/layouts/intro.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/packages/create-theme/template/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "module",
3 | "keywords": [
4 | "slidev-theme",
5 | "slidev"
6 | ],
7 | "engines": {
8 | "node": ">=18.0.0"
9 | },
10 | "scripts": {
11 | "build": "slidev build example.md",
12 | "dev": "slidev example.md --open",
13 | "export": "slidev export example.md",
14 | "screenshot": "slidev export example.md --format png"
15 | },
16 | "dependencies": {
17 | "@slidev/types": "^51.8.1"
18 | },
19 | "devDependencies": {
20 | "@slidev/cli": "^51.8.1"
21 | },
22 | "//": "Learn more: https://sli.dev/guide/write-theme.html",
23 | "slidev": {
24 | "colorSchema": "both",
25 | "defaults": {
26 | "fonts": {
27 | "sans": "Nunito Sans",
28 | "mono": "Fira Code"
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/packages/create-theme/template/setup/shiki.ts:
--------------------------------------------------------------------------------
1 | import type { ShikiSetupReturn } from '@slidev/types'
2 | import { defineShikiSetup } from '@slidev/types'
3 |
4 | export default defineShikiSetup((): ShikiSetupReturn => {
5 | return {
6 | themes: {
7 | dark: 'vitesse-dark',
8 | light: 'vitesse-light',
9 | },
10 | }
11 | })
12 |
--------------------------------------------------------------------------------
/packages/create-theme/template/styles/index.ts:
--------------------------------------------------------------------------------
1 | // inherit from base layouts, remove it to get full customizations
2 | import '@slidev/client/styles/layouts-base.css'
3 | import './layout.css'
4 |
--------------------------------------------------------------------------------
/packages/create-theme/template/styles/layout.css:
--------------------------------------------------------------------------------
1 | :root {
2 | /* default theme color */
3 | /* can be overrided by uses `themeConfig` option */
4 | --slidev-theme-primary: #5d8392;
5 | }
6 |
7 | .slidev-layout.cover,
8 | .slidev-layout.intro {
9 | @apply h-full grid;
10 |
11 | h1 {
12 | @apply text-6xl leading-20;
13 | }
14 |
15 | h1 + p {
16 | @apply -mt-2 opacity-50 mb-4;
17 | }
18 |
19 | p + h2,
20 | ul + h2,
21 | table + h2 {
22 | @apply mt-10;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/parser/README.md:
--------------------------------------------------------------------------------
1 | # @slidev/parser
2 |
3 | [](https://www.npmjs.com/package/@slidev/parser)
4 |
5 | Slides markdown parser for [Slidev](https://sli.dev).
6 |
7 | Learn more about the [Syntax](https://sli.dev/guide/syntax.html)
8 |
9 | Refer to the TypeScript definitions for API.
10 |
11 | ## License
12 |
13 | MIT License © 2021 [Anthony Fu](https://github.com/antfu)
14 |
--------------------------------------------------------------------------------
/packages/parser/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './core'
2 |
--------------------------------------------------------------------------------
/packages/parser/tsdown.config.ts:
--------------------------------------------------------------------------------
1 | export { default } from '../../tsdown.config.ts'
2 |
--------------------------------------------------------------------------------
/packages/slidev/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020-2021 Anthony Fu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/slidev/bin/slidev.mjs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict'
3 | import ('../dist/cli.js')
4 |
--------------------------------------------------------------------------------
/packages/slidev/node/commands/serve.ts:
--------------------------------------------------------------------------------
1 | import type { ResolvedSlidevOptions, SlidevServerOptions } from '@slidev/types'
2 | import type { InlineConfig } from 'vite'
3 | import { join } from 'node:path'
4 | import process from 'node:process'
5 | import { createServer as createViteServer } from 'vite'
6 | import { resolveViteConfigs } from './shared'
7 |
8 | export async function createServer(
9 | options: ResolvedSlidevOptions,
10 | viteConfig: InlineConfig = {},
11 | serverOptions?: SlidevServerOptions,
12 | ) {
13 | // default open editor to code, #312
14 | process.env.EDITOR = process.env.EDITOR || 'code'
15 |
16 | const inlineConfig = await resolveViteConfigs(
17 | options,
18 | {
19 | optimizeDeps: {
20 | entries: [
21 | join(options.clientRoot, 'main.ts'),
22 | ],
23 | },
24 | } satisfies InlineConfig,
25 | viteConfig,
26 | 'serve',
27 | serverOptions,
28 | )
29 |
30 | return await createViteServer(inlineConfig)
31 | }
32 |
--------------------------------------------------------------------------------
/packages/slidev/node/index.ts:
--------------------------------------------------------------------------------
1 | export { createServer } from './commands/serve'
2 | export * from './options'
3 | export { parser } from './parser'
4 | export { ViteSlidevPlugin } from './vite'
5 |
--------------------------------------------------------------------------------
/packages/slidev/node/integrations/snapshots.ts:
--------------------------------------------------------------------------------
1 | import type { ResolvedSlidevOptions } from '@slidev/types'
2 | import { existsSync } from 'node:fs'
3 | import fs from 'node:fs/promises'
4 | import { dirname, join, resolve } from 'node:path'
5 |
6 | function resolveSnapshotsDir(options: ResolvedSlidevOptions): string {
7 | return resolve(dirname(options.entry), '.slidev/snapshots')
8 | }
9 |
10 | export async function loadSnapshots(options: ResolvedSlidevOptions) {
11 | const dir = resolveSnapshotsDir(options)
12 | const file = join(dir, 'snapshots.json')
13 | if (!dir || !existsSync(file))
14 | return {}
15 |
16 | return JSON.parse(await fs.readFile(file, 'utf8'))
17 | }
18 |
19 | export async function writeSnapshots(options: ResolvedSlidevOptions, data: Record) {
20 | const dir = resolveSnapshotsDir(options)
21 | if (!dir)
22 | return
23 |
24 | await fs.mkdir(dir, { recursive: true })
25 | // TODO: write as each image file
26 | await fs.writeFile(join(dir, 'snapshots.json'), JSON.stringify(data, null, 2), 'utf-8')
27 | }
28 |
--------------------------------------------------------------------------------
/packages/slidev/node/integrations/themes.ts:
--------------------------------------------------------------------------------
1 | import type { SlidevThemeMeta } from '@slidev/types'
2 | import { existsSync } from 'node:fs'
3 | import fs from 'node:fs/promises'
4 | import { join } from 'node:path'
5 | import { satisfies } from 'semver'
6 | import { version } from '../../package.json'
7 | import { createResolver } from '../resolver'
8 |
9 | const officialThemes: Record = {
10 | 'none': '',
11 | 'default': '@slidev/theme-default',
12 | 'seriph': '@slidev/theme-seriph',
13 | 'apple-basic': '@slidev/theme-apple-basic',
14 | 'shibainu': '@slidev/theme-shibainu',
15 | 'bricks': '@slidev/theme-bricks',
16 | }
17 |
18 | export const resolveTheme = createResolver('theme', officialThemes)
19 |
20 | export async function getThemeMeta(name: string, root: string) {
21 | const path = join(root, 'package.json')
22 | if (!existsSync(path))
23 | return {}
24 |
25 | const { slidev = {}, engines = {} } = JSON.parse(await fs.readFile(path, 'utf-8'))
26 |
27 | if (engines.slidev && !satisfies(version, engines.slidev, { includePrerelease: true }))
28 | throw new Error(`[slidev] theme "${name}" requires Slidev version range "${engines.slidev}" but found "${version}"`)
29 |
30 | return slidev as SlidevThemeMeta
31 | }
32 |
--------------------------------------------------------------------------------
/packages/slidev/node/parser.ts:
--------------------------------------------------------------------------------
1 | export * as parser from '@slidev/parser/fs'
2 |
--------------------------------------------------------------------------------
/packages/slidev/node/setups/katex.ts:
--------------------------------------------------------------------------------
1 | import type { KatexSetup } from '@slidev/types'
2 | import type { KatexOptions } from 'katex'
3 | import { loadSetups } from './load'
4 |
5 | export default async function setupKatex(roots: string[]): Promise {
6 | const options = await loadSetups(roots, 'katex.ts', [])
7 | return Object.assign(
8 | { strict: false },
9 | ...options,
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/packages/slidev/node/setups/load.ts:
--------------------------------------------------------------------------------
1 | import type { Awaitable } from '@antfu/utils'
2 | import { existsSync } from 'node:fs'
3 | import { resolve } from 'node:path'
4 | import { deepMergeWithArray } from '@antfu/utils'
5 | import { loadModule } from '../utils'
6 |
7 | export async function loadSetups any>(
8 | roots: string[],
9 | filename: string,
10 | args: Parameters,
11 | extraLoader?: (root: string) => Awaitable>[]>,
12 | ) {
13 | const returns: Awaited>[] = []
14 | for (const root of roots) {
15 | const path = resolve(root, 'setup', filename)
16 | if (existsSync(path)) {
17 | const { default: setup } = await loadModule(path) as { default: F }
18 | const ret = await setup(...args)
19 | if (ret)
20 | returns.push(ret)
21 | }
22 | if (extraLoader)
23 | returns.push(...await extraLoader(root))
24 | }
25 | return returns
26 | }
27 |
28 | export function mergeOptions = T>(
29 | base: T,
30 | options: S[],
31 | merger: (base: T, options: S) => T = deepMergeWithArray as any,
32 | ): T {
33 | return options.reduce((acc, cur) => merger(acc, cur), base)
34 | }
35 |
--------------------------------------------------------------------------------
/packages/slidev/node/setups/preparser.ts:
--------------------------------------------------------------------------------
1 | import type { PreparserSetup } from '@slidev/types'
2 | import { uniq } from '@antfu/utils'
3 | import { injectPreparserExtensionLoader } from '@slidev/parser/fs'
4 | import { resolveAddons } from '../integrations/addons'
5 | import { getRoots } from '../resolver'
6 | import { loadSetups } from './load'
7 |
8 | export default function setupPreparser() {
9 | injectPreparserExtensionLoader(async (headmatter: Record, filepath: string, mode?: string) => {
10 | // Ensure addons is an array or an empty array if undefined
11 | const addons = Array.isArray(headmatter?.addons) ? headmatter.addons as string[] : []
12 |
13 | const { userRoot } = await getRoots()
14 | const roots = uniq([
15 | ...await resolveAddons(addons),
16 | userRoot,
17 | ])
18 |
19 | const returns = await loadSetups(roots, 'preparser.ts', [{ filepath, headmatter, mode }])
20 | return returns.flat()
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/packages/slidev/node/setups/transformers.ts:
--------------------------------------------------------------------------------
1 | import type { TransformersSetup, TransformersSetupReturn } from '@slidev/types'
2 | import { loadSetups } from './load'
3 |
4 | export default async function setupTransformers(roots: string[]) {
5 | const returns = await loadSetups(roots, 'transformers.ts', [])
6 | const result: TransformersSetupReturn = {
7 | pre: [],
8 | preCodeblock: [],
9 | postCodeblock: [],
10 | post: [],
11 | }
12 | for (const r of [...returns].reverse()) {
13 | if (r.pre)
14 | result.pre.push(...r.pre)
15 | if (r.preCodeblock)
16 | result.preCodeblock.push(...r.preCodeblock)
17 | }
18 | for (const r of returns) {
19 | if (r.postCodeblock)
20 | result.postCodeblock.push(...r.postCodeblock)
21 | if (r.post)
22 | result.post.push(...r.post)
23 | }
24 | return result
25 | }
26 |
--------------------------------------------------------------------------------
/packages/slidev/node/syntax/markdown-it/markdown-it-escape-code.ts:
--------------------------------------------------------------------------------
1 | import type MarkdownIt from 'markdown-it'
2 |
3 | export default function MarkdownItEscapeInlineCode(md: MarkdownIt) {
4 | const codeInline = md.renderer.rules.code_inline!
5 | md.renderer.rules.code_inline = (tokens, idx, options, env, self) => {
6 | const result = codeInline(tokens, idx, options, env, self)
7 | return result.replace(/^ self.renderToken(tokens, idx, options))
6 |
7 | md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
8 | const token = tokens[idx]
9 | const hrefIndex = token.attrIndex('href')
10 | const attr = token.attrs?.[hrefIndex]
11 | const href = attr?.[1] ?? ''
12 | if ('./#'.includes(href[0]) || /^\d+$/.test(href)) {
13 | token.tag = 'Link'
14 | attr![0] = 'to'
15 |
16 | for (let i = idx + 1; i < tokens.length; i++) {
17 | if (tokens[i].type === 'link_close') {
18 | tokens[i].tag = 'Link'
19 | break
20 | }
21 | }
22 | }
23 | else if (token.attrGet('target') == null) {
24 | token.attrPush(['target', '_blank'])
25 | }
26 | return defaultRender(tokens, idx, options, env, self)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/packages/slidev/node/syntax/markdown-it/markdown-it-shiki.ts:
--------------------------------------------------------------------------------
1 | import type { ResolvedSlidevOptions } from '@slidev/types'
2 | import type { ShikiTransformer } from 'shiki'
3 | import { isTruthy } from '@antfu/utils'
4 | import { fromHighlighter } from '@shikijs/markdown-it/core'
5 | import { escapeVueInCode } from '../transform/utils'
6 |
7 | export default async function MarkdownItShiki({ data: { config }, mode, utils }: ResolvedSlidevOptions) {
8 | const transformers = [
9 | ...utils.shikiOptions.transformers || [],
10 | (config.twoslash === true || config.twoslash === mode)
11 | && (await import('@shikijs/vitepress-twoslash')).transformerTwoslash({
12 | explicitTrigger: true,
13 | twoslashOptions: {
14 | handbookOptions: {
15 | noErrorValidation: true,
16 | },
17 | },
18 | }),
19 | {
20 | pre(pre) {
21 | this.addClassToHast(pre, 'slidev-code')
22 | delete pre.properties.tabindex
23 | },
24 | postprocess(code) {
25 | return escapeVueInCode(code)
26 | },
27 | } satisfies ShikiTransformer,
28 | ].filter(isTruthy) as ShikiTransformer[]
29 |
30 | return fromHighlighter(utils.shiki, {
31 | ...utils.shikiOptions,
32 | transformers,
33 | })
34 | }
35 |
--------------------------------------------------------------------------------
/packages/slidev/node/syntax/transform/code-wrapper.ts:
--------------------------------------------------------------------------------
1 | import type { MarkdownTransformContext } from '@slidev/types'
2 | import { normalizeRangeStr } from './utils'
3 |
4 | // eslint-disable-next-line regexp/no-super-linear-backtracking
5 | export const reCodeBlock = /^```([\w'-]+)?\s*(?:\[(.*?)\])?\s*(?:\{([\w*,|-]+)\}\s*?(\{[^}]*\})?([^\r\n]*))?\r?\n([ \t]*\S[\s\S]*?)^```$/gm
6 |
7 | /**
8 | * Transform code block with wrapper
9 | */
10 | export function transformCodeWrapper(ctx: MarkdownTransformContext) {
11 | ctx.s.replace(
12 | reCodeBlock,
13 | (full, lang = '', title = '', rangeStr: string = '', options = '', attrs = '', code: string) => {
14 | const ranges = normalizeRangeStr(rangeStr)
15 | code = code.trimEnd()
16 | options = options.trim() || '{}'
17 | return `\n\n\n\`\`\`${lang}${title ? ` [${title}]` : ''}${attrs}\n${code}\n\`\`\`\n\n `
18 | },
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/packages/slidev/node/syntax/transform/in-page-css.ts:
--------------------------------------------------------------------------------
1 | import type { MarkdownTransformContext } from '@slidev/types'
2 | import { getCodeBlocks } from './utils'
3 |
4 | /**
5 | * Transform