├── util └── build.js ├── favicon.ico ├── static ├── image │ ├── jsjzh.png │ └── cursor.png └── css │ ├── reset.css │ ├── normalize.css │ └── github-markdown.css ├── study ├── README.md ├── _build │ ├── build.js │ ├── webpack.prod.conf.js │ ├── build-server.js │ ├── webpack.base.conf.js │ ├── dev.js │ ├── utils.js │ └── webpack.dev.conf.js ├── _config │ ├── dev.env.js │ ├── prod.env.js │ └── index.js └── build │ ├── utils.js │ └── webpack.config.js ├── .babelrc ├── .gitignore ├── .postcssrc.js ├── .editorconfig ├── index.html ├── src ├── index.js ├── index.scss └── index.html ├── config └── index.js ├── package.json └── README.md /util/build.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsjzh/mini-app-template/HEAD/favicon.ico -------------------------------------------------------------------------------- /static/image/jsjzh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsjzh/mini-app-template/HEAD/static/image/jsjzh.png -------------------------------------------------------------------------------- /study/README.md: -------------------------------------------------------------------------------- 1 | # study 2 | 3 | ## 说明 4 | > 关于项目所用的 webpack 配置详细说明会在这里写出来 5 | 6 | - 前面带了 `_` 的是曾经的配置说明 -------------------------------------------------------------------------------- /static/image/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsjzh/mini-app-template/HEAD/static/image/cursor.png -------------------------------------------------------------------------------- /study/_build/build.js: -------------------------------------------------------------------------------- 1 | // require('./check-versions')() 2 | process.env.NODE_ENV = 'production' 3 | 4 | var config = require('../config') 5 | -------------------------------------------------------------------------------- /study/_config/dev.env.js: -------------------------------------------------------------------------------- 1 | // 注意,因为这个插件直接执行文本替换,给定的值必须包含字符串本身内的实际引号。通常,有两种方式来达到这个效果,使用 '"production"', 或者使用 JSON.stringify('production')。 2 | module.exports = { 3 | NODE_ENV: JSON.stringify('development') 4 | } 5 | -------------------------------------------------------------------------------- /study/_config/prod.env.js: -------------------------------------------------------------------------------- 1 | // 注意,因为这个插件直接执行文本替换,给定的值必须包含字符串本身内的实际引号。通常,有两种方式来达到这个效果,使用 '"production"', 或者使用 JSON.stringify('production')。 2 | module.exports = { 3 | NODE_ENV: JSON.stringify('production') 4 | } 5 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "modules": false, 7 | "targets": { 8 | "browsers": ["> 1%", "last 2 versions"] 9 | } 10 | } 11 | ], 12 | "stage-2" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | **/*.log 8 | 9 | # Editor directories and files 10 | .idea 11 | .vscode 12 | *.suo 13 | *.ntvs* 14 | *.njsproj 15 | *.sln 16 | 17 | package-lock.json 18 | yarn.lock -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | plugins: { 5 | 'postcss-import': {}, 6 | 'postcss-url': {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | autoprefixer: {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | insert_final_newline = false 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | small app template 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // 在 webpack.config.js 中配置了 alias 2 | // 会自动解析 static 为 webpack.config.js 目录下的 utils.resolve("static") 3 | // import 'static/css/normalize.css' 4 | // import 'static/css/reset.css' 5 | // import 'static/css/github-markdown.css' 6 | // import './index.scss' 7 | 8 | const app = document.getElementById('app') 9 | // app.innerHTML = require('./index.html') 10 | // ------------- 11 | // 开始写项目代码 12 | 13 | // ------------- 14 | // if (module.hot) { 15 | // module.hot.accept() 16 | // } 17 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const path = require('path') 4 | 5 | function resolve(dir) { 6 | return path.join(__dirname, '..', dir) 7 | } 8 | 9 | module.exports = { 10 | dev: { 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/' 13 | }, 14 | build: { 15 | assetsRoot: resolve('dist'), 16 | assetsSubDirectory: 'static', 17 | productionSourceMap: false, 18 | // 如果你希望将应用部署在 www.example.com/bar/ 下 19 | // 那就需要设置为 /bar/ 20 | // 大部分应用只要设置 / 即可 21 | assetsPublicPath: '/' 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/index.scss: -------------------------------------------------------------------------------- 1 | #app { 2 | min-width: 200px; 3 | max-width: 767px; 4 | margin: 0 auto; 5 | padding: 45px; 6 | .ct { 7 | text-align: center; 8 | } 9 | .header-image { 10 | width: 35px; 11 | height: 35px; 12 | } 13 | .fr { 14 | float: right; 15 | } 16 | .fl { 17 | float: left; 18 | } 19 | #change-image { 20 | animation: 1s image-animate infinite; 21 | } 22 | } 23 | 24 | @media (max-width: 767px) { 25 | #app { 26 | padding: 15px; 27 | } 28 | } 29 | 30 | @keyframes image-animate { 31 | 100% { 32 | transform: rotate(360deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /study/_build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var config = require('../config') 2 | var path = require('path') 3 | var webpack = require('webpack') 4 | var merge = require('webpack-merge') 5 | var HtmlWebpackPlugin = require('html-webpack-plugin') 6 | var webpackBaseConfig = require('./webpack.base.conf') 7 | 8 | module.exports = merge(webpackBaseConfig, { 9 | mode: 'production', 10 | output: { 11 | filename: '[name].js', 12 | path: utils.resolve('dist'), 13 | publicPath: '/' 14 | }, 15 | plugins: [ 16 | new HtmlWebpackPlugin({ 17 | filename: 'index.html', 18 | template: 'index.html', 19 | inject: true 20 | }) 21 | ] 22 | }) 23 | -------------------------------------------------------------------------------- /study/_config/index.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | 3 | function resolve(file) { 4 | return path.resolve(__dirname, '../', file) 5 | } 6 | 7 | module.exports = { 8 | dev: { 9 | env: require('./dev.env'), 10 | // host: "localhost", 11 | port: 8080, 12 | devtool: 'cheap-module-eval-source-map', 13 | autoOpenBrowser: true, 14 | errorOverlay: true, 15 | notifyOnErrors: true, 16 | assetsPublicPath: '/', 17 | assetsSubDirectory: 'static', 18 | poll: false, 19 | proxyTable: {} 20 | }, 21 | build: { 22 | env: require('./prod.env'), 23 | assetsRoot: resolve('./dist'), 24 | assetsSubDirectory: 'static', 25 | assetsPublicPath: '/' 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /study/_build/build-server.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | // 更友好的提示插件 3 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 4 | // 获取一个可用的 port 的插件 5 | var portfinder = require('portfinder') 6 | var devWebpackConfig = require('./webpack.dev.conf') 7 | 8 | // 导出一个 promise 函数,这可以让 wepback 接受一个异步加载的配置 9 | // 并在 resolve 的时候运行 这个配置 10 | // 比如这里我就用到了 portfinder 和 friendly-errors-webpack-plugin 11 | module.exports = new Promise((resolve, reject) => { 12 | portfinder.basePort = devWebpackConfig.devServer.port 13 | portfinder.getPort((err, port) => { 14 | if (err) reject(err) 15 | else { 16 | devWebpackConfig.devServer.port = port 17 | devWebpackConfig.plugins.push( 18 | new FriendlyErrorsPlugin({ 19 | clearConsole: true, 20 | compilationSuccessInfo: { 21 | messages: [`开发环境启动成功,项目运行在: http://${devWebpackConfig.devServer.host}:${port}`] 22 | }, 23 | onErrors: utils.createNotifierCallback() 24 | }) 25 | ) 26 | resolve(devWebpackConfig) 27 | } 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /study/build/utils.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const os = require('os') 3 | const packageConfig = require('../package.json') 4 | const notifier = require('node-notifier') 5 | 6 | exports.resolve = function(dir) { 7 | return path.join(__dirname, '..', dir) 8 | } 9 | 10 | exports.assetsPath = function(_path) { 11 | return path.posix.join('static', _path) 12 | } 13 | 14 | exports.getIPAdress = function() { 15 | const interfaces = os.networkInterfaces() 16 | for (const devName in interfaces) { 17 | const iface = interfaces[devName] 18 | for (let i = 0; i < iface.length; i++) { 19 | const alias = iface[i] 20 | if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) { 21 | return alias.address 22 | } 23 | } 24 | } 25 | } 26 | 27 | exports.createNotifierCallback = function() { 28 | return (severity, errors) => { 29 | if (severity !== 'error') return 30 | const error = errors[0] 31 | const filename = error.file && error.file.split('!').pop() 32 | notifier.notify({ 33 | title: packageConfig.name, 34 | message: severity + ': ' + error.name, 35 | subtitle: filename || '' 36 | }) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /static/css/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v4.0 | 20180602 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | main, menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, main, menu, nav, section { 29 | display: block; 30 | } 31 | /* HTML5 hidden-attribute fix for newer browsers */ 32 | *[hidden] { 33 | display: none; 34 | } 35 | body { 36 | line-height: 1; 37 | } 38 | ol, ul { 39 | list-style: none; 40 | } 41 | blockquote, q { 42 | quotes: none; 43 | } 44 | blockquote:before, blockquote:after, 45 | q:before, q:after { 46 | content: ''; 47 | content: none; 48 | } 49 | table { 50 | border-collapse: collapse; 51 | border-spacing: 0; 52 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mini-app-template", 3 | "version": "1.0.0", 4 | "description": "一个用于展示小项目的脚手架 可以自动处理 js css 的功能 修改 src 中的文件会进行热更新", 5 | "scripts": { 6 | "build": "cross-env NODE_ENV=production node ./build/build.js", 7 | "dev:new": "cross-env NODE_ENV=production node ./build/build.js", 8 | "dev:old": "webpack-dev-server --inline --progress --config build/webpack.config.js", 9 | "start": "npm run build" 10 | }, 11 | "author": "jsjzh ", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "autoprefixer": "^9.0.1", 15 | "babel-core": "^6.26.3", 16 | "babel-loader": "^7.1.5", 17 | "babel-preset-env": "^1.7.0", 18 | "babel-preset-stage-2": "^6.24.1", 19 | "chalk": "^2.4.2", 20 | "copy-webpack-plugin": "^4.6.0", 21 | "cross-env": "^5.2.0", 22 | "css-loader": "^1.0.0", 23 | "file-loader": "^3.0.1", 24 | "friendly-errors-webpack-plugin": "^1.7.0", 25 | "html-webpack-plugin": "^3.2.0", 26 | "mini-css-extract-plugin": "^0.5.0", 27 | "node-notifier": "^5.2.1", 28 | "node-sass": "^4.9.3", 29 | "optimize-css-assets-webpack-plugin": "^5.0.1", 30 | "ora": "^3.0.0", 31 | "postcss-loader": "^2.1.6", 32 | "raw-loader": "^0.5.1", 33 | "rimraf": "^2.6.3", 34 | "sass-loader": "^7.1.0", 35 | "script-ext-html-webpack-plugin": "^2.1.3", 36 | "shelljs": "^0.8.3", 37 | "style-loader": "^0.21.0", 38 | "uglifyjs-webpack-plugin": "^2.1.1", 39 | "url-loader": "^1.1.2", 40 | "webpack": "^4.16.1", 41 | "webpack-cli": "^3.0.8", 42 | "webpack-dev-server": "^3.1.4", 43 | "webpack-merge": "^4.2.1", 44 | "yargs": "^12.0.5" 45 | }, 46 | "dependencies": { 47 | "babel-polyfill": "^6.26.0" 48 | }, 49 | "engines": { 50 | "node": ">= 6.0.0", 51 | "npm": ">= 3.0.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mini-app-template 2 | 3 | ## 介绍 4 | 该 `template` 是所有带前缀 `mini-app` 的小项目的基础模板,在做项目的时候有的时候会想总结一些插件工具的用法,这个时候就会基于这个模板写一个项目的小 `demo`,还有的时候做面试题也会碰到一些好玩的面试题,又或者只是想记录一些好玩的 `js` 的方法,都可以以这个 `template` 为基础敲敲打打。 5 | 6 | 考虑到浏览器的情况,可能会需要做做 `ES6` 转 `ES5`,还希望用用 `sass` [(点我查看 sass 语法)](https://www.sass.hk/docs/) 让 `css` 写起来更舒畅一些,而且热更新的方法肯定是不能少的,每次都要 `F5` 不是很绝望么,我就以达到上述需求为目的,进行了该脚手架的开发。 7 | 8 | 项目中有一个 `study` 的目录,我的打算是在这个目录下存放一份当前环境下的 `build` 的配置详解,关于如何搭建等等也会在里面写一个 `README.md`,毕竟搭建的时候还是有一些小点需要注意的。 9 | 10 | ## mini-app 大合集 11 | - [mini-app-template](https://github.com/jsjzh/mini-app-template) 这就是该项目 12 | - [mini-app-tiny-code](https://github.com/jsjzh/mini-app-tiny-code) 一个收集 js 好玩的代码,好玩的面试题的地方 13 | 14 | 15 | ## 我该如何开始 16 | 首先一套组合拳,将项目拉到本地,这一步我们有两种做法。 17 | 18 | ### 方法一(推荐) 19 | 直接点击该项目右上角的 `fork`,在你的仓库中生成一份 `mini-app-template`,这样你不仅可以 `clone` 自己仓库中的 `mini-app-template` 代码,还可以 `pull request`,将你觉得这个项目可以完善的地方告诉我,我会及时查看并且合并的喔~笔芯 `*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。` 20 | 21 | ### 方法二 22 | 直接 clone 我的代码。 23 | ``` 24 | $ git clone https://github.com/jsjzh/mini-app-template.git 25 | $ cd mini-app-template 26 | $ npm install // or yarn 27 | $ npm start // or yarn start 28 | ``` 29 | 30 | ### 接着,如果我想创建一个新的 mini-app-new-app 怎么办 31 | 如果你想要以这个项目为模板,创建一个自己的 `mini-app` 用于展示 32 | 33 | 第一步:你需要删除 `mini-app-template` 目录下的 `.git` 34 | 第二步:在 `git` 上新建一个新的项目,我这里假设新建的项目名称为 `mini-app-new-app`(第四行别忘了改 `jsjzh` 为你自己的 `git` 账号) 35 | ``` 36 | $ git init 37 | $ git add . 38 | $ git commit -m "nimi-app-new-app first commit oh yeah ~" 39 | $ git remote add origin git@github.com:jsjzh/mini-app-new-app.git 40 | $ git push -u origin master 41 | ``` 42 | 43 | 最后,你就可以在这个项目下快乐的写自己的 `mini-app` 啦,撒花 万岁 `~\(≧▽≦)/~` 44 | 45 | 如果可以的话,请告诉我你的项目地址,我就可以把他们添加到我的 `mini-app` 列表中了。 46 | 47 | 代码如人生,我甘之如饴。 48 | 49 | ## 完成该项目功能所需模块整理 50 | - js 51 | - ES6 转 ES5 52 | - babel-core 53 | - babel-loader 54 | - babel-preset-env 55 | - babel-preset-stage-2 56 | - 补全 ES5 没有的一些方法 57 | - babel-polyfill 58 | - html 59 | - 使用 html 模板 并自动注入打包好的 js 文件 60 | - html-webpack-plugin 61 | - 将 html 文件转为字符串 62 | - raw-loader 63 | - css 64 | - 处理 scss|sass|css 文件 65 | - 从JS字符串创建样式节点 66 | - style-loader 67 | - 将 css 转换为 commonJs 68 | - css-loader 69 | - 将 sass 转为 css 70 | - sass-loader 71 | - node-sass 72 | - css 补全计划 73 | - postcss-loader 74 | - autoprefixer 75 | - 热更新 76 | - webpack-dev-server 77 | -------------------------------------------------------------------------------- /study/build/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const HtmlWebpackPlugin = require('html-webpack-plugin') 3 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 4 | 5 | const utils = require('./utils') 6 | 7 | const IP = utils.getIPAdress() 8 | const POTR = 8888 9 | 10 | module.exports = { 11 | context: utils.resolve('./'), 12 | mode: 'development', 13 | entry: { 14 | app: ['babel-polyfill', './src/index.js'] 15 | }, 16 | devtool: 'cheap-module-eval-source-map', 17 | output: { 18 | path: utils.resolve('dist'), 19 | filename: '[name].[hash].js', 20 | publicPath: '/' 21 | }, 22 | resolve: { 23 | extensions: ['.js', '.json'], 24 | alias: { 25 | '@': utils.resolve('src'), 26 | static: utils.resolve('static') 27 | } 28 | }, 29 | module: { 30 | rules: [ 31 | { 32 | test: /\.(html)$/, 33 | use: [ 34 | { 35 | loader: 'raw-loader' 36 | } 37 | ] 38 | }, 39 | { 40 | test: /\.(js)$/, 41 | loader: 'babel-loader', 42 | exclude: /node_modules/, 43 | include: [utils.resolve('src'), utils.resolve('node_modules/webpack-dev-server/client')] 44 | }, 45 | { 46 | test: /\.(scss|css|sass)$/, 47 | use: [ 48 | 'style-loader', 49 | { 50 | loader: 'css-loader', 51 | options: { 52 | importLoaders: 2 53 | } 54 | }, 55 | 'sass-loader', 56 | 'postcss-loader' 57 | ] 58 | } 59 | ] 60 | }, 61 | devServer: { 62 | clientLogLevel: 'warning', 63 | hot: true, 64 | compress: true, 65 | port: POTR, 66 | open: true, 67 | overlay: { 68 | warnings: false, 69 | errors: true 70 | }, 71 | quiet: true, 72 | host: IP, 73 | publicPath: '/' 74 | }, 75 | plugins: [ 76 | new webpack.DefinePlugin({ 77 | 'process.env': JSON.stringify('development') 78 | }), 79 | new webpack.HotModuleReplacementPlugin(), 80 | new HtmlWebpackPlugin({ 81 | filename: 'index.html', 82 | template: 'index.html', 83 | inject: true 84 | }), 85 | new FriendlyErrorsPlugin({ 86 | clearConsole: true, 87 | compilationSuccessInfo: { 88 | messages: [`你的项目在这里吼~ (╯‵□′)╯︵ http://${IP}:${POTR}`] 89 | }, 90 | onErrors: utils.createNotifierCallback() 91 | }) 92 | ] 93 | } 94 | -------------------------------------------------------------------------------- /study/_build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var config = require('../config') 3 | 4 | module.exports = { 5 | // webpack 处理打包文件的时候的初始目录 6 | // utils.resolve 其实就是对 nodeJs 的 path 模块的包装 7 | // 因为文件都是在 build 目录下 8 | // 因为很多地方都要得到项目的初始目录 9 | // 就包装了一下 path.resolve(__dirname, "../", file) 10 | context: utils.resolve('./'), 11 | // 入口文件,webapck 4.x 默认的就是这儿 12 | // 其实对于需要使用 ES6 语法转换的场景,这里还会需要一个 babel-polyfill 13 | // 这个是对于一些 ES6 的函数的声明,和 babel-preset-env 进行的语法转义不同 14 | // 比如 Array.from 这个在就是 ES6 新函数,是 babel-polyfill 做的事儿 15 | // 而 () => {} 或者 let { name, age } = obj; 这就是 babel-preset-env 做的事情 16 | entry: { 17 | // 使用 babel-polyfill,这会在全局增加一些 ES6 的方法用于调用 18 | app: ['babel-polyfill', './src/index.js'] 19 | }, 20 | // 输出文件的目录 21 | output: { 22 | path: config.build.assetsRoot, 23 | filename: '[name].js', 24 | publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath 25 | }, 26 | // 根据语法生成 AST 树,用于描述当前的语句,方便 babel 进行转换 27 | // babel-core 28 | // webpack 的 babel-loader 插件 29 | // babel-loader 30 | // .babelirc 中配置 31 | // babel-preset-env 32 | // babel 所需要转换的语法支持 33 | // babel-preset-stage-2 34 | // 包含了很多 ES6 的语法 35 | // babel-polyfill 36 | module: { 37 | rules: [ 38 | { 39 | test: /\.js$/, 40 | loader: 'babel-loader', 41 | include: [utils.resolve('src'), utils.resolve('node_modules/webpack-dev-server/client')] 42 | }, 43 | { 44 | test: /\.css$/, 45 | use: [ 46 | { 47 | loader: 'style-loader' 48 | }, 49 | { 50 | loader: 'css-loader' 51 | }, 52 | { 53 | loader: 'postcss-loader' 54 | } 55 | ] 56 | }, 57 | { 58 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 59 | loader: 'url-loader', 60 | options: { 61 | limit: 10000, 62 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 63 | } 64 | }, 65 | { 66 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 67 | loader: 'url-loader', 68 | options: { 69 | limit: 10000, 70 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 71 | } 72 | }, 73 | { 74 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 75 | loader: 'url-loader', 76 | options: { 77 | limit: 10000, 78 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 79 | } 80 | } 81 | ] 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /study/_build/dev.js: -------------------------------------------------------------------------------- 1 | // require('./check-versions')() 2 | process.env.NODE_ENV = 'development' 3 | 4 | var config = require('../config') 5 | var utils = require('./utils') 6 | var webpackConfig = require('./webpack.dev.conf') 7 | 8 | // 该插件可以在浏览器中打开一个网址 9 | var opn = require('opn') 10 | // 由于是用于 dev 的环境,所以对于性能以及 diy 性要求不高,遂和 vue-cli 一样直接使用大而全的 express 搭建 11 | var express = require('express') 12 | // 该处就类似于 webpack 官网中的命令行输入 webpack 一样 13 | var webpack = require('webpack') 14 | // webpack-dev-middleware 中间件 15 | // 可以用作 express 的中间件 该中间件可以使编译后的代码运行在内存中而不是打包到硬盘上 16 | // 和其他教程中使用的 webpack-dev-sever 有所不同 17 | // webpack-dev-server 是直接包装了一个服务器(可以看做是我们项目里的 express)和热更新插件,并且可以直接使用 18 | // https://webpack.docschina.org/guides/development/#%E4%BD%BF%E7%94%A8-webpack-dev-server 19 | var webpackDevMiddlerware = require('webpack-dev-middleware') 20 | // HMR 是 webpack 提供的最有用的功能之一 --- 摘自官网 21 | // 如果我们使用的是 webpack-dev-server 那就不用再使用 webpack-hot-middleware 了 22 | // 因为上面我用了 webpack-dev-middleware 的中间件 所以这里还需要进行 webpack-hot-middleware 的配置 23 | // 在许多文章中都看到 module.hot.accept 的写法 24 | // https://webpack.docschina.org/api/hot-module-replacement 25 | // 但如果你使用了 vue-loader 它会针对 vue 项目提供开箱即用的效果,意思就是自己用再写 module.hot-accept 了 26 | // 想要深入了解的人可以去看看 vue-hot-reload-api 插件,源码里面就使用了该方法,该插件在 vue-loader 插件中使用 27 | // 包括样式的无刷新更新 这个是 style-loader 提供的功能 28 | // TODO 热编译和热更新和刷新浏览器 29 | var webpackHotMiddlerware = require('webpack-hot-middleware') 30 | 31 | var port = config.dev.port 32 | var autoOpenBrowser = !!config.dev.autoOpenBrowser 33 | // 这里没有直接使用 localhost 作为访问地址 34 | // 而是使用了局域网 ip 35 | // 如果和其他同事处于相同的局域网,他就可以直接访问你的服务地址而实时看到你做的修改 36 | var ip = utils.getIPAdress() 37 | 38 | var app = express() 39 | // 这里就是相当与命令行执行了 webpack --config webpack.config.js 40 | // 采用文件的形式执行不仅可以方便使用中间件而且也更加直观 41 | var compiler = webpack(webpackConfig) 42 | 43 | // 配置 webpack-dev-middleware 中间件 44 | // https://segmentfault.com/a/1190000011761306 45 | var devMiddleware = webpackDevMiddlerware(compiler, { 46 | publicPath: webpackConfig.output.publicPath, 47 | quiet: true 48 | }) 49 | // 配置 webpack-hot-middleware 中间件 50 | // https://segmentfault.com/a/1190000011761345 51 | var hotMiddleware = webpackHotMiddlerware(compiler, { 52 | log: false, 53 | heartbeat: 2000 54 | }) 55 | 56 | // TODO 57 | // force page reload when html-webpack-plugin template changes 58 | // currently disabled until this is resolved: 59 | // https://github.com/jantimon/html-webpack-plugin/issues/680 60 | // compiler.plugin('compilation', function (compilation) { 61 | // compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 62 | // hotMiddleware.publish({ action: 'reload' }) 63 | // cb() 64 | // }) 65 | // }) 66 | 67 | // TODO 68 | // handle fallback for HTML5 history API 69 | // app.use(require('connect-history-api-fallback')()) 70 | 71 | // 将中间件分别装载 72 | app.use(hotMiddleware) 73 | app.use(devMiddleware) 74 | // 设置搭建的 web 服务器可以访问的静态文件的地址 75 | // 相关文档应该参考 express 76 | // http://www.expressjs.com.cn/starter/static-files.html 77 | app.use(express.static('static')) 78 | // 在 compiler 之后执行监听端口和打开浏览器的操作 79 | devMiddleware.waitUntilValid(() => { 80 | if (autoOpenBrowser) opn(`http://${ip}:${port}`) 81 | app.listen(port, ip) 82 | }) 83 | -------------------------------------------------------------------------------- /study/_build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | var path = require('path') 3 | var os = require('os') 4 | const packageConfig = require('../package.json') 5 | var config = require('../config') 6 | // var ExtractTextPlugin = require('extract-text-webpack-plugin') 7 | 8 | exports.resolve = function(file) { 9 | return path.resolve(__dirname, '../', file) 10 | } 11 | 12 | exports.getIPAdress = function() { 13 | var interfaces = os.networkInterfaces() 14 | for (var devName in interfaces) { 15 | var iface = interfaces[devName] 16 | for (var i = 0; i < iface.length; i++) { 17 | var alias = iface[i] 18 | if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) { 19 | return alias.address 20 | } 21 | } 22 | } 23 | } 24 | 25 | exports.createNotifierCallback = function() { 26 | var notifier = require('node-notifier') 27 | return (severity, errors) => { 28 | if (severity !== 'error') return 29 | var error = errors[0] 30 | var filename = error.file && error.file.split('!').pop() 31 | 32 | notifier.notify({ 33 | title: packageConfig.name, 34 | message: severity + ': ' + error.name, 35 | subtitle: filename || '' 36 | }) 37 | } 38 | } 39 | 40 | exports.assetsPath = function(_path) { 41 | const assetsSubDirectory = 42 | process.env.NODE_ENV === 'production' ? config.build.assetsSubDirectory : config.dev.assetsSubDirectory 43 | return path.posix.join(assetsSubDirectory, _path) 44 | } 45 | 46 | // exports.assetsPath = function (_path) { 47 | // var assetsSubDirectory = process.env.NODE_ENV === 'production' ? 48 | // config.build.assetsSubDirectory : 49 | // config.dev.assetsSubDirectory 50 | // return path.posix.join(assetsSubDirectory, _path) 51 | // } 52 | 53 | // exports.cssLoaders = function (options) { 54 | // options = options || {} 55 | 56 | // var cssLoader = { 57 | // loader: 'css-loader', 58 | // options: { 59 | // minimize: process.env.NODE_ENV === 'production', 60 | // sourceMap: options.sourceMap 61 | // } 62 | // } 63 | 64 | // // generate loader string to be used with extract text plugin 65 | // function generateLoaders(loader, loaderOptions) { 66 | // var loaders = [cssLoader] 67 | // if (loader) { 68 | // loaders.push({ 69 | // loader: loader + '-loader', 70 | // options: Object.assign({}, loaderOptions, { 71 | // sourceMap: options.sourceMap 72 | // }) 73 | // }) 74 | // } 75 | 76 | // // Extract CSS when that option is specified 77 | // // (which is the case during production build) 78 | // if (options.extract) { 79 | // return ExtractTextPlugin.extract({ 80 | // use: loaders, 81 | // fallback: 'vue-style-loader' 82 | // }) 83 | // } else { 84 | // return ['vue-style-loader'].concat(loaders) 85 | // } 86 | // } 87 | 88 | // // https://vue-loader.vuejs.org/en/configurations/extract-css.html 89 | // return { 90 | // css: generateLoaders(), 91 | // postcss: generateLoaders(), 92 | // less: generateLoaders('less'), 93 | // sass: generateLoaders('sass', { 94 | // indentedSyntax: true 95 | // }), 96 | // scss: generateLoaders('sass'), 97 | // stylus: generateLoaders('stylus'), 98 | // styl: generateLoaders('stylus') 99 | // } 100 | // } 101 | 102 | // // Generate loaders for standalone style files (outside of .vue) 103 | // exports.styleLoaders = function (options) { 104 | // var output = [] 105 | // var loaders = exports.cssLoaders(options) 106 | // for (var extension in loaders) { 107 | // var loader = loaders[extension] 108 | // output.push({ 109 | // test: new RegExp('\\.' + extension + '$'), 110 | // use: loader 111 | // }) 112 | // } 113 | // return output 114 | // } 115 | -------------------------------------------------------------------------------- /study/_build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | // 这里是去读取在 config 中的配置文件 2 | var config = require('../config') 3 | // 然后把配置文件的配置放到一个比较短的变量里面 对 能偷懒绝不站着 4 | var devConfig = config.dev 5 | // 一些自己写的工具函数,里面有个比较有用的函数 6 | // utils.getIPAdress 7 | // 这个可以获取你的电脑的 ip 地址,然后开发服务器就可以搭建在局域网里 8 | // 如果有一同开发的小伙伴,在同一局域网内就可以直接访问地址看到你的页面 9 | // 同样,这个也适用于手机,连上同一个 wifi 之后就可以在手机上实时看到修改的效果 10 | var utils = require('./utils') 11 | // nodeJs 内置的函数,专门用来解析路径啥的 12 | var path = require('path') 13 | // 大名鼎鼎的 webpack 14 | var webpack = require('webpack') 15 | // webpack-merge 插件,可以把 webpack 的配置进行 merge 16 | // 这里就用他 merge 了 base 和 dev 配置 17 | var merge = require('webpack-merge') 18 | // html-webpack-plugin 这个插件一定不陌生 19 | // 他可以生成 html 文件,并把 webpack 打包好的 bundle 插入到 html 文件中 20 | var HtmlWebpackPlugin = require('html-webpack-plugin') 21 | // 这个是在用 webpack 打包时,dev 和 prod 环境都适用的基础配置 22 | var webpackBaseConfig = require('./webpack.base.conf') 23 | 24 | module.exports = merge(webpackBaseConfig, { 25 | // webpack 4.x 新的东东,详细的可以在 readme.md 中查看 26 | mode: 'development', 27 | // 一句话,这是个方便开发工具进行代码定位的配置 28 | // 但是不同的配置会影响编译速度和打包速度,我这里使用了和 vue-cli 同样的配置 29 | devtool: devConfig.devtool, 30 | // 使用了 webpack-dev-server 之后就需要有的配置 31 | // 在这里可以配置详细的开发环境 32 | devServer: { 33 | // 当我们在 package.json 中使用 webpack-dev-server --inline 模式的时候 34 | // 我们在 chrome 的开发工具的控制台 console 可以看到信息种类 35 | // 可选 none error warning info 36 | clientLogLevel: 'warning', 37 | // Not to worry: To fix the issue, all you need to do is add a simple catch-all fallback route to your server. If the URL doesn't match any static assets, it should serve the same index.html page that your app lives in. Beautiful, again! 38 | // 这个配置就是应用了 connect-history-api-fallback 插件 39 | // 想象一个场景,vue 开发,我们利用 vue-router 的 history 模式进行单页面中的页面跳转 40 | // www.demo.com 跳转去 www.demo.com/list 41 | // 看起来没毛病,vue-router 中只要配置了 list 的路由即可 42 | // 但是,当你刷新页面的时候,浏览器会去向服务器请求 www.demo.com/list 的资源,这想当然是找不到的 43 | // 这个中间件就是会自动捕获这个错误,然后将它重新定位到 index.html 44 | historyApiFallback: { 45 | rewrites: [ 46 | { 47 | from: /.*/, 48 | to: path.posix.join(devConfig.assetsPublicPath, 'index.html') 49 | } 50 | ] 51 | }, 52 | // webpack 最有用的功能之一,热更新装填启动 53 | hot: true, 54 | // 告诉 webpack-dev-server 搭建服务器的时候从哪里获取静态文件 55 | // 默认情况下,将使用当前工作目录作为提供静态文件的目录 56 | // contentBase: false, 57 | // 搭建的开发服务器启动 gzip 压缩 58 | compress: true, 59 | // 搭建的开发服务器的 host,这里使用了一个函数去获取当前电脑的局域网 ip 60 | host: utils.getIPAdress(), 61 | // 开发服务器的端口号 62 | // 但是后面我们会用到 portfinder 插件,如果真的 config/index.js 中的端口被占用了 63 | // 那这个插件会以这个为 base port 去找一个没有被占用的 port 64 | port: devConfig.port, 65 | // 是否要服务器搭建完成之后自动打开浏览器 66 | // 在 webpack-dev-server 的源码里面就是直接用了 opn 这个插件实现功能 67 | open: devConfig.autoOpenBrowser, 68 | // 是否打开发现错误之后在浏览器全屏幕显示错误信息功能 69 | overlay: devConfig.errorOverlay 70 | ? { 71 | warnings: false, 72 | errors: true 73 | } 74 | : false, 75 | // 此路径下的打包文件可在浏览器中访问 76 | // 假设服务器运行在 http://localhost:8080 并且 output.filename 被设置为 bundle.js 77 | // 默认 publicPath 是 "/",所以 bundle.js 可以通过 http://localhost:8080/bundle.js 访问 78 | publicPath: devConfig.assetsPublicPath, 79 | // 启动接口访问代理 80 | proxy: devConfig.proxyTable, 81 | // 启用 quiet 后,除了初始启动信息之外的任何内容都不会被打印到控制台 82 | // 和 FriendlyErrorsPlugin 配合食用更佳 83 | quiet: true, 84 | // 开启监听文件修改的功能,在 webpack-dev-server 和 webpack-dev-middleware 中是默认开始的 85 | // watch: true, 86 | // 关于上面 watch 的一些选项配置 87 | watchOptions: { 88 | // 排除一些文件监听,这有利于提高性能 89 | // 这里排除了 node_modules 文件夹的监听 90 | // 但是这在应对需要 npm install 一些新的 module 的时候,就需要重启服务 91 | ignored: /node_modules/, 92 | // 是否开始轮询,有的时候文件已经更改了但是却没有被监听到,这时候就可以开始轮询 93 | poll: devConfig.poll 94 | } 95 | }, 96 | plugins: [ 97 | // 这可以创建一个在编译过程中的全局变量 98 | // 因为这个插件直接执行文本替换,给定的值必须包含字符串本身内的实际引号 99 | // 所以需要这么用 100 | // "process.env": JSON.stringify('development') 101 | // 或者 102 | // "process.env": '"production"' 103 | new webpack.DefinePlugin({ 104 | 'process.env': require('../config/dev.env') 105 | }), 106 | // 开启大名鼎鼎的热更新插件 107 | new webpack.HotModuleReplacementPlugin(), 108 | // 使用大名鼎鼎(词穷)的 html-webpack-plugin 模板插件 109 | new HtmlWebpackPlugin({ 110 | // 输出的 html 文件的名字 111 | filename: 'index.html', 112 | // 使用的 html 模板名字 113 | template: 'index.html', 114 | // 是否要插入 weback 打包好的 bundle.js 文件 115 | inject: true 116 | }) 117 | ] 118 | }) 119 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 暗器! 4 | 5 | 头像 BIU BIU BIU! 6 | 7 |

