├── .gitignore ├── .watch.toml ├── Blades.toml ├── content ├── config.md ├── getting_started.md ├── index.md ├── making-plugins.md ├── pages.md ├── plugins │ ├── index.md │ ├── katex-js.md │ ├── katex-rs.md │ └── kroki.md ├── templates.md └── themes │ ├── BLADE.md │ ├── after-dark.md │ ├── casper.md │ └── index.md ├── public ├── CNAME ├── assets │ └── style.css ├── config.html ├── favicon.ico ├── getting_started.html ├── img │ ├── after-dark.png │ ├── blade.png │ └── casper.png ├── index.html ├── making-plugins.html ├── pages.html ├── plugins │ ├── index.html │ ├── katex-js.html │ ├── katex-rs.html │ └── kroki.html ├── sitemap.xml ├── templates.html └── themes │ ├── BLADE.html │ ├── after-dark.html │ ├── casper.html │ └── index.html ├── sass └── style.scss └── templates ├── foot.html ├── head.html ├── navigation.html ├── page.html ├── prevnext.html ├── section.html ├── theme.html └── themes.html /.gitignore: -------------------------------------------------------------------------------- 1 | **.blades* 2 | -------------------------------------------------------------------------------- /.watch.toml: -------------------------------------------------------------------------------- 1 | [[watch]] 2 | name = "build site" 3 | path = "templates" 4 | command = "blades build" 5 | 6 | [[watch]] 7 | name = "build site" 8 | path = "content" 9 | command = "blades build" 10 | 11 | [[watch]] 12 | name = "build site" 13 | path = "Blades.toml" 14 | command = "blades build" 15 | 16 | [[watch]] 17 | name = "build sass" 18 | path = "sass" 19 | command = "sassc -t compressed sass/style.scss public/assets/style.css" 20 | 21 | -------------------------------------------------------------------------------- /Blades.toml: -------------------------------------------------------------------------------- 1 | title = "Blades" 2 | description = "Blazing fast dead simple static site generator" 3 | keywords = "static site generator, fast, rust" 4 | author = "Maroš Grego" 5 | 6 | lang = "en-us" 7 | logo = "" 8 | 9 | atom = false 10 | rss = false 11 | 12 | repository = "https://github.com/grego/blades" 13 | 14 | footer = """ 15 | Created with **blades** 16 | (of course - check the [source](https://github.com/grego/bladesite)) 17 | by [Maroš Grego](https://grego.site). 18 | No JavaScript used. 19 | """ 20 | 21 | -------------------------------------------------------------------------------- /content/config.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Configuration" 3 | weight = 1 4 | +++ 5 | The site can be configured in the file `Blades.toml` in its root directory. There, the following 6 | variables can be set. All of them are optional, default values are shown. 7 | 8 | **Any** other variable of **any type** can be set there and used in the templates, too. 9 | 10 | ```toml 11 | # Title of the site 12 | title = "" 13 | # URL which the site is expected to be accessed through 14 | url = "" 15 | # Name of the folder where theme templates and assets shall be loaded from, 16 | # located in the themes directory (see below) 17 | theme = "" 18 | description = "" 19 | keywords = "" 20 | image = "" 21 | # A code for the language of the site, such as en-gb 22 | lang = "" 23 | 24 | # Generate sitemap 25 | sitemap = true 26 | # Generate RSS feed 27 | rss = true 28 | # Generate Atom feed 29 | atom = true 30 | # Generate taxonomies that were not explicitly defined in this config 31 | implicit_taxonomies = true 32 | # When no date for a page is specified, use the file creation date 33 | dates_of_creation = true 34 | 35 | # A directory where the content is loaded from 36 | content_dir = "content" 37 | # A directory where the theme is loaded from 38 | theme_dir = "themes" 39 | # A directory where the content is rendered to 40 | output_dir = "public" 41 | # A subdirectory of the output directory where the assets are copied to 42 | assets = "assets" 43 | 44 | author = "" 45 | email = "" 46 | 47 | # A table of tables where you can specify some data about taxonomies 48 | [taxonomies] 49 | # Example with default values: 50 | tags = { name = "", description = "", template = "taxonomy.html", key_template = "taxonomy_key.html", paginate_by = inf, sort_by_weight = false } 51 | # If provided, 'paginate_by' must be a positive integer 52 | 53 | # Plugins to use in the site 54 | [plugins] 55 | # Commands to run as input plugins 56 | input = [] 57 | # Commands to run as output plugins 58 | output = [] 59 | # Commands to run as transform plugins 60 | transform = [] 61 | # A map of a short name and a command to run as a content plugin 62 | # Each one can then be enabled on a particular page to transform its content 63 | content = {} 64 | # A list of content plugins (specified above) to run on every page 65 | default = [] 66 | ``` 67 | -------------------------------------------------------------------------------- /content/getting_started.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Getting started" 3 | weight = 0 4 | +++ 5 | 6 | ## Installation 7 | 8 | ### From Source 9 | With the Rust toolchain installed, you can install Blades from [crates.io](https://crates.io/crates/blades) 10 | ```sh 11 | cargo install blades 12 | ``` 13 | 14 | Or from its repository 15 | ``` sh 16 | git clone https://github.com/grego/blades 17 | cd blades 18 | cargo install --path . 19 | ``` 20 | 21 | ### macOS 22 | 23 | Using the package manager [MacPorts](https://www.macports.org) 24 | ```sh 25 | sudo port install blades 26 | ``` 27 | 28 | ## Blades Commands 29 | Once installed, you can run the executable `blades` with the following subcommands: 30 |
31 | 32 | `init` Initialise the site in the current directory, creating the basic files and folders 33 | 34 | `build` Build the site according to config, content, templates and themes in the current directory 35 | 36 | `colocate` Move the assets from the "assets" directory and from the theme, if one is used, into the output directory 37 | 38 | `all` Build the site and colocate the assets 39 | 40 | `lazy` Build the site and (colocate assets only if the theme was switched) [default] 41 | 42 | `new` Create a new page 43 | 44 |
45 | 46 | ## Themes 47 | When you specify a theme in the [config](config.html), templates and assets from the theme are used. 48 | Every site that doesn't use a theme can be used as a theme for another site. 49 | To use it, simply clone it into the themes directory. 50 | ```sh 51 | cd themes 52 | git clone $site_repository 53 | ``` 54 | 55 | Then, set it as a theme in `Blades.toml`: 56 | ```toml 57 | theme = "$site_name" 58 | ``` 59 | 60 | To overwrite the theme, simply use the files in the `templates`, resp. `assets` subdirectories of the 61 | page root directory. 62 | 63 | ## Assets 64 | All the files from the `assets` directory (and from the theme) are moved into the directory 65 | specified in the [config](config.html), which is emptied before. This is a subdirectory of the 66 | output directory (defaults to `assets`). 67 | 68 | Blades takes of the pages it rendered before and if some of them is deleted, the corresponding 69 | files in the output directory will be deleted, too. The other files in the output directory 70 | are left intact. This way, you can place anything in the output directory and (as long as its name 71 | differs from all the page names and it's not in the assets subdirectory), Blades won't touch it. 72 | 73 | ## Meta 74 | Blades renders [sitemap](https://www.sitemaps.org) (into `sitemap.xml`), [Atom](https://en.wikipedia.org/wiki/Atom_(Web_standard)) (into `atom.xml`) 75 | and [RSS](https://en.wikipedia.org/wiki/RSS) (into `rss.xml`) feeds, unless explicitly disabled in the [config](config.html). 76 | 77 | ## Contribution 78 | If you found a bug or would like to see some feature in Blades, you are the most welcome to submit an issue 79 | or a pull request! Likewise if you found something in this documentation not clear or imprecise. 80 | """ 81 | -------------------------------------------------------------------------------- /content/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Index" 3 | sort_by_weight = true 4 | +++ 5 | 6 | 7 | **bla**zing fast 8 | **de**ad simple 9 | **s**tatic site generator 10 | 11 | 12 | 13 | 14 | Blades is made to do one job - generate HTML files from the provided 15 | content using the provided templates. 16 | Thanks to [zero-copy](https://serde.rs/lifetimes.html#borrowing-data-in-a-derived-impl) deserialisation 17 | and the [Ramhorns](https://github.com/maciejhirsz/ramhorns) templating engine, 18 | it renders the whole site in milliseconds, possibly more than 19 | [20 times](https://github.com/grego/ssg-bench) faster than other generators like Hugo. 20 | 21 | It's made for easy setup and use. A static site generator should be a no brainer. 22 | It uses [mustache](https://mustache.github.io/mustache.5.html) templates with extremely minimal 23 | and obvious syntax (like 7 rules!), providing the necessary building blocks 24 | to let you focus on your content. 25 | 26 | ## Features 27 | * Powerful plugin system 28 | * Themes 29 | * Image gallery generation 30 | * [CommonMark](https://commonmark.org) markdown with tables and footnotes for content 31 | * Automatic syntax highlighting using [cmark-syntax](https://github.com/grego/cmark-syntax) 32 | (with a possibility of turning LaTeX formulas into [MathML](https://developer.mozilla.org/docs/Web/MathML)) 33 | * Customizable taxonomies (like categories or tags) 34 | * Pagination 35 | * Breadcrumbs 36 | * Asset colocation 37 | * Table of contents with access to all of the site data 38 | * Automatic sitemap, Atom and RSS feed generation 39 | 40 | ## Why not _`blades`_? 41 | Unlike other monolithic generators, Blades is modest in its scope. All it does is generating your site. 42 | It doesn't do any fancy stuff like transpiling Haskell to minified Javascript, or ever 43 | watching the site for changes. For that, you can use a dedicated tool like 44 | [caretaker](https://github.com/grego/caretaker). 45 | 46 | Nevertheless, if you have a feature request or ran into some issue using Blades, please submit an 47 | [issue](https://github.com/grego/blades). Any contribution 48 | is welcome! `:)` 49 | 50 | ## Why _`blades`_? 51 | They shave the [mustache](https://mustache.github.io/mustache.5.html) off. 52 | -------------------------------------------------------------------------------- /content/making-plugins.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Making plugins" 3 | weight = 5 4 | +++ 5 | Blades has a versatile extension system, where a plugin can be written in any language 6 | that can read from standard input and write to the standard output. 7 | Each plugin is run at the appropriate stage of site rendering. 8 | 9 | Check out the already made [plugins](/plugins/index.html). 10 | 11 | There are 4 types of plugins that can be used with Blades. 12 | * **input** - they put a JSON-serialised list of [pages](/pages.html) on the standard output, can be used 13 | to get pages from different sources 14 | * **output** - they receive a JSON-serialised list of [pages](/pages.html) on the standard input and can be 15 | used to generate further page data, such as processed images 16 | * **transform** - they receive a JSON-serialised list of [pages](/pages.html) on the standard input and output 17 | another such list on the standard output, can transform anything on the pages 18 | * **content** - they receive a markdown content of one page on standard input and output markdown on the standard output; they are enabled 19 | on per-page basis 20 | 21 | The plugins can be set up in the [config](/config.html). 22 | 23 | ### Serialised page data 24 | All the data specified on every [page](/pages.html) is available in the serialised list of pages. 25 | It contains only the fields that were explicitly set, so no field can be assumed to be 26 | present or non-present. 27 | 28 | For Rust, Blades also provides a 29 | [library](https://docs.rs/blades) for automatic serialisation and deserialisation of pages. 30 | Currently, Cargo doesn't support binary-only dependencies. As such, these dependencies are behind 31 | the `bin` feature gate, which is enabled by default. When using Blades as a library, they are not 32 | necessary, so it is recommended to import blades with `default_features = false`. 33 | 34 | ```toml 35 | blades = { version = "0.3", default_features = false } 36 | ``` 37 | 38 | ### Example 39 | An example plugin can be found in the [Blades repository](https://github.com/grego/blades) 40 | in the `examples` directory. 41 | To try it, clone it and downolad the theme as a submodule 42 | ```bash 43 | git clone https://github.com/grego/blades 44 | cd blades 45 | git submodule update --init 46 | ``` 47 | Then build the plugin: 48 | ```bash 49 | cargo build --release transform_plugin 50 | ``` 51 | Then run Blades in the `examples` directory: 52 | ```bash 53 | cd examples 54 | cargo run --release 55 | ``` 56 | 57 | Or check some [real plugins](/plugins/index.html). 58 | -------------------------------------------------------------------------------- /content/pages.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Pages" 3 | weight = 3 4 | +++ 5 | Blades loads all [Markdown](https://commonmark.org) 6 | files (`.md` extension) with an optional [TOML](https://toml.io) header (delimited by `+++`) 7 | and all TOML files (`.toml` extension) from the directory 8 | specified in the [config](config.html) (defaults to `content`). 9 | 10 | In these files, the page content 11 | and metadata are provided. They are then rendered using the provided [templates](templates.html). 12 | 13 | When the file is called `index.md` or `index.toml`, the corresponding page is called **section**. The rendered page (`index.html`) is displayed 14 | when the user browses to the parent URL. They can use some additional data in templates, 15 | such as their subpages and subsections. Other files are treated as standard pages. 16 | 17 | In pages (either in the header or in the TOML files), these variables can be specified. 18 | All of them are optional, default values are shown.
19 | **Any** other variable of **any type** can be set there and used in the templates, too. 20 | 21 | ```toml 22 | # Title of the page 23 | title = "" 24 | # Date when the page was created 25 | date = nan 26 | # date = 2020-09-08 27 | 28 | # An image representing the page 29 | image = "" 30 | # A brief summary of the page content 31 | summary = "" 32 | 33 | # The main content of the page 34 | # CommonMark markdown can be used here 35 | # In Markdown files, it is replaced with the actual content of the file, if present. 36 | content = """ 37 | """ 38 | 39 | # A weight of the page, used if a collection this page is in is sorted by weight 40 | weight = 0 41 | # A priority of this page for SEO, in the range of 0-1 42 | priority = 0.5 43 | # Hide the page from the list of its parent's subpages or subsections 44 | hidden = false 45 | #A list of alternative paths to render this page in, relative to the output directory 46 | alternative_paths = [] 47 | 48 | #A list of content plugins to transform the content of this page with 49 | plugins = [] 50 | 51 | # A template to render this page with. 52 | # If none is specified, the one specified in the parent section is used 53 | template = "" 54 | # A template to render the gallery pictures with 55 | gallery_template = "gallery.html" 56 | 57 | # A list of pictures associated with this page 58 | # Each will be rendered into a separate gallery page 59 | [[pictures]] 60 | # Id string of the picture, used for the generated URL in the gallery page 61 | # MANDATORY for every picture used! 62 | pid = "" 63 | # An associated caption of the picture 64 | # [CommonMark](https://commonmark.org/) markdown can be used here 65 | caption = "" 66 | # An alternative text displayed when the image can't be loaded of for accessibility 67 | alt = "" 68 | # File name of the image 69 | file = "" 70 | # Date and time of when the image was taken 71 | taken = None 72 | # Repeat for every picture 73 | 74 | # A map of lists to classify this page with 75 | [taxonomies] 76 | # For example: 77 | # tags = ["blades", "documentation"] 78 | ``` 79 | 80 | ## Sections { #sections } 81 | For pages that are sections, you can additionally specify these variables: 82 | 83 | ```toml 84 | # A number of pages to paginate by, if this number is exceeded 85 | # If provided, must be a positive integer 86 | paginate_by = inf 87 | # A template to render every subpage with (unless it specifies another template) 88 | page_template = "page.html" 89 | # A template to render every subsection with (unless it specifies another template) 90 | section_template = "section.html" 91 | # Sort subpages and subsetions by their provided weight, low to high 92 | # By default, they are sorted by their date, newer to older 93 | sort_by_weight = false 94 | ``` 95 | 96 | ## Not sections { #not-sections } 97 | For pages that are not sections, you can additionally specify these variables 98 | (defaults are suggested): 99 | 100 | ```toml 101 | # The path in the output directory this page is rendered into* 102 | path = "{{ parent directory of the page }}" 103 | # The file name this page is rendered into, without the .html extension* 104 | slug = "{{ file name without the extension }}" 105 | ``` 106 | 107 | For an actual example of pages in Blades, you can take a look at the 108 | code of [this site](https://github.com/grego/blades). 109 | -------------------------------------------------------------------------------- /content/plugins/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Plugins" 3 | template = "themes.html" 4 | page_template = "theme.html" 5 | sort_by_weight = true 6 | weight = 1 7 | +++ 8 | There are 4 types of plugins that can be used with Blades. 9 | * **input** - they can be used to get pages from different sources 10 | * **output** - they can be used to generate further page data, such as processed images 11 | * **transform** - they can transform anything on all of the pages 12 | * **content** - they transform markdowned content of a particular page 13 | 14 | The plugins can be set up in the [config](/config.html). 15 | 16 | Here is a list of known plugins. To contribute your own, submit a PR to the [plugin repository](https://github.com/grego/blades-plugins). 17 | -------------------------------------------------------------------------------- /content/plugins/katex-js.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "KaTeX - JavaScript" 3 | weight = 1 4 | summary = "Render math formulas using KaTeX - written in JavaScript" 5 | 6 | repository = "https://github.com/grego/blades-katex" 7 | +++ 8 | Blades natively supports rendering LaTeX formulas into [MathML](https://developer.mozilla.org/docs/Web/MathML). 9 | Sadly, Chromium-based browsers don't support it. 10 | This plugin renders the formulas into HTML using [KaTeX](https://katex.org). 11 | Formulas delimited by `$` are rendered in inline mode and by `$$` in display mode. 12 | 13 | Be aware there is a [Rust version](/plugins/katex-rs.html) that does the same, 14 | but faster. 15 | 16 | This plugin can be installed as 17 | ```bash 18 | yarn global add https://github.com/grego/blades-katex 19 | ``` 20 | 21 | Then, it can be used in Blades as 22 | ```toml 23 | [plugins] 24 | transform = ["blades-katex"] 25 | ``` 26 | 27 | This plugin is basically a stripped-down version of 28 | [auto-render extension](https://katex.org/docs/autorender.html) for KaTeX. 29 | 30 | -------------------------------------------------------------------------------- /content/plugins/katex-rs.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "KaTeX - Rust" 3 | weight = 0 4 | summary = "Render math formulas using KaTeX - written in Rust" 5 | 6 | repository = "https://github.com/grego/blades-katex-rs" 7 | +++ 8 | Blades natively supports rendering LaTeX formulas into [MathML](https://developer.mozilla.org/docs/Web/MathML). 9 | Sadly, Chromium-based browsers don't support it. 10 | This plugin renders the formulas into HTML using [KaTeX](https://katex.org), 11 | run with the QuickJS engine. 12 | Formulas delimited by `$` are rendered in inline mode and by `$$` in display mode. 13 | 14 | This plugin can be installed as 15 | ```bash 16 | cargo install blades-katex 17 | ``` 18 | 19 | Or from its git repository 20 | ```bash 21 | git clone https://github.com/grego/blades-katex-rs 22 | cd blades-katex-rs 23 | cargo install --path . 24 | ``` 25 | 26 | Then, it can be used in Blades as 27 | ```toml 28 | [plugins] 29 | transform = ["blades-katex"] 30 | ``` 31 | -------------------------------------------------------------------------------- /content/plugins/kroki.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Kroki" 3 | weight = 2 4 | summary = "Render code blocks using Kroki as the default service. The algorithm can be specified in the first line." 5 | 6 | repository = "https://github.com/Heiss/blades-kroki" 7 | +++ 8 | A transform plugin that renders code blocks using [Kroki](https://kroki.io/) as the default service. 9 | Code blocks are delimited by `` ``` `` and the algorithm can be specified in the first line. 10 | 11 | You can use any other code blocks as before, too. This plugin replaces only code blocks, which Kroki responses with a successful conversion of a diagram. Otherwise it will print out the code block untouched, so another plugin can handle it. 12 | 13 | ## Beware: 14 | 15 | This implementation currently not support parallel requests to kroki server, so a heavy load of diagrams can lags performance. But we are using a cache, so all requests done only once as long as you do not change the diagramtype or diagram content. 16 | 17 | ## Tutorial 18 | 19 | General use: 20 | 21 | ```` 22 | ```[Diagramtype] 23 | 24 | ``` 25 | ```` 26 | 27 | Example: 28 | ```` 29 | ```Graphviz 30 | digraph D { 31 | subgraph cluster_p { 32 | label = "Kroki"; 33 | subgraph cluster_c1 { 34 | label = "Server"; 35 | Filebeat; 36 | subgraph cluster_gc_1 { 37 | label = "Docker/Server"; 38 | Java; 39 | } 40 | subgraph cluster_gc_2 { 41 | label = "Docker/Mermaid"; 42 | "Node.js"; 43 | "Puppeteer"; 44 | "Chrome"; 45 | } 46 | } 47 | subgraph cluster_c2 { 48 | label = "CLI"; 49 | Golang; 50 | } 51 | } 52 | } 53 | ``` 54 | ```` 55 | 56 | This plugin can be installed as 57 | ```bash 58 | git clone https://github.com/Heiss/blades-kroki 59 | cd blades-kroki 60 | cargo install --path . 61 | ``` 62 | 63 | Then, it can be used in Blades as 64 | ```toml 65 | [plugins] 66 | transform = ["blades-kroki"] 67 | ``` 68 | -------------------------------------------------------------------------------- /content/templates.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Templates" 3 | weight = 4 4 | +++ 5 | Blades uses [mustache](https://mustache.github.io/mustache.5.html) templates with the 6 | [Ramhorns](https://github.com/maciejhirsz/ramhorns) engine. While their syntax is simple 7 | (and can be learned in a few minutes), they are surprisingly expressive. 8 | 9 | Templates are loaded from the `templates` subdirectory, or secondarily from the `themes/$theme/templates` 10 | directory if a theme is specified in the [config](config.html). 11 | 12 | Here is the list of variables available to use in templates. Apart from these, 13 | **any** other variable of **any type** specified on the [page](/page.html) 14 | or in the [site config](/config.html) can also be used. 15 | 16 | These variables are common for all pages: 17 | 18 | 19 | 20 | *// The data of the whole site* 21 | **site**: [Site](#site) 22 | *// Main page in the site* 23 | **index**: [Page](#page) 24 | *// A dictionary of all the taxonomies used in the site* 25 | **classification**: Map 26 | 27 | 28 | 29 | ## Page { #page } 30 | When rendering a page, these variables are available: 31 | 32 | 33 | 34 | *// Title of the page* 35 | **title**: string 36 | *// Date when the page was created* 37 | **date**: Option<[DateTime](#datetime)> 38 | *// Image representing the page* 39 | **image**: string 40 | *// A brief summary of the page* 41 | **summary**: string 42 | *// The main content of the page* 43 | **content**: string 44 | 45 | *// The full link of the page, with the site URL included* 46 | **permalink**: string 47 | *// The path of the page, beginning with `/`, without the last segment* 48 | *// When rendered as section ({{#path}}), it acts as a list of [Ancestors](#ancestors)* 49 | **path**: string 50 | *// The trailing segment of this page's URL* 51 | *// Without the .html extension* 52 | *// For sections, it's the folder name rather than `index`* 53 | **slug**: string 54 | *// A list of alternative paths where this page is rendered to, if any* 55 | **alternative_paths**: List 56 | 57 | *// A list of classifications for each of the provided taxonomies* 58 | **taxonomies**: Map 59 | *// A list of pictures provided by this page* 60 | **pictures**: List<[Picture](#picture)> 61 | 62 | *// Is this page a section?* 63 | **is_section**: bool 64 | *// Is the page hidden from the list of its parent's subpages and subsections?* 65 | **hidden**: bool 66 | *// A priority of this page for SEO, in the range of 0-1* 67 | **priority**: float 68 | 69 | *// The page one level up in the hierarchy (for the index page it's itself)* 70 | **parent**: [Page](#page) 71 | *// The previous page on this level, if any* 72 | **previous**: Option<[Page](#page)> 73 | *// The next page in this level, if any* 74 | **next**: Option<[Page](#page)> 75 | *// A list of all the subpages (empty if not section)* 76 | **pages**: List<[Page](#page)> 77 | *// A list of all the subsections (empty if not section)* 78 | **subsections**: List<[Page](#page)> 79 | *// Available when the subpages are paginated* 80 | **pagination**: Option<[Pagination](#pagination)> 81 | 82 | *// Marks whether this page is the active one* 83 | *// Can be used to highlight the current page in a list of pages* 84 | **active**: bool 85 | 86 | 87 | 88 | ### Pagination { #pagination } 89 | When the pagination is available, you can use these variables in the pagination section 90 | (`{{#pagination}} ... {{/pagination}}`): 91 | 92 | 93 | 94 | *// Number of the current page in the paginated pages* 95 | **current**: integer 96 | *// Number of the previous page in the paginated pages* 97 | *// This is also its slug* 98 | **previous**: Option<integer> 99 | *// Number of the next page in the paginated pages* 100 | *// This is also its slug* 101 | **next**: Option<integer> 102 | *// Number of the paginated pages* 103 | **length**: integer 104 | 105 | 106 | 107 | ### Ancestors { #ancestors } 108 | When the page path is used as a section (`{{#path}} ... {{/path}}`), it is interpreted 109 | as a list of ancestors. This makes making breadcrumbs possible. 110 | For the path segments, the following are available: 111 | 112 | 113 | 114 | *// Name of the current path segment* 115 | **name**: string 116 | *// The full path up to this segment* 117 | **full**: string 118 | 119 | 120 | 121 | ### DateTime { #datetime } 122 | When the date is available, you can use these variables in the datetime section 123 | (`{{#date}} ... {{/date}}`), roughly corresponding to [strftime](https://strftime.org/): 124 | 125 | 126 | 127 | *// Year* 128 | **y**: integer 129 | *// Month* 130 | **m**: integer 131 | *// Day, 0-padded* 132 | **d**: integer 133 | *// Day, space-padded* 134 | **e**: integer 135 | *// Hour* 136 | **H**: integer 137 | *// Minute* 138 | **M**: integer 139 | *// Second* 140 | **S**: integer 141 | *// First 3 letters of the English month name* 142 | **b**: string 143 | *// First 3 letters of the English weekday name* 144 | **a**: string 145 | 146 | 147 | 148 | ### Picture { #picture } 149 | When pictures are available, you can use these variables in the pictures section 150 | (`{{#pictures}} ... {{/pictures}}` for a list of them): 151 | 152 | 153 | 154 | *# Id string of the picture, used for the generated URL in the gallery page* 155 | **pid**: string 156 | *# An associated caption of the picture* 157 | **caption**: string 158 | *# An alternative text displayed when the image can't be loaded of for accessibility* 159 | **alt**: string 160 | *# File name of the image* 161 | **file**: string 162 | *# Date and time of when the image was taken* 163 | **taken**: Option<[DateTime](#datetime)> 164 | *// The full link of the picture, with the site URL included* 165 | **permalink**: string 166 | 167 | 168 | 169 | ## Gallery { #gallery } 170 | When a page contains come picture, the gallery is created. The page of each photo in the gallery 171 | gets the following variables: 172 | 173 | 174 | 175 | *// The current picture* 176 | **current**: [Picture](#picture) 177 | *// The previous picture in the list (the last one for the first one)* 178 | **previous**: [Picture](#picture) 179 | *// The next picture in the list (the first one for the last one)* 180 | **next**: [Picture](#picture) 181 | *// The parent page, from which this gallery is generated* 182 | **parent**: [Page](#page) 183 | 184 | 185 | 186 | ## Taxonomy { #taxonomy } 187 | Each taxonomy that is rendered gets the following variables: 188 | 189 | 190 | 191 | *// Full name of the taxonomy* 192 | **title**: string 193 | *// A short name of the taxonomy, used in the URL* 194 | **slug**: string 195 | *// A brief description of the taxonomy* 196 | **description**: string 197 | *// A list of keys used in this taxonomy and their corresponding pages* 198 | **keys**: List<[KeyPages](#keypages)> 199 | 200 | 201 | 202 | ### Key pages { #keypages } 203 | When keys in the taxonomy are available, you can use these variables in the keys section 204 | (`{{#keys}} ... {{/keys}}` for a list of them): 205 | 206 | 207 | 208 | *// Name of this key (also used in the URL of the key page)* 209 | **key**: str 210 | *// All the pages with this key in this taxonomy* 211 | **pages**: List<[Page](#page)> 212 | 213 | 214 | 215 | ## Taxonomy key { #taxonomy-key } 216 | When rendering a page of a single taxonomy key, these variables are available: 217 | 218 | 219 | 220 | *// Name of this key (also used in the URL)* 221 | **title**: string 222 | *// The parent taxonomy where this key belongs to* 223 | **taxonomy**: [Taxonomy](#taxonomy) 224 | *// The pages using this key* 225 | **pages**: List<[Page](#page)> 226 | *// Optional pagination, if enabled for this taxonomy* 227 | **pagination**: Option<[Pagination](#pagination)> 228 | 229 | 230 | 231 | ## Site { #site } 232 | The data of the whole site, available for every page in the site section 233 | (`{{#site}} ... {{/site}}`): 234 | 235 | 236 | 237 | *// The main title of the site* 238 | **title**: string 239 | *// The main URL of the site* 240 | **url**: string 241 | **description**: string 242 | **keywords**: string 243 | *// A representative image of the site* 244 | **image**: string 245 | *// Info about the author of the site* 246 | **author**: [Author](#author) 247 | 248 | *// Path of the site where the assets are moved to* 249 | **assets**: string 250 | *// Is sitemap rendered?* 251 | **sitemap**: bool 252 | *// Is atom feed rendered?* 253 | **atom**: bool 254 | *// Is RSS feed rendered?* 255 | **rss**: bool 256 | *// Are taxonomies not explicitly defined in the config, but used in some page rendered?* 257 | **implicit_taxonomies**: bool 258 | *// Are pages without date provided assigned the date of file creation?* 259 | **dates_of_creation**: bool 260 | 261 | 262 | 263 | ### Author { #author } 264 | Info about the site author, available as a subsection of [site](#site) 265 | (`{{#site}}{{#author}} ... {{/author}}{{/site}}`): 266 | 267 | 268 | 269 | **name**: string 270 | **uri**: string 271 | **email**: string 272 | **avatar**: string 273 | 274 | 275 | 276 | 277 | 278 | For an actual example of templates in Blades, you can take a look at the 279 | code of [this site](https://github.com/grego/bladesite), or of various 280 | [themes](/themes/index.html). 281 | -------------------------------------------------------------------------------- /content/themes/BLADE.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "BLADE.386" 3 | image = "img/blade.png" 4 | weight = 2 5 | summary = "For people who like the MS-DOS æsthetics" 6 | 7 | repository = "https://github.com/grego/BLADE.386" 8 | preview = "https://blade386.netlify.app/" 9 | +++ 10 | To use this theme, simply clone it into your themes directory: 11 | ```sh 12 | cd themes 13 | git clone https://github.com/grego/BLADE.386 14 | ``` 15 | 16 | Or use it as a submodule: 17 | ```sh 18 | cd themes 19 | git submodule add https://github.com/grego/BLADE.386 20 | ``` 21 | 22 | Then, set it in your [config](/config.html). 23 | ```toml 24 | theme = "BLADE.386" 25 | ``` 26 | -------------------------------------------------------------------------------- /content/themes/after-dark.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "after-dark" 3 | image = "img/after-dark.png" 4 | weight = 1 5 | summary = "Secure and accessible dark theme" 6 | 7 | preview = "https://blades-after-dark.netlify.app/" 8 | repository = "https://github.com/grego/after-dark" 9 | +++ 10 | To use this theme, simply clone it into your themes directory: 11 | ```sh 12 | cd themes 13 | git clone https://github.com/grego/after-dark 14 | ``` 15 | 16 | Or use it as a submodule: 17 | ```sh 18 | cd themes 19 | git submodule add https://github.com/grego/after-dark 20 | ``` 21 | 22 | Then, set it in your [config](/config.html). 23 | ```toml 24 | theme = "after-dark" 25 | ``` 26 | -------------------------------------------------------------------------------- /content/themes/casper.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "casper" 3 | image = "img/casper.png" 4 | weight = 0 5 | summary = "A clean blog theme, loosely based on the old Ghost.io default, but without JavaScript" 6 | 7 | preview = "https://blades-casper.netlify.app/" 8 | repository = "https://github.com/grego/casper" 9 | +++ 10 | To use this theme, simply clone it into your themes directory: 11 | ```sh 12 | cd themes 13 | git clone https://github.com/grego/casper 14 | ``` 15 | 16 | Or use it as a submodule: 17 | ```sh 18 | cd themes 19 | git submodule add https://github.com/grego/casper 20 | ``` 21 | 22 | Then, set it in your [config](/config.html). 23 | ```toml 24 | theme = "casper" 25 | ``` 26 | -------------------------------------------------------------------------------- /content/themes/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Themes" 3 | template = "themes.html" 4 | page_template = "theme.html" 5 | sort_by_weight = true 6 | weight = 0 7 | +++ 8 | Any site that doesn't use a theme can be used as a theme for another site. 9 | 10 | To use it, simply clone it into the themes directory. 11 | ```sh 12 | cd themes 13 | git clone $site_repository 14 | ``` 15 | 16 | Then, set it as a theme in `Blades.toml`: 17 | ```toml 18 | theme = "$site_name" 19 | ``` 20 | 21 | To contribute your own theme, submit a PR to the [themes repository](https://github.com/grego/blades-themes). 22 | -------------------------------------------------------------------------------- /public/CNAME: -------------------------------------------------------------------------------- 1 | www.getblades.org 2 | -------------------------------------------------------------------------------- /public/assets/style.css: -------------------------------------------------------------------------------- 1 | body{margin:0;font-family:Roboto, Arial, sans-serif;box-sizing:border-box;color:#283C3F;font-size:1.05em;line-height:1.6;background:#1B4C5C;min-height:100vh;display:flex;flex-direction:column;align-items:center}*{box-sizing:inherit}a,a:visited{transition:color 0.3s;color:#548799}a:hover,a:active,a:focus,.active{color:#B73E40 !important;transition:color 0.3s}.navlink.active::before{content:""}h1{font-size:2em}h2{margin-bottom:0}img{width:100%}td{vertical-align:top}td:first-of-type{margin-left:3em}td:not(:first-of-type){font-size:0.8em}code{font-size:0.9rem}.highlighted,pre code{background:#283C3F;display:inline-block;color:#F9F9F8;width:100%;padding:1em;white-space:pre-wrap}.highlighted,pre code p{margin:0}.highlighted strong,pre code strong,.language-toml var{color:#D3C377;font-weight:bold;font-style:normal}.language-toml strong{color:#B73E40}.language-toml em{font-weight:bold;font-style:normal;color:#B73E40}.highlighted em,pre code i{color:#548799}pre code u{color:#ddd;text-decoration:none}pre code span,pre code var{color:#D8F3FD;font-style:normal}ul{padding-left:1em;list-style-type:square}#topbar{padding:0.3em;font-size:2em;background:#1B4C5C;color:#D3C377;position:relative;width:100%;max-width:1024px;overflow-x:clip;margin:auto;display:flex;justify-content:space-between;flex-shrink:0}.blades-logo::before{content:"{";transform:rotate(90deg);display:inline-block;clip-path:polygon(0 19%, 0 100%, 100% 100%, 100% 41%)}.blades-logo::after{content:"//";/*! font-size: 0.8em; */letter-spacing:-0.40ex;transform:translateX(-0.35ex);display:inline-block}.blades-logo{display:inline;margin:0 0.7ex;font-family:monospace;font-style:initial}#logo{font-size:1.5em;font-weight:900;font-style:italic;line-height:initial;left:calc(50vw - min(512px, 50vw) + 0.5em);font-family:monospace;text-transform:lowercase;z-index:1}#logo a{color:#D3C377;text-decoration:none}.control-button{position:absolute;right:2rem;width:4rem;height:3rem;cursor:pointer;z-index:11;background:#1B4C5C;border:none;transition:background 0.5s cubic-bezier(0.77, 0.2, 0.05, 1);top:0.6rem;appearance:none;margin:0;-webkit-appearance:none;-moz-appearance:none}.control-button::before,.control-button::after{display:block;width:2rem;height:0.3rem;position:absolute;top:1.35rem;left:1rem;background:#D3C377;z-index:2;content:"";transition:transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1),background 0.5s cubic-bezier(0.77, 0.2, 0.05, 1);/*! position: fixed; */}.control-button::before{transform:rotate(45deg)}.control-button::after{transform:rotate(-45deg)}#burger-check::before{transform:translateY(-0.45rem)}#burger-check::after{transform:translateY(0.45rem)}#burger-check:checked::before{transform:rotate(-45deg)}#burger-check:checked::after{transform:rotate(45deg)}#burger-check:checked~#nav{transform:translateX(0)}#nav{z-index:6;background:#1B4C5C;width:100vw;margin-bottom:0;text-align:left;overflow-y:auto;transform:translateX(100%);display:flex;color:#D3C377;align-items:center;flex-direction:column;padding:5rem 2rem;font-size:initial;transition:transform 0.5s ease;/*! text-transform: lowercase; */left:0;top:0;position:absolute}.navlink,.navlink:visited{font-size:1.1rem;text-align:center;text-decoration:none;margin:0.6em 0.8em;color:#D3C377}#container{width:100%;max-width:1024px;display:flex;align-items:flex-start;flex-direction:column;justify-content:flex-end;z-index:2;flex-grow:1;margin:auto;margin-bottom:1em}#pagesnav{display:flex;flex-direction:column;margin-top:0.5em}.shadowed{padding:1em 2em;border:1px solid #283C3F;box-shadow:0.5em 0.5em rgba(40,60,63,0.866667);background:#F9F9F8}#navwrap{width:100%}.pagelink{text-decoration:none;margin:0.5em 0;display:block}.active{font-weight:500}.active::before{content:"// ";color:#D3C377}#content{width:100%;max-width:1024px;padding:1em 1.5em;background:#F9F9F8}#prevnext{display:flex;justify-content:space-between;margin:1.6em 1em 1em;background:#1B4C5C;font-size:1.1em;height:1.2em}#prevnext a{color:#D3C377;text-decoration:none}.full{width:100%;z-index:5}#footer{width:100%;text-align:center;color:#F9F9F8;font-size:0.8em;padding:0.8em 1em;flex-shrink:0;bottom:0}#footer a{color:#D3C377;text-decoration:none;margin:auto}#commands p{text-indent:-0.5em;padding-left:1em;margin:0.3em 0}#commands code{display:inline-block;min-width:4em}#theme-grid{display:flex;flex-direction:column}.theme{display:block;margin:1em;z-index:100;text-decoration:none;color:#283C3F !important}.theme:hover p,.theme:active p{color:#283C3F}.left{float:left}.right{float:right}@media screen and (min-width: 900px){#topbar{justify-content:right}#burger-check{display:none}#logo{position:fixed}#nav{transform:initial;position:relative;padding:initial;height:100%;width:initial;flex-direction:row}#container{flex-direction:row}#navwrap{width:256px;margin-right:4em;float:right}#pagesnav{width:256px;position:fixed;margin-left:1em;z-index:6}#content{padding:3em 4em;position:relative}#theme-grid{flex-direction:row;flex-wrap:wrap;background:#1B4C5C}.theme{width:calc(50% - 2em)}pre code{padding:2em 1em 2em 2.4em}.highlighted{padding:1em 1em 1em 2.4em}.full{max-width:780px}} 2 | -------------------------------------------------------------------------------- /public/config.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Configuration | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 | 55 |
56 |

