Rewrite of Gulp asset pipeline in ES6 and separation of tasks

This commit is contained in:
squidfunk 2016-10-06 12:14:33 +02:00
parent 46f45bb8a9
commit 914ccc4550
61 changed files with 1747 additions and 568 deletions

6
.babelrc Normal file
View File

@ -0,0 +1,6 @@
{
"presets": ["es2015"],
"plugins": [
"add-module-exports"
]
}

View File

@ -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
View File

@ -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

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
6.7.0

View File

@ -21,6 +21,7 @@
files:
ignore:
- src/assets/stylesheets/_shame.scss
- src/assets/stylesheets/extensions/_codehilite.scss # Temporary disabled
options:
merge-default-rules: true

View File

@ -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:

View File

@ -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
View 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"])

View File

@ -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"])

View File

@ -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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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 %}

View File

@ -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",

View File

@ -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")

View 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()
}
}

View 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
}

View File

@ -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()
}
}

View 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
})
}
}

View 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
}
}

View File

@ -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

View File

@ -20,8 +20,6 @@
* IN THE SOFTWARE.
*/
"use strict"
/* ----------------------------------------------------------------------------
* Search
* ------------------------------------------------------------------------- */

View File

@ -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

View File

@ -21,7 +21,7 @@
////
// ----------------------------------------------------------------------------
// Nothing to see here, move along
// Rules
// ----------------------------------------------------------------------------
@include break-from-device(screen) {

View File

@ -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";

View File

@ -21,7 +21,7 @@
////
// ----------------------------------------------------------------------------
// Icon set
// Rules
// ----------------------------------------------------------------------------
// Icon placeholders

View File

@ -21,7 +21,7 @@
////
// ----------------------------------------------------------------------------
// Resets
// Rules
// ----------------------------------------------------------------------------
// Enfore correct box model - the prefixed versions are necessary for older

View File

@ -21,7 +21,7 @@
////
// ----------------------------------------------------------------------------
// Font definitions
// Rules: font definitions
// ----------------------------------------------------------------------------
// Default fonts
@ -57,7 +57,7 @@ kbd {
}
// ----------------------------------------------------------------------------
// Typeset
// Rules: typesetted content
// ----------------------------------------------------------------------------
// Content that is typeset

View File

@ -21,10 +21,10 @@
////
// ----------------------------------------------------------------------------
// Admonition extension
// Rules
// ----------------------------------------------------------------------------
// Admonition
// Admonition extension
.admonition {
position: relative;
margin: 2.0rem 0;

View File

@ -21,10 +21,10 @@
////
// ----------------------------------------------------------------------------
// Codehilite extension
// Rules
// ----------------------------------------------------------------------------
// Github-style syntax highlighting
// Codehilite extension
.codehilite,
.code {

View File

@ -21,10 +21,10 @@
////
// ----------------------------------------------------------------------------
// Footnotes extension
// Rules
// ----------------------------------------------------------------------------
// Footnote
// Footnotes extension
.footnote {
color: $md-color-black--light;
font-size: 80%;

View File

@ -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;

View File

@ -51,7 +51,7 @@
$break-devices: () !default;
// ----------------------------------------------------------------------------
// Breakpoint helpers
// Helpers
// ----------------------------------------------------------------------------
///
@ -115,7 +115,7 @@ $break-devices: () !default;
}
// ----------------------------------------------------------------------------
// Breakpoint mixins
// Mixins
// ----------------------------------------------------------------------------
///

View File

@ -21,7 +21,7 @@
////
// ----------------------------------------------------------------------------
// Pixel conversion helpers
// Helpers
// ----------------------------------------------------------------------------
///

View File

@ -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

View File

@ -21,7 +21,7 @@
////
// ----------------------------------------------------------------------------
// Main content
// Rules
// ----------------------------------------------------------------------------
// Content container

View File

@ -21,7 +21,7 @@
////
// ----------------------------------------------------------------------------
// Footer
// Rules
// ----------------------------------------------------------------------------
// Application footer

View File

@ -21,7 +21,7 @@
////
// ----------------------------------------------------------------------------
// Header
// Rules
// ----------------------------------------------------------------------------
// Application header (stays always on top)

View File

@ -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;
}

View File

@ -21,10 +21,10 @@
////
// ----------------------------------------------------------------------------
// Search
// Rules
// ----------------------------------------------------------------------------
// Application search
// Search container
.md-search {
padding: 0.8rem 0.8rem 0;

View File

@ -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);

View File

@ -21,10 +21,10 @@
////
// ----------------------------------------------------------------------------
// Source
// Rules
// ----------------------------------------------------------------------------
// Repository containing source
// Source container
.md-source {
display: block;
transition: opacity 0.25s;

View File

@ -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 %}

View 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`))
}
}

View 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)))
}
}

View 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))
}
}

View 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)))
}
}

View 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)))
}
}

View 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))
}
}

View 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()
})
})())
}
}

View 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)))
}
}

View 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))
}
}

View 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
View 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
View 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
View 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
View 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
View 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))
}
}