Themes » Pelican

Pel­ic­an is a stat­ic site gen­er­at­or powered by Py­thon and un­like most oth­er stat­ic site gen­er­at­ors, it uses re­Struc­tured­Text in­stead of Mark­down for au­thor­ing con­tent. m.css provides a theme for it, to­geth­er with a set of use­ful plu­gins. The theme is de­signed to fit both the use case of a simple blog con­sist­ing of just art­icles or a full product/pro­ject/port­fo­lio web­site where the blog is only a side dish.

First steps with Pel­ic­an

In­stall Pel­ic­an either via pip or us­ing your sys­tem pack­age man­ager.

# You may need sudo here
pip3 install pelican

Note that us­ing the m.css theme or Pel­ic­an plu­gins may re­quire ad­di­tion­al de­pend­en­cies than just Pel­ic­an — doc­u­ment­a­tion of each lists the ad­di­tion­al re­quire­ments, if any. Once you have Pel­ic­an in­stalled, cre­ate a dir­ect­ory for your web­site and boot­strap it:

mkdir ~/my-cool-site/
cd ~/my-cool-site/
pelican-quickstart

This com­mand will ask you a few ques­tions. Leave most of the ques­tions at their de­faults, you can change them later. Once the quick­start script fin­ishes, you can gen­er­ate the web­site and spin up a auto-re­load web­serv­er for it with the fol­low­ing com­mand:

pelican -Dlr

It will print quite some out­put about pro­cessing things and serving the data to the con­sole. Open your fresh web­site at http://localhost:8000. The site is now empty, so let’s cre­ate a simple art­icle and put it in­to content/ sub­dir­ect­ory with a .rst ex­ten­sion. For this ex­ample that would be ~/my-cool-site/content/my-cool-article.rst:

My cool article
###############

:date: 2017-09-14 23:04
:category: Cool things
:tags: cool, article, mine
:summary: This article has a cool summary.

This article has not only cool summary, but also has cool contents. Lorem?
*Ipsum.* `Hi, google! <https://google.com>`_

If you did everything right, the auto-re­load script should pick the file up and pro­cess it (check the con­sole out­put). Then it’s just a mat­ter of re­fresh­ing your browser to see it on the page.

That’s it! Con­grat­u­la­tions, you suc­cess­fully made your first steps with Pel­ic­an. Well, apart from the fact that the de­fault theme is a bit un­der­whelm­ing — so let’s fix that.

Ba­sic theme setup

The easi­est way to start is put­ting the whole Git re­pos­it­ory of m.css in­to your pro­ject, for ex­ample as a sub­mod­ule:

git submodule add https://github.com/mosra/m.css

The most min­im­al con­fig­ur­a­tion to use the theme is the fol­low­ing. Ba­sic­ally you need to tell Pel­ic­an where the theme resides (it’s in the pelican-theme/ sub­dir of your m.css sub­mod­ule), then you tell it to put the stat­ic con­tents of the theme in­to a static/ dir­ect­ory in the root of your web­serv­er; the M_CSS_FILES vari­able is a list of CSS files that the theme needs. You can put there any files you need, but there need to be at least the files men­tioned on the CSS themes page. The M_THEME_COLOR spe­cifies col­or used for the <meta name="theme-color" /> tag cor­res­pond­ing to giv­en theme; if not set, it’s simply not present. Lastly, the theme uses some Jin­ja2 fil­ters from the m.htmls­an­ity plu­gin, so that plu­gin needs to be loaded as well.

THEME = 'm.css/pelican-theme'
THEME_STATIC_DIR = 'static'
DIRECT_TEMPLATES = ['index']

M_CSS_FILES = ['https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600',
               '/static/m-dark.css']
M_THEME_COLOR = '#22272e'

PLUGIN_PATHS = ['m.css/plugins']
PLUGINS = ['m.htmlsanity']

Here you can take ad­vant­age of the pelicanconf.py and publishconf.py dis­tinc­tion — use m-dark.css for loc­al de­vel­op­ment and over­ride the M_CSS_FILES to use the smal­ler, faster and more com­pat­ible m-dark.compiled.css for pub­lish­ing.

If you would want to use the light theme in­stead, the con­fig­ur­a­tion is this (again with m-light.css pos­sibly re­placed with m-light.compiled.css):

