First check-in of "Elf's Notes"
This is the initial checkin of my notes site. It's mostly a cheat-sheet format, with two different strands: 1. A reference sheet of commands in the order that matters to *me*, i.e. the things I use most, or forget most often, appear at the top of the documents. 2. A collection of recipes for getting common tasks completed. Basically, my cookbook of things that I care about
This commit is contained in:
commit
0c8765a514
|
@ -0,0 +1,16 @@
|
||||||
|
# The URL the site will be built for
|
||||||
|
base_url = "https://elfsternberg.com/notes"
|
||||||
|
|
||||||
|
# Whether to automatically compile all Sass files in the sass directory
|
||||||
|
compile_sass = true
|
||||||
|
|
||||||
|
# Whether to build a search index to be used later on by a JavaScript library
|
||||||
|
build_search_index = true
|
||||||
|
|
||||||
|
[markdown]
|
||||||
|
# Whether to do syntax highlighting
|
||||||
|
# Theme can be customised by setting the `highlight_theme` variable to a theme supported by Zola
|
||||||
|
highlight_code = true
|
||||||
|
|
||||||
|
[extra]
|
||||||
|
# Put all your custom variables here
|
|
@ -0,0 +1,19 @@
|
||||||
|
+++
|
||||||
|
title = "Elf's Notes"
|
||||||
|
|
||||||
|
# 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.'
|
||||||
|
+++
|
|
@ -0,0 +1,177 @@
|
||||||
|
+++
|
||||||
|
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 = "section.html"
|
||||||
|
sort_by = "weight"
|
||||||
|
weight = 4
|
||||||
|
draft = false
|
||||||
|
+++
|
||||||
|
|
||||||
|
# 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).
|
||||||
|
|
||||||
|
## Running Zola
|
||||||
|
|
||||||
|
- `zola init` - Starts a new Zola project. Not for the faint of heart.
|
||||||
|
- `zola serve` - Starts a localhost webserver to serve your content for demo
|
||||||
|
- `zola build` - Builds a Zola project into a collection of static HTML.
|
||||||
|
|
||||||
|
## Project layout
|
||||||
|
|
||||||
|
The following files and folders define a basic Zola project
|
||||||
|
|
||||||
|
- `config.toml`: A configuration file in the [TOML](https://toml.io/en/)
|
||||||
|
configuration language. Can contain a lot of information that will be made
|
||||||
|
available to *all* pages in the system.
|
||||||
|
- `content/`: The structured content folder.
|
||||||
|
- `sass/`: [Sass](../sass) is a CSS preprocessor language that makes CSS easier.
|
||||||
|
- `static/`: Static content such as images, fonts, and Javascript
|
||||||
|
- `templates`: The HTML templates (and includes, etc) that define the website's
|
||||||
|
layouts
|
||||||
|
|
||||||
|
Note that if you want to use modern Javascript features such as a precompiler
|
||||||
|
like Typescript or a bundler like Webpack, that is outside the functionality of
|
||||||
|
Zola. You'll have to have a separate project for that, or a subfolder or git
|
||||||
|
submodule, and you'll have to have a separate build step for that.
|
||||||
|
|
||||||
|
It's also a bit of a shame that Tera is 100% an HTML play, and there's no HAML
|
||||||
|
or similar HTML templating involved. That would be a nifty project.
|
||||||
|
|
||||||
|
## Tera
|
||||||
|
|
||||||
|
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
|
||||||
|
_context_, which can be thought of as a JSON object with which to populate the
|
||||||
|
page (it is, technically, a [Serde::Serializable](https://serde.rs/)). Zola
|
||||||
|
provides a large and complex context, which is explained further down.
|
||||||
|
|
||||||
|
Tera has the following syntax. Everything within these markers is processed by
|
||||||
|
Tera; everything outside is left untouched.
|
||||||
|
|
||||||
|
- `{{` and `}}` for expressions
|
||||||
|
- `{%` and `%}` for statements
|
||||||
|
- `{#` and `#}` for comments
|
||||||
|
|
||||||
|
Statements that have a dash as part of their delimeter remove all whitespace
|
||||||
|
from around the delimiter. `{%-` says to eliminate all whitespace between this
|
||||||
|
statement and anything that came before it; `-%}` says to eliminate everything
|
||||||
|
that comes after it.
|
||||||
|
|
||||||
|
### Statements
|
||||||
|
|
||||||
|
#### `set`
|
||||||
|
|
||||||
|
Variables are set in a given scope with `set`:
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% set my_var = "hello" %}
|
||||||
|
```
|
||||||
|
|
||||||
|
Sets a variable `my_var`. Variables can contain booleans, floats, strings,
|
||||||
|
integers, and arrays. There is a special syntax, `set_global`, that can be used
|
||||||
|
to set variables one level up in scope when working inside `for` loops (i.e. in
|
||||||
|
the outer scope containing the loop, preserving its content between iterations).
|
||||||
|
|
||||||
|
#### `if`
|
||||||
|
|
||||||
|
Conditional statements are managed with `if/is ... else ... endif`
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% if my_var is ... %} ... {% endif %}
|
||||||
|
```
|
||||||
|
|
||||||
|
The list of `is` tests that are shipped with Zola are:
|
||||||
|
|
||||||
|
- `defined`: the given variable is defined.
|
||||||
|
- `undefined`: the given variable is undefined.
|
||||||
|
- `odd`: the given variable is an odd number.
|
||||||
|
- `even`: the given variable is an even number.
|
||||||
|
- `string`: the given variable is a string.
|
||||||
|
- `number`: the given variable is a number.
|
||||||
|
- `divisibleby`: the given expression is divisible by the arg given.
|
||||||
|
- `iterable`: Returns true if the given variable can be iterated over in Tera (i.e. is an array/tuple or an object).
|
||||||
|
- `object`: Returns true if the given variable is an object (i.e. can be iterated over key, value).
|
||||||
|
- `starting_with(string)`: Returns true if the given variable is a string and starts with the arg given.
|
||||||
|
- `ending_with(string)`: Returns true if the given variable is a string and ends with the arg given.
|
||||||
|
- `containing(val)`: Returns true if the given variable contains the arg given.
|
||||||
|
- strings: is the arg a substring?
|
||||||
|
- arrays: is the arg given one of the members of the array?
|
||||||
|
- maps: is the arg given a key of the map?
|
||||||
|
- `matching(regexp)`: Returns true if the given variable is a string and matches the regex in the argument.
|
||||||
|
|
||||||
|
#### `for`
|
||||||
|
|
||||||
|
Arrays are iterated with the `for x in array/map ... endfor` syntax.
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% for name in users %}
|
||||||
|
Hello: {{ name }}
|
||||||
|
{% endfor %}
|
||||||
|
```
|
||||||
|
|
||||||
|
Maps will provide a key/value pair. The names of the two fields are arbitrary:
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% for name, label in options %}
|
||||||
|
<option value="{name}">{label}</option>
|
||||||
|
{% endfor %}
|
||||||
|
```
|
||||||
|
|
||||||
|
Array filters (see below) are invoked before the loop. The following will print
|
||||||
|
the list in reverse order.
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% for name in users | reverse %}{{ name }}{% endfor %}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `include`
|
||||||
|
|
||||||
|
Include other content into the current template being rendered. Include strings
|
||||||
|
cannot be built out of variables, but they _may_ be a list, in which case the
|
||||||
|
first filename found is rendered. If the include block has the phrase 'ignore
|
||||||
|
missing' at the end a missing file will not cause an error at build time.
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% include "header.html" %}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Macros
|
||||||
|
|
||||||
|
Macros are blocks of template that can be passed variables; they're basically
|
||||||
|
just big chunks of content that can be parameterized. Macros must be defined in
|
||||||
|
a file separate from the main content and imported with a distinct syntax from
|
||||||
|
`import`:
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% import "header.html" as header %}
|
||||||
|
```
|
||||||
|
|
||||||
|
The header macro can be invoked in that file like this:
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{{ header::header("My Blog!") }}
|
||||||
|
```
|
||||||
|
|
||||||
|
And an example of this macro (again, in the `header.html` file) would look like this:
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% macro header(title) %}
|
||||||
|
<header class="header">
|
||||||
|
<h1>{ title }</h1>
|
||||||
|
</header>
|
||||||
|
{% endmacro %}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% raw %}Content {{ goes here }}{% endraw %}
|
||||||
|
```
|
||||||
|
|
||||||
|
Content within the `raw` block will not be processed.
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
[[extra.list]]
|
||||||
|
title = "React ⚛"
|
||||||
|
url="/docs/react"
|
||||||
|
content = 'React is a library for writing responsive web pages. Professionally, I write React, and I write a lot of it.'
|
||||||
|
|
||||||
|
[[extra.list]]
|
||||||
|
title = "Typescript"
|
||||||
|
url="/docs/typescript"
|
||||||
|
content = "Typescript is a superset of Javascript that provides a language of types and type flow. It's my preferred front-end language."
|
||||||
|
|
||||||
|
[[extra.list]]
|
||||||
|
title = "CSS"
|
||||||
|
url="/docs/css"
|
||||||
|
content = "CSS is the language of styles for web development."
|
||||||
|
|
||||||
|
[[extra.list]]
|
||||||
|
title = "Sass"
|
||||||
|
url="/docs/sass"
|
||||||
|
content = "Sass is a high-level language that compiles down to CSS."
|
||||||
|
|
||||||
|
[[extra.list]]
|
||||||
|
title = "Rust"
|
||||||
|
url="/docs/rust"
|
||||||
|
content = "Rust is a system programming language that provides the speed of C/C++, but imposes a strict discipline on memory management that creates much safer and more reliable code."
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,26 @@
|
||||||
|
{%- 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() }}
|
||||||
|
</head>
|
||||||
|
{% block body %}{% set page_class="home" %}{% endblock body %}
|
||||||
|
<body class="{{ page_class }}">
|
||||||
|
{% block header %}
|
||||||
|
{{ header::header(current_section="/") }}
|
||||||
|
{% endblock header %}
|
||||||
|
|
||||||
|
{% block content %}{% endblock content %}
|
||||||
|
|
||||||
|
{% block footer %}
|
||||||
|
{{ footer::footer() }}
|
||||||
|
{% endblock footer %}
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,48 @@
|
||||||
|
{% extends "section.html" %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{% set page_class = "docs list" %}
|
||||||
|
{% endblock body %}
|
||||||
|
|
||||||
|
{% block header %}
|
||||||
|
{% set current_section = "docs" %}
|
||||||
|
{{ macros_header::header(current_section=current_section)}}
|
||||||
|
{% endblock header %}
|
||||||
|
|
||||||
|
{% 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>
|
||||||
|
<h1 class="text-center">{{ section.title }}</h1>
|
||||||
|
<div class="text-center">{{ section.content | safe }}</div>
|
||||||
|
<div class="card-list">
|
||||||
|
{% set index_path = current_path ~ "_index.md" | trim_start_matches(pat="/") %}
|
||||||
|
{% set index = get_section(path=index_path) %}
|
||||||
|
{% for page in index.pages %}
|
||||||
|
<div class="card my-3">
|
||||||
|
<div class="card-body">
|
||||||
|
<a class="stretched-link" href="{{ page.permalink }}">{{ page.title }} →</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% for s in index.subsections %}
|
||||||
|
{% set subsection = get_section(path=s) %}
|
||||||
|
{% if subsection.pages %}
|
||||||
|
{% for page in subsection.pages %}
|
||||||
|
<div class="card my-3">
|
||||||
|
<div class="card-body">
|
||||||
|
<a class="stretched-link" href="{{ page.permalink }}">{{ page.title }} →</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
|
@ -0,0 +1,34 @@
|
||||||
|
{% 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>
|
||||||
|
<div class="col-lg-9 col-xl-8 text-center">
|
||||||
|
<p class="lead">
|
||||||
|
{{ section.extra.lead | default(value="Please start setting config.toml and adding
|
||||||
|
your content.") | safe }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="section section-sm">
|
||||||
|
<div class="container">
|
||||||
|
<div class="topic-cards">
|
||||||
|
{% if section.extra.list %} {% for val in section.extra.list %}
|
||||||
|
<div class="topic-card">
|
||||||
|
<h2>{{ val.title }}</h2>
|
||||||
|
<p>{{ val.content | safe }}</p>
|
||||||
|
</div>
|
||||||
|
{% endfor %} {% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{% macro preloads() %}
|
||||||
|
{% if config.extra.preloads %}
|
||||||
|
{% for preload in config.extra.preloads %}
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
as="font"
|
||||||
|
href="{{ get_url(path="{{ preload }}") | safe }}"
|
||||||
|
type="{% if preload is ending_with(".woff2") %}font/woff2{% else %}font/woff{% endif %}"
|
||||||
|
crossorigin />
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
|
@ -0,0 +1,24 @@
|
||||||
|
{% macro footer() %}
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-8 order-last order-lg-first">
|
||||||
|
<ul class="list-inline">
|
||||||
|
<li class="list-inline-item">
|
||||||
|
Elf's Notes are copyright (C) 2008-2022 Elf M. Sternberg
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-8 order-first order-lg-last text-lg-end">
|
||||||
|
<ul class="list-inline">
|
||||||
|
{% if config.extra.footer.nav %} {%- for val in config.extra.footer.nav -%}
|
||||||
|
<li class="list-inline-item">
|
||||||
|
<a href="{{ get_url(path=val.url, trailing_slash=true) | safe }}">{{ val.name }}</a>
|
||||||
|
</li>
|
||||||
|
{%- endfor -%} {% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
{% endmacro %}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{% macro header(current_section) %}
|
||||||
|
<header class="navbar">
|
||||||
|
<div class="container">
|
||||||
|
<a class="identity" href="{{ config.base_url | safe }}">{{ config.title | default(value="") }}</a>
|
||||||
|
</div>
|
||||||
|
{# TODO: Add buttons, perhaps even a menu, to handle navigating to other sections. #}
|
||||||
|
{# TODO: Add search feature. DO NOT use Zola's #}
|
||||||
|
{# TODO: Add social networking buttons for Twitter, Github, & Gitea #}
|
||||||
|
</header>
|
||||||
|
{% endmacro %}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{% macro stylesheets() %}
|
||||||
|
<link rel="stylesheet" href="{{ get_url(path="main.css") | safe }}">
|
||||||
|
{% endmacro %}
|
|
@ -0,0 +1,50 @@
|
||||||
|
{# Default section.html template #}
|
||||||
|
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block seo %}
|
||||||
|
{{ super() }}
|
||||||
|
{% set title_addition = "" %}
|
||||||
|
|
||||||
|
{% if section.title and config.title %}
|
||||||
|
{% set title = section.title %}
|
||||||
|
{% set title_addition = title_separator ~ config.title %}
|
||||||
|
{% elif section.title %}
|
||||||
|
{% set title = section.title %}
|
||||||
|
{% else %}
|
||||||
|
{% set title = config.title %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if section.description %}
|
||||||
|
{% set description = section.description %}
|
||||||
|
{% else %}
|
||||||
|
{% set description = config.description %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ macros_head::seo(title=title, title_addition=title_addition, description=description) }}
|
||||||
|
{% endblock seo %}
|
||||||
|
|
||||||
|
{% 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>
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>{{ section.title }}</h1>
|
||||||
|
</div>
|
||||||
|
{{ section.content | safe }}
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
Loading…
Reference in New Issue