A plain but pretty theme for the Pelican static site generator. Demo site.
- Nice typography and a wide range of HTML elements you can use in pages and articles. Sidecar is based on Oatcake, my universal CSS typography theme. See Oatcake's site for documentation: anything you see on that page, you can use in your pages and articles with Sidecar. The dummy articles on Sidecar's demo site show some of the elements in action.
- Responsive design: works great on both desktop and mobile.
- Customizable colors, fonts, and elements, both site-wide and per-page/article styles.
- Code blocks with syntax highlighting.
Use the
SIDECAR_PYGMENTS_THEMEsetting to choose from a few dozen builtin syntax highlighting color themes. - Automatically generated tables of contents for pages and articles.
- A customizable navbar with the
SIDECAR_NAVBARsetting. - Customizable article and page taglines and footers with the
SIDECAR_{ARTICLE|PAGE}_{TAGLINE|FOOTER}_ITEMSsettings. - Supports Pelican's Atom and RSS feeds with feed autodiscovery links in the HTML
<head>. - Supports all of Pelican's pages: the index page, article pages (example), static pages (example), the archives page, authors, categories, tags, and period archives (for example: all articles from 2024, all articles from January 2024, or all articles from 26th January 2024).
- Uses semantic HTML including:
the
<html>element'slangattribute for the site's default language (theDEFAULT_LANGsetting) or the page/article's language;<header>for the site header;<nav>for the navbar;<main>for the page's main content;<hgroup>to group headings and subheadings together;<footer>for page and article taglines and footers; link relations:rel="bookmark"for article permalinks,rel="author"for article and page authors,rel="tag"for tags,rel="next"andrel="prev"for pagination links;<time>elements with thedatetimeattribute for article/page created/updated dates; links have helpful tooltips with thetitleattribute; and pages have good tab titles with the<title>element.
-
Clone the theme to a local directory:
git clone https://github.com/pelican-themes/sidecar.git -
Pin your version by checking out the latest Sidecar release:
git -C sidecar checkout VERSIONReplace
VERSIONwith the latest version number from Sidecar's releases.Follow Sidecar on GitHub or subscribe to GitHub's Atom feed for new releases to get notified so you can update your version number.
-
Set the
THEMEsetting in your Pelican config to the path to your local clone of Sidecar. It can be either an absolute path or a path relative to your Pelican config file:# pelicanconf.py THEME = "../sidecar"
Sidecar supports optional article and page "summaries" (or "subtitles" / "subheadings") that're displayed in large-text beneath the article or page's title. See this demo post for an example of an article with a summary.
You create a summary by adding a Summary to your article or page's metadata, like this:
Title: Example Post Title
Summary: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin a malesuada orci.
Nullam at massa eros. Nullam ultricies suscipit volutpat.
Maecenas at elit quis sem semper rutrum eu condimentum loremβ¦You can also use Subtitle or Subheading instead of Summary. The difference
is that if you use Summary Pelican will also use the provided summary in its
RSS and Atom feeds (overriding the default summary that Pelican generates from
your article's body), whereas if you use Subtitle or Subheading this will
not replace the article summary in RSS and Atom feeds.
Markdown syntax works in Summary fields by default, but not in Subtitle
or Subheading fields. To get Markdown to work in Subtitle or Subheading
fields add them to the FORMATTED_FIELDS setting in your Pelican config:
# pelicanconf.py
FORMATTED_FIELDS = ["summary", "subheading", "subtitle"]Python-Markdown doesn't allow blank lines in metadata, so to create a
multi-paragraph summary you need to use <p>'s:
Title: About
Summary:
<p>
Sidecar is a plain but pretty theme for the Pelican static site generator
that works great on both mobile and desktop.
</p>
<p markdown="1">
This *About* page is an example of what a static page looks like
with Sidecar.
</p>
(The markdown="1" is needed to enable Markdown syntax within a <p>.)
You can also add subheadings to <h2> or <h3> headings within article or page
bodies by wrapping the <h2> or <h3> in an <hgroup> along with one or more
<p>'s above and/or below the heading, like this:
<hgroup>
<h2>The reality dysfunction</h2>
<p>Space is not the only void</p>
</hgroup>Sidecar includes support for HTML <meta name="description" content="..." />
metadata tags.
These are used by search engines like Google to generate the "snippets" that are shown in search page results. See Google's Best practices for creating quality meta descriptions.
A meta description is supposed to be "a short, relevant summary of what a particular page is about" that "informs and interests users": "[t]hey are like a pitch that convince the user that the page is exactly what they're looking for." Here's one of the examples Google gives of a good meta description:
<meta name="description" content="Learn how to cook eggs with this complete guide in 1 hour or less. We cover all the methods, including: over-easy, sunny side up, boiled, and poached.">To customize your page's meta descriptions using Sidecar:
-
On static pages and article pages, if the static page or article has a
Descriptionin its metadata then that will be used for the meta description. If not, then if the page or article has aSummaryin its metadata that will be used. If neitherDescriptionorSummaryis present in the page or article's metadata then the page will have no meta description.The difference between
DescriptionandSummaryis thatDescriptionis used for the meta description tag only, whereasSummary's are also displayed below the page or article's title and in RSS and Atom feeds (see above).For example to add a meta description to a Markdown-based article:
Title: Ruff Python formatting in Vim without plugins Tags: Python, Vim Description: The simplest way to integrate Ruff's Python code formatter into Vim. This is the body of the article...If you want to be able to write multi-line descriptions add
"description"to theFORMATTED_FIELDSsetting in your Pelican config:# pelicanconf.py FORMATTED_FIELDS = ["summary", "description"]
Now you can add multi-line descriptions to pages and articles like this:
Title: Ruff Python formatting in Vim without plugins Tags: Python, Vim Description: The simplest way to integrate Ruff's Python code formatter into Vim, no plugins or language servers needed. The same technique can also be used to integrate any command line formatter, for any file type. This is the body of the article... -
If you add a
SITEDESCRIPTIONstring to your site's Pelican config, Sidecar will use it as the meta description for your site's index page. Otherwise, Sidecar will fall back to theSITESUBTITLEsetting. -
Sidecar uses hard-coded meta descriptions for the archives page, period archives pages, tags/tag, categories/category and authors/author pages. For example the hard-coded meta description for the archives page is: "Archive of all posts."
Each hard-coded meta description can be customized with a corresponding
*_METADESCRIPTIONsetting in your site's Pelican config:# pelicanconf.py # The meta description for the archives page. ARCHIVES_METADESCRIPTION = "Archive of all posts." # The meta description string for the authors page. AUTHORS_METADESCRIPTION = "List of all authors with posts on this site." # The meta description string for the categories page. CATEGORIES_METADESCRIPTION = "List of all categories on this site." # The meta description string for the tags page. TAGS_METADESCRIPTION = "List of all tags on this site." # The meta description string for author pages. # {author} will be replaced with the name of the author. AUTHOR_METADESCRIPTION = "All posts by {author}." # The meta description string for category pages. # {category} will be replaced with the name of the category. CATEGORY_METADESCRIPTION = "All posts in category β{category}β." # The meta description string for tag pages. # {tag} will be replaced with the name of the tag. TAG_METADESCRIPTION = "All posts with tag β{tag}β." # The meta description string for period archive pages. # {periodstr} will be replaced with a string representing the period, e.g. "Jan 2026". PERIODARCHIVES_METADESCRIPTION = "All posts from {periodstr}."
Sidecar uses Tocbot to generate tables of contents with anchor links from AnchorJS. I prefer this approach rather than using a Pelican plugin or Markdown extension to generate tables of contents because it's portable to other site generators and even to static HTML: just include AnchorJS and Tocbot in your pages and your tables of contents will work.
Insert a <div> with the CSS class toc anywhere in a page or article and
it'll be turned into a table of contents based on the page or article's headers:
<!-- Tocbot will turn this div into a table of contents. -->
<div class="toc"></div>If you want to omit a particular heading from the table of contents add the CSS
class notoc to it:
<h2 class="notoc">Heading</h2>The table of contents depends on all your headings having id attributes for anchor links.
Sidecar uses AnchorJS to automatically generate id's for all your headings,
with the id values based on the contents of the headings.
If you want to control a heading's id value yourself (for example so it
doesn't change if you re-word the heading), add an id attribute manually as
normal and AnchorJS will use it instead of generating its own:
<h2 id="my-heading">My Heading</h2>If you don't want a heading to have an anchor link, add the CSS class noanchor
to it (this will also remove the heading from the table of contents):
<h2 class="noanchor">Heading</h2>You can add site-wide custom CSS to Sidecar using the
STYLESHEET_URL and STYLESHEET settings.
To add per-page or per-article CSS add a Stylesheet line to a page
or article's metadata, this way you can style different pages and articles
differently from each other:
Title: A Page or Article with a Custom Stylesheet
Stylesheet:
:root {
--ok-color-bg: #ff851b;
--ok-color-fg: #85144b;
}
Lorem ipsum dolor sit amet, consectetur adipiscing elitβ¦If you add a Modified date to an article's metadata it'll be shown in the
article's tagline as its "updated" date:
Title: My Article
Date: 2015-11-12
Modified: 2015-12-05You can see an example in this dummy article.
Static pages don't show any created or updated date by default, but if you add
a Modified date to a static page's metadata it'll be shown at the bottom of
the page as "Last updated".
You can see an example on the demo site's About page.
You must set this to the base URL of your site with no trailing slash. It's used to generate URLs in feeds, links in the navbar, etc.
# pelicanconf.py
SITEURL = "http://blog.notmyidea.org"Put any desired analytics scripts in this setting. Example:
# pelicanconf.py
ANALYTICS = """
<script src="/theme/js/primary-analytics.js"></script>
<script>
[ β¦ in-line Javascript code for secondary analytics β¦ ]
</script>
"""The format to use for page and article dates in Python strftime format.
Sidecar looks best if DEFAULT_DATE_FORMAT is set to something that makes
different dates (with different months and day numbers) roughly the same length,
for example:
# pelicanconf.py
DEFAULT_DATE_FORMAT = "%b %d, %Y"Your site's default language, used for the standard lang attribute on the
root <html> element. If not set this defaults to "en".
# pelicanconf.py
DEFAULT_LANG = "en"The maximum number of articles to show per-page, on paginated pages.
Set to False to disable pagination and show all articles on one page.
See Pelican's docs on pagination.
# pelicanconf.py
DEFAULT_PAGINATION = 10Set this to True to add links to each of your site's static pages to the navbar.
If SIDECAR_NAVBAR is set it overrides this setting.
# pelicanconf.py
DISPLAY_PAGES_ON_MENU = TrueIf GITHUB_URL is set in your Pelican config then a GitHub icon linking to
GITHUB_URL will be added to your site's navbar (as long as "GITHUB" is in
your SIDECAR_NAVBAR setting). The idea is that you set
GITHUB_URL to your GitHub profile page:
# pelicanconf.py
GITHUB_URL = "https://github.com/seanh"Sets the name of your site in tab and feed titles:
# pelicanconf.py
SITENAME = "A Pelican Blog"Sidecar's front page includes an optional "bio" section with an avatar
image, site subtitle, and bio text. To make this appear add the AVATAR_URL,
SITESUBTITLE and SITEBIO settings to your Pelican config. You can omit any
one of these settings and its corresponding element will be omitted from the
bio.
# pelicanconf.py
AVATAR_URL = "https://gravatar.com/avatar/bfda7359103e3879e16f65bed41ce848fb8c2e9ea44822fc7469984c19cb1902?s=72"
SITESUBTITLE = "I blog, you blog, weblog."
SITEBIO = '''Hi π, I'm <a rel="author" href="{SITEURL}/about/">Sean</a>, a developer and future Portuguese Water Dog owner living in <s>Berlin</s>, <s>Edinburgh</s>.'''Sidecar supports code blocks with syntax highlighting. See Syntax highlighting in Pelican's docs, and see the Pygments site for the list of available language names.
There are several ways to create syntax-highlighted code blocks but I recommend the "fenced code block" style because it also works on GitHub:
```python
def hello_world():
print("Hello, world!")
```
You can add hl_lines to highlight certain lines within the code block:
```python hl_lines="1 3"
def hello_world():
print("Hello, world!")
```
You can set your syntax highlighting color scheme with the SIDECAR_PYGMENTS_THEME setting:
# pelicanconf.py
SIDECAR_PYGMENTS_THEME = "monokai"See this folder for all the available themes and see the Pygments site for previews of all the themes.
Set SIDECAR_PYGMENTS_BORDERLESS = True to remove the border from code blocks:
# pelicanconf.py
SIDECAR_PYGMENTS_BORDERLESS = TrueOatcake provides several CSS variables for customizing the colors, fonts, etc.
See Oatcake's site for docs.
You can use the STYLESHEET and STYLESHEET_URL settings to inject your own
site-wide CSS that changes these variables or just adds arbitrary CSS rules.
You can also inject per-page/article CSS.
Both Oatcake and Sidecar use CSS layers
so your own custom CSS rules will take precedence regardless of specificity.
Just set STYLESHEET in your Pelican config to some custom CSS:
# pelicanconf.py
STYLESHEET = """
:root {
--ok-color-bg: #ff851b;
--ok-color-fg: #85144b;
}
"""First, add a CSS stylesheet to your site as static content
then set STYLESHEET_URL to its URL, for example:
# pelicanconf.py
STYLESHEET_URL = "css/stylesheet.css"You can customize the contents of the navbar by adding a SIDECAR_NAVBAR
setting (list of strings) to your Pelican config. For example:
# pelicanconf.py
SIDECAR_NAVBAR = [
"HOME",
"SPACE",
"MENUITEMS",
"PAGES",
"CATEGORIES",
"ARCHIVES",
"GITHUB",
'<a rel="external" href="https://example.com">Custom Link</a>',
]Certain string values have special meanings in SIDECAR_NAVBAR:
-
HOME: inserts a link to your site's home page (uses Pelican'sSITEURLandSITENAMEsettings). -
SPACE: inserts a flexible space. All items after aSPACEwill be right-aligned rather than left-aligned. -
MENUITEMS: inserts the items from Pelican'sMENUITEMSsetting. -
PAGES: inserts links to each of your site's static pages. -
GITHUB: inserts a GitHub logo linking to yourGITHUB_URL. -
CATEGORIES: inserts a link to your site's categories page.For this to work you must add matching
CATEGORIES_SAVE_ASandCATEGORIES_URLsettings to your Pelican config. For example:# pelicanconf.py CATEGORIES_SAVE_AS = "categories/index.html" CATEGORIES_URL = "categories/"
-
TAGS: inserts a link to your site's tags page.For this to work you must add matching
TAGS_SAVE_ASandTAGS_URLsettings to your Pelican config. For example:# pelicanconf.py TAGS_SAVE_AS = "tags/index.html" TAGS_URL = "tags/"
-
AUTHORS: inserts a link to your site's authors page.For this to work you must add matching
AUTHORS_SAVE_ASandAUTHORS_URLsettings to your Pelican config. For example:# pelicanconf.py AUTHORS_SAVE_AS = "authors/index.html" AUTHORS_URL = "authors/"
-
ARCHIVES: inserts a link to your site's archives page.For this to work you must add matching
ARCHIVES_SAVE_ASandARCHIVES_URLsettings to your Pelican config. For example:# pelicanconf.py ARCHIVES_SAVE_AS = "archives/index.html" ARCHIVES_URL = "archives/"
Items in SIDECAR_NAVBAR that don't match any of the special strings above are
rendered directly. This lets you include your own raw HTML strings as menu
items. For example, you could include a custom link. This lets you use HTML
attributes other than href in your navbar links, which you can't do with
Pelican's MENUITEMS:
# pelicanconf.py
SIDECAR_NAVBAR = [
...
'<a rel="external" href="https://example.com">Custom Link</a>',
'<a rel="license" href="{SITEURL}/license/">License</a>',
]{SITEURL} in menu item strings will be replaced with Pelican's
SITEURL setting.
You can customize the contents of the taglines above article and page
titles and the footers at the bottoms of articles and pages with four
settings in your Pelican config file: SIDECAR_ARTICLE_TAGLINE_ITEMS,
SIDECAR_ARTICLE_FOOTER_ITEMS, SIDECAR_PAGE_TAGLINE_ITEMS, and
SIDECAR_PAGE_FOOTER_ITEMS. The default values are:
# pelicanconf.py
SIDECAR_ARTICLE_TAGLINE_ITEMS = ["TIME", "TAGS"]
SIDECAR_ARTICLE_FOOTER_ITEMS = ["AUTHORS"]
SIDECAR_PAGE_TAGLINE_ITEMS = [] # No page tagline will be shown by default.
SIDECAR_PAGE_FOOTER_ITEMS = ["TIME"] # Shows 'Last updated' dates for pages that have Modified times.Certain string values have special meanings in SIDECAR_{ARTICLE|PAGE}_{TAGLINE|FOOTER}_ITEMS settings:
-
AUTHORS: insert links to Pelican's author pages for the article's authors. -
TIME: inserts the article's publication date/time.You can customize the format of dates with Pelican's
DEFAULT_DATE_FORMATandDATE_FORMATSsettings. -
CATEGORY: inserts a link to Pelican's category page for the article's category. -
TAGS: inserts links to Pelican's tag pages for each of the article's tags, if any.
Items that don't match any of the special strings above are rendered directly, so you can include your own raw HTML strings:
If Pelican's OUTPUT_SOURCES setting
is enabled Pelican includes the plaintext source files (e.g. Markdown files) of
your articles and pages in your site.
Source links can be included in article or page taglines or footers by including "SOURCE" in
the SIDECAR_{ARTICLE|PAGE}_{TAGLINE|FOOTER}_ITEMS settings.
Warning
This may cause URLs to the plain text versions of your articles to appear in search results!
If you have control of your HTTP headers you can add an X-Robots-Tag: noindex header to prevent this.
Otherwise you might consider not adding these links.
If you've changed Pelican's ARTICLE_SAVE_AS and ARTICLE_URL or PAGE_SAVE_AS and PAGE_URL settings
from the defaults then you need to add ARTICLE_SOURCE_URL and
PAGE_SOURCE_URL settings to your Pelican config to tell Sidecar how to
generate the URLs to your article and page source files. For example:
# pelicanconf.py
ARTICLE_SAVE_AS = '{date:%Y}/{date:%m}/{date:%d}/{slug}/index.html'
ARTICLE_URL = '{date:%Y}/{date:%m}/{date:%d}/{slug}/'
ARTICLE_SOURCE_URL = "{article.url}index{OUTPUT_SOURCES_EXTENSION}"
PAGE_SAVE_AS = '{slug}/index.html'
PAGE_URL = '{slug}/'
PAGE_SOURCE_URL = "{page.url}index{OUTPUT_SOURCES_EXTENSION}"You can customize the Sidecar theme by using Pelican's
THEME_TEMPLATES_OVERRIDES
setting to override some of Sidecar's templates.
When overriding a template you can inherit from one of the theme's templates with
{% extends '!theme/<template>.html' %} and then override some of the template's
blocks with {% block %}. When overriding a block you can call the template's
original block with {{ super() }}.
Let's work through an example of using template customization to add a favicon to a site:
-
Generate some favicon images for your site. You can start with an image or photo and use a favicon generator site like https://realfavicongenerator.net/ to convert it into favicon files in the right formats.
-
Add the favicon images to your site's
content/images/directory as static content. -
Create a
templatesdirectory in your site, to hold your custom templates:mkdir -p templates -
Add the
THEME_TEMPLATES_OVERRIDESsetting to your Pelican config file:# pelicanconf.py THEME_TEMPLATES_OVERRIDES = ["templates"]
-
Add a
templates/base.htmlfile, something like this:{# templates/base.html #} {% extends '!theme/base.html' %} {% block head %} {{ super() }} <link rel="icon" type="image/png" href="{{ SITEURL }}/images/favicon-96x96.png" sizes="96x96" /> <link rel="icon" type="image/svg+xml" href="{{ SITEURL }}/images/favicon.svg" /> <link rel="shortcut icon" href="{{ SITEURL }}/images/favicon.ico" /> <link rel="apple-touch-icon" sizes="180x180" href="{{ SITEURL }}/images/apple-touch-icon.png" /> {% endblock %}
That's it--your site should now have a favicon!
What the base.html template does is:
- Overrides Sidecar's
base.htmltemplate. - Uses
{% extends %}to inherit from Sidecar'sbase.htmltemplate. - Uses
{% block %}to override theheadblock in Sidecar'sbase.htmltemplate. - Uses
{{ super() }}to call the base template'sheadblock. - Finally, adds some HTML to the
headblock to inject the favicons into the site.
Sidecar puts a search bar on the archives page that, by default, uses Google to
search your site. You can customize the search bar by overriding the
search.html template. For example to change the
search to use Duck Duck Go you could add a templates/search.html file to your
site, like this:
{# templates/search.html #}
<form method="get" action="https://duckduckgo.com/" class="search">
<input type="hidden" name="sites" value="{{ SITEURL }}" />
<input type="search" name="q" placeholder="Full-text search…" aria-label="Full-text search" />
</form>If you simply want to remove the search bar, just add an empty templates/search.html file to your site.
