mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-07 21:23:31 +02:00
Added a CSS file to the epub output format.
This commit is contained in:
+23
-3
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 -->
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>My title</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|||||||
@@ -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__()
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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"))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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': [
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user