diff --git a/content/_index.md b/content/_index.md index 2bf29bd..43738be 100644 --- a/content/_index.md +++ b/content/_index.md @@ -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 Zola, 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. diff --git a/content/docs/git/_index.md b/content/git/_index.md similarity index 98% rename from content/docs/git/_index.md rename to content/git/_index.md index 66eb2ae..65d983e 100644 --- a/content/docs/git/_index.md +++ b/content/git/_index.md @@ -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 diff --git a/content/docs/zola-cookbook/_index.md b/content/zola-cookbook/_index.md similarity index 93% rename from content/docs/zola-cookbook/_index.md rename to content/zola-cookbook/_index.md index 2177a31..c3d27d5 100644 --- a/content/docs/zola-cookbook/_index.md +++ b/content/zola-cookbook/_index.md @@ -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") }} ``` diff --git a/content/docs/zola/_index.md b/content/zola/_index.md similarity index 79% rename from content/docs/zola/_index.md rename to content/zola/_index.md index 6ed528f..c6f3b2c 100644 --- a/content/docs/zola/_index.md +++ b/content/zola/_index.md @@ -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 diff --git a/content/docs/zola/expressions.json b/content/zola/expressions.json similarity index 100% rename from content/docs/zola/expressions.json rename to content/zola/expressions.json diff --git a/content/docs/zola/expressions.yaml b/content/zola/expressions.yaml similarity index 100% rename from content/docs/zola/expressions.yaml rename to content/zola/expressions.yaml diff --git a/content/docs/zola/filters.json b/content/zola/filters.json similarity index 100% rename from content/docs/zola/filters.json rename to content/zola/filters.json diff --git a/content/docs/zola/filters.yaml b/content/zola/filters.yaml similarity index 100% rename from content/docs/zola/filters.yaml rename to content/zola/filters.yaml diff --git a/content/docs/zola/predicates.json b/content/zola/predicates.json similarity index 100% rename from content/docs/zola/predicates.json rename to content/zola/predicates.json diff --git a/content/docs/zola/predicates.yaml b/content/zola/predicates.yaml similarity index 100% rename from content/docs/zola/predicates.yaml rename to content/zola/predicates.yaml diff --git a/sass/index.scss b/sass/index.scss new file mode 100644 index 0000000..7d20386 --- /dev/null +++ b/sass/index.scss @@ -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%; + } +} + diff --git a/templates/base.html b/templates/base.html index e975818..5ba5bb9 100644 --- a/templates/base.html +++ b/templates/base.html @@ -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 -%} -{{ font_preloads::preloads() }} -{{ stylesheets::stylesheets() }} +{% block styles %} + +{% endblock %} + +{% block seo %}{% endblock %} -{% block body %}{% set page_class="home" %}{% endblock body %} - - {% block header %} - {{ header::header(current_section="/") }} - {% endblock header %} + + {% 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 %} diff --git a/templates/components/left-sidebar-largedoc.html b/templates/components/left-sidebar-largedoc.html new file mode 100644 index 0000000..4b21a0d --- /dev/null +++ b/templates/components/left-sidebar-largedoc.html @@ -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. +#} + + diff --git a/templates/components/left-sidebar-singleton.html b/templates/components/left-sidebar-singleton.html new file mode 100644 index 0000000..c632d80 --- /dev/null +++ b/templates/components/left-sidebar-singleton.html @@ -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`. +#} + + diff --git a/templates/components/right-sidebar.html b/templates/components/right-sidebar.html new file mode 100644 index 0000000..bf1299e --- /dev/null +++ b/templates/components/right-sidebar.html @@ -0,0 +1,24 @@ +{% if section %} {% set toc = section.toc %} {% else %} {% set toc = page.toc %} {% endif %} +
+
+ +
+
diff --git a/templates/components/sitebar.html b/templates/components/sitebar.html new file mode 100644 index 0000000..31da7b9 --- /dev/null +++ b/templates/components/sitebar.html @@ -0,0 +1,103 @@ + diff --git a/templates/docs/section.html b/templates/docs/section.html index 01b5530..01448d1 100644 --- a/templates/docs/section.html +++ b/templates/docs/section.html @@ -7,9 +7,7 @@ {% block content %}
-
- Sidebar! -
+ {% include "components/left-sidebar-singleton.html" %}

{{ section.title }}

{{ section.content | safe }}
diff --git a/templates/index.html b/templates/index.html index cde2fd6..3535b7b 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,34 +1,23 @@ {% extends "base.html" %} {% block content %} -
-
-
-
-
-

{{ section.title | default(value="Elf's Notes") }}

-
-
-

- {{ section.extra.lead | default(value="You need to add some content") | safe }} -

-
-
-
-
-
+
+

{{ section.title | default(value="Elf's Notes") }}

+
+ {{ section.content | safe }} +
+
-
-

Topics Available:

-
-
- {% if section.extra.list %} {% for val in section.extra.list %} -
-

{{ val.title }}

-

{{ val.content | safe }}

-
- {% endfor %} {% endif %} -
-
-
+
+

Subjects Available:

+
+ {% for subsection_path in section.subsections %} + {% set subsection = get_section(path=subsection_path) %} +
+

{{ subsection.title }}

+

{{ subsection.description | default(value="No description provided") }}

+
+ {% endfor %} +
+
{% endblock %} diff --git a/templates/section.html b/templates/section.html index 5dbe0d5..59ec56f 100644 --- a/templates/section.html +++ b/templates/section.html @@ -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 %} -
-
-
-
-
- - {{ section.content | safe }} -
-
-
+
+
+ {% include "components/left-sidebar-singleton.html" %} + {% include "components/right-sidebar.html" %} +
+

{{ section.title }}

+
{{ section.content | safe }}
+
{% endblock content %}