Too many updates to track.

Moved the 'docs' section down and eliminated the folder. It wasn't
necessary.  Built out the Section.html file, and started work on
the SASS.  Having a hell of a time getting the side panels to
animate the way they do for adidoks, but I'm sure I'll figure it out
eventually.
This commit is contained in:
Elf M. Sternberg 2022-06-08 20:50:30 -07:00
parent 5517b77fad
commit 58cf0c9cbd
19 changed files with 557 additions and 115 deletions

View File

@ -1,19 +1,15 @@
+++
title = "Brains!!!"
title = "Elf's Notes"
description = "This is Elf Sternberg's brain dump of notes about various software things he knows. If you find it useful, good! Just be aware that this site is probably a bit random, as it consists of explanations, snippets, and recipes for how I do things. It's meant to be a guide from a past version of myself to explain things to a future version that may have forgotten."
date = 2025-05-01T18:00:00+00:00
updated = 2021-05-01T18:00:00+00:00
template = "index.html"
# The homepage contents
[extra]
lead = "This is Elf Sternberg's brain dump of notes about various software things he knows. If you find it useful, good! Just be aware that this site is probably a bit random, as it consists of explanations, snippets, and recipes for how I do things. It's meant to be a guide from a past version of myself to explain things to a future version that may have forgotten."
# Menu items
[[extra.menu.main]]
name = "Blog"
section = "blog"
url = "https://elfsternberg.com"
weight = 20
[[extra.list]]
title = "Zola"
url="/docs/zola"
content = 'This site is hosted with <a href="https://getzola.org">Zola</a>, a static site generator written in Rust.'
[taxonomies]
documentation=["Reference"]
+++
This is Elf Sternberg's brain dump of notes about various software things he
knows. If you find it useful, good! Just be aware that this site is probably a
bit random, as it consists of explanations, snippets, and recipes for how I do
things. It's meant to be a guide from a past version of myself to explain things
to a future version that may have forgotten.

View File

@ -3,7 +3,7 @@ title = "Git Notes"
description = "Basic documentation of Git"
date = 2022-04-27T18:00:00+00:00
updated = 2022-04-27T18:00:00+00:00
template = "docs/section.html"
template = "section.html"
sort_by = "weight"
weight = 6
draft = false

View File

@ -3,7 +3,7 @@ title = "Zola Cookbook"
description = "Snippets I've developed that I want to keep"
date = 2022-04-27T18:00:00+00:00
updated = 2022-04-27T18:00:00+00:00
template = "docs/section.html"
template = "section.html"
sort_by = "weight"
weight = 5
draft = false
@ -62,6 +62,6 @@ Zola shortcode to import the macro template into Markdown and start the render:
Invocation in Markdown file, providing the data source:
```
{{ definition_list(source="@/docs/zola/definitions.json") }}
{{ definition_list(source="@/docs/zola/definitions.json") }}
```

View File

