Skip to content

Commit

Permalink
feat: generate pdf!
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Apr 17, 2021
1 parent 3c2b2a8 commit d049b72
Show file tree
Hide file tree
Showing 12 changed files with 306 additions and 25 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ dist-ssr
node_modules
# intellij stuff
.idea/
*.pdf
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,10 @@ vite-slides build

**Export**

> Not yet.
```bash
npm i -D playwright
vite-slides export
```

## TODO

Expand All @@ -182,10 +185,10 @@ vite-slides build
- [x] Slides Overview
- [ ] Foot notes
- [x] `v-click` directive
- [ ] Standalone package
- [x] Standalone package
- [x] Dev Mode
- [x] Build Mode
- [ ] Export PDF
- [x] Export PDF
- [x] Configurable themes

## Sponsors
Expand Down
2 changes: 1 addition & 1 deletion demo/components/NumBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const value = useVModel(props, 'value', emit)

<template>
<div
class="w-16 h-16 rounded-xl shadow text-white overflow-hidden"
class="w-16 h-16 rounded-xl text-white overflow-hidden"
style="background-image: radial-gradient(farthest-corner at 0 0, var(--tw-gradient-from) 30%, var(--tw-gradient-to))"
>
<div
Expand Down
18 changes: 12 additions & 6 deletions packages/vite-slides/client/App.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<script setup lang="ts">
import { useHead } from '@vueuse/head'
import { computed } from 'vue'
import { computed, provide } from 'vue'
import { useNavigateControls } from './logic'
import { scale, targetHeight, targetWidth } from './logic/scale'
import { injectClickDisabled } from './modules/directives'
useHead({
title: 'Vite Slides',
Expand All @@ -16,21 +17,26 @@ const style = computed(() => ({
transform: `translate(-50%, -50%) scale(${scale.value})`,
}))
const query = new URLSearchParams(location.search)
if (query.has('print'))
provide(injectClickDisabled, true)
function onClick(e: MouseEvent) {
const classList = (e.target as HTMLElement)?.classList
if (classList?.contains('page-root'))
controls.next()
}
</script>

<template>
<div class="page-root" @click="onClick">
<div class="slide-container" :style="style">
<RouterView :class="controls.current.value?.meta?.class || ''" />
<div>
<div class="page-root" @click="onClick">
<div class="slide-container" :style="style">
<RouterView :class="controls.current.value?.meta?.class || ''" />
</div>
</div>
<SlideControls v-if="!query.has('print')" />
</div>
<SlideControls />
</template>
<style lang="postcss">
Expand Down
4 changes: 2 additions & 2 deletions packages/vite-slides/client/logic/controls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ export function createNavigateControls(router: Router) {
clickCurrent.value = 0
clickElements.value = []
counter.value = Math.min(routes.length - 1, counter.value + 1)
router.push(`/${counter.value}`)
router.push(`/${counter.value}${location.search}`)
}

function prevSlide() {
clickCurrent.value = 0
clickElements.value = []
counter.value = Math.max(0, counter.value - 1)
router.push(`/${counter.value}`)
router.push(`/${counter.value}${location.search}`)
}

const { space, right, left, up, down } = useMagicKeys()
Expand Down
6 changes: 3 additions & 3 deletions packages/vite-slides/client/logic/scale.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useElementSize } from '@vueuse/core'
import { useWindowSize } from '@vueuse/core'
import { reactive, computed } from 'vue'

export const aspect = 16 / 9
export const targetWidth = 1920 / 2.2
export const targetWidth = 980
export const targetHeight = targetWidth / aspect

const screen = reactive(useElementSize(document.body))
const screen = reactive(useWindowSize())
const screenAspect = computed(() => screen.width / screen.height)

export const scale = computed(() => {
Expand Down
2 changes: 1 addition & 1 deletion packages/vite-slides/client/modules/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export const install: UserModule = ({ app }) => {
},

beforeUnmount(el, dir) {
dirProvide(dir, injectClickDisabled, false)
dirProvide(dir, injectClickDisabled, true)
},
})
}
23 changes: 16 additions & 7 deletions packages/vite-slides/node/cli.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import chalk from 'chalk'
import minimist from 'minimist'
import { createServer } from './server'
import { build } from './build'

const argv: any = minimist(process.argv.slice(2))

