Refactored JavaScript architecture

This commit is contained in:
squidfunk 2016-12-15 15:55:40 +01:00
parent 65f23355c8
commit 2fcfb551be
73 changed files with 9541 additions and 921 deletions

View File

@ -76,7 +76,8 @@
"var": 2, "var": 2,
"let": 2, "let": 2,
"const": 3 "const": 3
} },
"SwitchCase": 1
}], }],
"init-declarations": 2, "init-declarations": 2,
"key-spacing": 2, "key-spacing": 2,
@ -115,7 +116,7 @@
"max": 1 "max": 1
}], }],
"no-nested-ternary": 2, "no-nested-ternary": 2,
"no-new": 2, "no-new": 0,
"no-new-object": 2, "no-new-object": 2,
"no-param-reassign": 2, "no-param-reassign": 2,
"no-prototype-builtins": 2, "no-prototype-builtins": 2,
@ -142,7 +143,6 @@
"no-whitespace-before-property": 2, "no-whitespace-before-property": 2,
"no-with": 2, "no-with": 2,
"object-curly-spacing": [2, "always"], "object-curly-spacing": [2, "always"],
"object-property-newline": 2,
"object-shorthand": 2, "object-shorthand": 2,
"one-var-declaration-per-line": 2, "one-var-declaration-per-line": 2,
"operator-assignment": 2, "operator-assignment": 2,

View File

@ -21,6 +21,8 @@
files: files:
ignore: ignore:
- node_modules/** - node_modules/**
- src/assets/stylesheets/extensions/pymdown/_arithmatex.scss
- src/assets/stylesheets/extensions/pymdown/_inlinehilite.scss
- src/assets/stylesheets/_shame.scss - src/assets/stylesheets/_shame.scss
options: options:

View File

@ -130,7 +130,7 @@ gulp.task("assets:images:clean",
load("assets/images/clean")) load("assets/images/clean"))
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Javascripts * JavaScript
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
/* /*
@ -161,13 +161,13 @@ gulp.task("assets:javascripts:build", (args.clean ? [
}) })
/* /*
* Clean javascripts generated by build * Clean JavaScript generated by build
*/ */
gulp.task("assets:javascripts:clean", gulp.task("assets:javascripts:clean",
load("assets/javascripts/clean")) load("assets/javascripts/clean"))
/* /*
* Lint javascripts * Lint JavaScript
*/ */
gulp.task("assets:javascripts:lint", gulp.task("assets:javascripts:lint",
load("assets/javascripts/lint")) load("assets/javascripts/lint"))
@ -321,7 +321,7 @@ gulp.task("watch", [
`${config.assets.src}/stylesheets/**/*.scss` `${config.assets.src}/stylesheets/**/*.scss`
], ["assets:stylesheets:build"]) ], ["assets:stylesheets:build"])
/* Rebuild javascripts */ /* Rebuild JavaScript */
gulp.watch([ gulp.watch([
`${config.assets.src}/javascripts/**/*.{js,jsx}` `${config.assets.src}/javascripts/**/*.{js,jsx}`
], ["assets:javascripts:build:application"]) ], ["assets:javascripts:build:application"])

View File

@ -85,7 +85,8 @@ paragraphs and other blocks except code blocks, because the parser from the
standard Markdown library does not account for those. standard Markdown library does not account for those.
However, the [PyMdown Extensions][] package adds an extension called However, the [PyMdown Extensions][] package adds an extension called
`superfences`, which makes it possible to nest code blocks within other blocks. [SuperFences][], which makes it possible to nest code blocks within other
blocks.
Example: Example:
@ -310,3 +311,4 @@ Qualifiers:
[Admonition]: https://pythonhosted.org/Markdown/extensions/admonition.html [Admonition]: https://pythonhosted.org/Markdown/extensions/admonition.html
[PyMdown Extensions]: https://facelessuser.github.io/pymdown-extensions [PyMdown Extensions]: https://facelessuser.github.io/pymdown-extensions
[SuperFences]: https://facelessuser.github.io/pymdown-extensions/extensions/superfences/

View File

@ -6,8 +6,8 @@ executed during compilation of the Markdown file.
## Installation ## Installation
CodeHilite parses code blocks and wraps them in `pre` tags. If [Pygments][] is CodeHilite parses code blocks and wraps them in `<pre>` tags. If [Pygments][]
installed, which is a generic syntax highlighter with support for over is installed, which is a generic syntax highlighter with support for over
[300 languages][], CodeHilite will also highlight the code block. Pygments can [300 languages][], CodeHilite will also highlight the code block. Pygments can
be installed with the following command: be installed with the following command:

View File

@ -1,3 +1 @@
# Metadata # Metadata
Foobar

View File

@ -14,7 +14,7 @@ markdown_extensions:
- toc(permalink=true) - toc(permalink=true)
``` ```
This will add a link containing the paragraph symbol "¶" at the end of each This will add a link containing the paragraph symbol `¶` at the end of each
headline (exactly like on the page you're currently viewing), which the headline (exactly like on the page you're currently viewing), which the
Material theme will make appear on hover. In order to change the text of the Material theme will make appear on hover. In order to change the text of the
permalink, a string can be passed, e.g.: permalink, a string can be passed, e.g.:

View File

@ -0,0 +1,63 @@
# Arithmatex <small>MathJax</small>
[Arithmatex][] integrates [MathJax][] with Markdown and is included in the
[PyMdown Extensions][] package. It parses block-style and inline equations
written in TeX markup and outputs them in mathematical notation.
## Installation
Make sure that the PyMdown Extensions package [is installed][] and add the
following lines to your `mkdocs.yml`:
``` yaml
markdown_extensions:
- pymdownx.arithmatex
```
The MathJax runtime is automatically included if the extension is enabled, so
there is no need for extra JavaScript.
## Usage
MathJax searches for `:::tex $$...$$` (blocks) and `:::tex $...$` (inline)
equations, parses their contents and renders them in mathematical notation.
See [this thread][] on StackExchange for a short introduction and quick
reference on how to write equations in TeX syntax.
### Blocks
Blocks are enclosed in `:::tex $$...$$` which are placed on separate lines.
Example:
``` tex
$$
\frac{n!}{k!(n-k)!} = \binom{n}{k}
$$
```
Result:
$$
\frac{n!}{k!(n-k)!} = \binom{n}{k}
$$
### Inline
Inline equations need to be enclosed in `:::tex $...$`:
Example:
``` tex
Lorem ipsum dolor sit amet: $p(x|y) = \frac{p(y|x)p(x)}{p(y)}$
```
Result:
Lorem ipsum dolor sit amet: $p(x|y) = \frac{p(y|x)p(x)}{p(y)}$
[Arithmatex]: https://facelessuser.github.io/pymdown-extensions/extensions/arithmatex/
[MathJax]: https://www.mathjax.org/
[PyMdown Extensions]: https://facelessuser.github.io/pymdown-extensions
[is installed]: /extensions/pymdown/overview/#installation
[this thread]: http://meta.math.stackexchange.com/questions/5020/

View File

@ -1,37 +1,93 @@
# PyMdown Extensions # PyMdown Extensions
[PyMdown Extensions][] is a collection of Markdown extensions that add some [PyMdown Extensions][] is a collection of Markdown extensions that add some
great and missing features to the standard Markdown library. For this reason, great features to the standard Markdown library. For this reason, the
the **installation of this package is highly recommended** as it's **installation of this package is highly recommended** as it's well-integrated
well-integrated with the Material theme. with the Material theme.
## Installation ## Installation
The Pymdown Extensions can be installed with the following command: The PyMdown Extensions package can be installed with the following command:
``` sh ``` sh
pip install pymdown-extensions pip install pymdown-extensions
``` ```
## Usage ## Extensions
### Improvements on existing Markdown ### GitHub Flavored Markdown
- BetterEm Most of the extensions included in the PyMdown Extensions package try to bring
- SuperFences the Markdown experience closer to GitHub Flavored Markdown (GFM):
- MagicLink
- [BetterEm][] improves the handling of emphasis markup (**bold** and *italic*)
within Markdown by providing a more sophisticated parser for better detecting
start and end tokens. Read the documentation for usage notes.
- [MagicLink][] detects links in Markdown and auto-generates the necessary
markup, so no special syntax is required. It auto-links HTTP(S) and FTP
links, as well as references to email addresses.
- [GitHub Emoji][] adds the ability to insert emojis, which does not only
include the :octocat: emojis, but also a :shit:-load of emojis that we use in
our daily lives. See the [Emoji Cheat Sheet][] for a list of all available
emojis. Happy scrolling :tada:
- [SuperFences][] provides the ability to nest code blocks under blockquotes,
lists and other block elements, which the [Fenced Code Blocks][] extension
from the standard Markdown library doesn't parse correctly.
- [Tasklist][] adds support for styled checkbox lists. This is useful for
keeping track of tasks and showing what has been done and has yet to be done.
The usage of this extension is documented [here][].
- [Tilde][] provides an easy way to ~~strike through~~ cross out text.
The portion of text that should be erased must be enclosed in two tildes
`~~...~~`, and the extension will take care of the rest.
The PyMdown Extensions package adds a shorthand to enable all of the included
extensions that provide the GFM experience. However, usage of the shorthand is
discouraged, because some extensions are not supported, as the Material theme
uses the counterparts included in the standard Markdown library.
To enable all extensions add the following lines to your `mkdocs.yml`:
``` yaml
markdown_extensions:
- pymdownx.betterem
- pymdownx.githubemoji
- pymdownx.magiclink
- pymdownx.superfences
- pymdownx.tasklist(custom_checkbox=true)
- pymdownx.tilde
```
### Syntactic Sugar
There are three other extensions that add further syntactic sugar:
- [Caret][] is the sister extension of [Tilde][] and makes it possible to
highlight ^^inserted text^^. The portion of text that should be marked as
added must be enclosed in two carets `^^...^^`, the extension will do the
rest.
- [Mark][] add the ability to ==mark text==.
- SmartSymbols - SmartSymbols
### New Syntax for... - Inlinehilite --- own documentation file
- Critic --- own documentation file
- Caret
- Mark
- Tilde
### New features
- Arithmatex
- Inlinehilite
- Tasklist
[PyMdown Extensions]: http://facelessuser.github.io/pymdown-extensions/ [PyMdown Extensions]: http://facelessuser.github.io/pymdown-extensions/
[usage notes]: https://facelessuser.github.io/pymdown-extensions/usage_notes/
[BetterEm]: https://facelessuser.github.io/pymdown-extensions/extensions/betterem/
[MagicLink]: https://facelessuser.github.io/pymdown-extensions/extensions/magiclink/
[GitHub Emoji]: https://facelessuser.github.io/pymdown-extensions/extensions/githubemoji/
[Emoji Cheat Sheet]: http://www.webpagefx.com/tools/emoji-cheat-sheet/
[SuperFences]: https://facelessuser.github.io/pymdown-extensions/extensions/superfences/
[Fenced Code Blocks]: https://pythonhosted.org/Markdown/extensions/fenced_code_blocks.html
[Tasklist]: https://facelessuser.github.io/pymdown-extensions/extensions/tasklist/
[here]: /extensions/pymdown/tasklist
[Tilde]: https://facelessuser.github.io/pymdown-extensions/extensions/tilde/
[Caret]: https://facelessuser.github.io/pymdown-extensions/extensions/caret/
[Mark]: https://facelessuser.github.io/pymdown-extensions/extensions/mark/