M_CSS_FILES = ['https://fonts.googleapis.com/css?family=Libre+Baskerville:400,400i,700,700i%7CSource+Code+Pro:400,400i,600',
               '/static/m-light.css']
M_THEME_COLOR = '#cb4b16'

If you see some­thing un­ex­pec­ted or not see some­thing ex­pec­ted, check the Troubleshoot­ing sec­tion be­low.

Con­fig­ur­a­tion

Value of SITENAME is used in the <title> tag, sep­ar­ated with a | char­ac­ter from page title. If page title is the same as SITENAME (for ex­ample on the in­dex page), only the page title is shown. The stat­ic part of the web­site with pages is treated dif­fer­ently from the “blog” part with art­icles and there are two ad­di­tion­al con­fig­ur­a­tion op­tions M_BLOG_URL and M_BLOG_NAME that con­trol how vari­ous parts of the theme link to the blog and how blog pages are named in the <title> ele­ment. The M_BLOG_URL can be either ab­so­lute or re­l­at­ive to SITEURL. If M_BLOG_NAME / M_BLOG_URL are not set, the theme as­sumes they are the same as SITENAME / SITEURL.

SITENAME = 'Your Brand'
SITEURL = ''

M_BLOG_NAME = 'Your Brand Blog'
M_BLOG_URL = 'blog/'

The M_FAVICON set­ting, if present, is used to spe­cify con­tents of the <link rel="icon"> tag. It’s a tuple of (url, type) where url is favicon URL and type is its cor­res­pond­ing MIME type. If M_BLOG_FAVICON is spe­cified, it’s over­rid­ing M_FAVICON on blog-like pages (art­icles, art­icle list­ing… ba­sic­ally everything ex­cept pages). If M_BLOG_FAVICON is not spe­cified, M_FAVICON is used every­where; if neither is spe­cified no <link> tag is rendered. Ex­ample con­fig­ur­a­tion:

M_FAVICON = ('favicon.ico', 'image/x-ico')
M_BLOG_FAVICON = ('favicon-blog.png', 'image/png')

Ar­bit­rary HTML con­tent can be ad­ded at the end of the <head> via the M_HTML_HEADER op­tion.

Top navbar

M_SITE_LOGO is an im­age file that will be used as a brand logo on left side of the navbar, M_SITE_LOGO_TEXT is brand logo text. Spe­cify­ing just one of these does the ex­pec­ted thing, if neither of them is spe­cified, the theme will use SITENAME in place of M_SITE_LOGO_TEXT. The brand logo/text is a link that leads to SITTEURL.

M_LINKS_NAVBAR1 and M_LINKS_NAVBAR2 vari­ables con­tain links to put in the top navbar. On nar­row screens, the navbar is di­vided in­to two columns, links from the first vari­able are in the left column while links from the second vari­able are in the right column. Omit the second vari­able if you want the links to be in a single column. Omit­ting both vari­ables will cause the ham­burger menu link on small screen sizes to not even be present.

Both vari­ables have the same format — a list of 4-tuples, where first item is link title, second the URL, third page slug of the cor­res­pond­ing page (used to high­light cur­rently act­ive menu item) and fourth is a list of sub-menu items (which are 3-tuples — link title, URL and page slug). Provid­ing an empty slug will make the menu item nev­er high­lighted; provid­ing an empty list of sub-menu items will not add any sub­menu. All blog-re­lated pages (art­icles, art­icle list­ing, au­thors, tags, cat­egor­ies etc.) have the slug set to a spe­cial value [blog]. The URL is pre­pen­ded with SITEURL un­less it con­tains also do­main name, then it’s left as-is (de­tailed be­ha­vi­or).

Ex­ample con­fig­ur­a­tion, match­ing ex­ample markup from the CSS page lay­out doc­u­ment­a­tion:

M_SITE_LOGO_TEXT = 'Your Brand'

M_LINKS_NAVBAR1 = [('Features', 'features/', 'features', []),
                   ('Showcase', 'showcase/', 'showcase', []),
                   ('Download', 'download/', 'download', [])]

M_LINKS_NAVBAR2 = [('Blog', 'blog/', '[blog]', [
                        ('News', 'blog/news/', ''),
                        ('Archive', 'blog/archive/', '')]),
                   ('Contact', 'contact/', 'contact', [])]

(So­cial) meta tags