Configuration

The site can be configured in the file Blades.toml in its root directory. There, the following 57 | variables can be set. All of them are optional, default values are shown.

58 |

Any other variable of any type can be set there and used in the templates, too.

59 |
# Title of the site
 60 | title = ""
 61 | # URL which the site is expected to be accessed through
 62 | url = ""
 63 | # Name of the folder where theme templates and assets shall be loaded from,
 64 | # located in the themes directory (see below)
 65 | theme = ""
 66 | description = "" 
 67 | keywords = ""
 68 | image = ""
 69 | # A code for the language of the site, such as en-gb
 70 | lang = ""
 71 | 
 72 | # Generate sitemap
 73 | sitemap = true
 74 | # Generate RSS feed
 75 | rss = true
 76 | # Generate Atom feed
 77 | atom = true
 78 | # Generate taxonomies that were not explicitly defined in this config
 79 | implicit_taxonomies = true
 80 | # When no date for a page is specified, use the file creation date
 81 | dates_of_creation = true
 82 | 
 83 | # A directory where the content is loaded from
 84 | content_dir = "content"
 85 | # A directory where the theme is loaded from
 86 | theme_dir = "themes"
 87 | # A directory where the content is rendered to
 88 | output_dir = "public"
 89 | # A subdirectory of the output directory where the assets are copied to
 90 | assets = "assets"
 91 | 
 92 | author = ""
 93 | email = ""
 94 | 
 95 | # A table of tables where you can specify some data about taxonomies
 96 | [taxonomies]
 97 | # Example with default values:
 98 | tags = { name = "", description = "", template = "taxonomy.html", key_template = "taxonomy_key.html", paginate_by = inf, sort_by_weight = false }
 99 | # If provided, 'paginate_by' must be a positive integer
