Theming for MfGames Writing

One of the big parts about MfGames Writing is the ability to customize the appearance of the generated files. If we didn't have that, then every book would look the same and I don't care for that. Books should allow for different themes, chapter numbers, and even spacing. To that regard, everything is funneled through a theme for formatting.

Series

I appear to be writing a short series of post about the tools I use for publication and writing.

  1. Semantic Versions and Releases: Why semantic versioning helps with the writing process.
  2. Evolution of MfGames Writing: A brief history and reasoning behind the tools.
  3. First Steps Using MfGames Writing: Starting a new project with MfGames Writing.
  4. Adding Content to MfGames Writing: Adding front and back matter to novels.
  5. Working with MfGames Writing, CI, and Docker: Adding automatic building with commits.
  6. Additional Formats for MfGames Writing: How to create PDF, MOBI, DOCX, and HTML versions.
  7. Theming for MfGames Writing: A light introduction on how to customize the output.
  8. Integrating Semantic Versioning into MfGames Writing: Tying semantic releases into the process.

HTML

The entire theme system is built on HTML and CSS. In previous versions of this, I generated XeLaTeX files for PDF and used a custom conversion utility for Word documents. It also increased the complexity significantly. Switching to a HTML-based system simplified the theme creation and made debugging easier.

This is one case where looking at a reference implementation will be helpful.

Components

In the content post, there are quite a few references to element on each of the content items. These elements are Liquid-based stylesheets that are provided by the theme.

For example, the title.xhtml in the clean theme looks like this:

<div class="element-page-break element-page-break-title">&#160;</div>
{{html}}

The {{html}} is where the contents in the source given on the content will be placed. In this case, the element-page-break is how I handle page rendering with WeasyPrint.

A more complicated example would be chapter.xhtml:

<div class="element-wrapper {{content.element}}">
    <div class="element-page-break element-page-break-right">&#160;</div>
    <div class="element-page-pad-right">
        {% if content.number %}
        <div class="element-number">Chapter {{content.number}}</div>
        {% endif %}
        <h1 class="element-title">{{content.title}}</h1>
        {{html}}
    </div>
</div>

You can see more uses of the Liquid tags. In this case, if we have a number property in the content, it will insert the Chapter # above the title of the chapter (from the YAML header) and the contents of the body into {{html}}.

Recursive Templates

To reduce copy/paste, there are also recursive templates. For example, the colophon template looks like this:

---
extends: simple-title
---
{{html}}

Once this page is rendered, the results are formatted by the simple-title

<div class="element-wrapper {{content.element}}">
<div class="element-page-break element-page-break-right">&#160;</div>
<h1 class="initial">{{content.title}}</h1>
{{html}}
</div>

It is recursive, so you can have one template extending another extending another.

Styling

You'll notice that there is very little styling in the HTML. Instead, most of it is done with a SASS template in the theme. The base style is called stylesheet.scss:

p {
    margin-bottom: 0;
    margin-top: 0;
    text-align: left;
    text-indent: 2em;
}

Stylesheets can be overridden by specific formats. The most common is having a WeasyPrint-specific stylesheet:

@import "stylesheet";

@page {
    @bottom-center {
        content: counter(page);
        vertical-align: top;
        padding-top: 1em;
    }
    size: letter portrait;
    margin: 3cm 2cm;
}

To figure out overrides, the system looks for the format name first (html.scss or weasyprint.scss) and if it doesn't find one, goes to the base (stylesheet.scss).

Stylesheet Variables

Because I'm fond of single points of truth, SASS also lets us have variables so we can pull the version, or information from the edition data.

@page :right {
    @top-right {
        content: themeString("edition.title");
        vertical-align: bottom;
        padding-bottom: 1em;
    }
    padding-left: 1cm;
}

The themeString works just like the Liquid templates.

Creating New Themes

To create a new theme, I basically just copy all of the clean theme and start customizing.

Metadata

Categories:

Tags: