The Solr Ref Guide uses Jekyll to build the HTML version of the site.
How We Use Jekyll
The following sections describe the main features of Jekyll that you will encounter while working with the Solr Ref Guide.
We use a plugin for Jekyll from the Asciidoctor project to integrate Jekyll with Asciidoc formatted content. The source for the plugin is available at https://github.com/asciidoctor/jekyll-asciidoc.
This plugin allows us to use Asciidoctor-style variables with Jekyll.
_config.yml is a global configuration file that drives many of the options used when building the site (particularly in our use of Jekyll).
We have template-ized
_config.yml, so in our use of Jekyll you will find it in
_config.yml.template. This allows us to define some variables during the build and use common Lucene/Solr build parameters (such as project versions).
Front matter for Jekyll is similar to a header that defines the title of the page, and other variables that may be helpful (or even required) when rendering the page.
Every document that will be converted to HTML must include at least the page title at the top of the page. Page titles are defined with a single equal sign (
=) followed by the title that will appear at the top of the page (such as
= Topic of the Page).
Many guides to Jekyll also say that defining the
layout in the front matter is required. However, since we only use one layout for all pages, we have defined this as a default.
The Solr Ref Guide uses the front matter to define some custom attributes on a per-page basis:
Other page-level elements can also be defined, such as an Asciidoctor attribute that should apply only to that page, but are not needed on a regular basis.
The format for adding any parameter to the front matter is to use colons on both sides of the parameter, followed by the value for the parameter (such as
Table of Contents
There are some optional custom attributes that can be defined in pages to affect the Table of Contents presentation in Jekyll:
- Changes how "deep" the TOC will be in terms of nested section/sub-section titles (default =
- If this is
false, then no TOCs will be generated for the page at all. The default is
true, so can usually be left undefined. Example
Layouts define the "look and feel" of each page. Jekyll uses Liquid for page templates.
For our implementation of Jekyll, layouts are found in
We currently use the
_layouts/default.html layout for overall page structure, for almost all pages and
_layouts/page.html for the page-level content.
page.html layout is inserted into the
The main page (
index.html) of the Ref Guide uses the
It also still uses
_layouts/page.html for the page-level content.
This is done because
index.html has some special formatting and rules for how to define the page.
Include files are (usually) small HTML files that are pulled into a layout when a page is being built.
They are Liquid templates that define an area of the page.
This allows flexibility across layouts - all pages can have the same header without duplicating code, but different pages could have different menu options.
Include files that we use define the top navigation, the page header, and the page footer.
For our implementation of Jekyll, include files are found in
Data files include data such as lists that should be included in each page.
The left-hand navigation menu is an example of a data file.
However, in our build, the navigation is built from the
page-children hierarchies defined on parent pages.
For our implementation of Jekyll, data files are found in
Asciidoctor Slim Templates
Jekyll creates all of the page elements we do not define in each
.adoc file: the header, footer, top nav, sidebar nav, and other parts of the page that we don’t worry about as we write the content of a page.
Asciidoctor converts the content in each
.adoc file into HTML and inserts it into the Jekyll page layout we have defined (see Layouts) to make the individual HTML files that make up the Ref Guide.
While we have unlimited control over styling page content via CSS, without creating custom Asciidoctor-specific plugins or templates there is little out-of-the-box control over the elements, classes, etc. that make up the HTML pages.
In order to better support HTML5, we have customized Asciidoc’s default conversion with templates found in the
_templates directory. These templates use Slim as the template engine.
Since these templates dictate the very structure of the HTML of our content, customizing these should only be attempted in rare instances and with extensive testing for unforeseen impacts.
The HTML files include Bootstrap (v4.1.3 as of April 2020, see
_includes/head.html to confirm the Bootstrap version currently being used), so all of the components of Bootstrap are available.
The design of the Ref Guide makes extensive use of Bootstrap classes to layout the page via the Liquid templates and our customized Asciidoctor templates.
When we want to use additional components of Boostrap that require specific HTML constructs, we must define those within the page content itself (using either
<div> elements in the content or with Asciidoctor’s roles, discussed in the section).
Asciidoctor helpfully provides a way to define custom
<div> classes in
.adoc files, as long as we understand how to use it.
Asciidoctor does not call these "divs" or "classes", but instead "roles". We can give any content a role - to images, content blocks (such as
[NOTE], etc.), even a word in the middle of a sentence.
Because roles are so flexible, they only apply to the thing - the word, content block, image, etc. - they are directly applied to. This means that if we want an entire section of content to be given a specific role in the HTML (i.e., enclosed in a
<div>), then we need to put the content in a block.
For more on Roles in Asciidoctor, see Role in the Asciidoctor User Guide.
Creating Tabbed Sections
Hopefully a little bit of background on roles is helpful to understanding the rest of what we’ll do to create a tabbed section in a page.
See the Bootstrap docs on nav tabs for details on how to use tabs and pills with Bootstrap. As a quick overview, tabs in Bootstrap are defined like this:
<ul class="nav nav-pills">
<li class="active"><a data-toggle="pill" href="#sec1">Section 1</a></li>
<li><a data-toggle="pill" href="#sect2">Section 2</a></li>
<div id="sect1" class="tab-pane active">
<div id="sect2" class="tab-pane">
<p>Some other content.</p>
|1||This section creates an unordered list with a line item for each tab. The |
class parameters are what tell Bootstrap how to render the content.
|2||Note the class defined here: |
<div class="tab-content">. This defines that what follows is the content that will make up the panes of our tabs. We will need to define these in our document.
|3||In our document, we need to delineate the separate sections of content that will make up each pane.|
Define an "open block" (an unformatted content block), and give it the role
.dynamic-tabs. An open block is defined by two hyphens on a line before the content that goes in the block, and two hyphens on a line after the content to end the block. We give a block a role by adding a period before the role name, like this:
The stuff we'll put in the tabs will go here.
- Next we need to define the content for the tabs between the open block delimiters.
- We enclose each tab pane in another type of block, and "example" block. This allows us to include any kind of content in the block and be sure all of the various types of elements (heading, text, examples, etc.) are included in the pane.
- We give the example block another role,
tab-pane, and we must make sure that each pane has a unique ID. We assign IDs with a hash mark (\#) followed by the ID value (
- We also need to define a label for each tab. We do this by adding another role,
tab-label to the content we want to appear as the name of the tab.
In the end one pane will look like this:
|1||When we define the example block with |
[example], it’s followed by
.tab-pane#sect1 as the class (each class separated by a period
.) and the ID defined in the tab definition earlier. Those will become the classes (
class="tab-pane active") and ID (
id="sect1") in the resulting HTML.
|2||Example blocks are delimited by 4 equal signs (|
====) before and after the enclosed content.
|3||The words "Section 1" will appear in the HTML page as the label for this tab.|
[example.tab-pane#id] sections for each tab, until you finally end up with something that looks like this:
Building the HTML Site
An Ant target
ant build-site when run from the
solr/solr-ref-guide directory will build the full HTML site (found in
This target builds the navigation for the left-hand menu, and converts all
.adoc files to
.html, including navigation and inter-document links.
Building the HTML has several dependencies that will need to be installed on your local machine. Review the
README.adoc file in the
solr/solr-ref-guide directory for specific details.
Using the Gradle build does not require any local dependencies. Simply use
./gradlew buildSite to generate the HTML files using Gradle (these will be found in
When you run
ant build-site to build the HTML, several additional validations occur during that process. See
solr-ref-guide/tools/CheckLinksAndAnchors.java for details of what that tool does to validate content.