Compare commits

..
121 Commits
Author SHA1 Message Date
squidfunk 8f5aa8ad5f Prepare 1.0.4 release 2017-02-16 23:19:32 +01:00
squidfunk 4927e57c88 Fixed source build for pypi 2017-02-16 23:01:59 +01:00
greenkeeper[bot] 9b471c682f chore(package): update postcss-pseudo-classes to version 0.2.0
https://greenkeeper.io/
2017-02-16 10:06:34 +01:00
squidfunk 18262ce8d2 Disable visual regression tests until less flaky 2017-02-16 09:59:27 +01:00
greenkeeper[bot] 769727e886 chore(package): update autoprefixer to version 6.7.3
https://greenkeeper.io/
2017-02-16 09:59:27 +01:00
greenkeeper[bot] 99bc558d5c chore(package): update babel-loader to version 6.3.1
https://greenkeeper.io/
2017-02-16 09:59:27 +01:00
greenkeeper[bot] b33a92e37b chore(package): update babel-register to version 6.23.0
https://greenkeeper.io/
2017-02-16 09:59:27 +01:00
Martin Donath eadce61e75 Merge pull request #151 from squidfunk/test/missing-navigation-testcases
Added missing navigation testcases
2017-02-12 19:11:29 +01:00
squidfunk 13ab32f631 Updated failing admonition tests 2017-02-12 18:57:55 +01:00
squidfunk e483055e17 Fixed build errors 2017-02-12 18:44:44 +01:00
squidfunk c890255c39 Merge branch 'master' into test/missing-navigation-testcases 2017-02-12 18:36:35 +01:00
squidfunk 5e5b680fa0 Added final tests for navigation 2017-02-12 18:31:05 +01:00
squidfunk 0975c7d1be Added further tests for navigation 2017-02-12 17:10:05 +01:00
squidfunk 31836391e1 Added further tests for navigation 2017-02-12 16:53:04 +01:00
squidfunk c9a7019333 Added SauceLabs test results integration 2017-02-11 21:34:16 +01:00
squidfunk b6b5904a7a Restructure package.json to separate test deps from dev deps 2017-02-11 16:26:23 +01:00
squidfunk 80fe7e010d Migrate build pipeline to Webpack 2 2017-02-11 16:26:23 +01:00
greenkeeper[bot] 7c36b5c4ef chore(package): update webpack to version 2.2.1
https://greenkeeper.io/
2017-02-11 14:52:13 +01:00
Martin Donath 099799cdf5 Merge pull request #147 from squidfunk/chore/setup-gemini-test-environment
Setup visual regression testing
2017-02-11 14:37:03 +01:00
squidfunk 854663ff03 Update baseline for Edge and adjust run script 2017-02-11 14:22:37 +01:00
squidfunk 885053bfbd Removed webfonts for visual tests 2017-02-10 16:43:32 +01:00
squidfunk 0cfee35151 Disable artifacts debug 2017-02-10 16:01:38 +01:00
squidfunk 89c68b03f0 Debug travis build 2017-02-10 15:35:34 +01:00
squidfunk ee198dd6d2 Debug travis build 2017-02-10 15:27:05 +01:00
squidfunk 401b512dda Debug travis build 2017-02-10 15:19:39 +01:00
squidfunk 4fc2a6c02e Enable HTML report in Travis build 2017-02-10 15:06:23 +01:00
squidfunk 7199f7ad6c Try to fix artifact paths 2017-02-10 14:54:57 +01:00
squidfunk 8792079cb3 Test upload of build artifacts 2017-02-10 14:44:43 +01:00
squidfunk 26d2ae36e3 Set retries to 0 2017-02-10 14:20:34 +01:00
squidfunk 2b0b90c5e9 Increase CIEDE2000 tolerance for edge 2017-02-10 13:59:36 +01:00
squidfunk c8ffa5203a Travis must build non-optimized assets due to pseudo classes 2017-02-10 10:50:34 +01:00
squidfunk f1ee7add1c Force travis to rebuild 2017-02-10 10:36:20 +01:00
squidfunk 78d7cdaf0b Updated visual test baseline 2017-02-10 10:30:14 +01:00
squidfunk 9028461c72 Removed IE10 from test matrix, as it doesn't support dataset 2017-02-09 19:40:32 +01:00
squidfunk d75aec1b7e Make tests run on Node.js 5 2017-02-09 19:01:23 +01:00
squidfunk 0beec63367 Ensure Gemini terminates with exit status 1 on failing build 2017-02-09 18:28:33 +01:00
squidfunk 57871449ea Fixed missing yarn in Travis 2017-02-09 18:10:27 +01:00
squidfunk 038288d489 Try to speed up build 2017-02-09 18:07:11 +01:00
squidfunk 3e2fa37250 Fixed case where there were no states defined 2017-02-09 17:49:13 +01:00
squidfunk 7e601d485a Refactored test filtering via grep CLI option 2017-02-09 17:35:50 +01:00
squidfunk 0bff78cd1b Added script to open a SauceConnect tunnel for manual testing 2017-02-09 11:12:56 +01:00
squidfunk 1fc01efe8b Fixed Edge specification in Gemini configuration 2017-02-09 10:35:06 +01:00
squidfunk 641b4ca13d Added visual test baseline for missing browsers 2017-02-09 10:34:28 +01:00
squidfunk cbb8567c76 Added visual test baseline for Firefox 2017-02-09 09:51:46 +01:00
squidfunk 70154b6047 Only build on Node.js 7 once 2017-02-09 00:51:53 +01:00
squidfunk d78e4e6a0b Integrate Gemini tests into Travis 2017-02-09 00:45:01 +01:00
squidfunk 52a3761d65 Added further tests for navigation 2017-02-09 00:02:07 +01:00
squidfunk 07329f4304 Merge branch 'master' into chore/setup-gemini-test-environment 2017-02-08 23:30:46 +01:00
squidfunk f40585f528 Fixed Jinja error for raw HTML header tags 2017-02-08 23:17:37 +01:00
squidfunk 9e3403ee4f Fixed stylelint deprecations 2017-02-05 23:51:32 +01:00
squidfunk 76a383fb1b Set minimal node version to 5 because of css-mqpacker 2017-02-05 23:51:32 +01:00
squidfunk d4c796c73e Switch Travis to yarn 2017-02-05 23:51:32 +01:00
squidfunk 64bd1d141a Pin dependencies by switching to yarn 2017-02-05 23:51:32 +01:00
squidfunk 551138e7c1 Setup SauceConnect tunnel for Gemini testing 2017-02-05 22:46:45 +01:00
squidfunk 7d94975960 Fixed navigation tests 2017-02-02 00:40:36 +01:00
squidfunk 8a7d9001fd Added tests for navigation and improved test generation logic 2017-02-01 23:56:57 +01:00
Martin Donath 55cae2d1f1 Merge pull request #134 from squidfunk/greenkeeper/selenium-standalone-6.0.0
Update selenium-standalone to the latest version 🚀
2017-01-29 22:05:27 +01:00
greenkeeper[bot] 4fe26f24db chore(package): update selenium-standalone to version 6.0.0
https://greenkeeper.io/
2017-01-29 17:34:15 +00:00
squidfunk 87c440c003 Remove JSDoc warning for now 2017-01-28 23:52:07 +01:00
squidfunk ef7b07a90e Linter warnings should fail pre-commit hook 2017-01-28 23:51:34 +01:00
squidfunk 17808d964d Visual test setup up and running 2017-01-28 23:50:33 +01:00
squidfunk 7d46ed2a85 Set PyMdown requirement to 1.2 2017-01-28 20:32:13 +01:00
squidfunk 3783eceb09 Implemented Gemini screenshot testing base 2017-01-28 20:25:30 +01:00
squidfunk 8f46cc6f09 Removed static test fixtures 2017-01-28 19:18:15 +01:00
squidfunk 0eb24a04ae Merge branch 'master' into chore/setup-gemini-test-environment 2017-01-28 17:57:37 +01:00
Martin Donath 4997d1f63c Merge pull request #133 from squidfunk/greenkeeper/node-notifier-5.0.0
Update node-notifier to the latest version 🚀
2017-01-27 22:41:26 +01:00
greenkeeper[bot] cae45a60b3 chore(package): update node-notifier to version 5.0.0
https://greenkeeper.io/
2017-01-27 19:43:51 +00:00
squidfunk 758ae36c92 Fixed offsets of targetted headlines 2017-01-26 22:39:42 +01:00
squidfunk c3231f1a9e Increased sidebar font size 2017-01-26 21:30:19 +01:00
squidfunk b04c3d1354 Merge branch 'master' into chore/setup-gemini-test-environment 2017-01-22 14:10:43 +01:00
squidfunk b09e334f3f Fix requirement for Math.sign 2017-01-22 13:59:23 +01:00
squidfunk f71359ce65 Prepare 1.0.3 release 2017-01-22 13:42:44 +01:00
squidfunk 80be8bb1ec Added mkdocs.yml as a requirement to issue template 2017-01-22 13:37:46 +01:00
Martin Donath 38f0099fc8 Merge pull request #123 from squidfunk/greenkeeper/babel-preset-es2015-6.22.0
Update babel-preset-es2015 to version 6.22.0
2017-01-22 13:22:01 +01:00
Martin Donath 4186b7b7f8 Merge branch 'master' into greenkeeper/babel-preset-es2015-6.22.0 2017-01-22 13:16:06 +01:00
greenkeeper[bot] bb9e1eb3df chore(package): update eslint to version 3.14.0
https://greenkeeper.io/
2017-01-22 13:15:42 +01:00
squidfunk 32ffc58d12 Track scroll direction to reset index cache 2017-01-22 13:05:12 +01:00
greenkeeper[bot] 2e228af92d chore(package): update babel-preset-es2015 to version 6.22.0
https://greenkeeper.io/
2017-01-20 00:45:17 +00:00
squidfunk 28d024af2f Try to fix travis 2017-01-18 23:32:56 +01:00
squidfunk 21f2617c9c Remove ... on hooks 2017-01-18 23:26:22 +01:00
squidfunk 203087bcb1 Initial setup of Gemini and first testcases 2017-01-18 23:23:45 +01:00
squidfunk 680725ed3a Revert last PR - still some problems to tackle 2017-01-16 00:35:00 +01:00
Martin Donath 1e61603b4e Merge pull request #115 from squidfunk/refactor/remove-unnecessary-sidebar-logic-and-styles
Remove unnecessary sidebar logic and styles
2017-01-16 00:22:46 +01:00
squidfunk f51f3c453d Re-add content of index page 2017-01-16 00:19:45 +01:00
squidfunk 61533af0ef No more need for csscalc and container height adjustment logic 2017-01-16 00:18:21 +01:00
Martin Donath 62ff9d0ac0 Merge pull request #114 from squidfunk/fix/drawer-not-opening-on-mobile
Scrollwrap must be stretched to full height for mobile
2017-01-15 15:17:40 +01:00
squidfunk 460164b560 Scrollwrap must be stretched to full height for mobile 2017-01-15 15:14:08 +01:00
Martin Donath 9d24e6880b Merge pull request #113 from squidfunk/refactor/reduce-repaints-for-sidebar
Reduce repaints for sidebar
2017-01-15 15:04:08 +01:00
squidfunk ceea88e066 Only set shadow on search results when active 2017-01-15 15:00:38 +01:00
squidfunk ed1ae7226a Further reduction of repaints by refactoring sidebar 2017-01-15 14:57:06 +01:00
Martin Donath f81a0c578a Merge pull request #112 from squidfunk/chore/prepare-1-0-2-release
Prepare 1.0.2 release
2017-01-15 11:30:23 +01:00
squidfunk 96168d05d8 Added 1.0.2 to changelog and release notes 2017-01-15 11:27:48 +01:00
squidfunk c691fff501 Prepare 1.0.2 release 2017-01-15 11:24:32 +01:00
Martin Donath c101debc8c Merge pull request #111 from squidfunk/chore/centralize-package-specs
Load package specs in setup.py from package.json
2017-01-14 23:09:11 +01:00
squidfunk 65d725f260 Load package specs in setup.py from package.json 2017-01-14 23:05:18 +01:00
Martin Donath 040d3a303c Merge pull request #110 from squidfunk/fix/scrollbar-appears-while-animating-repo-facts
Setting overflow to hidden removes appearing scrollbar
2017-01-14 22:58:46 +01:00
squidfunk 823b24aa9c Setting overflow to hidden removes appearing scrollbar 2017-01-14 22:55:58 +01:00
Martin Donath e3ac58a7c6 Merge pull request #109 from squidfunk/fix/horizontal-scrollbar-in-content-area
Remove float on inner content area
2017-01-14 22:45:06 +01:00
squidfunk e0855d4002 Remove float on inner content area 2017-01-14 22:40:55 +01:00
Martin Donath b54813ffd8 Merge pull request #107 from squidfunk/chore/prepare-1.0.1-release
Prepare 1.0.1 release
2017-01-14 20:26:50 +01:00
squidfunk 5593f99c14 Prepare 1.0.1 release 2017-01-14 20:22:09 +01:00
Martin Donath a463798593 Merge pull request #106 from squidfunk/fix/logo-not-hidden-on-mobile
Hide logo on mobile
2017-01-14 20:19:39 +01:00
squidfunk c55cf5cba9 Hide logo on mobile 2017-01-14 20:13:10 +01:00
Martin Donath 5257fe67a6 Merge pull request #105 from squidfunk/fix/only-show-scrollbars-on-overflow
Set overflow property to auto
2017-01-14 19:50:55 +01:00
squidfunk 180da60770 Set overflow property to auto 2017-01-14 19:48:00 +01:00
Martin Donath 7fd5811bf1 Merge pull request #104 from squidfunk/chore/dockerize
Updated Dockerfile and added documentation
2017-01-14 19:33:48 +01:00
squidfunk eea4ebdaf4 Updated Dockerfile and added documentation 2017-01-14 19:24:07 +01:00
Martin Donath 7b653fac4e Merge pull request #102 from squidfunk/fix/footnote-back-reference-position
Fixed footer back reference positions
2017-01-14 18:46:21 +01:00
squidfunk 7178bb4180 Fixed footer back reference positions 2017-01-14 18:42:07 +01:00
Martin Donath 87bc1c8ef9 Merge pull request #101 from squidfunk/chore/pre-commit-hook-for-branch-check
Forbid commits on master branch
2017-01-14 18:17:29 +01:00
squidfunk 99b057a9ae Use $(..) instead of `` 2017-01-14 18:12:57 +01:00
squidfunk 9633f69b74 Forbid commits on master branch 2017-01-14 18:06:03 +01:00
Martin Donath 7661631e3e Merge pull request #100 from squidfunk/fix/massive-repaints-when-scrolling
Massive repaints when scrolling
2017-01-14 13:59:44 +01:00
squidfunk 2ba776bb0e Added compiled output 2017-01-14 13:56:33 +01:00
Martin Donath e37f517240 Merge pull request #99 from squidfunk/docs/format-notes-on-chocolatey
Format notes on Chocolatey installation
2017-01-14 13:48:46 +01:00
squidfunk c0fe88004a Fix link reference 2017-01-14 13:44:23 +01:00
squidfunk 6f324afb37 Put choco under general installation procedures 2017-01-14 13:43:19 +01:00
Martin Donath cf17f3b71e Merge pull request #98 from pascalberger/chocolatey
Add documentation how to install using Chocolatey
2017-01-14 12:53:42 +01:00
Pascal Berger 9ecc9aa8c9 Add documentation how to install using Chocolatey 2017-01-14 12:48:56 +01:00
squidfunk e68f54c79f Setup Gemini for visual regression testing 2017-01-13 17:34:39 +01:00
squidfunk 4086c2c973 Fixed massive repaints when scrolling 2017-01-13 13:02:28 +01:00
377 changed files with 9999 additions and 570 deletions
+1 -4
View File
@@ -2,9 +2,6 @@
"presets": ["es2015"],
"plugins": [
"add-module-exports",
"babel-root-import",
["transform-react-jsx", {
"pragma": "JSX.createElement"
}]
"babel-root-import"
]
}
+5 -1
View File
@@ -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
+1 -1
View File
@@ -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
+34
View File
@@ -0,0 +1,34 @@
#!/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.
# Determine current branch
BRANCH=$(git rev-parse --abbrev-ref HEAD)
echo "Hook[pre-commit]: Checking branch"
# If we're on master, abort commit
if [[ "$BRANCH" == "master" ]]; then
echo "Commits on master are only allowed via Pull Requests. Aborting."
exit 1
fi
# We're good
exit 0
+1 -1
View File
@@ -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
+11 -5
View File
@@ -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]
+7 -2
View File
@@ -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
-1
View File
@@ -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",
+33 -4
View File
@@ -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
+24
View File
@@ -1,3 +1,27 @@
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 #108: Horizontal scrollbar in content area
mkdocs-material-1.0.1 (2017-01-14)
* Fixed massive repaints happening when scrolling
* Fixed footer back reference positions in case of overflow
* Fixed header logo from showing when the menu icon is rendered
* Changed scrollbar behavior to only show when content overflows
mkdocs-material-1.0.0 (2017-01-13)
* Introduced Webpack for more sophisticated JavaScript bundling
+3 -2
View File
@@ -19,9 +19,10 @@
# IN THE SOFTWARE.
FROM jfloff/alpine-python:2.7-slim
MAINTAINER Martin Donath <martin.donath@squidfunk.com>
# Set work directory
WORKDIR /usr/src
# Set working directory
WORKDIR /docs
# Install packages
COPY requirements.txt .
+56 -14
View File
@@ -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
+1
View File
@@ -3,3 +3,4 @@ recursive-exclude site *
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
include LICENSE
include package.json
+5 -1
View File
@@ -1,17 +1,21 @@
[![Travis][travis-image]][travis-link]
[![Dependencies][deps-image]][deps-link]
[![Codacy][codacy-image]][codacy-link]
[![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
[codacy-image]: https://api.codacy.com/project/badge/Grade/fe07aa1fa91d453cb69711d3885c5d7e
[codacy-link]: https://www.codacy.com/app/squidfunk/mkdocs-material?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=squidfunk/mkdocs-material&amp;utm_campaign=Badge_Grade
[docker-image]: https://img.shields.io/docker/pulls/squidfunk/mkdocs-material.svg
[docker-link]: https://hub.docker.com/r/squidfunk/mkdocs-material/
[pypi-image]: https://img.shields.io/pypi/v/mkdocs-material.svg
[pypi-link]: https://pypi.python.org/pypi/mkdocs-material
# Material for MkDocs
A Material Design theme for [MkDocs](http://www.mkdocs.org).
+1 -1
View File
@@ -196,7 +196,7 @@ The Material theme uses a sophisticated asset pipeline using [Gulp][9] and
Webpack which can be started with the following command:
``` sh
npm run start
npm start
```
This will also start the MkDocs development server which will monitor changes
+55 -33
View File
@@ -2,6 +2,12 @@
## Installation
!!! tip "Set up Material using Docker"
The official [Docker image][1] for Material comes with all dependencies
pre-installed and ready-to-use with the latest version published on PyPI,
packaged in a very small image (27MB compressed).
### Installing MkDocs
Before installing [MkDocs][2], you need to make sure you have Python and `pip`
@@ -22,7 +28,7 @@ pip install mkdocs && mkdocs --version
# mkdocs, version 0.16.0
```
!!! warning "MkDocs for Material requirements"
!!! warning "MkDocs version requirements"
Material requires MkDocs >= 0.16.
@@ -41,7 +47,7 @@ pip install pymdown-extensions
### Installing Material
#### by using pip
#### using pip
Material can be installed with `pip`:
@@ -63,7 +69,23 @@ pip install mkdocs-material
to a self-contained solution by installing Python with Homebrew. This
should eliminate a lot of problems you may be having with `pip`.
#### by cloning from GitHub
#### using choco
If you're on Windows you can use [Chocolatey][5] to install [Material][6]:
``` dos
choco install mkdocs-material
```
This will also install all required dependencies like [Python][7] and
[MkDocs][8].
[5]: https://chocolatey.org
[6]: https://chocolatey.org/packages/mkdocs-material
[7]: https://chocolatey.org/packages/python
[8]: https://chocolatey.org/packages/mkdocs
#### cloning from GitHub
Material can also be used without a system-wide installation by cloning the
repository into a subfolder of your project's root directory:
@@ -98,11 +120,11 @@ The development server can be started with the following command:
mkdocs serve
```
Now you can point your browser to [localhost:8000][5] and the Material theme
Now you can point your browser to [localhost:8000][9] and the Material theme
should be visible. From here on, you can start writing your documentation, or
read on and customize the theme through some options.
[5]: http://localhost:8000
[9]: http://localhost:8000
## Options
@@ -112,7 +134,7 @@ project's `mkdocs.yml`. See the following section for all available options.
### Changing the color palette
Material defines a default hue for every primary and accent color on Google's
Material Design [color palette][6]. This makes it very easy to change the
Material Design [color palette][10]. This makes it very easy to change the
overall look of the theme. Just set the primary and accent colors using the
following variables in your `mkdocs.yml`:
@@ -132,10 +154,10 @@ The last three colors can only be used as a primary color.
If the color is set via this configuration, an additional CSS file that
defines the color palette is included. If you want to keep things lean, clone
the repository and recompile the theme with your custom colors set. See the
guide on [customization][7] for more information.
guide on [customization][11] for more information.
[6]: http://www.materialui.co/colors
[7]: customization.md
[10]: http://www.materialui.co/colors
[11]: customization.md
#### Primary colors
@@ -202,10 +224,10 @@ Click on a tile to change the accent color of the theme:
### Changing the font family
Material uses the [Roboto font family][8] by default, specifically the regular
Material uses the [Roboto font family][12] by default, specifically the regular
sans-serif type for text and the `monospaced` type for code. Both fonts are
loaded from [Google Fonts][9] and can easily be changed to other fonts, like
for example the [Ubuntu font family][10]:
loaded from [Google Fonts][13] and can easily be changed to other fonts, like
for example the [Ubuntu font family][14]:
``` yaml
extra:
@@ -223,9 +245,9 @@ extra:
font: 'none'
```
[8]: https://fonts.google.com/specimen/Roboto
[9]: https://fonts.google.com/
[10]: https://fonts.google.com/specimen/Ubuntu
[12]: https://fonts.google.com/specimen/Roboto
[13]: https://fonts.google.com/
[14]: https://fonts.google.com/specimen/Ubuntu
### Adding a logo
@@ -244,7 +266,7 @@ extra:
If you want to link your social accounts, the Material theme provides an easy
way for doing this in the footer of the documentation using the automatically
included [FontAwesome][11] webfont. The syntax is simple the `type` must
included [FontAwesome][15] webfont. The syntax is simple the `type` must
denote the name of the social service, e.g. `github`, `twitter` or `linkedin`
and the `link` must contain the URL you want to link to:
@@ -263,7 +285,7 @@ The links are generated in order and the `type` of the links must match the
name of the FontAwesome glyph. The `fa` is automatically added, so `github`
will result in `fa fa-github`.
[11]: http://fontawesome.io/icons/
[15]: http://fontawesome.io/icons/
### Google Analytics integration
@@ -296,7 +318,7 @@ translations inside the macro `t`:
```
Just copy the file from the original theme and make your adjustments. See the
section on [overriding partials][12] in the customization guide.
section on [overriding partials][16] in the customization guide.
!!! warning "Migrating from Material 0.2.x"
@@ -304,18 +326,18 @@ section on [overriding partials][12] in the customization guide.
`mkdocs.yml`. With 1.0.0 this is no longer possible as the configuration
will be ignored.
[12]: customization.md#overriding-partials
[16]: customization.md#overriding-partials
### More advanced customization
If you want to change the general appearance of the Material theme, see
[this article][13] for more information on advanced customization.
[this article][17] for more information on advanced customization.
[13]: customization.md
[17]: customization.md
## Extensions
MkDocs supports several [Markdown extensions][14]. The following extensions
MkDocs supports several [Markdown extensions][18]. The following extensions
are not enabled by default (see the link for which are enabled by default)
but highly recommended, so they should be switched on at all times:
@@ -329,18 +351,18 @@ markdown_extensions:
For more information, see the following list of extensions supported by the
Material theme including more information regarding installation and usage:
* [Admonition][15]
* [Codehilite][16]
* [Permalinks][17]
* [Footnotes][18]
* [PyMdown Extensions][19]
* [Admonition][19]
* [Codehilite][20]
* [Permalinks][21]
* [Footnotes][22]
* [PyMdown Extensions][23]
[14]: http://www.mkdocs.org/user-guide/writing-your-docs/#markdown-extensions
[15]: extensions/admonition.md
[16]: extensions/codehilite.md
[17]: extensions/permalinks.md
[18]: extensions/footnotes.md
[19]: extensions/pymdown.md
[18]: http://www.mkdocs.org/user-guide/writing-your-docs/#markdown-extensions
[19]: extensions/admonition.md
[20]: extensions/codehilite.md
[21]: extensions/permalinks.md
[22]: extensions/footnotes.md
[23]: extensions/pymdown.md
## Full example
+34 -3
View File
@@ -1,4 +1,4 @@
# Release Notes
# Release notes
## Upgrading
@@ -12,12 +12,43 @@ 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.0 <small> _ January 13, 2017</small>
### 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 [#108][108]: Horizontal scrollbar in content area
[108]: https://github.com/squidfunk/mkdocs-material/issues/108
### 1.0.1 <small> _ January 14, 2017</small>
* Fixed massive repaints happening when scrolling
* Fixed footer back reference positions in case of overflow
* Fixed header logo from showing when the menu icon is rendered
* Changed scrollbar behavior to only show when content overflows
### 1.0.0 <small> _ January 13, 2017</small>
* Introduced Webpack for more sophisticated JavaScript bundling
* Introduced ESLint and Stylelint for code style checks
+6
View File
@@ -0,0 +1,6 @@
{
"rules": {
"no-invalid-this": 0,
"max-params": 0
}
}
+1 -1
View File
@@ -21,7 +21,7 @@
*/
/* ----------------------------------------------------------------------------
* Definition
* Module
* ------------------------------------------------------------------------- */
export default /* JSX */ {
+65
View File
@@ -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
}
}
+71
View File
@@ -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)
-5
View File
@@ -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()))
+1
View File
@@ -23,6 +23,7 @@
import path from "path"
import through from "through2"
import util from "gulp-util"
import { CLIEngine } from "eslint"
/* ----------------------------------------------------------------------------
+7 -2
View File
@@ -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", {
+1 -1
View File
@@ -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"
})
}
+38
View File
@@ -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))
}
}
+63
View File
@@ -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()
}))
}
}
+166
View File
@@ -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))
})
}
}
+82
View File
@@ -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)
})
}
}
+72
View File
@@ -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))
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+14 -14
View File
@@ -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.0">
<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-ff220fd69d.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 %}
+2 -2
View File
@@ -6,7 +6,7 @@
{% if page.previous_page %}
<a href="{{ page.previous_page.url }}" title="{{ page.previous_page.title }}" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__icon"></i>
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
@@ -29,7 +29,7 @@
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__icon"></i>
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
{% endif %}
+3 -3
View File
@@ -2,14 +2,14 @@
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="{{ nav.homepage.url }}" title="{{ config.site_name }}" class="md-icon {% if not config.extra.logo %} md-icon--home {% endif %} md-header-nav__icon">
<a href="{{ nav.homepage.url }}" title="{{ config.site_name }}" class="{% if config.extra.logo %} md-logo {% else %} md-icon md-icon--home {% endif %} md-header-nav__button">
{% if config.extra.logo %}
<img src="{{ base_url }}/{{ config.extra.logo }}" width="24" height="24">
{% endif %}
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__icon" for="drawer"></label>
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<span class="md-flex__ellipsis md-header-nav__title">
@@ -27,7 +27,7 @@
</div>
<div class="md-flex__cell md-flex__cell--shrink">
{% block search_box %}
<label class="md-icon md-icon--search md-header-nav__icon" for="search"></label>
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
{% include "partials/search.html" %}
{% endblock %}
</div>
+3 -3
View File
@@ -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 -1
View File
@@ -1,6 +1,6 @@
<nav class="md-nav md-nav--primary">
<label class="md-nav__title md-nav__title--site" for="drawer">
<i class="md-icon {% if not config.extra.logo %} md-icon--home {% endif %} md-nav__icon">
<i class="{% if config.extra.logo %} md-logo {% else %} md-icon md-icon--home {% endif %} md-nav__button">
{% if config.extra.logo %}
<img src="{{ base_url }}/{{ config.extra.logo }}">
{% endif %}
+2 -2
View File
@@ -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_ %}
+2 -2
View File
@@ -29,9 +29,9 @@ repo_name: squidfunk/mkdocs-material
repo_url: https://github.com/squidfunk/mkdocs-material
# Copyright
copyright: 'Copyright &copy; 2016 Martin Donath'
copyright: 'Copyright &copy; 2016 - 2017 Martin Donath'
# Documentation and theme
# Theme directory
theme_dir: material
# Options
+37 -26
View File
@@ -1,6 +1,6 @@
{
"name": "mkdocs-material",
"version": "1.0.0",
"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
}
+1 -1
View File
@@ -20,4 +20,4 @@
mkdocs>=0.16
pygments
pymdown-extensions
pymdown-extensions>=1.2
+1 -1
View File
@@ -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 "$@"
+1 -1
View File
@@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then
fi
# Run command
`npm bin`/gulp clean
`npm bin`/gulp clean "$@"
+1 -1
View File
@@ -28,7 +28,7 @@ if [[ ! -d `npm bin` ]]; then
fi
# Run ESLint
`npm bin`/eslint .
`npm bin`/eslint --max-warnings 0 .
ESLINT=$?
# Run Stylelint
+1 -1
View File
@@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then
fi
# Run command
`npm bin`/gulp watch --no-lint
`npm bin`/gulp watch --no-lint "$@"
+31
View File
@@ -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 "$@"
+31
View File
@@ -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 "$@"
+1 -1
View File
@@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then
fi
# Run command
`npm bin`/gulp test
`npm bin`/gulp tests:visual:update "$@"
+13 -8
View File
@@ -18,18 +18,23 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
import json
from setuptools import setup, find_packages
# Load package.json contents
with open("package.json") as data:
package = json.load(data)
# Package description
setup(
name = "mkdocs-material",
version = "1.0.0",
url = "http://squidfunk.github.io/mkdocs-material/",
license = "MIT",
description = "A Material Design theme for MkDocs",
author = "Martin Donath",
author_email = "martin.donath@squidfunk.com",
keywords = ["mkdocs", "documentation", "theme"],
name = package["name"],
version = package["version"],
url = package["homepage"],
license = package["license"],
description = package["description"],
author = package["author"]["name"],
author_email = package["author"]["email"],
keywords = package["keywords"],
packages = find_packages(),
include_package_data = True,
entry_points = {
+10
View File
@@ -0,0 +1,10 @@
{
"presets": [
["es2015", { "modules": false }]
],
"plugins": [
["transform-react-jsx", {
"pragma": "JSX.createElement"
}]
]
}
+183 -199
View File
@@ -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
}
/**
+2 -12
View File
@@ -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;
}
}
// ----------------------------------------------------------------------------
@@ -83,24 +83,21 @@
.footnote-backref {
@extend %md-icon;
position: absolute;
display: inline-block;
transform: translateX(0.5rem);
transition:
transform 0.25s 0.125s,
color 0.25s,
opacity 0.125s 0.125s;
color: $md-color-black--lighter;
font-size: 1.5625em;
opacity: 0;
vertical-align: middle;
// Hack: remove Unicode arrow for icon
&::first-letter {
font-size: 0;
}
font-size: 0;
opacity: 0;
vertical-align: text-bottom;
// Back reference icon
&::after {
&::before {
font-size: 1.6rem;
content: "keyboard_return";
}
}
@@ -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
@@ -35,6 +35,9 @@
// [screen +]: Add space for table of contents
@include break-from-device(screen) {
margin-left: 24.2rem;
// Hack: setting overflow to auto induces margin collapse which omits
// massive repaints because of the margins of the inner elements
overflow: auto;
}
// Define spacing
@@ -44,6 +47,11 @@
// [screen +]: Increase spacing
@include break-from-device(screen) {
margin: 2.4rem;
// Hack: remove bottom spacing, due to margin collapse
:last-child {
margin-bottom: 0;
}
}
}
+6 -6
View File
@@ -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;
}
}
@@ -83,8 +83,8 @@
}
}
// Icons
&__icon {
// Icon buttons
&__button {
@extend %md-icon__button;
transition: background 0.25s;
+12 -6
View File
@@ -48,8 +48,8 @@
.md-header-nav {
padding: 0.4rem;
// Icons
&__icon {
// Icon buttons
&__button {
@extend %md-icon__button;
position: relative;
@@ -61,8 +61,13 @@
opacity: 0.7;
}
// Set correct display on image
&.md-logo img {
display: block;
}
// Hide search icon, if JavaScript is not available.
.no-js & .md-icon--search {
.no-js &.md-icon--search {
display: none;
}
@@ -75,11 +80,12 @@
}
}
// [tablet -]: Hide the home icon
// [tablet -]: Hide the home icon or logo
@include break-to-device(tablet) {
// Home icon
&.md-icon--home {
// Home icon or logo
&.md-icon--home,
&.md-logo {
display: none;
}
}
+19 -24
View File
@@ -26,7 +26,7 @@
// Navigation container
.md-nav {
font-size: ms(-1);
font-size: 1.4rem;
line-height: 1.3;
// Table of contents
@@ -51,8 +51,8 @@
content: "arrow_back";
}
// Hide icon by default
.md-nav__icon {
// Hide button by default
.md-nav__button {
display: none;
}
}
@@ -84,8 +84,8 @@
}
}
// Icon
&__icon {
// Button with logo
&__button {
@extend %md-icon, %md-icon__button;
// Stretch image
@@ -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
@@ -240,7 +241,7 @@
color: $md-color-white;
// Site logo
.md-nav__icon {
.md-nav__button {
display: block;
position: absolute;
top: 0.4rem;
@@ -260,7 +261,7 @@
// List of items
.md-nav__list {
flex: 1;
overflow-y: scroll;
overflow-y: auto;
}
// List item
@@ -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
+2 -2
View File
@@ -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;
}
}
+11 -12
View File
@@ -28,6 +28,7 @@
.md-sidebar {
position: relative;
width: 24.2rem;
padding: 2.4rem 0;
float: left;
overflow: visible;
@@ -40,6 +41,7 @@
&[data-md-state="lock"] {
position: fixed;
top: 5.6rem;
backface-visibility: hidden;
}
// [tablet -]: Convert navigation to drawer
@@ -107,27 +109,24 @@
// Wrapper for scrolling on overflow
&__scrollwrap {
margin: 2.4rem 0.4rem;
overflow-y: scroll;
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;
+1 -1
View File
@@ -118,7 +118,7 @@
font-weight: 700;
list-style-type: none;
opacity: 0.75;
overflow: auto;
overflow: hidden;
// Show after the data was loaded
[data-md-state="done"] & {
+25 -34
View File
@@ -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>
+2 -2
View File
@@ -38,7 +38,7 @@
rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back
md-footer-nav__icon"></i>
md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch
md-footer-nav__title">
@@ -68,7 +68,7 @@
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward
md-footer-nav__icon"></i>
md-footer-nav__button"></i>
</div>
</a>
{% endif %}
+8 -6
View File
@@ -30,10 +30,12 @@
<!-- Link to home -->
<div class="md-flex__cell md-flex__cell--shrink">
<a href="{{ nav.homepage.url }}" title="{{ config.site_name }}"
class="md-icon
{% if not config.extra.logo %}
md-icon--home
{% endif %} md-header-nav__icon">
class="
{% if config.extra.logo %}
md-logo
{% else %}
md-icon md-icon--home
{% endif %} md-header-nav__button">
{% if config.extra.logo %}
<img src="{{ base_url }}/{{ config.extra.logo }}"
width="24" height="24" />
@@ -43,7 +45,7 @@
<!-- Button to toggle drawer -->
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__icon"
<label class="md-icon md-icon--menu md-header-nav__button"
for="drawer"></label>
</div>
@@ -66,7 +68,7 @@
<!-- Button to open search dialogue -->
<div class="md-flex__cell md-flex__cell--shrink">
{% block search_box %}
<label class="md-icon md-icon--search md-header-nav__icon"
<label class="md-icon md-icon--search md-header-nav__button"
for="search"></label>
<!-- Search interface -->
+4 -4
View File
@@ -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>
+6 -5
View File
@@ -23,11 +23,12 @@
<!-- Main navigation -->
<nav class="md-nav md-nav--primary">
<label class="md-nav__title md-nav__title--site" for="drawer">
<i class="md-icon
{% if not config.extra.logo %}
md-icon--home
{% endif %}
md-nav__icon">
<i class="
{% if config.extra.logo %}
md-logo
{% else %}
md-icon md-icon--home
{% endif %} md-nav__button">
{% if config.extra.logo %}
<img src="{{ base_url }}/{{ config.extra.logo }}" />
{% endif %}
+6 -6
View File
@@ -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_ %}
+8
View File
@@ -0,0 +1,8 @@
{
"globals": {
"gemini": true
},
"rules": {
"no-loop-func": 0
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Some files were not shown because too many files have changed in this diff Show More