100 | 
101 | # Plugins to use in the site
102 | [plugins]
103 | # Commands to run as input plugins
104 | input = []
105 | # Commands to run as output plugins
106 | output = []
107 | # Commands to run as transform plugins
108 | transform = []
109 | # A map of a short name and a command to run as a content plugin
110 | # Each one can then be enabled on a particular page to transform its content
111 | content = {}
112 | # A list of content plugins (specified above) to run on every page
113 | default = []
114 | 
115 |
116 | ← Getting started 117 | 118 | Pages → 119 |
120 |
121 |
122 | 126 | 127 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grego/bladesite/359b3560538c48196a58ffec0d5f32518b973d90/public/favicon.ico -------------------------------------------------------------------------------- /public/getting_started.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Getting started | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 | 55 |
56 |

Getting started

Installation

57 |

From Source

58 |

With the Rust toolchain installed, you can install Blades from crates.io

59 |
cargo install blades
 60 | 
61 |

Or from its repository

62 |
git clone https://github.com/grego/blades
 63 | cd blades
 64 | cargo install --path .
 65 | 
66 |

macOS

67 |

Using the package manager MacPorts

68 |
sudo port install blades
 69 | 
70 |

Blades Commands

71 |

Once installed, you can run the executable blades with the following subcommands:

72 |
73 |

init Initialise the site in the current directory, creating the basic files and folders

74 |

build Build the site according to config, content, templates and themes in the current directory

75 |

colocate Move the assets from the “assets” directory and from the theme, if one is used, into the output directory

76 |

all Build the site and colocate the assets

77 |

lazy Build the site and (colocate assets only if the theme was switched) [default]

78 |

new Create a new page

79 |
80 |

Themes

81 |

When you specify a theme in the config, templates and assets from the theme are used. 82 | Every site that doesn’t use a theme can be used as a theme for another site. 83 | To use it, simply clone it into the themes directory.

84 |
cd themes
 85 | git clone $site_repository
 86 | 
87 |

Then, set it as a theme in Blades.toml:

88 |
theme = "$site_name"
 89 | 
90 |

To overwrite the theme, simply use the files in the templates, resp. assets subdirectories of the 91 | page root directory.

92 |

Assets

93 |

All the files from the assets directory (and from the theme) are moved into the directory 94 | specified in the config, which is emptied before. This is a subdirectory of the 95 | output directory (defaults to assets).

96 |

Blades takes of the pages it rendered before and if some of them is deleted, the corresponding 97 | files in the output directory will be deleted, too. The other files in the output directory 98 | are left intact. This way, you can place anything in the output directory and (as long as its name 99 | differs from all the page names and it’s not in the assets subdirectory), Blades won’t touch it.

