slidev icon indicating copy to clipboard operation
slidev copied to clipboard

feat: print templates, slide layers and rewrite export function

Open KermanX opened this issue 4 months ago • 10 comments

close #1509

This PR:

  • Allow user to customize print template via the --template or -t option. In dev mode, the option is called --print-template.
    • User can add or override print template via ./pages/print/*.{vue,ts}
    • Print page is no longer being bundled in the build mode
    • The export-notes sub-command is removed. Use -t notes instead.
    • Previously, -t was the alias of --theme, but --theme is quite uncommon.
  • Add the "handout" print template (close #1421)
  • Add new layers for each slide:
    • layouts/slide-top.vue
    • layouts/slide-bottom.vue
  • Refactors DOM structure

The locations of the files and option names need some discussion.

KermanX avatar Apr 10 '24 14:04 KermanX

Deploy Preview for slidev ready!

Name Link
Latest commit 75f0744d13311ae46a68dc9cc96d5530db1bb428
Latest deploy log https://app.netlify.com/sites/slidev/deploys/663b2d0a1f118000082ba891
Deploy Preview https://deploy-preview-1513--slidev.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

netlify[bot] avatar Apr 10 '24 14:04 netlify[bot]

In order to make the handout https://github.com/slidevjs/slidev/pull/1421 pull request work with this code I found that I need to be able to control the scaling factor (zoom) inside SlideWrapper.vue

Currently it is retrieved from the front matter

const zoom = computed(() => props.route.meta?.slide?.frontmatter.zoom ?? 1)

If that would be configurable from a template (e.g. via inject) it would solve the problem that I ran into when implementing a notes template (point 2) where one adjusts the width and height correctly to fit an A4 page but the scale of the content is not adjusted and the content overflows out of the slide.

Here is a current draft of the notes template

oripka avatar Apr 17 '24 20:04 oripka

In order to make the handout #1421 pull request work with this code I found that I need to be able to control the scaling factor (zoom) inside SlideWrapper.vue

Currently it is retrieved from the front matter

const zoom = computed(() => props.route.meta?.slide?.frontmatter.zoom ?? 1)

If that would be configurable from a template (e.g. via inject) it would solve the problem that I ran into when implementing a notes template (point 2) where one adjusts the width and height correctly to fit an A4 page but the scale of the content is not adjusted and the content overflows out of the slide.

Here is a current draft of the notes template

About the debugging issue you said in #1421, there is a --print-template option in this PR now.

About the slide scale, we can use <SlideContainer> here (I will do this change).

KermanX avatar Apr 18 '24 03:04 KermanX

I tried the latest commit. Seems like solving a lot of issues.

One thing I noted is that the page aligns well in Firefox but not in Chrome and when exporting on the command line.

Here is firefox on the left, chrome on the right

image

And a document npx slidev export -t handout

slides-export-handout.pdf

Maybe an issue with some css?

oripka avatar Apr 18 '24 17:04 oripka

After a bit more testing, it seems that having a slide like this with transitions and renderwhen results in an empty slide.


---


# Test

<RenderWhen context="visible">
    <transition appear name="outro">
<img class="h-80 mx-auto" src="https://github.com/slidevjs/themes/blob/main/screenshots/theme-seriph/01.png?raw=true" alt="">
    </transition>
</RenderWhen>
<!--Test-->

<style>
.outro-enter-from {
  opacity: 0;
  transform: translate(-40px, 40px);
}
.outro-enter-active {
  transition: all 0.5s ease-in-out;
}
.outro-enter-to {
  transform: translate(0, 0);
}
.slidev-layout.outro {
  @apply bg-bottom bg-right;
}

</style>
image

oripka avatar Apr 18 '24 19:04 oripka

I spent 2 hours on this, trying to figure out why the page is (exactly) 1.5x larger than the expected size, but made no progress. The output is still like this:

image

KermanX avatar Apr 19 '24 05:04 KermanX

I spent 2 hours on this, trying to figure out why the page is (exactly) 1.5x larger than the expected size, but made no progress. The output is still like this:

Yes I have also spend some time debugging. I have found that changing the scale factor to 1.5 in export.ts works with your handout code, when exporting:

  async function genPagePdfOnePiece() {
    await go('print')
    await page.pdf({
      path: output,
      scale: 1.5,
      margin: {
        left: 0,
        top: 0,
        right: 0,
        bottom: 0,
      },
      printBackground: true,
      preferCSSPageSize: true,
    })

It might have to do with the DPI setting when exporting PDFs, here is a gist for debugging that tries to calculate the width and height according to the DPI (which is hardcoded for now): https://gist.github.com/oripka/36f4589df0fa72ed5758261c0a870264

The page breaks are now correct. The notes need a max-w-full in order to take the whole width.

oripka avatar Apr 19 '24 10:04 oripka

t might have to do with the DPI setting when exporting PDFs

I tried to set this setting to 100% and restart the browser:

image

, but the page is still 1.5x larger. I am worried that if we hard-code 1.5 in the code, it may not work on some machine🥺

KermanX avatar Apr 19 '24 10:04 KermanX

Maybe this is related to these known issues (pupeteer and chrome):

https://issues.chromium.org/issues/40144973#comment9 https://github.com/puppeteer/puppeteer/issues/666 https://github.com/puppeteer/puppeteer/issues/2278

I tried this code to determine it dynamically, but I think this is the incorrect DPI for printing, as this is one just displaying the page, not while generating the PDF. In my case it is 96. In the docs I found that the default reference value for PDF should be 72, which does not result in the 1.5 scale. It also contradicts the DPI of 144 that I found using tinkering: https://gist.github.com/oripka/36f4589df0fa72ed5758261c0a870264

    const dpi = await page.evaluate(() => {
      const div = document.createElement('div');
      div.style.position = 'absolute';
      div.style.top = 0;
      div.style.left = 0;
      div.style.width = '1in';
      div.style.height = '1in';
      document.body.appendChild(div);
      const height = div.offsetHeight;
      div.remove();
      return height;
    });

Maybe we should provide a sane default, test on Windows, Linux and macOS, in case there are any differences and make it a command line option.

oripka avatar Apr 19 '24 10:04 oripka

After some consideration I think I have to rewrite the export logic (this existing one is kind of messed up) Especially I am going to rewrite the --per-slide option.

KermanX avatar Apr 19 '24 13:04 KermanX