aboutsummaryrefslogtreecommitdiffstats
path: root/nikola/data/themes/bootstrap4
diff options
context:
space:
mode:
Diffstat (limited to 'nikola/data/themes/bootstrap4')
-rw-r--r--nikola/data/themes/bootstrap4/README.md10
l---------nikola/data/themes/bootstrap4/assets/css/bootstrap.min.css1
-rw-r--r--nikola/data/themes/bootstrap4/assets/css/theme.css232
l---------nikola/data/themes/bootstrap4/assets/js/bootstrap.min.js1
l---------nikola/data/themes/bootstrap4/assets/js/jquery.min.js1
l---------nikola/data/themes/bootstrap4/assets/js/popper.min.js1
-rw-r--r--nikola/data/themes/bootstrap4/bootstrap4.theme12
-rw-r--r--nikola/data/themes/bootstrap4/bundles26
-rw-r--r--nikola/data/themes/bootstrap4/templates/authors.tmpl25
-rw-r--r--nikola/data/themes/bootstrap4/templates/base.tmpl105
-rw-r--r--nikola/data/themes/bootstrap4/templates/base_helper.tmpl165
-rw-r--r--nikola/data/themes/bootstrap4/templates/index_helper.tmpl13
-rw-r--r--nikola/data/themes/bootstrap4/templates/listing.tmpl30
-rw-r--r--nikola/data/themes/bootstrap4/templates/pagination_helper.tmpl40
-rw-r--r--nikola/data/themes/bootstrap4/templates/post.tmpl57
-rw-r--r--nikola/data/themes/bootstrap4/templates/tags.tmpl38
-rw-r--r--nikola/data/themes/bootstrap4/templates/ui_helper.tmpl24
17 files changed, 781 insertions, 0 deletions
diff --git a/nikola/data/themes/bootstrap4/README.md b/nikola/data/themes/bootstrap4/README.md
new file mode 100644
index 0000000..bb1b484
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/README.md
@@ -0,0 +1,10 @@
+This is a theme based on Bootstrap 4.
+
+The theme is a good building block for a site. It is based on a simple navbar +
+content layout. For a more blog-style layout, check out `bootblog4`.
+
+Note that unlike previous versions of Bootstrap, icon fonts are not built-in.
+You can use Font Awesome for this.
+
+This theme supports Bootswatch font/color schemes through the `nikola
+bootwatch_theme` command.
diff --git a/nikola/data/themes/bootstrap4/assets/css/bootstrap.min.css b/nikola/data/themes/bootstrap4/assets/css/bootstrap.min.css
new file mode 120000
index 0000000..8c8dc62
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/assets/css/bootstrap.min.css
@@ -0,0 +1 @@
+../../../../../../npm_assets/node_modules/bootstrap/dist/css/bootstrap.min.css \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap4/assets/css/theme.css b/nikola/data/themes/bootstrap4/assets/css/theme.css
new file mode 100644
index 0000000..20eee8e
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/assets/css/theme.css
@@ -0,0 +1,232 @@
+img {
+ max-width: 100%;
+}
+
+.titlebox {
+ text-align: right;
+}
+
+
+td.label {
+ /* Issue #290 */
+ background-color: inherit;
+}
+
+.footnote-reference {
+ /* Issue 290 */
+ vertical-align: super;
+ font-size: xx-small;
+}
+
+.caption {
+ /* Issue 292 */
+ text-align: center;
+ padding-top: 1em;
+}
+
+div.figure > img,
+div.figure > a > img {
+ /* Issue 292 */
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+blockquote p, blockquote {
+ font-size: 1.25rem;
+ font-weight: 300;
+ line-height: 1.25;
+}
+
+ul.bricks > li {
+ display: inline;
+ background-color: lightblue;
+ padding: 8px;
+ border-radius: 5px;
+ line-height: 3;
+ white-space:nowrap;
+ margin: 3px;
+}
+
+pre, pre code {
+ white-space: pre;
+ word-wrap: normal;
+ overflow: auto;
+}
+
+article.post-micro {
+ font-family: Georgia, 'Times New Roman', Times, serif;
+ font-size: 1.5em;
+}
+
+.image-block {
+ display: inline-block;
+}
+
+.tags {
+ padding-left: 0;
+ margin-left: -5px;
+ list-style: none;
+ text-align: center;
+
+}
+
+.tags > li {
+ display: inline-block;
+}
+.tags > li a {
+ display: inline-block;
+ padding: .25em .4em;
+ font-size: 75%;
+ font-weight: 700;
+ line-height: 1;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ border-radius: .25rem;
+ background-color: #868e96;
+}
+
+.tags > li a:hover {
+ color: #fff;
+ text-decoration: none;
+ background-color: #6c757d;
+}
+
+.metadata p:before,
+.postlist .listdate:after {
+ content: " — ";
+}
+
+.metadata p:first-of-type:before {
+ content: "";
+}
+
+.metadata p {
+ display: inline;
+}
+
+.posttranslations h3 {
+ display: inline;
+ font-size: 1em;
+ font-weight: bold;
+}
+
+.posttranslations h3:last-child {
+ display: none;
+}
+
+.entry-content {
+ margin-top: 1em;
+}
+
+/* for alignment with Bootstrap's .entry-content styling */
+.entry-summary {
+ margin-top: 1em;
+}
+
+/* Custom page footer */
+#footer {
+ padding-top: 19px;
+ color: #777;
+ border-top: 1px solid #e5e5e5;
+}
+
+/* hat tip bootstrap/html5 boilerplate */
+@media print {
+ *, *:before, *:after {
+ font-family: Garamond, Junicode, serif;
+ }
+
+ body {
+ font-size: 12pt;
+ }
+
+ article .entry-title a[href]:after,
+ article .metadata a[href]:after,
+ article .tags a[href]:after {
+ content: "";
+ }
+
+ article .metadata .sourceline {
+ display: none;
+ }
+
+ article .metadata .linkline a[href]:after {
+ content: " (" attr(href) ")";
+ }
+
+ .navbar {
+ display: none;
+ }
+}
+
+pre, .codetable {
+ border: 1px solid #ccc;
+ border-radius: 0.25rem;
+ margin-bottom: 1rem;
+}
+
+pre {
+ padding: 0.75rem;
+}
+
+.codetable tr:first-child td.linenos {
+ border-top-left-radius: 0.25rem;
+}
+
+.codetable tr:last-child td.linenos {
+ border-bottom-left-radius: 0.25rem;
+}
+
+.postindexpager {
+ padding-bottom: 1rem;
+}
+
+ul.navbar-nav {
+ margin-top: 0;
+}
+
+ul.pager {
+ display: flex;
+ padding-left: 0;
+ list-style: none;
+ border-radius: .25rem;
+ padding-left: 0;
+ margin: 0.5rem 0;
+}
+
+ul.pager li.previous {
+ margin-right: auto;
+ display: inline;
+}
+
+ul.pager li.next {
+ margin-left: auto;
+ display: inline;
+}
+
+
+ul.pager li a {
+ display: inline;
+ position: relative;
+ padding: .5rem .75rem;
+ margin-left: -1px;
+ line-height: 1.25;
+ border: 1px solid #ddd;
+ border-radius: .25rem;
+}
+
+pre.code {
+ white-space: pre-wrap;
+}
+
+.byline a:not(:last-child):after {
+ content: ",";
+}
+
+/* Override incorrect Bootstrap 4 default */
+html[dir="rtl"] body {
+ text-align: right;
+}
diff --git a/nikola/data/themes/bootstrap4/assets/js/bootstrap.min.js b/nikola/data/themes/bootstrap4/assets/js/bootstrap.min.js
new file mode 120000
index 0000000..593bffb
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/assets/js/bootstrap.min.js
@@ -0,0 +1 @@
+../../../../../../npm_assets/node_modules/bootstrap/dist/js/bootstrap.min.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap4/assets/js/jquery.min.js b/nikola/data/themes/bootstrap4/assets/js/jquery.min.js
new file mode 120000
index 0000000..2a592f6
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/assets/js/jquery.min.js
@@ -0,0 +1 @@
+../../../../../../npm_assets/node_modules/jquery/dist/jquery.min.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap4/assets/js/popper.min.js b/nikola/data/themes/bootstrap4/assets/js/popper.min.js
new file mode 120000
index 0000000..43fca04
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/assets/js/popper.min.js
@@ -0,0 +1 @@
+../../../../../../npm_assets/node_modules/popper.js/dist/umd/popper.min.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap4/bootstrap4.theme b/nikola/data/themes/bootstrap4/bootstrap4.theme
new file mode 100644
index 0000000..0f3f9ef
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/bootstrap4.theme
@@ -0,0 +1,12 @@
+[Theme]
+engine = mako
+parent = base
+author = The Nikola Contributors
+author_url = https://getnikola.com/
+license = MIT
+based_on = Bootstrap 4 <http://getbootstrap.com/>
+tags = bootstrap
+
+[Family]
+family = bootstrap4
+jinja_version = bootstrap4-jinja
diff --git a/nikola/data/themes/bootstrap4/bundles b/nikola/data/themes/bootstrap4/bundles
new file mode 100644
index 0000000..71d458b
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/bundles
@@ -0,0 +1,26 @@
+; css bundles
+assets/css/all-nocdn.css=
+ bootstrap.min.css,
+ rst_base.css,
+ nikola_rst.css,
+ code.css,
+ baguetteBox.min.css,
+ theme.css,
+ custom.css,
+assets/css/all.css=
+ rst_base.css,
+ nikola_rst.css,
+ code.css,
+ baguetteBox.min.css,
+ theme.css,
+ custom.css,
+
+; javascript bundles
+assets/js/all-nocdn.js=
+ jquery.min.js,
+ popper.min.js,
+ bootstrap.min.js,
+ baguetteBox.min.js,
+ fancydates.min.js,
+assets/js/all.js=
+ fancydates.min.js
diff --git a/nikola/data/themes/bootstrap4/templates/authors.tmpl b/nikola/data/themes/bootstrap4/templates/authors.tmpl
new file mode 100644
index 0000000..300377d
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/templates/authors.tmpl
@@ -0,0 +1,25 @@
+## -*- coding: utf-8 -*-
+<%inherit file="base.tmpl"/>
+<%namespace name="feeds_translations" file="feeds_translations_helper.tmpl" import="*"/>
+
+<%block name="extra_head">
+ ${feeds_translations.head(kind=kind, feeds=False)}
+</%block>
+
+<%block name="content">
+% if items:
+ <h2>${messages("Authors")}</h2>
+ <div class="metadata">
+ ${feeds_translations.translation_link(kind)}
+ </div>
+% endif
+% if items:
+ <ul class="list-inline">
+ % for text, link in items:
+ % if text not in hidden_authors:
+ <li><a class="reference badge" href="${link}">${text|h}</a></li>
+ % endif
+ % endfor
+ </ul>
+% endif
+</%block>
diff --git a/nikola/data/themes/bootstrap4/templates/base.tmpl b/nikola/data/themes/bootstrap4/templates/base.tmpl
new file mode 100644
index 0000000..21b6141
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/templates/base.tmpl
@@ -0,0 +1,105 @@
+## -*- coding: utf-8 -*-
+<%namespace name="base" file="base_helper.tmpl" import="*" />
+<%namespace name="notes" file="annotation_helper.tmpl" import="*" />
+${set_locale(lang)}
+${base.html_headstart()}
+<%block name="extra_head">
+### Leave this block alone.
+</%block>
+${template_hooks['extra_head']()}
+</head>
+<body>
+<a href="#content" class="sr-only sr-only-focusable">${messages("Skip to main content")}</a>
+
+<!-- Menubar -->
+
+<nav class="navbar navbar-expand-md static-top mb-4
+% if theme_config.get('navbar_light'):
+navbar-light
+% else:
+navbar-dark
+% endif
+% if theme_config.get('navbar_custom_bg'):
+${theme_config['navbar_custom_bg']}
+% elif theme_config.get('navbar_light'):
+bg-light
+% else:
+bg-dark
+%endif
+">
+ <div class="container"><!-- This keeps the margins nice -->
+ <a class="navbar-brand" href="${_link("root", None, lang)}">
+ %if logo_url:
+ <img src="${logo_url}" alt="${blog_title|h}" id="logo" class="d-inline-block align-top">
+ %endif
+
+ % if show_blog_title:
+ <span id="blog-title">${blog_title|h}</span>
+ % endif
+ </a>
+ <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#bs-navbar" aria-controls="bs-navbar" aria-expanded="false" aria-label="Toggle navigation">
+ <span class="navbar-toggler-icon"></span>
+ </button>
+
+ <div class="collapse navbar-collapse" id="bs-navbar">
+ <ul class="navbar-nav mr-auto">
+ ${base.html_navigation_links_entries(navigation_links)}
+ ${template_hooks['menu']()}
+ </ul>
+ %if search_form:
+ ${search_form}
+ %endif
+
+ <ul class="navbar-nav navbar-right">
+ ${base.html_navigation_links_entries(navigation_alt_links)}
+ <%block name="belowtitle">
+ %if len(translations) > 1:
+ <li>${base.html_translations()}</li>
+ %endif
+ </%block>
+ % if show_sourcelink:
+ <%block name="sourcelink"></%block>
+ %endif
+ ${template_hooks['menu_alt']()}
+ </ul>
+ </div><!-- /.navbar-collapse -->
+ </div><!-- /.container -->
+</nav>
+
+<!-- End of Menubar -->
+
+<div class="container" id="content" role="main">
+ <div class="body-content">
+ <!--Body content-->
+ ${template_hooks['page_header']()}
+ <%block name="extra_header"></%block>
+ <%block name="content"></%block>
+ <!--End of body content-->
+
+ <footer id="footer">
+ ${content_footer}
+ ${template_hooks['page_footer']()}
+ <%block name="extra_footer"></%block>
+ </footer>
+ </div>
+</div>
+
+${base.late_load_js()}
+ %if date_fanciness != 0:
+ <!-- fancy dates -->
+ <script>
+ luxon.Settings.defaultLocale = "${luxon_locales[lang]}";
+ fancydates(${date_fanciness}, ${luxon_date_format});
+ </script>
+ <!-- end fancy dates -->
+ %endif
+ <%block name="extra_js"></%block>
+ <script>
+ baguetteBox.run('div#content', {
+ ignoreClass: 'islink',
+ captions: function(element){var i=element.getElementsByTagName('img')[0];return i===undefined?'':i.alt;}});
+ </script>
+${body_end}
+${template_hooks['body_end']()}
+</body>
+</html>
diff --git a/nikola/data/themes/bootstrap4/templates/base_helper.tmpl b/nikola/data/themes/bootstrap4/templates/base_helper.tmpl
new file mode 100644
index 0000000..f551116
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/templates/base_helper.tmpl
@@ -0,0 +1,165 @@
+## -*- coding: utf-8 -*-
+<%namespace name="feeds_translations" file="feeds_translations_helper.tmpl" import="*"/>
+
+<%def name="html_headstart()">
+<!DOCTYPE html>
+<html
+\
+prefix='\
+og: http://ogp.me/ns# article: http://ogp.me/ns/article#
+%if comment_system == 'facebook':
+fb: http://ogp.me/ns/fb# \
+%endif
+'\
+% if is_rtl:
+dir="rtl" \
+% endif
+\
+lang="${lang}">
+ <head>
+ <meta charset="utf-8">
+ %if description:
+ <meta name="description" content="${description|h}">
+ %endif
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ %if title == blog_title:
+ <title>${blog_title|h}</title>
+ %else:
+ <title>${title|h} | ${blog_title|h}</title>
+ %endif
+
+ ${html_stylesheets()}
+ <meta name="theme-color" content="${theme_color}">
+ % if meta_generator_tag:
+ <meta name="generator" content="Nikola (getnikola.com)">
+ % endif
+ ${html_feedlinks()}
+ <link rel="canonical" href="${abs_link(permalink)}">
+
+ %if favicons:
+ %for name, file, size in favicons:
+ <link rel="${name}" href="${file}" sizes="${size}"/>
+ %endfor
+ %endif
+
+ % if comment_system == 'facebook':
+ <meta property="fb:app_id" content="${comment_system_id}">
+ % endif
+
+ %if prevlink:
+ <link rel="prev" href="${prevlink}" type="text/html">
+ %endif
+ %if nextlink:
+ <link rel="next" href="${nextlink}" type="text/html">
+ %endif
+
+ %if use_cdn:
+ <!--[if lt IE 9]><script src="https://html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
+ %else:
+ <!--[if lt IE 9]><script src="${url_replacer(permalink, '/assets/js/html5.js', lang, url_type)}"></script><![endif]-->
+ %endif
+
+ ${extra_head_data}
+</%def>
+
+<%def name="late_load_js()">
+ %if use_cdn:
+ <script src="http://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
+ <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.11.1/baguetteBox.min.js" integrity="sha256-ULQV01VS9LCI2ePpLsmka+W0mawFpEA0rtxnezUj4A4=" crossorigin="anonymous"></script>
+ % endif
+ %if use_bundles and use_cdn:
+ <script src="/assets/js/all.js"></script>
+ %elif use_bundles:
+ <script src="/assets/js/all-nocdn.js"></script>
+ %else:
+ %if not use_cdn:
+ <script src="/assets/js/jquery.min.js"></script>
+ <script src="/assets/js/popper.min.js"></script>
+ <script src="/assets/js/bootstrap.min.js"></script>
+ <script src="/assets/js/baguetteBox.min.js"></script>
+ %endif
+ %endif
+ %if date_fanciness != 0:
+ %if date_fanciness == 2:
+ <script src="https://polyfill.io/v3/polyfill.js?features=Intl.RelativeTimeFormat.%7Elocale.${luxon_locales[lang]}"></script>
+ %endif
+ %if use_cdn:
+ <script src="https://cdn.jsdelivr.net/npm/luxon@1.25.0/build/global/luxon.min.js" integrity="sha256-OVk2fwTRcXYlVFxr/ECXsakqelJbOg5WCj1dXSIb+nU=" crossorigin="anonymous"></script>
+ %else:
+ <script src="/assets/js/luxon.min.js"></script>
+ %endif
+ %if not use_bundles:
+ <script src="/assets/js/fancydates.min.js"></script>
+ %endif
+ %endif
+ ${social_buttons_code}
+</%def>
+
+
+<%def name="html_stylesheets()">
+ %if use_cdn:
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.11.1/baguetteBox.min.css" integrity="sha256-cLMYWYYutHkt+KpNqjg7NVkYSQ+E2VbrXsEvOqU7mL0=" crossorigin="anonymous">
+ % endif
+ %if use_bundles and use_cdn:
+ <link href="/assets/css/all.css" rel="stylesheet" type="text/css">
+ %elif use_bundles:
+ <link href="/assets/css/all-nocdn.css" rel="stylesheet" type="text/css">
+ %else:
+ %if not use_cdn:
+ <link href="/assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/baguetteBox.min.css" rel="stylesheet" type="text/css">
+ %endif
+ <link href="/assets/css/rst.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/code.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/theme.css" rel="stylesheet" type="text/css">
+ %if has_custom_css:
+ <link href="/assets/css/custom.css" rel="stylesheet" type="text/css">
+ %endif
+ %endif
+ % if needs_ipython_css:
+ <link href="/assets/css/ipython.min.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/nikola_ipython.css" rel="stylesheet" type="text/css">
+ % endif
+</%def>
+
+<%def name="html_navigation_links()">
+ ${html_navigation_links_entries(navigation_links)}
+</%def>
+
+<%def name="html_navigation_links_entries(navigation_links_source)">
+ %for url, text in navigation_links_source[lang]:
+ % if isinstance(url, tuple):
+ <li class="nav-item dropdown"><a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">${text}</a>
+ <div class="dropdown-menu">
+ %for suburl, text in url:
+ % if rel_link(permalink, suburl) == "#":
+ <a href="${permalink}" class="dropdown-item active">${text} <span class="sr-only">${messages("(active)", lang)}</span></a>
+ %else:
+ <a href="${suburl}" class="dropdown-item">${text}</a>
+ %endif
+ %endfor
+ </div>
+ % else:
+ % if rel_link(permalink, url) == "#":
+ <li class="nav-item active"><a href="${permalink}" class="nav-link">${text} <span class="sr-only">${messages("(active)", lang)}</span></a>
+ %else:
+ <li class="nav-item"><a href="${url}" class="nav-link">${text}</a>
+ %endif
+ % endif
+ %endfor
+</%def>
+
+<%def name="html_feedlinks()">
+ ${feeds_translations.head(classification=None, kind='index', other=False)}
+</%def>
+
+<%def name="html_translations()">
+ %for langname in sorted(translations):
+ %if langname != lang:
+ <li class="nav-item"><a href="${_link("root", None, langname)}" rel="alternate" hreflang="${langname}" class="nav-link">${messages("LANGUAGE", langname)}</a></li>
+ %endif
+ %endfor
+</%def>
diff --git a/nikola/data/themes/bootstrap4/templates/index_helper.tmpl b/nikola/data/themes/bootstrap4/templates/index_helper.tmpl
new file mode 100644
index 0000000..e6b0089
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/templates/index_helper.tmpl
@@ -0,0 +1,13 @@
+## -*- coding: utf-8 -*-
+<%def name="html_pager()">
+ %if prevlink or nextlink:
+ <ul class="pager postindexpager clearfix">
+ %if prevlink:
+ <li class="previous"><a href="${prevlink}" rel="prev">${messages("Newer posts")}</a></li>
+ %endif
+ %if nextlink:
+ <li class="next"><a href="${nextlink}" rel="next">${messages("Older posts")}</a></li>
+ %endif
+ </ul>
+ %endif
+</%def>
diff --git a/nikola/data/themes/bootstrap4/templates/listing.tmpl b/nikola/data/themes/bootstrap4/templates/listing.tmpl
new file mode 100644
index 0000000..d9a4c56
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/templates/listing.tmpl
@@ -0,0 +1,30 @@
+## -*- coding: utf-8 -*-
+<%inherit file="base.tmpl"/>
+<%namespace name="ui" file="ui_helper.tmpl"/>
+<%block name="content">
+${ui.breadcrumbs(crumbs)}
+%if folders or files:
+<ul>
+% for name in folders:
+ <li><a href="${name|h}">📂&nbsp;${name|h}</a>
+% endfor
+% for name in files:
+ <li><a href="${name|h}.html">📄&nbsp;${name|h}</a>
+% endfor
+</ul>
+%endif
+% if code:
+<h1>${title}
+ % if source_link:
+ <small><a href="${source_link}">(${messages("Source")})</a></small>
+ % endif
+ </h1>
+ ${code}
+% endif
+</%block>
+
+<%block name="sourcelink">
+% if source_link and show_sourcelink:
+ ${ui.show_sourcelink(source_link)}
+% endif
+</%block>
diff --git a/nikola/data/themes/bootstrap4/templates/pagination_helper.tmpl b/nikola/data/themes/bootstrap4/templates/pagination_helper.tmpl
new file mode 100644
index 0000000..da0e920
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/templates/pagination_helper.tmpl
@@ -0,0 +1,40 @@
+## -*- coding: utf-8 -*-
+<%def name="page_navigation(current_page, page_links, prevlink, nextlink, prev_next_links_reversed, surrounding=5)">
+<nav aria-label="Page navigation">
+ <ul class="pagination">
+ % if prev_next_links_reversed:
+ % if nextlink:
+ <li class="page-item"><a href="${nextlink}" class="page-link" aria-label="${messages("Older posts")}"><span aria-hidden="true">&laquo;</span></a></li>
+ % else:
+ <li class="page-item disabled"><a href="#" class="page-link" aria-label="${messages("Older posts")}"><span aria-hidden="true">&laquo;</span></a></li>
+ % endif
+ % else:
+ % if prevlink:
+ <li class="page-item"><a href="${prevlink}" class="page-link" aria-label="${messages("Newer posts")}"><span aria-hidden="true">&laquo;</span></a></li>
+ % else:
+ <li class="page-item disabled"><a href="#" class="page-link" aria-label="${messages("Newer posts")}"><span aria-hidden="true">&laquo;</span></a></li>
+ % endif
+ % endif
+ % for i, link in enumerate(page_links):
+ % if abs(i - current_page) <= surrounding or i == 0 or i == len(page_links) - 1:
+ <li class="page-item ${'active' if i == current_page else ''}"><a href="${link}" class="page-link">${i + 1}${' <span class="sr-only">(current)</span>' if i == current_page else ''}</a></li>
+ % elif i == current_page - surrounding - 1 or i == current_page + surrounding + 1:
+ <li class="page-item disabled"><a href="#" class="page-link" aria-label="…"><span aria-hidden="true">…</span></a></li>
+ % endif
+ % endfor
+ % if prev_next_links_reversed:
+ % if prevlink:
+ <li class="page-item"><a href="${prevlink}" class="page-link" aria-label="${messages("Newer posts")}"><span aria-hidden="true">&raquo;</span></a></li>
+ % else:
+ <li class="page-item disabled"><a href="#" class="page-link" aria-label="${messages("Newer posts")}"><span aria-hidden="true">&raquo;</span></a></li>
+ % endif
+ % else:
+ % if nextlink:
+ <li class="page-item"><a href="${nextlink}" class="page-link" aria-label="${messages("Older posts")}"><span aria-hidden="true">&raquo;</span></a></li>
+ % else:
+ <li class="page-item disabled"><a href="#" class="page-link" aria-label="${messages("Older posts")}"><span aria-hidden="true">&raquo;</span></a></li>
+ % endif
+ % endif
+ </ul>
+</nav>
+</%def>
diff --git a/nikola/data/themes/bootstrap4/templates/post.tmpl b/nikola/data/themes/bootstrap4/templates/post.tmpl
new file mode 100644
index 0000000..0d4248e
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/templates/post.tmpl
@@ -0,0 +1,57 @@
+## -*- coding: utf-8 -*-
+<%namespace name="helper" file="post_helper.tmpl"/>
+<%namespace name="pheader" file="post_header.tmpl"/>
+<%namespace name="comments" file="comments_helper.tmpl"/>
+<%namespace name="math" file="math_helper.tmpl"/>
+<%namespace name="ui" file="ui_helper.tmpl"/>
+<%inherit file="base.tmpl"/>
+
+<%block name="extra_head">
+ ${parent.extra_head()}
+ % if post.meta('keywords'):
+ <meta name="keywords" content="${smartjoin(', ', post.meta('keywords'))|h}">
+ % endif
+ <meta name="author" content="${post.author()|h}">
+ %if post.prev_post:
+ <link rel="prev" href="${post.prev_post.permalink()}" title="${post.prev_post.title()|h}" type="text/html">
+ %endif
+ %if post.next_post:
+ <link rel="next" href="${post.next_post.permalink()}" title="${post.next_post.title()|h}" type="text/html">
+ %endif
+ % if post.is_draft:
+ <meta name="robots" content="noindex">
+ % endif
+ ${helper.open_graph_metadata(post)}
+ ${helper.twitter_card_information(post)}
+ ${helper.meta_translations(post)}
+ ${math.math_styles_ifpost(post)}
+</%block>
+
+<%block name="content">
+<article class="post-${post.meta('type')} h-entry hentry postpage" itemscope="itemscope" itemtype="http://schema.org/Article">
+ ${pheader.html_post_header()}
+ <div class="e-content entry-content" itemprop="articleBody text">
+ ${post.text()}
+ </div>
+ <aside class="postpromonav">
+ <nav>
+ ${helper.html_tags(post)}
+ ${helper.html_pager(post)}
+ </nav>
+ </aside>
+ % if not post.meta('nocomments') and site_has_comments:
+ <section class="comments hidden-print">
+ <h2>${messages("Comments")}</h2>
+ ${comments.comment_form(post.permalink(absolute=True), post.title(), post._base_path)}
+ </section>
+ % endif
+ ${math.math_scripts_ifpost(post)}
+</article>
+${comments.comment_link_script()}
+</%block>
+
+<%block name="sourcelink">
+% if show_sourcelink:
+ ${ui.show_sourcelink(post.source_link())}
+% endif
+</%block>
diff --git a/nikola/data/themes/bootstrap4/templates/tags.tmpl b/nikola/data/themes/bootstrap4/templates/tags.tmpl
new file mode 100644
index 0000000..f1870f6
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/templates/tags.tmpl
@@ -0,0 +1,38 @@
+## -*- coding: utf-8 -*-
+<%inherit file="base.tmpl"/>
+
+<%block name="content">
+<h1>${title|h}</h1>
+% if cat_items:
+ % if items:
+ <h2>${messages("Categories")}</h2>
+ % endif
+ % for text, full_name, path, link, indent_levels, indent_change_before, indent_change_after in cat_hierarchy:
+ % for i in range(indent_change_before):
+ <ul class="list-inline">
+ % endfor
+ <li class="list-inline-item"><a class="reference badge badge-secondary" href="${link}">${text|h}</a>
+ % if indent_change_after <= 0:
+ </li>
+ % endif
+ % for i in range(-indent_change_after):
+ </ul>
+ % if i + 1 < len(indent_levels):
+ </li>
+ % endif
+ % endfor
+ % endfor
+ % if items:
+ <h2>${messages("Tags")}</h2>
+ % endif
+%endif
+% if items:
+ <ul class="list-inline">
+ % for text, link in items:
+ % if text not in hidden_tags:
+ <li class="list-inline-item"><a class="reference badge badge-secondary" href="${link}">${text|h}</a></li>
+ % endif
+ % endfor
+ </ul>
+% endif
+</%block>
diff --git a/nikola/data/themes/bootstrap4/templates/ui_helper.tmpl b/nikola/data/themes/bootstrap4/templates/ui_helper.tmpl
new file mode 100644
index 0000000..7e884f9
--- /dev/null
+++ b/nikola/data/themes/bootstrap4/templates/ui_helper.tmpl
@@ -0,0 +1,24 @@
+## -*- coding: utf-8 -*-
+<%def name="breadcrumbs(crumbs)">
+%if crumbs:
+<nav class="breadcrumbs">
+<ul class="breadcrumb">
+ % for link, text in crumbs:
+ % if text != index_file:
+ % if link == '#':
+ <li class="breadcrumb-item active">${text.rsplit('.html', 1)[0]}</li>
+ % else:
+ <li class="breadcrumb-item"><a href="${link}">${text}</a></li>
+ % endif
+ % endif
+ % endfor
+</ul>
+</nav>
+%endif
+</%def>
+
+<%def name="show_sourcelink(sourcelink_href)">
+ <li class="nav-item">
+ <a href="${sourcelink_href}" id="sourcelink" class="nav-link">${messages("Source")}</a>
+ </li>
+</%def>