mirror of
https://github.com/squidfunk/mkdocs-material.git
synced 2024-06-14 11:52:32 +03:00
Rewrite of Gulp asset pipeline in ES6 and separation of tasks
This commit is contained in:
parent
46f45bb8a9
commit
914ccc4550
6
.babelrc
Normal file
6
.babelrc
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"presets": ["es2015"],
|
||||
"plugins": [
|
||||
"add-module-exports"
|
||||
]
|
||||
}
|
41
.eslintrc
41
.eslintrc
@ -1,8 +1,27 @@
|
||||
{
|
||||
"extends": "eslint:recommended",
|
||||
"ecmaFeatures": {
|
||||
"arrowFunctions": true,
|
||||
"binaryLiterals": true,
|
||||
"blockBindings": true,
|
||||
"classes": true,
|
||||
"defaultParams": true,
|
||||
"destructuring": true,
|
||||
"forOf": true,
|
||||
"generators": true,
|
||||
"globalReturn": true,
|
||||
"modules": true
|
||||
"modules": true,
|
||||
"objectLiteralComputedProperties": true,
|
||||
"objectLiteralDuplicateProperties": true,
|
||||
"objectLiteralShorthandMethods": true,
|
||||
"objectLiteralShorthandProperties": true,
|
||||
"octalLiterals": true,
|
||||
"regexUFlag": true,
|
||||
"regexYFlag": true,
|
||||
"spread": true,
|
||||
"superInFunctions": false,
|
||||
"templateStrings": true,
|
||||
"unicodeCodePointEscapes": true
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
@ -10,10 +29,10 @@
|
||||
"node": true
|
||||
},
|
||||
"globals": {
|
||||
"describe": true,
|
||||
"before": true,
|
||||
"it": true,
|
||||
"describe": true,
|
||||
"expect": true,
|
||||
"it": true,
|
||||
"Modernizr": true,
|
||||
"navigator": true
|
||||
},
|
||||
@ -34,7 +53,7 @@
|
||||
"block-spacing": 2,
|
||||
"brace-style": 2,
|
||||
"camelcase": [2, {
|
||||
"properties": "always",
|
||||
"properties": "always"
|
||||
}],
|
||||
"comma-dangle": [2, "never"],
|
||||
"comma-style": [2, "last"],
|
||||
@ -71,13 +90,12 @@
|
||||
"lines-around-comment": 2,
|
||||
"lines-around-directive": 2,
|
||||
"max-depth": 2,
|
||||
"max-len": [2, {
|
||||
"max-len": [1, {
|
||||
"ignorePattern": "\/\/ TODO"
|
||||
}],
|
||||
"max-nested-callbacks": 2,
|
||||
"max-params": 2,
|
||||
"max-statements-per-line": 2,
|
||||
"multiline-ternary": 2,
|
||||
"new-cap": 2,
|
||||
"newline-per-chained-call": 2,
|
||||
"no-array-constructor": 2,
|
||||
@ -86,6 +104,7 @@
|
||||
"no-confusing-arrow": [2, {
|
||||
"allowParens": false
|
||||
}],
|
||||
"no-console": 1,
|
||||
"no-duplicate-imports": 2,
|
||||
"no-eq-null": 2,
|
||||
"no-eval": 2,
|
||||
@ -97,7 +116,7 @@
|
||||
"no-labels": 2,
|
||||
"no-lone-blocks": 2,
|
||||
"no-loop-func": 2,
|
||||
"no-multiple-empty-lines": [2, {
|
||||
"no-multiple-empty-lines": [1, {
|
||||
"max": 1
|
||||
}],
|
||||
"no-nested-ternary": 2,
|
||||
@ -118,6 +137,7 @@
|
||||
"no-unneeded-ternary": 2,
|
||||
"no-unsafe-negation": 2,
|
||||
"no-unused-expressions": 2,
|
||||
"no-unused-vars": 1,
|
||||
"no-use-before-define": 2,
|
||||
"no-useless-call": 2,
|
||||
"no-useless-computed-key": 2,
|
||||
@ -126,8 +146,7 @@
|
||||
"no-var": 2,
|
||||
"no-whitespace-before-property": 2,
|
||||
"no-with": 2,
|
||||
"object-curly-newline": 2,
|
||||
"object-curly-spacing": 2,
|
||||
"object-curly-spacing": [2, "always"],
|
||||
"object-property-newline": 2,
|
||||
"object-shorthand": 2,
|
||||
"one-var-declaration-per-line": 2,
|
||||
@ -139,7 +158,7 @@
|
||||
"prefer-template": 2,
|
||||
"quotes": [2, "double"],
|
||||
"radix": 2,
|
||||
"require-jsdoc": [2, {
|
||||
"require-jsdoc": [1, {
|
||||
"require": {
|
||||
"FunctionDeclaration": true,
|
||||
"MethodDefinition": true,
|
||||
@ -167,7 +186,7 @@
|
||||
"strict": 2,
|
||||
"template-curly-spacing": 2,
|
||||
"unicode-bom": 2,
|
||||
"valid-jsdoc": [2, {
|
||||
"valid-jsdoc": [1, {
|
||||
"prefer": {
|
||||
"arg": "param",
|
||||
"argument": "param",
|
||||
|
16
.gitignore
vendored
16
.gitignore
vendored
@ -21,15 +21,15 @@
|
||||
# Mac OS X internals
|
||||
.DS_Store
|
||||
|
||||
# NPM libraries
|
||||
node_modules
|
||||
# Dependencies
|
||||
/node_modules
|
||||
|
||||
# Build files
|
||||
build
|
||||
manifest.json
|
||||
MANIFEST
|
||||
site
|
||||
/build
|
||||
/manifest.json
|
||||
/MANIFEST
|
||||
/site
|
||||
|
||||
# Distribution files
|
||||
dist
|
||||
mkdocs_material.egg-info
|
||||
/dist
|
||||
/mkdocs_material.egg-info
|
@ -21,6 +21,7 @@
|
||||
files:
|
||||
ignore:
|
||||
- src/assets/stylesheets/_shame.scss
|
||||
- src/assets/stylesheets/extensions/_codehilite.scss # Temporary disabled
|
||||
|
||||
options:
|
||||
merge-default-rules: true
|
||||
|
@ -22,8 +22,8 @@ language: node_js
|
||||
|
||||
# Node.js versions
|
||||
node_js:
|
||||
- '4.1'
|
||||
- '0.11'
|
||||
- 4.5.0
|
||||
- 6.7.0
|
||||
|
||||
# Install dependencies
|
||||
before_script:
|
||||
|
@ -15,6 +15,7 @@ mkdocs-material-1.0.0-rc.1 (2016-XX-XX)
|
||||
* Rewrite of JavaScript using ES6 and Babel as a transpiler
|
||||
* Rewrite of Admonition, Permalinks and Codehilite integration
|
||||
* Rewrite of the complete typographical system
|
||||
* Rewrite of Gulp asset pipeline in ES6 and separate tasks
|
||||
* Removed Bower as a dependency in favor of npm
|
||||
* Removed custom icon build in favor of the Material Design iconset
|
||||
* Removed _blank targets on links due to vulnerability: http://bit.ly/1Mk2Rtw
|
||||
|
328
Gulpfile.babel.js
Executable file
328
Gulpfile.babel.js
Executable file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import gulp from "gulp"
|
||||
import notifier from "node-notifier"
|
||||
import plumber from "gulp-plumber"
|
||||
import util from "gulp-util"
|
||||
import yargs from "yargs"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Configuration and arguments
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
const config = {
|
||||
assets: {
|
||||
src: "src/assets", /* Source directory for assets */
|
||||
build: "material/assets" /* Target directory for assets */
|
||||
},
|
||||
views: {
|
||||
src: "src", /* Source directory for views */
|
||||
build: "material" /* Target directory for views */
|
||||
}
|
||||
}
|
||||
|
||||
const args = yargs
|
||||
.default("clean", false) /* Clean before build */
|
||||
.default("lint", true) /* Lint sources */
|
||||
.default("mkdocs", false) /* MkDocs watchdog */
|
||||
.default("optimize", true) /* Optimize sources */
|
||||
.default("revision", true) /* Revision assets */
|
||||
.default("sourcemaps", false) /* Create sourcemaps */
|
||||
.argv
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Overrides and helpers
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Override gulp.src() for nicer error handling.
|
||||
*/
|
||||
const src = gulp.src
|
||||
gulp.src = (...glob) => {
|
||||
return src.apply(gulp, glob)
|
||||
.pipe(
|
||||
plumber(function(error) {
|
||||
util.log(util.colors.red(
|
||||
`Error (${error.plugin}): ${error.message}`
|
||||
))
|
||||
|
||||
/* Extract file where error happened, if existent */
|
||||
const file = error.relativePath
|
||||
? error.relativePath.split("/").pop()
|
||||
: ""
|
||||
|
||||
/* Dispatch system-level notification */
|
||||
notifier.notify({
|
||||
title: `Error (${error.plugin}): ${file}`,
|
||||
message: error.messageOriginal
|
||||
})
|
||||
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.emit("end")
|
||||
|
||||
/* Throw error and abort, if not in watch mode */
|
||||
if (args._[0] !== "watch")
|
||||
throw error
|
||||
}))
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to load a task
|
||||
*/
|
||||
const load = task => {
|
||||
return require(`./tasks/${task}.js`)(gulp, config, args)
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Images
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Copy favicon
|
||||
*/
|
||||
gulp.task("assets:images:build:ico",
|
||||
load("assets/images/build/ico"))
|
||||
|
||||
/*
|
||||
* Copy and minify vector graphics
|
||||
*/
|
||||
gulp.task("assets:images:build:svg",
|
||||
load("assets/images/build/svg"))
|
||||
|
||||
/*
|
||||
* Copy images
|
||||
*/
|
||||
gulp.task("assets:images:build", args.clean ? [
|
||||
"assets:images:clean"
|
||||
] : [], () => {
|
||||
return gulp.start([
|
||||
"assets:images:build:ico",
|
||||
"assets:images:build:svg"
|
||||
])
|
||||
})
|
||||
|
||||
/*
|
||||
* Clean images generated by build
|
||||
*/
|
||||
gulp.task("assets:images:clean",
|
||||
load("assets/images/clean"))
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Javascripts
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Build application logic
|
||||
*/
|
||||
gulp.task("assets:javascripts:build:application",
|
||||
load("assets/javascripts/build/application"))
|
||||
|
||||
/*
|
||||
* Build custom modernizr
|
||||
*/
|
||||
gulp.task("assets:javascripts:build:modernizr", [
|
||||
"assets:stylesheets:build"
|
||||
], load("assets/javascripts/build/modernizr"))
|
||||
|
||||
/*
|
||||
* Build application logic and modernizr
|
||||
*/
|
||||
gulp.task("assets:javascripts:build", (args.clean ? [
|
||||
"assets:javascripts:clean"
|
||||
] : []).concat(args.lint ? [
|
||||
"assets:javascripts:lint"
|
||||
] : []), () => {
|
||||
gulp.start([
|
||||
"assets:javascripts:build:application",
|
||||
"assets:javascripts:build:modernizr"
|
||||
])
|
||||
})
|
||||
|
||||
/*
|
||||
* Clean javascripts generated by build
|
||||
*/
|
||||
gulp.task("assets:javascripts:clean",
|
||||
load("assets/javascripts/clean"))
|
||||
|
||||
/*
|
||||
* Lint javascripts
|
||||
*/
|
||||
gulp.task("assets:javascripts:lint",
|
||||
load("assets/javascripts/lint"))
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Stylesheets
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Build stylesheets from SASS source
|
||||
*/
|
||||
gulp.task("assets:stylesheets:build", (args.clean ? [
|
||||
"assets:stylesheets:clean"
|
||||
] : []).concat(args.lint ? [
|
||||
"assets:stylesheets:lint"
|
||||
] : []),
|
||||
load("assets/stylesheets/build"))
|
||||
|
||||
/*
|
||||
* Clean stylesheets generated by build
|
||||
*/
|
||||
gulp.task("assets:stylesheets:clean",
|
||||
load("assets/stylesheets/clean"))
|
||||
|
||||
/*
|
||||
* Lint SASS sources
|
||||
*/
|
||||
gulp.task("assets:stylesheets:lint",
|
||||
load("assets/stylesheets/lint"))
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Assets
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Build assets
|
||||
*/
|
||||
gulp.task("assets:build", [
|
||||
"assets:images:build",
|
||||
"assets:javascripts:build",
|
||||
"assets:stylesheets:build"
|
||||
])
|
||||
|
||||
/*
|
||||
* Clean files generated by build
|
||||
*/
|
||||
gulp.task("assets:clean", [
|
||||
"assets:images:clean",
|
||||
"assets:javascripts:clean",
|
||||
"assets:stylesheets:clean"
|
||||
])
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Views
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Minify views
|
||||
*/
|
||||
gulp.task("views:build", (args.revision ? [
|
||||
"assets:images:build",
|
||||
"assets:stylesheets:build",
|
||||
"assets:javascripts:build"
|
||||
] : []).concat(args.clean ? [
|
||||
"views:clean"
|
||||
] : []), load("views/build"))
|
||||
|
||||
/*
|
||||
* Clean views
|
||||
*/
|
||||
gulp.task("views:clean",
|
||||
load("views/clean"))
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* MkDocs
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Build documentation
|
||||
*/
|
||||
gulp.task("mkdocs:build", [
|
||||
"assets:build",
|
||||
"views:build",
|
||||
"mkdocs:clean"
|
||||
], load("mkdocs/build"))
|
||||
|
||||
/*
|
||||
* Clean documentation build
|
||||
*/
|
||||
gulp.task("mkdocs:clean",
|
||||
load("mkdocs/clean"))
|
||||
|
||||
/*
|
||||
* Restart MkDocs server
|
||||
*/
|
||||
gulp.task("mkdocs:serve",
|
||||
load("mkdocs/serve"))
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Interface
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Build assets and documentation
|
||||
*/
|
||||
gulp.task("build", [
|
||||
"clean"
|
||||
], () => {
|
||||
return gulp.start([
|
||||
"assets:build",
|
||||
"views:build"
|
||||
].concat(args.mkdocs
|
||||
? "mkdocs:build"
|
||||
: []))
|
||||
})
|
||||
|
||||
/*
|
||||
* Clean assets and documentation
|
||||
*/
|
||||
gulp.task("clean", [
|
||||
"assets:clean",
|
||||
"views:clean",
|
||||
"mkdocs:clean"
|
||||
])
|
||||
|
||||
/*
|
||||
* Watch for changes and rebuild assets on the fly
|
||||
*/
|
||||
gulp.task("watch", [
|
||||
"assets:build",
|
||||
"views:build"
|
||||
], () => {
|
||||
if (args.mkdocs)
|
||||
gulp.start("mkdocs:serve")
|
||||
|
||||
/* Rebuild stylesheets */
|
||||
gulp.watch([
|
||||
`${config.assets.src}/stylesheets/**/*.scss`
|
||||
], ["assets:stylesheets:build"])
|
||||
|
||||
/* Rebuild javascripts */
|
||||
gulp.watch([
|
||||
`${config.assets.src}/javascripts/**/*.js`
|
||||
], ["assets:javascripts:build:application"])
|
||||
|
||||
/* Copy images */
|
||||
gulp.watch([
|
||||
`${config.assets.src}/images/**/*`
|
||||
], ["assets:images:build"])
|
||||
|
||||
/* Minify views */
|
||||
gulp.watch([
|
||||
`${config.views.src}/**/*.html`
|
||||
], ["views:build"])
|
||||
})
|
||||
|
||||
/*
|
||||
* Build assets by default
|
||||
*/
|
||||
gulp.task("default", ["build"])
|
434
Gulpfile.js
434
Gulpfile.js
@ -1,434 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Imports
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
var gulp = require("gulp")
|
||||
var args = require("yargs").argv
|
||||
var autoprefix = require("autoprefixer")
|
||||
var changed = require("gulp-changed")
|
||||
var child = require("child_process")
|
||||
var clean = require("del")
|
||||
var compact = require("gulp-remove-empty-lines")
|
||||
var concat = require("gulp-concat")
|
||||
var gulpif = require("gulp-if")
|
||||
var mincss = require("gulp-cssnano")
|
||||
var minhtml = require("gulp-htmlmin")
|
||||
var minsvg = require("gulp-svgmin")
|
||||
var modernizr = require("gulp-modernizr")
|
||||
var mqpacker = require("css-mqpacker")
|
||||
var notifier = require("node-notifier")
|
||||
var path = require("path")
|
||||
var plumber = require("gulp-plumber")
|
||||
var postcss = require("gulp-postcss")
|
||||
var replace = require("gulp-replace")
|
||||
var rev = require("gulp-rev")
|
||||
var sass = require("gulp-sass")
|
||||
var sasslint = require("gulp-sass-lint")
|
||||
var sourcemaps = require("gulp-sourcemaps")
|
||||
var stream = require("webpack-stream")
|
||||
var uglify = require("gulp-uglify")
|
||||
var util = require("gulp-util")
|
||||
var vinyl = require("vinyl-paths")
|
||||
var version = require("gulp-rev-replace")
|
||||
var webpack = require("webpack")
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Locals
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/* MkDocs server */
|
||||
var server = null
|
||||
|
||||
/* Watching context */
|
||||
var watch = false
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Overrides
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Override gulp.src() for nicer error handling.
|
||||
*/
|
||||
var src = gulp.src // TODO: do this via extension somehow...
|
||||
gulp.src = function() {
|
||||
return src.apply(gulp, arguments)
|
||||
.pipe(
|
||||
plumber(function(error) {
|
||||
util.log(util.colors.red(
|
||||
"Error (" + error.plugin + "): " + error.message
|
||||
))
|
||||
|
||||
/* Extract file where error happened, if existent */
|
||||
var file = error.relativePath
|
||||
? error.relativePath.split("/").pop()
|
||||
: ""
|
||||
|
||||
/* Dispatch system-level notification */
|
||||
notifier.notify({
|
||||
title: "Error (" + error.plugin + "): " + file,
|
||||
message: error.messageOriginal
|
||||
})
|
||||
this.emit("end")
|
||||
}))
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Asset pipeline
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Clean stylesheets generated by build.
|
||||
*/
|
||||
gulp.task("assets:clean:stylesheets", () => {
|
||||
return gulp.src("material/assets/stylesheets/*")
|
||||
.pipe(vinyl(clean))
|
||||
})
|
||||
|
||||
/*
|
||||
* Clean javascripts generated by build.
|
||||
*/
|
||||
gulp.task("assets:clean:javascripts", () => {
|
||||
return gulp.src("material/assets/javascripts/*")
|
||||
.pipe(vinyl(clean))
|
||||
})
|
||||
|
||||
/*
|
||||
* Clean images generated by build.
|
||||
*/
|
||||
gulp.task("assets:clean:images", () => {
|
||||
return gulp.src("material/assets/images/*")
|
||||
.pipe(vinyl(clean))
|
||||
})
|
||||
|
||||
/*
|
||||
* Clean files generated by build.
|
||||
*/
|
||||
gulp.task("assets:clean", [
|
||||
"assets:clean:stylesheets",
|
||||
"assets:clean:javascripts",
|
||||
"assets:clean:images"
|
||||
])
|
||||
|
||||
/*
|
||||
* Build stylesheets from SASS source.
|
||||
*/
|
||||
gulp.task("assets:build:stylesheets", args.production ? [
|
||||
"assets:clean:stylesheets",
|
||||
"assets:build:images"
|
||||
] : [], () => {
|
||||
return gulp.src("src/assets/stylesheets/*.scss")
|
||||
.pipe(gulpif(args.sourcemaps, sourcemaps.init()))
|
||||
.pipe(
|
||||
sass({
|
||||
includePaths: [
|
||||
"node_modules/modularscale-sass/stylesheets",
|
||||
"node_modules/material-design-color",
|
||||
"node_modules/material-shadows"
|
||||
]
|
||||
}))
|
||||
.pipe(
|
||||
postcss([
|
||||
autoprefix(),
|
||||
mqpacker
|
||||
]))
|
||||
.pipe(gulpif(args.sourcemaps, sourcemaps.write()))
|
||||
.pipe(gulpif(args.production, mincss()))
|
||||
.pipe(gulpif(args.production, rev()))
|
||||
.pipe(gulpif(args.production,
|
||||
version({ manifest: gulp.src("manifest.json") })))
|
||||
.pipe(gulp.dest("material/assets/stylesheets"))
|
||||
.pipe(gulpif(args.production,
|
||||
rev.manifest("manifest.json", {
|
||||
base: "material/assets",
|
||||
merge: true
|
||||
})))
|
||||
.pipe(gulpif(args.production, gulp.dest("material/assets")))
|
||||
})
|
||||
|
||||
/*
|
||||
* Build javascripts by transpiling ES6 with babel.
|
||||
*/
|
||||
gulp.task("assets:build:javascripts", args.production ? [
|
||||
"assets:clean:javascripts"
|
||||
] : [], () => {
|
||||
return gulp.src("src/assets/javascripts/**/*.js")
|
||||
.pipe(
|
||||
stream({
|
||||
entry: "application.js",
|
||||
output: {
|
||||
filename: "application.js"
|
||||
},
|
||||
module: {
|
||||
loaders: [{
|
||||
loader: "babel-loader",
|
||||
test: path.join(__dirname, "src/assets/javascripts"),
|
||||
query: {
|
||||
presets: "es2015"
|
||||
}
|
||||
}, {
|
||||
test: /\.js$/,
|
||||
loader: "eslint-loader",
|
||||
exclude: /node_modules/
|
||||
}]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.NoErrorsPlugin()
|
||||
].concat(
|
||||
args.production ? [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
warnings: false
|
||||
}
|
||||
})
|
||||
] : []),
|
||||
stats: {
|
||||
colors: true
|
||||
},
|
||||
resolve: {
|
||||
modulesDirectories: [
|
||||
"src/assets/javascripts",
|
||||
"node_modules"
|
||||
],
|
||||
extensions: [
|
||||
"", ".js"
|
||||
]
|
||||
},
|
||||
devtool: args.sourcemaps ? "source-map" : ""
|
||||
}))
|
||||
.pipe(gulpif(args.production, rev()))
|
||||
.pipe(gulp.dest("material/assets/javascripts"))
|
||||
.pipe(gulpif(args.production,
|
||||
rev.manifest("manifest.json", {
|
||||
base: "material/assets",
|
||||
merge: true
|
||||
})))
|
||||
.pipe(gulpif(args.production, gulp.dest("material/assets")))
|
||||
})
|
||||
|
||||
/*
|
||||
* Create a customized modernizr build.
|
||||
*/
|
||||
gulp.task("assets:build:modernizr", [
|
||||
"assets:build:stylesheets",
|
||||
"assets:build:javascripts"
|
||||
], () => {
|
||||
return gulp.src([
|
||||
"material/assets/stylesheets/*.css",
|
||||
"material/assets/javascripts/*.js"
|
||||
]).pipe(
|
||||
modernizr({
|
||||
options: [
|
||||
"addTest", /* Add custom tests */
|
||||
"fnBind", /* Use function.bind */
|
||||
"html5printshiv", /* HTML5 support for IE */
|
||||
"setClasses", /* Add CSS classes to root tag */
|
||||
"testProp" /* Test for properties */
|
||||
]
|
||||
}))
|
||||
.pipe(concat("modernizr.js"))
|
||||
.pipe(gulpif(args.production, uglify()))
|
||||
.pipe(gulpif(args.production, rev()))
|
||||
.pipe(gulp.dest("material/assets/javascripts"))
|
||||
.pipe(gulpif(args.production,
|
||||
rev.manifest("manifest.json", {
|
||||
base: "material/assets",
|
||||
merge: true
|
||||
})))
|
||||
.pipe(gulpif(args.production, gulp.dest("material/assets")))
|
||||
})
|
||||
|
||||
/*
|
||||
* Copy and minify vector graphics.
|
||||
*/
|
||||
gulp.task("assets:build:images:svg", () => {
|
||||
return gulp.src("src/assets/images/**/*.svg")
|
||||
.pipe(gulpif(watch, changed("material/assets/images")))
|
||||
.pipe(gulpif(args.production, minsvg()))
|
||||
.pipe(gulpif(args.production, rev()))
|
||||
.pipe(gulp.dest("material/assets/images"))
|
||||
.pipe(gulpif(args.production,
|
||||
rev.manifest("manifest.json", {
|
||||
base: "material/assets",
|
||||
merge: true
|
||||
})))
|
||||
.pipe(gulpif(args.production, gulp.dest("material/assets")))
|
||||
})
|
||||
|
||||
/*
|
||||
* Copy favicon.
|
||||
*/
|
||||
gulp.task("assets:build:images:ico", () => {
|
||||
return gulp.src("src/assets/images/**/*.ico")
|
||||
.pipe(gulp.dest("material/assets/images"))
|
||||
})
|
||||
|
||||
/*
|
||||
* Copy images.
|
||||
*/
|
||||
gulp.task("assets:build:images", [
|
||||
"assets:clean:images"
|
||||
], () => {
|
||||
return gulp.start([
|
||||
"assets:build:images:svg",
|
||||
"assets:build:images:ico"
|
||||
])
|
||||
})
|
||||
|
||||
/*
|
||||
* Minify views.
|
||||
*/
|
||||
gulp.task("assets:build:views", args.production ? [
|
||||
"assets:build:stylesheets",
|
||||
"assets:build:modernizr",
|
||||
"assets:build:images"
|
||||
] : [], () => {
|
||||
var metadata = require("./package.json")
|
||||
return gulp.src("src/**/*.html")
|
||||
.pipe(gulpif(watch, changed("material")))
|
||||
.pipe(
|
||||
minhtml({
|
||||
collapseBooleanAttributes: true,
|
||||
removeComments: true,
|
||||
removeScriptTypeAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
customAttrCollapse: /(content)/
|
||||
}))
|
||||
.pipe(replace("$theme-name$", metadata.name))
|
||||
.pipe(replace("$theme-version$", metadata.version))
|
||||
.pipe(compact())
|
||||
.pipe(gulpif(args.production,
|
||||
version({ manifest: gulp.src("manifest.json") })))
|
||||
.pipe(gulp.dest("material"))
|
||||
})
|
||||
|
||||
/*
|
||||
* Build assets.
|
||||
*/
|
||||
gulp.task("assets:build", [
|
||||
"assets:build:stylesheets",
|
||||
"assets:build:javascripts",
|
||||
"assets:build:modernizr",
|
||||
"assets:build:images",
|
||||
"assets:build:views"
|
||||
])
|
||||
|
||||
/*
|
||||
* Watch assets for changes and rebuild on the fly.
|
||||
*/
|
||||
gulp.task("assets:watch", () => {
|
||||
watch = true
|
||||
|
||||
/* Rebuild stylesheets */
|
||||
gulp.watch([
|
||||
"src/assets/stylesheets/**/*.scss"
|
||||
], ["assets:build:stylesheets"])
|
||||
|
||||
/* Rebuild javascripts */
|
||||
gulp.watch([
|
||||
"src/assets/javascripts/**/*.js"
|
||||
], ["assets:build:javascripts"])
|
||||
|
||||
/* Copy images */
|
||||
gulp.watch([
|
||||
"src/assets/images/**/*"
|
||||
], ["assets:build:images"])
|
||||
|
||||
/* Minify views */
|
||||
gulp.watch([
|
||||
"src/**/*.html"
|
||||
], ["assets:build:views"])
|
||||
})
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Application server
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Build documentation.
|
||||
*/
|
||||
gulp.task("mkdocs:build", [
|
||||
"assets:build"
|
||||
], () => {
|
||||
return child.spawnSync("mkdocs", ["build"])
|
||||
})
|
||||
|
||||
/*
|
||||
* Restart MkDocs server.
|
||||
*/
|
||||
gulp.task("mkdocs:serve", () => {
|
||||
if (server)
|
||||
server.kill()
|
||||
|
||||
/* Spawn MkDocs server */
|
||||
server = child.spawn("mkdocs", ["serve", "-a", "0.0.0.0:8000"])
|
||||
|
||||
/* Pretty print server log output */
|
||||
server.stdout.on("data", data => {
|
||||
var lines = data.toString().split("\n")
|
||||
for (var l in lines)
|
||||
if (lines[l].length)
|
||||
util.log(lines[l])
|
||||
})
|
||||
|
||||
/* Print errors to stdout */
|
||||
server.stderr.on("data", data => {
|
||||
process.stdout.write(data.toString())
|
||||
})
|
||||
})
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Interface
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Build assets and documentation.
|
||||
*/
|
||||
gulp.task("build", [
|
||||
"assets:clean",
|
||||
"assets:build"
|
||||
].concat(args.mkdocs
|
||||
? "mkdocs:build"
|
||||
: []))
|
||||
|
||||
/*
|
||||
* Start asset and MkDocs watchdogs.
|
||||
*/
|
||||
gulp.task("watch", [
|
||||
"assets:clean",
|
||||
"assets:build"
|
||||
], () => {
|
||||
return gulp.start([
|
||||
"assets:watch"
|
||||
].concat(args.mkdocs
|
||||
? "mkdocs:serve"
|
||||
: []))
|
||||
})
|
||||
|
||||
/*
|
||||
* Build assets by default.
|
||||
*/
|
||||
gulp.task("default", ["build"])
|
@ -1,2 +1,4 @@
|
||||
recursive-include material *.ico *.js *.css *.html *.svg
|
||||
recursive-exclude site *
|
||||
recursive-exclude * __pycache__
|
||||
recursive-exclude * *.py[co]
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
material/assets/javascripts/modernizr-dede1352ed.js
Normal file
1
material/assets/javascripts/modernizr-dede1352ed.js
Normal file
File diff suppressed because one or more lines are too long
1
material/assets/stylesheets/application-2ebf05d4b7.css
Normal file
1
material/assets/stylesheets/application-2ebf05d4b7.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -20,11 +20,11 @@
|
||||
<meta name="author" content="{{ site_author }}">
|
||||
{% endif %}
|
||||
<meta name="generator" content="mkdocs+mkdocs-material#0.2.1">
|
||||
<script src="{{ base_url }}/assets/javascripts/modernizr-d3fe1698b6.js"></script>
|
||||
<script src="{{ base_url }}/assets/javascripts/modernizr-dede1352ed.js"></script>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Mono:400">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
||||
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-d7ccfc4ec2.css">
|
||||
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-2ebf05d4b7.css">
|
||||
{% for path in extra_css %}
|
||||
<link rel="stylesheet" href="{{ path }}">
|
||||
{% endfor %}
|
||||
@ -39,7 +39,7 @@
|
||||
<div class="md-main__inner md-grid">
|
||||
{% set h1 = "\x3ch1 id=" in content %}
|
||||
{% if nav %}
|
||||
<div class="md-sidebar md-sidebar--primary md-js__sidebar">
|
||||
<div class="md-sidebar md-sidebar--primary" data-md-sidebar="primary">
|
||||
<div class="md-sidebar__scrollwrap">
|
||||
<div class="md-sidebar__inner">
|
||||
{% include "partials/nav.html" %}
|
||||
@ -48,7 +48,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if toc %}
|
||||
<div class="md-sidebar md-sidebar--secondary md-js__sidebar">
|
||||
<div class="md-sidebar md-sidebar--secondary" data-md-sidebar="secondary">
|
||||
<div class="md-sidebar__scrollwrap">
|
||||
<div class="md-sidebar__inner">
|
||||
{% include "partials/toc.html" %}
|
||||
@ -87,11 +87,19 @@
|
||||
</main>
|
||||
{% include "partials/footer.html" %}
|
||||
</div>
|
||||
<script src="{{ base_url }}/assets/javascripts/application-2ff8f6a9f1.js"></script>
|
||||
<script>
|
||||
window.baseUrl = '{{ base_url }}'; // TODO: define in global scope and use IIFE
|
||||
window.repoUrl = '{{ repo_url }}';
|
||||
/* Configuration for application */
|
||||
var config = {
|
||||
url: {
|
||||
base: "{{ base_url }}",
|
||||
repo: "{{ repo_url }}"
|
||||
}
|
||||
};
|
||||
/* Initialize application */
|
||||
var app = new Application(config);
|
||||
app.initialize();
|
||||
</script>
|
||||
<script src="{{ base_url }}/assets/javascripts/application-29b6c4d53e.js"></script>
|
||||
{% for path in extra_javascript %}
|
||||
<script src="{{ path }}"></script>
|
||||
{% endfor %}
|
||||
|
10
package.json
10
package.json
@ -9,8 +9,9 @@
|
||||
"license": "MIT",
|
||||
"main": "Gulpfile.js",
|
||||
"scripts": {
|
||||
"start": "./node_modules/.bin/gulp watch --mkdocs",
|
||||
"build": "./node_modules/.bin/gulp build --production"
|
||||
"start": "./node_modules/.bin/gulp watch --mkdocs --no-lint --no-revision",
|
||||
"build": "./node_modules/.bin/gulp build --clean",
|
||||
"clean": "./node_modules/.bin/gulp clean"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -29,11 +30,11 @@
|
||||
"autoprefixer": "^6.3.2",
|
||||
"babel-eslint": "^6.1.2",
|
||||
"babel-loader": "^6.2.4",
|
||||
"babel-plugin-add-module-exports": "^0.2.1",
|
||||
"babel-preset-es2015": "^6.13.2",
|
||||
"css-mqpacker": "^4.0.0",
|
||||
"del": "^2.2.0",
|
||||
"eslint": "^3.6.1",
|
||||
"eslint-loader": "^1.5.0",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-changed": "^1.3.2",
|
||||
"gulp-concat": "^2.6.0",
|
||||
@ -49,12 +50,13 @@
|
||||
"gulp-rev": "^7.0.0",
|
||||
"gulp-rev-replace": "^0.4.3",
|
||||
"gulp-sass": "^2.2.0",
|
||||
"gulp-sass-lint": "^1.2.0",
|
||||
"gulp-sourcemaps": "^1.6.0",
|
||||
"gulp-svgmin": "^1.2.2",
|
||||
"gulp-uglify": "^1.5.2",
|
||||
"gulp-util": "^3.0.7",
|
||||
"node-notifier": "^4.5.0",
|
||||
"sass-lint": "^1.9.1",
|
||||
"through2": "^2.0.1",
|
||||
"vinyl-paths": "^2.1.0",
|
||||
"webpack": "^1.13.1",
|
||||
"webpack-stream": "^3.2.0",
|
||||
|
@ -28,8 +28,8 @@ import FastClick from "fastclick"
|
||||
import lunr from "lunr"
|
||||
|
||||
// import Expander from "./components/expander"
|
||||
import Sidebar from "./components/sidebar"
|
||||
import ScrollSpy from "./components/scrollspy"
|
||||
|
||||
import Material from "./components/Material"
|
||||
|
||||
// import Search from './components/search';
|
||||
|
||||
@ -37,6 +37,22 @@ import ScrollSpy from "./components/scrollspy"
|
||||
* Application
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
class Application {
|
||||
|
||||
/**
|
||||
* @return {void}
|
||||
*/
|
||||
initialize() {
|
||||
const material = new Material()
|
||||
material.initialize()
|
||||
}
|
||||
}
|
||||
|
||||
export default Application
|
||||
|
||||
// TODO: wrap in function call
|
||||
// application module export
|
||||
|
||||
/* Initialize application upon DOM ready */
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
@ -53,27 +69,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
/* Attack FastClick to mitigate 300ms delay on touch devices */
|
||||
FastClick.attach(document.body)
|
||||
|
||||
const width = window.matchMedia("(min-width: 1200px)")
|
||||
|
||||
const sidebar = new Sidebar(".md-sidebar--primary")
|
||||
const handler = function() {
|
||||
if (width.matches) {
|
||||
sidebar.listen()
|
||||
} else {
|
||||
sidebar.unlisten()
|
||||
}
|
||||
}
|
||||
handler() // check listen!
|
||||
|
||||
const toc = new Sidebar(".md-sidebar--secondary")
|
||||
toc.listen()
|
||||
|
||||
const spy =
|
||||
new ScrollSpy(".md-sidebar--secondary .md-nav--secondary .md-nav__link")
|
||||
spy.listen()
|
||||
|
||||
window.addEventListener("resize", handler)
|
||||
|
||||
const query = document.getElementById("query")
|
||||
query.addEventListener("focus", () => {
|
||||
document.querySelector(".md-search").classList.add("md-js__search--locked")
|
||||
@ -230,7 +225,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
/* Create index */
|
||||
const index = lunr(() => {
|
||||
/* eslint-disable no-invalid-this, lines-around-comment */
|
||||
this.field("title", {boost: 10})
|
||||
this.field("title", { boost: 10 })
|
||||
this.field("text")
|
||||
this.ref("location")
|
||||
/* eslint-enable no-invalid-this, lines-around-comment */
|
||||
|
73
src/assets/javascripts/components/Material.js
Normal file
73
src/assets/javascripts/components/Material.js
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import Sidebar from "./Material/Sidebar"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Material application
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default
|
||||
class Material {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
// constructor() {
|
||||
//
|
||||
// }
|
||||
|
||||
/**
|
||||
* @return {void}
|
||||
*/
|
||||
initialize() {
|
||||
|
||||
// class AnchorMarker extends PageYOffsetListener
|
||||
// class SidebarConstrainer extends PageYOffsetListener
|
||||
|
||||
// MatchMedia!?
|
||||
|
||||
const width = window.matchMedia("(min-width: 1200px)")
|
||||
|
||||
// separate function in application.js --> initSidebar()
|
||||
const sidebar = new Sidebar.Position("[data-md-sidebar=primary]")
|
||||
const handler = function() {
|
||||
if (width.matches) {
|
||||
sidebar.listen()
|
||||
} else {
|
||||
sidebar.unlisten()
|
||||
}
|
||||
}
|
||||
handler() // check listen!
|
||||
|
||||
const toc = new Sidebar.Position("[data-md-sidebar=secondary]")
|
||||
toc.listen()
|
||||
|
||||
window.addEventListener("resize", handler) // TODO: orientation change etc...
|
||||
|
||||
const marker =
|
||||
new Sidebar.Marker("[data-md-sidebar=secondary] .md-nav__link")
|
||||
marker.listen()
|
||||
}
|
||||
}
|
33
src/assets/javascripts/components/Material/Sidebar.js
Normal file
33
src/assets/javascripts/components/Material/Sidebar.js
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import Marker from "./Sidebar/Marker"
|
||||
import Position from "./Sidebar/Position"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Definition
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default {
|
||||
Marker,
|
||||
Position
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Definition
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default
|
||||
class Abstract {
|
||||
|
||||
/**
|
||||
* Dispatch update on next repaint
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
constructor() {
|
||||
// if (new.target === this.constructor)
|
||||
// throw new TypeError("Cannot construct abstract instance")
|
||||
|
||||
/* Dispatch update on next repaint */
|
||||
this.handler_ = ev => {
|
||||
window.requestAnimationFrame(() => {
|
||||
this.update(ev)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update state
|
||||
*
|
||||
* @abstract
|
||||
* @return {void}
|
||||
*/
|
||||
update() {
|
||||
throw new Error("update(): not implemented")
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset state
|
||||
*
|
||||
* @abstract
|
||||
* @return {void}
|
||||
*/
|
||||
reset() {
|
||||
throw new Error("reset(): not implemented")
|
||||
}
|
||||
|
||||
/**
|
||||
* Register listener for all relevant events
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
listen() {
|
||||
["scroll", "resize", "orientationchange"].forEach(name => {
|
||||
window.addEventListener(name, this.handler_, false)
|
||||
})
|
||||
|
||||
/* Initial update */
|
||||
this.update()
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister listener for all relevant events
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
unlisten() {
|
||||
["scroll", "resize", "orientationchange"].forEach(name => {
|
||||
window.removeEventListener(name, this.handler_, false)
|
||||
})
|
||||
|
||||
/* Final reset */
|
||||
this.reset()
|
||||
}
|
||||
}
|
103
src/assets/javascripts/components/Material/Sidebar/Marker.js
Normal file
103
src/assets/javascripts/components/Material/Sidebar/Marker.js
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import Abstract from "./Abstract"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Definition
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default
|
||||
class Marker extends Abstract {
|
||||
|
||||
/**
|
||||
* Mark anchors within the table of contents above current page y-offset
|
||||
*
|
||||
* @constructor
|
||||
* @param {(string|HTMLCollection)} els - Selector or HTML elements
|
||||
*/
|
||||
constructor(els) {
|
||||
super()
|
||||
|
||||
/* Resolve elements */
|
||||
this.els_ = (typeof els === "string")
|
||||
? document.querySelectorAll(els)
|
||||
: els
|
||||
|
||||
/* Initialize index and page y-offset */
|
||||
this.index_ = 0
|
||||
this.offset_ = window.pageYOffset
|
||||
|
||||
/* Index anchor nodes for fast lookup */
|
||||
this.anchors_ = [].map.call(this.els_, el => {
|
||||
return document.querySelector(el.hash)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Update anchor states
|
||||
*
|
||||
* @param {Event} ev - Event (omitted)
|
||||
* @return {void}
|
||||
*/
|
||||
update() {
|
||||
|
||||
/* Scroll direction is down */
|
||||
if (this.offset_ <= window.pageYOffset) {
|
||||
for (let i = this.index_ + 1; i < this.els_.length; i++) {
|
||||
if (this.anchors_[i].offsetTop <= window.pageYOffset) {
|
||||
if (i > 0)
|
||||
this.els_[i - 1].dataset.mdMarked = true
|
||||
this.index_ = i
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/* Scroll direction is up */
|
||||
} else {
|
||||
for (let i = this.index_; i >= 0; i--) {
|
||||
if (this.anchors_[i].offsetTop > window.pageYOffset) {
|
||||
if (i > 0)
|
||||
delete this.els_[i - 1].dataset.mdMarked
|
||||
} else {
|
||||
this.index_ = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember current offset for next iteration */
|
||||
this.offset_ = window.pageYOffset
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset anchor states
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
reset() {
|
||||
[].forEach.call(this.els_, el => {
|
||||
delete el.dataset.mdMarked
|
||||
})
|
||||
}
|
||||
}
|
103
src/assets/javascripts/components/Material/Sidebar/Position.js
Normal file
103
src/assets/javascripts/components/Material/Sidebar/Position.js
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import Abstract from "./Abstract"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Definition
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default
|
||||
class Position extends Abstract {
|
||||
|
||||
/**
|
||||
* Set sidebars to locked state and limit height to parent node
|
||||
*
|
||||
* @constructor
|
||||
* @param {(string|HTMLElement)} el - Selector or HTML element
|
||||
*/
|
||||
constructor(el) {
|
||||
super()
|
||||
|
||||
/* Resolve elements */
|
||||
this.el_ = (typeof el === "string")
|
||||
? document.querySelector(el)
|
||||
: el
|
||||
|
||||
/* Index inner and outer container */
|
||||
this.inner_ = this.el_.parentNode
|
||||
this.outer_ = this.el_.parentNode.parentNode
|
||||
|
||||
/* Initialize current height */
|
||||
this.height_ = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Update locked state and height
|
||||
*
|
||||
* @param {Event} ev - Event (omitted)
|
||||
* @return {void}
|
||||
*/
|
||||
update() {
|
||||
const bounds = this.inner_.getBoundingClientRect() // TODO: thresholds can be calculated as a function
|
||||
const parent = this.outer_.offsetTop
|
||||
|
||||
/* Determine top and bottom offsets */
|
||||
const top = bounds.top + window.pageYOffset,
|
||||
bottom = bounds.bottom + window.pageYOffset
|
||||
|
||||
/* Determine current y-offset at top and bottom of window */
|
||||
const upper = window.pageYOffset,
|
||||
lower = window.pageYOffset + window.innerHeight
|
||||
|
||||
/* Calculate new bounds */
|
||||
const offset = top - upper
|
||||
const height = window.innerHeight
|
||||
- Math.max(lower - bottom, 0)
|
||||
- Math.max(offset, parent)
|
||||
|
||||
/* If height changed, update element */
|
||||
if (height !== this.height_)
|
||||
this.el_.style.height = `${this.height_ = height}px`
|
||||
|
||||
/* Sidebar should be locked, as we're below parent offset */
|
||||
if (offset < parent) {
|
||||
if (!this.el_.dataset.mdLocked)
|
||||
this.el_.dataset.mdLocked = true
|
||||
|
||||
/* Sidebar should be unlocked, if locked */
|
||||
} else if (this.el_.dataset.mdLocked) {
|
||||
delete this.el_.dataset.mdLocked
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset locked state and height
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
reset() {
|
||||
delete this.el_.dataset.mdLocked
|
||||
this.el_.style.height = ""
|
||||
this.height_ = 0
|
||||
}
|
||||
}
|
@ -24,23 +24,29 @@
|
||||
* Sidebar scroll-spy
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default
|
||||
class ScrollSpy {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @constructor
|
||||
* @param {(string|HTMLCollection)} el - Selector or HTML elements
|
||||
* @param {(string|HTMLCollection)} els - Selector or HTML elements
|
||||
*/
|
||||
constructor(el) {
|
||||
this.el_ = (typeof el === "string")
|
||||
? document.querySelectorAll(el)
|
||||
: el
|
||||
constructor(els) {
|
||||
this.els_ = (typeof els === "string")
|
||||
? document.querySelectorAll(els)
|
||||
: els
|
||||
|
||||
/* Initialize index for currently active element */
|
||||
this.index_ = 0
|
||||
this.offset_ = window.pageYOffset
|
||||
|
||||
/* Index anchor nodes for fast lookup */
|
||||
this.anchors_ = [].map.call(this.els_, el => {
|
||||
return document.querySelector(el.hash)
|
||||
})
|
||||
|
||||
/* Event listener */
|
||||
this.handler_ = ev => {
|
||||
this.update(ev)
|
||||
@ -48,7 +54,7 @@ class ScrollSpy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update state of sidebar and hash
|
||||
* Update state of sidebar
|
||||
*
|
||||
* @param {Event} ev - Event (omitted)
|
||||
* @return {void}
|
||||
@ -57,11 +63,10 @@ class ScrollSpy {
|
||||
|
||||
/* Scroll direction is down */
|
||||
if (this.offset_ <= window.pageYOffset) {
|
||||
for (let i = this.index_ + 1; i < this.el_.length; i++) {
|
||||
const anchor = document.querySelector(this.el_[i].hash) // TODO: improve performance by caching
|
||||
if (anchor.offsetTop <= window.pageYOffset) {
|
||||
for (let i = this.index_ + 1; i < this.els_.length; i++) {
|
||||
if (this.anchors_[i].offsetTop <= window.pageYOffset) {
|
||||
if (i > 0)
|
||||
this.el_[i - 1].classList.add("md-nav__link--marked")
|
||||
this.els_[i - 1].dataset.mdMarked = true
|
||||
this.index_ = i
|
||||
} else {
|
||||
break
|
||||
@ -71,10 +76,9 @@ class ScrollSpy {
|
||||
/* Scroll direction is up */
|
||||
} else {
|
||||
for (let i = this.index_; i >= 0; i--) {
|
||||
const anchor = document.querySelector(this.el_[i].hash)
|
||||
if (anchor.offsetTop > window.pageYOffset) {
|
||||
if (this.anchors_[i].offsetTop > window.pageYOffset) {
|
||||
if (i > 0)
|
||||
this.el_[i - 1].classList.remove("md-nav__link--marked")
|
||||
delete this.els_[i - 1].dataset.mdMarked
|
||||
} else {
|
||||
this.index_ = i
|
||||
break
|
||||
@ -92,8 +96,8 @@ class ScrollSpy {
|
||||
* @return {void}
|
||||
*/
|
||||
reset() {
|
||||
[].forEach.call(this.el_, el => {
|
||||
el.classList.remove("md-nav__link--marked")
|
||||
[].forEach.call(this.els_, el => {
|
||||
delete el.dataset.mdMarked
|
||||
})
|
||||
}
|
||||
|
||||
@ -125,9 +129,3 @@ class ScrollSpy {
|
||||
this.reset()
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Exports
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default ScrollSpy
|
||||
|
@ -20,8 +20,6 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Search
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
@ -21,7 +21,7 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Typography
|
||||
// Variables: typography
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Modular typographic scale
|
||||
@ -29,7 +29,7 @@ $ms-base: 1.6rem;
|
||||
$ms-ratio: $major-third;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Breakpoints
|
||||
// Variables: breakpoints
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Device-specific breakpoints
|
||||
@ -50,7 +50,7 @@ $break-devices: (
|
||||
);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Colors
|
||||
// Variables: base colors
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Primary and accent colors
|
||||
@ -70,7 +70,7 @@ $md-color-white--lighter: hsla(0, 0%, 100%, 0.30);
|
||||
$md-color-white--lightest: hsla(0, 0%, 100%, 0.12);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Sizing and spacing
|
||||
// Variables: sizing and spacing
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Icons
|
||||
|
@ -21,7 +21,7 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Nothing to see here, move along
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@include break-from-device(screen) {
|
||||
|
@ -29,7 +29,7 @@
|
||||
@import "material-shadows";
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Application
|
||||
// Local imports
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@import "helpers/break";
|
||||
@ -37,8 +37,8 @@
|
||||
|
||||
@import "config";
|
||||
|
||||
@import "base/icons";
|
||||
@import "base/reset";
|
||||
@import "base/icons";
|
||||
@import "base/typeset";
|
||||
|
||||
@import "layout/base";
|
||||
|
@ -21,7 +21,7 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Icon set
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Icon placeholders
|
||||
|
@ -21,7 +21,7 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Resets
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Enfore correct box model - the prefixed versions are necessary for older
|
||||
|
@ -21,7 +21,7 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Font definitions
|
||||
// Rules: font definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Default fonts
|
||||
@ -57,7 +57,7 @@ kbd {
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Typeset
|
||||
// Rules: typesetted content
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Content that is typeset
|
||||
|
@ -21,10 +21,10 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Admonition extension
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Admonition
|
||||
// Admonition extension
|
||||
.admonition {
|
||||
position: relative;
|
||||
margin: 2.0rem 0;
|
||||
|
@ -21,10 +21,10 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Codehilite extension
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Github-style syntax highlighting
|
||||
// Codehilite extension
|
||||
.codehilite,
|
||||
.code {
|
||||
|
||||
|
@ -21,10 +21,10 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Footnotes extension
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Footnote
|
||||
// Footnotes extension
|
||||
.footnote {
|
||||
color: $md-color-black--light;
|
||||
font-size: 80%;
|
||||
|
@ -21,13 +21,13 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Permalinks extension
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Scoped in typesetted content for greater specificity
|
||||
.md-typeset {
|
||||
|
||||
// Permalink
|
||||
// Permalinks extension
|
||||
.headerlink {
|
||||
display: inline-block;
|
||||
margin-left: 1.0rem;
|
||||
|
@ -51,7 +51,7 @@
|
||||
$break-devices: () !default;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Breakpoint helpers
|
||||
// Helpers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
///
|
||||
@ -115,7 +115,7 @@ $break-devices: () !default;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Breakpoint mixins
|
||||
// Mixins
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
///
|
||||
|
@ -21,7 +21,7 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Pixel conversion helpers
|
||||
// Helpers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
///
|
||||
|
@ -21,7 +21,7 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Grid
|
||||
// Rules: base grid and containers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Stretch container to viewport and set base font-size to 10px for simple
|
||||
@ -87,7 +87,7 @@ hr {
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Navigational elements
|
||||
// Rules: navigational elements
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Toggle checkbox
|
||||
@ -124,7 +124,7 @@ hr {
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Flexible elements, implemented with table layout
|
||||
// Rules: flexible elements, implemented with table layout
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Flexible layout container
|
||||
|
@ -21,7 +21,7 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Main content
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Content container
|
||||
|
@ -21,7 +21,7 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Footer
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Application footer
|
||||
|
@ -21,7 +21,7 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Header
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Application header (stays always on top)
|
||||
|
@ -21,10 +21,10 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Navigation
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Nested navigation
|
||||
// Navigation container
|
||||
.md-nav {
|
||||
font-size: ms(-1);
|
||||
line-height: 1.3;
|
||||
@ -113,7 +113,7 @@
|
||||
}
|
||||
|
||||
// Marked item
|
||||
&--marked {
|
||||
&[data-md-marked] {
|
||||
color: $md-color-black--light;
|
||||
}
|
||||
|
||||
|
@ -21,10 +21,10 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Search
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Application search
|
||||
// Search container
|
||||
.md-search {
|
||||
padding: 0.8rem 0.8rem 0;
|
||||
|
||||
|
@ -21,10 +21,10 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Sidebar
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Sidebar content
|
||||
// Sidebar container
|
||||
.md-sidebar {
|
||||
position: relative;
|
||||
width: 24.2rem;
|
||||
@ -32,7 +32,7 @@
|
||||
overflow: visible;
|
||||
|
||||
// Lock sidebar to container height (account for fixed header)
|
||||
&.md-js__sidebar--locked {
|
||||
&[data-md-locked] {
|
||||
position: fixed;
|
||||
top: 5.6rem;
|
||||
}
|
||||
@ -87,7 +87,7 @@
|
||||
float: right;
|
||||
|
||||
// Hack: align right in case of locked sidebar
|
||||
&.md-js__sidebar--locked {
|
||||
&[data-md-locked] {
|
||||
margin-left: 100%;
|
||||
transform: translate(-100%, 0);
|
||||
|
||||
|
@ -21,10 +21,10 @@
|
||||
////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Source
|
||||
// Rules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Repository containing source
|
||||
// Source container
|
||||
.md-source {
|
||||
display: block;
|
||||
transition: opacity 0.25s;
|
||||
|
@ -65,7 +65,7 @@
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="https://fonts.googleapis.com/css?family=Roboto+Mono:400" />
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
||||
href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
||||
|
||||
<!-- Theme-related stylesheets -->
|
||||
<link rel="stylesheet" type="text/css"
|
||||
@ -105,7 +105,8 @@
|
||||
|
||||
<!-- Main navigation -->
|
||||
{% if nav %}
|
||||
<div class="md-sidebar md-sidebar--primary md-js__sidebar">
|
||||
<div class="md-sidebar md-sidebar--primary"
|
||||
data-md-sidebar="primary">
|
||||
<div class="md-sidebar__scrollwrap">
|
||||
<div class="md-sidebar__inner">
|
||||
{% include "partials/nav.html" %}
|
||||
@ -116,7 +117,8 @@
|
||||
|
||||
<!-- Table of contents -->
|
||||
{% if toc %}
|
||||
<div class="md-sidebar md-sidebar--secondary md-js__sidebar">
|
||||
<div class="md-sidebar md-sidebar--secondary"
|
||||
data-md-sidebar="secondary">
|
||||
<div class="md-sidebar__scrollwrap">
|
||||
<div class="md-sidebar__inner">
|
||||
{% include "partials/toc.html" %}
|
||||
@ -169,11 +171,21 @@
|
||||
</div>
|
||||
|
||||
<!-- Theme-related and custom javascripts -->
|
||||
<script>
|
||||
window.baseUrl = '{{ base_url }}'; // TODO: define in global scope and use IIFE
|
||||
window.repoUrl = '{{ repo_url }}';
|
||||
</script>
|
||||
<script src="{{ base_url }}/assets/javascripts/application.js"></script>
|
||||
<script>
|
||||
|
||||
/* Configuration for application */
|
||||
var config = {
|
||||
url: {
|
||||
base: "{{ base_url }}",
|
||||
repo: "{{ repo_url }}"
|
||||
}
|
||||
};
|
||||
|
||||
/* Initialize application */
|
||||
var app = new Application(config);
|
||||
app.initialize();
|
||||
</script>
|
||||
{% for path in extra_javascript %}
|
||||
<script src="{{ path }}"></script>
|
||||
{% endfor %}
|
||||
|
35
tasks/assets/images/build/ico.js
Normal file
35
tasks/assets/images/build/ico.js
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import changed from "gulp-changed"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: clean images generated by build
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config) => {
|
||||
return () => {
|
||||
return gulp.src(`${config.assets.src}/images/**/*.ico`)
|
||||
.pipe(changed(`${config.assets.build}/images`))
|
||||
.pipe(gulp.dest(`${config.assets.build}/images`))
|
||||
}
|
||||
}
|
49
tasks/assets/images/build/svg.js
Normal file
49
tasks/assets/images/build/svg.js
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import changed from "gulp-changed"
|
||||
import gulpif from "gulp-if"
|
||||
import minsvg from "gulp-svgmin"
|
||||
import rev from "gulp-rev"
|
||||
import version from "gulp-rev-replace"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: clean images generated by build
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config, args) => {
|
||||
return () => {
|
||||
return gulp.src(`${config.assets.src}/images/**/*.svg`)
|
||||
.pipe(changed(`${config.assets.build}/images`))
|
||||
.pipe(gulpif(args.optimize, minsvg()))
|
||||
.pipe(gulpif(args.revision, rev()))
|
||||
.pipe(gulpif(args.revision,
|
||||
version({ manifest: gulp.src("manifest.json") })))
|
||||
.pipe(gulp.dest(`${config.assets.build}/images`))
|
||||
.pipe(gulpif(args.revision,
|
||||
rev.manifest("manifest.json", {
|
||||
base: config.assets.build,
|
||||
merge: true
|
||||
})))
|
||||
.pipe(gulpif(args.revision, gulp.dest(config.assets.build)))
|
||||
}
|
||||
}
|
35
tasks/assets/images/clean.js
Normal file
35
tasks/assets/images/clean.js
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import clean from "del"
|
||||
import vinyl from "vinyl-paths"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: clean images generated by build
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config) => {
|
||||
return () => {
|
||||
return gulp.src(`${config.assets.build}/images/*`)
|
||||
.pipe(vinyl(clean))
|
||||
}
|
||||
}
|
90
tasks/assets/javascripts/build/application.js
Normal file
90
tasks/assets/javascripts/build/application.js
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import gulpif from "gulp-if"
|
||||
import path from "path"
|
||||
import rev from "gulp-rev"
|
||||
import stream from "webpack-stream"
|
||||
import version from "gulp-rev-replace"
|
||||
import webpack from "webpack"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: build application logic
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config, args) => {
|
||||
return () => {
|
||||
return gulp.src(`${config.assets.src}/javascripts/**/*.js`)
|
||||
|
||||
/* Transpile with webpack */
|
||||
.pipe(
|
||||
stream({
|
||||
entry: "application.js",
|
||||
output: {
|
||||
filename: "application.js",
|
||||
library: "Application"
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
loader: "babel-loader",
|
||||
test: path.join(process.cwd(),
|
||||
`${config.assets.src}/javascripts`)
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.NoErrorsPlugin()
|
||||
].concat(
|
||||
args.optimize ? [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
warnings: false
|
||||
}
|
||||
})
|
||||
] : []),
|
||||
stats: {
|
||||
colors: true
|
||||
},
|
||||
resolve: {
|
||||
modulesDirectories: [
|
||||
"src/assets/javascripts",
|
||||
"node_modules"
|
||||
],
|
||||
extensions: [
|
||||
"", ".js"
|
||||
]
|
||||
},
|
||||
devtool: args.sourcemaps ? "source-map" : ""
|
||||
}))
|
||||
.pipe(gulpif(args.revision, rev()))
|
||||
.pipe(gulpif(args.revision,
|
||||
version({ manifest: gulp.src("manifest.json") })))
|
||||
.pipe(gulp.dest(`${config.assets.build}/javascripts`))
|
||||
.pipe(gulpif(args.revision,
|
||||
rev.manifest("manifest.json", {
|
||||
base: config.assets.build,
|
||||
merge: true
|
||||
})))
|
||||
.pipe(gulpif(args.revision, gulp.dest(config.assets.build)))
|
||||
}
|
||||
}
|
63
tasks/assets/javascripts/build/modernizr.js
Normal file
63
tasks/assets/javascripts/build/modernizr.js
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import concat from "gulp-concat"
|
||||
import gulpif from "gulp-if"
|
||||
import modernizr from "gulp-modernizr"
|
||||
import uglify from "gulp-uglify"
|
||||
import rev from "gulp-rev"
|
||||
import version from "gulp-rev-replace"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: build custom modernizr
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config, args) => {
|
||||
return () => {
|
||||
return gulp.src(`${config.assets.build}/stylesheets/*.css`)
|
||||
|
||||
/* Build custom modernizr */
|
||||
.pipe(
|
||||
modernizr({
|
||||
options: [
|
||||
"addTest", /* Add custom tests */
|
||||
"setClasses" /* Add CSS classes to root tag */
|
||||
]
|
||||
}))
|
||||
.pipe(concat("modernizr.js"))
|
||||
|
||||
/* Minify sources */
|
||||
.pipe(gulpif(args.optimize, uglify()))
|
||||
|
||||
/* Revisioning */
|
||||
.pipe(gulpif(args.revision, rev()))
|
||||
.pipe(gulpif(args.revision,
|
||||
version({ manifest: gulp.src("manifest.json") })))
|
||||
.pipe(gulp.dest(`${config.assets.build}/javascripts`))
|
||||
.pipe(gulpif(args.revision,
|
||||
rev.manifest("manifest.json", {
|
||||
base: config.assets.build,
|
||||
merge: true
|
||||
})))
|
||||
.pipe(gulpif(args.revision, gulp.dest(config.assets.build)))
|
||||
}
|
||||
}
|
35
tasks/assets/javascripts/clean.js
Normal file
35
tasks/assets/javascripts/clean.js
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import clean from "del"
|
||||
import vinyl from "vinyl-paths"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: clean javascripts generated by build
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config) => {
|
||||
return () => {
|
||||
return gulp.src(`${config.assets.build}/javascripts/*`)
|
||||
.pipe(vinyl(clean))
|
||||
}
|
||||
}
|
107
tasks/assets/javascripts/lint.js
Normal file
107
tasks/assets/javascripts/lint.js
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import path from "path"
|
||||
import through from "through2"
|
||||
import util from "gulp-util"
|
||||
import { CLIEngine } from "eslint"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Locals
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
const eslint = new CLIEngine
|
||||
const format = eslint.getFormatter()
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: lint SASS sources
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config) => {
|
||||
return () => {
|
||||
return gulp.src(`${config.assets.src}/javascripts/**/*.js`)
|
||||
|
||||
/* Linting */
|
||||
.pipe(
|
||||
through.obj(function(file, enc, cb) {
|
||||
if (file.isNull() || file.isStream())
|
||||
return cb()
|
||||
|
||||
/* Lint file using .eslintrc */
|
||||
file.eslint = eslint.executeOnText(
|
||||
file.contents.toString())
|
||||
|
||||
/* Correct file path */
|
||||
file.eslint.results[0].filePath =
|
||||
path.relative(process.cwd(), file.path)
|
||||
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.push(file)
|
||||
cb()
|
||||
}))
|
||||
|
||||
/* Print errors */
|
||||
.pipe(
|
||||
through.obj(function(file, enc, cb) {
|
||||
if (file.eslint.errorCount || file.eslint.warningCount) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(format(file.eslint.results))
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.push(file)
|
||||
cb()
|
||||
}))
|
||||
|
||||
/* Terminate on error */
|
||||
.pipe(
|
||||
(() => {
|
||||
const errors = []
|
||||
|
||||
/* Gather errors */
|
||||
return through.obj(function(file, enc, cb) {
|
||||
const results = file.eslint
|
||||
|
||||
/* Consider warnings as errors */
|
||||
if (results.errorCount || results.warningCount)
|
||||
errors.push(file)
|
||||
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.push(file)
|
||||
cb()
|
||||
|
||||
/* Format errors and terminate */
|
||||
}, function(cb) {
|
||||
if (errors.length > 0) {
|
||||
const message = errors.map(file => {
|
||||
return file.relative
|
||||
}).join(", ")
|
||||
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.emit("error", new util.PluginError("eslint",
|
||||
`Terminated with errors in files: ${message}`))
|
||||
}
|
||||
cb()
|
||||
})
|
||||
})())
|
||||
}
|
||||
}
|
75
tasks/assets/stylesheets/build.js
Normal file
75
tasks/assets/stylesheets/build.js
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import autoprefixer from "autoprefixer"
|
||||
import gulpif from "gulp-if"
|
||||
import mincss from "gulp-cssnano"
|
||||
import mqpacker from "css-mqpacker"
|
||||
import postcss from "gulp-postcss"
|
||||
import rev from "gulp-rev"
|
||||
import sass from "gulp-sass"
|
||||
import sourcemaps from "gulp-sourcemaps"
|
||||
import version from "gulp-rev-replace"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: build stylesheets from SASS source
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config, args) => {
|
||||
return () => {
|
||||
return gulp.src(`${config.assets.src}/stylesheets/*.scss`)
|
||||
.pipe(gulpif(args.sourcemaps, sourcemaps.init()))
|
||||
|
||||
/* Compile SASS sources */
|
||||
.pipe(
|
||||
sass({
|
||||
includePaths: [
|
||||
"node_modules/modularscale-sass/stylesheets",
|
||||
"node_modules/material-design-color",
|
||||
"node_modules/material-shadows"
|
||||
]
|
||||
}))
|
||||
|
||||
/* Apply PostCSS plugins */
|
||||
.pipe(
|
||||
postcss([
|
||||
autoprefixer(),
|
||||
mqpacker
|
||||
]))
|
||||
|
||||
/* Minify sources */
|
||||
.pipe(gulpif(args.optimize, mincss()))
|
||||
|
||||
/* Revisioning */
|
||||
.pipe(gulpif(args.revision, rev()))
|
||||
.pipe(gulpif(args.revision,
|
||||
version({ manifest: gulp.src("manifest.json") })))
|
||||
.pipe(gulpif(args.sourcemaps, sourcemaps.write(".")))
|
||||
.pipe(gulp.dest(`${config.assets.build}/stylesheets`))
|
||||
.pipe(gulpif(args.revision,
|
||||
rev.manifest("manifest.json", {
|
||||
base: config.assets.build,
|
||||
merge: true
|
||||
})))
|
||||
.pipe(gulpif(args.revision, gulp.dest(config.assets.build)))
|
||||
}
|
||||
}
|
35
tasks/assets/stylesheets/clean.js
Normal file
35
tasks/assets/stylesheets/clean.js
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import clean from "del"
|
||||
import vinyl from "vinyl-paths"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: clean stylesheets generated by build
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config) => {
|
||||
return () => {
|
||||
return gulp.src(`${config.assets.build}/stylesheets/*`)
|
||||
.pipe(vinyl(clean))
|
||||
}
|
||||
}
|
96
tasks/assets/stylesheets/lint.js
Normal file
96
tasks/assets/stylesheets/lint.js
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import path from "path"
|
||||
import sasslint from "sass-lint"
|
||||
import through from "through2"
|
||||
import util from "gulp-util"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: lint SASS sources
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config, args) => {
|
||||
return () => {
|
||||
return gulp.src(`${config.assets.src}/stylesheets/**/*.scss`)
|
||||
|
||||
/* Linting */
|
||||
.pipe(
|
||||
through.obj(function(file, enc, cb) {
|
||||
if (file.isNull() || file.isStream())
|
||||
return cb()
|
||||
|
||||
/* Lint file using .sass-lint.yml */
|
||||
file.sasslint = sasslint.lintFileText({
|
||||
text: file.contents,
|
||||
format: path.extname(file.path).replace(".", ""),
|
||||
filename: path.relative(process.cwd(), file.path)
|
||||
})
|
||||
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.push(file)
|
||||
cb()
|
||||
}))
|
||||
|
||||
/* Print errors */
|
||||
.pipe(
|
||||
through.obj(function(file, enc, cb) {
|
||||
sasslint.outputResults([file.sasslint])
|
||||
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.push(file)
|
||||
cb()
|
||||
}))
|
||||
|
||||
/* Terminate on error */
|
||||
.pipe(
|
||||
(() => {
|
||||
const errors = []
|
||||
|
||||
/* Gather errors */
|
||||
return through.obj(function(file, enc, cb) {
|
||||
const results = file.sasslint
|
||||
|
||||
/* Consider warnings as errors during clean compilation */
|
||||
if (results.errorCount || results.warningCount)
|
||||
errors.push(file)
|
||||
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.push(file)
|
||||
cb()
|
||||
|
||||
/* Format errors and terminate */
|
||||
}, function(cb) {
|
||||
if (errors.length > 0) {
|
||||
const message = errors.map(file => {
|
||||
return file.relative
|
||||
}).join(", ")
|
||||
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.emit("error", new util.PluginError("eslint",
|
||||
`Terminated with errors in files: ${message}`))
|
||||
}
|
||||
cb()
|
||||
})
|
||||
})())
|
||||
}
|
||||
}
|
33
tasks/mkdocs/build.js
Normal file
33
tasks/mkdocs/build.js
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import child from "child_process"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: build documentation
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default () => {
|
||||
return () => {
|
||||
return child.spawnSync("mkdocs", ["build"])
|
||||
}
|
||||
}
|
35
tasks/mkdocs/clean.js
Normal file
35
tasks/mkdocs/clean.js
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import clean from "del"
|
||||
import vinyl from "vinyl-paths"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: clean documentation build
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default gulp => {
|
||||
return () => {
|
||||
return gulp.src("site")
|
||||
.pipe(vinyl(clean))
|
||||
}
|
||||
}
|
58
tasks/mkdocs/serve.js
Normal file
58
tasks/mkdocs/serve.js
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import child from "child_process"
|
||||
import util from "gulp-util"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Locals
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/* MkDocs server */
|
||||
let server = null
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: serve documentation
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default () => {
|
||||
return () => {
|
||||
if (server)
|
||||
server.kill()
|
||||
|
||||
/* Spawn MkDocs server */
|
||||
server = child.spawn("mkdocs", ["serve", "-a", "0.0.0.0:8000"])
|
||||
|
||||
/* Pretty print server log output */
|
||||
server.stdout.on("data", data => {
|
||||
const lines = data.toString().split("\n")
|
||||
for (const l in lines)
|
||||
if (lines[l].length)
|
||||
util.log(lines[l])
|
||||
})
|
||||
|
||||
/* Print errors to stdout */
|
||||
server.stderr.on("data", data => {
|
||||
process.stdout.write(data.toString())
|
||||
})
|
||||
}
|
||||
}
|
55
tasks/views/build.js
Normal file
55
tasks/views/build.js
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import changed from "gulp-changed"
|
||||
import compact from "gulp-remove-empty-lines"
|
||||
import gulpif from "gulp-if"
|
||||
import minhtml from "gulp-htmlmin"
|
||||
import path from "path"
|
||||
import replace from "gulp-replace"
|
||||
import version from "gulp-rev-replace"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: minify views
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config, args) => {
|
||||
return () => {
|
||||
const metadata = require(path.join(process.cwd(), "./package.json"))
|
||||
return gulp.src(`${config.views.src}/**/*.html`)
|
||||
.pipe(changed(config.views.build))
|
||||
.pipe(
|
||||
minhtml({
|
||||
collapseBooleanAttributes: true,
|
||||
removeComments: true,
|
||||
removeScriptTypeAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
customAttrCollapse: /(content)/
|
||||
}))
|
||||
.pipe(replace("$theme-name$", metadata.name))
|
||||
.pipe(replace("$theme-version$", metadata.version))
|
||||
.pipe(compact())
|
||||
.pipe(gulpif(args.revision,
|
||||
version({ manifest: gulp.src("manifest.json") })))
|
||||
.pipe(gulp.dest(config.views.build))
|
||||
}
|
||||
}
|
35
tasks/views/clean.js
Normal file
35
tasks/views/clean.js
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import clean from "del"
|
||||
import vinyl from "vinyl-paths"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Task: clean views
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default (gulp, config) => {
|
||||
return () => {
|
||||
return gulp.src(`${config.views.build}/**/*.html`)
|
||||
.pipe(vinyl(clean))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user