Autogen docs (#44)

* Implement simple node script

* Add zola documentation

* Add gh pages workflow

* autogen widget docs
This commit is contained in:
ElKowar 2020-10-25 15:45:31 +01:00 committed by elkowar
parent b349c003e8
commit 571f65f627
40 changed files with 2246 additions and 364 deletions

27
.github/workflows/gh-pages.yml vendored Normal file
View file

@ -0,0 +1,27 @@
name: Build and deploy Github pages
on:
push:
branches:
- master
jobs:
build:
name: shalzz/zola-deploy-action
runs-on: ubuntu-latest
steps:
# Checkout
- uses: actions/checkout@master
# Build widget documentation
- name: Use nodejs to build widget documentation
uses: actions/setup-node@v1
with:
node-version: '12.x'
- run: node gen-docs.js ./src/widgets/widget_definitions.rs >> ./docs/content/main/widgets.md
# Build & deploy
- name: shalzz/zola-deploy-action
uses: shalzz/zola-deploy-action@v0.12.0
env:
PAGES_BRANCH: gh-pages
BUILD_DIR: docs
TOKEN: ${{ secrets.TOKEN }}

View file

@ -16,6 +16,9 @@
Elkowar’s Wacky Widgets is a standalone Widget System made in rust to add AwesomeWM like widgets to any WM
Documentation can be found [here](https://elkowar.github.io/eww/main)
<a id="org581ca61"></a>
# Configuration
@ -99,7 +102,7 @@ Create a Config and then just do `eww`!
If you experience any issues, the following things should be tried:
- Try killing the eww daemon with `eww kill` and run again
- If you're running with `-d`, run without `-d` to see output, or have a look at ~/.cache/eww.log
- If you're running with `-d`, run without `-d` to see output, or have a look at ~/.cache/eww.log
- use `eww state`, to see the state of all variables
- use `eww debug`, to see the xml of your widget and other information
- update to the latest eww version

1
docs/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
public

View file

@ -1,363 +0,0 @@
# Eww - Widgets for everyone!
Eww (ElKowar's Wacky Widgets, pronounced with sufficient amounts of disgust) Is a widgeting system made in [rust](https://www.rust-lang.org/), which let's you create your own widgets simmilarly to how you can in AwesomeWM. The key difference: It is independent of your window manager!
Configured in XML and themed using CSS, it is easy to customize and provides all the flexibility you need!
## Contents
- [How to install Eww](#how-to-install-eww)
- [Prerequisites](#prerequisites)
- [Building](#building)
- [Starting Eww](#starting-eww)
- [Configuration](#configuration)
- [Placing the configuration file](#placing-the-configuration-file)
- [Variables](#variables)
- [The var tag](#the-var-tag)
- [The script-var tag](#the-script-var-tag)
- [Tail](#tail)
- [The Definitions block](#the-definitions-block)
- [Custom Widgets](#custom-widgets)
- [The Windows block](#the-windows-block)
- [Widgets made in Eww](#widgets-made-in-eww)
- [GTK](#gtk)
- [GTK-Temeing / Eww Themeing](#gtk-themeing)
- [GTK-Debugger](#gtk-debugger)
- [Troubleshooting](#troubleshooting)
- [My scss isn't being loaded](#my-scss-isnt-being-loaded)
- [Eww can't find my configuration file](#eww-cant-find-my-configuration-file)
- [Something isn't styled correctly!](#something-isnt-styled-correctly)
## How to install Eww
### Prerequisites
* rustc
* cargo (nightly toolchain)
Rather than with your system package manager, I recommend installing it using [rustup](https://rustup.rs/), as this makes it easy to use the nightly toolchain, which is necessary to build eww.
### Building
Once you have the Prerequisites ready, you're ready to install and build eww.
First clone the repo:
```bash
git clone https://github.com/elkowar/eww
```
then enter it.
```bash
cd eww
```
and then to build:
```bash
cargo build --release
```
### Running eww
Once you've built it you can now run it by entering:
```bash
cd target/release
```
and then make the Eww binary executable
```bash
chmod +x ./eww
```
and then to run it do
```
./eww open <window_name>
```
`<window_name>` is the name of the window, see [The windows block](#the-windows-block).
## Configuration
For specific built in widgets `<box>, <text>, <slider>, etc` see [Widget Documetation]()
### Placing the configuration file
The configuration file and the scss file should lay in your `$HOME/.config/eww` folder. The xml file should be named `eww.xml` and the scss should be named `eww.scss`
So the directory structure should look like this:
```
$HOME
└──.config
└──eww
├──eww.xml
└──eww.scss
```
### Variables
If you create a `<var>` or a `<script-var>`, you can reference them in your `<box>` by doing `{{var}}`. Where `var` is your variable name.
#### The `<var>` tag
Allows you to repeat the same text multiple times through without retyping it multiple times.
Example: This will define a variable named `banana`, with the default value "I like bananas."
```xml
<variables>
<var name="banana">I like bananas.</var>
</variables>
```
You can then reference it in your widgets by doing:
```xml
<box>
{{banana}}
</box>
```
To change the value of the variable, and thus change the UI, you can run `eww update banana "I like apples"`
#### The `<script-var>` tag
Allows you to create a script that eww runs.
Useful for creating volume sliders or anything similar.
Example:
```xml
<variables>
<script-var name="date" interval="5s">
date +%H:%M
</script-var>
</variables>
```
and then reference it by doing:
```xml
<box>
{{date}}
</box>
```
The `interval="5s"` part says how long time it should take before Eww runs the command again.
Here are the available times you can set:
| Shortened | Full name |
| :------------- | :----------:|
| ms | Miliseconds |
| s | Seconds |
| m | Minutes |
| h | Hours |
#### Tail
If you don't want a set interval and instead want it to tail (run the script when it detects a change is present) you can simply remove the `interval="5s"` so it becomes:
```xml
<variables>
<script-var name="date">
date +%H:%M
</script-var>
</variables>
```
### The `<definitions>` block
In here you whole widget will be made, and you can also create your own widgets. Check [Widget Documentation]() for pre-defined widgets.
#### Custom widgets
Let's get a small config and break it down.
```xml
<definitions>
<def name="clock">
<box>
The time is: {{my_time}} currently.
</box>
</def>
<def name="main">
<box>
<clock my_time="{{date}}"/>
</box>
</def>
</definitions>
<variables>
<script-var name="date">
date
</script-var>
</variables>
```
That's a long config just for a custom widget. But let's break it down and try to understand it.
This part:
```xml
<def name="clock">
<box>
The time is: {{my_time}} currently.
</box>
</def>
```
Is the custom widget. As we can see by the
```xml
<def name="clock">
```
the widget is called `clock.`Or referenced `<clock>`
The `{{my_time}}` is the value we assign to be well, our time. You can actually set to be anything, it doesn't have to be a time. You can compare it to `value=""`
So if we look at:
```xml
<def name="main">
<box>
<clock my_time="{{date}}"/>
</box>
</def>
```
we can see that we assign `{{my_time}}` to be `{{date}}` and if we look at
```xml
<script-var name="date">
date
</script-var>
```
we can see that `{{date}}` is simply running the `date` command.
It doesn't have to be `{{my_time}}` either, it can be anything.
```xml
<def name="clock">
<box>
The time is: {{very_long_list_of_animals}} currently.
</box>
</def>
```
is valid.
To use that it would look like this:
```xml
<def name="main">
<box>
<clock very_long_list_of_animals="{{date}}"/>
</box>
</def>
```
### The `<windows>` block
This is the part the Eww reads and loads. The `<windows>` config should look something like this:
```xml
<windows>
<window name="main_window" stacking="fg">
<size x="300" y="300" />
<pos x="0" y="500" />
<widget>
<main/>
</widget>
</window>
</windows>
```
`<window name="main_window">` is the part that eww runs when you start it. In this example you would run eww by doing:
```bash
./eww open main_window
```
but if renamed the `<window>` to be `<window name="apple">` we would run eww by doing:
```bash
./eww open apple
```
The `stacking="fg"` says where the widget will be stacked. Possible values here are `foreground`, `fg`, `background` and `bg`.
`foreground` or `fg` *always* stays above windows.
`background` or `bg` *always* stays behind windows. So it will stay on your desktop.
If you were to remove the `stacking="fg"` it would default it to `fg`.
You can also have multiple windows in one document by doing:
```xml
<windows>
<window name="main_window">
<size x="300" y="300" />
<pos x="0" y="500" />
<widget>
<main/>
</widget>
</window>
<window name="main_window2">
<size x="400" y="600"/>
<pos x="0" y="0"/>
<widget>
<main2/>
</widget>
</window>
</windows>
```
---
- `<size>` sets x-y size of the widget.
- `<pos>` sets x-y position of the widget.
- `<widget>` is the part which you say which `<def>` eww should run. So if we take the example config from before:
```xml
<definitions>
<def name="clock">
<box>
The time is: {{my_time}} currently.
</box>
</def>
<def name="main">
<box>
<clock my_time="{{date}}"/>
</box>
</def>
</definitions>
```
and then look at
```xml
<widget>
<main/>
</widget>
```
we will see that eww will run `<def name="main">` and not `<def name="clock">`.
### Widgets made in Eww
![two](images/two.png) ![one](images/one.png)
## GTK
### Gtk-Themeing
Eww is styled in GTK CSS. To make theming even easier, it makes use of `scss` and then compiles that into CSS for you. If you don't know any way to style something check out the [GTK CSS Overview wiki](https://developer.gnome.org/gtk3/stable/chap-css-overview.html), the [GTK CSS Properties Overview wiki ](https://developer.gnome.org/gtk3/stable/chap-css-properties.html). Or check the [GTK-Debugger](#gtk-debugger)
If you have **NO** clue about how to do CSS, check out some online guides or tutorials.
SCSS is *very* close to CSS so if you know CSS you'll have no problem learning SCSS.
### GTK-Debugger
The debugger can be used for **a lot** of things. Especially if something doesn't work or isn't styled right. to enable it do
```bash
GTK_DEBUG=interactive ./eww open main_window
```
or in fish
```bash
env GTK_DEBUG=interactive ./eww open main_window
```
If a style or something similar doesn't work you can click on the icon in the top left icon to select the thing that isn't being styled or isn't being styled correctly.
Then you can click on the drop down menu in the top right corner and select CSS Nodes, here you will see everything about styling it, CSS Properties and how it's structured.
## Troubleshooting
Here you will find help if something doesn't work, if the issue isn't listed here please [open an issue on the github repo.](https://github.com/elkowar/eww/issues)
### My scss isn't being loaded!
1. You have not created a scss file
2. The scss file isn't called correctly. (it should be called `eww.scss` in the `$HOME/.config/eww` folder)
3. The scss file isn't placed in the correct location (check above)
4. You have used two (or more) semi-colons (;;) insted of one (;) at the end of a line.
If none of these fixed your problem [open an issue on the github repo.](https://github.com/elkowar/eww/issues) Or check the [GTK-Debugger](#gtk-debugger).
### Eww can't find my configuration file!
1. It's incorrectly named or it's in the wrong place (it should be called `eww.xml` in the `$HOME/.config/eww` folder)
2. You haven't started eww correctly or you started it wrong. (See [Starting Eww](starting-eww))
### Something isn't styled correctly!
1. You have misstyped the CSS class.
2. Check the [GTK-Debugger](#gtk-debugger)
Remeber if your issue isn't listed here, [open an issue on the github repo](https://github.com/elkowar/eww/issues).

19
docs/config.toml Normal file
View file

@ -0,0 +1,19 @@
# The URL the site will be built for
base_url = "https://elkowar.github.io/eww/"
# Whether to automatically compile all Sass files in the sass directory
compile_sass = true
# Whether to do syntax highlighting
# Theme can be customised by setting the `highlight_theme` variable to a theme supported by Zola
highlight_code = true
# Whether to build a search index to be used later on by a JavaScript library
build_search_index = true
theme = "book"
highlight_theme = "base16-ocean-dark"
[extra]
book_numbered_chapters = false

View file

@ -0,0 +1,52 @@
+++
title = "Eww - Widgets for everyone!"
slug = "eww"
sort_by = "weight"
+++
Eww (ElKowar's Wacky Widgets, pronounced with sufficient amounts of disgust) Is a widgeting system made in [rust](https://www.rust-lang.org/), which let's you create your own widgets simmilarly to how you can in AwesomeWM. The key difference: It is independent of your window manager!
Configured in XML and themed using CSS, it is easy to customize and provides all the flexibility you need!
## How to install Eww
### Prerequisites
* rustc
* cargo (nightly toolchain)
Rather than with your system package manager, I recommend installing it using [rustup](https://rustup.rs/), as this makes it easy to use the nightly toolchain, which is necessary to build eww.
### Building
Once you have the Prerequisites ready, you're ready to install and build eww.
First clone the repo:
```bash
git clone https://github.com/elkowar/eww
```
then enter it.
```bash
cd eww
```
and then to build:
```bash
cargo build --release
```
### Running eww
Once you've built it you can now run it by entering:
```bash
cd target/release
```
and then make the Eww binary executable
```bash
chmod +x ./eww
```
and then to run it do
```
./eww open <window_name>
```
`<window_name>` is the name of the window, see [The windows block](@/main/configuration.md#windows-block).

View file

@ -0,0 +1,241 @@
+++
title = "Configuration"
slug = "The basics of how to configure eww"
weight = 1
+++
## Configuration
For specific built in widgets `<box>, <text>, <slider>, etc` see [Widget Documetation](@/main/widgets.md)
### Placing the configuration file
The configuration file and the scss file should lay in your `$HOME/.config/eww` folder. The xml file should be named `eww.xml` and the scss should be named `eww.scss`
So the directory structure should look like this:
```
$HOME
└──.config
└──eww
├──eww.xml
└──eww.scss
```
### Variables
If you create a `<var>` or a `<script-var>`, you can reference them in your `<box>` by doing `{{var}}`. Where `var` is your variable name.
#### The `<var>` tag
Allows you to repeat the same text multiple times through without retyping it multiple times.
Example: This will define a variable named `banana`, with the default value "I like bananas."
```xml
<variables>
<var name="banana">I like bananas.</var>
</variables>
```
You can then reference it in your widgets by doing:
```xml
<box>
{{banana}}
</box>
```
To change the value of the variable, and thus change the UI, you can run `eww update banana "I like apples"`
#### The `<script-var>` tag
Allows you to create a script that eww runs.
Useful for creating volume sliders or anything similar.
Example:
```xml
<variables>
<script-var name="date" interval="5s">
date +%H:%M
</script-var>
</variables>
```
and then reference it by doing:
```xml
<box>
{{date}}
</box>
```
The `interval="5s"` part says how long time it should take before Eww runs the command again.
Here are the available times you can set:
| Shortened | Full name |
|-----------|-------------|
| ms | Miliseconds |
| s | Seconds |
| m | Minutes |
| h | Hours |
#### Tail
If you don't want a set interval and instead want it to tail (run the script when it detects a change is present) you can simply remove the `interval="5s"` so it becomes:
```xml
<variables>
<script-var name="date">
date +%H:%M
</script-var>
</variables>
```
### The `<definitions>` block
In here you whole widget will be made, and you can also create your own widgets. Check [Widget Documentation](@/main/widgets.md) for pre-defined widgets.
#### Custom widgets
Let's get a small config and break it down.
```xml
<definitions>
<def name="clock">
<box>
The time is: {{my_time}} currently.
</box>
</def>
<def name="main">
<box>
<clock my_time="{{date}}"/>
</box>
</def>
</definitions>
<variables>
<script-var name="date">
date
</script-var>
</variables>
```
That's a long config just for a custom widget. But let's break it down and try to understand it.
This part:
```xml
<def name="clock">
<box>
The time is: {{my_time}} currently.
</box>
</def>
```
Is the custom widget. As we can see by the
```xml
<def name="clock">
```
the widget is called `clock.`Or referenced `<clock>`
The `{{my_time}}` is the value we assign to be well, our time. You can actually set to be anything, it doesn't have to be a time. You can compare it to `value=""`
So if we look at:
```xml
<def name="main">
<box>
<clock my_time="{{date}}"/>
</box>
</def>
```
we can see that we assign `{{my_time}}` to be `{{date}}` and if we look at
```xml
<script-var name="date">
date
</script-var>
```
we can see that `{{date}}` is simply running the `date` command.
It doesn't have to be `{{my_time}}` either, it can be anything.
```xml
<def name="clock">
<box>
The time is: {{very_long_list_of_animals}} currently.
</box>
</def>
```
is valid.
To use that it would look like this:
```xml
<def name="main">
<box>
<clock very_long_list_of_animals="{{date}}"/>
</box>
</def>
```
### The `<windows>` block {#windows-block}
This is the part the Eww reads and loads. The `<windows>` config should look something like this:
```xml
<windows>
<window name="main_window" stacking="fg">
<size x="300" y="300" />
<pos x="0" y="500" />
<widget>
<main/>
</widget>
</window>
</windows>
```
`<window name="main_window">` is the part that eww runs when you start it. In this example you would run eww by doing:
```bash
./eww open main_window
```
but if renamed the `<window>` to be `<window name="apple">` we would run eww by doing:
```bash
./eww open apple
```
The `stacking="fg"` says where the widget will be stacked. Possible values here are `foreground`, `fg`, `background` and `bg`.
`foreground` or `fg` *always* stays above windows.
`background` or `bg` *always* stays behind windows. So it will stay on your desktop.
If you were to remove the `stacking="fg"` it would default it to `fg`.
You can also have multiple windows in one document by doing:
```xml
<windows>
<window name="main_window">
<size x="300" y="300" />
<pos x="0" y="500" />
<widget>
<main/>
</widget>
</window>
<window name="main_window2">
<size x="400" y="600"/>
<pos x="0" y="0"/>
<widget>
<main2/>
</widget>
</window>
</windows>
```
---
- `<size>` sets x-y size of the widget.
- `<pos>` sets x-y position of the widget.
- `<widget>` is the part which you say which `<def>` eww should run. So if we take the example config from before:
```xml
<definitions>
<def name="clock">
<box>
The time is: {{my_time}} currently.
</box>
</def>
<def name="main">
<box>
<clock my_time="{{date}}"/>
</box>
</def>
</definitions>
```
and then look at
```xml
<widget>
<main/>
</widget>
```
we will see that eww will run `<def name="main">` and not `<def name="clock">`.

View file

@ -0,0 +1,30 @@
+++
title = "Troubleshooting"
slug = "troubleshooting"
weight = 4
+++
## Troubleshooting
Here you will find help if something doesn't work, if the issue isn't listed here please [open an issue on the github repo.](https://github.com/elkowar/eww/issues)
### My scss isn't being loaded!
1. You have not created a scss file
2. The scss file isn't called correctly. (it should be called `eww.scss` in the `$HOME/.config/eww` folder)
3. The scss file isn't placed in the correct location (check above)
4. You have used two (or more) semi-colons (;;) insted of one (;) at the end of a line.
If none of these fixed your problem [open an issue on the github repo.](https://github.com/elkowar/eww/issues) Or check the [GTK-Debugger](#gtk-debugger).
### Eww can't find my configuration file!
1. It's incorrectly named or it's in the wrong place (it should be called `eww.xml` in the `$HOME/.config/eww` folder)
2. You haven't started eww correctly or you started it wrong. (See [Starting Eww](starting-eww))
### Something isn't styled correctly!
1. You have misstyped the CSS class.
2. Check the [GTK-Debugger](#gtk-debugger)
Remeber if your issue isn't listed here, [open an issue on the github repo](https://github.com/elkowar/eww/issues).

View file

@ -0,0 +1,5 @@
+++
title = "Widgets"
slug = "widget documentation"
weight = 3
+++

View file

@ -0,0 +1,37 @@
+++
title = "Theming with GTK"
slug = "How to use GTK-theming in Eww"
weight = 2
+++
## GTK
### Gtk-Themeing
Eww is styled in GTK CSS.
To make theming even easier, it makes use of `scss` and then compiles that into CSS for you.
If you don't know any way to style something check out the [GTK CSS Overview wiki](https://developer.gnome.org/gtk3/stable/chap-css-overview.html),
the [GTK CSS Properties Overview wiki ](https://developer.gnome.org/gtk3/stable/chap-css-properties.html),
or check the [GTK-Debugger](#gtk-debugger).
If you have **NO** clue about how to do CSS, check out some online guides or tutorials.
SCSS is _very_ close to CSS so if you know CSS you'll have no problem learning SCSS.
### GTK-Debugger
The debugger can be used for **a lot** of things. Especially if something doesn't work or isn't styled right. to enable it do
```bash
GTK_DEBUG=interactive ./eww open main_window
```
or in fish
```bash
env GTK_DEBUG=interactive ./eww open main_window
```
If a style or something similar doesn't work you can click on the icon in the top left icon to select the thing that isn't being styled or isn't being styled correctly.
Then you can click on the drop down menu in the top right corner and select CSS Nodes, here you will see everything about styling it, CSS Properties and how it's structured.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

55
docs/sass/style.scss Normal file
View file

@ -0,0 +1,55 @@
:root {
--bg: hsl(210, 25%, 8%);
--bg-code: #2b303b;
--fg: #c5c5c5;
--sidebar-bg: #14191f;
--sidebar-fg: #c8c9db;
--sidebar-non-existant: #5c6773;
--sidebar-active: #ffb454;
--sidebar-spacer: #2d334f;
--scrollbar: var(--sidebar-fg);
--icons: #737480;
--icons-hover: #b7b9cc;
--links: #0096cf;
--inline-code-color: #ffb454;
--theme-popup-bg: #14191f;
--theme-popup-border: #5c6773;
--theme-hover: #191f26;
--quote-bg: hsl(226, 15%, 17%);
--quote-border: hsl(226, 15%, 22%);
--table-border-color: hsl(210, 25%, 13%);
--table-header-bg: hsl(210, 25%, 28%);
--table-alternate-bg: hsl(210, 25%, 11%);
--searchbar-border-color: #848484;
--searchbar-bg: #424242;
--searchbar-fg: #fff;
--searchbar-shadow-color: #d4c89f;
--searchresults-header-fg: #666;
--searchresults-border-color: #888;
--searchresults-li-bg: #252932;
--search-mark-bg: #e3b171;
}
.menu {
background-color: var(--sidebar-bg);
ul a {
color: var(--sidebar-fg);
}
ul li.active > a {
color: var(--sidebar-active);
}
}
.page {
background-color: var(--bg);
color: var(--fg);
code {
color: var(--inline-code-color);
background-color: var(--bg-code);
}
.menu-icon > span {
background-color: rgba(255, 255, 255, 0.5);
}
}

5
docs/templates/index.html vendored Normal file
View file

@ -0,0 +1,5 @@
{% extends "book/templates/index.html" %}
{% block css %}
<link rel="stylesheet" href="{{ get_url(path="book.css") | safe }}">
<link rel="stylesheet" href="{{ get_url(path="style.css") | safe }}">
{% endblock css %}

2
docs/themes/book/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.idea/
public

21
docs/themes/book/LICENSE vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Vincent Prouillet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

54
docs/themes/book/README.md vendored Normal file
View file

@ -0,0 +1,54 @@
# book
A theme based on [Gitbook](https://www.gitbook.com), to write documentation
or books.
![book screenshot](https://github.com/Keats/book/blob/master/screenshot.png?raw=true)
## Contents
- [Installation](#installation)
- [Options](#options)
- [Numbered chapters](#numbered-chapters)
## Installation
First download this theme to your `themes` directory:
```bash
$ cd themes
$ git clone https://github.com/getzola/book.git
```
and then enable it in your `config.toml`:
```toml
theme = "book"
# Optional, if you want search
build_search_index = true
```
## Usage
Book will generate a book from the files you place in the `content` directory. Your book
can have two levels of hierarchy: chapters and subchapters.
Each chapter should be a `section` within the Gutenberg site and should have an `_index.md`
file that sets its `weight` front-matter variable to its chapter number. For example,
chapter 2 should have `weight = 2`. Additionally, each chapter should also set the
`sort_by = "weight"` in its front matter.
Each subchapter should be a `page` and should have its `weight` variable set to the subchapter
number. For example, subchapter 3.4 should have `weight = 4`.
Finally, you should create an `_index.md` file and set the `redirect_to` front-matter variable
to redirect to the first section of your content. For example, if your first section has the
slug `introduction`, then you would set `redirect_to = "introduction"`.
## Options
### Numbered chapters
By default, the `book` theme will number the chapters and pages in the left menu.
You can disable that by setting the `book_number_chapters` in `extra`:
```toml
book_number_chapters = false
```

9
docs/themes/book/config.toml vendored Normal file
View file

@ -0,0 +1,9 @@
base_url = "https://zola-book.netlify.com"
compile_sass = true
title = "book theme"
description = "A book theme"
highlight_code = true
build_search_index = true
[extra]
book_number_chapters = true

3
docs/themes/book/content/_index.md vendored Normal file
View file

@ -0,0 +1,3 @@
+++
redirect_to = "chapter1"
+++

View file

@ -0,0 +1,66 @@
+++
title = "Introduction"
weight = 1
sort_by = "weight"
insert_anchor_links = "right"
+++
Testing every `elements` you can find in [CommonMark](http://commonmark.org).
<!-- more -->
Quisque viverra a eros id auctor. Proin id nibh ut nisl dignissim pellentesque et ac mi. Nullam mattis urna quis consequat bibendum. Donec pretium dui elit, a semper purus tristique et. Mauris euismod nisl eu vehicula facilisis. Maecenas facilisis non massa non scelerisque. Integer malesuada cursus erat eu viverra. Duis ligula mi, eleifend vel justo id, laoreet porttitor ex. Etiam ultricies lacus lorem, sed aliquam nulla blandit in. Maecenas vel facilisis neque, vitae fringilla eros. In justo nibh, pellentesque sed faucibus nec, varius sit amet risus.
> This is a quote
- a
- bullet
- point
## Some code
```rust
fn main() {
let greetings = ["Hello", "Hola", "Bonjour",
"Ciao", "こんにちは", "안녕하세요",
"Cześć", "Olá", "Здравствуйте",
"Chào bạn", "您好", "Hallo",
"Hej", "Ahoj", "سلام"];
for (num, greeting) in greetings.iter().enumerate() {
print!("{} : ", greeting);
match num {
0 => println!("This code is editable and runnable!"),
1 => println!("¡Este código es editable y ejecutable!"),
2 => println!("Ce code est modifiable et exécutable !"),
3 => println!("Questo codice è modificabile ed eseguibile!"),
4 => println!("このコードは編集して実行出来ます!"),
5 => println!("여기에서 코드를 수정하고 실행할 수 있습니다!"),
6 => println!("Ten kod można edytować oraz uruchomić!"),
7 => println!("Este código é editável e executável!"),
8 => println!("Этот код можно отредактировать и запустить!"),
9 => println!("Bạn có thể edit và run code trực tiếp!"),
10 => println!("这段代码是可以编辑并且能够运行的!"),
11 => println!("Dieser Code kann bearbeitet und ausgeführt werden!"),
12 => println!("Den här koden kan redigeras och köras!"),
13 => println!("Tento kód můžete upravit a spustit"),
14 => println!("این کد قابلیت ویرایش و اجرا دارد!"),
_ => {},
}
}
}
```
## A table
| a | table | in | markdown | !! |
|----|-------|----|----------|---------------------------------|
| 1 | 2 | 3 | 4 | 5 |
| 1 | we | ew | we | with a longish column inside it |
## An image
![a cat](https://i.imgur.com/t6nPdY8.jpg "A cat")
## An iframe
{{ youtube(id="dQw4w9WgXcQ") }}

View file

@ -0,0 +1,84 @@
+++
title = "Page 1"
weight = 1
+++
Pages and sections are actually very similar.
## Page variables
Gutenberg will try to load the `templates/page.html` template, the `page.html` template of the theme if one is used
or will render the built-in template: a blank page.
Whichever template you decide to render, you will get a `page` variable in your template
with the following fields:
```ts
content: String;
title: String?;
description: String?;
date: String?;
slug: String;
path: String;
permalink: String;
summary: String?;
tags: Array<String>;
category: String?;
extra: HashMap<String, Any>;
// Naive word count, will not work for languages without whitespace
word_count: Number;
// Based on https://help.medium.com/hc/en-us/articles/214991667-Read-time
reading_time: Number;
// `previous` and `next` are only filled if the content can be sorted
previous: Page?;
next: Page?;
// See the Table of contents section below for more details
toc: Array<Header>;
```
## Section variables
By default, Gutenberg will try to load `templates/section.html`. If there isn't
one, it will render the built-in template: a blank page.
Whichever template you decide to render, you will get a `section` variable in your template
with the following fields:
```ts
content: String;
title: String?;
description: String?;
date: String?;
slug: String;
path: String;
permalink: String;
extra: HashMap<String, Any>;
// Pages directly in this section, sorted if asked
pages: Array<Pages>;
// Direct subsections to this section, sorted by subsections weight
subsections: Array<Section>;
// Naive word count, will not work for languages without whitespace
word_count: Number;
// Based on https://help.medium.com/hc/en-us/articles/214991667-Read-time
reading_time: Number;
// See the Table of contents section below for more details
toc: Array<Header>;
```
## Table of contents
Both page and section have a `toc` field which corresponds to an array of `Header`.
A `Header` has the following fields:
```ts
// The hX level
level: 1 | 2 | 3 | 4 | 5 | 6;
// The generated slug id
id: String;
// The text of the header
title: String;
// A link pointing directly to the header, using the inserted anchor
permalink: String;
// All lower level headers below this header
children: Array<Header>;
```

View file

@ -0,0 +1,6 @@
+++
title = "What is Gutenberg"
weight = 2
sort_by = "weight"
insert_anchor_links = "right"
+++

View file

@ -0,0 +1,14 @@
+++
title = "Page 1"
weight = 1
+++
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin pulvinar, sem id fermentum sollicitudin, velit sem elementum nisl, at tempus odio lectus eu sapien. Quisque ligula diam, cursus sed nisi et, ultricies rhoncus diam. Integer nec tellus a ante dapibus tincidunt nec id lacus. Quisque eu aliquet dui. Etiam placerat, ex in luctus lobortis, sem augue pellentesque nulla, in gravida lacus dui id arcu. Nam vel metus a ipsum condimentum porta non quis purus. Nullam feugiat vitae felis eu imperdiet. Sed et faucibus ligula.
Morbi tempus semper tellus eget luctus. Morbi eu dui leo. Aliquam vel neque id risus laoreet pellentesque. In mattis tincidunt nulla, sit amet pharetra tellus facilisis vel. Nulla facilisi. Nunc blandit massa a ante interdum pulvinar. Suspendisse bibendum efficitur gravida. Praesent gravida urna a luctus molestie. Fusce accumsan ipsum elit, quis gravida urna condimentum sed. Aliquam erat volutpat. Quisque eget mollis lorem, sit amet ultricies mauris. Fusce vulputate sollicitudin magna eget facilisis. Nunc id dignissim sapien.
Nulla pharetra eget ligula vitae auctor. Praesent consectetur consectetur nunc, quis commodo arcu posuere tincidunt. Praesent auctor, augue ut tincidunt semper, dolor ex malesuada justo, sit amet feugiat velit leo a lectus. Curabitur et velit ut magna vulputate vehicula nec sed lorem. Ut rutrum, odio sit amet mollis scelerisque, enim arcu euismod odio, vel faucibus libero ex sit amet nisl. Proin nec orci nec elit vehicula sodales id eget ex. Etiam et aliquet lacus. Cras tortor orci, blandit nec eleifend nec, venenatis at nibh. Vivamus eu feugiat purus. Nam viverra lobortis dui, non eleifend mauris commodo eget. Vestibulum quis erat et turpis maximus pretium. Aenean ac placerat quam. Nulla elit tortor, ornare a libero non, eleifend vestibulum nulla. Donec justo lorem, accumsan a feugiat ullamcorper, fringilla vel augue. Sed convallis et odio rhoncus vestibulum. Vivamus finibus lacinia dui, volutpat tincidunt felis condimentum et.
Cras accumsan libero sed nulla facilisis varius. Nulla auctor nibh quis mauris tincidunt fermentum. Nulla sed consectetur odio, a fringilla libero. Curabitur tincidunt varius mollis. Cras ornare nec enim in vestibulum. Quisque tempor nunc arcu, eu accumsan tellus pulvinar nec. Donec venenatis cursus est sed gravida. Ut non nisi sit amet ligula facilisis volutpat. Praesent lorem quam, euismod sit amet consequat eu, aliquam at justo. Nunc vel condimentum velit. Duis pharetra laoreet nulla sed consectetur. Pellentesque malesuada mauris id nunc ultricies, quis viverra tellus porttitor.
Aliquam vitae lectus tortor. Etiam auctor tortor elit, vel scelerisque metus tempor et. Quisque condimentum, massa vel condimentum sagittis, justo risus convallis eros, ac accumsan dolor ante in justo. Quisque et lacus at lectus semper commodo. Cras id viverra sem. Aliquam venenatis, tortor at fringilla semper, metus libero dictum libero, consequat facilisis nunc dolor sed sem. Nulla blandit, justo a condimentum malesuada, mauris mi lacinia orci, at finibus odio mi quis velit. Maecenas vel justo in lorem tristique sodales.

View file

@ -0,0 +1,6 @@
+++
title = "Chapter 3"
weight = 3
sort_by = "weight"
insert_anchor_links = "right"
+++

View file

@ -0,0 +1,20 @@
+++
title = "Page 1"
weight = 1
+++
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin pulvinar, sem id fermentum sollicitudin, velit sem elementum nisl, at tempus odio lectus eu sapien. Quisque ligula diam, cursus sed nisi et, ultricies rhoncus diam. Integer nec tellus a ante dapibus tincidunt nec id lacus. Quisque eu aliquet dui. Etiam placerat, ex in luctus lobortis, sem augue pellentesque nulla, in gravida lacus dui id arcu. Nam vel metus a ipsum condimentum porta non quis purus. Nullam feugiat vitae felis eu imperdiet. Sed et faucibus ligula.
```js
function isAllowed(user) {
return user.admin || user.staff;
}
```
Morbi tempus semper tellus eget luctus. Morbi eu dui leo. Aliquam vel neque id risus laoreet pellentesque. In mattis tincidunt nulla, sit amet pharetra tellus facilisis vel. Nulla facilisi. Nunc blandit massa a ante interdum pulvinar. Suspendisse bibendum efficitur gravida. Praesent gravida urna a luctus molestie. Fusce accumsan ipsum elit, quis gravida urna condimentum sed. Aliquam erat volutpat. Quisque eget mollis lorem, sit amet ultricies mauris. Fusce vulputate sollicitudin magna eget facilisis. Nunc id dignissim sapien.
Nulla pharetra eget ligula vitae auctor. Praesent consectetur consectetur nunc, quis commodo arcu posuere tincidunt. Praesent auctor, augue ut tincidunt semper, dolor ex malesuada justo, sit amet feugiat velit leo a lectus. Curabitur et velit ut magna vulputate vehicula nec sed lorem. Ut rutrum, odio sit amet mollis scelerisque, enim arcu euismod odio, vel faucibus libero ex sit amet nisl. Proin nec orci nec elit vehicula sodales id eget ex. Etiam et aliquet lacus. Cras tortor orci, blandit nec eleifend nec, venenatis at nibh. Vivamus eu feugiat purus. Nam viverra lobortis dui, non eleifend mauris commodo eget. Vestibulum quis erat et turpis maximus pretium. Aenean ac placerat quam. Nulla elit tortor, ornare a libero non, eleifend vestibulum nulla. Donec justo lorem, accumsan a feugiat ullamcorper, fringilla vel augue. Sed convallis et odio rhoncus vestibulum. Vivamus finibus lacinia dui, volutpat tincidunt felis condimentum et.
Cras accumsan libero sed nulla facilisis varius. Nulla auctor nibh quis mauris tincidunt fermentum. Nulla sed consectetur odio, a fringilla libero. Curabitur tincidunt varius mollis. Cras ornare nec enim in vestibulum. Quisque tempor nunc arcu, eu accumsan tellus pulvinar nec. Donec venenatis cursus est sed gravida. Ut non nisi sit amet ligula facilisis volutpat. Praesent lorem quam, euismod sit amet consequat eu, aliquam at justo. Nunc vel condimentum velit. Duis pharetra laoreet nulla sed consectetur. Pellentesque malesuada mauris id nunc ultricies, quis viverra tellus porttitor.
Aliquam vitae lectus tortor. Etiam auctor tortor elit, vel scelerisque metus tempor et. Quisque condimentum, massa vel condimentum sagittis, justo risus convallis eros, ac accumsan dolor ante in justo. Quisque et lacus at lectus semper commodo. Cras id viverra sem. Aliquam venenatis, tortor at fringilla semper, metus libero dictum libero, consequat facilisis nunc dolor sed sem. Nulla blandit, justo a condimentum malesuada, mauris mi lacinia orci, at finibus odio mi quis velit. Maecenas vel justo in lorem tristique sodales.

View file

@ -0,0 +1,20 @@
+++
title = "Page 2"
weight = 2
+++
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin pulvinar, sem id fermentum sollicitudin, velit sem elementum nisl, at tempus odio lectus eu sapien. Quisque ligula diam, cursus sed nisi et, ultricies rhoncus diam. Integer nec tellus a ante dapibus tincidunt nec id lacus. Quisque eu aliquet dui. Etiam placerat, ex in luctus lobortis, sem augue pellentesque nulla, in gravida lacus dui id arcu. Nam vel metus a ipsum condimentum porta non quis purus. Nullam feugiat vitae felis eu imperdiet. Sed et faucibus ligula.
```js
function isAllowed(user) {
return user.admin || user.staff;
}
```
Morbi tempus semper tellus eget luctus. Morbi eu dui leo. Aliquam vel neque id risus laoreet pellentesque. In mattis tincidunt nulla, sit amet pharetra tellus facilisis vel. Nulla facilisi. Nunc blandit massa a ante interdum pulvinar. Suspendisse bibendum efficitur gravida. Praesent gravida urna a luctus molestie. Fusce accumsan ipsum elit, quis gravida urna condimentum sed. Aliquam erat volutpat. Quisque eget mollis lorem, sit amet ultricies mauris. Fusce vulputate sollicitudin magna eget facilisis. Nunc id dignissim sapien.
Nulla pharetra eget ligula vitae auctor. Praesent consectetur consectetur nunc, quis commodo arcu posuere tincidunt. Praesent auctor, augue ut tincidunt semper, dolor ex malesuada justo, sit amet feugiat velit leo a lectus. Curabitur et velit ut magna vulputate vehicula nec sed lorem. Ut rutrum, odio sit amet mollis scelerisque, enim arcu euismod odio, vel faucibus libero ex sit amet nisl. Proin nec orci nec elit vehicula sodales id eget ex. Etiam et aliquet lacus. Cras tortor orci, blandit nec eleifend nec, venenatis at nibh. Vivamus eu feugiat purus. Nam viverra lobortis dui, non eleifend mauris commodo eget. Vestibulum quis erat et turpis maximus pretium. Aenean ac placerat quam. Nulla elit tortor, ornare a libero non, eleifend vestibulum nulla. Donec justo lorem, accumsan a feugiat ullamcorper, fringilla vel augue. Sed convallis et odio rhoncus vestibulum. Vivamus finibus lacinia dui, volutpat tincidunt felis condimentum et.
Cras accumsan libero sed nulla facilisis varius. Nulla auctor nibh quis mauris tincidunt fermentum. Nulla sed consectetur odio, a fringilla libero. Curabitur tincidunt varius mollis. Cras ornare nec enim in vestibulum. Quisque tempor nunc arcu, eu accumsan tellus pulvinar nec. Donec venenatis cursus est sed gravida. Ut non nisi sit amet ligula facilisis volutpat. Praesent lorem quam, euismod sit amet consequat eu, aliquam at justo. Nunc vel condimentum velit. Duis pharetra laoreet nulla sed consectetur. Pellentesque malesuada mauris id nunc ultricies, quis viverra tellus porttitor.
Aliquam vitae lectus tortor. Etiam auctor tortor elit, vel scelerisque metus tempor et. Quisque condimentum, massa vel condimentum sagittis, justo risus convallis eros, ac accumsan dolor ante in justo. Quisque et lacus at lectus semper commodo. Cras id viverra sem. Aliquam venenatis, tortor at fringilla semper, metus libero dictum libero, consequat facilisis nunc dolor sed sem. Nulla blandit, justo a condimentum malesuada, mauris mi lacinia orci, at finibus odio mi quis velit. Maecenas vel justo in lorem tristique sodales.

View file

@ -0,0 +1,6 @@
+++
title = "A chapter without sub-parts"
weight = 4
sort_by = "weight"
insert_anchor_links = "right"
+++

View file

@ -0,0 +1,6 @@
+++
title = "Another chapter without sub-parts"
weight = 5
sort_by = "weight"
insert_anchor_links = "right"
+++

226
docs/themes/book/sass/_content.scss vendored Normal file
View file

@ -0,0 +1,226 @@
.page {
position: absolute;
width: calc(100% - #{$sidebar-width});
height: 100%;
overflow-y: auto;
color: #000;
background: #fff;
padding-bottom: 20px;
transition: 0.5s;
.zola-anchor {
color: #4183c4;
padding-left: 10px;
text-decoration: none;
font-weight: initial;
&:hover {
text-decoration: underline;
}
}
img {
max-width: 100%;
}
&__content {
a {
color: #4183c4;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
hr {
height: 4px;
padding: 0;
margin: 1.7em 0;
overflow: hidden;
background-color: #e7e7e7;
border: none;
}
pre {
padding: 1rem;
span {
white-space: pre-wrap;
}
}
blockquote {
margin: 0;
margin-bottom: .85em;
padding: 0 15px;
color: #858585;
border-left: 4px solid #e5e5e5;
}
pre code {
background: none;
}
code {
display: inline-block;
vertical-align: middle;
padding: 0.1em 0.3em;
border-radius: 3px;
color: #6e6b5e;
background: #f1f1f1;
font-size: 0.875em;
font-family: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace;
}
iframe {
border: 0;
}
table {
margin: 0 auto;
border-collapse: collapse;
border-color: #cccccc;
td {
padding: 3px 20px;
border: 1px solid #ccc;
}
thead {
th {
padding: 6px 13px;
font-weight: bold;
border: 1px solid #ccc;
}
}
}
font-size: 1.6rem;
word-wrap: break-word;
line-height: 1.7;
position: relative;
left: 0;
max-width: 800px;
margin: 0 auto;
padding: 0 15px 40px;
p {
margin-top: 0;
margin-bottom: 0.85em;
}
}
.previous, .next {
position: fixed;
display: flex;
top: 50px;
bottom: 0;
font-size: 2.5em;
color: #ccc;
text-decoration: none;
text-align: center;
margin: 0;
max-width: 150px;
min-width: 90px;
justify-content: center;
align-content: center;
flex-direction: column;
&:hover {
color: #333;
}
}
.previous {
left: $sidebar-width;
float: left;
transition: left 0.5s;
}
.next {
// not 0 as it goes over the sidebar otherwise
right: 15px;
float: right;
}
@include max-screen(1250px) {
.previous, .next {
position: static;
top: auto;
display: inline-block;
max-width: 49%;
width: 49%;
&:hover {
text-decoration: none;
}
}
}
}
@include min-screen(600px) {
.page {
left: $sidebar-width;
}
}
.page-without-menu {
width: 100%;
left: 0;
.previous {
left: 15px;
}
}
@include max-screen(600px) {
.page {
width: 100%;
left: 0;
}
}
.search-container {
display: none;
&--is-visible {
display: block;
}
#search {
width: 100%;
padding: 1rem;
border: 1px solid #aaa;
border-radius: 3px;
background-color: #fafafa;
color: #000;
}
.search-results {
&__header {
font-weight: bold;
padding: 1rem 0rem;
}
&__items {
margin: 0;
padding: 0;
list-style: none;
}
&__item {
margin-bottom: 1rem;
}
&__teaser {
font-size: 90%;
}
}
}
.search-mode {
.prev-link, .next-link {
display: none;
}
}

160
docs/themes/book/sass/_header.scss vendored Normal file
View file

@ -0,0 +1,160 @@
@mixin menu-icon() {
@keyframes clickfirst {
0% {
transform: translateY(6px) rotate(0deg);
}
100% {
transform: translateY(0) rotate(45deg);
}
}
@keyframes clickmid {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes clicklast {
0% {
transform: translateY(-6px) rotate(0deg);
}
100% {
transform: translateY(0) rotate(-45deg);
}
}
@keyframes outfirst {
0% {
transform: translateY(0) rotate(-45deg);
}
100% {
transform: translateY(-6px) rotate(0deg);
}
}
@keyframes outmid {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes outlast {
0% {
transform: translateY(0) rotate(45deg);
}
100% {
transform: translateY(6px) rotate(0deg);
}
}
span {
position: absolute;
/* fallback for browsers which still doesn't support for `calc()` */
left: 15px;
top: 25px;
left: calc((100% - 20px) / 2);
top: calc((100% - 1px) / 2);
width: 20px;
height: 2px;
background-color: rgba(0, 0, 0, 0.5);
&:nth-child(1) {
transform: translateY(6px) rotate(0deg);
}
&:nth-child(3) {
transform: translateY(-6px) rotate(0deg);
}
}
&.icon-click {
span:nth-child(1) {
animation-duration: 0.5s;
animation-fill-mode: both;
animation-name: clickfirst;
}
span:nth-child(2) {
animation-duration: 0.2s;
animation-fill-mode: both;
animation-name: clickmid;
}
span:nth-child(3) {
animation-duration: 0.5s;
animation-fill-mode: both;
animation-name: clicklast;
}
}
&.icon-out {
span:nth-child(1) {
animation-duration: 0.5s;
animation-fill-mode: both;
animation-name: outfirst;
}
span:nth-child(2) {
animation-duration: 0.2s;
animation-fill-mode: both;
animation-name: outmid;
}
span:nth-child(3) {
animation-duration: 0.5s;
animation-fill-mode: both;
animation-name: outlast;
}
}
}
.page__header {
height: 50px;
.menu-icon {
height: 50px;
width: 50px;
font-size: 24px;
text-align: center;
float: left;
position: relative;
transition: background .5s;
cursor: pointer;
@include menu-icon();
&:hover {
span {
background-color: black;
}
}
}
.search-icon {
height: 50px;
width: 50px;
display: inline-block;
text-align: center;
line-height: 50px;
color: rgba(0, 0, 0, 0.5);
cursor: pointer;
font-size: 2rem;
&:hover {
color: black
}
}
}

50
docs/themes/book/sass/_navigation.scss vendored Normal file
View file

@ -0,0 +1,50 @@
.menu {
height: 100%;
position: absolute;
left: 0;
overflow-y: auto;
width: 300px;
color: #364149;
background: #fafafa;
border-right: 1px solid rgba(0, 0, 0, 0.07);
transition: 0.5s;
ul {
list-style: none;
margin: 0;
padding: 0;
a {
display: block;
color: #364149;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
text-decoration: none;
padding: 10px 15px;
&:hover {
text-decoration: underline;
}
}
li.active > a {
color: #008cff;
text-decoration: none;
}
ul {
padding-left: 20px;
}
}
}
.menu-hidden {
width: 0;
}
@include max-screen(600px) {
.menu {
width: 0;
}
}

447
docs/themes/book/sass/_normalize.scss vendored Normal file
View file

@ -0,0 +1,447 @@
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in
* IE on Windows Phone and in iOS.
*/
html {
line-height: 1.15; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers (opinionated).
*/
body {
margin: 0;
}
/**
* Add the correct display in IE 9-.
*/
article,
aside,
footer,
header,
nav,
section {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* Add the correct display in IE 9-.
* 1. Add the correct display in IE.
*/
figcaption,
figure,
main { /* 1 */
display: block;
}
/**
* Add the correct margin in IE 8.
*/
figure {
margin: 1em 40px;
}
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* 1. Remove the gray background on active links in IE 10.
* 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
*/
a {
background-color: transparent; /* 1 */
-webkit-text-decoration-skip: objects; /* 2 */
}
/**
* 1. Remove the bottom border in Chrome 57- and Firefox 39-.
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Prevent the duplicate application of `bolder` by the next rule in Safari 6.
*/
b,
strong {
font-weight: inherit;
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font style in Android 4.3-.
*/
dfn {
font-style: italic;
}
/**
* Add the correct background and color in IE 9-.
*/
mark {
background-color: #ff0;
color: #000;
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Add the correct display in IE 9-.
*/
audio,
video {
display: inline-block;
}
/**
* Add the correct display in iOS 4-7.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Remove the border on images inside links in IE 10-.
*/
img {
border-style: none;
}
/**
* Hide the overflow in IE.
*/
svg:not(:root) {
overflow: hidden;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers (opinionated).
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: sans-serif; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
* controls in Android 4.
* 2. Correct the inability to style clickable types in iOS and Safari.
*/
button,
html [type="button"], /* 1 */
[type="reset"],
[type="submit"] {
-webkit-appearance: button; /* 2 */
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* 1. Add the correct display in IE 9-.
* 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Remove the default vertical scrollbar in IE.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10-.
* 2. Remove the padding in IE 10-.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in IE 9-.
* 1. Add the correct display in Edge, IE, and Firefox.
*/
details, /* 1 */
menu {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Scripting
========================================================================== */
/**
* Add the correct display in IE 9-.
*/
canvas {
display: inline-block;
}
/**
* Add the correct display in IE.
*/
template {
display: none;
}
/* Hidden
========================================================================== */
/**
* Add the correct display in IE 10-.
*/
[hidden] {
display: none;
}

41
docs/themes/book/sass/book.scss vendored Normal file
View file

@ -0,0 +1,41 @@
@charset "utf-8";
@import "normalize";
* {
box-sizing: border-box;
}
html {
font-size: 62.5%;
}
body, html {
height: 100%;
}
body {
text-rendering: optimizeLegibility;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
letter-spacing: 0.2px;
}
@mixin min-screen($min-width: $body-width) {
@media screen and (min-width: $min-width) {
@content;
}
}
@mixin max-screen($max-width: $body-width) {
@media screen and (max-width: $max-width) {
@content;
}
}
$sidebar-width: 300px;
@import "navigation";
@import "content";
@import "header";

BIN
docs/themes/book/screenshot.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

223
docs/themes/book/static/book.js vendored Normal file
View file

@ -0,0 +1,223 @@
function initToggleMenu() {
var $menu = document.querySelector(".menu");
var $menuIcon = document.querySelector(".menu-icon");
var $page = document.querySelector(".page");
$menuIcon.addEventListener("click", function() {
$menu.classList.toggle("menu-hidden");
$page.classList.toggle("page-without-menu");
});
}
function debounce(func, wait) {
var timeout;
return function () {
var context = this;
var args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function () {
timeout = null;
func.apply(context, args);
}, wait);
};
}
// Taken from mdbook
// The strategy is as follows:
// First, assign a value to each word in the document:
// Words that correspond to search terms (stemmer aware): 40
// Normal words: 2
// First word in a sentence: 8
// Then use a sliding window with a constant number of words and count the
// sum of the values of the words within the window. Then use the window that got the
// maximum sum. If there are multiple maximas, then get the last one.
// Enclose the terms in <b>.
function makeTeaser(body, terms) {
var TERM_WEIGHT = 40;
var NORMAL_WORD_WEIGHT = 2;
var FIRST_WORD_WEIGHT = 8;
var TEASER_MAX_WORDS = 30;
var stemmedTerms = terms.map(function (w) {
return elasticlunr.stemmer(w.toLowerCase());
});
var termFound = false;
var index = 0;
var weighted = []; // contains elements of ["word", weight, index_in_document]
// split in sentences, then words
var sentences = body.toLowerCase().split(". ");
for (var i in sentences) {
var words = sentences[i].split(" ");
var value = FIRST_WORD_WEIGHT;
for (var j in words) {
var word = words[j];
if (word.length > 0) {
for (var k in stemmedTerms) {
if (elasticlunr.stemmer(word).startsWith(stemmedTerms[k])) {
value = TERM_WEIGHT;
termFound = true;
}
}
weighted.push([word, value, index]);
value = NORMAL_WORD_WEIGHT;
}
index += word.length;
index += 1; // ' ' or '.' if last word in sentence
}
index += 1; // because we split at a two-char boundary '. '
}
if (weighted.length === 0) {
return body;
}
var windowWeights = [];
var windowSize = Math.min(weighted.length, TEASER_MAX_WORDS);
// We add a window with all the weights first
var curSum = 0;
for (var i = 0; i < windowSize; i++) {
curSum += weighted[i][1];
}
windowWeights.push(curSum);
for (var i = 0; i < weighted.length - windowSize; i++) {
curSum -= weighted[i][1];
curSum += weighted[i + windowSize][1];
windowWeights.push(curSum);
}
// If we didn't find the term, just pick the first window
var maxSumIndex = 0;
if (termFound) {
var maxFound = 0;
// backwards
for (var i = windowWeights.length - 1; i >= 0; i--) {
if (windowWeights[i] > maxFound) {
maxFound = windowWeights[i];
maxSumIndex = i;
}
}
}
var teaser = [];
var startIndex = weighted[maxSumIndex][2];
for (var i = maxSumIndex; i < maxSumIndex + windowSize; i++) {
var word = weighted[i];
if (startIndex < word[2]) {
// missing text from index to start of `word`
teaser.push(body.substring(startIndex, word[2]));
startIndex = word[2];
}
// add <em/> around search terms
if (word[1] === TERM_WEIGHT) {
teaser.push("<b>");
}
startIndex = word[2] + word[0].length;
teaser.push(body.substring(word[2], startIndex));
if (word[1] === TERM_WEIGHT) {
teaser.push("</b>");
}
}
teaser.push("…");
return teaser.join("");
}
function formatSearchResultItem(item, terms) {
var li = document.createElement("li");
li.classList.add("search-results__item");
li.innerHTML = `<a href="${item.ref}">${item.doc.title}</a>`;
li.innerHTML += `<div class="search-results__teaser">${makeTeaser(item.doc.body, terms)}</div>`;
return li;
}
// Go from the book view to the search view
function toggleSearchMode() {
var $bookContent = document.querySelector(".book-content");
var $searchContainer = document.querySelector(".search-container");
if ($searchContainer.classList.contains("search-container--is-visible")) {
$searchContainer.classList.remove("search-container--is-visible");
document.body.classList.remove("search-mode");
$bookContent.style.display = "block";
} else {
$searchContainer.classList.add("search-container--is-visible");
document.body.classList.add("search-mode");
$bookContent.style.display = "none";
document.getElementById("search").focus();
}
}
function initSearch() {
var $searchInput = document.getElementById("search");
if (!$searchInput) {
return;
}
var $searchIcon = document.querySelector(".search-icon");
$searchIcon.addEventListener("click", toggleSearchMode);
var $searchResults = document.querySelector(".search-results");
var $searchResultsHeader = document.querySelector(".search-results__header");
var $searchResultsItems = document.querySelector(".search-results__items");
var MAX_ITEMS = 10;
var options = {
bool: "AND",
fields: {
title: {boost: 2},
body: {boost: 1},
}
};
var currentTerm = "";
var index = elasticlunr.Index.load(window.searchIndex);
$searchInput.addEventListener("keyup", debounce(function() {
var term = $searchInput.value.trim();
if (term === currentTerm || !index) {
return;
}
$searchResults.style.display = term === "" ? "none" : "block";
$searchResultsItems.innerHTML = "";
if (term === "") {
return;
}
var results = index.search(term, options).filter(function (r) {
return r.doc.body !== "";
});
if (results.length === 0) {
$searchResultsHeader.innerText = `No search results for '${term}'.`;
return;
}
currentTerm = term;
$searchResultsHeader.innerText = `${results.length} search results for '${term}':`;
for (var i = 0; i < Math.min(results.length, MAX_ITEMS); i++) {
if (!results[i].doc.body) {
continue;
}
// var item = document.createElement("li");
// item.innerHTML = formatSearchResultItem(results[i], term.split(" "));
console.log(results[i]);
$searchResultsItems.appendChild(formatSearchResultItem(results[i], term.split(" ")));
}
}, 150));
}
if (document.readyState === "complete" ||
(document.readyState !== "loading" && !document.documentElement.doScroll)
) {
initToggleMenu();
} else {
document.addEventListener("DOMContentLoaded", function () {
initToggleMenu();
initSearch();
});
}

109
docs/themes/book/templates/index.html vendored Normal file
View file

@ -0,0 +1,109 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<!-- Enable responsiveness on mobile devices-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
<title>{% block title %}{{ config.title }}{% endblock title %}</title>
{% block js %}
{% endblock js %}
<!-- CSS -->
{% block css %}
<link rel="stylesheet" href="{{ get_url(path="book.css") | safe }}">
{% endblock css %}
{% block extra_head %}
{% endblock extra_head %}
</head>
<body>
<div class="menu">
{% block before_menu %}
{% endblock before_menu %}
<nav role="navigation">
<ul>
{% block menu %}
{% set index = get_section(path="_index.md") %}
{% for s in index.subsections %}
{% set subsection = get_section(path=s) %}
<li {% if current_path == subsection.path %}class="active"{% endif %}>
{% set chapter_num = loop.index %}
<a href="{{ subsection.permalink }}">
{% if config.extra.book_number_chapters %}<strong>{{ chapter_num }}.</strong>{% endif %}
{{ subsection.title }}
</a>
{% if subsection.pages %}
<ul>
{% for page in subsection.pages %}
<li {% if current_path == page.path %}class="active"{% endif %}>
<a href="{{ page.permalink }}">
{% if config.extra.book_number_chapters %}<strong>{{ chapter_num }}.{{ loop.index }}.</strong>{% endif %}
{{ page.title }}
</a>
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
{% endblock menu %}
</ul>
</nav>
{% block after_menu %}
{% endblock after_menu %}
</div>
<div class="page">
<div class="page__header">
<div class="menu-icon">
<span></span>
<span></span>
<span></span>
</div>
{% if config.build_search_index %}
<span class="search-icon">🔎</span>
{% endif %}
</div>
<div class="page__content">
{% if config.build_search_index %}
<div class="search-container">
<input id="search" type="search" placeholder="Search..">
<div class="search-results">
<div class="search-results__header"></div>
<ul class="search-results__items"></ul>
</div>
</div>
{% endif %}
<div class="book-content">
{% block content %}
{% endblock content %}
</div>
</div>
<div class="prev-link">
{% block prev_link %}
{% endblock prev_link %}
</div>
<div class="next-link">
{% block next_link %}
{% endblock next_link %}
</div>
</div>
{% block js_body %}
{% if config.build_search_index %}
<script type="text/javascript" src="{{ get_url(path="elasticlunr.min.js") | safe }}"></script>
<script type="text/javascript" src="{{ get_url(path="search_index.en.js") | safe }}"></script>
{% endif %}
<script type="text/javascript" src="{{ get_url(path="book.js") | safe }}"></script>
{% endblock js_body %}
</body>
</html>

40
docs/themes/book/templates/page.html vendored Normal file
View file

@ -0,0 +1,40 @@
{% extends "index.html" %}
{% block content %}
<h1>{{ page.title }}</h1>
{{ page.content | safe }}
{% endblock content %}
{% block prev_link %}
{% if page.lighter %}
<a class="previous" href="{{ page.lighter.permalink }}"><</a>
{% else %}
{# No page before, find the link for the section it's in if there is one #}
{% set parent = get_section(path=page.ancestors | reverse | first) %}
<a class="previous" href="{{ parent.permalink }}"><</a>
{% endif %}
{% endblock prev_link %}
{% block next_link %}
{% if page.heavier %}
<a class="next" href="{{ page.heavier.permalink }}">></a>
{% else %}
{# No page after, find the link for the following section #}
{% set index = get_section(path="_index.md") %}
{% set found_current = false %}
{% for s in index.subsections %}
{% set subsection = get_section(path=s) %}
{% if found_current %}
<a class="next" href="{{ subsection.permalink }}">></a>
{# no break #}
{% set_global found_current = false %}
{% endif %}
{% for p in subsection.pages %}
{% if p.permalink == page.permalink %}
{% set_global found_current = true %}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endblock next_link %}

52
docs/themes/book/templates/section.html vendored Normal file
View file

@ -0,0 +1,52 @@
{% extends "index.html" %}
{% block content %}
<h1>{{ section.title }}</h1>
{{ section.content | safe }}
{% endblock content %}
{% block prev_link %}
{# need to find the last page of the previous section or the previous section directly
if there isn't any pages in it #}
{% set index = get_section(path="_index.md") %}
{% set found_current = false %}
{% for s in index.subsections | reverse %}
{% set subsection = get_section(path=s) %}
{% if subsection.permalink == section.permalink %}
{% set_global found_current = true %}
{% else %}
{% if found_current %}
{% if subsection.pages %}
{% set last_page = subsection.pages | last %}
<a class="previous" href="{{ last_page.permalink }}"><</a>
{% else %}
<a class="previous" href="{{ subsection.permalink }}"><</a>
{% endif %}
{# no break #}
{% set_global found_current = false %}
{% endif %}
{% endif %}
{% endfor %}
{% endblock prev_link %}
{% block next_link %}
{% if section.pages %}
{% set next_page = section.pages | first %}
<a class="next" href="{{ next_page.permalink }}">></a>
{% else %}
{# No page in the section, find the link for the following section #}
{% set index = get_section(path="_index.md") %}
{% set found_current = false %}
{% for s in index.subsections %}
{% set subsection = get_section(path=s) %}
{% if found_current %}
<a class="next" href="{{ subsection.permalink }}">></a>
{# no break #}
{% set_global found_current = false %}
{% endif %}
{% if subsection.permalink == section.permalink %}
{% set_global found_current = true %}
{% endif %}
{% endfor %}
{% endif %}
{% endblock next_link %}

13
docs/themes/book/theme.toml vendored Normal file
View file

@ -0,0 +1,13 @@
name = "book"
description = "A book theme inspired from GitBook/mdBook"
license = "MIT"
homepage = "https://github.com/getzola/book"
min_version = "0.5.0"
demo = "https://zola-book.netlify.com"
[extra]
book_number_chapters = true
[author]
name = "Vincent Prouillet"
homepage = "https://www.vincentprouillet.com"

92
gen-docs.js Normal file
View file

@ -0,0 +1,92 @@
const fs = require("fs");
fs.readFile(process.argv[process.argv.length - 1], "utf8", (err, data) => {
if (err) {
return console.log(err);
} else {
const vars = parseVars(data);
printDocs(vars, parseDocs(data));
}
});
function parseVars(code) {
const VAR_PATTERN = /^.*\/\/+ *@var +(.*?) +- +(.*)$/;
const vars = {};
for (let line of code.split("\n")) {
const match = line.match(VAR_PATTERN);
if (match && match.length == 3) {
const name = match[1];
const value = match[2];
vars[name] = value;
}
}
return vars;
}
function parseDocs(code) {
const NEW_WIDGET_PATTERN = /^.*\/\/+ *@widget +(!?)(.*?)(?: +extends +(.*))?$/;
const DESC_PATTERN = /^.*\/\/+ *@desc +(.*)$/;
const PROP_PATTERN = /^.*\/\/+ *@prop +(.*?) +- +(.*)$/;
const widgets = {};
let currentWidget = "";
for (let line of code.split("\n")) {
const newWidgetMatch = line.match(NEW_WIDGET_PATTERN);
if (newWidgetMatch && newWidgetMatch.length >= 3) {
const name = newWidgetMatch[2];
/** @type string[] */
const exts = newWidgetMatch[3]
? newWidgetMatch[3].split(/, */)
: [];
currentWidget = name;
widgets[currentWidget] = {
name,
exts,
props: [],
isVisible: newWidgetMatch[1] !== "!",
};
continue;
}
const descMatch = line.match(DESC_PATTERN);
if (descMatch && descMatch.length == 2) {
widgets[currentWidget].desc = descMatch[1];
continue;
}
const propMatch = line.match(PROP_PATTERN);
if (propMatch && propMatch.length == 3) {
widgets[currentWidget].props.push({
name: propMatch[1],
desc: propMatch[2],
});
}
}
return widgets;
}
function printDocs(vars, docs) {
let output = Object.values(docs)
.filter((x) => x.isVisible)
.map((x) => {
x.props = [
...x.props,
...x.exts.map((w) => docs[w]).flatMap((w) => w.props),
];
return x;
})
.map((x) => printWidget(x))
.map((x) => x.replace(/\$\w+/, (x) => vars[x.replace("$", "")]))
.join("\n\n");
console.log(output);
}
function printWidget(widget) {
return `
## \`${widget.name}\` ${widget.desc ? `\n${widget.desc}` : ""}
**Properties**
${widget.props.map((prop) => `- **\`${prop.name}\`**: ${prop.desc}`).join("\n")}
`;
}
// vim:ft=javascript