Compare commits

...

1 commit
master ... dev

Author SHA1 Message Date
Jakub Jirutka
a21a14a7cc Allow to include own style(s) into HTML produced by CLI
Resolves #6
2020-04-19 17:29:37 +02:00
2 changed files with 39 additions and 13 deletions

View file

@ -3,7 +3,7 @@ import minimist from 'minimist'
import minimistOptions from 'minimist-options' import minimistOptions from 'minimist-options'
import { Document } from 'nodom' import { Document } from 'nodom'
import { exit } from 'process' import { exit } from 'process'
import { $INLINE_JSON } from 'ts-transformer-inline-file' import { $INLINE_FILE, $INLINE_JSON } from 'ts-transformer-inline-file'
import * as ipynb2html from 'ipynb2html' import * as ipynb2html from 'ipynb2html'
@ -11,6 +11,8 @@ import renderPage from './page'
const { version, bugs: bugsUrl } = $INLINE_JSON('../package.json') const { version, bugs: bugsUrl } = $INLINE_JSON('../package.json')
const notebookCss = $INLINE_FILE('../../ipynb2html/styles/notebook.css')
const pageCss = $INLINE_FILE('./page.css')
const progName = 'ipynb2html' const progName = 'ipynb2html'
const helpMsg = `\ const helpMsg = `\
@ -24,13 +26,20 @@ Arguments:
provided, the output will be written to STDOUT. provided, the output will be written to STDOUT.
Options: Options:
-d --debug Print debug messages. -d --debug Print debug messages.
-h --help Show this message and exit.
-V --version Print version and exit. -s --style <file,...> Comma separated stylesheet(s) to embed into the output
HTML. The stylesheet may be a path to a CSS file,
"@base" for the base ipynb2html style, or "@default"
for the default full page style. Default is @default.
-h --help Show this message and exit.
-V --version Print version and exit.
Exit Codes: Exit Codes:
1 Generic error code. 1 Generic error code.
2 Missing required arguments or invalid option. 2 Missing required arguments or invalid option.
Please report bugs at <${bugsUrl}>. Please report bugs at <${bugsUrl}>.
` `
@ -39,9 +48,14 @@ function logErr (msg: string): void {
console.error(`${progName}: ${msg}`) console.error(`${progName}: ${msg}`)
} }
function arrify <T> (obj: T | T[]): T[] {
return Array.isArray(obj) ? obj : [obj]
}
function parseCliArgs (argv: string[]) { function parseCliArgs (argv: string[]) {
const opts = minimist(argv, minimistOptions({ const opts = minimist(argv, minimistOptions({
debug: { alias: 'd', type: 'boolean' }, debug: { alias: 'd', type: 'boolean' },
style: { alias: 's', type: 'string', default: '@default' },
version: { alias: 'V', type: 'boolean' }, version: { alias: 'V', type: 'boolean' },
help: { alias: 'h', type: 'boolean' }, help: { alias: 'h', type: 'boolean' },
arguments: 'string', arguments: 'string',
@ -73,24 +87,34 @@ function parseCliArgs (argv: string[]) {
const [input, output] = opts._ const [input, output] = opts._
return { return {
styles: arrify(opts.style).join(',').split(/,\s*/),
debug: opts.debug as boolean, debug: opts.debug as boolean,
input: input === '-' ? 0 : input, // 0 = stdin input: input === '-' ? 0 : input, // 0 = stdin
output, output,
} }
} }
function loadStyle (name: string): string {
switch (name) {
case '@base': return notebookCss
case '@default': return pageCss + notebookCss
default: return fs.readFileSync(name, 'utf8')
}
}
export default (argv: string[]): void => { export default (argv: string[]): void => {
const opts = parseCliArgs(argv) const opts = parseCliArgs(argv)
try { try {
const notebook = JSON.parse(fs.readFileSync(opts.input, 'utf-8')) const notebook = JSON.parse(fs.readFileSync(opts.input, 'utf-8'))
const style = opts.styles.map(loadStyle).join('\n')
const title = ipynb2html.readNotebookTitle(notebook) ?? 'Notebook' const title = ipynb2html.readNotebookTitle(notebook) ?? 'Notebook'
const renderNotebook = ipynb2html.createRenderer(new Document()) const renderNotebook = ipynb2html.createRenderer(new Document())
const contents = renderNotebook(notebook).outerHTML const contents = renderNotebook(notebook).outerHTML
const html = renderPage(contents, title) const html = renderPage({ contents, title, style })
if (opts.output) { if (opts.output) {
fs.writeFileSync(opts.output, html) fs.writeFileSync(opts.output, html)

View file

@ -1,11 +1,13 @@
import { version } from 'ipynb2html' import { version } from 'ipynb2html'
import { $INLINE_FILE } from 'ts-transformer-inline-file'
const notebookCss = $INLINE_FILE('../../ipynb2html/styles/notebook.css')
const pageCss = $INLINE_FILE('./page.css')
export default (contents: string, title: string): string => `\ export type Options = {
contents: string,
title: string,
style: string,
}
export default ({ contents, title, style }: Options): string => `\
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
@ -22,7 +24,7 @@ export default (contents: string, title: string): string => `\
integrity="sha384-BdGj8xC2eZkQaxoQ8nSLefg4AV4/AwB3Fj+8SUSo7pnKP6Eoy18liIKTPn9oBYNG" integrity="sha384-BdGj8xC2eZkQaxoQ8nSLefg4AV4/AwB3Fj+8SUSo7pnKP6Eoy18liIKTPn9oBYNG"
crossorigin="anonymous"> crossorigin="anonymous">
<style> <style>
${(pageCss + notebookCss).slice(0, -1).replace(/\n\n/g, '\n').replace(/^/gm, ' ')} ${style.replace(/\n\n/g, '\n').replace(/\n$/, '').replace(/^/gm, ' ')}
</style> </style>
</head> </head>
<body> <body>