使用说明

8 | 9 |

介绍

10 | 11 |

该 12 | template 是所有带前缀 13 | mini-app 的小项目的基础模板,在做项目的时候有的时候会想总结一些插件工具的用法,这个时候就会基于这个模板写一个项目的小 14 | demo,还有的时候做面试题也会碰到一些好玩的面试题,又或者只是想记录一些好玩的 15 | js 的方法,都可以以这个 16 | template 为基础敲敲打打。

17 | 18 |

考虑到浏览器的情况,可能会需要做做 19 | ES6 转 20 | ES5,还希望用用 21 | sass 22 | (点我查看 sass 语法) 让 23 | css 写起来更舒畅一些,而且热更新的方法肯定是不能少的,每次都要 24 | F5 不是很绝望么,我就以达到上述需求为目的,进行了该脚手架的开发。

25 | 26 |

项目中有一个 27 | study 的目录,我的打算是在这个目录下存放一份当前环境下的 28 | build 的配置详解,关于如何搭建等等也会在里面写一个 29 | README.md,毕竟搭建的时候还是有一些小点需要注意的。

30 | 31 |

mini-app 大合集

32 | 33 | 39 | 40 |

我该如何开始

41 | 42 |

首先一套组合拳,将项目拉到本地,这一步我们有两种做法。