Expand All @@ -13,18 +11,29 @@ const command = argv._[0]
const entry = argv._[command ? 1 : 0]

if (!command || command === 'dev') {
createServer(entry, argv)
import('./server')
.then(i => i.createServer(entry, argv))
.then(server => server.listen())
.catch((err) => {
console.error(chalk.red('failed to start server. error:\n'), err)
process.exit(1)
})
}
else if (command === 'build') {
build(entry, argv).catch((err) => {
console.error(chalk.red('build error:\n'), err)
process.exit(1)
})
import('./build')
.then(i => i.build(entry, argv))
.catch((err) => {
console.error(chalk.red('build error:\n'), err)
process.exit(1)
})
}
else if (command === 'export') {
import('./export')
.then(i => i.genratePDF(entry, argv))
.catch((err) => {
console.error(chalk.red('export error:\n'), err)
process.exit(1)
})
}
else {
console.log(chalk.red(`unknown command "${command}".`))
Expand Down
69 changes: 69 additions & 0 deletions packages/vite-slides/node/export.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { promises as fs } from 'fs'
import { chromium } from 'playwright'
import { InlineConfig } from 'vite'
import { PDFDocument } from 'pdf-lib'
import { green } from 'chalk'
import { createServer } from './server'
import { parseSlidesMarkdown } from './parser'

export async function genratePDF(entry = 'slides.md', config: InlineConfig = {}) {
const pages = parseSlidesMarkdown(await fs.readFile(entry, 'utf-8'))
const server = await createServer(entry, {
...config,
logLevel: 'silent',
clearScreen: false,
})
const port = 18724
await server.listen(port)

const browser = await chromium.launch()
const context = await browser.newContext({
viewport: {
width: 1920,
height: 1080,
},
deviceScaleFactor: 1,
})
const page = await context.newPage()

const buffers: Buffer[] = []
const pagesCount = pages.length - 1
for (let i = 0; i < pagesCount; i++) {
console.log(`Exporting: ${i + 1} / ${pagesCount}`)
await page.goto(`http://localhost:${port}/${i}?print`, {
waitUntil: 'networkidle',
})
await page.emulateMedia({ media: 'screen' })
const pdf = await page.pdf({
width: 1920,
height: 1080,
margin: {
left: 0,
top: 0,
right: 0,
bottom: 0,
},
pageRanges: '1',
printBackground: true,
preferCSSPageSize: true,
})
buffers.push(pdf)
}

const mergedPdf = await PDFDocument.create({})
for (const pdfBytes of buffers) {
const pdf = await PDFDocument.load(pdfBytes)
const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices())
copiedPages.forEach((page) => {
mergedPdf.addPage(page)
})
}

const buffer = await mergedPdf.save()
await fs.writeFile('slides.pdf', buffer)
console.log(green`Exporting finished: ./slides.pdf`)

browser.close()
server.close()
process.exit(0)
}
2 changes: 1 addition & 1 deletion packages/vite-slides/node/server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createServer as createViteServer, InlineConfig, mergeConfig } from 'vite'
import { ViteSlides } from './plugins/preset'

export async function createServer(entry: string, config: InlineConfig = {}) {
export async function createServer(entry?: string, config: InlineConfig = {}) {
return await createViteServer(
mergeConfig(
config,
Expand Down
10 changes: 10 additions & 0 deletions packages/vite-slides/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@
"client",
"dist"
],
"peerDependencies": {
"playwright": "^1.10.0"
},
"peerDependenciesMeta": {
"playwright": {
"optional": true
}
},
"dependencies": {
"@antfu/utils": "^0.0.9",
"@iconify/json": "^1.1.330",
Expand All @@ -41,6 +49,7 @@
"markdown-it-prism": "^2.1.6",
"minimist": "^1.2.5",
"monaco-editor": "^0.23.0",
"pdf-lib": "^1.16.0",
"prettier": "^2.2.1",
"prism-theme-vars": "^0.2.2",
"theme-vitesse": "^0.1.9",
Expand All @@ -64,6 +73,7 @@
"cross-env": "^7.0.3",
"eslint": "^7.24.0",
"esno": "^0.5.0",
"playwright": "^1.10.0",
"pnpm": "^6.1.0",
"rimraf": "^3.0.2",
"tsup": "^4.8.21",
Expand Down

0 comments on commit d049b72

Please sign in to comment.