Merge branch 'master' into refactor/sidebar-height-spacing

This commit is contained in:
squidfunk 2017-02-26 11:04:12 +01:00
commit 2c3ca5aeb4
290 changed files with 1619 additions and 1407 deletions

View File

@ -23,6 +23,10 @@
/material
/site
# Files used and generated by flow
/lib/declarations
/tmp
# Files generated by visual tests
/gemini-report
/tests/visual/data

View File

@ -169,7 +169,7 @@
"space-unary-ops": 2,
"spaced-comment": [2, "always", {
"line": {
"markers": ["/"],
"markers": ["/", ":"],
"exceptions": ["-", "+"]
},
"block": {

8
.flowconfig Normal file
View File

@ -0,0 +1,8 @@
[ignore]
.*/node_modules/.*
[libs]
lib/declarations/
[options]
strip_root=true

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 -e "\x1B[33m!\x1B[0m Updating dependencies"
npm install && npm prune
fi

View File

@ -22,12 +22,14 @@
# Determine current branch
BRANCH=$(git rev-parse --abbrev-ref HEAD)
echo "Hook[pre-commit]: Checking branch"
MESSAGE="Commits on master are only allowed via Pull Requests. Aborting."
# If we're on master, abort commit
if [[ "$BRANCH" == "master" ]]; then
echo "Commits on master are only allowed via Pull Requests. Aborting."
echo -e "\x1B[31m✗\x1B[0m Branch: $BRANCH - \x1B[31m$MESSAGE\x1B[0m"
exit 1
else
echo -e "\x1B[32m✓\x1B[0m Branch: $BRANCH"
fi
# We're good

View File

@ -22,6 +22,7 @@
# Patch file to store unindexed changes
PATCH_FILE=".working-tree.patch"
MESSAGE="Terminated with errors"
# Revert changes that have been registered in the patch file
function cleanup {
@ -30,7 +31,7 @@ function cleanup {
git apply "$PATCH_FILE" 2> /dev/null
rm "$PATCH_FILE"
fi
exit $EXIT_CODE
exit $EXIT_CODE
}
# Register signal handlers
@ -44,8 +45,26 @@ git checkout -- .
FILES=$(git diff --cached --name-only --diff-filter=ACMR | \
grep "\.\(js\|jsx\|scss\)$")
# Run the check and print indicator
# Run check and print indicator
if [ "$FILES" ]; then
echo "Hook[pre-commit]: Running linter"
npm run lint --silent || exit 1
# If linter terminated with errors, abort commit
if [ $? -gt 0 ]; then
echo -e "\x1B[31m✗\x1B[0m Linter - \x1B[31m$MESSAGE\x1B[0m"
exit 1
else
echo -e "\x1B[32m✓\x1B[0m Linter"
fi
# If flow terminated with errors, abort commit
npm run flow --silent > /dev/null
if [ $? -gt 0 ]; then
echo -e "\x1B[31m✗\x1B[0m Flow - \x1B[31m$MESSAGE\x1B[0m"
exit 1
else
echo -e "\x1B[32m✓\x1B[0m Flow"
fi
fi
# We're good
exit 0

4
.gitignore vendored
View File

@ -24,6 +24,7 @@
# NPM-related
/node_modules
/npm-debug.log*
/yarn-error.log
# Files generated by build
/build
@ -31,6 +32,9 @@
/MANIFEST
/site
# Files generated by flow typechecker
/tmp
# Files generated by visual tests
/gemini-report
/tests/visual/baseline/local

View File

@ -21,31 +21,16 @@
language: node_js
sudo: false
# -----------------------------------------------------------------------------
# Regular builds
# -----------------------------------------------------------------------------
# Node.js versions
node_js:
- 5
- 6
- 7
# Build visual tests separately
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
@ -58,13 +43,72 @@ cache:
- 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
before_install:
- npm install -g yarn
# Install dependencies
before_script: pip install --user -r requirements.txt
install:
- yarn install --ignore-optional
- pip install --user -r requirements.txt
# Perform build and tests
script: yarn run build
script:
- yarn run build
# -----------------------------------------------------------------------------
# Additional builds
# -----------------------------------------------------------------------------
# Matrix for additional builds
matrix:
include:
# Build release and docker image and send to PyPI and Docker Hub.
- node_js: 5
services:
- docker
env:
- __TASK=RELEASE
# If we're not on a release branch, exit early and indicate success
before_install:
- echo "$TRAVIS_BRANCH" | grep -qvE "^[0-9.]+$" && exit 0; :;
# Install wheel for build
install:
- pip install wheel
# Perform build
script:
- python setup.py build sdist bdist_wheel --universal
- docker build -t $TRAVIS_REPO_SLUG .
# If build was successful, publish
after_success:
# Install twine and push release to PyPI
- pip install twine
- twine upload -u $PYPI_USERNAME -p $PYPI_PASSWORD dist/*
# Push to Docker Hub
- docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
- docker tag $TRAVIS_REPO_SLUG $TRAVIS_REPO_SLUG:$TRAVIS_BRANCH
- docker tag $TRAVIS_REPO_SLUG $TRAVIS_REPO_SLUG:latest
- docker push $TRAVIS_REPO_SLUG
# # Build visual tests separately - temporary disabled until tests stable
# - 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

View File

@ -1,3 +1,15 @@
mkdocs-material-1.0.5 (2017-02-18)
* Fixed #153: Sidebar flows out of constrained area in Chrome 56
* Fixed #159: Footer jitter due to JavaScript if content is short
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

View File

@ -21,17 +21,30 @@
FROM jfloff/alpine-python:2.7-slim
MAINTAINER Martin Donath <martin.donath@squidfunk.com>
# Set working directory
WORKDIR /docs
# Set build directory
WORKDIR /tmp
# Install packages
# Install dependencies
COPY requirements.txt .
RUN \
pip install -r requirements.txt && \
pip install mkdocs-material && \
rm requirements.txt
# Expose MkDocs default port
# Copy files necessary for build
COPY material material
COPY MANIFEST.in MANIFEST.in
COPY package.json package.json
COPY setup.py setup.py
# Perform build and cleanup artifacts
RUN \
python setup.py install && \
rm -rf /tmp/*
# Set working directory
WORKDIR /docs
# Expose MkDocs development server port
EXPOSE 8000
# Start development server by default

View File

@ -55,9 +55,11 @@ let args = yargs
.default("sourcemaps", false) /* Create sourcemaps */
.argv
/* Only use the last value seen, so overrides are possible */
/* Only use the last seen value if boolean, so overrides are possible */
args = Object.keys(args).reduce((result, arg) => {
result[arg] = [].concat(args[arg]).pop()
result[arg] = Array.isArray(args[arg]) && typeof args[arg][0] === "boolean"
? [].concat(args[arg]).pop()
: args[arg]
return result
}, {})
@ -151,9 +153,13 @@ gulp.task("assets:images:clean",
/*
* Build application logic
*
* When revisioning, the build must be serialized due to race conditions
* happening when two tasks try to write manifest.json simultaneously
*/
gulp.task("assets:javascripts:build:application", [
args.revision ? "assets:javascripts:build:application" : false,
args.clean ? "assets:javascripts:clean" : false,
args.lint ? "assets:javascripts:lint" : false
].filter(t => t),
@ -161,16 +167,20 @@ gulp.task("assets:javascripts:build:application", [
/*
* Build custom modernizr
*
* When revisioning, the build must be serialized due to race conditions
* happening when two tasks try to write manifest.json simultaneously
*/
gulp.task("assets:javascripts:build:modernizr", [
"assets:stylesheets:build",
args.revision ? "assets:javascripts:build:application" : false,
args.clean ? "assets:javascripts:clean" : false,
args.lint ? "assets:javascripts:lint" : false
].filter(t => t),
load("assets/javascripts/build/modernizr"))
/*
* Build application logic and modernizr
* Build application logic and Modernizr
*/
gulp.task("assets:javascripts:build", [
"assets:javascripts:build:application",
@ -183,6 +193,12 @@ gulp.task("assets:javascripts:build", [
gulp.task("assets:javascripts:clean",
load("assets/javascripts/clean"))
/*
* Annotate JavaScript
*/
gulp.task("assets:javascripts:annotate",
load("assets/javascripts/annotate"))
/*
* Lint JavaScript
*/
@ -359,10 +375,6 @@ gulp.task("watch", [
if (args.mkdocs)
gulp.start("mkdocs:serve")
/* Start karma test runner */
// if (args.karma)
// gulp.start("tests:unit:watch")
/* Rebuild stylesheets */
gulp.watch([
`${config.assets.src}/stylesheets/**/*.scss`

View File

@ -3,3 +3,4 @@ recursive-exclude site *
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
include LICENSE
include package.json

View File

@ -1,21 +1,17 @@
[![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-image]: https://img.shields.io/docker/automated/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).

View File

@ -6,7 +6,7 @@
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).
packaged in a very small image (28MB compressed).
### Installing MkDocs
@ -246,7 +246,7 @@ extra:
```
[12]: https://fonts.google.com/specimen/Roboto
[13]: https://fonts.google.com/
[13]: https://fonts.google.com
[14]: https://fonts.google.com/specimen/Ubuntu
### Adding a logo
@ -300,6 +300,21 @@ google_analytics:
- 'auto'
```
### Disqus integation
Material for MkDocs is integrated with [Disqus][16], so if you want to add a
comments section to your documentation set the shortname of your Disqus project
in your `mkdocs.yml`:
``` yaml
extra:
disqus: 'your-disqus-shortname'
```
The necessary JavaScript is automatically included.
[16]: https://disqus.com
### Localization <small>L10N</small>
In order to localize the labels (e.g. *Previous* and *Next* in the footer),
@ -309,6 +324,7 @@ translations inside the macro `t`:
``` jinja
{% macro t(key) %}{{ {
"edit.link.title": "Edit this page",
"comments": "Comments",
"footer.previous": "Previous",
"footer.next": "Next",
"search.placeholder": "Search",
@ -318,7 +334,7 @@ translations inside the macro `t`:
```
Just copy the file from the original theme and make your adjustments. See the
section on [overriding partials][16] in the customization guide.
section on [overriding partials][17] in the customization guide.
!!! warning "Migrating from Material 0.2.x"
@ -326,18 +342,18 @@ section on [overriding partials][16] in the customization guide.
`mkdocs.yml`. With 1.0.0 this is no longer possible as the configuration
will be ignored.
[16]: customization.md#overriding-partials
[17]: customization.md#overriding-partials
### More advanced customization
If you want to change the general appearance of the Material theme, see
[this article][17] for more information on advanced customization.
[this article][18] for more information on advanced customization.
[17]: customization.md
[18]: customization.md
## Extensions
MkDocs supports several [Markdown extensions][18]. The following extensions
MkDocs supports several [Markdown extensions][19]. 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:
@ -351,18 +367,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][19]
* [Codehilite][20]
* [Permalinks][21]
* [Footnotes][22]
* [PyMdown Extensions][23]
* [Admonition][20]
* [Codehilite][21]
* [Permalinks][22]
* [Footnotes][23]
* [PyMdown Extensions][24]
[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
[19]: http://www.mkdocs.org/user-guide/writing-your-docs/#markdown-extensions
[20]: extensions/admonition.md
[21]: extensions/codehilite.md
[22]: extensions/permalinks.md
[23]: extensions/footnotes.md
[24]: extensions/pymdown.md
## Full example
@ -380,7 +396,7 @@ repo_name: 'GitHub'
repo_url: 'https://github.com/my-github-handle/my-project'
# Copyright
copyright: 'Copyright &copy; 2016 John Doe'
copyright: 'Copyright &copy; 2016 - 2017 John Doe'
# Documentation and theme
theme: 'material'
@ -394,13 +410,14 @@ extra:
font:
text: 'Roboto'
code: 'Roboto Mono'
disqus: 'your-disqus-shortname'
social:
- type: 'github'
link: 'https://github.com/squidfunk'
link: 'https://github.com/john-doe'
- type: 'twitter'
link: 'https://twitter.com/squidfunk'
link: 'https://twitter.com/jonh-doe'
- type: 'linkedin'
link: 'https://de.linkedin.com/in/martin-donath-20a95039'
link: 'https://de.linkedin.com/in/john-doe'
# Google Analytics
google_analytics:

View File

@ -2,7 +2,7 @@
**MIT License**
Copyright &copy; 2016 Martin Donath
Copyright &copy; 2016 - 2017 Martin Donath
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to

View File

@ -12,11 +12,29 @@ To determine the currently installed version, use the following command:
``` sh
pip show mkdocs-material | grep -E ^Version
# Version 1.0.3
# Version 1.0.4
```
## Changelog
### 1.0.5 <small> _ February 18, 2017</small>
* Fixed [#153][153]: Sidebar flows out of constrained area in Chrome 56
* Fixed [#159][159]: Footer jitter due to JavaScript if content is short
[153]: https://github.com/squidfunk/mkdocs-material/issues/153
[159]: https://github.com/squidfunk/mkdocs-material/issues/159
### 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

View File

@ -137,6 +137,24 @@ tincidunt. Aenean ullamcorper sit amet nulla at interdum.
sagittis. Aliquam purus tellus, faucibus eget urna at, iaculis venenatis
nulla. Vivamus a pharetra leo.
### Definition lists
Lorem ipsum dolor sit amet
: Sed sagittis eleifend rutrum. Donec vitae suscipit est. Nullam tempus
tellus non sem sollicitudin, quis rutrum leo facilisis. Nulla tempor
lobortis orci, at elementum urna sodales vitae. In in vehicula nulla.
Duis mollis est eget nibh volutpat, fermentum aliquet dui mollis.
Nam vulputate tincidunt fringilla.
Nullam dignissim ultrices urna non auctor.
Cras arcu libero
: Aliquam metus eros, pretium sed nulla venenatis, faucibus auctor ex. Proin
ut eros sed sapien ullamcorper consequat. Nunc ligula ante, fringilla at
aliquam ac, aliquet sed mauris.
## Code blocks
### Inline

View File

@ -0,0 +1,36 @@
/*
* 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.
*/
/* ----------------------------------------------------------------------------
* Declarations
* ------------------------------------------------------------------------- */
declare module "fastclick" {
/* Type: FastClick */
declare type FastClick = {
attach(name: HTMLElement): void
}
/* Exports */
declare export default FastClick
}

View File

@ -21,45 +21,23 @@
*/
/* ----------------------------------------------------------------------------
* Class
* Declarations
* ------------------------------------------------------------------------- */
export default class Container {
declare module "js-cookie" {
/**
* Monitor window height to stretch sidebar container to viewport
*
* @constructor
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {
this.el_ = (typeof el === "string")
? document.querySelector(el)
: el
/* Retrieve parent node */
this.parent_ = this.el_.parentNode
/* Type: Options for setting cookie values */
declare type Options = {
path?: string,
expires?: number | string
}
/**
* Initialize container state
*/
setup() {
this.update()
/* Type: Cookie */
declare type Cookie = {
getJSON(json: string): Object,
set(key: string, value: string, options?: Options): string
}
/**
* Update minimum height
*/
update() {
const height = this.parent_.offsetHeight - this.el_.offsetTop
this.el_.style.minHeight = `${height}px`
}
/**
* Reset minimum height
*/
reset() {
this.el_.style.minHeight = ""
}
/* Exports */
declare export default Cookie
}

34
lib/declarations/jsx.js Normal file
View File

@ -0,0 +1,34 @@
/*
* 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.
*/
/* ----------------------------------------------------------------------------
* Declarations
* ------------------------------------------------------------------------- */
declare class Jsx {
static createElement(tag: string, properties?: Object,
...children?: Array<string | number | Array<HTMLElement>>
): HTMLElement
}
/* Exports */
declare export default Jsx

34
lib/declarations/lunr.js Normal file
View File

@ -0,0 +1,34 @@
/*
* 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.
*/
/* ----------------------------------------------------------------------------
* Declarations
* ------------------------------------------------------------------------- */
/*
* Currently, it's not possible to export a function that returns a class type,
* as the imports just don't correctly work with flow. As a workaround we
* export an object until this error is fixed.
*/
declare module "lunr" {
declare function exports(name: () => void): Object
}

View File

@ -0,0 +1,32 @@
/*
* 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.
*/
/* ----------------------------------------------------------------------------
* Declarations
* ------------------------------------------------------------------------- */
declare class Modernizr {
static addTest(name: string, test: () => boolean): void
}
/* Exports */
declare export default Modernizr

View File

@ -24,13 +24,13 @@
* Module
* ------------------------------------------------------------------------- */
export default /* JSX */ {
export default /* Jsx */ {
/**
* Create a native DOM node from JSX's intermediate representation
*
* @param {string} tag - Tag name
* @param {object} properties - Properties
* @param {?Object} properties - Properties
* @param {...(string|number|Array)} children - Child nodes
* @return {HTMLElement} Native DOM node
*/

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 { transform } from "babel-core"
import jsdoc2flow from "flow-jsdoc"
import through from "through2"
/* ----------------------------------------------------------------------------
* Task: annotate JavaScript
* ------------------------------------------------------------------------- */
export default (gulp, config) => {
return () => {
return gulp.src(`${config.assets.src}/javascripts/**/*.{js,jsx}`)
/* Linting */
.pipe(
through.obj(function(file, enc, done) {
if (file.isNull() || file.isStream())
return done()
/* Perform Babel transformation to resolve JSX calls */
const transformed = transform(file.contents.toString(), {
plugins: [
["transform-react-jsx", {
"pragma": "Jsx.createElement"
}]
]
})
/* Annotate contents */
file.contents = new Buffer(jsdoc2flow(
`/* @flow */\n\n${transformed.code}`
).toString())
/* Push file to next stage */
this.push(file)
done()
}))
/* Print errors */
.pipe(gulp.dest("tmp/assets/javascripts"))
}
}

View File

@ -70,7 +70,7 @@ export default (gulp, config, args) => {
/* Provide JSX helper */
new webpack.ProvidePlugin({
JSX: path.join(process.cwd(), `${config.lib}/providers/jsx.js`)
Jsx: path.join(process.cwd(), `${config.lib}/providers/jsx.js`)
})
].concat(

View File

@ -39,7 +39,7 @@ const format = eslint.getFormatter()
export default (gulp, config) => {
return () => {
return gulp.src(`${config.assets.src}/javascripts/**/*.js`)
return gulp.src(`${config.assets.src}/javascripts/**/*.{js,jsx}`)
/* Linting */
.pipe(

View File

@ -51,10 +51,10 @@ export default (gulp, config) => {
cwd: path.dirname(file.path)
})
/* Emit error, if any */
/* Emit error, if any */
if (proc.status)
this.emit("error", new util.PluginError("mkdocs",
`Terminated with errors: ${proc.stderr.toString()}`))
`Terminated with errors: ${proc.stderr.toString()}`))
/* Terminate */
done()

View File

@ -38,27 +38,35 @@ export default (gulp, config) => {
/* Open SauceConnect tunnel */
}).then(() => {
return new Promise((resolve, reject) => {
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)
})
/* 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(() => {
.then(runner => {
return new Promise(resolve => {
process.on("SIGINT", () => {
sauce.stop(resolve)
return runner
? runner.stop(resolve)
: resolve()
})
})
})

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

View File

@ -19,7 +19,7 @@
{% else %}
<link rel="shortcut icon" href="{{ base_url }}/assets/images/favicon.png">
{% endif %}
<meta name="generator" content="mkdocs-{{ mkdocs_version }}, mkdocs-material-1.0.3">
<meta name="generator" content="mkdocs-{{ mkdocs_version }}, mkdocs-material-1.0.5">
{% endblock %}
{% block htmltitle %}
{% if page.title and not page.is_homepage %}
@ -29,10 +29,10 @@
{% endif %}
{% endblock %}
{% block libs %}
<script src="{{ base_url }}/assets/javascripts/modernizr-5b0c41c2b5.js"></script>
<script src="{{ base_url }}/assets/javascripts/modernizr-56ade86843.js"></script>
{% endblock %}
{% block styles %}
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-932e030699.css">
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-a7dac97dbb.css">
{% if config.extra.palette %}
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-02ce7adcc2.palette.css">
{% endif %}
@ -117,6 +117,23 @@
{% endif %}
{{ page.content }}
{% endblock %}
{% if config.extra.disqus and not page.is_homepage %}
<h2>{{ lang.t('comments') }}</h2>
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
this.page.url = "{{ page.canonical_url }}";
this.page.identifier =
"{{ page.canonical_url | replace(config.site_url, "") }}";
};
(function() {
var d = document, s = d.createElement("script");
s.src = "//{{ config.extra.disqus }}.disqus.com/embed.js";
s.setAttribute("data-timestamp", +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
{% endif %}
</article>
</div>
</div>
@ -126,7 +143,7 @@
{% endblock %}
</div>
{% block scripts %}
<script src="{{ base_url }}/assets/javascripts/application-c7c31dee65.js"></script>
<script src="{{ base_url }}/assets/javascripts/application-8dc3dfc020.js"></script>
<script>app.initialize({url:{base:"{{ base_url }}"}})</script>
{% for path in extra_javascript %}
<script src="{{ path }}"></script>

View File

@ -1,5 +1,6 @@
{% macro t(key) %}{{ {
"edit.link.title": "Edit this page",
"comments": "Comments",
"footer.previous": "Previous",
"footer.next": "Next",
"search.placeholder": "Search",

View File

@ -3,7 +3,7 @@
<div class="md-search__overlay"></div>
<div class="md-search__inner">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="{{ lang.t('search.placeholder') }}" accesskey="s" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false">
<input type="text" class="md-search__input" name="query" placeholder="{{ lang.t('search.placeholder') }}" accesskey="s" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query">
<label class="md-icon md-search__icon" for="search"></label>
</form>
<div class="md-search__output">

View File

@ -53,6 +53,7 @@ extra:
markdown_extensions:
- markdown.extensions.admonition
- markdown.extensions.codehilite(guess_lang=false)
- markdown.extensions.def_list
- markdown.extensions.footnotes
- markdown.extensions.meta
- markdown.extensions.toc(permalink=true)

View File

@ -1,6 +1,6 @@
{
"name": "mkdocs-material",
"version": "1.0.3",
"version": "1.0.5",
"description": "A Material Design theme for MkDocs",
"keywords": [
"mkdocs",
@ -25,6 +25,7 @@
"scripts": {
"build": "scripts/build",
"clean": "scripts/clean",
"flow": "scripts/flow",
"lint": "scripts/lint",
"start": "scripts/start",
"test:visual:run": "scripts/test/visual/run",
@ -33,26 +34,28 @@
},
"dependencies": {},
"devDependencies": {
"autoprefixer": "^6.6.1",
"babel-core": "^6.0.0",
"autoprefixer": "^6.7.3",
"babel-core": "^6.23.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.22.0",
"babel-register": "^6.18.0",
"babel-register": "^6.23.0",
"babel-root-import": "^4.1.5",
"core-js": "^2.4.1",
"css-mqpacker": "^5.0.1",
"custom-event-polyfill": "^0.3.0",
"del": "^2.2.2",
"ecstatic": "^2.1.0",
"eslint": "^3.14.0",
"eslint": "^3.16.0",
"fastclick": "^1.0.6",
"flow-bin": "^0.39.0",
"flow-jsdoc": "^0.2.2",
"git-hooks": "^1.1.7",
"gulp": "^3.9.1",
"gulp-changed": "^1.3.2",
"gulp-changed": "^2.0.0",
"gulp-concat": "^2.6.1",
"gulp-cssnano": "^2.1.2",
"gulp-htmlmin": "^3.0.0",
@ -72,15 +75,15 @@
"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",
"lunr": "^1.0.0",
"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.1.0",
"postcss-pseudo-classes": "^0.2.0",
"stylelint": "^7.8.0",
"stylelint-config-standard": "^16.0.0",
"stylelint-order": "^0.2.2",
"stylelint-order": "^0.3.0",
"stylelint-scss": "^1.4.1",
"through2": "^2.0.3",
"vinyl-paths": "^2.1.0",
@ -93,14 +96,6 @@
"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",
"karma-mocha": "^1.3.0",
"karma-notify-reporter": "^1.0.1",
"karma-sourcemap-loader": "^0.3.7",
"karma-spec-reporter": "0.0.26",
"karma-webpack": "^2.0.1",
"mocha": "^3.2.0",
"moniker": "^0.1.2",
"saucelabs": "^1.4.0",

44
scripts/flow Executable file
View File

@ -0,0 +1,44 @@
#!/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
# Annotate source files
`npm bin`/gulp assets:javascripts:annotate "$@"
FLOW_JSDOC=$?
# Run flow typecheck
`npm bin`/flow check tmp
FLOW=$?
# If one command failed, exit with error
if [ $FLOW_JSDOC -gt 0 ] || [ $FLOW -gt 0 ]; then
exit 1
fi;
# Otherwise return with success
exit 0

View File

@ -4,7 +4,7 @@
],
"plugins": [
["transform-react-jsx", {
"pragma": "JSX.createElement"
"pragma": "Jsx.createElement"
}]
]
}

View File

@ -27,35 +27,40 @@ import Material from "./components/Material"
* Application
* ------------------------------------------------------------------------- */
export const initialize = config => {
/**
* Initialize Material for MkDocs
*
* @param {Object} config - Configuration
*/
function initialize(config) { // eslint-disable-line func-style
/* Initialize Modernizr and FastClick */
new Material.Event.Listener(document, "DOMContentLoaded", () => {
if (!(document.body instanceof HTMLElement))
throw new ReferenceError
/* Attach FastClick to mitigate 300ms delay on touch devices */
FastClick.attach(document.body)
/* Test for iOS */
Modernizr.addTest("ios", () => {
return !!navigator.userAgent.match(/(iPad|iPhone|iPod)/g)
})
/* Test for web application context */
Modernizr.addTest("standalone", () => {
return !!navigator.standalone
})
/* Attach FastClick to mitigate 300ms delay on touch devices */
FastClick.attach(document.body)
/* 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")
const wrap = (
<div class="md-typeset__scrollwrap">
<div class="md-typeset__table"></div>
</div>
)
if (table.nextSibling) {
table.parentNode.insertBefore(wrap, table.nextSibling)
} else {
table.parentNode.appendChild(wrap)
}
wrap.appendChild(table)
wrap.children[0].appendChild(table)
})
/* Force 1px scroll offset to trigger overflow scrolling */
@ -89,13 +94,6 @@ export const initialize = config => {
"scroll", "resize", "orientationchange"
], new Material.Tabs.Toggle("[data-md-component=tabs]")).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, [
@ -139,7 +137,7 @@ export const initialize = config => {
new Material.Search.Lock("[data-md-toggle=search]")))
/* Component: search results */
new Material.Event.Listener(document.forms.search.query, [
new Material.Event.Listener("[data-md-component=query]", [
"focus", "keyup"
], new Material.Search.Result("[data-md-component=result]", () => {
return fetch(`${config.url.base}/mkdocs/search_index.json`, {
@ -163,6 +161,8 @@ export const initialize = config => {
new Material.Event.Listener("[data-md-component=navigation] [href^='#']",
"click", () => {
const toggle = document.querySelector("[data-md-toggle=drawer]")
if (!(toggle instanceof HTMLInputElement))
throw new ReferenceError
if (toggle.checked) {
toggle.checked = false
toggle.dispatchEvent(new CustomEvent("change"))
@ -172,16 +172,23 @@ export const initialize = config => {
/* 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)
if (!(toggle instanceof HTMLInputElement))
throw new ReferenceError
if (toggle.checked) {
const query = document.querySelector("[data-md-component=query]")
if (!(query instanceof HTMLInputElement))
throw new ReferenceError
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", () => {
new Material.Event.Listener("[data-md-component=query]", "focus", () => {
const toggle = document.querySelector("[data-md-toggle=search]")
if (!(toggle instanceof HTMLInputElement))
throw new ReferenceError
if (!toggle.checked) {
toggle.checked = true
toggle.dispatchEvent(new CustomEvent("change"))
@ -192,6 +199,8 @@ export const initialize = config => {
new Material.Event.MatchMedia("(min-width: 960px)",
new Material.Event.Listener(document.body, "click", () => {
const toggle = document.querySelector("[data-md-toggle=search]")
if (!(toggle instanceof HTMLInputElement))
throw new ReferenceError
if (toggle.checked) {
toggle.checked = false
toggle.dispatchEvent(new CustomEvent("change"))
@ -203,10 +212,15 @@ export const initialize = config => {
const code = ev.keyCode || ev.which
if (code === 27) {
const toggle = document.querySelector("[data-md-toggle=search]")
if (!(toggle instanceof HTMLInputElement))
throw new ReferenceError
if (toggle.checked) {
toggle.checked = false
toggle.dispatchEvent(new CustomEvent("change"))
document.forms.search.query.blur()
const query = document.querySelector("[data-md-component=query]")
if (!(query instanceof HTMLInputElement))
throw new ReferenceError
query.focus()
}
}
}).listen()
@ -224,13 +238,16 @@ export const initialize = config => {
/* Retrieve facts for the given repository type */
;(() => {
const el = document.querySelector("[data-md-source]")
if (!el) return Promise.resolve([])
if (!el)
return Promise.resolve([])
else if (!(el instanceof HTMLAnchorElement))
throw new ReferenceError
switch (el.dataset.mdSource) {
case "github": return new Material.Source.Adapter.GitHub(el).fetch()
default: return Promise.resolve([])
}
/* Render repository source information */
/* Render repository information */
})().then(facts => {
const sources = document.querySelectorAll("[data-md-source]")
Array.prototype.forEach.call(sources, source => {
@ -239,3 +256,11 @@ export const initialize = config => {
})
})
}
/* ----------------------------------------------------------------------------
* Exports
* ------------------------------------------------------------------------- */
export {
initialize
}

View File

@ -30,14 +30,22 @@ export default class Listener {
* Generic event listener
*
* @constructor
* @param {(string|NodeList<HTMLElement>)} els - Selector or HTML elements
* @param {Array.<string>} events - Event names
* @param {(object|function)} handler - Handler to be invoked
*
* @property {(Array<EventTarget>)} els_ - Event targets
* @property {Object} handler_- Event handlers
* @property {Array<string>} events_ - Event names
* @property {Function} update_ - Update handler
*
* @param {?(string|EventTarget|NodeList<EventTarget>)} els -
* Selector or Event targets
* @param {(string|Array<string>)} events - Event names
* @param {(Object|Function)} handler - Handler to be invoked
*/
constructor(els, events, handler) {
this.els_ = (typeof els === "string")
? document.querySelectorAll(els)
: [].concat(els)
this.els_ = Array.prototype.slice.call(
(typeof els === "string")
? document.querySelectorAll(els)
: [].concat(els))
/* Set handler as function or directly as object */
this.handler_ = typeof handler === "function"
@ -53,7 +61,7 @@ export default class Listener {
* Register listener for all relevant events
*/
listen() {
Array.prototype.forEach.call(this.els_, el => {
this.els_.forEach(el => {
this.events_.forEach(event => {
el.addEventListener(event, this.update_, false)
})
@ -68,7 +76,7 @@ export default class Listener {
* Unregister listener for all relevant events
*/
unlisten() {
Array.prototype.forEach.call(this.els_, el => {
this.els_.forEach(el => {
this.events_.forEach(event => {
el.removeEventListener(event, this.update_)
})

View File

@ -20,6 +20,8 @@
* IN THE SOFTWARE.
*/
import Listener from "./Listener" // eslint-disable-line no-unused-vars
/* ----------------------------------------------------------------------------
* Class
* ------------------------------------------------------------------------- */
@ -33,6 +35,9 @@ export default class MatchMedia {
* switches the given listeners on or off.
*
* @constructor
*
* @property {Function} handler_ - Media query event handler
*
* @param {string} query - Media query to test for
* @param {Listener} listener - Event listener
*/

View File

@ -27,19 +27,29 @@
export default class Shadow {
/**
* Show the header shadow depending on scroll offset
* Show or hide header shadow depending on page y-offset
*
* @constructor
*
* @property {HTMLElement} el_ - Content container
* @property {HTMLElement} header_ - Header
* @property {number} height_ - Offset height of previous nodes
* @property {boolean} active_ - Header shadow state
*
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {
this.el_ = (typeof el === "string")
const ref = (typeof el === "string")
? document.querySelector(el)
: el
if (!(ref instanceof Node) ||
!(ref.parentNode instanceof HTMLElement) ||
!(ref.parentNode.previousElementSibling instanceof HTMLElement))
throw new ReferenceError
/* Grab parent and header */
this.el_ = this.el_.parentNode
this.header_ = this.el_.parentNode.previousElementSibling
this.el_ = ref.parentNode
this.header_ = ref.parentNode.previousElementSibling
/* Initialize height and state */
this.height_ = 0
@ -51,8 +61,11 @@ export default class Shadow {
*/
setup() {
let current = this.el_
while ((current = current.previousElementSibling))
while ((current = current.previousElementSibling)) {
if (!(current instanceof HTMLElement))
throw new ReferenceError
this.height_ += current.offsetHeight
}
this.update()
}

View File

@ -27,9 +27,16 @@
export default class Blur {
/**
* Blur anchors within the navigation above current page y-offset
* Blur links within the table of contents above current page y-offset
*
* @constructor
*
* @property {NodeList<HTMLElement>} els_ - Table of contents links
* @property {Array<HTMLElement>} anchors_ - Referenced anchor nodes
* @property {number} index_ - Current link index
* @property {number} offset_ - Current page y-offset
* @property {boolean} dir_ - Scroll direction change
*
* @param {(string|NodeList<HTMLElement>)} els - Selector or HTML elements
*/
constructor(els) {
@ -38,27 +45,28 @@ export default class Blur {
: els
/* Initialize index and page y-offset */
this.index_ = 0
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))
})
this.anchors_ = [].reduce.call(this.els_, (anchors, el) => {
return anchors.concat(
document.getElementById(el.hash.substring(1)) || [])
}, [])
}
/**
* Initialize anchor states
* Initialize blur states
*/
setup() {
this.update()
}
/**
* Update anchor states
* Update blur states
*
* Deduct the static offset of the header (56px) and sidebar offset (24px),
* see _permalinks.scss for more information.
@ -67,7 +75,7 @@ export default class Blur {
const offset = window.pageYOffset
const dir = this.offset_ - offset < 0
/* Hack: reset index if direction changed, to catch very fast scrolling,
/* 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
@ -109,7 +117,7 @@ export default class Blur {
}
/**
* Reset anchor states
* Reset blur states
*/
reset() {
Array.prototype.forEach.call(this.els_, el => {

View File

@ -30,12 +30,18 @@ export default class Collapse {
* Expand or collapse navigation on toggle
*
* @constructor
*
* @property {HTMLElement} el_ - Navigation list
*
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {
this.el_ = (typeof el === "string")
const ref = (typeof el === "string")
? document.querySelector(el)
: el
if (!(ref instanceof HTMLElement))
throw new ReferenceError
this.el_ = ref
}
/**
@ -75,11 +81,16 @@ export default class Collapse {
/* Remove state on end of transition */
const end = ev => {
ev.target.removeAttribute("data-md-state")
ev.target.style.maxHeight = ""
const target = ev.target
if (!(target instanceof HTMLElement))
throw new ReferenceError
/* Reset height and state */
target.removeAttribute("data-md-state")
target.style.maxHeight = ""
/* Only fire once, so directly remove event listener */
ev.target.removeEventListener("transitionend", end)
target.removeEventListener("transitionend", end)
}
this.el_.addEventListener("transitionend", end, false)
}

View File

@ -30,12 +30,18 @@ export default class Scrolling {
* Set overflow scrolling on the current active pane (for iOS)
*
* @constructor
*
* @property {HTMLElement} el_ - Primary navigation
*
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {
this.el_ = (typeof el === "string")
const ref = (typeof el === "string")
? document.querySelector(el)
: el
if (!(ref instanceof HTMLElement))
throw new ReferenceError
this.el_ = ref
}
/**
@ -49,13 +55,22 @@ export default class Scrolling {
/* Find all toggles and check which one is active */
const toggles = this.el_.querySelectorAll("[data-md-toggle]")
Array.prototype.forEach.call(toggles, toggle => {
if (!(toggle instanceof HTMLInputElement))
throw new ReferenceError
if (toggle.checked) {
/* Find corresponding navigational pane */
let pane = toggle.nextElementSibling
while (pane.tagName !== "NAV")
if (!(pane instanceof HTMLElement))
throw new ReferenceError
while (pane.tagName !== "NAV" && pane.nextElementSibling)
pane = pane.nextElementSibling
/* Check references */
if (!(toggle.parentNode instanceof HTMLElement) ||
!(toggle.parentNode.parentNode instanceof HTMLElement))
throw new ReferenceError
/* Find current and parent list elements */
const parent = toggle.parentNode.parentNode
const target = pane.children[pane.children.length - 1]
@ -73,34 +88,48 @@ export default class Scrolling {
* @param {Event} ev - Change event
*/
update(ev) {
const target = ev.target
if (!(target instanceof HTMLElement))
throw new ReferenceError
/* Find corresponding navigational pane */
let pane = ev.target.nextElementSibling
while (pane.tagName !== "NAV")
let pane = target.nextElementSibling
if (!(pane instanceof HTMLElement))
throw new ReferenceError
while (pane.tagName !== "NAV" && pane.nextElementSibling)
pane = pane.nextElementSibling
/* Find current and parent list elements */
const parent = ev.target.parentNode.parentNode
const target = pane.children[pane.children.length - 1]
/* Check references */
if (!(target.parentNode instanceof HTMLElement) ||
!(target.parentNode.parentNode instanceof HTMLElement))
throw new ReferenceError
/* Find parent and active panes */
const parent = target.parentNode.parentNode
const active = pane.children[pane.children.length - 1]
/* Always reset all lists when transitioning */
parent.style.webkitOverflowScrolling = ""
target.style.webkitOverflowScrolling = ""
active.style.webkitOverflowScrolling = ""
/* Set overflow scrolling on parent */
if (!ev.target.checked) {
/* Set overflow scrolling on parent pane */
if (!target.checked) {
const end = () => {
parent.style.webkitOverflowScrolling = "touch"
pane.removeEventListener("transitionend", end)
if (pane instanceof HTMLElement) {
parent.style.webkitOverflowScrolling = "touch"
pane.removeEventListener("transitionend", end)
}
}
pane.addEventListener("transitionend", end, false)
}
/* Set overflow scrolling on target */
if (ev.target.checked) {
/* Set overflow scrolling on active pane */
if (target.checked) {
const end = () => {
target.style.webkitOverflowScrolling = "touch"
pane.removeEventListener("transitionend", end, false)
if (pane instanceof HTMLElement) {
active.style.webkitOverflowScrolling = "touch"
pane.removeEventListener("transitionend", end)
}
}
pane.addEventListener("transitionend", end, false)
}
@ -117,20 +146,29 @@ export default class Scrolling {
/* Find all toggles and check which one is active */
const toggles = this.el_.querySelectorAll("[data-md-toggle]")
Array.prototype.forEach.call(toggles, toggle => {
if (!(toggle instanceof HTMLInputElement))
throw new ReferenceError
if (toggle.checked) {
/* Find corresponding navigational pane */
let pane = toggle.nextElementSibling
while (pane.tagName !== "NAV")
if (!(pane instanceof HTMLElement))
throw new ReferenceError
while (pane.tagName !== "NAV" && pane.nextElementSibling)
pane = pane.nextElementSibling
/* Find current and parent list elements */
/* Check references */
if (!(toggle.parentNode instanceof HTMLElement) ||
!(toggle.parentNode.parentNode instanceof HTMLElement))
throw new ReferenceError
/* Find parent and active panes */
const parent = toggle.parentNode.parentNode
const target = pane.children[pane.children.length - 1]
const active = pane.children[pane.children.length - 1]
/* Always reset all lists when transitioning */
parent.style.webkitOverflowScrolling = ""
target.style.webkitOverflowScrolling = ""
active.style.webkitOverflowScrolling = ""
}
})
}

View File

@ -30,12 +30,25 @@ export default class Lock {
* Lock body for full-screen search modal
*
* @constructor
*
* @property {HTMLInputElement} el_ - Lock toggle
* @property {HTMLElement} lock_ - Element to lock (document body)
* @property {number} offset_ - Current page y-offset
*
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {
this.el_ = (typeof el === "string")
const ref = (typeof el === "string")
? document.querySelector(el)
: el
if (!(ref instanceof HTMLInputElement))
throw new ReferenceError
this.el_ = ref
/* Retrieve element to lock (= body) */
if (!document.body)
throw new ReferenceError
this.lock_ = document.body
}
/**
@ -60,13 +73,13 @@ export default class Lock {
/* Lock body after finishing transition */
if (this.el_.checked) {
document.body.dataset.mdState = "lock"
this.lock_.dataset.mdState = "lock"
}
}, 400)
/* Exiting search mode */
} else {
document.body.dataset.mdState = ""
this.lock_.dataset.mdState = ""
/* Scroll to former position, but wait for 100ms to prevent flashes on
iOS. A short timeout seems to do the trick */
@ -81,8 +94,8 @@ export default class Lock {
* Reset locked state and page y-offset
*/
reset() {
if (document.body.dataset.mdState === "lock")
if (this.lock_.dataset.mdState === "lock")
window.scrollTo(0, this.offset_)
document.body.dataset.mdState = ""
this.lock_.dataset.mdState = ""
}
}

View File

@ -32,13 +32,24 @@ export default class Result {
* Perform search and update results on keyboard events
*
* @constructor
*
* @property {HTMLElement} el_ - Search result container
* @property {(Array<Object>|Function)} data_ - Raw document data
* @property {Object} docs_ - Indexed documents
* @property {HTMLElement} meta_ - Search meta information
* @property {HTMLElement} list_ - Search result list
* @property {Object} index_ - Search index
*
* @param {(string|HTMLElement)} el - Selector or HTML element
* @param {(Array.<object>|Function)} data - Promise or array providing data
* @param {(Array<Object>|Function)} data - Function providing data or array
*/
constructor(el, data) {
this.el_ = (typeof el === "string")
const ref = (typeof el === "string")
? document.querySelector(el)
: el
if (!(ref instanceof HTMLElement))
throw new ReferenceError
this.el_ = ref
/* Set data and create metadata and list elements */
this.data_ = data
@ -54,19 +65,26 @@ export default class Result {
/* Inject created elements */
this.el_.appendChild(this.meta_)
this.el_.appendChild(this.list_)
}
/* Truncate a string after the given number of characters - this is not
a reasonable approach, since the summaries kind of suck. It would be
better to create something more intelligent, highlighting the search
occurrences and making a better summary out of it */
this.truncate_ = function(string, n) {
let i = n
if (string.length > i) {
while (string[i] !== " " && --i > 0);
return `${string.substring(0, i)}...`
}
return string
/**
* Truncate a string after the given number of character
*
* This is not a reasonable approach, since the summaries kind of suck. It
* would be better to create something more intelligent, highlighting the
* search occurrences and making a better summary out of it
*
* @param {string} string - String to be truncated
* @param {number} n - Number of characters
* @return {string} Truncated string
*/
truncate_(string, n) {
let i = n
if (string.length > i) {
while (string[i] !== " " && --i > 0);
return `${string.substring(0, i)}...`
}
return string
}
/**
@ -90,7 +108,7 @@ export default class Result {
})
/* Index documents */
this.data_ = data.reduce((docs, doc) => {
this.docs_ = data.reduce((docs, doc) => {
this.index_.add(doc)
docs[doc.location] = doc
return docs
@ -104,15 +122,20 @@ export default class Result {
: init(this.data_)
}, 250)
/* Execute search on new input event after clearing current list */
/* Execute search on new input event */
} else if (ev.type === "keyup") {
const target = ev.target
if (!(target instanceof HTMLInputElement))
throw new ReferenceError
/* Clear current list */
while (this.list_.firstChild)
this.list_.removeChild(this.list_.firstChild)
/* Perform search on index and render documents */
const result = this.index_.search(ev.target.value)
const result = this.index_.search(target.value)
result.forEach(item => {
const doc = this.data_[item.ref]
const doc = this.docs_[item.ref]
/* Check if it's a anchor link on the current page */
let [pathname] = doc.location.split("#")
@ -143,6 +166,8 @@ export default class Result {
Array.prototype.forEach.call(anchors, anchor => {
anchor.addEventListener("click", ev2 => {
const toggle = document.querySelector("[data-md-toggle=search]")
if (!(toggle instanceof HTMLInputElement))
throw new ReferenceError
if (toggle.checked) {
toggle.checked = false
toggle.dispatchEvent(new CustomEvent("change"))

View File

@ -20,7 +20,6 @@
* IN THE SOFTWARE.
*/
import Container from "./Sidebar/Container"
import Position from "./Sidebar/Position"
/* ----------------------------------------------------------------------------
@ -28,6 +27,5 @@ import Position from "./Sidebar/Position"
* ------------------------------------------------------------------------- */
export default {
Container,
Position
}

View File

@ -30,15 +30,25 @@ export default class Position {
* Set sidebars to locked state and limit height to parent node
*
* @constructor
*
* @property {HTMLElement} el_ - Sidebar
* @property {HTMLElement} parent_ - Sidebar container
* @property {number} height_ - Current sidebar height
* @property {number} offset_ - Current page y-offset
*
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {
this.el_ = (typeof el === "string")
const ref = (typeof el === "string")
? document.querySelector(el)
: el
if (!(ref instanceof HTMLElement) ||
!(ref.parentNode instanceof HTMLElement))
throw new ReferenceError
this.el_ = ref
/* Initialize parent container and current height */
this.parent_ = this.el_.parentNode
this.parent_ = ref.parentNode
this.height_ = 0
}
@ -65,15 +75,15 @@ export default class Position {
/* Set bounds of sidebar container - must be calculated on every run, as
the height of the content might change due to loading images etc. */
this.bounds_ = {
const bounds = {
top: 56,
bottom: this.parent_.offsetTop + this.parent_.offsetHeight
}
/* Calculate new offset and height */
const height = visible - this.bounds_.top
const height = visible - bounds.top
- Math.max(0, this.offset_ - offset)
- Math.max(0, offset + visible - this.bounds_.bottom)
- Math.max(0, offset + visible - bounds.bottom)
/* If height changed, update element */
if (height !== this.height_)

View File

@ -29,16 +29,25 @@ import Cookies from "js-cookie"
export default class Abstract {
/**
* Retrieve source information
* Retrieve repository information
*
* @constructor
* @param {(string|HTMLElement)} el - Selector or HTML element
*
* @property {HTMLAnchorElement} el_ - Link to repository
* @property {string} base_ - API base URL
* @property {number} salt_ - Unique identifier
*
* @param {(string|HTMLAnchorElement)} el - Selector or HTML element
*/
constructor(el) {
this.el_ = (typeof el === "string")
const ref = (typeof el === "string")
? document.querySelector(el)
: el
if (!(ref instanceof HTMLAnchorElement))
throw new ReferenceError
this.el_ = ref
/* Retrieve base URL */
this.base_ = this.el_.href
this.salt_ = this.hash_(this.base_)
@ -47,7 +56,7 @@ export default class Abstract {
/**
* Retrieve data from Cookie or fetch from respective API
*
* @return {Promise} Promise that returns an array of facts
* @return {Promise<Array<string>>} Promise that returns an array of facts
*/
fetch() {
return new Promise(resolve => {
@ -70,7 +79,6 @@ export default class Abstract {
* Abstract private function that fetches relevant repository information
*
* @abstract
* @return {Promise} Promise that provides the facts in an array
*/
fetch_() {
throw new Error("fetch_(): Not implemented")
@ -79,15 +87,15 @@ export default class Abstract {
/**
* Format a number with suffix
*
* @param {Number} number - Number to format
* @return {Number} Formatted number
* @param {number} number - Number to format
* @return {string} Formatted number
*/
format_(number) {
if (number > 10000)
return `${(number / 1000).toFixed(0)}k`
else if (number > 1000)
return `${(number / 1000).toFixed(1)}k`
return number
return `${number}`
}
/**
@ -96,7 +104,7 @@ export default class Abstract {
* Taken from http://stackoverflow.com/a/7616484/1065584
*
* @param {string} str - Input string
* @return {string} Hashed string
* @return {number} Hashed string
*/
hash_(str) {
let hash = 0

View File

@ -29,10 +29,10 @@ import Abstract from "./Abstract"
export default class GitHub extends Abstract {
/**
* Retrieve source information from GitHub
* Retrieve repository information from GitHub
*
* @constructor
* @param {(string|HTMLElement)} el - Selector or HTML element
* @param {(string|HTMLAnchorElement)} el - Selector or HTML element
*/
constructor(el) {
super(el)
@ -42,9 +42,9 @@ export default class GitHub extends Abstract {
}
/**
* Fetch relevant source information from GitHub
* Fetch relevant repository information from GitHub
*
* @return {function} Promise returning an array of facts
* @return {Promise<Array<string>>} Promise returning an array of facts
*/
fetch_() {
return fetch(this.base_)

View File

@ -30,21 +30,27 @@ export default class Repository {
* Render repository information
*
* @constructor
*
* @property {HTMLElement} el_ - Repository information
*
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {
this.el_ = (typeof el === "string")
const ref = (typeof el === "string")
? document.querySelector(el)
: el
if (!(ref instanceof HTMLElement))
throw new ReferenceError
this.el_ = ref
}
/**
* Initialize the source repository
* Initialize the repository
*
* @param {Array.<string>} facts - Facts to be rendered
* @param {Array<string>} facts - Facts to be rendered
*/
initialize(facts) {
if (facts.length)
if (facts.length && this.el_.children.length)
this.el_.children[this.el_.children.length - 1].appendChild(
<ul class="md-source__facts">
{facts.map(fact => <li class="md-source__fact">{fact}</li>)}

View File

@ -27,18 +27,26 @@
export default class Toggle {
/**
* Show tabs depending on scroll offset
* Toggle tabs visibility depending on page y-offset
*
* @constructor
*
* @property {HTMLElement} el_ - Content container
* @property {number} offset_ - Toggle page-y offset
* @property {boolean} active_ - Tabs visibility
*
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {
this.el_ = (typeof el === "string")
const ref = (typeof el === "string")
? document.querySelector(el)
: el
if (!(ref instanceof Node))
throw new ReferenceError
this.el_ = ref
/* Initialize height and state */
this.height_ = 5
/* Initialize offset and state */
this.offset_ = 5
this.active_ = false
}
@ -46,7 +54,7 @@ export default class Toggle {
* Update visibility
*/
update() {
const active = window.pageYOffset >= this.height_
const active = window.pageYOffset >= this.offset_
if (active !== this.active_)
this.el_.dataset.mdState = (this.active_ = active) ? "hidden" : ""
}

View File

@ -351,6 +351,11 @@ kbd {
}
}
// Definition lists
dd {
margin: 1em 0 1em 1.875em;
}
// Limit width to container
iframe,
img,
@ -362,18 +367,18 @@ kbd {
table:not([class]) {
@include z-depth(2);
margin: 2em 0;
display: inline-block;
max-width: 100%;
border-radius: 0.2rem;
font-size: ms(-1);
overflow: hidden;
overflow: auto;
-webkit-overflow-scrolling: touch;
// Semi-cool overflow solution, in case JavaScript is not available
.no-js & {
display: inline-block;
max-width: 100%;
margin: 0.8em 0;
overflow: auto;
-webkit-overflow-scrolling: touch;
// Due to margin collapse because of the necessary inline-block hack, we
// cannot increase the bottom margin on the table, so we just increase the
// top margin on the following element
& + * {
margin-top: 1.5em;
}
// Table headings and cells
@ -409,16 +414,25 @@ kbd {
}
}
// Data table wrapper, in case JavaScript is available
.md-typeset__table {
margin: 1.6em -1.6rem;
// Wrapper for scrolling on overflow
&__scrollwrap {
margin: 1em -1.6rem;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
// Data table wrapper, in case JavaScript is available
.md-typeset__table {
display: inline-block;
margin-bottom: 0.5em;
padding: 0 1.6rem;
// Data tables
table {
display: inline-block;
margin: 0 1.6rem;
display: table;
width: 100%;
margin: 0;
overflow: hidden;
}
}
}

View File

@ -102,27 +102,11 @@ hr {
display: table-row;
height: 100%;
// Top-spacing to account for header and some additional padding
// Increase top spacing of content area to give typography more room
&__inner {
min-height: 100%;
padding-top: 2.4rem + 0.6rem;
overflow: auto;
// If the browser supports calc(), no JavaScript is necessary
.csscalc & {
min-height: calc(100% - #{5.6rem - 3rem});
// Hack: Firefox doesn't correctly calculate min-height, as it takes the
// top margin into account which leads to the container overflowing its
// parent. For this reason we use this hack here to target only Firefox
// and see if we can find a better solution later.
// stylelint-disable-next-line function-url-quotes
@-moz-document url-prefix() {
& {
min-height: calc(100% - 5.6rem);
}
}
}
}
}

View File

@ -47,11 +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;
}
// Hack: remove bottom spacing of last element, due to margin collapse
> :last-child {
margin-bottom: 0;
}
}

View File

@ -141,7 +141,7 @@
color: $md-color-primary;
}
// Focused or hovered item
// Focused or hovered link
&:focus,
&:hover {
color: $md-color-accent;
@ -155,6 +155,7 @@
// [tablet -]: Layered navigation
@include break-to-device(tablet) {
background-color: $md-color-white;
// Stretch primary navigation to drawer
&--primary,
@ -171,14 +172,6 @@
// 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,
@ -304,7 +297,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;
}

View File

@ -64,7 +64,7 @@
line-height: 1.2;
white-space: nowrap;
// Hovered source information
// Hovered source container
&:hover {
opacity: 0.7;
}

View File

@ -232,6 +232,25 @@
<!-- Content -->
{{ page.content }}
{% endblock %}
<!-- Disqus integration -->
{% if config.extra.disqus and not page.is_homepage %}
<h2>{{ lang.t('comments') }}</h2>
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
this.page.url = "{{ page.canonical_url }}";
this.page.identifier =
"{{ page.canonical_url | replace(config.site_url, "") }}";
};
(function() {
var d = document, s = d.createElement("script");
s.src = "//{{ config.extra.disqus }}.disqus.com/embed.js";
s.setAttribute("data-timestamp", +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
{% endif %}
</article>
</div>
</div>

View File

@ -23,6 +23,7 @@
<!-- Translations -->
{% macro t(key) %}{{ {
"edit.link.title": "Edit this page",
"comments": "Comments",
"footer.previous": "Previous",
"footer.next": "Next",
"search.placeholder": "Search",

View File

@ -30,7 +30,7 @@
<input type="text" class="md-search__input" name="query"
placeholder="{{ lang.t('search.placeholder') }}"
accesskey="s" autocapitalize="off" autocorrect="off"
autocomplete="off" spellcheck="false" />
autocomplete="off" spellcheck="false" data-md-component="query" />
<label class="md-icon md-search__icon" for="search"></label>
</form>
<div class="md-search__output">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

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