diff --git a/README.md b/README.md index d18156de8c..cfccae0c6c 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Presentation slides for developers 🧑‍💻👩‍💻👨‍ ### Init Project Locally -Install [Node.js >=18](https://nodejs.org/) and run the following command: +Install [Node.js >= 20.12.0](https://nodejs.org/) and run the following command: ```bash npm init slidev diff --git a/docs/.vitepress/addons.ts b/docs/.vitepress/addons.ts index 881c12f140..df3eb936f4 100644 --- a/docs/.vitepress/addons.ts +++ b/docs/.vitepress/addons.ts @@ -225,6 +225,17 @@ export const community: AddonInfo[] = [ }, repo: 'https://github.com/emaarco/slidev-addon-bpmn', }, + { + id: 'slidev-addon-dmn', + name: 'DMN viewer', + description: 'Display DMN decision tables and DRD diagrams in your slidev', + tags: ['Component'], + author: { + name: 'emaarco', + link: 'https://github.com/emaarco', + }, + repo: 'https://github.com/emaarco/slidev-addon-dmn', + }, { id: 'slidev-addon-p5', name: 'Runner for p5js', @@ -236,15 +247,22 @@ export const community: AddonInfo[] = [ }, repo: 'https://github.com/mjvo/slidev-addon-p5', }, + { + id: 'slidev-pane', + name: 'slidev-pane', + description: 'PowerPoint-style pane presenter for Slidev with slide thumbnails, quick navigation, and a zoomable main canvas.', + tags: ['Navigation'], + author: { + name: 'xunz', + link: 'https://github.com/xunz3', + }, + repo: 'https://github.com/xunz3/slidev-pane', + }, // Add yours here! { id: '', link: 'https://github.com/slidevjs/slidev/edit/main/docs/.vitepress/addons.ts', name: 'Yours?', description: 'Click here to submit your addon :)', - tags: [], - author: { - name: '', - }, }, ] diff --git a/docs/.vitepress/theme/components/AddonInfo.vue b/docs/.vitepress/theme/components/AddonInfo.vue index 17c11071d2..1a443399ea 100644 --- a/docs/.vitepress/theme/components/AddonInfo.vue +++ b/docs/.vitepress/theme/components/AddonInfo.vue @@ -27,12 +27,12 @@ defineProps<{
{{ addon.author.name }} -
+
{{ addon.author.name }}
diff --git a/docs/.vitepress/theme/components/FeatureTag.vue b/docs/.vitepress/theme/components/FeatureTag.vue index c131336ce3..32fb9b87b6 100644 --- a/docs/.vitepress/theme/components/FeatureTag.vue +++ b/docs/.vitepress/theme/components/FeatureTag.vue @@ -33,8 +33,11 @@ function getHsla( } const formattedTag = computed(() => { - const tag = props.tag - .replace(/\b(API|CLI)\b/gi, m => m.toUpperCase()) + let tag = props.tag + if (tag === tag.toUpperCase()) { + return tag + } + tag = tag.replace(/\b(API|CLI)\b/gi, m => m.toUpperCase()) .replace(/-/g, ' ') return tag[0].toUpperCase() + tag.slice(1) }) diff --git a/docs/.vitepress/theme/components/ThemeInfo.vue b/docs/.vitepress/theme/components/ThemeInfo.vue index de725c7928..065fb6638a 100644 --- a/docs/.vitepress/theme/components/ThemeInfo.vue +++ b/docs/.vitepress/theme/components/ThemeInfo.vue @@ -46,12 +46,12 @@ if (props.theme.previews.length > 1 && isClient) {
{{ theme.author.name }} -
+
{{ theme.author.name }}
diff --git a/docs/.vitepress/themes.ts b/docs/.vitepress/themes.ts index 367f6423ee..508a0e2ffc 100644 --- a/docs/.vitepress/themes.ts +++ b/docs/.vitepress/themes.ts @@ -4,7 +4,7 @@ export interface ThemeInfo { description: string previews: string[] repo?: string - author: { + author?: { name: string link?: string } @@ -644,9 +644,6 @@ export const community: ThemeInfo[] = [ link: 'https://github.com/slidevjs/slidev/edit/main/docs/.vitepress/themes.ts', name: 'Yours?', description: 'Click here to submit your theme :)', - author: { - name: '', - }, previews: [ '/theme-placeholder.png', ], diff --git a/docs/custom/directory-structure.md b/docs/custom/directory-structure.md index 95bdb5da78..9d3ccdb376 100644 --- a/docs/custom/directory-structure.md +++ b/docs/custom/directory-structure.md @@ -43,6 +43,12 @@ Pattern: `./style.css` | `./styles/index.{css,js,ts}` Files following this convention will be injected to the App root. If you need to import multiple CSS entries, you can create the following structure and manage the import order yourself. +:::warning +Global CSS here also applies to the presenter UI. Prefer scoping styles to individual slides, or wrap your selectors under `.slidev-layout` to avoid leaking styles into presenter mode. + +**Example:** Use `.slidev-layout .grid { ... }` instead of just `.grid { ... }`. +::: + ```bash your-slidev/ ├── ... diff --git a/docs/features/index.md b/docs/features/index.md index 94e87109ec..b89143db24 100644 --- a/docs/features/index.md +++ b/docs/features/index.md @@ -17,7 +17,7 @@ const query = useUrlSearchParams('hash-params', { removeFalsyValues: true }) const search = toRef(query, 'search') as Ref const tags = toRef(query, 'tags') as Ref const tagsArr = computed({ - get: () => tags.value?.toLowerCase().split(',').map(t => t.trim()).filter(Boolean) ?? [], + get: () => tags.value?.split(',').map(t => t.trim()).filter(Boolean) ?? [], set: (val: string[]) => query.tags = val.join(','), }) @@ -25,8 +25,17 @@ const filteredFeatures = computed(() => { const s = search.value?.toLowerCase().trim() const t = tagsArr.value return Object.values(features).filter(feature => { - return (!s || feature.title.toLowerCase().includes(s) || feature.description.toLowerCase().includes(s)) - && (!t?.length || t.every(tag => feature.tags?.includes(tag))) + const matchSearch = !s || + feature.name.toLowerCase().includes(s) || + feature.title.toLowerCase().includes(s) || + feature.description.toLowerCase().includes(s) + + const matchTags = !t?.length || t.every(tag => + feature.tags?.some(featureTag => + featureTag.toLowerCase() === tag.toLowerCase() + ) + ) + return matchSearch && matchTags }) }) diff --git a/docs/guide/hosting.md b/docs/guide/hosting.md index 7166a080ed..b818d019ad 100644 --- a/docs/guide/hosting.md +++ b/docs/guide/hosting.md @@ -188,6 +188,28 @@ Create `vercel.json` in your project root with the following content: Then go to your [Vercel dashboard](https://vercel.com/) and create a new site with the repository. +### Zephyr Cloud {#zephyr-cloud} + +To deploy your Slidev deck on [Zephyr Cloud](https://zephyr-cloud.io/), you can add Zephyr support to an existing Slidev project with: + +```bash +npx with-zephyr@latest +``` + +This codemod detects your bundler (Slidev uses Vite) and updates your config for Zephyr Cloud. + +After setup, run your normal build command, for example: + +```bash +npm run build +``` + +When the build runs with Zephyr enabled, your app is deployed and Zephyr Cloud returns a preview URL. + +::: info +Zephyr Cloud is a bit different from most hosting providers: every `build` run triggers a deployment. +::: + ### Host on Docker {#docker} If you need a rapid way to run a presentation with containers, you can use the prebuilt [docker image](https://hub.docker.com/r/tangramor/slidev) maintained by [tangramor](https://github.com/tangramor), or build your own. diff --git a/docs/guide/index.md b/docs/guide/index.md index cbd7a04d3e..69fac97d0c 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -40,7 +40,7 @@ Start Slidev right in your browser with StackBlitz: [sli.dev/new](https://sli.de ### Create Locally -> Requires [Node.js](https://nodejs.org) >= 18.0 installed. +> Requires [Node.js](https://nodejs.org) >= 20.12.0 installed. Run the following command to create a new Slidev project locally: diff --git a/docs/package.json b/docs/package.json index eeb89d5814..b395c148e2 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,7 +1,7 @@ { "name": "@slidev/docs", "type": "module", - "version": "52.14.1", + "version": "52.14.2", "license": "MIT", "funding": "https://github.com/sponsors/antfu", "homepage": "https://sli.dev", diff --git a/docs/resources/addon-gallery.md b/docs/resources/addon-gallery.md index 662838d45c..cc48a79ce0 100644 --- a/docs/resources/addon-gallery.md +++ b/docs/resources/addon-gallery.md @@ -12,11 +12,11 @@ Browse awesome addons available for Slidev here. Read more about to use them, and to create your own addon. -## Official Addons + ## Community Addons diff --git a/package.json b/package.json index 0453862b21..2e42dbce50 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "type": "module", - "version": "52.14.1", + "version": "52.14.2", "private": true, "packageManager": "pnpm@10.30.3", "engines": { - "node": ">=18.0.0" + "node": ">=20.12.0" }, "scripts": { "build": "pnpm -r --filter=\"./packages/**\" --parallel run build", @@ -46,6 +46,7 @@ "@types/resolve": "catalog:types", "@types/semver": "catalog:types", "@types/yargs": "catalog:types", + "@vue/compiler-sfc": "catalog:demo", "@vueuse/core": "catalog:frontend", "bumpp": "catalog:dev", "cypress": "catalog:dev", diff --git a/packages/client/internals/Goto.vue b/packages/client/internals/Goto.vue index 12ca9d82f1..a7811cc9ab 100644 --- a/packages/client/internals/Goto.vue +++ b/packages/client/internals/Goto.vue @@ -26,7 +26,7 @@ const fuse = computed(() => new Fuse(slides.value.map(i => i.meta?.slide).filter })) const path = computed(() => text.value.startsWith('/') ? text.value.substring(1) : text.value) -const result = computed(() => fuse.value.search(path.value).map(result => result.item)) +const result = computed(() => path.value ? fuse.value.search(path.value).map(result => result.item) : []) const valid = computed(() => !!result.value.length) function goTo() { diff --git a/packages/client/logic/slides.ts b/packages/client/logic/slides.ts index 6891cc468f..075d43f4e5 100644 --- a/packages/client/logic/slides.ts +++ b/packages/client/logic/slides.ts @@ -1,7 +1,6 @@ import type { SlideRoute } from '@slidev/types' import { slides } from '#slidev/slides' import { computed, watch, watchEffect } from 'vue' -import { useNav } from '../composables/useNav' import { useSlideContext } from '../context' export { slides } @@ -24,9 +23,9 @@ export function getSlidePath( } export function useIsSlideActive() { - const { $page } = useSlideContext() - const { currentSlideNo } = useNav() - return computed(() => $page.value === currentSlideNo.value) + const { $page, $nav } = useSlideContext() + // Use `$nav.value.currentSlideNo` rather than `useNav().currentSlideNo` to make it work in print/export mode. See https://github.com/slidevjs/slidev/issues/2310. + return computed(() => $page.value === $nav.value.currentSlideNo) } export function onSlideEnter(cb: () => void) { diff --git a/packages/client/package.json b/packages/client/package.json index 9a2c12daac..955023b6f7 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,7 +1,7 @@ { "name": "@slidev/client", "type": "module", - "version": "52.14.1", + "version": "52.14.2", "description": "Presentation slides for developers", "author": "Anthony Fu ", "license": "MIT", @@ -25,7 +25,7 @@ }, "main": "./public.ts", "engines": { - "node": ">=18.0.0" + "node": ">=20.12.0" }, "dependencies": { "@antfu/utils": "catalog:frontend", diff --git a/packages/create-app/package.json b/packages/create-app/package.json index b5ff3e1d5a..a9e99bed43 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "create-slidev", "type": "module", - "version": "52.14.1", + "version": "52.14.2", "description": "Create starter template for Slidev", "author": "Anthony Fu ", "license": "MIT", @@ -21,7 +21,7 @@ "template" ], "engines": { - "node": ">=18.0.0" + "node": ">=20.12.0" }, "scripts": { "build": "node build.mjs", diff --git a/packages/create-app/template/package.json b/packages/create-app/template/package.json index f024fa136d..0fa5c0f157 100644 --- a/packages/create-app/template/package.json +++ b/packages/create-app/template/package.json @@ -8,7 +8,7 @@ "export": "slidev export" }, "dependencies": { - "@slidev/cli": "^52.14.1", + "@slidev/cli": "^52.14.2", "@slidev/theme-default": "latest", "@slidev/theme-seriph": "latest", "vue": "^3.5.29" diff --git a/packages/create-theme/package.json b/packages/create-theme/package.json index 4468ec9e49..f26c967514 100644 --- a/packages/create-theme/package.json +++ b/packages/create-theme/package.json @@ -1,7 +1,7 @@ { "name": "create-slidev-theme", "type": "module", - "version": "52.14.1", + "version": "52.14.2", "description": "Create starter theme template for Slidev", "author": "Anthony Fu ", "license": "MIT", @@ -17,7 +17,7 @@ "create-slidev-theme": "index.mjs" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.12.0" }, "dependencies": { "ansis": "catalog:prod", diff --git a/packages/create-theme/template/package.json b/packages/create-theme/template/package.json index 36572845f1..996f86db76 100644 --- a/packages/create-theme/template/package.json +++ b/packages/create-theme/template/package.json @@ -5,7 +5,7 @@ "slidev" ], "engines": { - "node": ">=18.0.0" + "node": ">=20.12.0" }, "scripts": { "build": "slidev build example.md", @@ -14,10 +14,10 @@ "screenshot": "slidev export example.md --format png" }, "dependencies": { - "@slidev/types": "^52.14.1" + "@slidev/types": "^52.14.2" }, "devDependencies": { - "@slidev/cli": "^52.14.1" + "@slidev/cli": "^52.14.2" }, "//": "Learn more: https://sli.dev/guide/write-theme.html", "slidev": { diff --git a/packages/parser/package.json b/packages/parser/package.json index 3c33f0173d..d40f04570f 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -1,6 +1,6 @@ { "name": "@slidev/parser", - "version": "52.14.1", + "version": "52.14.2", "description": "Markdown parser for Slidev", "author": "Anthony Fu ", "license": "MIT", @@ -26,7 +26,7 @@ "dist" ], "engines": { - "node": ">=18.0.0" + "node": ">=20.12.0" }, "scripts": { "build": "tsdown", diff --git a/packages/slidev/node/cli.ts b/packages/slidev/node/cli.ts index 9c500d2859..08f4200482 100644 --- a/packages/slidev/node/cli.ts +++ b/packages/slidev/node/cli.ts @@ -271,6 +271,8 @@ cli.command( ] function bindShortcut() { + if (!process.stdin.isTTY) + return process.stdin.resume() process.stdin.setEncoding('utf8') readline.emitKeypressEvents(process.stdin) diff --git a/packages/slidev/package.json b/packages/slidev/package.json index 68d72c2476..74e6cdfa93 100644 --- a/packages/slidev/package.json +++ b/packages/slidev/package.json @@ -1,7 +1,7 @@ { "name": "@slidev/cli", "type": "module", - "version": "52.14.1", + "version": "52.14.2", "description": "Presentation slides for developers", "author": "Anthony Fu ", "license": "MIT", @@ -32,7 +32,7 @@ "template.md" ], "engines": { - "node": ">=18.0.0" + "node": ">=20.12.0" }, "scripts": { "build": "tsdown node/index.ts node/cli.ts", diff --git a/packages/types/package.json b/packages/types/package.json index 4f210e5108..84b9f7e8e5 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@slidev/types", - "version": "52.14.1", + "version": "52.14.2", "description": "Shared types declarations for Slidev", "author": "Anthony Fu ", "license": "MIT", @@ -20,7 +20,7 @@ "index.d.ts" ], "engines": { - "node": ">=18.0.0" + "node": ">=20.12.0" }, "scripts": { "build": "tsdown src/index.ts", diff --git a/packages/vscode/package.json b/packages/vscode/package.json index 752aec407c..64d7d400e8 100644 --- a/packages/vscode/package.json +++ b/packages/vscode/package.json @@ -4,7 +4,7 @@ "displayName": "Slidev", "type": "module", "preview": true, - "version": "52.14.1", + "version": "52.14.2", "private": true, "description": "Slidev support for VS Code", "license": "MIT", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3aadeb6e88..e782f4c999 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -498,6 +498,9 @@ importers: '@types/yargs': specifier: catalog:types version: 17.0.35 + '@vue/compiler-sfc': + specifier: catalog:demo + version: 3.5.29 '@vueuse/core': specifier: catalog:frontend version: 14.2.1(vue@3.5.29(typescript@5.9.3)) diff --git a/skills/slidev/SKILL.md b/skills/slidev/SKILL.md index 427b8db524..35c3484229 100644 --- a/skills/slidev/SKILL.md +++ b/skills/slidev/SKILL.md @@ -1,6 +1,6 @@ --- name: slidev -description: Create and present web-based slides for developers using Markdown, Vue components, code highlighting, animations, and interactive features. Use when building technical presentations, conference talks, or teaching materials. +description: Create and present web-based slidedecks for developers using Slidev with Markdown, Vue components, code highlighting, animations, and interactive features. Use when building technical presentations, conference talks, code walkthroughs, teaching materials, or developer decks. --- # Slidev - Presentation Slides for Developers @@ -9,21 +9,25 @@ Web-based slides maker built on Vite, Vue, and Markdown. ## When to Use -- Technical presentations with live code examples +- Technical presentations or slidedecks with live code examples - Syntax-highlighted code snippets with animations - Interactive demos (Monaco editor, runnable code) - Mathematical equations (LaTeX) or diagrams (Mermaid, PlantUML) - Record presentations with presenter notes - Export to PDF, PPTX, or host as SPA +- Code walkthroughs for developer talks or workshops ## Quick Start ```bash pnpm create slidev # Create project -pnpm run dev # Start dev server -pnpm run export # Export to PDF +pnpm run dev # Start dev server (opens http://localhost:3030) +pnpm run build # Build static SPA +pnpm run export # Export to PDF (requires playwright-chromium) ``` +**Verify**: After `pnpm run dev`, confirm slides load at `http://localhost:3030`. After `pnpm run export`, check the output PDF exists in the project root. + ## Basic Syntax ```md @@ -144,6 +148,8 @@ Presenter notes go here | OG image | `seoMeta.ogImage` or `og-image.png` | [build-og-image](references/build-og-image.md) | | SEO tags | `seoMeta:` | [build-seo-meta](references/build-seo-meta.md) | +**Export prerequisite**: `pnpm add -D playwright-chromium` is required for PDF/PPTX/PNG export. If export fails with a browser error, install this dependency first. + ### Editor & Tools | Feature | Usage | Reference | diff --git a/tsdown.config.ts b/tsdown.config.ts index 293c5c5218..3c9a54633a 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -4,7 +4,7 @@ export default defineConfig({ format: [ 'esm', ], - target: 'node18', + target: 'node20', dts: true, clean: true, shims: false,