Themes and templates
While the /docs
folder holds the content for the site, the /theme
folder holds the layout. Shromp uses Handlebars to organise and re-use layouts.
Configuring a theme
You can set your current theme configuration in the shromp.toml
file, using the following properties:
theme_folder="./default-theme/"
-- folder where the theme is locateddefault_page_template="page"
-- default template to use
Folder structure
The theme folder usually looks like this:
- theme/
assets/
scripts/
*.js
styles/
*.css
images/
*
templates/
partials/
*.hbs
*.hbs
helpers.js
shromp-theme.toml
I'll explain each one of these items in the next sections.
shromp-theme.toml
This file should be in the root of your theme. It holds theme specific configuration:
Property | Description |
---|---|
default_template |
Default template to use for content with custom template not set. Default: page |
Templates
Check the Handlebars documentation for syntax and features. Usually, a handlebars file looks like this:
<ul class="people_list">
{{#each people}}
<li>{{this}}</li>
{{/each}}
</ul>
Partials
Handlebars allows for template reuse through partials. Partials are normal Handlebars templates that may be called directly by other templates.
In Shromp, partials should be defined in the <theme>/templates/partials/
folder. To use a partial, just include {{ > partial_name }}
in your template file. Here is an example with a page that re-uses header, footer and side navigation:
{{> header }}
{{> side-navigation }}
<main class="content page-doc with-menu" role="main">
{{{ mainContent }}}
</main>
{{> footer }}
Check the partials documentation for more features.
Helpers
Helpers can be used to implement functionality that is not part of the Handlebars language itself.
Shromp allows you to define custom helpers by including them in the <theme>/templates/helpers.js
file. Just implement and export the function, and it will be available as a helper with the same name. For example:
The helper definition:
// Helper to return the "current" class when the navigation link refers to the
// current file
export function getNavClassWhenCurrent(navLink, currentFile) {
return navLink === currentFile ? "current" : "";
};
In the template, you can use the helper like this:
<ul>
{{#each links}}
<li class="nav-item {{getNavClassWhenCurrent path @root.currentFilePath}}">
<a href="{{path}}">{{title}}</a>
</li>
{{/each}}
</ul>
The result will be:
<ul>
<li class="nav-item">
<a href="/another-page">Another page</a>
</li>
<li class="nav-item current">
<a href="/this-page">This page</a>
</li>
<li class="nav-item">
<a href="/another-page">Another page</a>
</li>
</ul>
Check the Handlebar's helpers documentation for more examples and features.
Data available in the templates
Shromp provides a way for you to send metadata from your markdown content to your template by using the metadata block, as described on the docs folder documentation.
Some of this data is used to configure the template, but you can also pass custom data. To define metadata in your page, create a comment block as the first thing in your markdown file. This block should contain one property per line. Here is an example:
<!--
page_title: This is a custom title
template: custom_template
nav_max: 3
hidden: true
this_is_a_custom_metadata: custom value
another_custom_metadata: 123
custom_flag_option
-->
# Page's title
...
Template configuration metadata
Metadata | Description |
---|---|
template: <template_name> |
Define which template to use for this content. When omitted, the default template will be used |
page_title: <text> |
By default, the page title is the first H1 in your markdown document. You can use this property to override that value. For example, your main heading might be "Getting started", but you want your page title to be "Introduction". |
Navigation menu metadata
The next section will cover which data is made available to your template by default. One of the most useful is the navigationMenu
, which can be used to build your site's navigation and breadcrumbs.
The navigationMenu has the following contract:
interface NavigationLink {
title: string;
path: string;
level: number;
children?: NavigationLink[];
}
Child pages and headings are nested, forming a navigation tree. For the following folder structure:
- docs/
en/
1.0/
1-intro/
index.md
index.md
The result tree might look like this:
{
title: "Home page",
path: "/en/1.0",
level: 1,
children: [
{
title: "Home page", // this is the page title
path: "/en/1.0/index.html",
children: [
{
title: "A H2 heading",
path: "/en/1.0/another-page#sp-h2-heading",
level: 2,
children: [],
},
{
title: "Intro page",
path: "/en/1.0/intro.html",
level: 1,
children: [
{
title: "A H2 heading",
path: "/en/1.0/intro.html#sp-h2-heading",
level: 2,
children: [
{
title: "A H3 heading",
path: "/en/1.0/intro.html#sp-h3-heading",
level: 3,
children: [],
},
],
},
],
}
]
}
]
}
These metadata options are related to the navigation tree:
Metadata | Description |
---|---|
nav_max: <number> |
Max heading depth to include in the navigation. Default: 3. |
hidden: <boolean> |
Define whether this page should be included in the navigation tree at all. |
Custom metadata
Any other property in the metadata block is considered custom metadata and will be included in the metadata
object in the template. Values are automatically converted, and if only a name is provided, the data is understood as a flag, having true
as the default value.
<!--
this_is_a_custom_metadata: custom value
another_custom_metadata: 123
custom_flag_option
-->
is available as:
{
this_is_a_custom_metadata: "custom_value",
another_custom_metadata: 123,
custom_flag_option: true,
}
Default data
Shromp makes some useful information available in the template root context by default.
metadata | description |
---|---|
pageTitle |
The title for the page. By default, it's the first H1 in your markdown document. It can be overridden by setting the page_title metadata in your source markdown file. |
mainContent |
This is the source file's markdown content converted to HTML. |
locale |
The content locale. |
version |
The content version, or undefined if versioning is disabled. |
currentFilePath |
The path the current file will be available. Useful for helpers like the one in the previous helper example. |
navigationMenu |
A link tree that can be used to construct a navigation menu, like the one in this site. |
childLinks |
A tree of links hosted under this file's path. Useful for building index pages. |
assets |
This is a list of assets file generated from the assets folder. More details in the next section. |
metadata |
An object containing all metadata from this content, including custom-defined values. |
baseUrl |
Site base URL configured via shromp.toml |
Accessing data in the template
The data above is available in the root context in your template, which can be accessed either directly or using the @root.
prefix.
Here is an example:
<html locale="{{locale}}">
<head>
<title>{{pageTitle}}</title>
</head>
<body>
{{{mainContent}}}
{{#if metadata.show_the_shrimp_train}}
🦐🦐🦐🦐🦐🦐🦐🦐
{{/if}}
</body>
</html>
Assets
You can save your theme's assets in the <theme>/assets
folder, either under styles
, scripts
or images
.
Assets are copied to their respective folders at <public>/assets/
. By default, Shromp will generate a content hash to append to the filenames to prevent wrong caching, and copy the content as-is.
If you want to process styles and script assets further, you can define an asset pipeline that can change the file content before saving it.
The assets will be available in the assets
variable in the template's root context, so they can be inserted in the page correctly. Here is an example:
<html">
<head>
<title>{{pageTitle}}</title>
{{#each assets.styles}}
<link rel="stylesheet" href="{{this}}" type="text/css"/>
{{/each}}
</head>
<body>
{{{mainContent}}}
<footer>
{{#each assets.scripts}}
<script src="{{this}}" defer></script>
{{/each}}
</footer>
</body>
</html>
The assets
variable properties are maps of the original file name and the public file path, to allow lookup for the original name. Sample object:
// assets
{
styles: {
'main.css': '/assets/styles/main.6980c0c18e.css',
'prism.css': '/assets/styles/prism.014b449a00.css'
},
scripts: {
'main.js': '/assets/scripts/main.93cfb2886a.js',
'prism.js': '/assets/scripts/prism.edb4f0d7bc.js'
},
images: {
'favicon.ico': '/assets/images/favicon.daaed75b7a.ico'
}
}
Sometimes you might want assets to be included in a given order (i.e a reset.css before the base.css). For that, you can either add them by name using the asset map, or use the same numbering pattern as the other content files: 0-reset.css
, 1-base.css
;