Organized doc md with metadata & draft for doc template

This commit is contained in:
Lucas Chaplain 2022-01-25 15:27:39 +01:00
parent ada5e9ac0e
commit ee4d6a01e1
51 changed files with 336 additions and 411 deletions

View file

@ -1,133 +1,54 @@
# The base URL of the site; the only required configuration variable.
base_url = "https://garagehq.deuxfleurs.fr"
# The site title and description; used in feeds by default.
title = "Garage"
description = "An open-source distributed storage service you can self-host to fullfill many needs"
# The default language; used in feeds.
default_language = "en"
# For overriding the default output directory `public`, set it to another value (e.g.: "docs")
output_dir = "public"
# When set to "true", the Sass files in the `sass` directory in the site root are compiled.
# Sass files in theme directories are always compiled.
compile_sass = true
# When set to "true", the generated HTML files are minified.
minify_html = false
# A list of glob patterns specifying asset files to ignore when the content
# directory is processed. Defaults to none, which means that all asset files are
# copied over to the `public` directory.
# Example:
# ignored_content = ["*.{graphml,xlsx}", "temp.*"]
ignored_content = []
# When set to "true", a feed is automatically generated.
generate_feed = true
# The filename to use for the feed. Used as the template filename, too.
# Defaults to "atom.xml", which has a built-in template that renders an Atom 1.0 feed.
# There is also a built-in template "rss.xml" that renders an RSS 2.0 feed.
feed_filename = "rss.xml"
# The number of articles to include in the feed. All items are included if
# this limit is not set (the default).
# feed_limit = 20
# When set to "true", files in the `static` directory are hard-linked. Useful for large
# static files. Note that for this to work, both `static` and the
# output directory need to be on the same filesystem. Note that the theme's `static`
# files are always copied, regardless of this setting.
hard_link_static = false
# The taxonomies to be rendered for the site and their configuration of the default languages
# Example:
# taxonomies = [
# {name = "tags", feed = true}, # each tag will have its own feed
# {name = "tags"}, # you can have taxonomies with the same name in multiple languages
# {name = "categories", paginate_by = 5}, # 5 items per page for a term
# {name = "authors"}, # Basic definition: no feed or pagination
# ]
#
taxonomies = [
{ name = "categories", feed = true, paginate_by = 10 },
{ name = "tags", feed = true, paginate_by = 10 }
]
# When set to "true", a search index is built from the pages and section
# content for `default_language`.
build_search_index = true
# Configuration of the Markdown rendering
[markdown]
# When set to "true", all code blocks are highlighted.
highlight_code = true
# A list of directories used to search for additional `.sublime-syntax` files.
extra_syntaxes = []
# The theme to use for code highlighting.
# See below for list of allowed values.
highlight_theme = "one-dark"
# When set to "true", emoji aliases translated to their corresponding
# Unicode emoji equivalent in the rendered Markdown files. (e.g.: :smile: => 😄)
render_emoji = true
# Whether external links are to be opened in a new tab
# If this is true, a `rel="noopener"` will always automatically be added for security reasons
external_links_target_blank = true
# Whether to set rel="nofollow" for all external links
external_links_no_follow = true
# Whether to set rel="noreferrer" for all external links
external_links_no_referrer = true
# Whether smart punctuation is enabled (changing quotes, dashes, dots in their typographic form)
# For example, `...` into `…`, `"quote"` into `“curly”` etc
smart_punctuation = false
# Configuration of the link checker.
[link_checker]
# Skip link checking for external URLs that start with these prefixes
skip_prefixes = [
"http://[2001:db8::]/",
]
# Skip anchor checking for external URLs that start with these prefixes
skip_anchor_prefixes = [
"https://caniuse.com/",
]
# Various slugification strategies, see below for details
# Defaults to everything being a slug
[slugify]
paths = "on"
taxonomies = "on"
anchors = "on"
[search]
# Whether to include the title of the page/section in the index
include_title = true
# Whether to include the description of the page/section in the index
include_description = false
# Whether to include the path of the page/section in the index
include_path = false
# Whether to include the rendered content of the page/section in the index
include_content = true
[extra]
katex.enabled = true
katex.auto_render = true
chart.enabled = true
mermaid.enabled = true
galleria.enabled = true
navbar_items = [
{ code = "en", nav_items = [
{ url = "$BASE_URL/", name = "Overview" },
@ -159,9 +80,6 @@ email = "contact@garagehq.com"
[extra.analytics]
google = "UA-176984489-2"
[extra.commenting]
disqus = "deepthought-theme"
[extra.mapbox]
enabled = true
access_token = "pk.eyJ1IjoicmF0YW5zaHJlc2h0aGEiLCJhIjoiY2tla2s2NmM3MDd0ZzJzbXFtc3Y2YmU0NyJ9.0RhUnJPKbxHWw3xGPnnBlA"

View file

@ -0,0 +1,5 @@
+++
template = "documentation.html"
page_template = "documentation.html"
redirect_to = "documentation/quick-start/"
+++

View file

@ -0,0 +1,6 @@
+++
title = "Integrations"
weight = 3
sort_by = "weight"
redirect_to = "documentation/connect/apps/"
+++

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Apps (Nextcloud, Peertube...)"
weight = 5
+++
# Apps (Nextcloud, Peertube...)

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Backups (restic, duplicity...)"
weight = 25
+++
# Backups (restic, duplicity...)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "CLI tools"
weight = 20
+++
# CLI tools

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Your code (PHP, JS, Go...)"
weight = 30
+++
# Your code (PHP, JS, Go...)

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "FUSE (s3fs, goofys, s3backer...)"
weight = 25
+++
# FUSE (s3fs, goofys, s3backer...)

View file

@ -1,46 +0,0 @@
+++
title="Doc Post"
date=2018-08-20
+++
# Integrations
Garage implements the Amazon S3 protocol, which makes it compatible with many existing software programs.
In particular, you will find here instructions to connect it with:
- [web applications](./apps.md)
- [website hosting](./websites.md)
- [software repositories](./repositories.md)
- [CLI tools](./cli.md)
- [your own code](./code.md)
### Generic instructions
To configure S3-compatible software to interact with Garage,
you will need the following parameters:
- An **API endpoint**: this corresponds to the HTTP or HTTPS address
used to contact the Garage server. When runing Garage locally this will usually
be `http://127.0.0.1:3900`. In a real-world setting, you would usually have a reverse-proxy
that adds TLS support and makes your Garage server available under a public hostname
such as `https://garage.example.com`.
- An **API access key** and its associated **secret key**. These usually look something
like this: `GK3515373e4c851ebaad366558` (access key),
`7d37d093435a41f2aab8f13c19ba067d9776c90215f56614adad6ece597dbb34` (secret key).
These keys are created and managed using the `garage` CLI, as explained in the
[quick start](../quick_start/index.md) guide.
Most S3 clients can be configured easily with these parameters,
provided that you follow the following guidelines:
- **Force path style:** Garage does not support DNS-style buckets, which are now by default
on Amazon S3. Instead, Garage uses the legacy path-style bucket addressing.
Remember to configure your client to acknowledge this fact.
- **Configuring the S3 region:** Garage requires your client to talk to the correct "S3 region",
which is set in the configuration file. This is often set just to `garage`.
If this is not configured explicitly, clients usually try to talk to region `us-east-1`.
Garage should normally redirect your client to the correct region,
but in case your client does not support this you might have to configure it manually.

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Repositories (Docker, Nix, Git...)"
weight = 15
+++
# Repositories (Docker, Nix, Git...)

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Websites (Hugo, Jekyll, Publii...)"
weight = 10
+++
# Websites (Hugo, Jekyll, Publii...)

View file

@ -0,0 +1,6 @@
+++
title="Cookbook"
weight = 2
sort_by = "weight"
redirect_to = "documentation/cookbook/real-world/"
+++

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Exposing buckets as websites"
weight = 25
+++
# Exposing buckets as websites

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Compiling Garage from source"
weight = 10
+++
# Compiling Garage from source

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Configuring a gateway node"
weight = 20
+++
# Gateways

View file

@ -1,31 +0,0 @@
+++
title="Doc Post"
date=2018-08-20
+++
# Cookbook
A cookbook, when you cook, is a collection of recipes.
Similarly, Garage's cookbook contains a collection of recipes that are known to works well!
This chapter could also be referred as "Tutorials" or "Best practices".
- **[Multi-node deployment](real_world.md):** This page will walk you through all of the necessary
steps to deploy Garage in a real-world setting.
- **[Building from source](from_source.md):** This page explains how to build Garage from
source in case a binary is not provided for your architecture, or if you want to
hack with us!
- **[Integration with Systemd](systemd.md):** This page explains how to run Garage
as a Systemd service (instead of as a Docker container).
- **[Configuring a gateway node](gateways.md):** This page explains how to run a gateway node in a Garage cluster, i.e. a Garage node that doesn't store data but accelerates access to data present on the other nodes.
- **[Hosting a website](exposing_websites.md):** This page explains how to use Garage
to host a static website.
- **[Configuring a reverse-proxy](reverse_proxy.md):** This page explains how to configure a reverse-proxy to add TLS support to your S3 api endpoint.
- **[Recovering from failures](recovering.md):** Garage's first selling point is resilience
to hardware failures. This section explains how to recover from such a failure in the
best possible way.

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Multi-node deployment"
weight = 5
+++
# Deploying Garage on a real-world cluster

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Recovering from failures"
weight = 35
+++
# Recovering from failures

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Configuring a reverse proxy"
weight = 30
+++
# Configuring a reverse proxy

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Starting Garage with systemd"
weight = 15
+++
# Starting Garage with systemd

View file

@ -1,8 +0,0 @@
+++
title="Doc Post"
date=2018-08-20
+++
# Hosting a website
TODO

View file

@ -0,0 +1,6 @@
+++
title = "Design"
weight = 5
sort_by = "weight"
redirect_to = "documentation/design/goals/"
+++

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Benchmarks"
weight = 10
+++
# Benchmarks

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Goals and use cases"
weight = 5
+++
# Goals and use cases

View file

@ -1,31 +0,0 @@
+++
title="Doc Post"
date=2018-08-20
+++
# Design
The design section helps you to see Garage from a "big picture"
perspective. It will allow you to understand if Garage is a good fit for
you, how to better use it, how to contribute to it, what can Garage could
and could not do, etc.
- **[Goals and use cases](goals.md):** This page explains why Garage was concieved and what practical use cases it targets.
- **[Related work](related_work.md):** This pages presents the theoretical background on which Garage is built, and describes other software storage solutions and why they didn't work for us.
- **[Internals](internals.md):** This page enters into more details on how Garage manages data internally.
## Talks
We love to talk and hear about Garage, that's why we keep a log here:
- [(fr, 2021-11-13, video) Garage : Mille et une façons de stocker vos données](https://video.tedomum.net/w/moYKcv198dyMrT8hCS5jz9) and [slides (html)](https://rfid.deuxfleurs.fr/presentations/2021-11-13/garage/) - during [RFID#1](https://rfid.deuxfleurs.fr/programme/2021-11-13/) event
- [(en, 2021-04-28) Distributed object storage is centralised](https://git.deuxfleurs.fr/Deuxfleurs/garage/raw/commit/b1f60579a13d3c5eba7f74b1775c84639ea9b51a/doc/talks/2021-04-28_spirals-team/talk.pdf)
- [(fr, 2020-12-02) Garage : jouer dans la cour des grands quand on est un hébergeur associatif](https://git.deuxfleurs.fr/Deuxfleurs/garage/raw/commit/b1f60579a13d3c5eba7f74b1775c84639ea9b51a/doc/talks/2020-12-02_wide-team/talk.pdf)
*Did you write or talk about Garage? [Open a pull request](https://git.deuxfleurs.fr/Deuxfleurs/garage/) to add a link here!*

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Internals"
weight = 20
+++
# Internals

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Related work"
weight = 15
+++
# Related work

View file

@ -0,0 +1,6 @@
+++
title = "Development"
weight = 6
sort_by = "weight"
redirect_to = "documentation/development/devenv/"
+++

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Setup your environment"
weight = 5
+++
# Setup your development environment

View file

@ -1,19 +0,0 @@
+++
title="Doc Post"
date=2018-08-20
+++
# Development
Now that you are a Garage expert, you want to enhance it, you are in the right place!
We discuss here how to hack on Garage, how we manage its development, etc.
## Rust API (docs.rs)
If you encounter a specific bug in Garage or plan to patch it, you may jump directly to the source code's documentation!
- [garage\_api](https://docs.rs/garage_api/latest/garage_api/) - contains the S3 standard API endpoint
- [garage\_model](https://docs.rs/garage_model/latest/garage_model/) - contains Garage's model built on the table abstraction
- [garage\_rpc](https://docs.rs/garage_rpc/latest/garage_rpc/) - contains Garage's federation protocol
- [garage\_table](https://docs.rs/garage_table/latest/garage_table/) - contains core Garage's CRDT datatypes
- [garage\_util](https://docs.rs/garage_util/latest/garage_util/) - contains garage helpers
- [garage\_web](https://docs.rs/garage_web/latest/garage_web/) - contains the S3 website endpoint

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Miscellaneous notes"
weight = 20
+++
# Miscellaneous Notes

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Release process"
weight = 15
+++
# Release process

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Development scripts"
weight = 10
+++
# Development scripts

View file

@ -1,106 +0,0 @@
+++
title="Doc Post"
date=2018-08-20
+++
<p align="center" style="text-align:center;">
<a href="https://garagehq.deuxfleurs.fr">
<img alt="Garage's Logo" src="img/logo.svg" height="200" />
</a>
</p>
<p align="center" style="text-align:center;">
[ <a href="https://garagehq.deuxfleurs.fr/_releases.html">Download</a>
| <a href="https://git.deuxfleurs.fr/Deuxfleurs/garage">Git repository</a>
| <a href="https://matrix.to/#/%23garage:deuxfleurs.fr">Matrix channel</a>
| <a href="https://drone.deuxfleurs.fr/Deuxfleurs/garage">Drone CI</a>
]
</p>
# Data resiliency for everyone
Garage is an **open-source** distributed **storage service** you can **self-host** to fullfill many needs:
<p align="center" style="text-align:center; margin-bottom: 5rem;">
<img alt="Summary of the possible usages with a related icon: host a website, store media and backup target" src="img/usage.svg" />
</p>
<p align="center" style="text-align:center; margin-bottom: 5rem;">
<a href="/design/goals.html#use-cases">⮞ learn more about use cases ⮜</a>
</p>
Garage implements the **[Amazon S3 API](https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html)** and thus is already **compatible** with many applications:
<p align="center" style="text-align:center; margin-bottom: 8rem;">
<img alt="Garage is already compatible with Nextcloud, Mastodon, Matrix Synapse, Cyberduck, RClone and Peertube" src="img/software.svg" />
</p>
<p align="center" style="text-align:center; margin-bottom: 5rem;">
<a href="/connect/index.html">⮞ learn more about integrations ⮜</a>
</p>
Garage provides **data resiliency** by **replicating** data 3x over **distant** servers:
<p align="center" style="text-align:center; margin-bottom: 5rem;">
<img alt="An example deployment on a map with servers in 5 zones: UK, France, Belgium, Germany and Switzerland. Each chunk of data is replicated in 3 of these 5 zones." src="img/map.svg" />
</p>
<p align="center" style="text-align:center; margin-bottom: 5rem;">
<a href="/design/index.html">⮞ learn more about our design ⮜</a>
</p>
Did you notice that *this website* is hosted and served by Garage?
## Keeping requirements low
We worked hard to keep requirements as low as possible as we target the largest possible public.
* **CPU:** any x86\_64 CPU from the last 10 years, ARMv7 or ARMv8.
* **RAM:** 1GB
* **Disk Space:** at least 16GB
* **Network:** 200ms or less, 50 Mbps or more
* **Heterogeneous hardware:** build a cluster with whatever second-hand machines are available
*For the network, as we do not use consensus algorithms like Paxos or Raft, Garage is not as latency sensitive.*
*Thanks to Rust and its zero-cost abstractions, we keep CPU and memory low.*
## Built on the shoulder of giants
- [Dynamo: Amazons Highly Available Key-value Store ](https://dl.acm.org/doi/abs/10.1145/1323293.1294281) by DeCandia et al.
- [Conflict-Free Replicated Data Types](https://link.springer.com/chapter/10.1007/978-3-642-24550-3_29) by Shapiro et al.
- [Maglev: A Fast and Reliable Software Network Load Balancer](https://www.usenix.org/conference/nsdi16/technical-sessions/presentation/eisenbud) by Eisenbud et al.
## Talks
- [(fr, 2021-11-13, video) Garage : Mille et une façons de stocker vos données](https://video.tedomum.net/w/moYKcv198dyMrT8hCS5jz9) and [slides (html)](https://rfid.deuxfleurs.fr/presentations/2021-11-13/garage/) - during [RFID#1](https://rfid.deuxfleurs.fr/programme/2021-11-13/) event
- [(en, 2021-04-28, pdf) Distributed object storage is centralised](https://git.deuxfleurs.fr/Deuxfleurs/garage/raw/commit/b1f60579a13d3c5eba7f74b1775c84639ea9b51a/doc/talks/2021-04-28_spirals-team/talk.pdf)
- [(fr, 2020-12-02, pdf) Garage : jouer dans la cour des grands quand on est un hébergeur associatif](https://git.deuxfleurs.fr/Deuxfleurs/garage/raw/commit/b1f60579a13d3c5eba7f74b1775c84639ea9b51a/doc/talks/2020-12-02_wide-team/talk.pdf)
## Community
If you want to discuss with us, you can join our Matrix channel at [#garage:deuxfleurs.fr](https://matrix.to/#/#garage:deuxfleurs.fr).
Our code repository and issue tracker, which is the place where you should report bugs, is managed on [Deuxfleurs' Gitea](https://git.deuxfleurs.fr/Deuxfleurs/garage).
## License
Garage's source code, is released under the [AGPL v3 License](https://www.gnu.org/licenses/agpl-3.0.en.html).
Please note that if you patch Garage and then use it to provide any service over a network, you must share your code!
# Sponsors and funding
The Deuxfleurs association has received a grant from [NGI POINTER](https://pointer.ngi.eu/), to fund 3 people working on Garage full-time for a year: from October 2021 to September 2022.
<div style="display: flex; justify-content: space-around">
<a href="https://pointer.ngi.eu/">
<img style="height:100px" src="img/ngi-logo.png" alt="NGI Pointer logo">
</a>
<a href="https://ec.europa.eu/programmes/horizon2020/what-horizon-2020">
<img style="height:100px" src="img/eu-flag-logo.png" alt="EU flag logo">
</a>
</div>
_This project has received funding from the European Unions Horizon 2020 research and innovation programme within the framework of the NGI-POINTER Project funded under grant agreement N° 871528._

View file

@ -0,0 +1,6 @@
+++
title = "Quick Start"
weight = 1
sort_by = "weight"
redirect_to = "documentation/quick-start/overview/"
+++

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Overview"
weight = 5
+++
# Quick Start
@ -73,7 +73,7 @@ Garage server will not be persistent. Change these to locations on your local di
your data to be persisted properly.
## Launching the Garage server
# Launching the Garage server
Use the following command to launch the Garage server with our configuration file:

View file

@ -0,0 +1,6 @@
+++
title = "Reference Manual"
weight = 4
sort_by = "weight"
redirect_to = "documentation/reference-manual/configuration/"
+++

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Garage CLI"
weight = 15
+++
# Garage CLI

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Garage configuration file"
weight = 5
+++
# Garage configuration file format reference

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Cluster layout management"
weight = 10
+++
# Creating and updating a cluster layout

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "S3 Compatibility status"
weight = 20
+++
# S3 Compatibility status

View file

@ -1,10 +0,0 @@
+++
title="Doc Post"
date=2018-08-20
+++
# Reference Manual
A reference manual contains some extensive descriptions about the features and the behaviour of the software.
Reading of this chapter is recommended once you have a good knowledge/understanding of Garage.
It will be useful if you want to tune it or to use it in some exotic conditions.

View file

@ -0,0 +1,6 @@
+++
title = "Working Documents"
weight = 7
sort_by = "weight"
redirect_to = "documentation/working-documents/compatibility-target/"
+++

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "S3 compatibility target"
weight = 5
+++
# S3 compatibility target

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Design draft"
weight = 25
+++
# Design draft

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Load balancing data"
weight = 10
+++
# Load Balancing Data (planned for version 0.2)

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Migrating from 0.3 to 0.4"
weight = 20
+++
# Migrating from 0.3 to 0.4

View file

@ -1,6 +1,6 @@
+++
title="Doc Post"
date=2018-08-20
title = "Migrating from 0.5 to 0.6"
weight = 15
+++
# Migrating from 0.5 to 0.6

View file

@ -1,13 +0,0 @@
+++
title="Doc Post"
date=2018-08-20
+++
# Working Documents
Working documents are documents that reflect the fact that Garage is a software that evolves quickly.
They are a way to communicate our ideas, our changes, and so on before or while we are implementing them in Garage.
If you like to live on the edge, it could also serve as a documentation of our next features to be released.
Ideally, once the feature/patch has been merged, the working document should serve as a source to
update the rest of the documentation and then be removed.

View file

@ -0,0 +1,224 @@
{% extends 'base.html' %}
{% block title %}
{{ config.title }} | {{ page.title }}
{% endblock %}
{% block content %}
{% set section = get_section(path="documentation/_index.md") %}
<section class="section overflow-x-hidden">
<div class="grid grid-cols-5">
<aside class="col-span-1 h-full bg-gray-100 shadow-inner border-r border-t border-gray-200">
{% if section.toc %}
<ul>
{% for h1 in section.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>
{% endif %}
</aside>
<div class="col-span-3">
<article class="box my-12 px-12">
<div class="flex flex-col bg-gray-100 rounded-r shadow-sm w-max">
<div class="flex flex-col border-l-4 border-garage-orange py-2 px-4 relative">
<h1 class="title leading-10 text-3xl text-garage-orange font-semibold">
{{ page.title }}
</h1>
{% if page.description %}
<p class="subtitle my-2 text-gray-600 italic text-sm">{{ page.description }}</p>
{% endif %}
</div>
</div>
<div class="page-content max-w-4xl">
{{ page.content | safe }}
</div>
</article>
</div>
<aside class="hidden 2xl:block fixed right-0 bottom-1/2 transform translate-y-1/2 col-span-1 h-auto bg-gray-100 rounded-l-lg shadow-inner">
{% if page.toc %}
<div class="w-full flex items-center justify-center py-1.5 bg-gray-200 rounded-tl-lg">
<span class="uppercase tracking-wide text-xs text-garage-gray">Page content</span>
</div>
<ol class="text-sm space-y-0.5 py-0.5 px-8 py-3 list-decimal">
{% for h1 in page.toc %}
<li>
<a href="{{ h1.permalink | safe }}" class="font-semibold bg-gradient-to-r from-garage-gray to-garage-orange text-transparent bg-clip-text transition-all hover:text-garage-orange">{{ h1.title }}</a>
{% if h1.children %}
<ul class="space-y-0.5 py-0.5">
{% for h2 in h1.children %}
<li>
<a href="{{ h2.permalink | safe }}" class="text-gray-700 hover:text-garage-orange">{{ h2.title }}</a>
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ol>
{% endif %}
</aside>
</div>
</section>
{% endblock %}
{% block pagination %}
{% if page.earlier or page.later or page.lighter or page.heavier %}
<section class="w-full">
<div class="container py-20">
<div class="mx-auto max-w-4xl">
<div class="column is-8">
<nav class="flex space-x-8 items-center justify-center">
{% if page.later %}
<div>
<a class="flex items-center space-x-1 hover:text-garage-orange font-semibold text-gray-800"
href="{{ page.later.permalink }}">
<span class="icon mr-2">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M7 16l-4-4m0 0l4-4m-4 4h18"></path>
</svg>
</span>
<span>{{ page.later.title }}</span>
</a>
</div>
{% endif %} {% if page.earlier %}
<div>
<a class="flex items-center space-x-1 hover:text-garage-orange font-semibold text-gray-800"
href="{{ page.earlier.permalink }}">
{{ page.earlier.title }}<span class="icon ml-2">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17 8l4 4m0 0l-4 4m4-4H3"></path>
</svg>
</span>
</a>
</div>
{% endif %} {% if page.heavier %}
<div>
<a class="flex items-center space-x-1 hover:text-garage-orange font-semibold text-gray-800"
href="{{ page.heavier.permalink }}">
<span class="icon mr-2">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M7 16l-4-4m0 0l4-4m-4 4h18"></path>
</svg>
</span>
<span>{{ page.heavier.title }}</span>
</a>
</div>
{% endif %} {% if page.lighter %}
<div>
<a class="flex items-center space-x-1 hover:text-garage-orange font-semibold text-gray-800"
href="{{ page.lighter.permalink }}">
{{ page.lighter.title }}<span class="icon ml-2">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17 8l4 4m0 0l-4 4m4-4H3"></path>
</svg>
</span>
</a>
</div>
{% endif %}
</nav>
</div>
</div>
</div>
</section>
{% endif %}
{% endblock %}
{% block comment %}
{% if page.extra.comments and config.extra.commenting.disqus %}
<section class="section">
<div class="container">
<div class="columns is-centered">
<div class="column is-6">
<div id="disqus_thread"></div>
</div>
</div>
</div>
</section>
{% endif %}
{% endblock %}
{% block custom_js %}
{% if page.extra.toc %}
<script type="text/javascript">
const menuBarHeight = document.querySelector("nav.navbar").clientHeight;
const tocItems = document.querySelectorAll(".toc");
const navSections = new Array(tocItems.length);
tocItems.forEach((el, i) => {
let id = el.getAttribute("id").substring(5);
navSections[i] = document.getElementById(id);
})
function isVisible(tocIndex) {
const current = navSections[tocIndex];
const next = tocIndex < tocItems.length - 1 ? navSections[tocIndex + 1]
: document.querySelectorAll("section.section").item(1);
const c = current.getBoundingClientRect();
const n = next.getBoundingClientRect();
const h = (window.innerHeight || document.documentElement.clientHeight);
return (c.top <= h) && (n.top - menuBarHeight >= 0);
}
function activateIfVisible() {
for (b = true, i = 0; i < tocItems.length; i++) {
if (b && isVisible(i)) {
tocItems[i].classList.add('is-active');
b = false;
} else
tocItems[i].classList.remove('is-active');
}
}
var isTicking = null;
window.addEventListener('scroll', () => {
if (!isTicking) {
window.requestAnimationFrame(() => {
activateIfVisible();
isTicking = false;
});
isTicking = true;
}
}, false);
</script>
{% endif %}
{% if page.extra.comments and config.extra.commenting.disqus %}
<script>
var disqus_config = function () {
this.page.url = "{{config.base_url | safe}}";
this.page.identifier = "{{ current_path | safe}}";
};
(function () {
var d = document, s = d.createElement('script');
s.src = 'https://{{ config.extra.commenting.disqus | safe}}.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
{% endif %}
{% endblock %}