Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f5aa8ad5f | ||
|
|
4927e57c88 | ||
|
|
9b471c682f | ||
|
|
18262ce8d2 | ||
|
|
769727e886 | ||
|
|
99bc558d5c | ||
|
|
b33a92e37b | ||
|
|
eadce61e75 | ||
|
|
13ab32f631 | ||
|
|
e483055e17 | ||
|
|
c890255c39 | ||
|
|
5e5b680fa0 | ||
|
|
0975c7d1be | ||
|
|
31836391e1 | ||
|
|
c9a7019333 | ||
|
|
b6b5904a7a | ||
|
|
80fe7e010d | ||
|
|
7c36b5c4ef | ||
|
|
099799cdf5 | ||
|
|
854663ff03 | ||
|
|
885053bfbd | ||
|
|
0cfee35151 | ||
|
|
89c68b03f0 | ||
|
|
ee198dd6d2 | ||
|
|
401b512dda | ||
|
|
4fc2a6c02e | ||
|
|
7199f7ad6c | ||
|
|
8792079cb3 | ||
|
|
26d2ae36e3 | ||
|
|
2b0b90c5e9 | ||
|
|
c8ffa5203a | ||
|
|
f1ee7add1c | ||
|
|
78d7cdaf0b | ||
|
|
9028461c72 | ||
|
|
d75aec1b7e | ||
|
|
0beec63367 | ||
|
|
57871449ea | ||
|
|
038288d489 | ||
|
|
3e2fa37250 | ||
|
|
7e601d485a | ||
|
|
0bff78cd1b | ||
|
|
1fc01efe8b | ||
|
|
641b4ca13d | ||
|
|
cbb8567c76 | ||
|
|
70154b6047 | ||
|
|
d78e4e6a0b | ||
|
|
52a3761d65 | ||
|
|
07329f4304 | ||
|
|
f40585f528 | ||
|
|
9e3403ee4f | ||
|
|
76a383fb1b | ||
|
|
d4c796c73e | ||
|
|
64bd1d141a | ||
|
|
551138e7c1 | ||
|
|
7d94975960 | ||
|
|
8a7d9001fd | ||
|
|
55cae2d1f1 | ||
|
|
4fe26f24db | ||
|
|
87c440c003 | ||
|
|
ef7b07a90e | ||
|
|
17808d964d | ||
|
|
7d46ed2a85 | ||
|
|
3783eceb09 | ||
|
|
8f46cc6f09 | ||
|
|
0eb24a04ae | ||
|
|
4997d1f63c | ||
|
|
cae45a60b3 | ||
|
|
758ae36c92 | ||
|
|
c3231f1a9e | ||
|
|
b04c3d1354 | ||
|
|
b09e334f3f | ||
|
|
f71359ce65 | ||
|
|
80be8bb1ec | ||
|
|
38f0099fc8 | ||
|
|
4186b7b7f8 | ||
|
|
bb9e1eb3df | ||
|
|
32ffc58d12 | ||
|
|
2e228af92d | ||
|
|
28d024af2f | ||
|
|
21f2617c9c | ||
|
|
203087bcb1 | ||
|
|
680725ed3a | ||
|
|
1e61603b4e | ||
|
|
f51f3c453d | ||
|
|
61533af0ef | ||
|
|
62ff9d0ac0 | ||
|
|
460164b560 | ||
|
|
9d24e6880b | ||
|
|
ceea88e066 | ||
|
|
ed1ae7226a | ||
|
|
e68f54c79f |
@@ -2,9 +2,6 @@
|
||||
"presets": ["es2015"],
|
||||
"plugins": [
|
||||
"add-module-exports",
|
||||
"babel-root-import",
|
||||
["transform-react-jsx", {
|
||||
"pragma": "JSX.createElement"
|
||||
}]
|
||||
"babel-root-import"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -18,7 +18,11 @@
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
# Build files
|
||||
# Files generated by build
|
||||
/build
|
||||
/material
|
||||
/site
|
||||
|
||||
# Files generated by visual tests
|
||||
/gemini-report
|
||||
/tests/visual/data
|
||||
|
||||
@@ -25,6 +25,6 @@ CHANGED="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)"
|
||||
|
||||
# Perform install and prune of NPM dependencies if package.json changed
|
||||
if $(echo "$CHANGED" | grep --quiet package.json); then
|
||||
echo "Hook[post-merge]: Updating dependencies..."
|
||||
echo "Hook[post-merge]: Updating dependencies"
|
||||
npm install && npm prune
|
||||
fi
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
# Determine current branch
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
echo "Hook[pre-commit]: Checking branch..."
|
||||
echo "Hook[pre-commit]: Checking branch"
|
||||
|
||||
# If we're on master, abort commit
|
||||
if [[ "$BRANCH" == "master" ]]; then
|
||||
|
||||
@@ -46,6 +46,6 @@ FILES=$(git diff --cached --name-only --diff-filter=ACMR | \
|
||||
|
||||
# Run the check and print indicator
|
||||
if [ "$FILES" ]; then
|
||||
echo "Hook[pre-commit]: Running linter..."
|
||||
echo "Hook[pre-commit]: Running linter"
|
||||
npm run lint --silent || exit 1
|
||||
fi
|
||||
|
||||
@@ -18,11 +18,17 @@
|
||||
|
||||
### Package versions
|
||||
|
||||
- Python: `python --version`
|
||||
- MkDocs: `mkdocs --version`
|
||||
- Material: `pip show mkdocs-material | grep -E ^Version`
|
||||
* Python: `python --version`
|
||||
* MkDocs: `mkdocs --version`
|
||||
* Material: `pip show mkdocs-material | grep -E ^Version`
|
||||
|
||||
### Project configuration
|
||||
|
||||
``` yaml
|
||||
The contents of your mkdocs.yml
|
||||
```
|
||||
|
||||
### System information
|
||||
|
||||
- OS: [The operating system you're running]
|
||||
- Browser: [The browser used, if relevant]
|
||||
* OS: [The operating system you're running]
|
||||
* Browser: [The browser used, if relevant]
|
||||
|
||||
@@ -23,14 +23,19 @@
|
||||
|
||||
# NPM-related
|
||||
/node_modules
|
||||
/npm-debug.log
|
||||
/npm-debug.log*
|
||||
|
||||
# Build files
|
||||
# Files generated by build
|
||||
/build
|
||||
/manifest.json
|
||||
/MANIFEST
|
||||
/site
|
||||
|
||||
# Files generated by visual tests
|
||||
/gemini-report
|
||||
/tests/visual/baseline/local
|
||||
/tests/visual/data
|
||||
|
||||
# Distribution files
|
||||
/dist
|
||||
/mkdocs_material.egg-info
|
||||
|
||||
@@ -180,7 +180,6 @@
|
||||
"z-index"
|
||||
],
|
||||
"property-no-vendor-prefix": true,
|
||||
"root-no-standard-properties": true,
|
||||
"selector-class-pattern": "^[a-z0-9]+(-[a-z0-9]+)*(__[a-z]+)?(--[a-z]+)?$",
|
||||
"selector-descendant-combinator-no-non-space": null,
|
||||
"string-quotes": "double",
|
||||
|
||||
@@ -23,19 +23,48 @@ sudo: false
|
||||
|
||||
# Node.js versions
|
||||
node_js:
|
||||
- 4
|
||||
- 5
|
||||
- 6
|
||||
- 7
|
||||
|
||||
# Build visual tests separately - temporary disabled until tests are stable
|
||||
# matrix:
|
||||
# include:
|
||||
# - node_js: 5
|
||||
# addons:
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - gemini-report
|
||||
# apt:
|
||||
# sources:
|
||||
# - ubuntu-toolchain-r-test
|
||||
# packages:
|
||||
# - gcc-4.8
|
||||
# - g++-4.8
|
||||
# env:
|
||||
# - CXX=g++-4.8
|
||||
# install: yarn install
|
||||
# script: yarn run test:visual:run
|
||||
|
||||
# Limit clone depth to 5, to speed up build
|
||||
git:
|
||||
depth: 5
|
||||
|
||||
# Cache dependencies
|
||||
cache:
|
||||
pip: true
|
||||
yarn: true
|
||||
directories:
|
||||
- node_modules
|
||||
|
||||
# Install yarn as Travis doesn't support it out of the box
|
||||
before_install: npm install -g yarn
|
||||
|
||||
# Do not install optional dependencies by default
|
||||
install: yarn install --ignore-optional
|
||||
|
||||
# Install dependencies
|
||||
before_script:
|
||||
- pip install --user -r requirements.txt
|
||||
before_script: pip install --user -r requirements.txt
|
||||
|
||||
# Perform build and tests
|
||||
script: npm run build
|
||||
script: yarn run build
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
mkdocs-material-1.0.4 (2017-02-16)
|
||||
|
||||
* Fixed #142: Documentation build errors if h1 is defined as raw HTML
|
||||
* Fixed #164: PyPI release does not build and install
|
||||
* Fixed offsets of targeted headlines
|
||||
* Increased sidebar font size by 0.12rem
|
||||
|
||||
mkdocs-material-1.0.3 (2017-01-22)
|
||||
|
||||
* Fixed #117: Table of contents items don't blur on fast scrolling
|
||||
* Refactored sidebar positioning logic
|
||||
* Further reduction of repaints
|
||||
|
||||
mkdocs-material-1.0.2 (2017-01-15)
|
||||
|
||||
* Fixed horizontal scrollbar in content area
|
||||
* Fixed #108: Horizontal scrollbar in content area
|
||||
|
||||
mkdocs-material-1.0.1 (2017-01-14)
|
||||
|
||||
|
||||
@@ -35,14 +35,17 @@ const config = {
|
||||
src: "src/assets", /* Source directory for assets */
|
||||
build: "material/assets" /* Target directory for assets */
|
||||
},
|
||||
lib: "lib", /* Libraries */
|
||||
lib: "lib", /* Libraries and tasks */
|
||||
tests: {
|
||||
visual: "tests/visual" /* Base directory for visual tests */
|
||||
},
|
||||
views: {
|
||||
src: "src", /* Source directory for views */
|
||||
build: "material" /* Target directory for views */
|
||||
}
|
||||
}
|
||||
|
||||
const args = yargs
|
||||
let args = yargs
|
||||
.default("clean", false) /* Clean before build */
|
||||
.default("karma", true) /* Karma watchdog */
|
||||
.default("lint", true) /* Lint sources */
|
||||
@@ -52,6 +55,12 @@ const args = yargs
|
||||
.default("sourcemaps", false) /* Create sourcemaps */
|
||||
.argv
|
||||
|
||||
/* Only use the last value seen, so overrides are possible */
|
||||
args = Object.keys(args).reduce((result, arg) => {
|
||||
result[arg] = [].concat(args[arg]).pop()
|
||||
return result
|
||||
}, {})
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Overrides and helpers
|
||||
* ------------------------------------------------------------------------- */
|
||||
@@ -92,7 +101,10 @@ gulp.src = (...glob) => {
|
||||
* Helper function to load a task
|
||||
*/
|
||||
const load = task => {
|
||||
return require(`./${config.lib}/tasks/${task}`)(gulp, config, args)
|
||||
return done => {
|
||||
return require(`./${config.lib}/tasks/${task}`)
|
||||
.call(gulp, gulp, config, args)(done)
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
@@ -228,12 +240,11 @@ gulp.task("assets:clean", [
|
||||
* Minify views
|
||||
*/
|
||||
gulp.task("views:build", (args.revision ? [
|
||||
"assets:images:build",
|
||||
"assets:stylesheets:build",
|
||||
"assets:javascripts:build"
|
||||
"assets:build"
|
||||
] : []).concat(args.clean ? [
|
||||
"views:clean"
|
||||
] : []), load("views/build"))
|
||||
] : []),
|
||||
load("views/build"))
|
||||
|
||||
/*
|
||||
* Clean views
|
||||
@@ -267,14 +278,45 @@ gulp.task("mkdocs:serve",
|
||||
load("mkdocs/serve"))
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Tests
|
||||
* Visual tests
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Start karma test runner
|
||||
* Generate visual tests
|
||||
*/
|
||||
gulp.task("tests:unit:watch",
|
||||
load("tests/unit/watch"))
|
||||
gulp.task("tests:visual:generate", [
|
||||
].concat(args.clean ? [
|
||||
"tests:visual:clean",
|
||||
"assets:build",
|
||||
"views:build"
|
||||
] : []),
|
||||
load("tests/visual/generate"))
|
||||
|
||||
/*
|
||||
* Run visual tests
|
||||
*/
|
||||
gulp.task("tests:visual:run", [
|
||||
"tests:visual:generate"
|
||||
], load("tests/visual/run"))
|
||||
|
||||
/*
|
||||
* Update reference images for visual tests
|
||||
*/
|
||||
gulp.task("tests:visual:update",
|
||||
load("tests/visual/update"))
|
||||
|
||||
/*
|
||||
* Clean files generated by visual tests
|
||||
*/
|
||||
gulp.task("tests:visual:clean",
|
||||
load("tests/visual/clean"))
|
||||
|
||||
/*
|
||||
* Open a SauceConnect session for manual testing
|
||||
*/
|
||||
gulp.task("tests:visual:session", [
|
||||
"tests:visual:generate"
|
||||
], load("tests/visual/session"))
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Interface
|
||||
@@ -286,9 +328,9 @@ gulp.task("tests:unit:watch",
|
||||
gulp.task("build", [
|
||||
"assets:build",
|
||||
"views:build"
|
||||
].concat(args.mkdocs
|
||||
? "mkdocs:build"
|
||||
: []))
|
||||
].concat(args.mkdocs ? [
|
||||
"mkdocs:build"
|
||||
] : []))
|
||||
|
||||
/*
|
||||
* Clean assets and documentation
|
||||
|
||||
@@ -3,3 +3,4 @@ recursive-exclude site *
|
||||
recursive-exclude * __pycache__
|
||||
recursive-exclude * *.py[co]
|
||||
include LICENSE
|
||||
include package.json
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[![Docker][docker-image]][docker-link]
|
||||
[![PyPI][pypi-image]][pypi-link]
|
||||
|
||||
[travis-image]: https://travis-ci.org/squidfunk/mkdocs-material.svg
|
||||
[travis-image]: https://travis-ci.org/squidfunk/mkdocs-material.svg?branch=master
|
||||
[travis-link]: https://travis-ci.org/squidfunk/mkdocs-material
|
||||
[deps-image]: https://david-dm.org/squidfunk/mkdocs-material/dev-status.svg
|
||||
[deps-link]: https://david-dm.org/squidfunk/mkdocs-material?type=dev
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Release Notes
|
||||
# Release notes
|
||||
|
||||
## Upgrading
|
||||
|
||||
@@ -12,14 +12,34 @@ To determine the currently installed version, use the following command:
|
||||
|
||||
``` sh
|
||||
pip show mkdocs-material | grep -E ^Version
|
||||
# Version 1.0.0
|
||||
# Version 1.0.4
|
||||
```
|
||||
|
||||
## Changelog
|
||||
|
||||
### 1.0.4 <small> _ February 16, 2017</small>
|
||||
|
||||
* Fixed [#142][142]: Documentation build errors if `h1` is defined as raw HTML
|
||||
* Fixed [#164][164]: PyPI release does not build and install
|
||||
* Fixed offsets of targeted headlines
|
||||
* Increased sidebar font size by `0.12rem`
|
||||
|
||||
[142]: https://github.com/squidfunk/mkdocs-material/issues/142
|
||||
[164]: https://github.com/squidfunk/mkdocs-material/issues/164
|
||||
|
||||
### 1.0.3 <small> _ January 22, 2017</small>
|
||||
|
||||
* Fixed [#117][117]: Table of contents items don't blur on fast scrolling
|
||||
* Refactored sidebar positioning logic
|
||||
* Further reduction of repaints
|
||||
|
||||
[117]: https://github.com/squidfunk/mkdocs-material/issues/117
|
||||
|
||||
### 1.0.2 <small> _ January 15, 2017</small>
|
||||
|
||||
* Fixed horizontal scrollbar in content area
|
||||
* Fixed [#108][108]: Horizontal scrollbar in content area
|
||||
|
||||
[108]: https://github.com/squidfunk/mkdocs-material/issues/108
|
||||
|
||||
### 1.0.1 <small> _ January 14, 2017</small>
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-invalid-this": 0,
|
||||
"max-params": 0
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Definition
|
||||
* Module
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default /* JSX */ {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 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 ecstatic from "ecstatic"
|
||||
import * as http from "http"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Locals
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Static file server */
|
||||
let server = null
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Functions
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Start static file server
|
||||
*
|
||||
* @param {string} directory - Directory to serve
|
||||
* @param {number} port - Port to listen on
|
||||
* @param {Function} done - Resolve callback
|
||||
*/
|
||||
export const start = (directory, port, done) => {
|
||||
server = http.createServer(ecstatic({
|
||||
root: directory
|
||||
}))
|
||||
|
||||
/* Listen and register signal handlers */
|
||||
server.listen(port, "127.0.0.1", done)
|
||||
for (const signal of ["SIGTERM", "SIGINT", "exit"])
|
||||
process.on(signal, stop)
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop static file server
|
||||
*
|
||||
* @param {Function} done - Resolve callback
|
||||
*/
|
||||
export const stop = done => {
|
||||
if (server) {
|
||||
server.close(done)
|
||||
server = null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 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 launcher from "sauce-connect-launcher"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Locals
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/* SauceConnect process */
|
||||
let server = null
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Functions
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Open SauceConnect tunnel
|
||||
*
|
||||
* @param {string} id - Unique identifier
|
||||
* @param {string} username - SauceConnect username
|
||||
* @param {string} accesskey - SauceConnect accesskey
|
||||
* @param {Function} done - Resolve callback
|
||||
*/
|
||||
export const start = (id, username, accesskey, done) => {
|
||||
launcher({
|
||||
username,
|
||||
accessKey: accesskey,
|
||||
tunnelIdentifier: id
|
||||
}, (err, proc) => {
|
||||
if (err)
|
||||
throw new Error(err)
|
||||
server = proc
|
||||
done()
|
||||
})
|
||||
|
||||
/* Register signal handlers */
|
||||
for (const signal of ["SIGTERM", "SIGINT", "exit"])
|
||||
process.on(signal, stop)
|
||||
}
|
||||
|
||||
/**
|
||||
* Close SauceConnect tunnel
|
||||
*
|
||||
* @param {Function} done - Resolve callback
|
||||
*/
|
||||
export const stop = done => {
|
||||
if (server) {
|
||||
server.close(done)
|
||||
server = null
|
||||
}
|
||||
}
|
||||
@@ -33,19 +33,33 @@ let server = null
|
||||
* Definition
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Start Selenium
|
||||
*
|
||||
* @param {Function} done - Resolve callback
|
||||
*/
|
||||
export const start = done => {
|
||||
selenium.start({}, (err, proc) => {
|
||||
|
||||
/* Register signal handlers */
|
||||
for (const signal of ["SIGTERM", "SIGINT", "exit"])
|
||||
process.on(signal, stop)
|
||||
if (err) {
|
||||
|
||||
/* Install selenium, if not present */
|
||||
if (/^Missing(.*)chromedriver$/.test(err.message)) {
|
||||
selenium.install(done)
|
||||
|
||||
/* Start selenium again */
|
||||
selenium.start({}, (err_, proc_) => {
|
||||
server = proc_
|
||||
new Promise(resolve => {
|
||||
selenium.install({}, resolve)
|
||||
})
|
||||
|
||||
/* Start selenium again */
|
||||
.then(() => {
|
||||
selenium.start({}, (err_, proc_) => {
|
||||
server = proc_
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
/* Otherwise, throw error */
|
||||
} else {
|
||||
throw err
|
||||
@@ -53,20 +67,21 @@ export const start = done => {
|
||||
}
|
||||
|
||||
/* Remember process handle */
|
||||
server = server || proc
|
||||
server = proc
|
||||
done()
|
||||
})
|
||||
}
|
||||
|
||||
export const stop = () => {
|
||||
if (server)
|
||||
/**
|
||||
* Stop Selenium
|
||||
*
|
||||
* @param {Function} done - Resolve callback
|
||||
*/
|
||||
export const stop = done => {
|
||||
if (server) {
|
||||
if (typeof done === "function")
|
||||
server.on("exit", done)
|
||||
server.kill()
|
||||
server = null
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Signal handler
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Register signal handler for all relevant events */
|
||||
for (const signal of ["SIGTERM", "SIGINT", "exit"])
|
||||
process.on(signal, stop)
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-invalid-this": 0
|
||||
}
|
||||
}
|
||||
@@ -50,12 +50,13 @@ export default (gulp, config, args) => {
|
||||
],
|
||||
output: {
|
||||
filename: "application.js",
|
||||
library: "Application"
|
||||
library: "app",
|
||||
libraryTarget: "window"
|
||||
},
|
||||
module: {
|
||||
|
||||
/* Transpile ES6 to ES5 with Babel */
|
||||
loaders: [
|
||||
rules: [
|
||||
{
|
||||
loader: "babel-loader",
|
||||
test: /\.jsx?$/
|
||||
@@ -65,7 +66,7 @@ export default (gulp, config, args) => {
|
||||
plugins: [
|
||||
|
||||
/* Don't emit assets that include errors */
|
||||
new webpack.NoErrorsPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
|
||||
/* Provide JSX helper */
|
||||
new webpack.ProvidePlugin({
|
||||
@@ -77,19 +78,30 @@ export default (gulp, config, args) => {
|
||||
args.optimize ? [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
warnings: false
|
||||
warnings: false,
|
||||
screw_ie8: true, // eslint-disable-line camelcase
|
||||
conditionals: true,
|
||||
unused: true,
|
||||
comparisons: true,
|
||||
sequences: true,
|
||||
dead_code: true, // eslint-disable-line camelcase
|
||||
evaluate: true,
|
||||
if_return: true, // eslint-disable-line camelcase
|
||||
join_vars: true // eslint-disable-line camelcase
|
||||
},
|
||||
output: {
|
||||
comments: false
|
||||
}
|
||||
})
|
||||
] : []),
|
||||
|
||||
/* Module resolver */
|
||||
resolve: {
|
||||
modulesDirectories: [
|
||||
modules: [
|
||||
"src/assets/javascripts",
|
||||
"node_modules"
|
||||
],
|
||||
extensions: [
|
||||
"",
|
||||
".js",
|
||||
".jsx"
|
||||
]
|
||||
@@ -101,8 +113,8 @@ export default (gulp, config, args) => {
|
||||
},
|
||||
|
||||
/* Sourcemap support */
|
||||
devtool: args.sourcemaps ? "source-map" : ""
|
||||
}))
|
||||
devtool: args.sourcemaps ? "inline-source-map" : ""
|
||||
}, webpack))
|
||||
|
||||
/* Revisioning */
|
||||
.pipe(gulpif(args.revision, rev()))
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
import path from "path"
|
||||
import through from "through2"
|
||||
import util from "gulp-util"
|
||||
|
||||
import { CLIEngine } from "eslint"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
|
||||
@@ -25,6 +25,7 @@ import gulpif from "gulp-if"
|
||||
import mincss from "gulp-cssnano"
|
||||
import mqpacker from "css-mqpacker"
|
||||
import postcss from "gulp-postcss"
|
||||
import pseudoclasses from "postcss-pseudo-classes"
|
||||
import rev from "gulp-rev"
|
||||
import sass from "gulp-sass"
|
||||
import sourcemaps from "gulp-sourcemaps"
|
||||
@@ -54,7 +55,11 @@ export default (gulp, config, args) => {
|
||||
postcss([
|
||||
autoprefixer(),
|
||||
mqpacker
|
||||
]))
|
||||
].concat(!args.optimize ? [
|
||||
pseudoclasses({
|
||||
"restrictTo": ["hover", "focus"]
|
||||
})
|
||||
] : [])))
|
||||
|
||||
/* Minify sources */
|
||||
.pipe(gulpif(args.optimize, mincss()))
|
||||
@@ -63,7 +68,7 @@ export default (gulp, config, args) => {
|
||||
.pipe(gulpif(args.revision, rev()))
|
||||
.pipe(gulpif(args.revision,
|
||||
version({ manifest: gulp.src("manifest.json") })))
|
||||
.pipe(gulpif(args.sourcemaps, sourcemaps.write(".")))
|
||||
.pipe(gulpif(args.sourcemaps, sourcemaps.write()))
|
||||
.pipe(gulp.dest(`${config.assets.build}/stylesheets`))
|
||||
.pipe(gulpif(args.revision,
|
||||
rev.manifest("manifest.json", {
|
||||
|
||||
@@ -39,7 +39,7 @@ export default () => {
|
||||
server.kill()
|
||||
|
||||
/* Spawn MkDocs server */
|
||||
server = child.spawn("mkdocs", ["serve", "-a", "0.0.0.0:8000"], {
|
||||
server = child.spawn("mkdocs", ["serve", "--dev-addr", "0.0.0.0:8000"], {
|
||||
stdio: "inherit"
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 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 clean from "del"
|
||||
import vinyl from "vinyl-paths"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: clean files generated by visual tests
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config) => {
|
||||
return () => {
|
||||
return gulp.src([
|
||||
`${config.tests.visual}/data`,
|
||||
"./gemini-report"
|
||||
])
|
||||
.pipe(vinyl(clean))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 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 child from "child_process"
|
||||
import path from "path"
|
||||
import through from "through2"
|
||||
import util from "gulp-util"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: generate visual tests
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config) => {
|
||||
const theme = path.resolve(process.cwd(), config.views.build)
|
||||
return () => {
|
||||
return gulp.src(`${config.tests.visual}/suites/**/mkdocs.yml`)
|
||||
.pipe(
|
||||
through.obj(function(file, enc, done) {
|
||||
if (file.isNull() || file.isStream())
|
||||
return done()
|
||||
|
||||
/* Resolve test name and destination */
|
||||
const name = path.relative(`${config.tests.visual}/suites`,
|
||||
path.dirname(file.path))
|
||||
const site = path.resolve(process.cwd(),
|
||||
`${config.tests.visual}/data`, name, "_")
|
||||
|
||||
/* Generate test fixtures with freshly built theme */
|
||||
const proc = child.spawnSync("mkdocs", [
|
||||
"build", "--site-dir", site, "--theme-dir", theme
|
||||
], {
|
||||
cwd: path.dirname(file.path)
|
||||
})
|
||||
|
||||
/* Emit error, if any */
|
||||
if (proc.status)
|
||||
this.emit("error", new util.PluginError("mkdocs",
|
||||
`Terminated with errors: ${proc.stderr.toString()}`))
|
||||
|
||||
/* Terminate */
|
||||
done()
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 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 moniker from "moniker"
|
||||
import path from "path"
|
||||
import * as ecstatic from "~/lib/servers/ecstatic"
|
||||
import * as sauce from "~/lib/servers/sauce-connect"
|
||||
import * as selenium from "~/lib/servers/selenium"
|
||||
|
||||
import Gemini from "gemini"
|
||||
import SauceLabs from "saucelabs"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Locals
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/* SauceLabs job name */
|
||||
const id = process.env.TRAVIS
|
||||
? `Travis #${process.env.TRAVIS_BUILD_NUMBER}`
|
||||
: `Local #${moniker.choose()}`
|
||||
|
||||
/* SauceLabs test results */
|
||||
const passed = {}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: run visual tests
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config, args) => {
|
||||
return done => {
|
||||
|
||||
/* Start static file server */
|
||||
let error = false
|
||||
new Promise(resolve => {
|
||||
ecstatic.start(`${config.tests.visual}/data`, 8000, resolve)
|
||||
|
||||
/* Create and start test runner */
|
||||
}).then(() => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
/* Start SauceConnect tunnel */
|
||||
if (process.env.CI || process.env.SAUCE) {
|
||||
if (!process.env.SAUCE_USERNAME ||
|
||||
!process.env.SAUCE_ACCESS_KEY)
|
||||
throw new Error(
|
||||
"SauceConnect: please provide SAUCE_USERNAME " +
|
||||
"and SAUCE_ACCESS_KEY")
|
||||
|
||||
/* Start tunnel, if credentials are given */
|
||||
sauce.start(
|
||||
id,
|
||||
process.env.SAUCE_USERNAME,
|
||||
process.env.SAUCE_ACCESS_KEY,
|
||||
err => {
|
||||
return err ? reject(err) : resolve(sauce)
|
||||
})
|
||||
|
||||
/* Start Selenium */
|
||||
} else {
|
||||
selenium.start(() => resolve(selenium))
|
||||
}
|
||||
})
|
||||
|
||||
/* Setup and run Gemini */
|
||||
.then(runner => {
|
||||
const setup = require(
|
||||
path.join(process.cwd(), `${config.tests.visual}/config`,
|
||||
process.env.CI || process.env.SAUCE
|
||||
? "gemini.sauce-connect.json"
|
||||
: "gemini.selenium.json"))
|
||||
|
||||
/* Add dynamic configuration to capabilities */
|
||||
for (const key of Object.keys(setup.browsers)) {
|
||||
const caps = setup.browsers[key].desiredCapabilities
|
||||
caps.tunnelIdentifier = id
|
||||
caps.public = "private"
|
||||
caps.name = id
|
||||
|
||||
/* Adjust configuration for Travis CI */
|
||||
if (process.env.CI && process.env.TRAVIS)
|
||||
caps.public = "public"
|
||||
}
|
||||
|
||||
/* Setup Gemini and test listeners */
|
||||
const gemini = new Gemini(setup)
|
||||
if (process.env.CI || process.env.SAUCE) {
|
||||
|
||||
/* Initialize test run */
|
||||
gemini.on(gemini.events.START_BROWSER, job => {
|
||||
passed[job.sessionId] = true
|
||||
})
|
||||
|
||||
/* Update state of test run */
|
||||
gemini.on(gemini.events.TEST_RESULT, job => {
|
||||
passed[job.sessionId] = passed[job.sessionId] && job.equal
|
||||
})
|
||||
}
|
||||
|
||||
/* Run tests */
|
||||
return gemini.test(`${config.tests.visual}/suites`, {
|
||||
reporters: ["flat", "html"],
|
||||
browsers: args.browsers ? [].concat(args.browsers) : null
|
||||
})
|
||||
|
||||
/* Return runner for graceful stop */
|
||||
.then(status => {
|
||||
error = status.failed + status.errored > 0
|
||||
return runner
|
||||
})
|
||||
})
|
||||
|
||||
/* Stop test runner */
|
||||
.then(runner => {
|
||||
return new Promise(resolve => {
|
||||
runner.stop(resolve)
|
||||
})
|
||||
})
|
||||
|
||||
/* Update SauceLabs jobs with test results */
|
||||
.then(() => {
|
||||
const saucelabs = new SauceLabs({
|
||||
username: process.env.SAUCE_USERNAME,
|
||||
password: process.env.SAUCE_ACCESS_KEY
|
||||
})
|
||||
const updates = Object.keys(passed).map(sessionId => {
|
||||
return new Promise(resolve => {
|
||||
saucelabs.updateJob(sessionId, {
|
||||
passed: passed[sessionId]
|
||||
}, resolve)
|
||||
})
|
||||
})
|
||||
return Promise.all(updates)
|
||||
})
|
||||
|
||||
/* Stop static file server */
|
||||
})
|
||||
.then(() => {
|
||||
ecstatic.stop(() => {
|
||||
return error
|
||||
? done(new Error("Gemini terminated with errors"))
|
||||
: done()
|
||||
})
|
||||
}, err => {
|
||||
return done(new Error(err))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 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 moniker from "moniker"
|
||||
import * as ecstatic from "~/lib/servers/ecstatic"
|
||||
import * as sauce from "~/lib/servers/sauce-connect"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: run visual tests
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config) => {
|
||||
return done => {
|
||||
|
||||
/* Start static file server */
|
||||
new Promise(resolve => {
|
||||
ecstatic.start(`${config.tests.visual}/data`, 8000, resolve)
|
||||
|
||||
/* Open SauceConnect tunnel */
|
||||
}).then(() => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
/* Start SauceConnect tunnel */
|
||||
if (process.env.CI || process.env.SAUCE) {
|
||||
if (!process.env.SAUCE_USERNAME ||
|
||||
!process.env.SAUCE_ACCESS_KEY)
|
||||
throw new Error(
|
||||
"SauceConnect: please provide SAUCE_USERNAME " +
|
||||
"and SAUCE_ACCESS_KEY")
|
||||
|
||||
/* Open tunnel */
|
||||
sauce.start(
|
||||
`Local #${moniker.choose()}`,
|
||||
process.env.SAUCE_USERNAME,
|
||||
process.env.SAUCE_ACCESS_KEY,
|
||||
err => {
|
||||
return err ? reject(err) : resolve(sauce)
|
||||
})
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
|
||||
/* Close tunnel on CTRL-C */
|
||||
.then(runner => {
|
||||
return new Promise(resolve => {
|
||||
process.on("SIGINT", () => {
|
||||
return runner
|
||||
? runner.stop(resolve)
|
||||
: resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/* Stop static file server */
|
||||
})
|
||||
.then(() => {
|
||||
ecstatic.stop(done)
|
||||
}, err => {
|
||||
return done(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 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 fs from "fs"
|
||||
import path from "path"
|
||||
import through from "through2"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: update reference images for visual tests
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config) => {
|
||||
return () => {
|
||||
const base = path.join(
|
||||
process.cwd(), `${config.tests.visual}/config`)
|
||||
|
||||
/* Read Gemini configs and map browsers to screenshot directories */
|
||||
const mapping = fs.readdirSync(base)
|
||||
.reduce((result, filename) => {
|
||||
return Object.assign(result, (gemini => {
|
||||
return Object.keys(gemini.browsers)
|
||||
.reduce((browsers, name) => {
|
||||
browsers[name] = gemini.screenshotsDir
|
||||
return browsers
|
||||
}, {})
|
||||
})(require(path.join(base, filename))))
|
||||
}, {})
|
||||
|
||||
/* Prepare filenames */
|
||||
const dest = path.join(process.cwd(), `${config.tests.visual}/baseline`)
|
||||
return gulp.src("gemini-report/images/**/*~current.png")
|
||||
.pipe(
|
||||
through.obj(function(file, enc, done) {
|
||||
if (file.isNull() || file.isStream())
|
||||
return done()
|
||||
|
||||
/* Remove the state from the filename */
|
||||
file.path = file.path.replace("~current", "")
|
||||
|
||||
/* Retrieve the folder for the environment of the baseline */
|
||||
const folder = path.relative(dest,
|
||||
mapping[path.basename(file.path, ".png")])
|
||||
file.path = file.path.replace("images", `images/${folder}`)
|
||||
|
||||
/* Push file to next stage */
|
||||
this.push(file)
|
||||
done()
|
||||
}))
|
||||
|
||||
/* Update reference images */
|
||||
.pipe(gulp.dest(dest))
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
{% else %}
|
||||
<link rel="shortcut icon" href="{{ base_url }}/assets/images/favicon.ico">
|
||||
{% endif %}
|
||||
<meta name="generator" content="mkdocs+mkdocs-material#1.0.1">
|
||||
<meta name="generator" content="mkdocs-{{ mkdocs_version }}, mkdocs-material-1.0.3">
|
||||
{% endblock %}
|
||||
{% block htmltitle %}
|
||||
{% if page.title %}
|
||||
@@ -31,7 +31,13 @@
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block libs %}
|
||||
<script src="{{ base_url }}/assets/javascripts/modernizr-facb31f4a3.js"></script>
|
||||
<script src="{{ base_url }}/assets/javascripts/modernizr-5b0c41c2b5.js"></script>
|
||||
{% endblock %}
|
||||
{% block styles %}
|
||||
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-166740f5bb.css">
|
||||
{% if config.extra.palette %}
|
||||
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-02ce7adcc2.palette.css">
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block fonts %}
|
||||
{% if config.extra.font != "none" %}
|
||||
@@ -44,15 +50,9 @@
|
||||
{% endif %}
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
||||
{% endblock %}
|
||||
{% block styles %}
|
||||
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-1b8b9fdf68.css">
|
||||
{% if config.extra.palette %}
|
||||
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-02ce7adcc2.palette.css">
|
||||
{% endif %}
|
||||
{% for path in extra_css %}
|
||||
<link rel="stylesheet" href="{{ path }}">
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
{% for path in extra_css %}
|
||||
<link rel="stylesheet" href="{{ path }}">
|
||||
{% endfor %}
|
||||
{% block extrahead %}{% endblock %}
|
||||
</head>
|
||||
{% set palette = config.extra.get("palette", {}) %}
|
||||
@@ -110,7 +110,7 @@
|
||||
<a href="{{ page.edit_url }}" title="{{ lang.t('edit.link.title') }}" class="md-icon md-content__edit">edit</a>
|
||||
{% endif %}
|
||||
{% block content %}
|
||||
{% if not "\x3ch1 id=" in page.content %}
|
||||
{% if not "\x3ch1" in page.content %}
|
||||
<h1>{{ page.title | default(config.site_name, true)}}</h1>
|
||||
{% endif %}
|
||||
{{ page.content }}
|
||||
@@ -124,8 +124,8 @@
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% block scripts %}
|
||||
<script src="{{ base_url }}/assets/javascripts/application-16f434a21a.js"></script>
|
||||
<script>var config={url:{base:"{{ base_url }}"}},app=new Application(config);app.initialize()</script>
|
||||
<script src="{{ base_url }}/assets/javascripts/application-39a173f6f5.js"></script>
|
||||
<script>app.initialize({url:{base:"{{ base_url }}"}})</script>
|
||||
{% for path in extra_javascript %}
|
||||
<script src="{{ path }}"></script>
|
||||
{% endfor %}
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
<li class="md-nav__item">
|
||||
{% set toc_ = page.toc %}
|
||||
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
|
||||
{% if "\x3ch1 id=" in page.content %}
|
||||
{% if toc_ | first is defined %}
|
||||
{% set toc_ = (toc_ | first).children %}
|
||||
{% endif %}
|
||||
{% if toc_ and (toc_ | first) %}
|
||||
{% if toc_ | first is defined %}
|
||||
<label class="md-nav__link md-nav__link--active" for="toc">
|
||||
{{ nav_item.title }}
|
||||
</label>
|
||||
@@ -36,7 +36,7 @@
|
||||
<a href="{{ nav_item.url }}" title="{{ nav_item.title }}" class="md-nav__link md-nav__link--active">
|
||||
{{ nav_item.title }}
|
||||
</a>
|
||||
{% if page.toc %}
|
||||
{% if toc_ | first is defined %}
|
||||
{% include "partials/toc.html" %}
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{% import "partials/language.html" as lang %}
|
||||
<nav class="md-nav md-nav--secondary">
|
||||
{% set toc_ = page.toc %}
|
||||
{% if "\x3ch1 id=" in page.content %}
|
||||
{% if toc_ | first is defined and "\x3ch1 id=" in page.content %}
|
||||
{% set toc_ = (toc_ | first).children %}
|
||||
{% endif %}
|
||||
{% if toc_ and (toc_ | first) %}
|
||||
{% if toc_ | first is defined %}
|
||||
<label class="md-nav__title" for="toc">{{ lang.t('toc.title') }}</label>
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
{% for toc_item in toc_ %}
|
||||
|
||||
@@ -31,7 +31,7 @@ repo_url: https://github.com/squidfunk/mkdocs-material
|
||||
# Copyright
|
||||
copyright: 'Copyright © 2016 - 2017 Martin Donath'
|
||||
|
||||
# Documentation and theme
|
||||
# Theme directory
|
||||
theme_dir: material
|
||||
|
||||
# Options
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mkdocs-material",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.4",
|
||||
"description": "A Material Design theme for MkDocs",
|
||||
"keywords": [
|
||||
"mkdocs",
|
||||
@@ -27,26 +27,28 @@
|
||||
"clean": "scripts/clean",
|
||||
"lint": "scripts/lint",
|
||||
"start": "scripts/start",
|
||||
"test": "scripts/test"
|
||||
"test:visual:run": "scripts/test/visual/run",
|
||||
"test:visual:update": "scripts/test/visual/update",
|
||||
"test:visual:session": "scripts/test/visual/session"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^6.6.1",
|
||||
"autoprefixer": "^6.7.3",
|
||||
"babel-core": "^6.0.0",
|
||||
"babel-eslint": "^7.1.1",
|
||||
"babel-loader": "^6.2.10",
|
||||
"babel-loader": "^6.3.1",
|
||||
"babel-plugin-add-module-exports": "^0.2.1",
|
||||
"babel-plugin-transform-react-jsx": "^6.8.0",
|
||||
"babel-polyfill": "^6.20.0",
|
||||
"babel-preset-es2015": "^6.18.0",
|
||||
"babel-register": "^6.18.0",
|
||||
"babel-preset-es2015": "^6.22.0",
|
||||
"babel-register": "^6.23.0",
|
||||
"babel-root-import": "^4.1.5",
|
||||
"chai": "^3.5.0",
|
||||
"core-js": "^2.4.1",
|
||||
"css-mqpacker": "^5.0.1",
|
||||
"custom-event-polyfill": "^0.3.0",
|
||||
"del": "^2.2.2",
|
||||
"eslint": "^3.13.1",
|
||||
"eslint-plugin-mocha": "^4.8.0",
|
||||
"ecstatic": "^2.1.0",
|
||||
"eslint": "^3.14.0",
|
||||
"fastclick": "^1.0.6",
|
||||
"git-hooks": "^1.1.7",
|
||||
"gulp": "^3.9.1",
|
||||
@@ -70,6 +72,27 @@
|
||||
"gulp-uglify": "^2.0.0",
|
||||
"gulp-util": "^3.0.8",
|
||||
"js-cookie": "^2.1.3",
|
||||
"lunr": "^0.7.2",
|
||||
"material-design-color": "^2.3.2",
|
||||
"material-shadows": "^3.0.1",
|
||||
"modularscale-sass": "^2.1.1",
|
||||
"node-notifier": "^5.0.0",
|
||||
"postcss-pseudo-classes": "^0.2.0",
|
||||
"stylelint": "^7.8.0",
|
||||
"stylelint-config-standard": "^16.0.0",
|
||||
"stylelint-order": "^0.2.2",
|
||||
"stylelint-scss": "^1.4.1",
|
||||
"through2": "^2.0.3",
|
||||
"vinyl-paths": "^2.1.0",
|
||||
"webpack": "^2.2.1",
|
||||
"webpack-stream": "^3.2.0",
|
||||
"whatwg-fetch": "^2.0.1",
|
||||
"yargs": "^6.6.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"chai": "^3.5.0",
|
||||
"eslint-plugin-mocha": "^4.8.0",
|
||||
"gemini": "^4.14.3",
|
||||
"karma": "^1.3.0",
|
||||
"karma-chrome-launcher": "^2.0.0",
|
||||
"karma-coverage": "^1.1.1",
|
||||
@@ -78,26 +101,14 @@
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-spec-reporter": "0.0.26",
|
||||
"karma-webpack": "^2.0.1",
|
||||
"lunr": "^0.7.2",
|
||||
"material-design-color": "^2.3.2",
|
||||
"material-shadows": "^3.0.1",
|
||||
"mocha": "^3.2.0",
|
||||
"modularscale-sass": "^2.1.1",
|
||||
"node-notifier": "^4.6.1",
|
||||
"selenium-standalone": "^5.9.1",
|
||||
"stylelint": "^7.7.1",
|
||||
"stylelint-config-standard": "^15.0.1",
|
||||
"stylelint-order": "^0.2.2",
|
||||
"stylelint-scss": "^1.4.1",
|
||||
"through2": "^2.0.3",
|
||||
"vinyl-paths": "^2.1.0",
|
||||
"webpack": "^1.14.0",
|
||||
"webpack-stream": "^3.2.0",
|
||||
"whatwg-fetch": "^2.0.1",
|
||||
"yargs": "^6.6.0"
|
||||
"moniker": "^0.1.2",
|
||||
"saucelabs": "^1.4.0",
|
||||
"sauce-connect-launcher": "^1.2.0",
|
||||
"selenium-standalone": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.5.0"
|
||||
"node": ">= 5.0.0"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -20,4 +20,4 @@
|
||||
|
||||
mkdocs>=0.16
|
||||
pygments
|
||||
pymdown-extensions
|
||||
pymdown-extensions>=1.2
|
||||
|
||||
@@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then
|
||||
fi
|
||||
|
||||
# Run command
|
||||
`npm bin`/gulp build --clean --optimize --revision
|
||||
`npm bin`/gulp build --clean --optimize --revision "$@"
|
||||
|
||||
@@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then
|
||||
fi
|
||||
|
||||
# Run command
|
||||
`npm bin`/gulp clean
|
||||
`npm bin`/gulp clean "$@"
|
||||
|
||||
@@ -28,7 +28,7 @@ if [[ ! -d `npm bin` ]]; then
|
||||
fi
|
||||
|
||||
# Run ESLint
|
||||
`npm bin`/eslint .
|
||||
`npm bin`/eslint --max-warnings 0 .
|
||||
ESLINT=$?
|
||||
|
||||
# Run Stylelint
|
||||
|
||||
@@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then
|
||||
fi
|
||||
|
||||
# Run command
|
||||
`npm bin`/gulp watch --no-lint
|
||||
`npm bin`/gulp watch --no-lint "$@"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2016-2017 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.
|
||||
|
||||
# Check if "npm install" was executed
|
||||
if [[ ! -d `npm bin` ]]; then
|
||||
echo "\"node_modules\" not found:"
|
||||
echo "npm install"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run command
|
||||
`npm bin`/gulp tests:visual:run --clean --no-optimize "$@"
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2016-2017 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.
|
||||
|
||||
# Check if "npm install" was executed
|
||||
if [[ ! -d `npm bin` ]]; then
|
||||
echo "\"node_modules\" not found:"
|
||||
echo "npm install"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run command
|
||||
`npm bin`/gulp tests:visual:session "$@"
|
||||
@@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then
|
||||
fi
|
||||
|
||||
# Run command
|
||||
`npm bin`/gulp test
|
||||
`npm bin`/gulp tests:visual:update "$@"
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"presets": [
|
||||
["es2015", { "modules": false }]
|
||||
],
|
||||
"plugins": [
|
||||
["transform-react-jsx", {
|
||||
"pragma": "JSX.createElement"
|
||||
}]
|
||||
]
|
||||
}
|
||||
@@ -27,215 +27,199 @@ import Material from "./components/Material"
|
||||
* Application
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default class Application {
|
||||
export const initialize = config => {
|
||||
|
||||
/**
|
||||
* Create the application
|
||||
*
|
||||
* @constructor
|
||||
* @param {object} config Configuration object
|
||||
*/
|
||||
constructor(config) {
|
||||
this.config_ = config
|
||||
}
|
||||
/* Initialize Modernizr and FastClick */
|
||||
new Material.Event.Listener(document, "DOMContentLoaded", () => {
|
||||
|
||||
/**
|
||||
* Initialize all components and listeners
|
||||
*/
|
||||
initialize() {
|
||||
/* Test for iOS */
|
||||
Modernizr.addTest("ios", () => {
|
||||
return !!navigator.userAgent.match(/(iPad|iPhone|iPod)/g)
|
||||
})
|
||||
|
||||
/* Initialize Modernizr and FastClick */
|
||||
new Material.Event.Listener(document, "DOMContentLoaded", () => {
|
||||
/* Test for web application context */
|
||||
Modernizr.addTest("standalone", () => {
|
||||
return !!navigator.standalone
|
||||
})
|
||||
|
||||
/* Test for iOS */
|
||||
Modernizr.addTest("ios", () => {
|
||||
return !!navigator.userAgent.match(/(iPad|iPhone|iPod)/g)
|
||||
})
|
||||
/* Attach FastClick to mitigate 300ms delay on touch devices */
|
||||
FastClick.attach(document.body)
|
||||
|
||||
/* Test for web application context */
|
||||
Modernizr.addTest("standalone", () => {
|
||||
return !!navigator.standalone
|
||||
})
|
||||
/* Wrap all data tables for better overflow scrolling */
|
||||
const tables = document.querySelectorAll("table:not([class])")
|
||||
Array.prototype.forEach.call(tables, table => {
|
||||
const wrap = document.createElement("div")
|
||||
wrap.classList.add("md-typeset__table")
|
||||
if (table.nextSibling) {
|
||||
table.parentNode.insertBefore(wrap, table.nextSibling)
|
||||
} else {
|
||||
table.parentNode.appendChild(wrap)
|
||||
}
|
||||
wrap.appendChild(table)
|
||||
})
|
||||
|
||||
/* Attack FastClick to mitigate 300ms delay on touch devices */
|
||||
FastClick.attach(document.body)
|
||||
/* Force 1px scroll offset to trigger overflow scrolling */
|
||||
if (Modernizr.ios) {
|
||||
const scrollable = document.querySelectorAll("[data-md-scrollfix]")
|
||||
Array.prototype.forEach.call(scrollable, item => {
|
||||
item.addEventListener("touchstart", () => {
|
||||
const top = item.scrollTop
|
||||
|
||||
/* Wrap all data tables for better overflow scrolling */
|
||||
const tables = document.querySelectorAll("table:not([class])")
|
||||
Array.prototype.forEach.call(tables, table => {
|
||||
const wrap = document.createElement("div")
|
||||
wrap.classList.add("md-typeset__table")
|
||||
if (table.nextSibling) {
|
||||
table.parentNode.insertBefore(wrap, table.nextSibling)
|
||||
} else {
|
||||
table.parentNode.appendChild(wrap)
|
||||
}
|
||||
wrap.appendChild(table)
|
||||
})
|
||||
|
||||
/* Force 1px scroll offset to trigger overflow scrolling */
|
||||
if (Modernizr.ios) {
|
||||
const scrollable = document.querySelectorAll("[data-md-scrollfix]")
|
||||
Array.prototype.forEach.call(scrollable, item => {
|
||||
item.addEventListener("touchstart", () => {
|
||||
const top = item.scrollTop
|
||||
|
||||
/* We're at the top of the container */
|
||||
if (top === 0) {
|
||||
item.scrollTop = 1
|
||||
/* We're at the top of the container */
|
||||
if (top === 0) {
|
||||
item.scrollTop = 1
|
||||
|
||||
/* We're at the bottom of the container */
|
||||
} else if (top + item.offsetHeight === item.scrollHeight) {
|
||||
item.scrollTop = top - 1
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}).listen()
|
||||
|
||||
/* Component: sidebar container */
|
||||
if (!Modernizr.csscalc)
|
||||
new Material.Event.MatchMedia("(min-width: 960px)",
|
||||
new Material.Event.Listener(window, [
|
||||
"resize", "orientationchange"
|
||||
], new Material.Sidebar.Container("[data-md-component=container]")))
|
||||
|
||||
/* Component: sidebar with navigation */
|
||||
new Material.Event.MatchMedia("(min-width: 1220px)",
|
||||
new Material.Event.Listener(window, [
|
||||
"scroll", "resize", "orientationchange"
|
||||
], new Material.Sidebar.Position("[data-md-component=navigation]")))
|
||||
|
||||
/* Component: sidebar with table of contents */
|
||||
new Material.Event.MatchMedia("(min-width: 960px)",
|
||||
new Material.Event.Listener(window, [
|
||||
"scroll", "resize", "orientationchange"
|
||||
], new Material.Sidebar.Position("[data-md-component=toc]")))
|
||||
|
||||
/* Component: link blurring for table of contents */
|
||||
new Material.Event.MatchMedia("(min-width: 960px)",
|
||||
new Material.Event.Listener(window, "scroll",
|
||||
new Material.Nav.Blur("[data-md-component=toc] .md-nav__link")))
|
||||
|
||||
/* Component: collapsible elements for navigation */
|
||||
const collapsibles =
|
||||
document.querySelectorAll("[data-md-component=collapsible]")
|
||||
Array.prototype.forEach.call(collapsibles, collapse => {
|
||||
new Material.Event.MatchMedia("(min-width: 1220px)",
|
||||
new Material.Event.Listener(collapse.previousElementSibling, "click",
|
||||
new Material.Nav.Collapse(collapse)))
|
||||
})
|
||||
|
||||
/* Component: active pane monitor for iOS scrolling fixes */
|
||||
new Material.Event.MatchMedia("(max-width: 1219px)",
|
||||
new Material.Event.Listener(
|
||||
"[data-md-component=navigation] [data-md-toggle]", "change",
|
||||
new Material.Nav.Scrolling("[data-md-component=navigation] nav")))
|
||||
|
||||
/* 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-component=result]", () => {
|
||||
return fetch(`${this.config_.url.base}/mkdocs/search_index.json`, {
|
||||
credentials: "same-origin"
|
||||
}).then(response => response.json())
|
||||
.then(data => {
|
||||
return data.docs.map(doc => {
|
||||
doc.location = this.config_.url.base + doc.location
|
||||
return doc
|
||||
})
|
||||
})
|
||||
})).listen()
|
||||
|
||||
/* Listener: prevent touches on overlay if navigation is active */
|
||||
new Material.Event.MatchMedia("(max-width: 1219px)",
|
||||
new Material.Event.Listener("[data-md-component=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-component=navigation] [href^='#']",
|
||||
"click", () => {
|
||||
const toggle = document.querySelector("[data-md-toggle=drawer]")
|
||||
if (toggle.checked) {
|
||||
toggle.checked = false
|
||||
toggle.dispatchEvent(new CustomEvent("change"))
|
||||
} else if (top + item.offsetHeight === item.scrollHeight) {
|
||||
item.scrollTop = top - 1
|
||||
}
|
||||
}))
|
||||
|
||||
/* Listener: focus input after opening 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: open 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
|
||||
toggle.dispatchEvent(new CustomEvent("change"))
|
||||
}
|
||||
}))
|
||||
|
||||
/* Listener: close search when clicking outside */
|
||||
new Material.Event.MatchMedia("(min-width: 960px)",
|
||||
new Material.Event.Listener(document.body, "click", () => {
|
||||
const toggle = document.querySelector("[data-md-toggle=search]")
|
||||
if (toggle.checked) {
|
||||
toggle.checked = false
|
||||
toggle.dispatchEvent(new CustomEvent("change"))
|
||||
}
|
||||
}))
|
||||
|
||||
/* Listener: disable search when ESC key is pressed */
|
||||
new Material.Event.Listener(window, "keyup", ev => {
|
||||
const code = ev.keyCode || ev.which
|
||||
if (code === 27) {
|
||||
const toggle = document.querySelector("[data-md-toggle=search]")
|
||||
if (toggle.checked) {
|
||||
toggle.checked = false
|
||||
toggle.dispatchEvent(new CustomEvent("change"))
|
||||
document.forms.search.query.blur()
|
||||
}
|
||||
}
|
||||
}).listen()
|
||||
|
||||
/* Listener: fix unclickable toggle due to blur handler */
|
||||
new Material.Event.MatchMedia("(min-width: 960px)",
|
||||
new Material.Event.Listener("[data-md-toggle=search]", "click",
|
||||
ev => ev.stopPropagation()))
|
||||
|
||||
/* Listener: prevent search from closing when clicking */
|
||||
new Material.Event.MatchMedia("(min-width: 960px)",
|
||||
new Material.Event.Listener("[data-md-component=search]", "click",
|
||||
ev => ev.stopPropagation()))
|
||||
|
||||
/* Retrieve facts for the given repository type */
|
||||
;(() => {
|
||||
const el = document.querySelector("[data-md-source]")
|
||||
if (!el) return Promise.resolve([])
|
||||
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]")
|
||||
Array.prototype.forEach.call(sources, source => {
|
||||
new Material.Source.Repository(source)
|
||||
.initialize(facts)
|
||||
})
|
||||
})
|
||||
}
|
||||
}).listen()
|
||||
|
||||
/* Component: sidebar container */
|
||||
if (!Modernizr.csscalc)
|
||||
new Material.Event.MatchMedia("(min-width: 960px)",
|
||||
new Material.Event.Listener(window, [
|
||||
"resize", "orientationchange"
|
||||
], new Material.Sidebar.Container("[data-md-component=container]")))
|
||||
|
||||
/* Component: sidebar with navigation */
|
||||
new Material.Event.MatchMedia("(min-width: 1220px)",
|
||||
new Material.Event.Listener(window, [
|
||||
"scroll", "resize", "orientationchange"
|
||||
], new Material.Sidebar.Position("[data-md-component=navigation]")))
|
||||
|
||||
/* Component: sidebar with table of contents */
|
||||
new Material.Event.MatchMedia("(min-width: 960px)",
|
||||
new Material.Event.Listener(window, [
|
||||
"scroll", "resize", "orientationchange"
|
||||
], new Material.Sidebar.Position("[data-md-component=toc]")))
|
||||
|
||||
/* Component: link blurring for table of contents */
|
||||
new Material.Event.MatchMedia("(min-width: 960px)",
|
||||
new Material.Event.Listener(window, "scroll",
|
||||
new Material.Nav.Blur("[data-md-component=toc] .md-nav__link")))
|
||||
|
||||
/* Component: collapsible elements for navigation */
|
||||
const collapsibles =
|
||||
document.querySelectorAll("[data-md-component=collapsible]")
|
||||
Array.prototype.forEach.call(collapsibles, collapse => {
|
||||
new Material.Event.MatchMedia("(min-width: 1220px)",
|
||||
new Material.Event.Listener(collapse.previousElementSibling, "click",
|
||||
new Material.Nav.Collapse(collapse)))
|
||||
})
|
||||
|
||||
/* Component: active pane monitor for iOS scrolling fixes */
|
||||
new Material.Event.MatchMedia("(max-width: 1219px)",
|
||||
new Material.Event.Listener(
|
||||
"[data-md-component=navigation] [data-md-toggle]", "change",
|
||||
new Material.Nav.Scrolling("[data-md-component=navigation] nav")))
|
||||
|
||||
/* 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-component=result]", () => {
|
||||
return fetch(`${config.url.base}/mkdocs/search_index.json`, {
|
||||
credentials: "same-origin"
|
||||
}).then(response => response.json())
|
||||
.then(data => {
|
||||
return data.docs.map(doc => {
|
||||
doc.location = config.url.base + doc.location
|
||||
return doc
|
||||
})
|
||||
})
|
||||
})).listen()
|
||||
|
||||
/* Listener: prevent touches on overlay if navigation is active */
|
||||
new Material.Event.MatchMedia("(max-width: 1219px)",
|
||||
new Material.Event.Listener("[data-md-component=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-component=navigation] [href^='#']",
|
||||
"click", () => {
|
||||
const toggle = document.querySelector("[data-md-toggle=drawer]")
|
||||
if (toggle.checked) {
|
||||
toggle.checked = false
|
||||
toggle.dispatchEvent(new CustomEvent("change"))
|
||||
}
|
||||
}))
|
||||
|
||||
/* Listener: focus input after opening 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: open 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
|
||||
toggle.dispatchEvent(new CustomEvent("change"))
|
||||
}
|
||||
}))
|
||||
|
||||
/* Listener: close search when clicking outside */
|
||||
new Material.Event.MatchMedia("(min-width: 960px)",
|
||||
new Material.Event.Listener(document.body, "click", () => {
|
||||
const toggle = document.querySelector("[data-md-toggle=search]")
|
||||
if (toggle.checked) {
|
||||
toggle.checked = false
|
||||
toggle.dispatchEvent(new CustomEvent("change"))
|
||||
}
|
||||
}))
|
||||
|
||||
/* Listener: disable search when ESC key is pressed */
|
||||
new Material.Event.Listener(window, "keyup", ev => {
|
||||
const code = ev.keyCode || ev.which
|
||||
if (code === 27) {
|
||||
const toggle = document.querySelector("[data-md-toggle=search]")
|
||||
if (toggle.checked) {
|
||||
toggle.checked = false
|
||||
toggle.dispatchEvent(new CustomEvent("change"))
|
||||
document.forms.search.query.blur()
|
||||
}
|
||||
}
|
||||
}).listen()
|
||||
|
||||
/* Listener: fix unclickable toggle due to blur handler */
|
||||
new Material.Event.MatchMedia("(min-width: 960px)",
|
||||
new Material.Event.Listener("[data-md-toggle=search]", "click",
|
||||
ev => ev.stopPropagation()))
|
||||
|
||||
/* Listener: prevent search from closing when clicking */
|
||||
new Material.Event.MatchMedia("(min-width: 960px)",
|
||||
new Material.Event.Listener("[data-md-component=search]", "click",
|
||||
ev => ev.stopPropagation()))
|
||||
|
||||
/* Retrieve facts for the given repository type */
|
||||
;(() => {
|
||||
const el = document.querySelector("[data-md-source]")
|
||||
if (!el) return Promise.resolve([])
|
||||
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]")
|
||||
Array.prototype.forEach.call(sources, source => {
|
||||
new Material.Source.Repository(source)
|
||||
.initialize(facts)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@ export default class Blur {
|
||||
this.index_ = 0
|
||||
this.offset_ = window.pageYOffset
|
||||
|
||||
/* Necessary state to correctly reset the index */
|
||||
this.dir_ = false
|
||||
|
||||
/* Index anchor node offsets for fast lookup */
|
||||
this.anchors_ = [].map.call(this.els_, el => {
|
||||
return document.getElementById(el.hash.substring(1))
|
||||
@@ -62,6 +65,14 @@ export default class Blur {
|
||||
*/
|
||||
update() {
|
||||
const offset = window.pageYOffset
|
||||
const dir = this.offset_ - offset < 0
|
||||
|
||||
/* Hack: reset index if direction changed, to catch very fast scrolling,
|
||||
because otherwise we would have to register a timer and that sucks */
|
||||
if (this.dir_ !== dir)
|
||||
this.index_ = dir
|
||||
? this.index_ = 0
|
||||
: this.index_ = this.els_.length - 1
|
||||
|
||||
/* Exit when there are no anchors */
|
||||
if (this.anchors_.length === 0)
|
||||
@@ -92,8 +103,9 @@ export default class Blur {
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember current offset for next iteration */
|
||||
/* Remember current offset and direction for next iteration */
|
||||
this.offset_ = offset
|
||||
this.dir_ = dir
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,14 +34,9 @@ body {
|
||||
body,
|
||||
input {
|
||||
color: $md-color-black;
|
||||
// font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-feature-settings: "kern", "onum", "liga";
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-weight: 400;
|
||||
|
||||
// Use system fonts, if browser doesn't support webfonts
|
||||
.no-fontface & {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
}
|
||||
|
||||
// Proportionally spaced fonts
|
||||
@@ -49,14 +44,9 @@ pre,
|
||||
code,
|
||||
kbd {
|
||||
color: $md-color-black;
|
||||
// font-family: "Roboto Mono", "Courier New", Courier, monospace;
|
||||
font-feature-settings: "kern", "onum", "liga";
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-weight: 400;
|
||||
|
||||
// Use system fonts, if browser doesn't support webfonts
|
||||
.no-fontface & {
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -80,18 +80,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Hide anchor for top-level heading, as it makes no sense
|
||||
h1[id] .headerlink {
|
||||
display: none;
|
||||
// Correct headline offset with padding due to margin layering
|
||||
h1[id] {
|
||||
padding-top: 0.8rem;
|
||||
|
||||
// Hide anchor for top-level heading, as it makes no sense
|
||||
&.headerlink {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Correct anchor offset for link blurring
|
||||
@each $level, $delta in (
|
||||
h2: 0.2rem,
|
||||
h3: 0.4rem,
|
||||
h4: 0.6rem,
|
||||
h5: 1rem,
|
||||
h6: 1rem
|
||||
h2: 0.4rem,
|
||||
h3: 0.7rem,
|
||||
h4: 0.8rem,
|
||||
h5: 1.1rem,
|
||||
h6: 1.1rem
|
||||
) {
|
||||
|
||||
// Un-targeted anchor
|
||||
|
||||
@@ -50,8 +50,8 @@
|
||||
padding-bottom: 0.8rem;
|
||||
transition: opacity 0.25s;
|
||||
|
||||
// [mobile landscape +]: Set proportional width
|
||||
@include break-from-device(mobile landscape) {
|
||||
// [tablet +]: Set proportional width
|
||||
@include break-from-device(tablet) {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@
|
||||
// Title
|
||||
.md-footer-nav__title {
|
||||
|
||||
// [mobile portrait -]: Hide title for previous page
|
||||
@include break-to-device(mobile portrait) {
|
||||
// [mobile -]: Hide title for previous page
|
||||
@include break-to-device(mobile) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
// Navigation container
|
||||
.md-nav {
|
||||
font-size: ms(-1);
|
||||
font-size: 1.4rem;
|
||||
line-height: 1.3;
|
||||
|
||||
// Table of contents
|
||||
@@ -84,7 +84,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Icon buttons
|
||||
// Button with logo
|
||||
&__button {
|
||||
@extend %md-icon, %md-icon__button;
|
||||
|
||||
@@ -129,18 +129,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Blurred item
|
||||
// Blurred link
|
||||
&[data-md-state="blur"] {
|
||||
color: $md-color-black--light;
|
||||
}
|
||||
|
||||
// Active item
|
||||
// Active link
|
||||
&:active,
|
||||
&--active {
|
||||
color: $md-color-primary;
|
||||
}
|
||||
|
||||
// Hovered item
|
||||
// Focused or hovered link
|
||||
&:focus,
|
||||
&:hover {
|
||||
color: $md-color-accent;
|
||||
}
|
||||
@@ -153,6 +154,7 @@
|
||||
|
||||
// [tablet -]: Layered navigation
|
||||
@include break-to-device(tablet) {
|
||||
background-color: $md-color-white;
|
||||
|
||||
// Stretch primary navigation to drawer
|
||||
&--primary,
|
||||
@@ -169,13 +171,12 @@
|
||||
|
||||
// Adjust styles for primary navigation
|
||||
&--primary {
|
||||
background-color: $md-color-white;
|
||||
|
||||
// Move subsequent navigations off
|
||||
.md-nav__toggle ~ .md-nav {
|
||||
@include z-depth(4);
|
||||
|
||||
background-color: $md-color-white;
|
||||
// List title and item
|
||||
.md-nav__title,
|
||||
.md-nav__item {
|
||||
font-size: 1.6rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
// List title - higher specificity is necessary to ensure that the title
|
||||
@@ -294,7 +295,8 @@
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
|
||||
// Color of icon should inherit link color on hover
|
||||
// Color of icon should inherit link color on focus or hover
|
||||
&:focus::after,
|
||||
&:hover::after {
|
||||
color: inherit;
|
||||
}
|
||||
@@ -354,13 +356,6 @@
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// List item
|
||||
.md-nav__title,
|
||||
.md-nav__item {
|
||||
font-size: 1.6rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
// [tablet portrait -]: Show table of contents in drawer
|
||||
|
||||
@@ -265,14 +265,14 @@
|
||||
|
||||
// [tablet landscape +]: Header-embedded search
|
||||
@include break-from-device(tablet landscape) {
|
||||
@include z-depth(6);
|
||||
|
||||
top: 4rem;
|
||||
transition: opacity 0.4s;
|
||||
opacity: 0;
|
||||
|
||||
// Show search output in active state
|
||||
[data-md-toggle="search"]:checked ~ .md-header & {
|
||||
@include z-depth(6);
|
||||
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
.md-sidebar {
|
||||
position: relative;
|
||||
width: 24.2rem;
|
||||
padding: 2.4rem 0;
|
||||
float: left;
|
||||
overflow: visible;
|
||||
|
||||
@@ -108,27 +109,24 @@
|
||||
|
||||
// Wrapper for scrolling on overflow
|
||||
&__scrollwrap {
|
||||
margin: 2.4rem 0.4rem;
|
||||
max-height: 100%;
|
||||
margin: 0 0.4rem;
|
||||
overflow-y: auto;
|
||||
|
||||
// [tablet -]: Adjust margins
|
||||
@include break-to-device(tablet) {
|
||||
|
||||
// Adjust margins for primary scrollbar
|
||||
// Stretch scrollwrap for primary sidebar
|
||||
.md-sidebar--primary & {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Limit height to window, if JavaScript is available
|
||||
.js & {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
// Override native scrollbar styles
|
||||
&::-webkit-scrollbar {
|
||||
width: 0.4rem;
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
{% endif %}
|
||||
|
||||
<!-- Generator banner -->
|
||||
<meta name="generator" content="mkdocs+$theme-name$#$theme-version$" />
|
||||
<meta name="generator"
|
||||
content="mkdocs-{{ mkdocs_version }}, $theme-name$-$theme-version$" />
|
||||
{% endblock %}
|
||||
|
||||
<!-- Block: site title -->
|
||||
@@ -75,6 +76,20 @@
|
||||
<script src="{{ base_url }}/assets/javascripts/modernizr.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
<!-- Block: stylesheets -->
|
||||
{% block styles %}
|
||||
|
||||
<!-- Theme-related stylesheets -->
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="{{ base_url }}/assets/stylesheets/application.css" />
|
||||
|
||||
<!-- Extra color palette -->
|
||||
{% if config.extra.palette %}
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="{{ base_url }}/assets/stylesheets/application.palette.css" />
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
<!-- Block: webfonts -->
|
||||
{% block fonts %}
|
||||
{% if config.extra.font != "none" %}
|
||||
@@ -101,24 +116,10 @@
|
||||
href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
||||
{% endblock %}
|
||||
|
||||
<!-- Block: stylesheets -->
|
||||
{% block styles %}
|
||||
|
||||
<!-- Theme-related stylesheets -->
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="{{ base_url }}/assets/stylesheets/application.css" />
|
||||
|
||||
<!-- Extra color palette -->
|
||||
{% if config.extra.palette %}
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="{{ base_url }}/assets/stylesheets/application.palette.css" />
|
||||
{% endif %}
|
||||
|
||||
<!-- Custom stylesheets -->
|
||||
{% for path in extra_css %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ path }}" />
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
<!-- Custom stylesheets -->
|
||||
{% for path in extra_css %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ path }}" />
|
||||
{% endfor %}
|
||||
|
||||
<!-- Block: custom front matter -->
|
||||
{% block extrahead %}{% endblock %}
|
||||
@@ -218,11 +219,11 @@
|
||||
{% block content %}
|
||||
|
||||
<!--
|
||||
This is a nasty hack that checks whether the content contains
|
||||
a h1 headline. If it doesn't, the page title (or respectively
|
||||
site name) is used as the main headline.
|
||||
Hack: check whether the content contains a h1 headline. If it
|
||||
doesn't, the page title (or respectively site name) is used
|
||||
as the main headline.
|
||||
-->
|
||||
{% if not "\x3ch1 id=" in page.content %}
|
||||
{% if not "\x3ch1" in page.content %}
|
||||
<h1>{{ page.title | default(config.site_name, true)}}</h1>
|
||||
{% endif %}
|
||||
|
||||
@@ -244,17 +245,7 @@
|
||||
{% block scripts %}
|
||||
<script src="{{ base_url }}/assets/javascripts/application.js"></script>
|
||||
<script>
|
||||
|
||||
/* Configuration for application */
|
||||
var config = {
|
||||
url: {
|
||||
base: "{{ base_url }}",
|
||||
}
|
||||
};
|
||||
|
||||
/* Initialize application */
|
||||
var app = new Application(config);
|
||||
app.initialize();
|
||||
app.initialize({ url: { base: "{{ base_url }}", } });
|
||||
</script>
|
||||
{% for path in extra_javascript %}
|
||||
<script src="{{ path }}"></script>
|
||||
|
||||
@@ -62,13 +62,13 @@
|
||||
<input class="md-toggle md-nav__toggle" data-md-toggle="toc"
|
||||
type="checkbox" id="toc" />
|
||||
|
||||
<!-- Nasty hack - see partials/toc.html for more information -->
|
||||
{% if "\x3ch1 id=" in page.content %}
|
||||
<!-- Hack: see partials/toc.html for more information -->
|
||||
{% if toc_ | first is defined %}
|
||||
{% set toc_ = (toc_ | first).children %}
|
||||
{% endif %}
|
||||
|
||||
<!-- Render table of contents, if not empty -->
|
||||
{% if toc_ and (toc_ | first) %}
|
||||
{% if toc_ | first is defined %}
|
||||
<label class="md-nav__link md-nav__link--active" for="toc">
|
||||
{{ nav_item.title }}
|
||||
</label>
|
||||
@@ -79,7 +79,7 @@
|
||||
</a>
|
||||
|
||||
<!-- Show table of contents -->
|
||||
{% if page.toc %}
|
||||
{% if toc_ | first is defined %}
|
||||
{% include "partials/toc.html" %}
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
@@ -27,17 +27,17 @@
|
||||
{% set toc_ = page.toc %}
|
||||
|
||||
<!--
|
||||
This is a nasty hack that checks whether the content contains a h1
|
||||
headline. If it does, the top-level anchor must be skipped, since it would
|
||||
be redundant to the link to the current page that is located just above the
|
||||
anchor. Therefore we directly continue with the children of the anchor.
|
||||
Hack: check whether the content contains a h1 headline. If it does, the
|
||||
top-level anchor must be skipped, since it would be redundant to the link
|
||||
to the current page that is located just above the anchor. Therefore we
|
||||
directly continue with the children of the anchor.
|
||||
-->
|
||||
{% if "\x3ch1 id=" in page.content %}
|
||||
{% if toc_ | first is defined and "\x3ch1 id=" in page.content %}
|
||||
{% set toc_ = (toc_ | first).children %}
|
||||
{% endif %}
|
||||
|
||||
<!-- Render item list -->
|
||||
{% if toc_ and (toc_ | first) %}
|
||||
{% if toc_ | first is defined %}
|
||||
<label class="md-nav__title" for="toc">{{ lang.t('toc.title') }}</label>
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
{% for toc_item in toc_ %}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"globals": {
|
||||
"gemini": true
|
||||
},
|
||||
"rules": {
|
||||
"no-loop-func": 0
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 5.0 KiB |