Added a CSS file to the epub output format.

This commit is contained in:
Mark Wolfman
2021-07-05 22:54:23 -05:00
parent 05aec37352
commit b1e69182eb
12 changed files with 122 additions and 47 deletions
+23 -3
View File
@@ -1,11 +1,11 @@
from typing import Mapping from typing import Mapping
from ebooklib import epub from ebooklib import epub, ITEM_STYLE
from docutils import core from docutils import core
from sphinx.util.docstrings import prepare_docstring from sphinx.util.docstrings import prepare_docstring
from docutils.writers.html5_polyglot import Writer as HTMLWriter from docutils.writers.html5_polyglot import Writer as HTMLWriter
from dungeonsheets.latex import dice_re from dungeonsheets.forms import dice_re, jinja_environment
def create_epub( def create_epub(
@@ -35,12 +35,21 @@ def create_epub(
book.set_identifier('id123456') book.set_identifier('id123456')
book.set_title(title) book.set_title(title)
book.set_language('en') book.set_language('en')
# Add the css files
css_template = jinja_env.get_template("dungeonsheets_epub.css")
style = css_template.render(use_dnd_decorations=use_dnd_decorations)
css = epub.EpubItem(uid="style_default", file_name="style/gm_sheet.css",
media_type="text/css", content=style)
book.add_item(css)
# Create the separate chapters # Create the separate chapters
html_chapters = [] html_chapters = []
for chap_title, content in chapters.items(): for chap_title, content in chapters.items():
chap_fname = "{}.html".format(chap_title.replace(" ", "_").lower()) chap_fname = "{}.html".format(chap_title.replace(" ", "_").lower())
chapter = epub.EpubHtml(title=chap_title, file_name=chap_fname, lang="en") chapter = epub.EpubHtml(title=chap_title,
file_name=chap_fname, lang="en",
media_type="application/xhtml+xml")
chapter.set_content(content) chapter.set_content(content)
chapter.add_item(css)
book.add_item(chapter) book.add_item(chapter)
html_chapters.append(chapter) html_chapters.append(chapter)
# Add the table of contents # Add the table of contents
@@ -137,3 +146,14 @@ def rst_to_html(rst, top_heading_level=0):
_html_parts = html_parts(rst) _html_parts = html_parts(rst)
html = _html_parts["body"] html = _html_parts["body"]
return html return html
def to_heading_id(inpt: str) -> str:
"""Take a string and make it suitable for use as an HTML header id."""
return inpt.replace(" ", "-")
# Prepare the jinja environment
jinja_env = jinja_environment()
jinja_env.filters['rst_to_html'] = rst_to_html
jinja_env.filters['to_heading_id'] = to_heading_id
+1 -1
View File
@@ -6,7 +6,7 @@ import warnings
import pdfrw import pdfrw
from fdfgen import forge_fdf from fdfgen import forge_fdf
from dungeonsheets.stats import mod_str from dungeonsheets.forms import mod_str
CHECKBOX_ON = "Yes" CHECKBOX_ON = "Yes"
CHECKBOX_OFF = "Off" CHECKBOX_OFF = "Off"
+38
View File
@@ -0,0 +1,38 @@
import re
from jinja2 import Environment, PackageLoader
# A dice string, with optional backticks: ``1d6 + 3``
dice_re = re.compile(r"`*(\d+d\d+(?:\s*\+\s*\d+)?)`*")
def mod_str(modifier):
"""Converts a modifier to a string, eg 2 -> '+2'."""
return "{:+d}".format(modifier)
def jinja_environment():
"""Prepare a new environment for Jinja templates.
This function loads filters that are agnostic to the output
format. Format specific filters (e.g. html, latex, etc.) should be
added to ``jinja_env.filters``.
Returns
-------
jinja_env
The newly created jinja environment.
"""
jinja_env = Environment(
loader=PackageLoader("dungeonsheets", "forms"),
block_start_string="[%",
block_end_string="%]",
variable_start_string="[[",
variable_end_string="]]",
)
jinja_env.filters["mod_str"] = mod_str
return jinja_env
@@ -0,0 +1,39 @@
h1, h2, h3, h4, h5, h6 {
color: #58180d;
}
/* End fancy decorations */
table {
margin-bottom: 10px;
}
th {
border-style: solid;
border-width: 0px;
border-bottom-width: 1px;
padding-left: 5px;
padding-right: 5px;
text-align: center;
}
td {
padding-left: 5px;
padding-right: 5px;
text-align: center;
}
dt {
font-weight: bold;
}
dd > p {
margin-top: 0px;
}
div.system-message {
background: pink;
border-color: red;
border-style: solid;
border-width: 2px;
color: red;
}
+2 -2
View File
@@ -1,10 +1,10 @@
<h1 id="gm-monsters">Monsters</h1> <h1 id="gm-monsters">Monsters</h1>
[% for monster in monsters|sort(attribute='name') %] [% for monster in monsters|sort(attribute='name') %]
<h1 id="gm-monsters-[[ monster.name ]]">[[ monster.name ]]</h1> <h2 id="gm-monsters-[[ monster.name|to_heading_id ]]">[[ monster.name ]]</h1>
[% if monster.description %] [% if monster.description %]
<h2>[[ monster.description ]]</h2> <h3>[[ monster.description ]]</h2>
[% endif %] [% endif %]
<!-- Basic properties --> <!-- Basic properties -->
-3
View File
@@ -1,3 +0,0 @@
</body>
</html>
-6
View File
@@ -1,6 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>My title</title>
</head>
<body>
+1 -4
View File
@@ -8,15 +8,12 @@ from docutils.writers.latex2e import Writer, Table, LaTeXTranslator
from sphinx.util.docstrings import prepare_docstring from sphinx.util.docstrings import prepare_docstring
from dungeonsheets import exceptions from dungeonsheets import exceptions
from dungeonsheets.forms import dice_re
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
# A dice string, with optional backticks: ``1d6 + 3``
dice_re = re.compile(r"`*(\d+d\d+(?:\s*\+\s*\d+)?)`*")
class LatexWriter(Writer): class LatexWriter(Writer):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
+12 -18
View File
@@ -11,10 +11,8 @@ from multiprocessing import Pool, cpu_count
from itertools import product from itertools import product
from typing import Union, Sequence, Optional from typing import Union, Sequence, Optional
from jinja2 import Environment, PackageLoader from dungeonsheets import character as _char, exceptions, readers, latex, epub, monsters, forms
from dungeonsheets.forms import mod_str
from dungeonsheets import character as _char, exceptions, readers, latex, epub, monsters
from dungeonsheets.stats import mod_str
from dungeonsheets.content_registry import find_content from dungeonsheets.content_registry import find_content
from dungeonsheets.fill_pdf_template import ( from dungeonsheets.fill_pdf_template import (
create_character_pdf_template, create_character_pdf_template,
@@ -41,21 +39,16 @@ ORDINALS = {
9: "9th", 9: "9th",
} }
jinja_env = Environment(
loader=PackageLoader("dungeonsheets", "forms"),
block_start_string="[%",
block_end_string="%]",
variable_start_string="[[",
variable_end_string="]]",
)
jinja_env.filters["rst_to_latex"] = latex.rst_to_latex
jinja_env.filters["rst_to_html"] = epub.rst_to_html
jinja_env.filters["mod_str"] = mod_str
PDFTK_CMD = "pdftk" PDFTK_CMD = "pdftk"
jinja_env = forms.jinja_environment()
jinja_env.filters["rst_to_latex"] = latex.rst_to_latex
jinja_env.filters["rst_to_html"] = epub.rst_to_html
jinja_env.filters["to_heading_id"] = epub.to_heading_id
# Custom types # Custom types
File = Union[Path, str] File = Union[Path, str]
@@ -219,12 +212,13 @@ def make_gm_sheet(
gm_file = Path(gm_file) gm_file = Path(gm_file)
basename = gm_file.stem basename = gm_file.stem
gm_props = readers.read_sheet_file(gm_file) gm_props = readers.read_sheet_file(gm_file)
session_title = gm_props.get("session_title", f"GM Notes: {basename}")
# Create the intro tex # Create the intro tex
content_suffix = format_suffixes[output_format] content_suffix = format_suffixes[output_format]
content = [ content = [
jinja_env.get_template(f"preamble.{content_suffix}").render( jinja_env.get_template(f"preamble.{content_suffix}").render(
use_dnd_decorations=fancy_decorations, use_dnd_decorations=fancy_decorations,
title=gm_props.pop("session_title", "GM Session Notes"), title=session_title,
) )
] ]
# Add the party stats table and session summary # Add the party stats table and session summary
@@ -302,9 +296,9 @@ def make_gm_sheet(
log.warning(f"``pdflatex`` not available. Skipping {basename}") log.warning(f"``pdflatex`` not available. Skipping {basename}")
elif output_format == "epub": elif output_format == "epub":
epub.create_epub( epub.create_epub(
chapters={"GM Sheet": "".join(content)}, chapters={session_title: "".join(content)},
basename=basename, basename=basename,
title=gm_props.get("session_title", f"GM Notes: {basename}"), title=session_title,
use_dnd_decorations=fancy_decorations, use_dnd_decorations=fancy_decorations,
) )
else: else:
-5
View File
@@ -30,11 +30,6 @@ from dungeonsheets.features import (
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def mod_str(modifier):
"""Converts a modifier to a string, eg 2 -> '+2'."""
return "{:+d}".format(modifier)
AbilityScore = namedtuple("AbilityScore", ("value", "modifier", "saving_throw")) AbilityScore = namedtuple("AbilityScore", ("value", "modifier", "saving_throw"))
+2 -1
View File
@@ -25,7 +25,8 @@ setup(name='dungeonsheets',
'../VERSION'] '../VERSION']
}, },
install_requires=[ install_requires=[
'fdfgen', 'npyscreen', 'jinja2', 'pdfrw', 'sphinx', 'EbookLib', 'fdfgen', 'npyscreen', 'jinja2', 'pdfrw', 'sphinx',
'EbookLib',
], ],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [
+4 -4
View File
@@ -55,10 +55,10 @@ class MakeSheetsTestCase(unittest.TestCase):
class EpubOutputTestCase(unittest.TestCase): class EpubOutputTestCase(unittest.TestCase):
gm_epub = Path(f"{GMFILE.stem}.epub").resolve() gm_epub = Path(f"{GMFILE.stem}.epub").resolve()
def tearDown(self): # def tearDown(self):
for f in [self.gm_epub]: # for f in [self.gm_epub]:
if f.exists(): # if f.exists():
f.unlink() # f.unlink()
def test_file_created(self): def test_file_created(self):
# Check that a file is created once the function is run # Check that a file is created once the function is run