EJS
CMintS is using EJS as a templating engine for creating layouts, EJS can also be used for the page creation. EJS is a simple templating language that lets you generate HTML markup while writing plain JavaScript. Detailed EJS syntax documentation can be found here, also there is an online playground, to try out the syntax.
Layout
As was mentioned in the themes overview in order to decide which layout to use for the page, a Front Matter "layout" property needs to be used, which falls back to the default layout.
Considering snippet below being theme/layouts/default.ejs
:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/css/main.css">
</head>
<body>
<main>
<%- page.body %>
</main>
</body>
</html>
And snippet below being pages/about.md
:
# about
This is the about page
The request to the /about
page will generate HTML below:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/css/main.css">
</head>
<body>
<main>
<h1>about</h1>
<p>This is the about page</p>
</main>
</body>
</html>
But if you have another layout, which is located in
theme/layouts/home.ejs
, in order to use it you would use Front Matter
ex.:
---
layout: home
---
# Homepage
This page is using home.ejs layout
body
As you might have noticed from the previous example <%- page.body %>
placeholder in the layout ejs is replaced with the actual content, no matter
what page is used(markdown, html or ejs) actual content
of the page is being rendered and replaces the <%- page.body %>
placeholder.
partials
Partials are EJS layout files that can be loaded into the EJS layouts:
<% include partialPath %>
<%- include('partialPath', {key: value}) %>
This can come handy for different layout parts separation and reuse:
<!DOCTYPE html>
<html lang="en-US">
<head>
<% include partials/head %>
<% include partials/meta %>
</head>
<body>
<% include partials/header %>
<main>
<%- page.body %>
</main>
<% include partials/footer %>
</body>
</html>
Considering the example above, we could for example create partial that will be
reusable accross different layouts, ex, consider partials/head.ejs
with
content below:
<link rel="stylesheet" type="text/css" href="/css/main.css">
<script src="/js/main.js" defer></script>
this snippet now can be used and loaded in the layout by just adding <% include partials/head %>
into the layout.
Front Matter
As was already mentioned Front Matter is not only used for the layout selection, but it's also possible to define page properties which can be accessed from the layouts.
Considering a Front Matter below:
---
title: About page
showSidebar: true
---
Data defined in the Front Matter is accessible from the layout files using page object:
<title><%= page.title %></title>
<meta property="og:title" content="EJS">
...
</head>
<body>
...
<%if (page.showSidebar) { %>
<% include partials/sidebar %>
<% } %>
Helpers
There are also some built in helpers in CMintS that can be used out of the box:
Helper | Type | Description |
---|---|---|
page.pathname | Variable | URL path of current page (without locale) |
page.locale | Variable | Locale of the current page |
page.locales | Array | Other locales that current page is available in |
page.urlLocale | Variable | Locale as it's specified in the URL. |
page.markdown.toc | Object | Page's Table Of Content |
i18n.getPageLocales | Function | Get available locales for a specific page |
i18n.href | Function | Generate href and hreflang for path. Check if the target path is available in current language otherwise falls back to default language. |
site.queryPages | Function | Query Array of pages metadata Objects. |
page.pathname
URL path of current page (without locale):
<a <%-i18n.href(item.url)%> <% if (item.url == page.pathname) { %>class="active"<% } %>>
page.locale
Locale of the current page:
<!DOCTYPE html>
<html lang="<%= page.locale %>">
<head>
<title>...</title>
</head>
<body>
...
page.locales
Other locales that current page is available in:
<!DOCTYPE html>
<html lang="<%= page.locale %>">
<head>
...
<!-- og:locale, og:locale:alternate, rel="canonical" rel="alternate" -->
<% for (const locale of page.locales) { %>
<% const localeRegion = site.localeMap[locale] ? site.localeMap[locale].region : locale; %>
<% if (locale == page.locale) { %>
<meta property="og:locale" content="<%= localeRegion %>" />
<link rel="canonical" href="https://<%= site.domain %>/<%= page.pathname %>">
<% } else { %>
<meta property="og:locale:alternate" content="<%= localeRegion %>" />
<link rel="alternate" href="https://<%= site.domain %>/<%= locale %>/<%= page.pathname %>" hreflang="<%= locale %>" />
<% } %>
<% } %>
</head>
<body>
...
page.urlLocale
Locale as it's specified in the URL.
- https://example.com/about
- https://example.com/en/about
- https://example.com/de/about
- https://example.com/es/about
Considering the URL structure above, sometimes you might want to have a
redirection script on pages that doesn't have locale specified in the URL, which
in the current case is https://example.com/about
, this is when
current helper comes handy, for example:
<% if (!page.urlLocale) { %>
<% include redirectionScript %>
<% } %>
page.markdown.toc
page.markdown.toc
Object can be used in the ".ejs" to create a
Table Of Content. The Object is a tree where each node corresponds to a markdown
Heading containing id and title of the heading. If the node contain children,
then all children nodes can be accessible by the node's children
property:
{
"children": [
{
"id": "ejs",
"title": "EJS",
"children": [
{
"id": "layout",
"title": "Layout"
},
{
"id": "body",
"title": "Body"
}
...
So, in order to construct a Table Of Content from that variable an EJS snippet
an .ejs
file like the one below can be used:
<%/* partials/navigations/toc.ejs */%>
<% if (items) { %>
<ul>
<% items.forEach(function(item){ %>
<li>
<% if (item.id) { %>
<a href="#<%= item.id %>"><%= item.text %></a>
<% } %>
<% if (item.children) { %>
<%- include('toc', {items: item.children}) %>
<% } %>
</li>
<% }) %>
</ul>
<% } %>
Considering the example above, the TOC can be generated by simply calling the
.ejs
file and passing the page.markdown.toc
to it, for
example:
<%if (page.
<aside id="toc">
<h2>Table of content</h2>
<%- include('partials/navigations/toc', {items: page.markdown.toc.children}) %>
</aside>
<% } %>
i18n.getPageLocales
Get available locales for a specific page
<% const configPageLocales = i18n.getPageLocales("documentation/getting-started/configuration"); %>
<% const homepageLocales = i18n.getPageLocales("index"); %>
<% if (homepageLocales.includes("de")) { %>
Homepage is available in German
<% } %>
<% if (configPageLocales.includes("es")) { %>
Config page is available in Spanish
<% } %>
i18n.href
Generate href and hreflang for path. Check if the target path is available in current language otherwise falls back to default language.
<a <%-i18n.href("documentation")%> class="button">{get-started[Main button text] Get started}</a>
site.queryPages
Query Array of pages metadata Objects.
Besides of Front Matter page metadata, pages contain pathname
which
is actual pathname of the page and originalPathname
which holds
pathname ignoring permalink
.
<% let docPages = site.queryPages((data) => data.categories &&
data.categories.includes("documentation")) %>
<% docPages.forEach(function(item) { %>
<a <%- i18n.href(item.pathname) %>> <%= item.title %> </a>
<% }); %>