View File

@ -24,7 +24,7 @@ import clean from "del"
import vinyl from "vinyl-paths" import vinyl from "vinyl-paths"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Task: clean javascripts generated by build * Task: clean JavaScript generated by build
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default (gulp, config) => { export default (gulp, config) => {

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="352" height="448" viewBox="0 0 352 448"><path d="M203.75 214.75q2 15.75-12.625 25.25t-27.875 1.5q-9.75-4.25-13.375-14.5t-.125-20.5 13-14.5q9-4.5 18.125-3t16 8.875 6.875 16.875zm27.75-5.25q-3.5-26.75-28.25-41T154 165.25q-15.75 7-25.125 22.125t-8.625 32.375q1 22.75 19.375 38.75t41.375 14q22.75-2 38-21t12.5-42zM291.25 74q-5-6.75-14-11.125t-14.5-5.5T245 54.25q-72.75-11.75-141.5.5-10.75 1.75-16.5 3t-13.75 5.5T60.75 74q7.5 7 19 11.375t18.375 5.5T120 93.75Q177 101 232 94q15.75-2 22.375-3t18.125-5.375T291.25 74zm14.25 258.75q-2 6.5-3.875 19.125t-3.5 21-7.125 17.5-14.5 14.125q-21.5 12-47.375 17.875t-50.5 5.5-50.375-4.625q-11.5-2-20.375-4.5T88.75 412 70.5 401.125t-13-15.375q-6.25-24-14.25-73l1.5-4 4.5-2.25q55.75 37 126.625 37t126.875-37q5.25 1.5 6 5.75t-1.25 11.25-2 9.25zM350.75 92.5q-6.5 41.75-27.75 163.75-1.25 7.5-6.75 14t-10.875 10T291.75 288q-63 31.5-152.5 22-62-6.75-98.5-34.75-3.75-3-6.375-6.625t-4.25-8.75-2.25-8.5-1.5-9.875T25 232.75q-2.25-12.5-6.625-37.5t-7-40.375T5.5 118 0 78.5Q.75 72 4.375 66.375T12.25 57t11.25-7.5T35 43.875t12-4.625q31.25-11.5 78.25-16 94.75-9.25 169 12.5Q333 47.25 348 66.25q4 5 4.125 12.75t-1.375 13.5z"/></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" width="352" height="448"
viewBox="0 0 352 448">
<path d="M203.75 214.75q2 15.75-12.625 25.25t-27.875
1.5q-9.75-4.25-13.375-14.5t-0.125-20.5 13-14.5q9-4.5 18.125-3t16 8.875
6.875 16.875zM231.5 209.5q-3.5-26.75-28.25-41t-49.25-3.25q-15.75
7-25.125 22.125t-8.625 32.375q1 22.75 19.375 38.75t41.375 14q22.75-2
38-21t12.5-42zM291.25
74q-5-6.75-14-11.125t-14.5-5.5-17.75-3.125q-72.75-11.75-141.5 0.5-10.75
1.75-16.5 3t-13.75 5.5-12.5 10.75q7.5 7 19 11.375t18.375 5.5 21.875
2.875q57 7.25 112 0.25 15.75-2 22.375-3t18.125-5.375 18.75-11.625zM305.5
332.75q-2 6.5-3.875 19.125t-3.5 21-7.125 17.5-14.5 14.125q-21.5
12-47.375 17.875t-50.5 5.5-50.375-4.625q-11.5-2-20.375-4.5t-19.125-6.75-18.25-10.875-13-15.375q-6.25-24-14.25-73l1.5-4
4.5-2.25q55.75 37 126.625 37t126.875-37q5.25 1.5 6 5.75t-1.25 11.25-2
9.25zM350.75 92.5q-6.5 41.75-27.75 163.75-1.25 7.5-6.75 14t-10.875
10-13.625 7.75q-63 31.5-152.5
22-62-6.75-98.5-34.75-3.75-3-6.375-6.625t-4.25-8.75-2.25-8.5-1.5-9.875-1.375-8.75q-2.25-12.5-6.625-37.5t-7-40.375-5.875-36.875-5.5-39.5q0.75-6.5
4.375-12.125t7.875-9.375 11.25-7.5 11.5-5.625 12-4.625q31.25-11.5
78.25-16 94.75-9.25 169 12.5 38.75 11.5 53.75 30.5 4 5 4.125
12.75t-1.375 13.5z" />
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="352" height="448" viewBox="0 0 352 448"><path d="M203.75 214.75q2 15.75-12.625 25.25t-27.875 1.5q-9.75-4.25-13.375-14.5t-.125-20.5 13-14.5q9-4.5 18.125-3t16 8.875 6.875 16.875zm27.75-5.25q-3.5-26.75-28.25-41T154 165.25q-15.75 7-25.125 22.125t-8.625 32.375q1 22.75 19.375 38.75t41.375 14q22.75-2 38-21t12.5-42zM291.25 74q-5-6.75-14-11.125t-14.5-5.5T245 54.25q-72.75-11.75-141.5.5-10.75 1.75-16.5 3t-13.75 5.5T60.75 74q7.5 7 19 11.375t18.375 5.5T120 93.75Q177 101 232 94q15.75-2 22.375-3t18.125-5.375T291.25 74zm14.25 258.75q-2 6.5-3.875 19.125t-3.5 21-7.125 17.5-14.5 14.125q-21.5 12-47.375 17.875t-50.5 5.5-50.375-4.625q-11.5-2-20.375-4.5T88.75 412 70.5 401.125t-13-15.375q-6.25-24-14.25-73l1.5-4 4.5-2.25q55.75 37 126.625 37t126.875-37q5.25 1.5 6 5.75t-1.25 11.25-2 9.25zM350.75 92.5q-6.5 41.75-27.75 163.75-1.25 7.5-6.75 14t-10.875 10T291.75 288q-63 31.5-152.5 22-62-6.75-98.5-34.75-3.75-3-6.375-6.625t-4.25-8.75-2.25-8.5-1.5-9.875T25 232.75q-2.25-12.5-6.625-37.5t-7-40.375T5.5 118 0 78.5Q.75 72 4.375 66.375T12.25 57t11.25-7.5T35 43.875t12-4.625q31.25-11.5 78.25-16 94.75-9.25 169 12.5Q333 47.25 348 66.25q4 5 4.125 12.75t-1.375 13.5z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" width="352" height="448"
viewBox="0 0 352 448">
<path d="M203.75 214.75q2 15.75-12.625 25.25t-27.875
1.5q-9.75-4.25-13.375-14.5t-0.125-20.5 13-14.5q9-4.5 18.125-3t16 8.875
6.875 16.875zM231.5 209.5q-3.5-26.75-28.25-41t-49.25-3.25q-15.75
7-25.125 22.125t-8.625 32.375q1 22.75 19.375 38.75t41.375 14q22.75-2
38-21t12.5-42zM291.25
74q-5-6.75-14-11.125t-14.5-5.5-17.75-3.125q-72.75-11.75-141.5 0.5-10.75
1.75-16.5 3t-13.75 5.5-12.5 10.75q7.5 7 19 11.375t18.375 5.5 21.875
2.875q57 7.25 112 0.25 15.75-2 22.375-3t18.125-5.375 18.75-11.625zM305.5
332.75q-2 6.5-3.875 19.125t-3.5 21-7.125 17.5-14.5 14.125q-21.5
12-47.375 17.875t-50.5 5.5-50.375-4.625q-11.5-2-20.375-4.5t-19.125-6.75-18.25-10.875-13-15.375q-6.25-24-14.25-73l1.5-4
4.5-2.25q55.75 37 126.625 37t126.875-37q5.25 1.5 6 5.75t-1.25 11.25-2
9.25zM350.75 92.5q-6.5 41.75-27.75 163.75-1.25 7.5-6.75 14t-10.875
10-13.625 7.75q-63 31.5-152.5
22-62-6.75-98.5-34.75-3.75-3-6.375-6.625t-4.25-8.75-2.25-8.5-1.5-9.875-1.375-8.75q-2.25-12.5-6.625-37.5t-7-40.375-5.875-36.875-5.5-39.5q0.75-6.5
4.375-12.125t7.875-9.375 11.25-7.5 11.5-5.625 12-4.625q31.25-11.5
78.25-16 94.75-9.25 169 12.5 38.75 11.5 53.75 30.5 4 5 4.125
12.75t-1.375 13.5z" fill="white" />
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448" viewBox="0 0 416 448"><path d="M160 304q0 10-3.125 20.5t-10.75 19T128 352t-18.125-8.5-10.75-19T96 304t3.125-20.5 10.75-19T128 256t18.125 8.5 10.75 19T160 304zm160 0q0 10-3.125 20.5t-10.75 19T288 352t-18.125-8.5-10.75-19T256 304t3.125-20.5 10.75-19T288 256t18.125 8.5 10.75 19T320 304zm40 0q0-30-17.25-51T296 232q-10.25 0-48.75 5.25Q229.5 240 208 240t-39.25-2.75Q130.75 232 120 232q-29.5 0-46.75 21T56 304q0 22 8 38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0 37.25-1.75t35-7.375 30.5-15 20.25-25.75T360 304zm56-44q0 51.75-15.25 82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5T212 416q-19.5 0-35.5-.75t-36.875-3.125-38.125-7.5-34.25-12.875T37 371.5t-21.5-28.75Q0 312 0 260q0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25 30.875Q171.5 96 212 96q37 0 70 8 26.25-20.5 46.75-30.25T376 64q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34 99.5z"/></svg>

Before

Width:  |  Height:  |  Size: 959 B

View File

@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448">
<path d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448" viewBox="0 0 416 448"><path d="M160 304q0 10-3.125 20.5t-10.75 19T128 352t-18.125-8.5-10.75-19T96 304t3.125-20.5 10.75-19T128 256t18.125 8.5 10.75 19T160 304zm160 0q0 10-3.125 20.5t-10.75 19T288 352t-18.125-8.5-10.75-19T256 304t3.125-20.5 10.75-19T288 256t18.125 8.5 10.75 19T320 304zm40 0q0-30-17.25-51T296 232q-10.25 0-48.75 5.25Q229.5 240 208 240t-39.25-2.75Q130.75 232 120 232q-29.5 0-46.75 21T56 304q0 22 8 38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0 37.25-1.75t35-7.375 30.5-15 20.25-25.75T360 304zm56-44q0 51.75-15.25 82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5T212 416q-19.5 0-35.5-.75t-36.875-3.125-38.125-7.5-34.25-12.875T37 371.5t-21.5-28.75Q0 312 0 260q0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25 30.875Q171.5 96 212 96q37 0 70 8 26.25-20.5 46.75-30.25T376 64q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34 99.5z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 971 B

View File

@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448">
<path d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" fill="white" />
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500" viewBox="0 0 500 500"><path d="M249.865 474.507l90.684-279.097H159.18l90.684 279.097z"/><path d="M249.864 474.506L159.18 195.41H32.088l217.776 279.095z" opacity=".7"/><path d="M32.089 195.41l-27.56 84.816a18.773 18.773 0 0 0 6.822 20.99l238.514 173.29L32.089 195.41z" opacity=".5"/><path d="M32.089 195.412H159.18L104.56 27.314c-2.81-8.65-15.046-8.65-17.855 0L32.089 195.412z"/><path d="M249.865 474.506l90.684-279.095H467.64L249.865 474.506z" opacity=".7"/><path d="M467.641 195.41l27.56 84.816a18.772 18.772 0 0 1-6.822 20.99l-238.515 173.29L467.641 195.41z" opacity=".5"/><path d="M467.64 195.412H340.55l54.618-168.098c2.81-8.65 15.047-8.65 17.856 0l54.618 168.098z"/></svg>

Before

Width:  |  Height:  |  Size: 742 B

View File

@ -0,0 +1,31 @@
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500"
viewBox="0 0 500 500">
<g transform="translate(156.197863, 1.160267)">
<path d="M93.667,473.347L93.667,473.347l90.684-279.097H2.983L93.667,
473.347L93.667,473.347z" />
</g>
<g transform="translate(28.531199, 1.160800)" opacity="0.7">
<path d="M221.333,473.345L130.649,194.25H3.557L221.333,473.345L221.333,
473.345z" />
</g>
<g transform="translate(0.088533, 0.255867)" opacity="0.5">
<path d="M32,195.155L32,195.155L4.441,279.97c-2.513,7.735,0.24,16.21,6.821,
20.99l238.514,173.29 L32,195.155L32,195.155z" />
</g>
<g transform="translate(29.421866, 280.255593)">
<path d="M2.667-84.844h127.092L75.14-252.942c-2.811-8.649-15.047-8.649-17.856,
0L2.667-84.844 L2.667-84.844z" />
</g>
<g transform="translate(247.197860, 1.160800)" opacity="0.7">
<path d="M2.667,473.345L93.351,194.25h127.092L2.667,473.345L2.667,
473.345z" />
</g>
<g transform="translate(246.307061, 0.255867)" opacity="0.5">
<path d="M221.334,195.155L221.334,195.155l27.559,84.815c2.514,7.735-0.24,
16.21-6.821,20.99 L3.557,474.25L221.334,195.155L221.334,195.155z" />
</g>
<g transform="translate(336.973725, 280.255593)">
<path d="M130.667-84.844H3.575l54.618-168.098c2.811-8.649,15.047-8.649,
17.856,0L130.667-84.844 L130.667-84.844z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500" viewBox="0 0 500 500"><path d="M249.865 474.507l90.684-279.097H159.18l90.684 279.097z" fill="#fff"/><path d="M249.864 474.506L159.18 195.41H32.088l217.776 279.095z" fill="#fff" opacity=".7"/><path d="M32.089 195.41l-27.56 84.816a18.773 18.773 0 0 0 6.822 20.99l238.514 173.29L32.089 195.41z" fill="#fff" opacity=".5"/><path d="M32.089 195.412H159.18L104.56 27.314c-2.81-8.65-15.046-8.65-17.855 0L32.089 195.412z" fill="#fff"/><path d="M249.865 474.506l90.684-279.095H467.64L249.865 474.506z" fill="#fff" opacity=".7"/><path d="M467.641 195.41l27.56 84.816a18.772 18.772 0 0 1-6.822 20.99l-238.515 173.29L467.641 195.41z" fill="#fff" opacity=".5"/><path d="M467.64 195.412H340.55l54.618-168.098c2.81-8.65 15.047-8.65 17.856 0l54.618 168.098z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 826 B

View File

@ -0,0 +1,32 @@
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500"
viewBox="0 0 500 500">
<g transform="translate(156.197863, 1.160267)">
<path d="M93.667,473.347L93.667,473.347l90.684-279.097H2.983L93.667,
473.347L93.667,473.347z" fill="white" />
</g>
<g transform="translate(28.531199, 1.160800)" opacity="0.7">
<path d="M221.333,473.345L130.649,194.25H3.557L221.333,473.345L221.333,
473.345z" fill="white" />
</g>
<g transform="translate(0.088533, 0.255867)" opacity="0.5">
<path d="M32,195.155L32,195.155L4.441,279.97c-2.513,7.735,0.24,16.21,6.821,
20.99l238.514,173.29 L32,195.155L32,195.155z" fill="white" />
</g>
<g transform="translate(29.421866, 280.255593)">
<path d="M2.667-84.844h127.092L75.14-252.942c-2.811-8.649-15.047-8.649-17.856,
0L2.667-84.844 L2.667-84.844z" fill="white" />
</g>
<g transform="translate(247.197860, 1.160800)" opacity="0.7">
<path d="M2.667,473.345L93.351,194.25h127.092L2.667,473.345L2.667,
473.345z" fill="white" />
</g>
<g transform="translate(246.307061, 0.255867)" opacity="0.5">
<path d="M221.334,195.155L221.334,195.155l27.559,84.815c2.514,7.735-0.24,
16.21-6.821,20.99 L3.557,474.25L221.334,195.155L221.334,195.155z"
fill="white" />
</g>
<g transform="translate(336.973725, 280.255593)">
<path d="M130.667-84.844H3.575l54.618-168.098c2.811-8.649,15.047-8.649,
17.856,0L130.667-84.844 L130.667-84.844z" fill="white" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -20,19 +20,19 @@
<meta name="author" content="{{ site_author }}"> <meta name="author" content="{{ site_author }}">
{% endif %} {% endif %}
<meta name="generator" content="mkdocs+mkdocs-material#0.2.1"> <meta name="generator" content="mkdocs+mkdocs-material#0.2.1">
<script src="{{ base_url }}/assets/javascripts/modernizr-dede1352ed.js"></script> <script src="{{ base_url }}/assets/javascripts/modernizr.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Mono:400"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Mono:400">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-9cd3c99a66.css"> <link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application.css">
{% for path in extra_css %} {% for path in extra_css %}
<link rel="stylesheet" href="{{ path }}"> <link rel="stylesheet" href="{{ path }}">
{% endfor %} {% endfor %}
</head> </head>
<body> <body>
<input class="md-toggle md-toggle--drawer" type="checkbox" id="drawer"> <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer">
<input class="md-toggle md-toggle--search" type="checkbox" id="search"> <input class="md-toggle" data-md-toggle="search" type="checkbox" id="search">
<label class="md-overlay" for="drawer"></label> <label class="md-overlay" data-md-overlay for="drawer"></label>
{% include "partials/header.html" %} {% include "partials/header.html" %}
<div class="md-container"> <div class="md-container">
<main class="md-main"> <main class="md-main">
@ -87,6 +87,12 @@
</main> </main>
{% include "partials/footer.html" %} {% include "partials/footer.html" %}
</div> </div>
{% for extension in config.markdown_extensions %}
{% if extension == "pymdownx.arithmatex" %}
{% set path = "mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML" %}
<script src="https://cdn.mathjax.org/{{ path }}"></script>
{% endif %}
{% endfor %}
<script src="{{ base_url }}/assets/javascripts/application.js"></script> <script src="{{ base_url }}/assets/javascripts/application.js"></script>
<script> <script>
/* Configuration for application */ /* Configuration for application */

View File

@ -1,9 +1,9 @@
{% if nav_item.children %} {% if nav_item.children %}
<li class="md-nav__item md-nav__item--nested"> <li class="md-nav__item md-nav__item--nested">
{% if nav_item.active %} {% if nav_item.active %}
<input class="md-toggle md-nav__toggle" type="checkbox" id="{{ path }}" checked> <input class="md-toggle md-nav__toggle" data-md-toggle="{{ path }}" type="checkbox" id="{{ path }}" checked>
{% else %} {% else %}
<input class="md-toggle md-nav__toggle" type="checkbox" id="{{ path }}"> <input class="md-toggle md-nav__toggle" data-md-toggle="{{ path }}" type="checkbox" id="{{ path }}">
{% endif %} {% endif %}
<label class="md-nav__link" for="{{ path }}"> <label class="md-nav__link" for="{{ path }}">
{{ nav_item.title }} {{ nav_item.title }}
@ -24,7 +24,7 @@
</li> </li>
{% elif nav_item == current_page %} {% elif nav_item == current_page %}
<li class="md-nav__item"> <li class="md-nav__item">
<input class="md-toggle md-nav__toggle" type="checkbox" id="toc"> <input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
<label class="md-nav__link md-nav__link--active" for="toc"> <label class="md-nav__link md-nav__link--active" for="toc">
{{ nav_item.title }} {{ nav_item.title }}
</label> </label>

View File

@ -1,18 +1,13 @@
<div class="md-search"> <div class="md-search" data-md-search>
<div class="md-search__overlay"></div> <div class="md-search__overlay"></div>
<div class="md-search__inner"> <div class="md-search__inner">
<form class="md-search__form"> <form class="md-search__form" name="search">
<input type="text" class="md-search__input" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" id="query"> <input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false">
<label class="md-icon md-search__icon" for="search"></label> <label class="md-icon md-search__icon" for="search"></label>
</form> </form>
<div class="md-search__output"> <div class="md-search__output">
<div class="md-search__scrollwrap"> <div class="md-search__scrollwrap">
<div class="md-search-result"> <div class="md-search-result" data-md-search-result></div>
<div class="md-search-result__meta">
Indexing
</div>
<ol class="md-search-result__list"></ol>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,20 +1,19 @@
{% set platform = config.extra.repo_icon or repo_url %} {% set platform = config.extra.repo_icon or repo_url %}
{% if "github" in platform %} {% if "github" in platform %}
{% set repo_icon = "md-source--github" %} {% set repo_type = "github" %}
{% set repo_icon = "md-source--github" %}
{% elif "gitlab" in platform %} {% elif "gitlab" in platform %}
{% set repo_type = "gitlab" %}
{% set repo_icon = "md-source--gitlab" %} {% set repo_icon = "md-source--gitlab" %}
{% elif "bitbucket" in platform %} {% elif "bitbucket" in platform %}
{% set repo_type = "bitbucket" %}
{% set repo_icon = "md-source--bitbucket" %} {% set repo_icon = "md-source--bitbucket" %}
{% else %} {% else %}
{% set repo_type = "" %}
{% set repo_icon = "" %} {% set repo_icon = "" %}
{% endif %} {% endif %}
<a href="{{ repo_url }}" title="Go to repository" class="md-source {{ repo_icon }}"> <a href="{{ repo_url }}" title="Go to repository" class="md-source {{ repo_icon }}" data-md-source="{{ repo_type }}">
<div class="md-source__repository"> <div class="md-source__repository">
{{ repo_name }} {{ repo_name }}
<ul class="md-source__facts">
{% if config.extra.version %}
<li class="md-source__fact">v{{ config.extra.version }}</li>
{% endif %}
</ul>
</div> </div>
</a> </a>

View File

@ -52,9 +52,11 @@ markdown_extensions:
- markdown.extensions.footnotes - markdown.extensions.footnotes
- markdown.extensions.meta - markdown.extensions.meta
- markdown.extensions.toc(permalink=true) - markdown.extensions.toc(permalink=true)
- pymdownx.betterem - pymdownx.arithmatex
- pymdownx.betterem(smart_enable=all)
- pymdownx.caret - pymdownx.caret
- pymdownx.critic - pymdownx.critic
- pymdownx.githubemoji
- pymdownx.inlinehilite - pymdownx.inlinehilite
- pymdownx.magiclink - pymdownx.magiclink
- pymdownx.mark - pymdownx.mark
@ -76,6 +78,7 @@ pages:
- Permalinks: extensions/permalinks.md - Permalinks: extensions/permalinks.md
- PyMdown: - PyMdown:
- Overview: extensions/pymdown/overview.md - Overview: extensions/pymdown/overview.md
- Arithmatex: extensions/pymdown/arithmatex.md
- Tasklist: extensions/pymdown/tasklist.md - Tasklist: extensions/pymdown/tasklist.md
- Specimen: specimen.md - Specimen: specimen.md
- Customization: customization.md - Customization: customization.md

View File

@ -31,6 +31,7 @@
}, },
"dependencies": { "dependencies": {
"fastclick": "^1.0.6", "fastclick": "^1.0.6",
"js-cookie": "^2.1.3",
"lunr": "^0.7.1", "lunr": "^0.7.1",
"material-design-color": "^2.3.1", "material-design-color": "^2.3.1",
"material-shadows": "^3.0.0", "material-shadows": "^3.0.0",

View File

@ -20,234 +20,180 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
/* ----------------------------------------------------------------------------
* Imports
* ------------------------------------------------------------------------- */
import FastClick from "fastclick" import FastClick from "fastclick"
// import Expander from "./components/expander"
import GithubSourceFacts from "./components/GithubSourceFacts"
import Material from "./components/Material" import Material from "./components/Material"
// import Search from './components/search';
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Application * Application
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
class Application { export default class Application {
/** /**
* Constructor. * Create the application
* *
* @constructor * @constructor
* @param {object} config Configuration object * @param {object} config Configuration object
* @return {void}
*/ */
constructor(config) { constructor(config) {
this.config_ = config this.config_ = config
} }
/** /**
* Initialize all components * Initialize all components and listeners
*/ */
initialize() { initialize() {
/* Initialize sticky sidebars */ /* Initialize Modernizr and Fastclick */
this.initializeSidebar("[data-md-sidebar=primary]", "(min-width: 1200px)") new Material.Event.Listener(document, "DOMContentLoaded", () => {
this.initializeSidebar("[data-md-sidebar=secondary]")
/* Initialize navigation style modifiers */ /* Test for iOS */
this.initializeNavBlur("[data-md-sidebar=secondary] .md-nav__link") Modernizr.addTest("ios", () => {
this.initializeNavCollapse("[data-md-collapse]", "(min-width: 1200px)") return !!navigator.userAgent.match(/(iPad|iPhone|iPod)/g)
})
// TODO /* Test for web application context */
if (this.hasGithubRepo()) { Modernizr.addTest("standalone", () => {
const githubSource = new GithubSourceFacts( return !!navigator.standalone
this.config_.storage, })
this.config_.repo.url
) /* Attack FastClick to mitigate 300ms delay on touch devices */
githubSource.initialize() FastClick.attach(document.body)
}).listen()
/* Cross-browser helper to dispatch/fire an event */
const dispatch = (el, event) => {
return document.createEvent
? el.dispatchEvent(new Event(event))
: el.fireEvent(`on${event}`, document.createEventObject())
} }
} /* Truncate a string after the given number of characters - this is not
a reasonable approach, since the summaries kind of suck. It would be
better to create something more intelligent, highlighting the search
occurrences and making a better summary out of it */
const truncate = function(string, n) {
let i = n
if (string.length > i) {
while (string[i] !== " " && --i > 0);
return `${string.substring(0, i)}...`
}
return string
}
/** /* Component: sidebar with navigation */
* Initialize sidebar within optional media query range new Material.Event.MatchMedia("(min-width: 1200px)",
* new Material.Event.Listener(window, [
* @param {(string|HTMLElement)} el - Selector or HTML element "scroll", "resize", "orientationchange"
* @param {string} [query] - Media query ], new Material.Sidebar("[data-md-sidebar=primary]")))
*/
initializeSidebar(el, query = null) {
const sidebar = new Material.Sidebar(el)
const listeners = [
new Material.Listener.Viewport.Offset(() => sidebar.update()),
new Material.Listener.Viewport.Resize(() => sidebar.update())
]
/* Initialize depending on media query */ /* Component: sidebar with table of contents */
if (typeof query === "string" && query.length) { new Material.Event.MatchMedia("(min-width: 960px)",
new Material.Listener.Viewport.Media(query, media => { new Material.Event.Listener(window, [
if (media.matches) { "scroll", "resize", "orientationchange"
sidebar.update() ], new Material.Sidebar("[data-md-sidebar=secondary]")))
for (const listener of listeners)
listener.listen() /* Component: link blurring for table of contents */
} else { new Material.Event.MatchMedia("(min-width: 960px)",
sidebar.reset() new Material.Event.Listener(window, "scroll",
for (const listener of listeners) new Material.Nav.Blur("[data-md-sidebar=secondary] .md-nav__link")))
listener.unlisten()
/* Component: collapsible elements for navigation */
const collapsibles = document.querySelectorAll("[data-md-collapse]")
for (const collapse of collapsibles)
new Material.Event.MatchMedia("(min-width: 1200px)",
new Material.Event.Listener(collapse.previousElementSibling, "click",
new Material.Nav.Collapse(collapse)))
/* Component: search body lock for mobile */
new Material.Event.MatchMedia("(max-width: 959px)",
new Material.Event.Listener("[data-md-toggle=search]", "change",
new Material.Search.Lock("[data-md-toggle=search]")))
/* Component: search results */
new Material.Event.Listener(document.forms.search.query, [
"focus", "keyup"
], new Material.Search.Result("[data-md-search-result]", () => {
return fetch(`${this.config_.url.base}/mkdocs/search_index.json`)
.then(response => response.json())
.then(data => {
return data.docs.map(doc => {
doc.location = this.config_.url.base + doc.location
doc.text = truncate(doc.text, 140)
return doc
})
})
})).listen()
/* Listener: prevent touches on overlay if navigation is active */
new Material.Event.MatchMedia("(max-width: 1199px)",
new Material.Event.Listener("[data-md-overlay]", "touchstart",
ev => ev.preventDefault()))
/* Listener: close drawer when anchor links are clicked */
new Material.Event.MatchMedia("(max-width: 959px)",
new Material.Event.Listener("[data-md-sidebar=primary] [href^='#']",
"click", () => {
const toggle = document.querySelector("[data-md-toggle=drawer]")
if (toggle.checked) {
toggle.checked = false
dispatch(toggle, "change")
}
}))
/* Listener: focus input after activating search */
new Material.Event.Listener("[data-md-toggle=search]", "change", ev => {
setTimeout(toggle => {
const query = document.forms.search.query
if (toggle.checked)
query.focus()
}, 400, ev.target)
}).listen()
/* Listener: activate search on focus */
new Material.Event.MatchMedia("(min-width: 960px)",
new Material.Event.Listener(document.forms.search.query, "focus", () => {
const toggle = document.querySelector("[data-md-toggle=search]")
if (!toggle.checked) {
toggle.checked = true
dispatch(toggle, "change")
} }
}).listen() }))
/* Initialize without media query */ /* Listener: disable search when clicking outside */
} else { new Material.Event.MatchMedia("(min-width: 960px)",
sidebar.update() new Material.Event.Listener(document.body, "click", () => {
for (const listener of listeners) const toggle = document.querySelector("[data-md-toggle=search]")
listener.listen() if (toggle.checked) {
} toggle.checked = false
} dispatch(toggle, "change")
/**
* Initialize blurring of anchors above page y-offset
*
* @param {(string|NodeList<HTMLElement>)} els - Selector or HTML elements
*/
initializeNavBlur(els) {
const blur = new Material.Nav.Blur(els)
const listeners = [
new Material.Listener.Viewport.Offset(() => blur.update())
]
/* Initialize blur and listeners */
blur.update()
for (const listener of listeners)
listener.listen()
}
/**
* Initialize collapsible nested navigation elements
*
* @param {(string|NodeList<HTMLElement>)} els - Selector or HTML elements
* @param {string} [query] - Media query
*/
initializeNavCollapse(els, query = null) {
const collapsibles = document.querySelectorAll(els)
for (const collapsible of collapsibles) {
const collapse = new Material.Nav.Collapse(collapsible)
const listener = new Material.Listener.Toggle(
collapsible.previousElementSibling, () => collapse.update())
/* Initialize depending on media query */
new Material.Listener.Viewport.Media(query, media => {
if (media.matches) {
listener.listen()
} else {
collapse.reset()
listener.unlisten()
} }
}).listen() }))
}
}
/** /* Listener: fix unclickable toggle due to blur handler */
* Is this application about a Github repository? new Material.Event.MatchMedia("(min-width: 960px)",
* new Material.Event.Listener("[data-md-toggle=search]", "click",
* @return {bool} - true if `repo.icon` or `repo.url` contains 'github' ev => ev.stopPropagation()))
*/
hasGithubRepo() { /* Listener: prevent search from closing when clicking */
return this.config_.repo.icon === "github" new Material.Event.MatchMedia("(min-width: 960px)",
|| this.config_.repo.url.includes("github") new Material.Event.Listener("[data-md-search]", "click",
ev => ev.stopPropagation()))
/* Retrieve the facts for the given repository type */
;(() => {
const el = document.querySelector("[data-md-source]")
switch (el.dataset.mdSource) {
case "github": return new Material.Source.Adapter.GitHub(el).fetch()
default: return Promise.resolve([])
}
/* Render repository source information */
})().then(facts => {
const sources = document.querySelectorAll("[data-md-source]")
for (const source of sources)
new Material.Source.Repository(source)
.initialize(facts)
})
} }
} }
export default Application
// const consume = reader => {
// let total = 0, body = ""
// return new Promise((resolve, reject) => {
// function pump() {
// reader.read().then(({ done, value }) => {
// if (done) {
// console.log(body)
// resolve()
// return
// }
// total += value.byteLength
// // value +=
// body += value
// console.log(`received ${value.byteLength}, total: ${total}`)
// pump()
// })
// .catch(reject)
// }
// pump()
// })
// }
//
// fetch("/mkdocs/search_index.json")
// .then(res => consume(res.body.getReader()))
// .then(() => console.log("consumed entire body"))
// .catch(e => console.log(e))
// TODO: wrap in function call
// application module export
/* Initialize application upon DOM ready */
document.addEventListener("DOMContentLoaded", () => {
/* Test for iOS */
Modernizr.addTest("ios", () => {
return !!navigator.userAgent.match(/(iPad|iPhone|iPod)/g)
})
/* Test for web application context */
Modernizr.addTest("standalone", () => {
return !!navigator.standalone
})
/* Attack FastClick to mitigate 300ms delay on touch devices */
FastClick.attach(document.body)
// query.addEventListener("focus", () => {
// document.querySelector(".md-search").dataset.mdLocked = ""
// })
/* Intercept click on search mode toggle */
// TODO: this needs to be abstracted...
document.getElementById("query").addEventListener("focus", () => {
document.getElementById("search").checked = true
})
// should be registered on body, but leads to problems
document.querySelector(".md-container").addEventListener("click", () => {
if (document.getElementById("search").checked)
document.getElementById("search").checked = false
})
// stop propagation, if search is active...
document.querySelector(".md-search").addEventListener("click", ev => {
ev.stopPropagation()
})
// toggleSearchClose.addEventListener("click", ev => {
// ev.preventDefault()
// // ev.target
//
// const search = document.getElementById("search")
// search.checked = false
// })
// }, 1000);
fetch(
"https://api.github.com/repos/squidfunk/mkdocs-material/releases/latest")
.then(response => {
return response.json()
})
// .then(data => {
// // console.log(data)
// })
})

View File

@ -1,110 +0,0 @@
/*
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
*
* 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 NON-INFRINGEMENT. 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.
*/
/* ----------------------------------------------------------------------------
* Github Source
* ------------------------------------------------------------------------- */
export default
class GithubSourceFacts {
/**
* Constructor.
*
* @constructor
* @param {object} storage - Accessor to storage, eg. `window.sessionStorage`
* @param {string} repoUrl - URL to Github repository
*/
constructor(storage, repoUrl) {
this.storage = storage
this.storageKey = "github-source-facts"
this.apiRepoUrl = repoUrl.replace("github.com/", "api.github.com/repos/")
}
/**
* Retrieve stars and fork counts for the repository before invoking
* `GithubSourceFacts.paint`.
*
* @return {void}
*/
initialize() {
const facts = this.storage.getItem(this.storageKey)
// Retrieve the facts, then invoke paint
if (!facts) {
fetch(this.apiRepoUrl)
.then(response => {
return response.json()
})
.then(data => {
const repoFacts = {
stars: data.stargazers_count,
forks: data.forks_count
}
this.storage.setItem(this.storageKey, JSON.stringify(repoFacts))
GithubSourceFacts.paint(repoFacts)
})
.catch(() => {
// console.log("parsing failed", ex)
})
// Use the cached facts
} else {
GithubSourceFacts.paint(JSON.parse(facts))
}
}
/**
* Populates `.md-source__facts` with star and fork counts.
*
* @param {integer} options.stars - Stars count for the repo
* @param {integer} options.forks - Fork count for the repo
* @return {void}
*/
static paint({ stars, forks }) {
const lists = document.querySelectorAll(".md-source__facts"); // TODO 2x list in drawer and header
// TODO: use ... of ...
[].forEach.call(lists, list => {
let li = (
<li class="md-source__fact md-source__fact--hidden">
{stars} Stars
</li>
)
setTimeout(fact => {
fact.classList.remove("md-source__fact--hidden")
}, 100, li)
list.appendChild(li)
li = (
<li class="md-source__fact md-source__fact--hidden">
{forks} Forks
</li>
)
setTimeout(fact => {
fact.classList.remove("md-source__fact--hidden")
}, 500, li)
list.appendChild(li)
})
}
}

View File

@ -20,56 +20,20 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import Event from "./Material/Event"
import Nav from "./Material/Nav" import Nav from "./Material/Nav"
import Search from "./Material/Search" import Search from "./Material/Search"
import Listener from "./Material/Listener"
import Sidebar from "./Material/Sidebar" import Sidebar from "./Material/Sidebar"
import Source from "./Material/Source"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Module * Module
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default { export default {
Event,
Nav, Nav,
Search, Search,
Listener, Sidebar,
Sidebar Source
} }
/* ----------------------------------------------------------------------------
* Definition
* ------------------------------------------------------------------------- */
// export default class Material {
//
//
//
// static initializeSearch() {
//
// }
//
// /**
// * Initialize all components
// */
// static initialize() {
//
// const search = new Search.Lock("#search", () => {
// document.getElementById("query").focus()
// })
// search.listen() // TODO when this is commented out, focusing the search somehow breaks things...
//
// const searchx = document.getElementById("search")
// const initialize = () => {
// const foo = new Search.Index()
// console.log(foo)
//
// searchx.removeEventListener("change", initialize)
// }
// searchx.addEventListener("change", initialize)
// console.log(searchx)
//
// // TODO nav bar is blurry until 959px, when expanded...
// }
// }

View File

@ -20,16 +20,14 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import Media from "./Viewport/Media" import Listener from "./Event/Listener"
import Offset from "./Viewport/Offset" import MatchMedia from "./Event/MatchMedia"
import Resize from "./Viewport/Resize"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Module * Module
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default { export default {
Media, Listener,
Offset, MatchMedia
Resize
} }

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
*
* 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 NON-INFRINGEMENT. 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.
*/
/* ----------------------------------------------------------------------------
* Class
* ------------------------------------------------------------------------- */
export default class Listener {
/**
* Generic event listener
*
* @constructor
* @param {(string|NodeList<HTMLElement>)} els - Selector or HTML elements
* @param {Array.<string>} events - Event names
* @param {(object|function)} handler - Handler to be invoked
*/
constructor(els, events, handler) {
this.els_ = (typeof els === "string")
? document.querySelectorAll(els)
: [].concat(els)
/* Set handler as function or directly as object */
this.handler_ = typeof handler === "function"
? { update: handler }
: handler
/* Initialize event names and update handler */
this.events_ = [].concat(events)
this.update_ = ev => this.handler_.update(ev)
}
/**
* Register listener for all relevant events
*/
listen() {
for (const el of this.els_)
for (const event of this.events_)
el.addEventListener(event, this.update_, false)
/* Execute setup handler, if implemented */
if (typeof this.handler_.setup === "function")
this.handler_.setup()
}
/**
* Unregister listener for all relevant events
*/
unlisten() {
for (const el of this.els_)
for (const event of this.events_)
el.removeEventListener(event, this.update_)
/* Execute reset handler, if implemented */
if (typeof this.handler_.reset === "function")
this.handler_.reset()
}
}

View File

@ -21,37 +21,34 @@
*/ */
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Definition * Class
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default class Media { export default class MatchMedia {
/** /**
* Listener which checks for media queries on dimension changes * Media query listener
*
* This class listens for state changes of media queries and automatically
* switches the given listeners on or off.
* *
* @constructor * @constructor
* @param {string} query - Media query * @param {string} query - Media query to test for
* @param {Function} handler - Event handler to execute * @param {Listener} listener - Event listener
*/ */
constructor(query, handler) { constructor(query, listener) {
this.media_ = window.matchMedia(query) this.handler_ = mq => {
this.handler_ = media => { if (mq.matches)
handler(media) listener.listen()
else
listener.unlisten()
} }
}
/** /* Initialize media query listener */
* Register listener for media query check const media = window.matchMedia(query)
*/ media.addListener(this.handler_)
listen() {
this.media_.addListener(this.handler_)
this.handler_(this.media_)
}
/** /* Always check at initialization */
* Unregister listener for media query check this.handler_(media)
*/
unlisten() {
this.media_.removeListener(this.handler_)
} }
} }

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
*
* 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 NON-INFRINGEMENT. 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.
*/
import Abstract from "../Abstract"
/* ----------------------------------------------------------------------------
* Definition
* ------------------------------------------------------------------------- */
export default class Resize extends Abstract {
/**
* Listener which monitors changes to the dimensions of the viewport
*
* @constructor
* @param {Function} handler - Event handler to execute
*/
constructor(handler) {
super(window, ["resize", "orientationchange"], handler)
}
}

View File

@ -21,7 +21,7 @@
*/ */
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Definition * Class
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default class Blur { export default class Blur {
@ -47,6 +47,13 @@ export default class Blur {
}) })
} }
/**
* Initialize anchor states
*/
setup() {
this.update()
}
/** /**
* Update anchor states * Update anchor states
*/ */
@ -58,7 +65,7 @@ export default class Blur {
for (let i = this.index_ + 1; i < this.els_.length; i++) { for (let i = this.index_ + 1; i < this.els_.length; i++) {
if (this.anchors_[i].offsetTop <= offset) { if (this.anchors_[i].offsetTop <= offset) {
if (i > 0) if (i > 0)
this.els_[i - 1].dataset.mdBlurred = "" this.els_[i - 1].dataset.mdState = "blur"
this.index_ = i this.index_ = i
} else { } else {
break break
@ -70,7 +77,7 @@ export default class Blur {
for (let i = this.index_; i >= 0; i--) { for (let i = this.index_; i >= 0; i--) {
if (this.anchors_[i].offsetTop > offset) { if (this.anchors_[i].offsetTop > offset) {
if (i > 0) if (i > 0)
delete this.els_[i - 1].dataset.mdBlurred delete this.els_[i - 1].dataset.mdState
} else { } else {
this.index_ = i this.index_ = i
break break
@ -86,8 +93,11 @@ export default class Blur {
* Reset anchor states * Reset anchor states
*/ */
reset() { reset() {
[].forEach.call(this.els_, el => { for (const el of this.els_)
delete el.dataset.mdBlurred delete el.dataset.mdState
})
/* Reset index and page y-offset */
this.index_ = 0
this.offset_ = window.pageYOffset
} }
} }

View File

@ -21,7 +21,7 @@
*/ */
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Definition * Class
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default class Collapse { export default class Collapse {
@ -39,7 +39,7 @@ export default class Collapse {
} }
/** /**
* Make expand and collapse transition smoothly * Animate expand and collapse smoothly
*/ */
update() { update() {
const current = this.el_.getBoundingClientRect().height const current = this.el_.getBoundingClientRect().height
@ -48,43 +48,43 @@ export default class Collapse {
if (current) { if (current) {
this.el_.style.maxHeight = `${current}px` this.el_.style.maxHeight = `${current}px`
requestAnimationFrame(() => { requestAnimationFrame(() => {
this.el_.dataset.mdAnimated = "" this.el_.dataset.mdState = "animate"
this.el_.style.maxHeight = "0px" this.el_.style.maxHeight = "0px"
}) })
/* Collapsed, so expand */ /* Collapsed, so expand */
} else { } else {
this.el_.dataset.mdState = "expand"
this.el_.style.maxHeight = "" this.el_.style.maxHeight = ""
this.el_.dataset.mdExpanded = ""
/* Read height and unset pseudo-toggled state */ /* Read height and unset pseudo-toggled state */
const height = this.el_.getBoundingClientRect().height const height = this.el_.getBoundingClientRect().height
delete this.el_.dataset.mdExpanded delete this.el_.dataset.mdState
/* Set initial state and animate */ /* Set initial state and animate */
this.el_.style.maxHeight = "0px" this.el_.style.maxHeight = "0px"
requestAnimationFrame(() => { requestAnimationFrame(() => {
this.el_.dataset.mdAnimated = "" this.el_.dataset.mdState = "animate"
this.el_.style.maxHeight = `${height}px` this.el_.style.maxHeight = `${height}px`
}) })
} }
/* Remove state on end of transition */ /* Remove state on end of transition */
const end = function(ev) { const end = function(ev) {
delete ev.target.dataset.mdAnimated delete ev.target.dataset.mdState
ev.target.style.maxHeight = "" ev.target.style.maxHeight = ""
/* Only fire once, so remove event listener again */ /* Only fire once, so directly remove event listener */
ev.target.removeEventListener("transitionend", end, false) ev.target.removeEventListener("transitionend", end, false)
} }
this.el_.addEventListener("transitionend", end, false) this.el_.addEventListener("transitionend", end, false)
} }
/** /**
* Nothing to reset * Reset height and pseudo-toggled state
*/ */
reset() { reset() {
delete this.el_.dataset.mdState
this.el_.style.maxHeight = "" this.el_.style.maxHeight = ""
delete this.el_.dataset.mdToggled
} }
} }

View File

@ -20,14 +20,14 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import Index from "./Search/Index"
import Lock from "./Search/Lock" import Lock from "./Search/Lock"
import Result from "./Search/Result"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Module * Module
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default { export default {
Index, Lock,
Lock Result
} }

View File

@ -1,152 +0,0 @@
/*
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
*
* 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 NON-INFRINGEMENT. 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.
*/
import lunr from "lunr"
/* ----------------------------------------------------------------------------
* Definition
* ------------------------------------------------------------------------- */
export default class Index {
/**
* // TODO: just copy+pasted
*
* @constructor
*/
constructor() {
const query = document.getElementById("query")
// TODO: put this in search index class...
// setTimeout(function() {
// indexed percentage!
fetch("/mkdocs/search_index.json") // TODO: prepend BASE URL!!!
.then(response => {
return response.json()
})
.then(data => {
/* Create index */
const index = lunr(function() {
/* eslint-disable no-invalid-this, lines-around-comment */
this.field("title", { boost: 10 })
this.field("text")
this.ref("location")
/* eslint-enable no-invalid-this, lines-around-comment */
})
/* Index articles */
const articles = {}
data.docs.forEach((article, i) => {
// console.log(`indexing...${i}`)
const meta = document.querySelector(".md-search-result__meta")
meta.innerHTML = `Indexing: ${(i + 1) / data.docs.length}%`
// TODO: match for two whitespaces, then replace unnecessary whitespace after string
article.text = article.text.replace(/\s(\.,\:)\s/gi, (string, g1) => {
return `${g1} `
})
// TODO: window.baseUrl sucks...
article.location = window.baseUrl + article.location
articles[article.location] = article
index.add(article)
})
/* Truncate a string after the given number of characters */
const truncate = function(string, n) {
let i = n
if (string.length > i) {
while (string[i] !== " " && --i > 0);
return `${string.substring(0, i)}&hellip;`
}
return string
}
/* Register keyhandler to execute search on key up */
const queryx = document.getElementById("query")
queryx.addEventListener("keyup", () => {
const container = document.querySelector(".md-search-result__list")
while (container.firstChild)
container.removeChild(container.firstChild)
// /* Abort, if the query is empty */
// var bar = document.querySelector('.bar.search');
// if (!query.value.length) {
// while (meta.firstChild)
// meta.removeChild(meta.firstChild);
//
// /* Restore state */
// bar.classList.remove('non-empty');
// return;
// }
/* Show reset button */
// bar.classList.add('non-empty');
/* Execute search */
const results = index.search(query.value)
results.forEach(result => {
const article = articles[result.ref]
container.appendChild(
<li class="md-search-result__item">
<a href={article.location} title={article.title}
class="md-search-result__link">
<article class="md-search-result__article">
<h1 class="md-search-result__title">
{article.title}
</h1>
<p class="md-search-result__teaser">
{truncate(article.text, 140)}
</p>
</article>
</a>
</li>
)
})
/* Show number of search results */
// var number = document.createElement('strong');
const meta = document.querySelector(".md-search-result__meta")
meta.innerHTML = `${results.length} search result${
results.length !== 1
? "s"
: ""}`
/* Update number */
// while (meta.firstChild)
// meta.removeChild(meta.firstChild);
// meta.appendChild(number);
})
// setTimeout(function() {
// li.classList.remove('md-source__fact--hidden');
// }, 100);
})
.catch(() => {
// console.log("parsing failed", ex)
})
}
}

View File

@ -21,102 +21,68 @@
*/ */
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Definition * Class
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default class Lock { export default class Lock {
/** /**
* Lock body for full-screen search bar * Lock body for full-screen search modal
* *
* @constructor * @constructor
* @param {(string|HTMLElement)} el - Selector or HTML element * @param {(string|HTMLElement)} el - Selector or HTML element
* @param {Function} handler - Callback to execute in active search mode
*/ */
constructor(el, handler) { constructor(el) {
this.el_ = (typeof el === "string") this.el_ = (typeof el === "string")
? document.querySelector(el) ? document.querySelector(el)
: el : el
/* Initialize page y-offset and callback */
this.offset_ = 0
this.handler_ = handler
/* Dispatch update on next repaint */
this.handler_ = ev => {
this.update(ev)
}
} }
/** /**
* Update state * Setup locked state
*
* @param {Event} ev - Event
*/ */
update(ev) { setup() {
this.update()
}
/**
* Update locked state
*/
update() {
/* Entering search mode */ /* Entering search mode */
if (ev.target.checked) { if (this.el_.checked) {
this.offset_ = window.scrollY this.offset_ = window.pageYOffset
/* First timeout: scroll to top after transition, to omit flickering */ /* Scroll to top after transition, to omit flickering */
setTimeout(() => { setTimeout(() => {
window.scrollTo(0, 0) window.scrollTo(0, 0)
}, 400)
/* Second timeout: Lock body after finishing transition and scrolling /* Lock body after finishing transition */
to top and focus input field. Sadly, the focus event is not dispatched if (this.el_.checked) {
on iOS Safari and there's nothing we can do about it. */ document.body.dataset.mdState = "lock"
setTimeout(() => {
/* This additional check is necessary to handle fast subsequent clicks
on the toggle and the timeout to lock the body must be cancelled */
if (ev.target.checked) {
document.body.dataset.mdLocked = ""
setTimeout(this.handler_, 200)
} }
}, 400) }, 400)
/* Exiting search mode */ /* Exiting search mode */
} else { } else {
delete document.body.dataset.mdLocked delete document.body.dataset.mdState
/* Scroll to former position, but wait for 100ms to prevent flashes on /* Scroll to former position, but wait for 100ms to prevent flashes on
iOS. A short timeout seems to do the trick */ iOS. A short timeout seems to do the trick */
setTimeout(() => { setTimeout(() => {
window.scrollTo(0, this.offset_) if (typeof this.offset_ !== "undefined")
window.scrollTo(0, this.offset_)
}, 100) }, 100)
} }
} }
/** /**
* Reset state * Reset locked state and page y-offset
*
* @param {Event} ev - Event
*/ */
reset() { reset() {
delete document.body.dataset.mdLocked if (document.body.dataset.mdState)
window.scrollTo(0, this.offset_) window.scrollTo(0, this.offset_)
} delete document.body.dataset.mdState
/**
* Register listener for all relevant events
*/
listen() {
["change"].forEach(name => {
this.el_.addEventListener(name, this.handler_, false)
})
}
/**
* Unregister listener for all relevant events
*/
unlisten() {
["change"].forEach(name => {
this.el_.removeEventListener(name, this.handler_, false)
})
/* Final reset */
this.reset()
} }
} }

View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
*
* 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 NON-INFRINGEMENT. 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.
*/
import lunr from "lunr"
/* ----------------------------------------------------------------------------
* Class
* ------------------------------------------------------------------------- */
export default class Result {
/**
* Perform search and update results on keyboard events
*
* @constructor
* @param {(string|HTMLElement)} el - Selector or HTML element
* @param {(Array.<object>|Function)} data - Promise or array providing data
*/
constructor(el, data) {
this.el_ = (typeof el === "string")
? document.querySelector(el)
: el
/* Set data and create metadata and list elements */
this.data_ = data
this.meta_ = (
<div class="md-search-result__meta">
Type to start searching
</div>
)
this.list_ = (
<ol class="md-search-result__list"></ol>
)
/* Inject created elements */
this.el_.appendChild(this.meta_)
this.el_.appendChild(this.list_)
}
/**
* Update search results
*
* @param {Event} ev - Input or focus event
*/
update(ev) {
/* Initialize index, if this has not be done yet */
if (ev.type === "focus" && !this.index_) {
/* Initialize index */
const init = data => {
this.index_ = lunr(function() {
/* eslint-disable no-invalid-this, lines-around-comment */
this.field("title", { boost: 10 })
this.field("text")
this.ref("location")
/* eslint-enable no-invalid-this, lines-around-comment */
})
/* Index documents */
this.data_ = data.reduce((docs, doc) => {
this.index_.add(doc)
docs[doc.location] = doc
return docs
}, {})
}
/* Initialize index after short timeout to account for transition */
setTimeout(() => {
return typeof this.data_ === "function"
? this.data_().then(init)
: init(this.data_)
}, 250)
/* Execute search on new input event after clearing current list */
} else if (ev.type === "keyup") {
while (this.list_.firstChild)
this.list_.removeChild(this.list_.firstChild)
/* Perform search on index and render documents */
const result = this.index_.search(ev.target.value)
for (const item of result) {
const doc = this.data_[item.ref]
this.list_.appendChild(
<li class="md-search-result__item">
<a href={doc.location} title={doc.title}
class="md-search-result__link">
<article class="md-search-result__article">
<h1 class="md-search-result__title">
{doc.title}
</h1>
<p class="md-search-result__teaser">
{doc.text}
</p>
</article>
</a>
</li>
)
}
/* Update search metadata */
this.meta_.textContent =
`${result.length} search result${result.length !== 1 ? "s" : ""}`
}
}
}

View File

@ -21,7 +21,7 @@
*/ */
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Definition * Class
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default class Sidebar { export default class Sidebar {
@ -37,7 +37,7 @@ export default class Sidebar {
? document.querySelector(el) ? document.querySelector(el)
: el : el
/* Index inner and outer container */ /* Retrieve inner and outer container */
const inner = this.el_.parentNode const inner = this.el_.parentNode
const outer = this.el_.parentNode.parentNode const outer = this.el_.parentNode.parentNode
@ -52,6 +52,13 @@ export default class Sidebar {
this.height_ = 0 this.height_ = 0
} }
/**
* Initialize sidebar state
*/
setup() {
this.update()
}
/** /**
* Update locked state and height * Update locked state and height
*/ */
@ -71,12 +78,12 @@ export default class Sidebar {
/* Sidebar should be locked, as we're below parent offset */ /* Sidebar should be locked, as we're below parent offset */
if (offset < this.offset_) { if (offset < this.offset_) {
if (!this.el_.dataset.mdLocked) if (this.el_.dataset.mdState !== "lock")
this.el_.dataset.mdLocked = "" this.el_.dataset.mdState = "lock"
/* Sidebar should be unlocked, if locked */ /* Sidebar should be unlocked, if locked */
} else if (typeof this.el_.dataset.mdLocked === "string") { } else if (this.el_.dataset.mdState === "lock") {
delete this.el_.dataset.mdLocked delete this.el_.dataset.mdState
} }
} }
@ -84,7 +91,7 @@ export default class Sidebar {
* Reset locked state and height * Reset locked state and height
*/ */
reset() { reset() {
delete this.el_.dataset.mdLocked delete this.el_.dataset.mdState
this.el_.style.height = "" this.el_.style.height = ""
this.height_ = 0 this.height_ = 0
} }

View File

@ -20,19 +20,14 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import Adapter from "./Source/Adapter"
import Repository from "./Source/Repository"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Definition * Module
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default export default {
class Abstract { Adapter,
Repository
/**
* Dispatch update on next repaint
*
* @constructor
*/
// constructor() {
//
// }
} }

View File

@ -20,14 +20,12 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import Toggle from "./Listener/Toggle" import GitHub from "./Adapter/GitHub"
import Viewport from "./Listener/Viewport"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Module * Module
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default { export default {
Toggle, GitHub
Viewport
} }

View File

@ -20,49 +20,71 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import Cookies from "js-cookie"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Definition * Class
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default class Abstract { export default class Abstract {
/** /**
* Abstract listener * Retrieve source information
* *
* @constructor * @constructor
* @param {(string|HTMLElement)} el - Selector or HTML element * @param {(string|HTMLElement)} el - Selector or HTML element
* @param {Array.<string>} events - Event names to listen on
* @param {Function} handler - Event handler to execute
*/ */
constructor(el, events, handler) { constructor(el) {
if (this === Abstract)
throw new Error("Cannot construct abstract instance")
/* Resolve element */
this.el_ = (typeof el === "string") this.el_ = (typeof el === "string")
? document.querySelector(el) ? document.querySelector(el)
: el : el
/* Set event names and handler */ /* Retrieve base URL */
this.events_ = events this.base_ = this.el_.href
this.handler_ = handler
} }
/** /**
* Register listener for all relevant events * Retrieve data from Cookie or fetch from respective API
*
* @return {Promise} Promise that returns an array of facts
*/ */
listen() { fetch() {
this.events_.forEach(name => { return new Promise(resolve => {
this.el_.addEventListener(name, this.handler_, false) const cached = Cookies.getJSON(".cache-source")
if (typeof cached !== "undefined") {
resolve(cached)
/* If the data is not cached in a cookie, invoke fetch */
} else {
this.fetch_().then(data => {
Cookies.set(".cache-source", data)
resolve(data)
})
}
}) })
} }
/** /**
* Unregister listener for all relevant events * Abstract private function that fetches relevant repository information
*
* @abstract
* @return {Promise} Promise that provides the facts in an array
*/ */
unlisten() { fetch_() {
this.events_.forEach(name => { throw new Error("fetch_(): Not implemented")
this.el_.removeEventListener(name, this.handler_, false) }
})
/**
* Format a number with suffix
*
* @param {Number} number - Number to format
* @return {Number} Formatted number
*/
format_(number) {
if (number > 10000)
return `${(number / 1000).toFixed(0)}k`
else if (number > 1000)
return `${(number / 1000).toFixed(1)}k`
return number
} }
} }

View File

@ -20,21 +20,40 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import Abstract from "../Abstract" import Abstract from "./Abstract"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Definition * Class
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default class Offset extends Abstract { export default class GitHub extends Abstract {
/** /**
* Listener which monitors changes to the offset of the viewport * Retrieve source information from GitHub
* *
* @constructor * @constructor
* @param {Function} handler - Event handler to execute * @param {(string|HTMLElement)} el - Selector or HTML element
*/ */
constructor(handler) { constructor(el) {
super(window, ["scroll"], handler) super(el)
/* Adjust base URL to reach API endpoints */
this.base_ = this.base_.replace("github.com/", "api.github.com/repos/")
}
/**
* Fetch relevant source information from GitHub
*
* @return {function} Promise returning an array of facts
*/
fetch_() {
return fetch(this.base_)
.then(response => response.json())
.then(data => {
return [
`${this.format_(data.stargazers_count)} Stars`,
`${this.format_(data.forks_count)} Forks`
]
})
} }
} }

View File

@ -20,22 +20,39 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import Abstract from "./Abstract" import Cookies from "js-cookie"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Definition * Class
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
export default class Toggle extends Abstract { export default class Repository {
/** /**
* Listener which monitors state changes of a toggle * Render repository information
* *
* @constructor * @constructor
* @param {(string|HTMLElement)} el - Selector or HTML element * @param {(string|HTMLElement)} el - Selector or HTML element
* @param {Function} handler - Event handler to execute
*/ */
constructor(el, handler) { constructor(el) {
super(el, ["click"], handler) this.el_ = (typeof el === "string")
? document.querySelector(el)
: el
}
/**
* Initialize the source repository
*
* @param {Array.<string>} facts - Facts to be rendered
*/
initialize(facts) {
this.el_.children[0].appendChild(
<ul class="md-source__facts">
{facts.map(fact => <li class="md-source__fact">{fact}</li>)}
</ul>
)
/* Finish rendering with animation */
this.el_.dataset.mdState = "done"
} }
} }

View File

@ -55,7 +55,10 @@
@import "extensions/footnotes"; @import "extensions/footnotes";
@import "extensions/permalinks"; @import "extensions/permalinks";
@import "extensions/pymdown/arithmatex";
@import "extensions/pymdown/critic"; @import "extensions/pymdown/critic";
@import "extensions/pymdown/emoji";
@import "extensions/pymdown/inlinehilite";
@import "extensions/pymdown/tasklist"; @import "extensions/pymdown/tasklist";
@import "shame"; @import "shame";

View File

@ -24,21 +24,16 @@
// Rules // Rules
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Enfore correct box model - the prefixed versions are necessary for older // Enfore correct box model
// browsers, i.e. Chrome < 10, Firefox < 29, Safari < 6 and Android < 4
html { html {
box-sizing: border-box; box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
} }
// All elements shall inherit the document default // All elements shall inherit the document default
*, *,
*::before, *::before,
*::after { *::after {
box-sizing: inherit; box-sizing: inherit;
-moz-box-sizing: inherit;
-webkit-box-sizing: inherit;
} }
// Prevent adjustments of font size after orientation changes in IE and iOS // Prevent adjustments of font size after orientation changes in IE and iOS
@ -51,19 +46,6 @@ body {
margin: 0; margin: 0;
} }
// Add correct display property in IE < 9
article,
aside,
figcaption,
figure,
footer,
header,
main,
nav,
section {
display: block;
}
// Reset horizontal rules in FF // Reset horizontal rules in FF
hr { hr {
overflow: visible; overflow: visible;
@ -82,7 +64,7 @@ a {
} }
} }
// Remove gaps in links underline in iOS >= 8 and Safari >= 8 // Remove gaps in underlined links in iOS >= 8 and Safari >= 8
a { a {
-webkit-text-decoration-skip: objects; -webkit-text-decoration-skip: objects;
} }

View File

@ -226,15 +226,15 @@ kbd {
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 0.4rem; width: 0.4rem;
height: 0.4rem; height: 0.4rem;
}
// Style scrollbar thumb // Style scrollbar thumb
&-thumb { &::-webkit-scrollbar-thumb {
background-color: $md-color-black--lighter; background-color: $md-color-black--lighter;
// Hovered scrollbar thumb // Hovered scrollbar thumb
&:hover { &:hover {
background-color: $md-color-accent; background-color: $md-color-accent;
}
} }
} }

View File

@ -229,15 +229,15 @@ $codehilite-whitespace: transparent;
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 0.4rem; width: 0.4rem;
height: 0.4rem; height: 0.4rem;
}
// Style scrollbar thumb // Style scrollbar thumb
&-thumb { &::-webkit-scrollbar-thumb {
background-color: $md-color-black--lighter; background-color: $md-color-black--lighter;
// Hovered scrollbar thumb // Hovered scrollbar thumb
&:hover { &:hover {
background-color: $md-color-accent; background-color: $md-color-accent;
}
} }
} }

View File

@ -63,7 +63,7 @@
} }
} }
// Correct anchor offset of headlines // Correct anchor offset of active targets
@each $level, $delta in ( @each $level, $delta in (
h1: 3.0rem, h1: 3.0rem,
h2: 0.2rem, h2: 0.2rem,
@ -72,7 +72,7 @@
h5: 1.0rem, h5: 1.0rem,
h6: 1.0rem h6: 1.0rem
) { ) {
#{$level}[id]::before { #{$level}[id]:target::before {
display: block; display: block;
margin-top: -(5.6rem + 2.4rem + $delta); margin-top: -(5.6rem + 2.4rem + $delta);
padding-top: (5.6rem + 2.4rem + $delta); padding-top: (5.6rem + 2.4rem + $delta);

View File

@ -0,0 +1,51 @@
////
/// Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
///
/// 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 NON-INFRINGEMENT. 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
////
// ----------------------------------------------------------------------------
// Rules
// ----------------------------------------------------------------------------
// Scoped in typesetted content to match specificity of regular content
.md-typeset {
// MathJax integration - add padding to omit vertical scrollbar
.MJXc-display {
margin: 0.75em 0;
padding: 0.25em 0;
overflow: auto;
}
// Stretch top-level containers
> p > .MJXc-display {
// [mobile -]: Stretch to whole width
@include break-to-device(mobile) {
margin: 0.75em -1.6rem;
padding: 0.25em 1.6rem;
}
}
// Remove outline on tab index
.MathJax_CHTML {
outline: 0;
}
}

View File

@ -0,0 +1,30 @@
////
/// Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
///
/// 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 NON-INFRINGEMENT. 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
////
// ----------------------------------------------------------------------------
// Rules
// ----------------------------------------------------------------------------
// Correct alignment of emojis
.emoji {
vertical-align: text-top;
}

View File

@ -0,0 +1,37 @@
////
/// Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
///
/// 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 NON-INFRINGEMENT. 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
////
// ----------------------------------------------------------------------------
// Rules
// ----------------------------------------------------------------------------
// Scoped in typesetted content to match specificity of regular content
.md-typeset {
// Qualified class selector to distinguish inline code from code blocks
code.codehilite {
$correct: 1 / 0.85;
margin: 0 0.25em * $correct;
padding: 0.0625em * $correct 0;
}
}

View File

@ -49,10 +49,10 @@
@extend %md-icon; @extend %md-icon;
position: absolute; position: absolute;
top: 0.15em; top: 0.05em;
left: -1.25em; left: -1.25em;
color: $md-color-black--lighter; color: $md-color-black--lighter;
font-size: 1.25em; font-size: 1.5em;
content: "check_box_outline_blank"; content: "check_box_outline_blank";
vertical-align: -0.25em; vertical-align: -0.25em;
} }

View File

@ -50,7 +50,7 @@ body {
@include break-to-device(tablet portrait) { @include break-to-device(tablet portrait) {
// Lock body to viewport height (e.g. in search mode) // Lock body to viewport height (e.g. in search mode)
&[data-md-locked] { &[data-md-state="lock"] {
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
} }
@ -117,7 +117,7 @@ hr {
@include break-to-device(tablet) { @include break-to-device(tablet) {
// Expanded drawer // Expanded drawer
.md-toggle--drawer:checked ~ & { [data-md-toggle="drawer"]:checked ~ & {
width: 100%; width: 100%;
height: 100%; height: 100%;
transition: transition:

View File

@ -113,7 +113,7 @@
} }
// Blurred item // Blurred item
&[data-md-blurred] { &[data-md-state="blur"] {
color: $md-color-black--light; color: $md-color-black--light;
} }
@ -334,7 +334,7 @@
// Animation is only possible if JavaScript is available, as the max-height // Animation is only possible if JavaScript is available, as the max-height
// property must be calculated before transitioning // property must be calculated before transitioning
&[data-md-animated] { &[data-md-state="animate"] {
transition: max-height 0.25s cubic-bezier(0.86, 0.0, 0.07, 1.0); transition: max-height 0.25s cubic-bezier(0.86, 0.0, 0.07, 1.0);
} }
@ -346,7 +346,7 @@
// Expand nested navigation, if toggle is checked // Expand nested navigation, if toggle is checked
.md-nav__toggle:checked ~ &, .md-nav__toggle:checked ~ &,
&[data-md-expanded] { &[data-md-state="expand"] {
max-height: 100%; max-height: 100%;
} }

View File

@ -62,7 +62,7 @@
z-index: 1; z-index: 1;
// Expanded overlay // Expanded overlay
.md-toggle--search:checked ~ .md-header & { [data-md-toggle="search"]:checked ~ .md-header & {
transition: transition:
transform 0.4s, transform 0.4s,
opacity 0.1s; opacity 0.1s;
@ -71,7 +71,7 @@
} }
// Set scale factors // Set scale factors
.md-toggle--search:checked ~ .md-header & { [data-md-toggle="search"]:checked ~ .md-header & {
// [mobile portrait -]: Scale up 45 times // [mobile portrait -]: Scale up 45 times
@include break-to-device(mobile portrait) { @include break-to-device(mobile portrait) {
@ -109,7 +109,7 @@
z-index: 2; z-index: 2;
// Active search modal // Active search modal
.md-toggle--search:checked ~ .md-header & { [data-md-toggle="search"]:checked ~ .md-header & {
left: 0; left: 0;
transform: translateX(0); transform: translateX(0);
transition: transition:
@ -144,7 +144,7 @@
} }
// Set maximum width // Set maximum width
.md-toggle--search:checked ~ .md-header & { [data-md-toggle="search"]:checked ~ .md-header & {
// [tablet landscape]: Do not overlay title // [tablet landscape]: Do not overlay title
@include break-at-device(tablet landscape) { @include break-at-device(tablet landscape) {
@ -204,7 +204,7 @@
} }
// Set light background on active search field // Set light background on active search field
.md-toggle--search:checked ~ .md-header & { [data-md-toggle="search"]:checked ~ .md-header & {
border-radius: 0.2rem 0.2rem 0 0; border-radius: 0.2rem 0.2rem 0 0;
background: $md-color-white; background: $md-color-white;
color: $md-color-black; color: $md-color-black;
@ -269,7 +269,7 @@
opacity: 0; opacity: 0;
// Show search output in active state // Show search output in active state
.md-toggle--search:checked ~ .md-header & { [data-md-toggle="search"]:checked ~ .md-header & {
opacity: 1; opacity: 1;
} }
} }
@ -299,12 +299,22 @@
box-shadow: 0 0.1rem 0 $md-color-black--lightest inset; box-shadow: 0 0.1rem 0 $md-color-black--lightest inset;
overflow-y: auto; overflow-y: auto;
// [tablet landscape]: Set absolute width to omit unnecessary reflow
@include break-at-device(tablet landscape) {
width: 46.8rem;
}
// [screen +]: Set absolute width to omit unnecessary reflow
@include break-from-device(screen) {
width: 66.8rem;
}
// [tablet landscape +]: Limit height to viewport // [tablet landscape +]: Limit height to viewport
@include break-from-device(tablet landscape) { @include break-from-device(tablet landscape) {
max-height: 0; max-height: 0;
// Expand in active state // Expand in active state
.md-toggle--search:checked ~ .md-header & { [data-md-toggle="search"]:checked ~ .md-header & {
max-height: 75vh; max-height: 75vh;
} }

View File

@ -37,7 +37,7 @@
} }
// Lock sidebar to container height (account for fixed header) // Lock sidebar to container height (account for fixed header)
&[data-md-locked] { &[data-md-state="lock"] {
position: fixed; position: fixed;
top: 5.6rem; top: 5.6rem;
} }
@ -65,7 +65,7 @@
} }
// Expanded drawer // Expanded drawer
.md-toggle--drawer:checked ~ .md-container & { [data-md-toggle="drawer"]:checked ~ .md-container & {
@include z-depth(8); @include z-depth(8);
transform: translateX(24.2rem); transform: translateX(24.2rem);
@ -93,7 +93,7 @@
float: right; float: right;
// Hack: align right in case of locked sidebar // Hack: align right in case of locked sidebar
&[data-md-locked] { &[data-md-state="lock"] {
margin-left: 100%; margin-left: 100%;
transform: translate(-100%, 0); transform: translate(-100%, 0);

View File

@ -24,6 +24,40 @@
// Rules // Rules
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Show source facts
@keyframes md-source__facts--done {
0% {
height: 0;
}
100% {
height: 1.3rem;
}
}
// Show source fact
@keyframes md-source__fact--done {
0% {
transform: translateY(100%);
opacity: 0;
}
50% {
opacity: 0;
}
100% {
transform: translateY(0%);
opacity: 1;
}
}
// ----------------------------------------------------------------------------
// Rules
// ----------------------------------------------------------------------------
// Source container // Source container
.md-source { .md-source {
display: block; display: block;
@ -98,25 +132,25 @@
font-size: 1.1rem; font-size: 1.1rem;
font-weight: 700; font-weight: 700;
opacity: 0.75; opacity: 0.75;
overflow: auto;
list-style-type: none; list-style-type: none;
// Show after the data was loaded
[data-md-state="done"] & {
animation: md-source__facts--done 0.25s ease-in;
}
} }
// Fact // Fact
&__fact { &__fact {
float: left; float: left;
transform: translateY(0%);
transition:
transform 0.25s cubic-bezier(0.1, 0.7, 0.1, 1.0),
opacity 0.25s;
opacity: 1;
// Facts are hidden by default // Show after the data was loaded
&--hidden { [data-md-state="done"] & {
transform: translateY(100%); animation: md-source__fact--done 0.4s ease-out;
opacity: 0;
} }
// Middle dots before fact // Middle dot before fact
&::before { &::before {
margin: 0 0.2rem; margin: 0 0.2rem;
content: "\00B7"; content: "\00B7";

View File

@ -79,11 +79,13 @@
<body> <body>
<!-- State toggles --> <!-- State toggles -->
<input class="md-toggle md-toggle--drawer" type="checkbox" id="drawer" /> <input class="md-toggle" data-md-toggle="drawer"
<input class="md-toggle md-toggle--search" type="checkbox" id="search" /> type="checkbox" id="drawer" />
<input class="md-toggle" data-md-toggle="search"
type="checkbox" id="search" />
<!-- Overlay for expanded drawer --> <!-- Overlay for expanded drawer -->
<label class="md-overlay" for="drawer"></label> <label class="md-overlay" data-md-overlay for="drawer"></label>
<!-- Application header --> <!-- Application header -->
{% include "partials/header.html" %} {% include "partials/header.html" %}
@ -170,7 +172,17 @@
{% include "partials/footer.html" %} {% include "partials/footer.html" %}
</div> </div>
<!-- Theme-related and custom javascripts --> <!-- Extension-related JavaScript -->
{% for extension in config.markdown_extensions %}
<!-- MathJax integration -->
{% if extension == "pymdownx.arithmatex" %}
{% set path = "mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML" %}
<script src="https://cdn.mathjax.org/{{ path }}"></script>
{% endif %}
{% endfor %}
<!-- Theme-related and custom JavaScript -->
<script src="{{ base_url }}/assets/javascripts/application.js"></script> <script src="{{ base_url }}/assets/javascripts/application.js"></script>
<script> <script>

View File

@ -26,11 +26,11 @@
<!-- Active checkbox expands items contained within nested section --> <!-- Active checkbox expands items contained within nested section -->
{% if nav_item.active %} {% if nav_item.active %}
<input class="md-toggle md-nav__toggle" type="checkbox" <input class="md-toggle md-nav__toggle" data-md-toggle="{{ path }}"
id="{{ path }}" checked /> type="checkbox" id="{{ path }}" checked />
{% else %} {% else %}
<input class="md-toggle md-nav__toggle" type="checkbox" <input class="md-toggle md-nav__toggle" data-md-toggle="{{ path }}"
id="{{ path }}" /> type="checkbox" id="{{ path }}" />
{% endif %} {% endif %}
<!-- Expand active pages --> <!-- Expand active pages -->
@ -54,12 +54,13 @@
</nav> </nav>
</li> </li>
<!-- Main navigation item with nested items --> <!-- Current navigation item -->
{% elif nav_item == current_page %} {% elif nav_item == current_page %}
<li class="md-nav__item"> <li class="md-nav__item">
<!-- Active checkbox expands items contained within nested section --> <!-- Active checkbox expands items contained within nested section -->
<input class="md-toggle md-nav__toggle" type="checkbox" id="toc" /> <input class="md-toggle md-nav__toggle" data-md-toggle="toc"
type="checkbox" id="toc" />
<!-- Expand active pages --> <!-- Expand active pages -->
<label class="md-nav__link md-nav__link--active" for="toc"> <label class="md-nav__link md-nav__link--active" for="toc">

View File

@ -21,23 +21,18 @@
--> -->
<!-- Search interface --> <!-- Search interface -->
<div class="md-search"> <div class="md-search" data-md-search>
<div class="md-search__overlay"></div> <div class="md-search__overlay"></div>
<div class="md-search__inner"> <div class="md-search__inner">
<form class="md-search__form"> <form class="md-search__form" name="search">
<input type="text" class="md-search__input" <input type="text" class="md-search__input" name="query"
placeholder="Search" autocapitalize="off" autocorrect="off" placeholder="Search" autocapitalize="off" autocorrect="off"
autocomplete="off" spellcheck="false" id="query" /> autocomplete="off" spellcheck="false" />
<label class="md-icon md-search__icon" for="search"></label> <label class="md-icon md-search__icon" for="search"></label>
</form> </form>
<div class="md-search__output"> <div class="md-search__output">
<div class="md-search__scrollwrap"> <div class="md-search__scrollwrap">
<div class="md-search-result"> <div class="md-search-result" data-md-search-result></div>
<div class="md-search-result__meta">
Indexing
</div>
<ol class="md-search-result__list"></ol>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -26,24 +26,23 @@
--> -->
{% set platform = config.extra.repo_icon or repo_url %} {% set platform = config.extra.repo_icon or repo_url %}
{% if "github" in platform %} {% if "github" in platform %}
{% set repo_icon = "md-source--github" %} {% set repo_type = "github" %}
{% set repo_icon = "md-source--github" %} <!-- TODO: remove this in favor of type -->
{% elif "gitlab" in platform %} {% elif "gitlab" in platform %}
{% set repo_type = "gitlab" %}
{% set repo_icon = "md-source--gitlab" %} {% set repo_icon = "md-source--gitlab" %}
{% elif "bitbucket" in platform %} {% elif "bitbucket" in platform %}
{% set repo_type = "bitbucket" %}
{% set repo_icon = "md-source--bitbucket" %} {% set repo_icon = "md-source--bitbucket" %}
{% else %} {% else %}
{% set repo_type = "" %}
{% set repo_icon = "" %} {% set repo_icon = "" %}
{% endif %} {% endif %}
<!-- Repository containing source --> <!-- Repository containing source -->
<a href="{{ repo_url }}" title="Go to repository" <a href="{{ repo_url }}" title="Go to repository"
class="md-source {{ repo_icon }}"> class="md-source {{ repo_icon }}" data-md-source="{{ repo_type }}"> <!-- use <> for custom / private repo -->
<div class="md-source__repository"> <div class="md-source__repository">
{{ repo_name }} {{ repo_name }}
<ul class="md-source__facts">
{% if config.extra.version %}
<li class="md-source__fact">v{{ config.extra.version }}</li>
{% endif %}
</ul>
</div> </div>
</a> </a>