43 | 44 |

方法一(推荐)

45 | 46 |

直接点击该项目右上角的 47 | fork,在你的仓库中生成一份 48 | mini-app-template,这样你不仅可以 49 | clone 自己仓库中的 50 | mini-app-template 代码,还可以 51 | pull request,将你觉得这个项目可以完善的地方告诉我,我会及时查看并且合并的喔~笔芯 52 | *★,°*:.☆( ̄▽ ̄)/$:*.°★* 。 53 |

54 | 55 |

方法二

56 | 57 |

直接 clone 我的代码。 58 |

 59 |       $ git clone https://github.com/jsjzh/mini-app-template.git
 60 |       $ cd mini-app-template
 61 |       $ npm install // or yarn
 62 |       $ npm start // or yarn start
 63 |     
64 |

65 | 66 |

接着,如果我想创建一个新的 mini-app-new-app 怎么办

67 | 68 |

如果你想要以这个项目为模板,创建一个自己的 69 | mini-app 用于展示

70 | 71 |

第一步:你需要删除 72 | mini-app-template 目录下的 73 | .git 74 |
第二步:在 75 | git 上新建一个新的项目,我这里假设新建的项目名称为 76 | mini-app-new-app(第四行别忘了改 77 | jsjzh 为你自己的 78 | git 账号) 79 |

 80 |       
 81 |         $ git init 
 82 |         $ git add . 
 83 |         $ git commit -m "nimi-app-new-app first commit oh yeah ~" 
 84 |         $ git remote add origin git@github.com:jsjzh/mini-app-new-app.git
 85 |         $ git push -u origin master
 86 |       
 87 |     
