Add a Navbar
‘Minima’, the default Jekyll theme, uses the list header_pages in _config.yml (site.header_pages) to render its navbar:
header_pages:
- blog.html
- about.md
This works for a small set of links, but starts to bother when for large content driven sites.
In the absense of the
header_pageslist, Minima lists all site pages found under the root folder in the header navigation bar.
See_includes\header.html
Modifying this is a non-trivial exercise, which explains the proliferation of Jekyll themes.
My search led me to Feeling Responsive as the closest to what I had in mind.
I might switch over yet, but meanwhile it’s tinker time…
Target
First create the _data\navbar.yml
navbar:
- title: Personal
page: personal/index.md
subfolderitems:
- page: Blog
url: /personal/blog.html
- page: DMS Memorial
url: /personal/dms-memorial.html
- title: Technology
subfolderitems:
- page: Architecture
url: /technology/architecture.html
- page: Web Development
url: /technology/web-development.html
- title: About
url: /about/
Onto the navbar
The Liquid template under the example produces an unordered list – useful for confirmation…
{% for item in site.data.samplelist.toc %}
<h3>{{ item.title }}</h3>
<ul>
{% for entry in item.subfolderitems %}
<li><a href="{{ entry.url }}">{{ entry.page }}</a></li>
{% endfor %}
</ul>
{% endfor %}
But you need to stitch the CSS classes for navbar display.
Going with Bootswatch Cerulean, an open-source collection of themes built over Bootstrap.
_includes\head.html
Copy it over from the Minima gem location (bundle info --path minima), to the project _includes\ folder.
- Import the Navbar Cerulean CSS classes and the Bootstrap Javascript for the drop down menu (defer skips the need to put the script before the closing
</body>tag (in the footer).
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.8/cerulean/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous" defer></script>
_includes\header.html
Replace the copy in the project _includes with the content below:
Bootstrap has a responsive .container class that provides a classic desktop width on widescreen monitors inplace of Minima’s constrained .wrapper central column.
Replacing .wrapper in both header.html and _layouts/default.html alllows for a comfortable width:
<main class="page-content" aria-label="Content">
<div class="container">
{{ content }}
</div>
</main>
The sticky-top class in <header> tag keeps the header from scrolling off the screen.
<header class="site-header sticky-top" role="banner"> <!-- 'sticky-top' keeps navbar locked to the top of browser viewport -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<!-- Bootstrap .container-fluid: stretches navbar to 100% width, pushing links to outer edges.
Minima .wrapper constrains width to a central column.
.container class gives a nice middle-path desktop width -->
<div class="container d-flex align-items-center justify-content-between w-100">
<a class="navbar-brand" rel="author" href="{{ '/' | relative_url }}">
{{ site.title | escape }}
</a>
<!-- Mobile Hamburger Toggle -->
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<!-- Links Wrapper -->
<div class="collapse navbar-collapse justify-content-end" id="navbarNavDropdown">
<ul class="navbar-nav">
{% for item in site.data.navbar.navbar %}
{% if item.subfolderitems and item.subfolderitems.size > 0 %}
{% assign dropdown_active = false %}
{% for entry in item.subfolderitems %}
{% if entry.url == page.url %}
{% assign dropdown_active = true %}
{% endif %}
{% endfor %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle {% if dropdown_active %}active{% endif %}"
href="#"
id="navbarDropdown{{ forloop.index }}"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false"
{% if dropdown_active %}aria-current="page"{% endif %}>
{{ item.title }}
</a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown{{ forloop.index }}">
{% for entry in item.subfolderitems %}
<li>
<a class="dropdown-item {% if entry.url == page.url %}active{% endif %}" href="{{ entry.url | relative_url }}">
{{ entry.page }}
</a>
</li>
{% endfor %}
</ul>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link {% if item.url == page.url %}active{% endif %}" href="{{ item.url | relative_url }}" {% if item.url == page.url %}aria-current="page"{% endif %}>
{{ item.title }}
</a>
</li>
{% endif %}
{% endfor %}
</ul>
</div>
</div>
</nav>
</header>