Pelican » Theme

The sec­ond largest of­fer­ing of m.css is a full-fea­tured theme for the Pel­i­can stat­ic site gen­er­a­tor. The theme is de­signed to fit both the use case of a sim­ple blog con­sist­ing of just ar­ti­cles or a full prod­uct/project/port­fo­lio web­site where the blog is on­ly a side dish.

Quick start

Fol­low­ing the Pel­i­can quick start guide, it’s as­sumed you al­ready have at least Python 3.4 and the Python 3 ver­sion of Pel­i­can in­stalled. The eas­i­est way to start is putting the whole Git re­pos­i­to­ry of m.css in­to your project, for ex­am­ple as a sub­mod­ule:

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

The most min­i­mal con­fig­u­ra­tion to use the theme is the fol­low­ing. Ba­si­cal­ly you need to tell Pel­i­can where the theme re­sides (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/ di­rec­to­ry 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 spec­i­fies col­or used for the <meta name="theme-color" /> tag cor­re­spond­ing to giv­en theme; if not set, it’s sim­ply not present. Last­ly, the theme us­es some Jin­ja2 fil­ters from the m.html­san­i­ty plug­in, so that plug­in needs to be load­ed 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/pelican-plugins']
PLUGINS = ['m.htmlsanity']

Here you can take ad­van­tage of the pelicanconf.py and publishconf.py dis­tinc­tion — use m-dark.css for lo­cal de­vel­op­ment and over­ride the M_CSS_FILES to use the small­er, faster and more com­pat­i­ble m-dark.compiled.css for pub­lish­ing.

If you would want to use the light theme in­stead, the con­fig­u­ra­tion is this (again with m-light.css pos­si­bly 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­pect­ed or not see some­thing ex­pect­ed, check the Trou­bleshoot­ing sec­tion be­low.

Con­fig­u­ra­tion

Val­ue of SITENAME is used in the <title> tag, sep­a­rat­ed with a | char­ac­ter from page ti­tle. If page ti­tle is the same as SITENAME (for ex­am­ple on the in­dex page), on­ly the page ti­tle is shown. The stat­ic part of the web­site with pages is treat­ed dif­fer­ent­ly from the “blog” part with ar­ti­cles and there are two ad­di­tion­al con­fig­u­ra­tion op­tions M_BLOG_URL and M_BLOG_NAME that con­trol how var­i­ous parts of the theme link to the blog and how blog pages are named in the <title> el­e­ment. The M_BLOG_URL can be ei­ther ab­so­lute or rel­a­tive 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 spec­i­fy con­tents of the <link rel="icon"> tag. It’s a tu­ple of (url, type) where url is fav­i­con URL and type is its cor­re­spond­ing MIME type. If M_BLOG_FAVICON is spec­i­fied, it’s over­rid­ing M_FAVICON on blog-like pages (ar­ti­cles, ar­ti­cle list­ing… ba­si­cal­ly ev­ery­thing ex­cept pages). If M_BLOG_FAVICON is not spec­i­fied, M_FAVICON is used ev­ery­where; if nei­ther is spec­i­fied no <link> tag is ren­dered. Ex­am­ple con­fig­u­ra­tion:

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

Top navbar

M_SITE_LOGO is an im­age file that will be used as a brand lo­go on left side of the navbar, M_SITE_LOGO_TEXT is brand lo­go text. Spec­i­fy­ing just one of these does the ex­pect­ed thing, if nei­ther of them is spec­i­fied, the theme will use SITENAME in place of M_SITE_LOGO_TEXT. The brand lo­go/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­vid­ed in­to two col­umns, links from the first vari­able are in the left col­umn while links from the sec­ond vari­able are in the right col­umn. Omit the sec­ond vari­able if you want the links to be in a sin­gle col­umn. Omit­ting both vari­ables will cause the ham­burg­er menu link on small screen sizes to not even be present.

Both vari­ables have the same for­mat — a list of 4-tu­ples, where first item is link ti­tle, sec­ond the URL, third page slug of the cor­re­spond­ing page (used to high­light cur­rent­ly ac­tive menu item) and fourth is a list of sub-menu items (which are 3-tu­ples — link ti­tle, URL and page slug). Pro­vid­ing an emp­ty slug will make the menu item nev­er high­light­ed; pro­vid­ing an emp­ty list of sub-menu items will not add any sub­menu. All blog-re­lat­ed pages (ar­ti­cles, ar­ti­cle list­ing, au­thors, tags, cat­e­gories etc.) have the slug set to a spe­cial val­ue [blog]. The URL is prepend­ed with SITEURL un­less it con­tains al­so do­main name, then it’s left as-is (de­tailed be­hav­ior).

Ex­am­ple con­fig­u­ra­tion, match­ing ex­am­ple markup from the CSS page lay­out doc­u­men­ta­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 / ar­chive page, which can be then shown in search en­gine re­sults. For shar­ing pages on Twit­ter, Face­book and else­where, it’s pos­si­ble 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 ar­chive pages and to cat­e­go­ry/au­thor/tag name on par­tic­u­lar fil­ter­ing pages. This is over­ri­den by par­tic­u­lar pages and ar­ti­cles.
  • Glob­al og:url is set to M_BLOG_URL on in­dex and ar­chive pages and to cat­e­go­ry/au­thor/tag URL on par­tic­u­lar fil­ter­ing pages. Pag­i­na­tion is not in­clud­ed in the URL. This is over­ri­den by par­tic­u­lar pages and ar­ti­cles.
  • Glob­al og:image / twitter:image is set to the M_SOCIAL_IMAGE set­ting, if avail­able. The im­age is ex­pect­ed to be small­er and square; Pel­i­can in­ter­nal link­ing ca­pa­bil­i­ties are not sup­port­ed in this set­ting. This can be over­ri­den by par­tic­u­lar pages and ar­ti­cles.
  • Glob­al twitter:card is set to summary. This is fur­ther af­fect­ed by meta­da­ta of par­tic­u­lar pages and ar­ti­cles.
  • Glob­al og:description / twitter:description is set to M_SOCIAL_BLOG_SUMMARY on in­dex and ar­chive pages.
  • Glob­al og:type is set to website. This is over­ri­den by par­tic­u­lar pages and ar­ti­cles.

See (So­cial) meta tags for pages and (So­cial) meta tags for ar­ti­cles sec­tions be­low for page- and ar­ti­cle-spe­cif­ic <meta> tags.

Ex­am­ple con­fig­u­ra­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­si­ble to dis­able ren­der­ing of all so­cial meta tags (for ex­am­ple for test­ing pur­pos­es) by set­ting M_DISABLE_SOCIAL_META_TAGS to True.

Pages

Page con­tent is sim­ply put in­to <main>, wrapped in an <article>, in the cen­ter 10 col­umns on large screens and span­ning the full 12 col­umns else­where; the con­tain­er is marked as in­flat­able. Page ti­tle is ren­dered 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­light­ed by spec­i­fy­ing the cor­re­spond­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­ter­nal link tar­gets are ex­pand­ed. Sim­i­lar­ly :js: can be used to link JavaScript files. Be­sides that, the :html_header: field can be used to put ar­bi­trary HTML at the end of the <head> el­e­ment. In­dent­ing the lines is pos­si­ble by putting an es­caped space in front (the back­slash and the es­caped space it­self won’t get in­sert­ed). Ex­am­ple:

Showcase
########

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

Land­ing pages

It’s pos­si­ble to over­ride the de­fault 10-col­umn be­hav­ior 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­pect­ed to ful­ly take care of rows and col­umns in it. The :hide_navbar_brand: field con­trols vis­i­bil­i­ty of the navbar brand link. Set it to True to hide it, de­fault (if not present) is False.

Ex­am­ple of a ful­ly cus­tom in­dex page that over­rides the de­fault theme in­dex page (which would just list all the ar­ti­cles) is be­low. Note the over­ri­den save des­ti­na­tion and URL.

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

:save_as: index.html
:url:
:cover: {filename}/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 spec­i­fy­ing the :cover: field but omit­ting the :landing: field. See cor­re­spond­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 lat­est ar­ti­cles. 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­si­ble to show a block with lat­est ar­ti­cles on the in­dex page us­ing the M_NEWS_ON_INDEX set­ting. It’s a tu­ple of (title, count) where title is the block head­er ti­tle that acts as a link to M_BLOG_URL and count is the max num­ber of ar­ti­cles shown. Ex­am­ple con­fig­u­ra­tion:

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

(So­cial) meta tags for pages

Ev­ery page has <link rel="canonical"> point­ing to its URL to avoid du­pli­cates in search en­gines when us­ing GET pa­ram­e­ters. 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 ren­dered page. If such field is not set, the de­scrip­tion <meta> tag is not ren­dered at all. It’s rec­om­mend­ed to add it to FORMATTED_FIELDS so you can make use of the ad­vanced ty­pog­ra­phy 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 ti­tle 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­plic­it sum­ma­ry, Pel­i­can takes it from the first few sen­tences of the con­tent and that may not be what you want. This is al­so dif­fer­ent from the :description: field men­tioned above and, un­like with ar­ti­cles, :summary: doesn’t ap­pear any­where on the ren­dered 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 with­out any re­siz­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­am­ple 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: {filename}/static/cover.jpg
:summary: This is the brand you need.

Ar­ti­cles

Com­pared to pages, ar­ti­cles have ad­di­tion­al meta­da­ta like :date:, :author:, :category: and tags that or­der them and di­vide them in­to var­i­ous sec­tions. Be­sides that, there’s ar­ti­cle :summary:, that, un­like with pages, is dis­played in the ar­ti­cle head­er; oth­er meta­da­ta are dis­played in ar­ti­cle foot­er. The ar­ti­cle can al­so op­tion­al­ly have a :modified: date, which is shown as date of last up­date in the foot­er.

All ar­ti­cle list­ing pages (ar­chives, cat­e­gories, tags, au­thors) are dis­play­ing just the ar­ti­cle sum­ma­ry and the full ar­ti­cle con­tent is avail­able on­ly on the ded­i­cat­ed ar­ti­cle page. An ex­cep­tion to this is the main in­dex or ar­chive page, where the first ar­ti­cle is ful­ly ex­pand­ed so the users are greet­ed with some ac­tu­al con­tent in­stead of just a bor­ing list of ar­ti­cle sum­maries.

Ar­ti­cle 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­al­ly 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­u­ra­tion:

M_SHOW_AUTHOR_LIST = True

Jum­bo ar­ti­cles

Jum­bo ar­ti­cles are made by in­clud­ing the :cover: field con­tain­ing URL of the cov­er im­age. Be­sides that, if the ti­tle con­tains an em-dash (—), it gets split in­to a ti­tle and sub­ti­tle that’s then ren­dered in a dif­fer­ent font size. Ex­am­ple:

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

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

Article contents.

Side­bar with tag, cat­e­go­ry and au­thor list shown in the clas­sic ar­ti­cle lay­out on the right is moved to the bot­tom for jum­bo ar­ti­cles. 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 ar­ti­cles

It’s pos­si­ble to mark ar­ti­cles and archived by set­ting the :archived: field to True. In ad­di­tion to that, you can dis­play an ar­bi­trary for­mat­ted block on the ar­ti­cle page on top of ar­ti­cle con­tents right be­low the sum­ma­ry. The con­tent of the block is con­trolled by the M_ARCHIVED_ARTICLE_BADGE set­ting, con­tain­inig reST-for­mat­ted markup. The {year} place­hold­er, if present, is re­placed with the ar­ti­cle year. If the set­ting is not present, no block is ren­dered at all. Ex­am­ple 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 ar­ti­cles

Ev­ery ar­ti­cle has <link rel="canonical"> point­ing to its URL to avoid du­pli­cates in search en­gines when us­ing GET pa­ram­e­ters. 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 ren­dered ar­ti­cle. If such field is not set, the de­scrip­tion <meta> tag is not ren­dered at all. Again, it’s rec­om­mend­ed to add it to FORMATTED_FIELDS.

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

  • Ar­ti­cle ti­tle is mapped to og:title / twitter:title
  • Ar­ti­cle URL is mapped to og:url
  • The :summary: field is mapped to og:description / twitter:description. Note that if the ar­ti­cle doesn’t have ex­plic­it sum­ma­ry, Pel­i­can takes it from the first few sen­tences of the con­tent and that may not be what you want. This is al­so dif­fer­ent from the :description: field men­tioned above.
  • The :cover: field from jum­bo ar­ti­cles, 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 with­out any re­siz­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 rec­om­men­da­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­trol­ling ar­ti­cle ap­pear­an­ce

By de­fault, the theme as­sumes that you pro­vide an ex­plic­it :summary: field for each ar­ti­cle. The sum­ma­ry is then dis­played on ar­ti­cle list­ing page and al­so prepend­ed to ful­ly ex­pand­ed ar­ti­cle. If your :summary: is au­to­mat­i­cal­ly gen­er­at­ed by Pel­i­can or for any oth­er rea­son re­peats ar­ti­cle con­tent, it might not be de­sir­able to show it in com­bi­na­tion with ar­ti­cle con­tent. This can be con­fig­ured via the fol­low­ing set­ting:

M_HIDE_ARTICLE_SUMMARY = True

There’s al­so a pos­si­bil­i­ty to con­trol this on a per-ar­ti­cle ba­sis by set­ting :hide_summary: to ei­ther True or False. If both glob­al and per-ar­ti­cle set­ting is present, ar­ti­cle-spe­cif­ic set­ting has a prece­dence. Ex­am­ple:

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

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

Implicit article summary paragraph.

Article contents.

As not­ed above, the first ar­ti­cle is by de­fault ful­ly ex­pand­ed on in­dex and ar­chive page. How­ev­er, some­times the ar­ti­cle is maybe too long to be ex­pand­ed or you might want to not ex­pand any ar­ti­cle at all. This can be con­trolled ei­ther glob­al­ly us­ing the fol­low­ing set­ting:

M_COLLAPSE_FIRST_ARTICLE = True

Or, again, on a per-ar­ti­cle ba­sis, by set­ting :collapse_first: to ei­ther True or False. If both glob­al and per-ar­ti­cle set­ting is present, ar­ti­cle-spe­cif­ic set­ting has a prece­dence.

Pre-de­fined pages

With the de­fault con­fig­u­ra­tion above the in­dex page is just a list of ar­ti­cles with the first be­ing ex­pand­ed; the ar­chives page is ba­si­cal­ly the same. If you want to have a cus­tom in­dex page (for ex­am­ple a land­ing page), re­move 'index' from the DIRECT_TEMPLATES set­ting and keep just 'archives' for the blog front page. Al­so you may want to en­able pag­i­na­tion for the ar­chives, as that’s not en­abled by de­fault:

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

# Defaults to ['index']
PAGINATED_DIRECT_TEMPLATES = ['archives']

Ev­ery cat­e­go­ry, tag and au­thor has its own page that lists cor­re­spond­ing ar­ti­cles in a way sim­i­lar to the in­dex or ar­chives page, but with­out the first ar­ti­cle ex­pand­ed. On the top of the page there is a note stat­ing what con­di­tion the ar­ti­cles are fil­tered with.

In­dex, ar­chive and all cat­e­go­ry/tag/au­thor pages are pag­i­nat­ed 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 pro­vides the same as a hint to search en­gines.

Pass-through pages

Be­sides pages, ar­ti­cles and pre-de­fined 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­si­ble to have pages with ful­ly cus­tom markup — for ex­am­ple var­i­ous pre­sen­ta­tion slides, demos etc. To do that, set the :template: meta­da­ta to passthrough. While it works with reST sources, this is best com­bined with raw HTML in­put. Pel­i­can will copy the con­tents of the <body> tag ver­ba­tim and use con­tents of the <title> el­e­ment for a page ti­tle, put again in the <title> (not as a <h1> in­side <body>). Be­sides that, you can spec­i­fy ad­di­tion­al meta­da­ta 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­i­can use the passthrough tem­plate.
  • <meta name="css" />, <meta name="js" /> and <meta name="html_header" /> spec­i­fy ad­di­tion­al CSS files, JavaScript files and ar­bi­trary HTML, sim­i­lar­ly as with nor­mal pages. The content can be mul­ti­ple lines, emp­ty lines are dis­card­ed for CSS and JS ref­er­ences. Be sure to prop­er­ly es­cape ev­ery­thing.
  • <meta name="class" /> can be used to add a CSS class to the top-lev­el <html> el­e­ment
  • All usu­al Pel­i­can meta­da­ta 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­am­ple 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, nice­ly in­dent­ed out­put. The code is valid HTM­L5 and should be parsable as XML.

Trou­bleshoot­ing

Out­put is miss­ing styling

If you are on Win­dows and don’t have Git sym­links en­abled, emp­ty CSS files might get copied. The so­lu­tion is ei­ther to re­in­stall Git with sym­links en­abled or man­u­al­ly copy all *.css files from css/ to pelican-theme/static/, re­plac­ing the bro­ken sym­links present there.