Skip to content

Commit

Permalink
Adds support for inline CSS
Browse files Browse the repository at this point in the history
  • Loading branch information
danburzo committed Oct 12, 2018
1 parent 7c43aec commit 0641c8c
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 43 deletions.
43 changes: 37 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@

Percollate is a command-line tool to turn web pages as beautifully formatted PDFs.

## Table of Contents

- [Installation](#installation)
- [Usage](#usage)
_ [Available commands](#available-commands)
_ [Available options](#available-options)
- [Examples](#examples)
_ [Basic PDF Generation](#basic-pdf-generation)
_ [Custom page size / margins](#custom-page-size-margins)
_ [Using a custom HTML template](#using-a-custom-html-template)
_ [Using a custom CSS stylesheet](#using-a-custom-css-stylesheet) \* [Customizing the page header / footer](#customizing-the-page-header-footer)
- [How it works](#how-it-works)
- [Troubleshooting](#troubleshooting)
- [See also](#see-also)

## Installation

> 💡 `percollate` needs Node.js version 8 or later, as it uses new(ish) JavaScript syntax.
Expand Down Expand Up @@ -42,15 +57,16 @@ yarn global upgrade --latest percollate

The `pdf`, `epub`, and `html` commands have these options:

| Option | What it does |
| -------------- | ----------------------------------------------- |
| `-o, --output` | (**Required**) The path of the resulting bundle |
| `--template` | Path to a custom HTML template |
| `--style` | Path to a custom CSS |
| Option | What it does |
| -------------- | --------------------------------------------------------------------------------------------------------- |
| `-o, --output` | (**Required**) The path of the resulting bundle |
| `--template` | Path to a custom HTML template |
| `--style` | Path to a custom CSS |
| `--css` | Additional CSS styles you can pass from the command-line to override the default/custom stylesheet styles |

## Examples

### Generating a PDF
### Basic PDF generation

To transform a single web page to PDF:

Expand All @@ -70,6 +86,21 @@ You can use common Unix commands and keep the list of URLs in a newline-delimite
cat urls.txt | xargs percollate pdf --output some.pdf
```

### Custom page size / margins

The default page size is A5 (portrait). You can use the `--css` option to override it using [any supported CSS `size`](https://www.w3.org/TR/css3-page/#page-size):

```bash
percollate pdf --output some.pdf --css "@page { size: A3 landscape }" http://example.com
```

Similarly, you can define:

- custom margins: `@page { margin: 0 }`
- the base font size: `html { font-size: 10pt }`

or, for that matter, any other style defined in the default / custom stylesheet.

### Using a custom HTML template

> ⚠️ TODO add example here
Expand Down
59 changes: 28 additions & 31 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ async function bundle(items, options) {
console.log(`Generating temporary HTML file at: ${temp_file}`);

const stylesheet = resolve(options.style || './templates/default.css');
const style = fs.readFileSync(stylesheet, 'utf8') + (options.css || '');

const html = nunjucks.renderString(
fs.readFileSync(
Expand All @@ -74,6 +75,9 @@ async function bundle(items, options) {
),
{
items: items,
style: style,

// deprecated
stylesheet: stylesheet
}
);
Expand All @@ -88,40 +92,32 @@ async function bundle(items, options) {
footerTemplate ? footerTemplate.innerHTML : '<span></span>'
).window.document;

if (fs.existsSync(stylesheet)) {
const css_ast = css.parse(fs.readFileSync(stylesheet, 'utf8'));
const css_ast = css.parse(style);

const header_style = get_style_attribute_value(css_ast, '.header-template');
const header_div = header.querySelector('body :first-child');

const header_style = get_style_attribute_value(
css_ast,
'.header-template'
if (header_div && header_style) {
header_div.setAttribute(
'style',
`
${header_style};
${header_div.getAttribute('style') || ''}
`
);
const header_div = header.querySelector('body :first-child');

if (header_div && header_style) {
header_div.setAttribute(
'style',
`
${header_style};
${header_div.getAttribute('style') || ''}
`
);
}
}

const footer_style = get_style_attribute_value(css_ast, '.footer-template');
const footer_div = footer.querySelector('body :first-child');

const footer_style = get_style_attribute_value(
css_ast,
'.footer-template'
if (footer_div && footer_style) {
footer_div.setAttribute(
'style',
`
${footer_style};
${footer_div.getAttribute('style') || ''}
`
);
const footer_div = footer.querySelector('body :first-child');

if (footer_div && footer_style) {
footer_div.setAttribute(
'style',
`
${footer_style};
${footer_div.getAttribute('style') || ''}
`
);
}
}

fs.writeFileSync(temp_file, html);
Expand Down Expand Up @@ -161,7 +157,8 @@ function with_common_options(cmd) {
return cmd
.option('-o, --output [output]', 'Path for the generated bundle')
.option('--template [template]', 'Path to custom HTML template')
.option('--style [stylesheet]', 'Path to custom CSS');
.option('--style [stylesheet]', 'Path to custom CSS')
.option('--css [style]', 'Additional CSS style');
}

program.version(pkg.version);
Expand Down
14 changes: 9 additions & 5 deletions src/get-style-attribute-value.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
module.exports = function(css_ast, selector) {
let rule = css_ast.stylesheet.rules.find(
let rules = css_ast.stylesheet.rules.filter(
rule => rule.type === 'rule' && rule.selectors.includes(selector)
);
if (!rule) {
if (!rules.length) {
return '';
}
return rule.declarations
.filter(d => d.type === 'declaration')
.map(d => `${d.property}: ${d.value}`)
return rules
.map(rule =>
rule.declarations
.filter(d => d.type === 'declaration')
.map(d => `${d.property}: ${d.value}`)
.join(';')
)
.join(';');
};
5 changes: 4 additions & 1 deletion templates/default.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
<head>
<meta charset="utf-8">
<title>🌐 Percollate</title>
<link rel='stylesheet' media='all' href="{{ stylesheet }}"/>

<style type='text/css'>
{{ style }}
</style>
</head>
<body>
{% for item in items %}
Expand Down

0 comments on commit 0641c8c

Please sign in to comment.