@ -3,7 +3,7 @@ title = "Zola"
description = "Zola is a static site generator"
date = 2025-05-01T18:00:00+00:00
updated = 2021-05-01T18:00:00+00:00
template = "docs/section.html"
template = "section.html"
sort_by = "weight"
weight = 4
draft = false
@ -13,19 +13,55 @@ categories=["Web Development", "Static Site Generation", "Zola"]
+++
[Zola](https://getzola.org) is a static site generator written in
[Rust](../rust). It builds an entire web page out of a structured markdown
collection and a collection of HTML templates. The templating language is called
[Tera](https://tera.netlify.app).
Zola is a single binary capable of assembling the website out of a collection of
templates, SASS files, static data (including CSS if you're not into SASS), and
markdown files. The Markdown files create the structure of the website as a
series of folders.
[Rust](../rust). It is a single binary that builds an entire web site out of a
collection of markdown documents in a folder-structured hierarchy, using a
corresponding collection of HTML templates, which in turn use a corresponding
collection of SASS collection and a collection of HTML templates. The templating
language is called [Tera](https://tera.netlify.app).
If you need anything else (Typescript built into Javascript, templates other
than Zola's internal, static file conversion, etc.), you'll need separate
toolchains for those.
## Mental Model for Zola
A website built with Zola originates with the `content/` folder. Inside that
folder, every markdown document and every folder creates a corresponding page in
the constructed website. There are only *two* models you have to understand
Zola: *sections* and *pages*.
A *section* is a folder with a file named `_index.md` in it; note the
underscore, which signifies the section definition file. For these documents, a
[`Section` model](#section) is the default context object received by the
template. Each markdown document in the same folder, and each folder immediately
underneath this folder that has an `index.md` folder (note the lack of
underscore) is a *page* and receives the [`Page` model](#page) as the default
context.
Every markdown document has two parts: a frontmatter block, written in TOML, and
the content, written in Markdown. Whether a `section` or `page` context is
passed by default, if there is content the `.content` field will be the HTML
output of the markdown in the document.
Every folder, whether containing an `_index.md` or `index.md` file, can contain
co-located assets such a images, videos, and even Javascript. These will be
found in the `.assets` field of the context object (the use of co-located assets
in why a folder can be a page).
Whether a `Page` or a `Section`, the corresponding context object provides means
by which every template has access to the metadata (and even the content!) of
every other markdown document, arranged in the hierarchy described in the
`content` folder.
### Recommendation
1. Design your document hierarchy first.
2. Construct your content folder to support that hierarchy.
3. Build the `Section` template for the home page.
4. Build the `Section` template for your level two sections
5. Build the corresponding `Page` templates.
6. Worry about Sass afterward
## Running Zola
Zola has only a few commands:
@ -66,7 +102,7 @@ underscore prefix) is considered a *page*. This allows content writers to
supply additional assets, such as images or data files, along with the contents
of the page.
## The Templating Languagae
## The Templating Language
The Tera templating language looks a lot like Django's, or for that matter any
number of templating languages. Every page generated with Tera receives a
@ -139,7 +175,7 @@ Conditional statements are managed with `if/is ... else ... endif`
The list of `is` tests that are shipped with Zola are:
{{ definition_list(source="docs/zola/predicates.json") }}
{{ definition_list(source="zola/predicates.json") }}
#### `for`
@ -222,7 +258,7 @@ variable. There are a few basic operations and filters available, however:
**Math And Logic Expressions**:
{{ definition_list(source="docs/zola/expressions.json") }}
{{ definition_list(source="zola/expressions.json") }}
**Concatenation**:
@ -244,31 +280,31 @@ An entire chunk of HTML can be filtered by:
The filters provided are:
{{ definition_list(source="docs/zola/filters.json") }}
{{ definition_list(source="zola/filters.json") }}
### Functions
Only a few functions provide ad-hoc expressions in-line with template
interpretation.
- `range`: Generates an array of numbers.
- `now`: Generates the current datetime
- `get_random`: Generates a random number
- `get_env`: Returns an environment variable
- `get_page`: Returns a the content of a page in the Zola content folder
- `get_section`: Returns the content of a Zola section (an `_index.md`) file as an
- `range(end=n, start=0, [step_by=n])`: Generates an array of numbers.
- `now(datetime, utc)`: Generates the current datetime.
- `get_random(end=n, [start=0])`: Generates a random number
- `get_env(name="s", default="d")`: Returns an environment variable
- `get_page(path="p")`: Returns a the content of a page in the Zola content folder
- `get_section(path="p")`: Returns the content of a Zola section (an `_index.md`) file as an
object.
- `get_taxonomy_url`: Returns the URL of a Zola taxonomy index
- `get_url`: Gets the generated URL for a document in the Zola content folder
- `get_image_metadata`: Gets the metadata for an image in Zola's static folder
- `load_data`: (Zola) Loads static data from a file. Understands TOML, JSON, CSV and
- `get_taxonomy_url(kind="taxonomy", name=page.taxonomies.category)`: Returns the URL of a Zola taxonomy index
- `get_url(path="p")`: Gets the generated URL for a document in the Zola content folder
- `get_image_metadata(path="p")`: Gets the metadata for an image in Zola's static folder
- `load_data(path="p")`: (Zola) Loads static data from a file. Understands TOML, JSON, CSV and
BibTeX. Takes either `path=` or `url=` (!) as an argument.
- `resize_image`: (Zola) Takes an image, resizes the image, and provides a link to the
resized image.
- `resize_image(path, width, height, op, format, quality)`: (Zola) Takes an
image, resizes the image, and provides a link to the resized image.
## Zola Content
### Sections
### Sections {#section}
In Zola, every folder under `./content/` (including that folder itself) is
potentially a _section_. Sections are basically Zola's version of the WWW
@ -315,7 +351,7 @@ available to the template:
- `assets`: An array of assets available in this section.
- `ancestors`: An array of parent paths, with the root being the last one.
### Pages
### Pages {#page}
A page is _either_ a markdown file within the same folder as its section, or it
is in a subfolder with a file named `index.md` (note the lack of prefix
@ -339,7 +375,7 @@ The following items can appear in the TOML header of a page:
- `[taxonomies]`: The taxonomies for this page
- `[extra]`: Your own extra data
Pages have the following information in their context:
Pages derive the following information in their context:
- `content`: The markdown content from the page's file
- `title`: The title, if present in the TOML block

226
sass/index.scss Normal file
View File

@ -0,0 +1,226 @@
@import "design/_normalize";
@import "design/_scales";
@import "design/_typography";
@import "design/fonts/_nunito";
@import "design/fonts/_sauna_mono";
:root {
--default-font-size: var(--step-0);
--background-color: #ffffff;
--border-color: #e9ecef;
--text-color: #1f000d;
--header-size: calc(1.5 * var(--step-0) + 2 * var(--space-3xs));
}
:root {
font-size: var(--default-font-size);
font-family: "Nunito", sans-serif;
}
.toggle-dark {
display: none;
}
body {
padding-top: var(--header-size);
font-size: var(--default-font-size);
font-family: "Nunito", sans-serif;
font-weight: 400;
}
@mixin fixed-top {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
}
.container {
max-width: 1044px;
width: 100%;
padding: 0 var(--space-xs) 0 var(--space-xs);
margin-right: auto;
margin-left: auto;
}
.hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
margin-left: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.navbar {
display: flex;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
padding-top: calc(0.5 * var(--space-3xs));
padding-bottom: calc(0.5 * var(--space-3xs));
background-color: var(--background-color);
opacity: 0.95;
border-bottom: 1px solid var(--border-color);
@include fixed-top();
.container {
display: flex;
flex-wrap: inherit;
align-items: center;
justify-content: space-between;
}
.btn {
cursor: pointer;
display: inline-block;
font-weight: 400;
line-height: 1.5;
color: #1d2d35;
text-align: cent er;
vertical-align: middle;
user-select: none;
background-color: transparent;
border: 1px solid transparent;
font-size: 1rem;
border-radius: 0.25rem;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out,
border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
&:focus {
box-shadow: none;
}
}
.brand {
font-size: var(--step-1);
margin-right: var(--space-s);
font-weight: 700;
color: var(--text-color);
text-decoration: none;
&:visited,
&:hover {
color: var(--text-color);
text-decoration: none;
}
}
form {
font-size: var(--step-0);
flex-grow: 1;
margin-left: var(--space-2xl);
margin-right: var(--space-s);
input {
appearance: none;
background-clip: padding-box;
background: #f8f9fa;
border-radius: 0.25rem;
border: 0;
color: #1d2d35;
line-height: 1.5;
padding: var(--space-3xs) var(--space-l) var(--space-3xs) var(--space-3xs);
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
width: 100%;
}
}
.navbar-nav {
font-size: var(--step-1);
align-items: center;
display: flex;
list-style: none;
gap: var(--space-xs);
margin-bottom: 0;
& > * {
line-height: 1.5;
vertical-align: middle;
}
}
}
@mixin toc-sticky {
max-width: 100%;
position: sticky;
top: var(--space-xl);
height: calc(100vh - var(--space-xl));
z-index: 900;
&:hover .scrollable-sidebar {
scrollbar-color: #e9ecef #fff;
}
.scrollable-sidebar {
scrollbar-width: thin;
scrollbar-color: #fff #fff;
display: block;
width: auto;
overflow-y: scroll;
padding-bottom: 4rem;
}
}
.main {
display: flex;
position: relative;
flex-wrap: nowrap;
ul {
padding-left: 0;
padding-bottom: var(--step--1);
list-style: none;
ul {
padding-left: var(--space-s);
list-style: disc;
}
}
.left-sidebar {
@include toc-sticky();
font-size: 80%;
order: 0;
flex: 0 1 auto;
width: 25%;
padding-right: var(--space-2xs);
border-right: 1px solid var(--border-color);
}
.docs-toc {
@include toc-sticky();
font-size: 66.666%;
order: 2;
flex: 0 0 auto;
width: 18.75%;
border-left: 1px solid var(--border-color);
padding-left: var(--space-2xs);
nav > ul {
& > li:not(:first-child) {
margin-top: var(--space-3xs);
border-top: 1px dashed #e9ecef;
}
& > li:not(:first-child) {
padding-top: var(--space-3xs);
}
ul {
padding-bottom: 0;
}
}
}
article {
order: 1;
padding: 0 var(--space-s) var(--space-m-l) var(--space-s);
flex: 0 0 auto;
width: 56.25%;
}
}

View File

@ -1,26 +1,27 @@
{%- import 'macros/font_preloads.html' as font_preloads -%}
{%- import 'macros/stylesheets.html' as stylesheets -%}
{%- import 'macros/header.html' as header -%}
{%- import 'macros/footer.html' as footer -%}
<!DOCTYPE html>
<html lang="{{ config.extra.language_code | default(value="en-US") }}">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
{{ font_preloads::preloads() }}
{{ stylesheets::stylesheets() }}
{% block styles %}
<link rel="stylesheet" href="{{ get_url(path="index.css") | safe }}">
{% endblock %}
{% block seo %}{% endblock %}
</head>
{% block body %}{% set page_class="home" %}{% endblock body %}
<body class="{{ page_class }}">
{% block header %}
{{ header::header(current_section="/") }}
{% endblock header %}
<body>
{% block body %}
{% include "components/sitebar.html" %}
{% block content %}
{% block header %}
{% endblock header %}
{% block content %}{% endblock content %}
{% block footer %}
{{ footer::footer() }}
{% endblock footer %}
{% block main %}
{% endblock main %}
{% endblock content %}
{% block footer %}
{% endblock footer %}
{% endblock body %}
</body>
</html>

View File

@ -0,0 +1,39 @@
{#
The left sidebar for large document sections navigation for topics that
have child pages. This sidebar contains links to all the pages, and all their
level-one headers, for all the content in the section.
#}
<nav class="left-sidebar" aria-label="Site navigation">
{% set index = get_section(path="_index.md") %}
<h3>{{ index.title }}</h3>
<ul class="notes">
{% for subsection in index.subsections %}
{% set active = "" %}
{% if current_url == subsection.permalink %}
{% set active = " active" %}
{% endif %}
<li>
<h3><a class="note-link {{ active }}" href="{{ subsection.permalink | safe }}">
{{ subsection.title }}
</h3>
{% set pagecount = subsection.pages | length %}
{% if pagecount > 0 %}
<ul>
{% for page in subsection.pages %}
<li><a class="note-link" href="{{ page.permalink | safe }}">{{ page.title }}</a></li>
{% endfor %}
</ul>
{% else %}
<ul>
{% for dest in subsection.toc %}
<li><a class="note-link" href="{{ dest.permalink | safe }}">{{ dest.title }}</a></li>
{% endfor %}
<ul>
{% endif %}
</li>
{% endfor %}
<ul>
</nav>

View File

@ -0,0 +1,42 @@
{#
The left sidebar for singleton pages provides navigation is for topics that
have no child pages. This sidebar contains only links to all the level zero
and level one headers for all content in the site. It should only be used for
document section that have only a section definition file, `_index.md`.
#}
<div class="left-sidebar" aria-label="Site navigation">
<nav class="scrollable-sidebar">
{% set index = get_section(path="_index.md") %}
<h3>{{ index.title }}</h3>
<ul class="notes">
{% for s in index.subsections %}
{% set subsection = get_section(path=s) %}
{% set active = "" %}
{% if current_url == subsection.permalink %}
{% set active = " active" %}
{% endif %}
<li>
<a class="note-link {{ active }}" href="{{ subsection.permalink | safe }}">
{{ subsection.title }}
</a>
{% set pagecount = subsection.pages | length %}
{% if pagecount > 0 %}
<ul>
{% for page in subsection.pages %}
<li><a class="note-link" href="{{ page.permalink | safe }}">{{ page.title }}</a></li>
{% endfor %}
</ul>
{% else %}
<ul>
{% for dest in subsection.toc %}
<li><a class="note-link" href="{{ dest.permalink | safe }}">{{ dest.title }}</a></li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
<ul>
</nav>
</div>

View File

@ -0,0 +1,24 @@
{% if section %} {% set toc = section.toc %} {% else %} {% set toc = page.toc %} {% endif %}
<div class="docs-toc" aria-label="On-page navigation">
<div class="scrollable-sidebar">
<div class="page-links">
<h4>On this page</h3>
<nav id="TableOfContents">
<ul>
{% for h1 in toc %}
<li>
<a href="{{ h1.permalink | safe}}">{{ h1.title }}</a>
{% if h1.children %}
<ul>
{% for h2 in h1.children %}
<li><a href="{{ h2.permalink | safe }}">{{ h2.title }}</a></li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
</nav>
</div>
</div>
</div>

View File

@ -0,0 +1,103 @@
<header class="navbar">
<div class="container">
<label class="menu-icon" for="menu-btn"><span class="navicon"></span></label>
<a class="brand" href="{{ config.base_url | safe }}"
>{{ config.title | default(value="Elf M. Sternberg's Notebook") }}</a
>
<form class="search">
<input
id="userinput"
class="search-form"
type="search"
placeholder="Search notes..."
aria-label="Search notes..."
autocomplete="off"
/>
<div id="suggestions"></div>
</form>
<ul class="navbar-nav">
<li class="nav-item">
<button id="mode" class="btn" type="button" aria-label="Toggle mode">
<span class="toggle-dark"
><svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="feather feather-moon"
>
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg
></span>
<span class="toggle-light"
><svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="feather feather-sun"
>
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg
></span>
</button>
</li>
<li class="nav-item">
<a class="nav-link" href="https://twitter.com/elfsternberg"
><svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="feather feather-twitter"
>
<path
d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"
></path></svg
><span class="hidden">Twitter</span></a
>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/elfsternberg"
><svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="feather feather-github"
>
<path
d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"
></path></svg
><span class="hidden">GitHub</span></a
>
</li>
</ul>
</div>
</header>

View File

@ -7,9 +7,7 @@
{% block content %}
<div class="container" role="document">
<div class="main">
<div class="notes-sidebar">
Sidebar!
</div>
{% include "components/left-sidebar-singleton.html" %}
<article>
<h1 class="text-center">{{ section.title }}</h1>
<div class="text-center">{{ section.content | safe }}</div>

View File

@ -1,34 +1,23 @@
{% extends "base.html" %}
{% block content %}
<div class="container" role="document">
<div class="content">
<section class="section container-fluid mt-n3 pb-3">
<div class="row justify-content-center">
<div class="col-lg-12 text-center">
<h1>{{ section.title | default(value="Elf's Notes") }}</h1>
</div>
<article class="text-article">
<p class="lead">
{{ section.extra.lead | default(value="You need to add some content") | safe }}
</p>
</article>
</div>
</section>
</div>
</div>
<section class="section">
<h1>{{ section.title | default(value="Elf's Notes") }}</h1>
<article class="text">
{{ section.content | safe }}
</article>
</section>
<div class="container topic-list">
<h2>Topics Available:</h2>
<section class="section">
<div class="topic-cards">
{% if section.extra.list %} {% for val in section.extra.list %}
<div class="topic-card">
<h3><a href="{{val.url}}">{{ val.title }}</a></h3>
<p>{{ val.content | safe }}</p>
</div>
{% endfor %} {% endif %}
</div>
</section>
</div>
<section class="subject-list">
<h2>Subjects Available:</h2>
<div class="topic-cards">
{% for subsection_path in section.subsections %}
{% set subsection = get_section(path=subsection_path) %}
<div class="topic-card">
<h3><a href="{{subsection.permalink}}">{{ subsection.title }}</a></h3>
<p>{{ subsection.description | default(value="No description provided") }}</p>
</div>
{% endfor %}
</div>
</section>
{% endblock %}

View File

@ -2,27 +2,15 @@
{% extends "base.html" %}
{% block body %}
{% if section.extra.class %}
{% set page_class = section.extra.class %}
{% else %}
{% set page_class = "page list" %}
{% endif %}
{% endblock body %}
{% block content %}
<div class="wrap container" role="document">
<div class="content">
<div class="row justify-content-center">
<div class="col-md-12 col-lg-10 col-xxl-8">
<article class="text-article">
<div class="page-header">
<h1>{{ section.title }}</h1>
</div>
{{ section.content | safe }}
</article>
</div>
</div>
<div class="container" role="document">
<div class="main">
{% include "components/left-sidebar-singleton.html" %}
{% include "components/right-sidebar.html" %}
<article>
<h1 class="text-center">{{ section.title }}</h1>
<div class="text-center">{{ section.content | safe }}</div>
</article>
</div>
</div>
{% endblock content %}