100 |

Meta

101 |

Blades renders sitemap (into sitemap.xml), Atom (into atom.xml) 102 | and RSS (into rss.xml) feeds, unless explicitly disabled in the config.

103 |

Contribution

104 |

If you found a bug or would like to see some feature in Blades, you are the most welcome to submit an issue 105 | or a pull request! Likewise if you found something in this documentation not clear or imprecise. 106 | “”“

107 |
108 |
109 | 110 | 111 | Configuration → 112 |
113 |
114 |
115 | 119 | 120 | -------------------------------------------------------------------------------- /public/img/after-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grego/bladesite/359b3560538c48196a58ffec0d5f32518b973d90/public/img/after-dark.png -------------------------------------------------------------------------------- /public/img/blade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grego/bladesite/359b3560538c48196a58ffec0d5f32518b973d90/public/img/blade.png -------------------------------------------------------------------------------- /public/img/casper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grego/bladesite/359b3560538c48196a58ffec0d5f32518b973d90/public/img/casper.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Index | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 | 55 |
56 |

blazing fast 57 | dead simple 58 | static site generator

59 |
60 |

Blades is made to do one job - generate HTML files from the provided 61 | content using the provided templates.
62 | Thanks to zero-copy deserialisation 63 | and the Ramhorns templating engine, 64 | it renders the whole site in milliseconds, possibly more than 65 | 20 times faster than other generators like Hugo.

66 |

It’s made for easy setup and use. A static site generator should be a no brainer. 67 | It uses mustache templates with extremely minimal 68 | and obvious syntax (like 7 rules!), providing the necessary building blocks 69 | to let you focus on your content.

70 |

Features

71 |
    72 |
  • Powerful plugin system
  • 73 |
  • Themes
  • 74 |
  • Image gallery generation
  • 75 |
  • CommonMark markdown with tables and footnotes for content
  • 76 |
  • Automatic syntax highlighting using cmark-syntax 77 | (with a possibility of turning LaTeX formulas into MathML)
  • 78 |
  • Customizable taxonomies (like categories or tags)
  • 79 |
  • Pagination
  • 80 |
  • Breadcrumbs
  • 81 |
  • Asset colocation
  • 82 |
  • Table of contents with access to all of the site data
  • 83 |
  • Automatic sitemap, Atom and RSS feed generation
  • 84 |
85 |

Why not blades?

86 |

Unlike other monolithic generators, Blades is modest in its scope. All it does is generating your site. 87 | It doesn’t do any fancy stuff like transpiling Haskell to minified Javascript, or ever 88 | watching the site for changes. For that, you can use a dedicated tool like 89 | caretaker.

90 |

Nevertheless, if you have a feature request or ran into some issue using Blades, please submit an 91 | issue. Any contribution 92 | is welcome! :)

93 |

Why blades?

94 |

They shave the mustache off.

95 |
96 |
97 | 101 | 102 | -------------------------------------------------------------------------------- /public/making-plugins.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Making plugins | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 | 55 |
56 |

Making plugins

Blades has a versatile extension system, where a plugin can be written in any language 57 | that can read from standard input and write to the standard output. 58 | Each plugin is run at the appropriate stage of site rendering.

59 |

Check out the already made plugins.

60 |

There are 4 types of plugins that can be used with Blades.

61 |
    62 |
  • input - they put a JSON-serialised list of pages on the standard output, can be used 63 | to get pages from different sources
  • 64 |
  • output - they receive a JSON-serialised list of pages on the standard input and can be 65 | used to generate further page data, such as processed images
  • 66 |
  • transform - they receive a JSON-serialised list of pages on the standard input and output 67 | another such list on the standard output, can transform anything on the pages
  • 68 |
  • content - they receive a markdown content of one page on standard input and output markdown on the standard output; they are enabled 69 | on per-page basis
  • 70 |
71 |

The plugins can be set up in the config.

72 |

Serialised page data

73 |

All the data specified on every page is available in the serialised list of pages. 74 | It contains only the fields that were explicitly set, so no field can be assumed to be 75 | present or non-present.

76 |

For Rust, Blades also provides a 77 | library for automatic serialisation and deserialisation of pages. 78 | Currently, Cargo doesn’t support binary-only dependencies. As such, these dependencies are behind 79 | the bin feature gate, which is enabled by default. When using Blades as a library, they are not 80 | necessary, so it is recommended to import blades with default_features = false.

81 |
blades = { version = "0.3", default_features = false }
 82 | 
83 |

Example

84 |

An example plugin can be found in the Blades repository 85 | in the examples directory. 86 | To try it, clone it and downolad the theme as a submodule

87 |
git clone https://github.com/grego/blades
 88 | cd blades
 89 | git submodule update --init
 90 | 
91 |

Then build the plugin:

92 |
cargo build --release transform_plugin
 93 | 
94 |

Then run Blades in the examples directory:

95 |
cd examples
 96 | cargo run --release
 97 | 
98 |

Or check some real plugins.

99 |
100 |
101 | ← Templates 102 | 103 | 104 |
105 |
106 |
107 | 111 | 112 | -------------------------------------------------------------------------------- /public/pages.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Pages | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 | 55 |
56 |

Pages

Blades loads all Markdown 57 | files (.md extension) with an optional TOML header (delimited by +++) 58 | and all TOML files (.toml extension) from the directory 59 | specified in the config (defaults to content).

60 |

In these files, the page content 61 | and metadata are provided. They are then rendered using the provided templates.

62 |

When the file is called index.md or index.toml, the corresponding page is called section. The rendered page (index.html) is displayed 63 | when the user browses to the parent URL. They can use some additional data in templates, 64 | such as their subpages and subsections. Other files are treated as standard pages.

65 |

In pages (either in the header or in the TOML files), these variables can be specified. 66 | All of them are optional, default values are shown.
67 | Any other variable of any type can be set there and used in the templates, too.

68 |
# Title of the page
 69 | title = ""
 70 | # Date when the page was created
 71 | date = nan
 72 | # date = 2020-09-08
 73 | 
 74 | # An image representing the page
 75 | image = ""
 76 | # A brief summary of the page content
 77 | summary = ""
 78 | 
 79 | # The main content of the page
 80 | # CommonMark markdown can be used here
 81 | # In Markdown files, it is replaced with the actual content of the file, if present.
 82 | content = """
 83 | """
 84 | 
 85 | # A weight of the page, used if a collection this page is in is sorted by weight
 86 | weight = 0
 87 | # A priority of this page for SEO, in the range of 0-1
 88 | priority = 0.5
 89 | # Hide the page from the list of its parent's subpages or subsections
 90 | hidden = false
 91 | #A list of alternative paths to render this page in, relative to the output directory
 92 | alternative_paths = []
 93 | 
 94 | #A list of content plugins to transform the content of this page with
 95 | plugins = []
 96 | 
 97 | # A template to render this page with.
 98 | # If none is specified, the one specified in the parent section is used
 99 | template = ""
100 | # A template to render the gallery pictures with
101 | gallery_template = "gallery.html"
102 | 
103 | # A list of pictures associated with this page
104 | # Each will be rendered into a separate gallery page
105 | [[pictures]]
106 | # Id string of the picture, used for the generated URL in the gallery page
107 | # MANDATORY for every picture used!
108 | pid = ""
109 | # An associated caption of the picture
110 | # [CommonMark](https://commonmark.org/) markdown can be used here
111 | caption = ""
112 | # An alternative text displayed when the image can't be loaded of for accessibility
113 | alt = ""
114 | # File name of the image
115 | file = ""
116 | # Date and time of when the image was taken
117 | taken = None
118 | # Repeat for every picture
119 | 
120 | # A map of lists to classify this page with
121 | [taxonomies]
122 | # For example:
123 | # tags = ["blades", "documentation"]
124 | 
125 |