88 |

89 | 90 |

最后,你就可以在这个项目下快乐的写自己的 91 | mini-app 啦,撒花 万岁 92 | ~\(≧▽≦)/~ 93 |

94 | 95 |

如果可以的话,请告诉我你的项目地址,我就可以把他们添加到我的 96 | mini-app 列表中了。

97 | 98 |

代码如人生,我甘之如饴。

99 | 100 |

完成该项目功能所需模块整理

101 | 102 | 158 | 159 |
-------------------------------------------------------------------------------- /static/css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in iOS. 9 | */ 10 | 11 | html { 12 | line-height: 1.15; /* 1 */ 13 | -webkit-text-size-adjust: 100%; /* 2 */ 14 | } 15 | 16 | /* Sections 17 | ========================================================================== */ 18 | 19 | /** 20 | * Remove the margin in all browsers. 21 | */ 22 | 23 | body { 24 | margin: 0; 25 | } 26 | 27 | /** 28 | * Correct the font size and margin on `h1` elements within `section` and 29 | * `article` contexts in Chrome, Firefox, and Safari. 30 | */ 31 | 32 | h1 { 33 | font-size: 2em; 34 | margin: 0.67em 0; 35 | } 36 | 37 | /* Grouping content 38 | ========================================================================== */ 39 | 40 | /** 41 | * 1. Add the correct box sizing in Firefox. 42 | * 2. Show the overflow in Edge and IE. 43 | */ 44 | 45 | hr { 46 | box-sizing: content-box; /* 1 */ 47 | height: 0; /* 1 */ 48 | overflow: visible; /* 2 */ 49 | } 50 | 51 | /** 52 | * 1. Correct the inheritance and scaling of font size in all browsers. 53 | * 2. Correct the odd `em` font sizing in all browsers. 54 | */ 55 | 56 | pre { 57 | font-family: monospace, monospace; /* 1 */ 58 | font-size: 1em; /* 2 */ 59 | } 60 | 61 | /* Text-level semantics 62 | ========================================================================== */ 63 | 64 | /** 65 | * Remove the gray background on active links in IE 10. 66 | */ 67 | 68 | a { 69 | background-color: transparent; 70 | } 71 | 72 | /** 73 | * 1. Remove the bottom border in Chrome 57- 74 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 75 | */ 76 | 77 | abbr[title] { 78 | border-bottom: none; /* 1 */ 79 | text-decoration: underline; /* 2 */ 80 | text-decoration: underline dotted; /* 2 */ 81 | } 82 | 83 | /** 84 | * Add the correct font weight in Chrome, Edge, and Safari. 85 | */ 86 | 87 | b, 88 | strong { 89 | font-weight: bolder; 90 | } 91 | 92 | /** 93 | * 1. Correct the inheritance and scaling of font size in all browsers. 94 | * 2. Correct the odd `em` font sizing in all browsers. 95 | */ 96 | 97 | code, 98 | kbd, 99 | samp { 100 | font-family: monospace, monospace; /* 1 */ 101 | font-size: 1em; /* 2 */ 102 | } 103 | 104 | /** 105 | * Add the correct font size in all browsers. 106 | */ 107 | 108 | small { 109 | font-size: 80%; 110 | } 111 | 112 | /** 113 | * Prevent `sub` and `sup` elements from affecting the line height in 114 | * all browsers. 115 | */ 116 | 117 | sub, 118 | sup { 119 | font-size: 75%; 120 | line-height: 0; 121 | position: relative; 122 | vertical-align: baseline; 123 | } 124 | 125 | sub { 126 | bottom: -0.25em; 127 | } 128 | 129 | sup { 130 | top: -0.5em; 131 | } 132 | 133 | /* Embedded content 134 | ========================================================================== */ 135 | 136 | /** 137 | * Remove the border on images inside links in IE 10. 138 | */ 139 | 140 | img { 141 | border-style: none; 142 | } 143 | 144 | /* Forms 145 | ========================================================================== */ 146 | 147 | /** 148 | * 1. Change the font styles in all browsers. 149 | * 2. Remove the margin in Firefox and Safari. 150 | */ 151 | 152 | button, 153 | input, 154 | optgroup, 155 | select, 156 | textarea { 157 | font-family: inherit; /* 1 */ 158 | font-size: 100%; /* 1 */ 159 | line-height: 1.15; /* 1 */ 160 | margin: 0; /* 2 */ 161 | } 162 | 163 | /** 164 | * Show the overflow in IE. 165 | * 1. Show the overflow in Edge. 166 | */ 167 | 168 | button, 169 | input { /* 1 */ 170 | overflow: visible; 171 | } 172 | 173 | /** 174 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 175 | * 1. Remove the inheritance of text transform in Firefox. 176 | */ 177 | 178 | button, 179 | select { /* 1 */ 180 | text-transform: none; 181 | } 182 | 183 | /** 184 | * Correct the inability to style clickable types in iOS and Safari. 185 | */ 186 | 187 | button, 188 | [type="button"], 189 | [type="reset"], 190 | [type="submit"] { 191 | -webkit-appearance: button; 192 | } 193 | 194 | /** 195 | * Remove the inner border and padding in Firefox. 196 | */ 197 | 198 | button::-moz-focus-inner, 199 | [type="button"]::-moz-focus-inner, 200 | [type="reset"]::-moz-focus-inner, 201 | [type="submit"]::-moz-focus-inner { 202 | border-style: none; 203 | padding: 0; 204 | } 205 | 206 | /** 207 | * Restore the focus styles unset by the previous rule. 208 | */ 209 | 210 | button:-moz-focusring, 211 | [type="button"]:-moz-focusring, 212 | [type="reset"]:-moz-focusring, 213 | [type="submit"]:-moz-focusring { 214 | outline: 1px dotted ButtonText; 215 | } 216 | 217 | /** 218 | * Correct the padding in Firefox. 219 | */ 220 | 221 | fieldset { 222 | padding: 0.35em 0.75em 0.625em; 223 | } 224 | 225 | /** 226 | * 1. Correct the text wrapping in Edge and IE. 227 | * 2. Correct the color inheritance from `fieldset` elements in IE. 228 | * 3. Remove the padding so developers are not caught out when they zero out 229 | * `fieldset` elements in all browsers. 230 | */ 231 | 232 | legend { 233 | box-sizing: border-box; /* 1 */ 234 | color: inherit; /* 2 */ 235 | display: table; /* 1 */ 236 | max-width: 100%; /* 1 */ 237 | padding: 0; /* 3 */ 238 | white-space: normal; /* 1 */ 239 | } 240 | 241 | /** 242 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 243 | */ 244 | 245 | progress { 246 | vertical-align: baseline; 247 | } 248 | 249 | /** 250 | * Remove the default vertical scrollbar in IE 10+. 251 | */ 252 | 253 | textarea { 254 | overflow: auto; 255 | } 256 | 257 | /** 258 | * 1. Add the correct box sizing in IE 10. 259 | * 2. Remove the padding in IE 10. 260 | */ 261 | 262 | [type="checkbox"], 263 | [type="radio"] { 264 | box-sizing: border-box; /* 1 */ 265 | padding: 0; /* 2 */ 266 | } 267 | 268 | /** 269 | * Correct the cursor style of increment and decrement buttons in Chrome. 270 | */ 271 | 272 | [type="number"]::-webkit-inner-spin-button, 273 | [type="number"]::-webkit-outer-spin-button { 274 | height: auto; 275 | } 276 | 277 | /** 278 | * 1. Correct the odd appearance in Chrome and Safari. 279 | * 2. Correct the outline style in Safari. 280 | */ 281 | 282 | [type="search"] { 283 | -webkit-appearance: textfield; /* 1 */ 284 | outline-offset: -2px; /* 2 */ 285 | } 286 | 287 | /** 288 | * Remove the inner padding in Chrome and Safari on macOS. 289 | */ 290 | 291 | [type="search"]::-webkit-search-decoration { 292 | -webkit-appearance: none; 293 | } 294 | 295 | /** 296 | * 1. Correct the inability to style clickable types in iOS and Safari. 297 | * 2. Change font properties to `inherit` in Safari. 298 | */ 299 | 300 | ::-webkit-file-upload-button { 301 | -webkit-appearance: button; /* 1 */ 302 | font: inherit; /* 2 */ 303 | } 304 | 305 | /* Interactive 306 | ========================================================================== */ 307 | 308 | /* 309 | * Add the correct display in Edge, IE 10+, and Firefox. 310 | */ 311 | 312 | details { 313 | display: block; 314 | } 315 | 316 | /* 317 | * Add the correct display in all browsers. 318 | */ 319 | 320 | summary { 321 | display: list-item; 322 | } 323 | 324 | /* Misc 325 | ========================================================================== */ 326 | 327 | /** 328 | * Add the correct display in IE 10+. 329 | */ 330 | 331 | template { 332 | display: none; 333 | } 334 | 335 | /** 336 | * Add the correct display in IE 10. 337 | */ 338 | 339 | [hidden] { 340 | display: none; 341 | } 342 | -------------------------------------------------------------------------------- /static/css/github-markdown.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: octicons-link; 3 | src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAZwABAAAAAACFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEU0lHAAAGaAAAAAgAAAAIAAAAAUdTVUIAAAZcAAAACgAAAAoAAQAAT1MvMgAAAyQAAABJAAAAYFYEU3RjbWFwAAADcAAAAEUAAACAAJThvmN2dCAAAATkAAAABAAAAAQAAAAAZnBnbQAAA7gAAACyAAABCUM+8IhnYXNwAAAGTAAAABAAAAAQABoAI2dseWYAAAFsAAABPAAAAZwcEq9taGVhZAAAAsgAAAA0AAAANgh4a91oaGVhAAADCAAAABoAAAAkCA8DRGhtdHgAAAL8AAAADAAAAAwGAACfbG9jYQAAAsAAAAAIAAAACABiATBtYXhwAAACqAAAABgAAAAgAA8ASm5hbWUAAAToAAABQgAAAlXu73sOcG9zdAAABiwAAAAeAAAAME3QpOBwcmVwAAAEbAAAAHYAAAB/aFGpk3jaTY6xa8JAGMW/O62BDi0tJLYQincXEypYIiGJjSgHniQ6umTsUEyLm5BV6NDBP8Tpts6F0v+k/0an2i+itHDw3v2+9+DBKTzsJNnWJNTgHEy4BgG3EMI9DCEDOGEXzDADU5hBKMIgNPZqoD3SilVaXZCER3/I7AtxEJLtzzuZfI+VVkprxTlXShWKb3TBecG11rwoNlmmn1P2WYcJczl32etSpKnziC7lQyWe1smVPy/Lt7Kc+0vWY/gAgIIEqAN9we0pwKXreiMasxvabDQMM4riO+qxM2ogwDGOZTXxwxDiycQIcoYFBLj5K3EIaSctAq2kTYiw+ymhce7vwM9jSqO8JyVd5RH9gyTt2+J/yUmYlIR0s04n6+7Vm1ozezUeLEaUjhaDSuXHwVRgvLJn1tQ7xiuVv/ocTRF42mNgZGBgYGbwZOBiAAFGJBIMAAizAFoAAABiAGIAznjaY2BkYGAA4in8zwXi+W2+MjCzMIDApSwvXzC97Z4Ig8N/BxYGZgcgl52BCSQKAA3jCV8CAABfAAAAAAQAAEB42mNgZGBg4f3vACQZQABIMjKgAmYAKEgBXgAAeNpjYGY6wTiBgZWBg2kmUxoDA4MPhGZMYzBi1AHygVLYQUCaawqDA4PChxhmh/8ODDEsvAwHgMKMIDnGL0x7gJQCAwMAJd4MFwAAAHjaY2BgYGaA4DAGRgYQkAHyGMF8NgYrIM3JIAGVYYDT+AEjAwuDFpBmA9KMDEwMCh9i/v8H8sH0/4dQc1iAmAkALaUKLgAAAHjaTY9LDsIgEIbtgqHUPpDi3gPoBVyRTmTddOmqTXThEXqrob2gQ1FjwpDvfwCBdmdXC5AVKFu3e5MfNFJ29KTQT48Ob9/lqYwOGZxeUelN2U2R6+cArgtCJpauW7UQBqnFkUsjAY/kOU1cP+DAgvxwn1chZDwUbd6CFimGXwzwF6tPbFIcjEl+vvmM/byA48e6tWrKArm4ZJlCbdsrxksL1AwWn/yBSJKpYbq8AXaaTb8AAHja28jAwOC00ZrBeQNDQOWO//sdBBgYGRiYWYAEELEwMTE4uzo5Zzo5b2BxdnFOcALxNjA6b2ByTswC8jYwg0VlNuoCTWAMqNzMzsoK1rEhNqByEyerg5PMJlYuVueETKcd/89uBpnpvIEVomeHLoMsAAe1Id4AAAAAAAB42oWQT07CQBTGv0JBhagk7HQzKxca2sJCE1hDt4QF+9JOS0nbaaYDCQfwCJ7Au3AHj+LO13FMmm6cl7785vven0kBjHCBhfpYuNa5Ph1c0e2Xu3jEvWG7UdPDLZ4N92nOm+EBXuAbHmIMSRMs+4aUEd4Nd3CHD8NdvOLTsA2GL8M9PODbcL+hD7C1xoaHeLJSEao0FEW14ckxC+TU8TxvsY6X0eLPmRhry2WVioLpkrbp84LLQPGI7c6sOiUzpWIWS5GzlSgUzzLBSikOPFTOXqly7rqx0Z1Q5BAIoZBSFihQYQOOBEdkCOgXTOHA07HAGjGWiIjaPZNW13/+lm6S9FT7rLHFJ6fQbkATOG1j2OFMucKJJsxIVfQORl+9Jyda6Sl1dUYhSCm1dyClfoeDve4qMYdLEbfqHf3O/AdDumsjAAB42mNgYoAAZQYjBmyAGYQZmdhL8zLdDEydARfoAqIAAAABAAMABwAKABMAB///AA8AAQAAAAAAAAAAAAAAAAABAAAAAA==) format('woff'); 4 | } 5 | 6 | .markdown-body { 7 | -ms-text-size-adjust: 100%; 8 | -webkit-text-size-adjust: 100%; 9 | line-height: 1.5; 10 | color: #24292e; 11 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 12 | font-size: 16px; 13 | line-height: 1.5; 14 | word-wrap: break-word; 15 | } 16 | 17 | .markdown-body .pl-c { 18 | color: #6a737d; 19 | } 20 | 21 | .markdown-body .pl-c1, 22 | .markdown-body .pl-s .pl-v { 23 | color: #005cc5; 24 | } 25 | 26 | .markdown-body .pl-e, 27 | .markdown-body .pl-en { 28 | color: #6f42c1; 29 | } 30 | 31 | .markdown-body .pl-smi, 32 | .markdown-body .pl-s .pl-s1 { 33 | color: #24292e; 34 | } 35 | 36 | .markdown-body .pl-ent { 37 | color: #22863a; 38 | } 39 | 40 | .markdown-body .pl-k { 41 | color: #d73a49; 42 | } 43 | 44 | .markdown-body .pl-s, 45 | .markdown-body .pl-pds, 46 | .markdown-body .pl-s .pl-pse .pl-s1, 47 | .markdown-body .pl-sr, 48 | .markdown-body .pl-sr .pl-cce, 49 | .markdown-body .pl-sr .pl-sre, 50 | .markdown-body .pl-sr .pl-sra { 51 | color: #032f62; 52 | } 53 | 54 | .markdown-body .pl-v, 55 | .markdown-body .pl-smw { 56 | color: #e36209; 57 | } 58 | 59 | .markdown-body .pl-bu { 60 | color: #b31d28; 61 | } 62 | 63 | .markdown-body .pl-ii { 64 | color: #fafbfc; 65 | background-color: #b31d28; 66 | } 67 | 68 | .markdown-body .pl-c2 { 69 | color: #fafbfc; 70 | background-color: #d73a49; 71 | } 72 | 73 | .markdown-body .pl-c2::before { 74 | content: "^M"; 75 | } 76 | 77 | .markdown-body .pl-sr .pl-cce { 78 | font-weight: bold; 79 | color: #22863a; 80 | } 81 | 82 | .markdown-body .pl-ml { 83 | color: #735c0f; 84 | } 85 | 86 | .markdown-body .pl-mh, 87 | .markdown-body .pl-mh .pl-en, 88 | .markdown-body .pl-ms { 89 | font-weight: bold; 90 | color: #005cc5; 91 | } 92 | 93 | .markdown-body .pl-mi { 94 | font-style: italic; 95 | color: #24292e; 96 | } 97 | 98 | .markdown-body .pl-mb { 99 | font-weight: bold; 100 | color: #24292e; 101 | } 102 | 103 | .markdown-body .pl-md { 104 | color: #b31d28; 105 | background-color: #ffeef0; 106 | } 107 | 108 | .markdown-body .pl-mi1 { 109 | color: #22863a; 110 | background-color: #f0fff4; 111 | } 112 | 113 | .markdown-body .pl-mc { 114 | color: #e36209; 115 | background-color: #ffebda; 116 | } 117 | 118 | .markdown-body .pl-mi2 { 119 | color: #f6f8fa; 120 | background-color: #005cc5; 121 | } 122 | 123 | .markdown-body .pl-mdr { 124 | font-weight: bold; 125 | color: #6f42c1; 126 | } 127 | 128 | .markdown-body .pl-ba { 129 | color: #586069; 130 | } 131 | 132 | .markdown-body .pl-sg { 133 | color: #959da5; 134 | } 135 | 136 | .markdown-body .pl-corl { 137 | text-decoration: underline; 138 | color: #032f62; 139 | } 140 | 141 | .markdown-body .octicon { 142 | display: inline-block; 143 | vertical-align: text-top; 144 | fill: currentColor; 145 | } 146 | 147 | .markdown-body a { 148 | background-color: transparent; 149 | } 150 | 151 | .markdown-body a:active, 152 | .markdown-body a:hover { 153 | outline-width: 0; 154 | } 155 | 156 | .markdown-body strong { 157 | font-weight: inherit; 158 | } 159 | 160 | .markdown-body strong { 161 | font-weight: bolder; 162 | } 163 | 164 | .markdown-body h1 { 165 | font-size: 2em; 166 | margin: 0.67em 0; 167 | } 168 | 169 | .markdown-body img { 170 | border-style: none; 171 | } 172 | 173 | .markdown-body code, 174 | .markdown-body kbd, 175 | .markdown-body pre { 176 | font-family: monospace, monospace; 177 | font-size: 1em; 178 | } 179 | 180 | .markdown-body hr { 181 | box-sizing: content-box; 182 | height: 0; 183 | overflow: visible; 184 | } 185 | 186 | .markdown-body input { 187 | font: inherit; 188 | margin: 0; 189 | } 190 | 191 | .markdown-body input { 192 | overflow: visible; 193 | } 194 | 195 | .markdown-body [type="checkbox"] { 196 | box-sizing: border-box; 197 | padding: 0; 198 | } 199 | 200 | .markdown-body * { 201 | box-sizing: border-box; 202 | } 203 | 204 | .markdown-body input { 205 | font-family: inherit; 206 | font-size: inherit; 207 | line-height: inherit; 208 | } 209 | 210 | .markdown-body a { 211 | color: #0366d6; 212 | text-decoration: none; 213 | } 214 | 215 | .markdown-body a:hover { 216 | text-decoration: underline; 217 | } 218 | 219 | .markdown-body strong { 220 | font-weight: 600; 221 | } 222 | 223 | .markdown-body hr { 224 | height: 0; 225 | margin: 15px 0; 226 | overflow: hidden; 227 | background: transparent; 228 | border: 0; 229 | border-bottom: 1px solid #dfe2e5; 230 | } 231 | 232 | .markdown-body hr::before { 233 | display: table; 234 | content: ""; 235 | } 236 | 237 | .markdown-body hr::after { 238 | display: table; 239 | clear: both; 240 | content: ""; 241 | } 242 | 243 | .markdown-body table { 244 | border-spacing: 0; 245 | border-collapse: collapse; 246 | } 247 | 248 | .markdown-body td, 249 | .markdown-body th { 250 | padding: 0; 251 | } 252 | 253 | .markdown-body h1, 254 | .markdown-body h2, 255 | .markdown-body h3, 256 | .markdown-body h4, 257 | .markdown-body h5, 258 | .markdown-body h6 { 259 | margin-top: 0; 260 | margin-bottom: 0; 261 | } 262 | 263 | .markdown-body h1 { 264 | font-size: 32px; 265 | font-weight: 600; 266 | } 267 | 268 | .markdown-body h2 { 269 | font-size: 24px; 270 | font-weight: 600; 271 | } 272 | 273 | .markdown-body h3 { 274 | font-size: 20px; 275 | font-weight: 600; 276 | } 277 | 278 | .markdown-body h4 { 279 | font-size: 16px; 280 | font-weight: 600; 281 | } 282 | 283 | .markdown-body h5 { 284 | font-size: 14px; 285 | font-weight: 600; 286 | } 287 | 288 | .markdown-body h6 { 289 | font-size: 12px; 290 | font-weight: 600; 291 | } 292 | 293 | .markdown-body p { 294 | margin-top: 0; 295 | margin-bottom: 10px; 296 | } 297 | 298 | .markdown-body blockquote { 299 | margin: 0; 300 | } 301 | 302 | .markdown-body ul, 303 | .markdown-body ol { 304 | padding-left: 0; 305 | margin-top: 0; 306 | margin-bottom: 0; 307 | } 308 | 309 | .markdown-body ol ol, 310 | .markdown-body ul ol { 311 | list-style-type: lower-roman; 312 | } 313 | 314 | .markdown-body ul ul ol, 315 | .markdown-body ul ol ol, 316 | .markdown-body ol ul ol, 317 | .markdown-body ol ol ol { 318 | list-style-type: lower-alpha; 319 | } 320 | 321 | .markdown-body dd { 322 | margin-left: 0; 323 | } 324 | 325 | .markdown-body code { 326 | font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 327 | font-size: 12px; 328 | } 329 | 330 | .markdown-body pre { 331 | margin-top: 0; 332 | margin-bottom: 0; 333 | font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 334 | font-size: 12px; 335 | } 336 | 337 | .markdown-body .octicon { 338 | vertical-align: text-bottom; 339 | } 340 | 341 | .markdown-body .pl-0 { 342 | padding-left: 0 !important; 343 | } 344 | 345 | .markdown-body .pl-1 { 346 | padding-left: 4px !important; 347 | } 348 | 349 | .markdown-body .pl-2 { 350 | padding-left: 8px !important; 351 | } 352 | 353 | .markdown-body .pl-3 { 354 | padding-left: 16px !important; 355 | } 356 | 357 | .markdown-body .pl-4 { 358 | padding-left: 24px !important; 359 | } 360 | 361 | .markdown-body .pl-5 { 362 | padding-left: 32px !important; 363 | } 364 | 365 | .markdown-body .pl-6 { 366 | padding-left: 40px !important; 367 | } 368 | 369 | .markdown-body::before { 370 | display: table; 371 | content: ""; 372 | } 373 | 374 | .markdown-body::after { 375 | display: table; 376 | clear: both; 377 | content: ""; 378 | } 379 | 380 | .markdown-body>*:first-child { 381 | margin-top: 0 !important; 382 | } 383 | 384 | .markdown-body>*:last-child { 385 | margin-bottom: 0 !important; 386 | } 387 | 388 | .markdown-body a:not([href]) { 389 | color: inherit; 390 | text-decoration: none; 391 | } 392 | 393 | .markdown-body .anchor { 394 | float: left; 395 | padding-right: 4px; 396 | margin-left: -20px; 397 | line-height: 1; 398 | } 399 | 400 | .markdown-body .anchor:focus { 401 | outline: none; 402 | } 403 | 404 | .markdown-body p, 405 | .markdown-body blockquote, 406 | .markdown-body ul, 407 | .markdown-body ol, 408 | .markdown-body dl, 409 | .markdown-body table, 410 | .markdown-body pre { 411 | margin-top: 0; 412 | margin-bottom: 16px; 413 | } 414 | 415 | .markdown-body hr { 416 | height: 0.25em; 417 | padding: 0; 418 | margin: 24px 0; 419 | background-color: #e1e4e8; 420 | border: 0; 421 | } 422 | 423 | .markdown-body blockquote { 424 | padding: 0 1em; 425 | color: #6a737d; 426 | border-left: 0.25em solid #dfe2e5; 427 | } 428 | 429 | .markdown-body blockquote>:first-child { 430 | margin-top: 0; 431 | } 432 | 433 | .markdown-body blockquote>:last-child { 434 | margin-bottom: 0; 435 | } 436 | 437 | .markdown-body kbd { 438 | display: inline-block; 439 | padding: 3px 5px; 440 | font-size: 11px; 441 | line-height: 10px; 442 | color: #444d56; 443 | vertical-align: middle; 444 | background-color: #fafbfc; 445 | border: solid 1px #c6cbd1; 446 | border-bottom-color: #959da5; 447 | border-radius: 3px; 448 | box-shadow: inset 0 -1px 0 #959da5; 449 | } 450 | 451 | .markdown-body h1, 452 | .markdown-body h2, 453 | .markdown-body h3, 454 | .markdown-body h4, 455 | .markdown-body h5, 456 | .markdown-body h6 { 457 | margin-top: 24px; 458 | margin-bottom: 16px; 459 | font-weight: 600; 460 | line-height: 1.25; 461 | } 462 | 463 | .markdown-body h1 .octicon-link, 464 | .markdown-body h2 .octicon-link, 465 | .markdown-body h3 .octicon-link, 466 | .markdown-body h4 .octicon-link, 467 | .markdown-body h5 .octicon-link, 468 | .markdown-body h6 .octicon-link { 469 | color: #1b1f23; 470 | vertical-align: middle; 471 | visibility: hidden; 472 | } 473 | 474 | .markdown-body h1:hover .anchor, 475 | .markdown-body h2:hover .anchor, 476 | .markdown-body h3:hover .anchor, 477 | .markdown-body h4:hover .anchor, 478 | .markdown-body h5:hover .anchor, 479 | .markdown-body h6:hover .anchor { 480 | text-decoration: none; 481 | } 482 | 483 | .markdown-body h1:hover .anchor .octicon-link, 484 | .markdown-body h2:hover .anchor .octicon-link, 485 | .markdown-body h3:hover .anchor .octicon-link, 486 | .markdown-body h4:hover .anchor .octicon-link, 487 | .markdown-body h5:hover .anchor .octicon-link, 488 | .markdown-body h6:hover .anchor .octicon-link { 489 | visibility: visible; 490 | } 491 | 492 | .markdown-body h1 { 493 | padding-bottom: 0.3em; 494 | font-size: 2em; 495 | border-bottom: 1px solid #eaecef; 496 | } 497 | 498 | .markdown-body h2 { 499 | padding-bottom: 0.3em; 500 | font-size: 1.5em; 501 | border-bottom: 1px solid #eaecef; 502 | } 503 | 504 | .markdown-body h3 { 505 | font-size: 1.25em; 506 | } 507 | 508 | .markdown-body h4 { 509 | font-size: 1em; 510 | } 511 | 512 | .markdown-body h5 { 513 | font-size: 0.875em; 514 | } 515 | 516 | .markdown-body h6 { 517 | font-size: 0.85em; 518 | color: #6a737d; 519 | } 520 | 521 | .markdown-body ul, 522 | .markdown-body ol { 523 | padding-left: 2em; 524 | } 525 | 526 | .markdown-body ul ul, 527 | .markdown-body ul ol, 528 | .markdown-body ol ol, 529 | .markdown-body ol ul { 530 | margin-top: 0; 531 | margin-bottom: 0; 532 | } 533 | 534 | .markdown-body li { 535 | word-wrap: break-all; 536 | } 537 | 538 | .markdown-body li>p { 539 | margin-top: 16px; 540 | } 541 | 542 | .markdown-body li+li { 543 | margin-top: 0.25em; 544 | } 545 | 546 | .markdown-body dl { 547 | padding: 0; 548 | } 549 | 550 | .markdown-body dl dt { 551 | padding: 0; 552 | margin-top: 16px; 553 | font-size: 1em; 554 | font-style: italic; 555 | font-weight: 600; 556 | } 557 | 558 | .markdown-body dl dd { 559 | padding: 0 16px; 560 | margin-bottom: 16px; 561 | } 562 | 563 | .markdown-body table { 564 | display: block; 565 | width: 100%; 566 | overflow: auto; 567 | } 568 | 569 | .markdown-body table th { 570 | font-weight: 600; 571 | } 572 | 573 | .markdown-body table th, 574 | .markdown-body table td { 575 | padding: 6px 13px; 576 | border: 1px solid #dfe2e5; 577 | } 578 | 579 | .markdown-body table tr { 580 | background-color: #fff; 581 | border-top: 1px solid #c6cbd1; 582 | } 583 | 584 | .markdown-body table tr:nth-child(2n) { 585 | background-color: #f6f8fa; 586 | } 587 | 588 | .markdown-body img { 589 | max-width: 100%; 590 | box-sizing: content-box; 591 | background-color: #fff; 592 | } 593 | 594 | .markdown-body img[align=right] { 595 | padding-left: 20px; 596 | } 597 | 598 | .markdown-body img[align=left] { 599 | padding-right: 20px; 600 | } 601 | 602 | .markdown-body code { 603 | padding: 0.2em 0.4em; 604 | margin: 0; 605 | font-size: 85%; 606 | background-color: rgba(27,31,35,0.05); 607 | border-radius: 3px; 608 | } 609 | 610 | .markdown-body pre { 611 | word-wrap: normal; 612 | } 613 | 614 | .markdown-body pre>code { 615 | padding: 0; 616 | margin: 0; 617 | font-size: 100%; 618 | word-break: normal; 619 | white-space: pre; 620 | background: transparent; 621 | border: 0; 622 | } 623 | 624 | .markdown-body .highlight { 625 | margin-bottom: 16px; 626 | } 627 | 628 | .markdown-body .highlight pre { 629 | margin-bottom: 0; 630 | word-break: normal; 631 | } 632 | 633 | .markdown-body .highlight pre, 634 | .markdown-body pre { 635 | padding: 16px; 636 | overflow: auto; 637 | font-size: 85%; 638 | line-height: 1.45; 639 | background-color: #f6f8fa; 640 | border-radius: 3px; 641 | } 642 | 643 | .markdown-body pre code { 644 | display: inline; 645 | max-width: auto; 646 | padding: 0; 647 | margin: 0; 648 | overflow: visible; 649 | line-height: inherit; 650 | word-wrap: normal; 651 | background-color: transparent; 652 | border: 0; 653 | } 654 | 655 | .markdown-body .full-commit .btn-outline:not(:disabled):hover { 656 | color: #005cc5; 657 | border-color: #005cc5; 658 | } 659 | 660 | .markdown-body kbd { 661 | display: inline-block; 662 | padding: 3px 5px; 663 | font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 664 | line-height: 10px; 665 | color: #444d56; 666 | vertical-align: middle; 667 | background-color: #fafbfc; 668 | border: solid 1px #d1d5da; 669 | border-bottom-color: #c6cbd1; 670 | border-radius: 3px; 671 | box-shadow: inset 0 -1px 0 #c6cbd1; 672 | } 673 | 674 | .markdown-body :checked+.radio-label { 675 | position: relative; 676 | z-index: 1; 677 | border-color: #0366d6; 678 | } 679 | 680 | .markdown-body .task-list-item { 681 | list-style-type: none; 682 | } 683 | 684 | .markdown-body .task-list-item+.task-list-item { 685 | margin-top: 3px; 686 | } 687 | 688 | .markdown-body .task-list-item input { 689 | margin: 0 0.2em 0.25em -1.6em; 690 | vertical-align: middle; 691 | } 692 | 693 | .markdown-body hr { 694 | border-bottom-color: #eee; 695 | } 696 | --------------------------------------------------------------------------------