The M_BLOG_DESCRIPTION set­ting, if avail­able, is used to pop­u­late <meta name="description"> on the in­dex / archive page, which can be then shown in search en­gine res­ults. For shar­ing pages on Twit­ter, Face­book and else­where, it’s pos­sible to con­fig­ure site-wide Open Graph and Twit­ter Card <meta> tags:

  • og:site_name is set to M_SOCIAL_SITE_NAME, if avail­able
  • twitter:site / twitter:site:id is set to M_SOCIAL_TWITTER_SITE / M_SOCIAL_TWITTER_SITE_ID`, if avail­able
  • Glob­al og:title / twitter:title is set to M_BLOG_NAME on in­dex and archive pages and to cat­egory/au­thor/tag name on par­tic­u­lar fil­ter­ing pages. This is over­rid­den by par­tic­u­lar pages and art­icles.
  • Glob­al og:url is set to M_BLOG_URL on in­dex and archive pages and to cat­egory/au­thor/tag URL on par­tic­u­lar fil­ter­ing pages. Pa­gin­a­tion is not in­cluded in the URL. This is over­rid­den by par­tic­u­lar pages and art­icles.
  • Glob­al og:image / twitter:image is set to the M_SOCIAL_IMAGE set­ting, if avail­able. The im­age is ex­pec­ted to be smal­ler and square; Pel­ic­an in­tern­al link­ing cap­ab­il­it­ies are not sup­por­ted in this set­ting. This can be over­rid­den by par­tic­u­lar pages and art­icles.
  • Glob­al twitter:card is set to summary. This is fur­ther af­fected by metadata of par­tic­u­lar pages and art­icles.
  • Glob­al og:description / twitter:description is set to M_SOCIAL_BLOG_SUMMARY on in­dex and archive pages.
  • Glob­al og:type is set to website. This is over­rid­den by par­tic­u­lar pages and art­icles.

See (So­cial) meta tags for pages and (So­cial) meta tags for art­icles sec­tions be­low for page- and art­icle-spe­cif­ic <meta> tags.

Ex­ample con­fig­ur­a­tion to give sane de­faults to all so­cial meta tags:

M_BLOG_NAME = "Your Brand Blog"
M_BLOG_URL = 'https://blog.your.brand/'
M_BLOG_DESCRIPTION = "Your Brand is the brand that provides all that\'s needed."

M_SOCIAL_TWITTER_SITE = '@your.brand'
M_SOCIAL_TWITTER_SITE_ID = 1234567890
M_SOCIAL_IMAGE = 'https://your.brand/static/site.png'
M_SOCIAL_BLOG_SUMMARY = "This is the brand you need"

It’s pos­sible to dis­able ren­der­ing of all so­cial meta tags (for ex­ample for test­ing pur­poses) by set­ting M_DISABLE_SOCIAL_META_TAGS to True.

Pages

Page con­tent is simply put in­to <main>, wrapped in an <article>, in the cen­ter 10 columns on large screens and span­ning the full 12 columns else­where; the con­tain­er is marked as in­flat­able. Page title is rendered in an <h1> and there’s noth­ing else apart from the page con­tent.

Pages can over­ride which menu item in the top navbar will be high­lighted by spe­cify­ing the cor­res­pond­ing menu item slug in the :highlight: field. If the field is not present, page’s own slug is used in­stead.

Ex­tend­ing HTML <head>

The :css: field can be used to link ad­di­tion­al CSS files in page head­er. Put one URL per line, in­tern­al link tar­gets are ex­pan­ded. Sim­il­arly :js: can be used to link JavaS­cript files. Be­sides that, the :html_header: field can be used to put ar­bit­rary HTML at the end of the <head> ele­ment. In­dent­ing the lines is pos­sible by put­ting an es­caped space in front (the back­slash and the es­caped space it­self won’t get in­ser­ted). Ex­ample:

Showcase
########

:css:
    {static}/static/webgl.css
    {static}/static/canvas-controls.css
:js:
    {static}/static/showcase.js
:html_header:
    <script>
    \   function handleDrop(event) {
    \     event.preventDefault();
    \     ...
    \   }
    </script>

Land­ing pages

It’s pos­sible to over­ride the de­fault 10-column be­ha­vi­or for pages to make a land­ing page with large cov­er im­age span­ning the whole win­dow width. Put cov­er im­age URL in­to a :cover: field, the :landing: field then con­tains reST-pro­cessed con­tent that ap­pears on top of the cov­er im­age. Con­tents of the :landing: are put in­to a <div class="m-container">, you are ex­pec­ted to fully take care of rows and columns in it. The :hide_navbar_brand: field con­trols vis­ib­il­ity of the navbar brand link. Set it to True to hide it, de­fault (if not present) is False.

Ex­ample of a fully cus­tom in­dex page that over­rides the de­fault theme in­dex page (which would just list all the art­icles) is be­low. Note the over­rid­den save des­tin­a­tion and URL.

Your Brand
##########

:save_as: index.html
:url:
:cover: {static}/static/cover.jpg
:hide_navbar_brand: True
:landing:
    .. container:: m-row

        .. container:: m-col-m-6 m-push-m-5

            .. raw:: html

                <h1>Your Brand</h1>

            *This is the brand you need.*

Pages with cov­er im­age

Be­sides full-blown land­ing pages that give you con­trol over the whole lay­out, you can add cov­er im­ages to reg­u­lar pages by just spe­cify­ing the :cover: field but omit­ting the :landing: field. See cor­res­pond­ing sec­tion in the CSS page lay­out docs for de­tails about how the cov­er im­age af­fects page lay­out.

News on in­dex page

If you over­ride the in­dex page to a cus­tom land­ing page, by de­fault you lose the list of latest art­icles. That might cause the web­site to ap­pear stale when you up­date just the blog. In or­der to fix that, it’s pos­sible to show a block with latest art­icles on the in­dex page us­ing the M_NEWS_ON_INDEX set­ting. It’s a tuple of (title, count) where title is the block head­er title that acts as a link to M_BLOG_URL and count is the max num­ber of art­icles shown. Ex­ample con­fig­ur­a­tion:

M_NEWS_ON_INDEX = ("Latest news on our blog", 3)

(So­cial) meta tags for pages

Every page has <link rel="canonical"> point­ing to its URL to avoid du­plic­ates in search en­gines when us­ing GET para­met­ers. In ad­di­tion to the glob­al meta tags de­scribed in (So­cial) meta tags above, you can use the :description: field to pop­u­late <meta name="description">. Oth­er than that, the field does not ap­pear any­where on the rendered page. If such field is not set, the de­scrip­tion <meta> tag is not rendered at all. It’s re­com­men­ded to add it to FORMATTED_FIELDS so you can make use of the ad­vanced ty­po­graphy fea­tures like smart quotes etc. in it:

FORMATTED_FIELDS += ['description']

The glob­al Open Graph and Twit­ter Card <meta> tags are spe­cial­ized for pages like this:

  • Page title is mapped to og:title / twitter:title
  • Page URL is mapped to og:url
  • The :summary: field is mapped to og:description / twitter:description. Note that if the page doesn’t have ex­pli­cit sum­mary, Pel­ic­an takes it from the first few sen­tences of the con­tent and that may not be what you want. This is also dif­fer­ent from the :description: field men­tioned above and, un­like with art­icles, :summary: doesn’t ap­pear any­where on the rendered page.
  • The :cover: field (e.g. the one used on land­ing pages), if present, is mapped to og:image / twitter:image, over­rid­ing the glob­al M_SOCIAL_IMAGE set­ting. The ex­act same file is used without any res­iz­ing or crop­ping and is as­sumed to be in land­scape.
  • twitter:card is set to summary_large_image if :cover: is present and to summary oth­er­wise
  • og:type is set to page

Ex­ample over­rid­ing the in­dex page with es­sen­tial prop­er­ties for nice-look­ing so­cial links:

Your Brand
##########

:save_as: index.html
:url:
:cover: {static}/static/cover.jpg
:summary: This is the brand you need.

Art­icles

Com­pared to pages, art­icles have ad­di­tion­al metadata like :date:, :author:, :category: and tags that or­der them and di­vide them in­to vari­ous sec­tions. Be­sides that, there’s art­icle :summary:, that, un­like with pages, is dis­played in the art­icle head­er; oth­er metadata are dis­played in art­icle foot­er. The art­icle can also op­tion­ally have a :modified: date, which is shown as date of last up­date in the foot­er.

All art­icle list­ing pages (archives, cat­egor­ies, tags, au­thors) are dis­play­ing just the art­icle sum­mary and the full art­icle con­tent is avail­able only on the ded­ic­ated art­icle page. An ex­cep­tion to this is the main in­dex or archive page, where the first art­icle is fully ex­pan­ded so the users are greeted with some ac­tu­al con­tent in­stead of just a bor­ing list of art­icle sum­mar­ies.

Art­icle pages show a list of sec­tions and tags in a right side­bar. By de­fault, list of au­thors is not dis­played as there is usu­ally just one au­thor. If you want to dis­play the au­thors as well, en­able it us­ing the M_SHOW_AUTHOR_LIST op­tion in the con­fig­ur­a­tion:

M_SHOW_AUTHOR_LIST = True

Jumbo art­icles

Jumbo art­icles are made by in­clud­ing the :cover: field con­tain­ing URL of the cov­er im­age. Be­sides that, if the title con­tains an em-dash (—), it gets split in­to a title and sub­title that’s then rendered in a dif­fer­ent font size. Ex­ample:

An article --- a jumbo one
##########################

:cover: {static}/static/ship.jpg
:summary: Article summary paragraph.

Article contents.

Side­bar with tag, cat­egory and au­thor list shown in the clas­sic art­icle lay­out on the right is moved to the bot­tom for jumbo art­icles. In case you need to in­vert text col­or on cov­er, add a :class: field con­tain­ing the m-inverted CSS class.

Archived art­icles

It’s pos­sible to mark art­icles and archived by set­ting the :archived: field to True. In ad­di­tion to that, you can dis­play an ar­bit­rary format­ted block on the art­icle page on top of art­icle con­tents right be­low the sum­mary. The con­tent of the block is con­trolled by the M_ARCHIVED_ARTICLE_BADGE set­ting, con­tain­inig reST-format­ted markup. The {year} place­hold­er, if present, is re­placed with the art­icle year. If the set­ting is not present, no block is rendered at all. Ex­ample set­ting:

M_ARCHIVED_ARTICLE_BADGE = """
.. container:: m-note m-warning

    This article is from {year}. **It's old.** Deal with it.
"""

(So­cial) meta tags for art­icles

Every art­icle has <link rel="canonical"> point­ing to its URL to avoid du­plic­ates in search en­gines when us­ing GET para­met­ers. In ad­di­tion to the glob­al meta tags de­scribed in (So­cial) meta tags above, you can use the :description: field to pop­u­late <meta name="description">. Oth­er than that, the field doesn’t ap­pear any­where in the rendered art­icle. If such field is not set, the de­scrip­tion <meta> tag is not rendered at all. Again, it’s re­com­men­ded to add it to FORMATTED_FIELDS.

The glob­al Open Graph and Twit­ter Card <meta> tags are spe­cial­ized for art­icles like this:

  • Art­icle title is mapped to og:title / twitter:title
  • Art­icle URL is mapped to og:url
  • The :summary: field is mapped to og:description / twitter:description. Note that if the art­icle doesn’t have ex­pli­cit sum­mary, Pel­ic­an takes it from the first few sen­tences of the con­tent and that may not be what you want. This is also dif­fer­ent from the :description: field men­tioned above.
  • The :cover: field from jumbo art­icles, if present, is mapped to og:image / twitter:image, over­rid­ing the glob­al M_SOCIAL_IMAGE set­ting. The ex­act same file is used without any res­iz­ing or crop­ping and is as­sumed to be in land­scape. See (So­cial) meta tags for pages above for im­age size re­com­mend­a­tions.
  • twitter:card is set to summary_large_image if :cover: is present and to summary oth­er­wise
  • og:type is set to article

Con­trolling art­icle ap­pear­ance

By de­fault, the theme as­sumes that you provide an ex­pli­cit :summary: field for each art­icle. The sum­mary is then dis­played on art­icle list­ing page and also pre­pen­ded to fully ex­pan­ded art­icle. If your :summary: is auto­mat­ic­ally gen­er­ated by Pel­ic­an or for any oth­er reas­on re­peats art­icle con­tent, it might not be de­sir­able to show it in com­bin­a­tion with art­icle con­tent. This can be con­figured via the fol­low­ing set­ting:

M_HIDE_ARTICLE_SUMMARY = True

There’s also a pos­sib­il­ity to con­trol this on a per-art­icle basis by set­ting :hide_summary: to either True or False. If both glob­al and per-art­icle set­ting is present, art­icle-spe­cif­ic set­ting has a pre­ced­ence. Ex­ample:

An article without explicit summary
###################################

:cover: {static}/static/ship.jpg
:hide_summary: True

Implicit article summary paragraph.

Article contents.

As noted above, the first art­icle is by de­fault fully ex­pan­ded on in­dex and archive page. How­ever, some­times the art­icle is maybe too long to be ex­pan­ded or you might want to not ex­pand any art­icle at all. This can be con­trolled either glob­ally us­ing the fol­low­ing set­ting:

M_COLLAPSE_FIRST_ARTICLE = True

Or, again, on a per-art­icle basis, by set­ting :collapse_first: to either True or False. If both glob­al and per-art­icle set­ting is present, art­icle-spe­cif­ic set­ting has a pre­ced­ence.

Pre-defined pages

With the de­fault con­fig­ur­a­tion above the in­dex page is just a list of art­icles with the first be­ing ex­pan­ded; the archives page is ba­sic­ally the same. If you want to have a cus­tom in­dex page (for ex­ample a land­ing page), re­move 'index' from the DIRECT_TEMPLATES set­ting and keep just 'archives' for the blog front page. Also you may want to en­able pa­gin­a­tion for the archives, as that’s not en­abled by de­fault:

# Defaults to ['index', 'categories', 'authors', 'archives']
DIRECT_TEMPLATES = ['archives']

# Defaults to {'index': None, 'tag': None, 'category': None, 'author': None}
PAGINATED_TEMPLATES = {'archives': None, 'tag': None, 'category': None, 'author': None}

Every cat­egory, tag and au­thor has its own page that lists cor­res­pond­ing art­icles in a way sim­il­ar to the in­dex or archives page, but without the first art­icle ex­pan­ded. On the top of the page there is a note stat­ing what con­di­tion the art­icles are filtered with.

In­dex, archive and all cat­egory/tag/au­thor pages are pa­gin­ated based on the DEFAULT_PAGINATION set­ting — on the bot­tom of each page there are link to prev and next page, be­sides that there’s <link rel="prev"> and <link rel="next"> that provides the same as a hint to search en­gines.

Pass-through pages

Be­sides pages, art­icles and pre-defined pages ex­plained above, where the con­tent is al­ways wrapped with the navbar on top and the foot­er bot­tom, it’s pos­sible to have pages with fully cus­tom markup — for ex­ample vari­ous present­a­tion slides, demos etc. To do that, set the :template: metadata to passthrough. While it works with reST sources, this is best com­bined with raw HTML in­put. Pel­ic­an will copy the con­tents of the <body> tag ver­batim and use con­tents of the <title> ele­ment for a page title, put again in the <title> (not as a <h1> in­side <body>). Be­sides that, you can spe­cify ad­di­tion­al metadata us­ing the <meta name="key" content="value" /> tags:

  • <meta name="template" content="passthrough" /> needs to be al­ways present in or­der to make Pel­ic­an use the passthrough tem­plate.
  • <meta name="css" />, <meta name="js" /> and <meta name="html_header" /> spe­cify ad­di­tion­al CSS files, JavaS­cript files and ar­bit­rary HTML, sim­il­arly as with nor­mal pages. The content can be mul­tiple lines, empty lines are dis­carded for CSS and JS ref­er­ences. Be sure to prop­erly es­cape everything.
  • <meta name="class" /> can be used to add a CSS class to the top-level <html> ele­ment
  • All usu­al Pel­ic­an metadata like url, slug etc. work here as well.

Note that at the mo­ment, the pass-through pages do not in­sert any of the (so­cial) meta tags. Ex­ample of an in­put file for a pass-through page:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>WebGL Demo Page</title>
  <meta name="template" content="passthrough" />
  <meta name="css" content="
    m-dark.css
    https://fonts.googleapis.com/css?family=Source+Code+Pro:400,400i,600%7CSource+Sans+Pro:400,400i,600,600i
    " />
  <meta name="js" content="webgl-demo.js" />
</head>
<body>
<!-- the actual page body -->
</body>
</html>

Theme prop­er­ties

The theme markup is de­signed to have read­able, nicely in­den­ted out­put. The code is val­id HTM­L5 and should be pars­able as XML.

Troubleshoot­ing

Out­put is miss­ing styl­ing

If you are on Win­dows and don’t have Git sym­links en­abled, empty CSS files might get copied. The solu­tion is either to re­in­stall Git with sym­links en­abled or manu­ally copy all *.css files from css/ to pelican-theme/static/, re­pla­cing the broken sym­links present there.