Sections

126 |

For pages that are sections, you can additionally specify these variables:

127 |
# A number of pages to paginate by, if this number is exceeded
128 | # If provided, must be a positive integer
129 | paginate_by = inf
130 | # A template to render every subpage with (unless it specifies another template)
131 | page_template = "page.html"
132 | # A template to render every subsection with (unless it specifies another template)
133 | section_template = "section.html"
134 | # Sort subpages and subsetions by their provided weight, low to high
135 | # By default, they are sorted by their date, newer to older
136 | sort_by_weight = false
137 | 
138 |

Not sections

139 |

For pages that are not sections, you can additionally specify these variables 140 | (defaults are suggested):

141 |
# The path in the output directory this page is rendered into*
142 | path = "{{ parent directory of the page }}"
143 | # The file name this page is rendered into, without the .html extension*
144 | slug = "{{ file name without the extension }}"
145 | 
146 |

For an actual example of pages in Blades, you can take a look at the 147 | code of this site.

148 |
149 |
150 | ← Configuration 151 | 152 | Templates → 153 |
154 |
155 |
156 | 160 | 161 | -------------------------------------------------------------------------------- /public/plugins/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Plugins | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 |
43 |

There are 4 types of plugins that can be used with Blades.

44 |
    45 |
  • input - they can be used to get pages from different sources
  • 46 |
  • output - they can be used to generate further page data, such as processed images
  • 47 |
  • transform - they can transform anything on all of the pages
  • 48 |
  • content - they transform markdowned content of a particular page
  • 49 |
50 |

The plugins can be set up in the config.

51 |

Here is a list of known plugins. To contribute your own, submit a PR to the plugin repository.

52 |
53 |
54 | 55 | 56 |

KaTeX - Rust

57 |

Render math formulas using KaTeX - written in Rust

58 |
59 | 60 | 61 | 62 |

KaTeX - JavaScript

63 |

Render math formulas using KaTeX - written in JavaScript

64 |
65 | 66 | 67 | 68 |

Kroki

69 |

Render code blocks using Kroki as the default service. The algorithm can be specified in the first line.

70 |
71 |
72 |
73 |
74 | 78 | 79 | -------------------------------------------------------------------------------- /public/plugins/katex-js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | KaTeX - JavaScript | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 |
43 |
44 |

KaTeX - JavaScript

45 | 46 | 47 |

Render math formulas using KaTeX - written in JavaScript

48 | 49 |

Blades natively supports rendering LaTeX formulas into MathML. 50 | Sadly, Chromium-based browsers don’t support it. 51 | This plugin renders the formulas into HTML using KaTeX. 52 | Formulas delimited by $ are rendered in inline mode and by in display mode.

53 |

Be aware there is a Rust version that does the same, 54 | but faster.

55 |

This plugin can be installed as

56 |
yarn global add https://github.com/grego/blades-katex
57 | 
58 |

Then, it can be used in Blades as

59 |
[plugins]
60 | transform = ["blades-katex"]
61 | 
62 |

This plugin is basically a stripped-down version of 63 | auto-render extension for KaTeX.

64 | 65 |

Repository

66 |
67 |
68 | ← KaTeX - Rust 69 | 70 | Kroki → 71 |
72 |
73 |
74 | 78 | 79 | -------------------------------------------------------------------------------- /public/plugins/katex-rs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | KaTeX - Rust | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 |
43 |
44 |

KaTeX - Rust

45 | 46 | 47 |

Render math formulas using KaTeX - written in Rust

48 | 49 |

Blades natively supports rendering LaTeX formulas into MathML. 50 | Sadly, Chromium-based browsers don’t support it. 51 | This plugin renders the formulas into HTML using KaTeX, 52 | run with the QuickJS engine. 53 | Formulas delimited by $ are rendered in inline mode and by in display mode.

54 |

This plugin can be installed as

55 |
cargo install blades-katex
56 | 
57 |

Or from its git repository

58 |
git clone https://github.com/grego/blades-katex-rs
59 | cd blades-katex-rs
60 | cargo install --path .
61 | 
62 |

Then, it can be used in Blades as

63 |
[plugins]
64 | transform = ["blades-katex"]
65 | 
66 |

Repository

67 |
68 |
69 | 70 | 71 | KaTeX - JavaScript → 72 |
73 |
74 |
75 | 79 | 80 | -------------------------------------------------------------------------------- /public/plugins/kroki.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Kroki | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 |
43 |
44 |

Kroki

45 | 46 | 47 |

Render code blocks using Kroki as the default service. The algorithm can be specified in the first line.

48 | 49 |

A transform plugin that renders code blocks using Kroki as the default service. 50 | Code blocks are delimited by ``` and the algorithm can be specified in the first line.

51 |

You can use any other code blocks as before, too. This plugin replaces only code blocks, which Kroki responses with a successful conversion of a diagram. Otherwise it will print out the code block untouched, so another plugin can handle it.

52 |

Beware:

53 |

This implementation currently not support parallel requests to kroki server, so a heavy load of diagrams can lags performance. But we are using a cache, so all requests done only once as long as you do not change the diagramtype or diagram content.

54 |

Tutorial

55 |

General use:

56 |
```[Diagramtype]
 57 | <your diagram code>
 58 | ```
 59 | 
60 |

Example:

61 |
```Graphviz
 62 | digraph D {
 63 |   subgraph cluster_p {
 64 |     label = "Kroki";
 65 |     subgraph cluster_c1 {
 66 |       label = "Server";
 67 |       Filebeat;
 68 |       subgraph cluster_gc_1 {
 69 |         label = "Docker/Server";
 70 |         Java;
 71 |       }
 72 |       subgraph cluster_gc_2 {
 73 |         label = "Docker/Mermaid";
 74 |         "Node.js";
 75 |         "Puppeteer";
 76 |         "Chrome";
 77 |       }
 78 |     }
 79 |     subgraph cluster_c2 {
 80 |       label = "CLI";
 81 |       Golang;
 82 |     }
 83 |   }
 84 | }
 85 | ```
 86 | 
87 |

This plugin can be installed as

88 |
git clone https://github.com/Heiss/blades-kroki
 89 | cd blades-kroki
 90 | cargo install --path .
 91 | 
92 |

Then, it can be used in Blades as

93 |
[plugins]
 94 | transform = ["blades-kroki"]
 95 | 
96 |

Repository

97 |
98 |
99 | ← KaTeX - JavaScript 100 | 101 | 102 |
103 |
104 |
105 | 109 | 110 | -------------------------------------------------------------------------------- /public/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | / 5 | 0.5 6 | 7 | /getting_started.html 8 | 0.5 9 | 10 | /config.html 11 | 0.5 12 | 13 | /pages.html 14 | 0.5 15 | 16 | /templates.html 17 | 0.5 18 | 19 | /making-plugins.html 20 | 0.5 21 | 22 | /themes/ 23 | 0.5 24 | 25 | /plugins/ 26 | 0.5 27 | 28 | /themes/casper.html 29 | 0.5 30 | 31 | /themes/after-dark.html 32 | 0.5 33 | 34 | /themes/BLADE.html 35 | 0.5 36 | 37 | /plugins/katex-rs.html 38 | 0.5 39 | 40 | /plugins/katex-js.html 41 | 0.5 42 | 43 | /plugins/kroki.html 44 | 0.5 45 | 46 | 47 | -------------------------------------------------------------------------------- /public/templates.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Templates | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 | 55 |
56 |

Templates

Blades uses mustache templates with the 57 | Ramhorns engine. While their syntax is simple 58 | (and can be learned in a few minutes), they are surprisingly expressive.

59 |

Templates are loaded from the templates subdirectory, or secondarily from the themes/$theme/templates 60 | directory if a theme is specified in the config.

61 |

Here is the list of variables available to use in templates. Apart from these, 62 | any other variable of any type specified on the page 63 | or in the site config can also be used.

64 |

These variables are common for all pages:

65 | 66 |

// The data of the whole site 67 | site: Site 68 | // Main page in the site 69 | index: Page 70 | // A dictionary of all the taxonomies used in the site 71 | classification: Map<string, Taxonomy>

72 |
73 |

Page

74 |

When rendering a page, these variables are available:

75 | 76 |

// Title of the page 77 | title: string 78 | // Date when the page was created 79 | date: Option<DateTime> 80 | // Image representing the page 81 | image: string 82 | // A brief summary of the page 83 | summary: string 84 | // The main content of the page 85 | content: string

86 |

// The full link of the page, with the site URL included 87 | permalink: string 88 | // The path of the page, beginning with /, without the last segment 89 | // When rendered as section ({{#path}}), it acts as a list of Ancestors 90 | path: string 91 | // The trailing segment of this page’s URL 92 | // Without the .html extension 93 | // For sections, it’s the folder name rather than index 94 | slug: string 95 | // A list of alternative paths where this page is rendered to, if any 96 | alternative_paths: List

97 |

// A list of classifications for each of the provided taxonomies 98 | taxonomies: Map<string, List<string>> 99 | // A list of pictures provided by this page 100 | pictures: List<Picture>

101 |

// Is this page a section? 102 | is_section: bool 103 | // Is the page hidden from the list of its parent’s subpages and subsections? 104 | hidden: bool 105 | // A priority of this page for SEO, in the range of 0-1 106 | priority: float

107 |

// The page one level up in the hierarchy (for the index page it’s itself) 108 | parent: Page 109 | // The previous page on this level, if any 110 | previous: Option<Page> 111 | // The next page in this level, if any 112 | next: Option<Page> 113 | // A list of all the subpages (empty if not section) 114 | pages: List<Page> 115 | // A list of all the subsections (empty if not section) 116 | subsections: List<Page> 117 | // Available when the subpages are paginated 118 | pagination: Option<Pagination>

119 |

// Marks whether this page is the active one 120 | // Can be used to highlight the current page in a list of pages 121 | active: bool

122 |
123 |

Pagination

124 |

When the pagination is available, you can use these variables in the pagination section 125 | ({{#pagination}} ... {{/pagination}}):

126 | 127 |

// Number of the current page in the paginated pages 128 | current: integer 129 | // Number of the previous page in the paginated pages 130 | // This is also its slug 131 | previous: Option<integer> 132 | // Number of the next page in the paginated pages 133 | // This is also its slug 134 | next: Option<integer> 135 | // Number of the paginated pages 136 | length: integer

137 |
138 |

Ancestors

139 |

When the page path is used as a section ({{#path}} ... {{/path}}), it is interpreted 140 | as a list of ancestors. This makes making breadcrumbs possible. 141 | For the path segments, the following are available:

142 | 143 |

// Name of the current path segment 144 | name: string 145 | // The full path up to this segment 146 | full: string

147 |
148 |

DateTime

149 |

When the date is available, you can use these variables in the datetime section 150 | ({{#date}} ... {{/date}}), roughly corresponding to strftime:

151 | 152 |

// Year 153 | y: integer 154 | // Month 155 | m: integer 156 | // Day, 0-padded 157 | d: integer 158 | // Day, space-padded 159 | e: integer 160 | // Hour 161 | H: integer 162 | // Minute 163 | M: integer 164 | // Second 165 | S: integer 166 | // First 3 letters of the English month name 167 | b: string 168 | // First 3 letters of the English weekday name 169 | a: string

170 |
171 |

Picture

172 |

When pictures are available, you can use these variables in the pictures section 173 | ({{#pictures}} ... {{/pictures}} for a list of them):

174 | 175 |

# Id string of the picture, used for the generated URL in the gallery page 176 | pid: string 177 | # An associated caption of the picture 178 | caption: string 179 | # An alternative text displayed when the image can’t be loaded of for accessibility 180 | alt: string 181 | # File name of the image 182 | file: string 183 | # Date and time of when the image was taken 184 | taken: Option<DateTime> 185 | // The full link of the picture, with the site URL included 186 | permalink: string

187 |
188 | 189 |

When a page contains come picture, the gallery is created. The page of each photo in the gallery 190 | gets the following variables:

191 | 192 |

// The current picture 193 | current: Picture 194 | // The previous picture in the list (the last one for the first one) 195 | previous: Picture 196 | // The next picture in the list (the first one for the last one) 197 | next: Picture 198 | // The parent page, from which this gallery is generated 199 | parent: Page

200 |
201 |

Taxonomy

202 |

Each taxonomy that is rendered gets the following variables:

203 | 204 |

// Full name of the taxonomy 205 | title: string 206 | // A short name of the taxonomy, used in the URL 207 | slug: string 208 | // A brief description of the taxonomy 209 | description: string 210 | // A list of keys used in this taxonomy and their corresponding pages 211 | keys: List<KeyPages>

212 |
213 |

Key pages

214 |

When keys in the taxonomy are available, you can use these variables in the keys section 215 | ({{#keys}} ... {{/keys}} for a list of them):

216 | 217 |

// Name of this key (also used in the URL of the key page) 218 | key: str 219 | // All the pages with this key in this taxonomy 220 | pages: List<Page>

221 |
222 |

Taxonomy key

223 |

When rendering a page of a single taxonomy key, these variables are available:

224 | 225 |

// Name of this key (also used in the URL) 226 | title: string 227 | // The parent taxonomy where this key belongs to 228 | taxonomy: Taxonomy 229 | // The pages using this key 230 | pages: List<Page> 231 | // Optional pagination, if enabled for this taxonomy 232 | pagination: Option<Pagination>

233 |
234 |

Site

235 |

The data of the whole site, available for every page in the site section 236 | ({{#site}} ... {{/site}}):

237 | 238 |

// The main title of the site 239 | title: string 240 | // The main URL of the site 241 | url: string 242 | description: string 243 | keywords: string 244 | // A representative image of the site 245 | image: string 246 | // Info about the author of the site 247 | author: Author

248 |

// Path of the site where the assets are moved to 249 | assets: string 250 | // Is sitemap rendered? 251 | sitemap: bool 252 | // Is atom feed rendered? 253 | atom: bool 254 | // Is RSS feed rendered? 255 | rss: bool 256 | // Are taxonomies not explicitly defined in the config, but used in some page rendered? 257 | implicit_taxonomies: bool 258 | // Are pages without date provided assigned the date of file creation? 259 | dates_of_creation: bool

260 |
261 |

Author

262 |

Info about the site author, available as a subsection of site 263 | ({{#site}}{{#author}} ... {{/author}}{{/site}}):

264 | 265 |

name: string 266 | uri: string 267 | email: string 268 | avatar: string

269 |
270 |

For an actual example of templates in Blades, you can take a look at the 271 | code of this site, or of various 272 | themes.

273 |
274 |
275 | ← Pages 276 | 277 | Making plugins → 278 |
279 |
280 |
281 | 285 | 286 | -------------------------------------------------------------------------------- /public/themes/BLADE.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | BLADE.386 | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 |
43 |
44 |

BLADE.386

45 | 46 | 47 |

For people who like the MS-DOS æsthetics

48 |

Live demo

49 |

To use this theme, simply clone it into your themes directory:

50 |
cd themes
51 | git clone https://github.com/grego/BLADE.386
52 | 
53 |

Or use it as a submodule:

54 |
cd themes
55 | git submodule add https://github.com/grego/BLADE.386
56 | 
57 |

Then, set it in your config.

58 |
theme = "BLADE.386"
59 | 
60 |

Repository

61 |
62 |
63 | ← after-dark 64 | 65 | 66 |
67 |
68 |
69 | 73 | 74 | -------------------------------------------------------------------------------- /public/themes/after-dark.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | after-dark | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 |
43 |
44 |

after-dark

45 | 46 | 47 |

Secure and accessible dark theme

48 |

Live demo

49 |

To use this theme, simply clone it into your themes directory:

50 |
cd themes
51 | git clone https://github.com/grego/after-dark
52 | 
53 |

Or use it as a submodule:

54 |
cd themes
55 | git submodule add https://github.com/grego/after-dark
56 | 
57 |

Then, set it in your config.

58 |
theme = "after-dark"
59 | 
60 |

Repository

61 |
62 |
63 | ← casper 64 | 65 | BLADE.386 → 66 |
67 |
68 |
69 | 73 | 74 | -------------------------------------------------------------------------------- /public/themes/casper.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | casper | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 |
43 |
44 |

casper

45 | 46 | 47 |

A clean blog theme, loosely based on the old Ghost.io default, but without JavaScript

48 |

Live demo

49 |

To use this theme, simply clone it into your themes directory:

50 |
cd themes
51 | git clone https://github.com/grego/casper
52 | 
53 |

Or use it as a submodule:

54 |
cd themes
55 | git submodule add https://github.com/grego/casper
56 | 
57 |

Then, set it in your config.

58 |
theme = "casper"
59 | 
60 |

Repository

61 |
62 |
63 | 64 | 65 | after-dark → 66 |
67 |
68 |
69 | 73 | 74 | -------------------------------------------------------------------------------- /public/themes/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Themes | Blades 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 |
25 | 28 | 29 | 40 |
41 |
42 |
43 |

Any site that doesn’t use a theme can be used as a theme for another site.

44 |

To use it, simply clone it into the themes directory.

45 |
cd themes
46 | git clone $site_repository
47 | 
48 |

Then, set it as a theme in Blades.toml:

49 |
theme = "$site_name"
50 | 
51 |

To contribute your own theme, submit a PR to the themes repository.

52 |
53 |
54 | 55 | 56 |

casper

57 |

A clean blog theme, loosely based on the old Ghost.io default, but without JavaScript

58 |
59 | 60 | 61 | 62 |

after-dark

63 |

Secure and accessible dark theme

64 |
65 | 66 | 67 | 68 |

BLADE.386

69 |

For people who like the MS-DOS æsthetics

70 |
71 |
72 |
73 |
74 | 78 | 79 | -------------------------------------------------------------------------------- /sass/style.scss: -------------------------------------------------------------------------------- 1 | $dark: #1B4C5C; 2 | $main: #D3C377; 3 | $red: #B73E40; 4 | $link: #548799; 5 | $text: #283C3F; 6 | $bg: #F9F9F8; 7 | $shadow: #283C3FDD; 8 | $literal: #D8F3FD; 9 | 10 | body { 11 | margin: 0; 12 | font-family: Roboto, Arial, sans-serif; 13 | box-sizing: border-box; 14 | color: $text; 15 | font-size: 1.05em; 16 | line-height: 1.6; 17 | background: $dark; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | } 23 | 24 | * { 25 | box-sizing: inherit; 26 | } 27 | 28 | a, a:visited { 29 | transition: color 0.3s; 30 | color: $link; 31 | } 32 | 33 | a:hover, a:active, a:focus, .active { 34 | color: $red !important; 35 | transition: color 0.3s 36 | } 37 | 38 | .navlink.active::before { 39 | content: "" 40 | } 41 | 42 | h1 { 43 | font-size: 2em; 44 | } 45 | 46 | h2 { 47 | margin-bottom: 0 48 | } 49 | 50 | img { 51 | width: 100%; 52 | } 53 | 54 | td { 55 | vertical-align: top; 56 | } 57 | 58 | td:first-of-type { 59 | margin-left: 3em; 60 | } 61 | 62 | td:not(:first-of-type) { 63 | font-size: 0.8em; 64 | } 65 | 66 | code { 67 | font-size: 0.9rem; 68 | } 69 | 70 | .highlighted, pre code { 71 | background: $text; 72 | display: inline-block; 73 | color: $bg; 74 | width: 100%; 75 | padding: 1em; 76 | white-space: pre-wrap; 77 | } 78 | 79 | .highlighted, pre code p { 80 | margin: 0; 81 | } 82 | 83 | .highlighted strong, pre code strong, .language-toml var { 84 | color: $main; 85 | font-weight: bold; 86 | font-style: normal; 87 | } 88 | 89 | .language-toml strong { 90 | color: $red; 91 | } 92 | 93 | .language-toml em { 94 | font-weight: bold; 95 | font-style: normal; 96 | color: $red; 97 | } 98 | 99 | .highlighted em, pre code i { 100 | color: $link; 101 | } 102 | 103 | pre code u { 104 | color: #ddd; 105 | text-decoration: none; 106 | } 107 | 108 | pre code span, pre code var { 109 | color: $literal; 110 | font-style: normal; 111 | } 112 | 113 | ul { 114 | padding-left: 1em; 115 | list-style-type: square; 116 | } 117 | 118 | #topbar { 119 | padding: 0.3em; 120 | font-size: 2em; 121 | background: $dark; 122 | color: $main; 123 | position: relative; 124 | width: 100%; 125 | max-width: 1024px; 126 | overflow-x: clip; 127 | margin: auto; 128 | display: flex; 129 | justify-content: space-between; 130 | flex-shrink: 0; 131 | } 132 | 133 | .blades-logo::before { 134 | content: "{"; 135 | transform: rotate(90deg); 136 | display: inline-block; 137 | clip-path: polygon(0 19%, 0 100%, 100% 100%, 100% 41%); 138 | } 139 | 140 | .blades-logo::after { 141 | content: "//"; 142 | /*! font-size: 0.8em; */ 143 | letter-spacing: -0.40ex; 144 | transform: translateX(-0.35ex); 145 | display: inline-block; 146 | } 147 | 148 | .blades-logo { 149 | display: inline; 150 | margin: 0 0.7ex; 151 | font-family: monospace; 152 | font-style: initial; 153 | } 154 | 155 | #logo { 156 | font-size: 1.5em; 157 | font-weight: 900; 158 | font-style: italic; 159 | line-height: initial; 160 | left: calc(50vw - min(512px, 50vw) + 0.5em); 161 | font-family: monospace; 162 | text-transform: lowercase; 163 | z-index: 1; 164 | } 165 | 166 | #logo a { 167 | color: $main; 168 | text-decoration: none; 169 | } 170 | 171 | .control-button { 172 | position: absolute; 173 | right: 2rem; 174 | width: 4rem; 175 | height: 3rem; 176 | cursor: pointer; 177 | z-index: 11; 178 | background: $dark; 179 | border: none; 180 | transition: background 0.5s cubic-bezier(0.77,0.2,0.05,1.0); 181 | top: 0.6rem; 182 | appearance: none; 183 | margin: 0; 184 | -webkit-appearance: none; 185 | -moz-appearance: none; 186 | } 187 | 188 | .control-button::before, .control-button::after { 189 | display: block; 190 | width: 2rem; 191 | height: 0.3rem; 192 | position: absolute; 193 | top: 1.35rem; 194 | left: 1rem; 195 | 196 | background: $main; 197 | 198 | z-index: 2; 199 | content: ""; 200 | 201 | transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0), 202 | background 0.5s cubic-bezier(0.77,0.2,0.05,1.0); 203 | /*! position: fixed; */ 204 | } 205 | 206 | .control-button::before { 207 | transform: rotate(45deg); 208 | } 209 | 210 | .control-button::after { 211 | transform: rotate(-45deg); 212 | } 213 | 214 | #burger-check::before { 215 | transform: translateY(-0.45rem); 216 | } 217 | 218 | #burger-check::after { 219 | transform: translateY(0.45rem); 220 | } 221 | 222 | #burger-check:checked::before { 223 | transform: rotate(-45deg); 224 | } 225 | 226 | #burger-check:checked::after { 227 | transform: rotate(45deg); 228 | } 229 | 230 | #burger-check:checked ~ #nav { 231 | transform: translateX(0); 232 | } 233 | 234 | #nav { 235 | z-index: 6; 236 | background: $dark; 237 | width: 100vw; 238 | margin-bottom: 0; 239 | text-align: left; 240 | overflow-y: auto; 241 | 242 | transform: translateX(100%); 243 | display: flex; 244 | color: $main; 245 | align-items: center; 246 | flex-direction: column; 247 | padding: 5rem 2rem; 248 | font-size: initial; 249 | transition: transform 0.5s ease; 250 | /*! text-transform: lowercase; */ 251 | left: 0; 252 | top: 0; 253 | position: absolute; 254 | } 255 | 256 | .navlink, .navlink:visited { 257 | font-size: 1.1rem; 258 | text-align: center; 259 | text-decoration: none; 260 | margin: 0.6em 0.8em; 261 | color: $main; 262 | } 263 | 264 | #container { 265 | width: 100%; 266 | max-width: 1024px; 267 | display: flex; 268 | align-items: flex-start; 269 | flex-direction: column; 270 | justify-content: flex-end; 271 | z-index: 2; 272 | flex-grow: 1; 273 | margin: auto; 274 | margin-bottom: 1em; 275 | } 276 | 277 | #pagesnav { 278 | display: flex; 279 | flex-direction: column; 280 | margin-top: 0.5em; 281 | } 282 | 283 | .shadowed { 284 | padding: 1em 2em; 285 | border: 1px solid $text; 286 | box-shadow: 0.5em 0.5em $shadow; 287 | background: $bg; 288 | } 289 | 290 | #navwrap { 291 | width: 100%; 292 | } 293 | 294 | .pagelink { 295 | text-decoration: none; 296 | margin: 0.5em 0; 297 | display: block; 298 | } 299 | 300 | .active { 301 | font-weight: 500; 302 | } 303 | 304 | .active::before { 305 | content: "// "; 306 | color: $main; 307 | } 308 | 309 | #content { 310 | width: 100%; 311 | max-width: 1024px; 312 | padding: 1em 1.5em; 313 | background: $bg; 314 | } 315 | 316 | #prevnext { 317 | display: flex; 318 | justify-content: space-between; 319 | margin: 1.6em 1em 1em; 320 | background: $dark; 321 | font-size: 1.1em; 322 | height: 1.2em; 323 | } 324 | 325 | #prevnext a { 326 | color: $main; 327 | text-decoration: none; 328 | } 329 | 330 | .full { 331 | width: 100%; 332 | z-index: 5; 333 | } 334 | 335 | #footer { 336 | width: 100%; 337 | text-align: center; 338 | color: $bg; 339 | font-size: 0.8em; 340 | padding: 0.8em 1em; 341 | flex-shrink: 0; 342 | bottom: 0; 343 | } 344 | 345 | #footer a { 346 | color: $main; 347 | text-decoration: none; 348 | margin: auto; 349 | } 350 | 351 | #commands p { 352 | text-indent: -0.5em; 353 | padding-left: 1em; 354 | margin: 0.3em 0; 355 | } 356 | 357 | #commands code { 358 | display: inline-block; 359 | min-width: 4em; 360 | } 361 | 362 | #theme-grid { 363 | display: flex; 364 | flex-direction: column; 365 | } 366 | 367 | .theme { 368 | display: block; 369 | margin: 1em; 370 | z-index: 100; 371 | text-decoration: none; 372 | color: $text !important; 373 | } 374 | 375 | .theme:hover p, .theme:active p { 376 | color: $text; 377 | } 378 | 379 | .left { 380 | float: left; 381 | } 382 | 383 | .right { 384 | float: right; 385 | } 386 | 387 | @media screen and (min-width: 900px) { 388 | #topbar { 389 | justify-content: right; 390 | } 391 | 392 | #burger-check { 393 | display: none; 394 | } 395 | 396 | #logo { 397 | position: fixed; 398 | } 399 | 400 | #nav { 401 | transform: initial; 402 | position: relative; 403 | padding: initial; 404 | height: 100%; 405 | width: initial; 406 | flex-direction: row; 407 | } 408 | 409 | #container { 410 | flex-direction: row; 411 | } 412 | 413 | #navwrap { 414 | width: 256px; 415 | margin-right: 4em; 416 | float: right; 417 | } 418 | 419 | #pagesnav { 420 | width: 256px; 421 | position: fixed; 422 | margin-left: 1em; 423 | z-index: 6; 424 | } 425 | 426 | #content { 427 | padding: 3em 4em; 428 | position: relative; 429 | } 430 | 431 | #theme-grid { 432 | flex-direction: row; 433 | flex-wrap: wrap; 434 | background: $dark; 435 | } 436 | 437 | .theme { 438 | width: calc(50% - 2em); 439 | } 440 | 441 | pre code { 442 | padding: 2em 1em 2em 2.4em; 443 | } 444 | 445 | .highlighted { 446 | padding: 1em 1em 1em 2.4em; 447 | } 448 | 449 | .full { 450 | max-width: 780px; 451 | } 452 | } 453 | 454 | -------------------------------------------------------------------------------- /templates/foot.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /templates/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{title}}{{current pid}} | {{#site}}{{title}} 9 | {{#author}}{{/author}} 10 | {{#description}}{{/description}} 11 | {{#keywords}}{{/keywords}} 12 | 13 | 14 | {{#rss}}{{/rss}} 15 | {{#atom}}{{/atom}} 16 | 17 | {{/site}} 18 | 21 | 22 | 23 | 24 | {{>navigation.html}} 25 |
26 | -------------------------------------------------------------------------------- /templates/navigation.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | 6 | 15 |
16 | -------------------------------------------------------------------------------- /templates/page.html: -------------------------------------------------------------------------------- 1 | {{>head.html}} 2 | 7 |
8 |

{{title}}

{{content}}
9 | {{>prevnext.html}} 10 |
11 | {{>foot.html}} 12 | -------------------------------------------------------------------------------- /templates/prevnext.html: -------------------------------------------------------------------------------- 1 |
2 | {{#previous}}← {{title}}{{/previous}} 3 | {{^previous}}{{/previous}} 4 | {{#next}}{{title}} →{{/next}} 5 |
6 | -------------------------------------------------------------------------------- /templates/section.html: -------------------------------------------------------------------------------- 1 | {{>head.html}} 2 | 7 |
{{content}}
8 | {{>foot.html}} 9 | -------------------------------------------------------------------------------- /templates/theme.html: -------------------------------------------------------------------------------- 1 | {{>head.html}} 2 |
3 |
4 |

{{title}}

5 | {{#author}}by {{author}}{{/author}} 6 | {{#image}}{{/image}} 7 | {{#summary}}

{{summary}}

{{/summary}} 8 | {{#preview}}

Live demo

{{/preview}} 9 | {{content}} 10 | {{#repository}}

Repository

{{/repository}} 11 |
12 | {{>prevnext.html}} 13 |
14 | {{>foot.html}} 15 | -------------------------------------------------------------------------------- /templates/themes.html: -------------------------------------------------------------------------------- 1 | {{>head.html}} 2 |
3 |
{{content}}
4 |
{{#pages}} 5 | 6 | {{#image}}{{/image}} 7 |

{{title}}

8 |

{{summary}}

9 |
10 | {{/pages}}
11 |
12 | {{>foot.html}} 13 | --------------------------------------------------------------------------------