@@ -0,0 +1,18 @@ | |||||
{ | |||||
"presets": [ | |||||
["env", { | |||||
"modules": false, | |||||
"targets": { | |||||
"browsers": ["> 1%", "last 2 versions", "not ie <= 11"] | |||||
} | |||||
}], | |||||
"stage-2" | |||||
], | |||||
"plugins": ["transform-runtime"], | |||||
"env": { | |||||
"test": { | |||||
"presets": ["env", "stage-2"], | |||||
"plugins": [ "istanbul" ] | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,9 @@ | |||||
root = true | |||||
[*] | |||||
charset = utf-8 | |||||
indent_style = space | |||||
indent_size = 4 | |||||
end_of_line = lf | |||||
insert_final_newline = true | |||||
trim_trailing_whitespace = true |
@@ -0,0 +1,4 @@ | |||||
/build/ | |||||
/config/ | |||||
/dist/ | |||||
/*.js |
@@ -0,0 +1,27 @@ | |||||
// http://eslint.org/docs/user-guide/configuring | |||||
module.exports = { | |||||
root: true, | |||||
parser: 'babel-eslint', | |||||
parserOptions: { | |||||
sourceType: 'module' | |||||
}, | |||||
env: { | |||||
browser: true, | |||||
}, | |||||
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style | |||||
extends: 'standard', | |||||
// required to lint *.vue files | |||||
plugins: [ | |||||
'html' | |||||
], | |||||
// add your custom rules here | |||||
'rules': { | |||||
// allow paren-less arrow functions | |||||
'arrow-parens': 0, | |||||
// allow async-await | |||||
'generator-star-spacing': 0, | |||||
// allow debugger during development | |||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 | |||||
} | |||||
} |
@@ -0,0 +1,13 @@ | |||||
.DS_Store | |||||
node_modules/ | |||||
/dist/ | |||||
npm-debug.log* | |||||
yarn-debug.log* | |||||
yarn-error.log* | |||||
# Editor directories and files | |||||
.idea | |||||
*.suo | |||||
*.ntvs* | |||||
*.njsproj | |||||
*.sln |
@@ -0,0 +1,8 @@ | |||||
// https://github.com/michael-ciniawsky/postcss-load-config | |||||
module.exports = { | |||||
"plugins": { | |||||
// to edit target browsers: use "browserlist" field in package.json | |||||
"autoprefixer": {} | |||||
} | |||||
} |
@@ -0,0 +1,4 @@ | |||||
FROM nginx:latest | |||||
COPY config/docker/nginx.conf /etc/nginx/conf.d | |||||
@@ -0,0 +1,21 @@ | |||||
# nexus-timers | |||||
> Timers ans other features for Heroes of the Storm | |||||
## Build Setup | |||||
``` bash | |||||
# install dependencies | |||||
yarn | |||||
# serve with hot reload at localhost:8080 | |||||
yarn dev | |||||
# build for production with minification | |||||
yarn build | |||||
# build for production and view the bundle analyzer report | |||||
yarn build --report | |||||
``` | |||||
For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). |
@@ -0,0 +1,37 @@ | |||||
'use strict' | |||||
require('./check-versions')() | |||||
process.env.NODE_ENV = 'production' | |||||
const ora = require('ora') | |||||
const rm = require('rimraf') | |||||
const path = require('path') | |||||
const chalk = require('chalk') | |||||
const webpack = require('webpack') | |||||
const config = require('../config') | |||||
const webpackConfig = require('./webpack.prod.conf') | |||||
const spinner = ora('building for production...') | |||||
spinner.start() | |||||
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { | |||||
if (err) throw err | |||||
webpack(webpackConfig, function (err, stats) { | |||||
spinner.stop() | |||||
if (err) throw err | |||||
process.stdout.write(stats.toString({ | |||||
colors: true, | |||||
modules: false, | |||||
children: false, | |||||
chunks: false, | |||||
chunkModules: false | |||||
}) + '\n\n') | |||||
console.log(chalk.cyan(' Build complete.\n')) | |||||
console.log(chalk.yellow( | |||||
' Tip: built files are meant to be served over an HTTP server.\n' + | |||||
' Opening index.html over file:// won\'t work.\n' | |||||
)) | |||||
}) | |||||
}) |
@@ -0,0 +1,50 @@ | |||||
'use strict' | |||||
const chalk = require('chalk') | |||||
const semver = require('semver') | |||||
const packageConfig = require('../package.json') | |||||
const shell = require('shelljs') | |||||
function exec (cmd) { | |||||
return require('child_process').execSync(cmd).toString().trim() | |||||
} | |||||
const versionRequirements = [ | |||||
{ | |||||
name: 'node', | |||||
currentVersion: semver.clean(process.version), | |||||
versionRequirement: packageConfig.engines.node | |||||
}, | |||||
] | |||||
if (shell.which('npm')) { | |||||
versionRequirements.push({ | |||||
name: 'npm', | |||||
currentVersion: exec('npm --version'), | |||||
versionRequirement: packageConfig.engines.npm | |||||
}) | |||||
} | |||||
module.exports = function () { | |||||
const warnings = [] | |||||
for (let i = 0; i < versionRequirements.length; i++) { | |||||
const mod = versionRequirements[i] | |||||
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { | |||||
warnings.push(mod.name + ': ' + | |||||
chalk.red(mod.currentVersion) + ' should be ' + | |||||
chalk.green(mod.versionRequirement) | |||||
) | |||||
} | |||||
} | |||||
if (warnings.length) { | |||||
console.log('') | |||||
console.log(chalk.yellow('To use this template, you must update following to modules:')) | |||||
console.log() | |||||
for (let i = 0; i < warnings.length; i++) { | |||||
const warning = warnings[i] | |||||
console.log(' ' + warning) | |||||
} | |||||
console.log() | |||||
process.exit(1) | |||||
} | |||||
} |
@@ -0,0 +1,11 @@ | |||||
'use strict' | |||||
/* eslint-disable */ | |||||
require('eventsource-polyfill') | |||||
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') | |||||
hotClient.subscribe(function (event) { | |||||
if (event.action === 'reload') { | |||||
window.location.reload() | |||||
} | |||||
}) |
@@ -0,0 +1,91 @@ | |||||
'use strict' | |||||
require('./check-versions')() | |||||
const config = require('../config') | |||||
if (!process.env.NODE_ENV) { | |||||
process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) | |||||
} | |||||
const opn = require('opn') | |||||
const path = require('path') | |||||
const express = require('express') | |||||
const webpack = require('webpack') | |||||
const proxyMiddleware = require('http-proxy-middleware') | |||||
const webpackConfig = require('./webpack.dev.conf') | |||||
// default port where dev server listens for incoming traffic | |||||
const port = process.env.PORT || config.dev.port | |||||
// automatically open browser, if not set will be false | |||||
const autoOpenBrowser = !!config.dev.autoOpenBrowser | |||||
// Define HTTP proxies to your custom API backend | |||||
// https://github.com/chimurai/http-proxy-middleware | |||||
const proxyTable = config.dev.proxyTable | |||||
const app = express() | |||||
const compiler = webpack(webpackConfig) | |||||
const devMiddleware = require('webpack-dev-middleware')(compiler, { | |||||
publicPath: webpackConfig.output.publicPath, | |||||
quiet: true | |||||
}) | |||||
const hotMiddleware = require('webpack-hot-middleware')(compiler, { | |||||
log: false | |||||
}) | |||||
// force page reload when html-webpack-plugin template changes | |||||
compiler.plugin('compilation', function (compilation) { | |||||
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { | |||||
hotMiddleware.publish({ action: 'reload' }) | |||||
cb() | |||||
}) | |||||
}) | |||||
// enable hot-reload and state-preserving | |||||
// compilation error display | |||||
app.use(hotMiddleware) | |||||
// proxy api requests | |||||
Object.keys(proxyTable).forEach(function (context) { | |||||
let options = proxyTable[context] | |||||
if (typeof options === 'string') { | |||||
options = { target: options } | |||||
} | |||||
app.use(proxyMiddleware(options.filter || context, options)) | |||||
}) | |||||
// handle fallback for HTML5 history API | |||||
app.use(require('connect-history-api-fallback')()) | |||||
// serve webpack bundle output | |||||
app.use(devMiddleware) | |||||
// serve pure static assets | |||||
const staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) | |||||
app.use(staticPath, express.static('./static')) | |||||
const uri = 'http://localhost:' + port | |||||
let _resolve | |||||
const readyPromise = new Promise(resolve => { | |||||
_resolve = resolve | |||||
}) | |||||
console.log('> Starting dev server...') | |||||
devMiddleware.waitUntilValid(() => { | |||||
console.log('> Listening at ' + uri + '\n') | |||||
// when env is testing, don't need open it | |||||
if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { | |||||
opn(uri) | |||||
} | |||||
_resolve() | |||||
}) | |||||
const server = app.listen(port) | |||||
module.exports = { | |||||
ready: readyPromise, | |||||
close: () => { | |||||
server.close() | |||||
} | |||||
} |
@@ -0,0 +1,11 @@ | |||||
'use strict' | |||||
const fs = require('fs') | |||||
const UglifyJS = require('uglify-es') | |||||
module.exports = function(filePath) { | |||||
const code = fs.readFileSync(filePath, 'utf-8') | |||||
const result = UglifyJS.minify(code) | |||||
if (result.error) return '' | |||||
return result.code | |||||
} |
@@ -0,0 +1,17 @@ | |||||
// This service worker file is effectively a 'no-op' that will reset any | |||||
// previous service worker registered for the same host:port combination. | |||||
// In the production build, this file is replaced with an actual service worker | |||||
// file that will precache your site's local assets. | |||||
// See https://github.com/facebookincubator/create-react-app/issues/2272#issuecomment-302832432 | |||||
self.addEventListener('install', () => self.skipWaiting()); | |||||
self.addEventListener('activate', () => { | |||||
self.clients.matchAll({ type: 'window' }).then(windowClients => { | |||||
for (let windowClient of windowClients) { | |||||
// Force open pages to refresh, so that they have a chance to load the | |||||
// fresh navigation response from the local dev server. | |||||
windowClient.navigate(windowClient.url); | |||||
} | |||||
}); | |||||
}); |
@@ -0,0 +1,55 @@ | |||||
(function() { | |||||
'use strict'; | |||||
// Check to make sure service workers are supported in the current browser, | |||||
// and that the current page is accessed from a secure origin. Using a | |||||
// service worker from an insecure origin will trigger JS console errors. | |||||
var isLocalhost = Boolean(window.location.hostname === 'localhost' || | |||||
// [::1] is the IPv6 localhost address. | |||||
window.location.hostname === '[::1]' || | |||||
// 127.0.0.1/8 is considered localhost for IPv4. | |||||
window.location.hostname.match( | |||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ | |||||
) | |||||
); | |||||
window.addEventListener('load', function() { | |||||
if ('serviceWorker' in navigator && | |||||
(window.location.protocol === 'https:' || isLocalhost)) { | |||||
navigator.serviceWorker.register('service-worker.js') | |||||
.then(function(registration) { | |||||
// updatefound is fired if service-worker.js changes. | |||||
registration.onupdatefound = function() { | |||||
// updatefound is also fired the very first time the SW is installed, | |||||
// and there's no need to prompt for a reload at that point. | |||||
// So check here to see if the page is already controlled, | |||||
// i.e. whether there's an existing service worker. | |||||
if (navigator.serviceWorker.controller) { | |||||
// The updatefound event implies that registration.installing is set | |||||
var installingWorker = registration.installing; | |||||
installingWorker.onstatechange = function() { | |||||
switch (installingWorker.state) { | |||||
case 'installed': | |||||
// At this point, the old content will have been purged and the | |||||
// fresh content will have been added to the cache. | |||||
// It's the perfect time to display a "New content is | |||||
// available; please refresh." message in the page's interface. | |||||
break; | |||||
case 'redundant': | |||||
throw new Error('The installing ' + | |||||
'service worker became redundant.'); | |||||
default: | |||||
// Ignore | |||||
} | |||||
}; | |||||
} | |||||
}; | |||||
}).catch(function(e) { | |||||
console.error('Error during service worker registration:', e); | |||||
}); | |||||
} | |||||
}); | |||||
})(); |
@@ -0,0 +1,73 @@ | |||||
'use strict' | |||||
const path = require('path') | |||||
const config = require('../config') | |||||
const ExtractTextPlugin = require('extract-text-webpack-plugin') | |||||
exports.assetsPath = function (_path) { | |||||
const assetsSubDirectory = process.env.NODE_ENV === 'production' | |||||
? config.build.assetsSubDirectory | |||||
: config.dev.assetsSubDirectory | |||||
return path.posix.join(assetsSubDirectory, _path) | |||||
} | |||||
exports.cssLoaders = function (options) { | |||||
options = options || {} | |||||
const cssLoader = { | |||||
loader: 'css-loader', | |||||
options: { | |||||
minimize: process.env.NODE_ENV === 'production', | |||||
sourceMap: options.sourceMap | |||||
} | |||||
} | |||||
// generate loader string to be used with extract text plugin | |||||
function generateLoaders (loader, loaderOptions) { | |||||
const loaders = [cssLoader] | |||||
if (loader) { | |||||
loaders.push({ | |||||
loader: loader + '-loader', | |||||
options: Object.assign({}, loaderOptions, { | |||||
sourceMap: options.sourceMap | |||||
}) | |||||
}) | |||||
} | |||||
// Extract CSS when that option is specified | |||||
// (which is the case during production build) | |||||
if (options.extract) { | |||||
return ExtractTextPlugin.extract({ | |||||
use: loaders, | |||||
fallback: 'vue-style-loader' | |||||
}) | |||||
} else { | |||||
return ['vue-style-loader'].concat(loaders) | |||||
} | |||||
} | |||||
// https://vue-loader.vuejs.org/en/configurations/extract-css.html | |||||
return { | |||||
css: generateLoaders(), | |||||
postcss: generateLoaders(), | |||||
less: generateLoaders('less'), | |||||
sass: generateLoaders('sass', { indentedSyntax: true }), | |||||
scss: generateLoaders('sass'), | |||||
stylus: generateLoaders('stylus'), | |||||
styl: generateLoaders('stylus') | |||||
} | |||||
} | |||||
// Generate loaders for standalone style files (outside of .vue) | |||||
exports.styleLoaders = function (options) { | |||||
const output = [] | |||||
const loaders = exports.cssLoaders(options) | |||||
for (const extension in loaders) { | |||||
const loader = loaders[extension] | |||||
output.push({ | |||||
test: new RegExp('\\.' + extension + '$'), | |||||
use: loader | |||||
}) | |||||
} | |||||
return output | |||||
} |
@@ -0,0 +1,20 @@ | |||||
'use strict' | |||||
const utils = require('./utils') | |||||
const config = require('../config') | |||||
const isProduction = process.env.NODE_ENV === 'production' | |||||
module.exports = { | |||||
loaders: utils.cssLoaders({ | |||||
sourceMap: isProduction | |||||
? config.build.productionSourceMap | |||||
: config.dev.cssSourceMap, | |||||
extract: isProduction | |||||
}), | |||||
transformToRequire: { | |||||
video: ['src', 'poster'], | |||||
source: 'src', | |||||
img: 'src', | |||||
image: 'xlink:href' | |||||
} | |||||
} |
@@ -0,0 +1,77 @@ | |||||
'use strict' | |||||
const path = require('path') | |||||
const utils = require('./utils') | |||||
const config = require('../config') | |||||
const vueLoaderConfig = require('./vue-loader.conf') | |||||
function resolve (dir) { | |||||
return path.join(__dirname, '..', dir) | |||||
} | |||||
module.exports = { | |||||
entry: { | |||||
app: './src/main.js' | |||||
}, | |||||
output: { | |||||
path: config.build.assetsRoot, | |||||
filename: '[name].js', | |||||
publicPath: process.env.NODE_ENV === 'production' | |||||
? config.build.assetsPublicPath | |||||
: config.dev.assetsPublicPath | |||||
}, | |||||
resolve: { | |||||
extensions: ['.js', '.vue', '.json'], | |||||
alias: { | |||||
'vue$': 'vue/dist/vue.esm.js', | |||||
'@': resolve('src') | |||||
} | |||||
}, | |||||
module: { | |||||
rules: [ | |||||
{ | |||||
test: /\.(js|vue)$/, | |||||
loader: 'eslint-loader', | |||||
enforce: 'pre', | |||||
include: [resolve('src'), resolve('test')], | |||||
options: { | |||||
formatter: require('eslint-friendly-formatter') | |||||
} | |||||
}, | |||||
{ | |||||
test: /\.vue$/, | |||||
loader: 'vue-loader', | |||||
options: vueLoaderConfig | |||||
}, | |||||
{ | |||||
test: /\.js$/, | |||||
loader: 'babel-loader', | |||||
include: [resolve('src'), resolve('test')] | |||||
}, | |||||
{ | |||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, | |||||
loader: 'url-loader', | |||||
options: { | |||||
limit: 10000, | |||||
name: utils.assetsPath('img/[name].[hash:7].[ext]') | |||||
} | |||||
}, | |||||
{ | |||||
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, | |||||
loader: 'url-loader', | |||||
options: { | |||||
limit: 10000, | |||||
name: utils.assetsPath('media/[name].[hash:7].[ext]') | |||||
} | |||||
}, | |||||
{ | |||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, | |||||
loader: 'url-loader', | |||||
options: { | |||||
limit: 10000, | |||||
name: utils.assetsPath('fonts/[name].[hash:7].[ext]') | |||||
} | |||||
} | |||||
] | |||||
} | |||||
} |
@@ -0,0 +1,41 @@ | |||||
'use strict' | |||||
const fs = require('fs') | |||||
const path = require('path') | |||||
const utils = require('./utils') | |||||
const webpack = require('webpack') | |||||
const config = require('../config') | |||||
const merge = require('webpack-merge') | |||||
const baseWebpackConfig = require('./webpack.base.conf') | |||||
const HtmlWebpackPlugin = require('html-webpack-plugin') | |||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') | |||||
// add hot-reload related code to entry chunks | |||||
Object.keys(baseWebpackConfig.entry).forEach(function (name) { | |||||
baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) | |||||
}) | |||||
module.exports = merge(baseWebpackConfig, { | |||||
module: { | |||||
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) | |||||
}, | |||||
// cheap-module-eval-source-map is faster for development | |||||
devtool: '#cheap-module-eval-source-map', | |||||
plugins: [ | |||||
new webpack.DefinePlugin({ | |||||
'process.env': config.dev.env | |||||
}), | |||||
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage | |||||
new webpack.HotModuleReplacementPlugin(), | |||||
new webpack.NoEmitOnErrorsPlugin(), | |||||
// https://github.com/ampedandwired/html-webpack-plugin | |||||
new HtmlWebpackPlugin({ | |||||
filename: 'index.html', | |||||
template: 'index.html', | |||||
inject: true, | |||||
serviceWorkerLoader: `<script>${fs.readFileSync(path.join(__dirname, | |||||
'./service-worker-dev.js'), 'utf-8')}</script>` | |||||
}), | |||||
new FriendlyErrorsPlugin() | |||||
] | |||||
}) |
@@ -0,0 +1,135 @@ | |||||
'use strict' | |||||
const fs = require('fs') | |||||
const path = require('path') | |||||
const utils = require('./utils') | |||||
const webpack = require('webpack') | |||||
const config = require('../config') | |||||
const merge = require('webpack-merge') | |||||
const baseWebpackConfig = require('./webpack.base.conf') | |||||
const CopyWebpackPlugin = require('copy-webpack-plugin') | |||||
const HtmlWebpackPlugin = require('html-webpack-plugin') | |||||
const ExtractTextPlugin = require('extract-text-webpack-plugin') | |||||
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') | |||||
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin') | |||||
const loadMinified = require('./load-minified') | |||||
const env = config.build.env | |||||
const webpackConfig = merge(baseWebpackConfig, { | |||||
module: { | |||||
rules: utils.styleLoaders({ | |||||
sourceMap: config.build.productionSourceMap, | |||||
extract: true | |||||
}) | |||||
}, | |||||
devtool: config.build.productionSourceMap ? '#source-map' : false, | |||||
output: { | |||||
path: config.build.assetsRoot, | |||||
filename: utils.assetsPath('js/[name].[chunkhash].js'), | |||||
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') | |||||
}, | |||||
plugins: [ | |||||
// http://vuejs.github.io/vue-loader/en/workflow/production.html | |||||
new webpack.DefinePlugin({ | |||||
'process.env': env | |||||
}), | |||||
new webpack.optimize.UglifyJsPlugin({ | |||||
compress: { | |||||
warnings: false | |||||
}, | |||||
sourceMap: true | |||||
}), | |||||
// extract css into its own file | |||||
new ExtractTextPlugin({ | |||||
filename: utils.assetsPath('css/[name].[contenthash].css') | |||||
}), | |||||
// Compress extracted CSS. We are using this plugin so that possible | |||||
// duplicated CSS from different components can be deduped. | |||||
new OptimizeCSSPlugin({ | |||||
cssProcessorOptions: { | |||||
safe: true | |||||
} | |||||
}), | |||||
// generate dist index.html with correct asset hash for caching. | |||||
// you can customize output by editing /index.html | |||||
// see https://github.com/ampedandwired/html-webpack-plugin | |||||
new HtmlWebpackPlugin({ | |||||
filename: config.build.index, | |||||
template: 'index.html', | |||||
inject: true, | |||||
minify: { | |||||
removeComments: true, | |||||
collapseWhitespace: true, | |||||
removeAttributeQuotes: true | |||||
// more options: | |||||
// https://github.com/kangax/html-minifier#options-quick-reference | |||||
}, | |||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin | |||||
chunksSortMode: 'dependency', | |||||
serviceWorkerLoader: `<script>${loadMinified(path.join(__dirname, | |||||
'./service-worker-prod.js'))}</script>` | |||||
}), | |||||
// split vendor js into its own file | |||||
new webpack.optimize.CommonsChunkPlugin({ | |||||
name: 'vendor', | |||||
minChunks: function (module, count) { | |||||
// any required modules inside node_modules are extracted to vendor | |||||
return ( | |||||
module.resource && | |||||
/\.js$/.test(module.resource) && | |||||
module.resource.indexOf( | |||||
path.join(__dirname, '../node_modules') | |||||
) === 0 | |||||
) | |||||
} | |||||
}), | |||||
// extract webpack runtime and module manifest to its own file in order to | |||||
// prevent vendor hash from being updated whenever app bundle is updated | |||||
new webpack.optimize.CommonsChunkPlugin({ | |||||
name: 'manifest', | |||||
chunks: ['vendor'] | |||||
}), | |||||
// copy custom static assets | |||||
new CopyWebpackPlugin([ | |||||
{ | |||||
from: path.resolve(__dirname, '../static'), | |||||
to: config.build.assetsSubDirectory, | |||||
ignore: ['.*'] | |||||
} | |||||
]), | |||||
// service worker caching | |||||
new SWPrecacheWebpackPlugin({ | |||||
cacheId: 'nexus-timers', | |||||
filename: 'service-worker.js', | |||||
staticFileGlobs: ['dist/**/*.{js,html,css}'], | |||||
minify: true, | |||||
stripPrefix: 'dist/' | |||||
}) | |||||
] | |||||
}) | |||||
if (config.build.productionGzip) { | |||||
const CompressionWebpackPlugin = require('compression-webpack-plugin') | |||||
webpackConfig.plugins.push( | |||||
new CompressionWebpackPlugin({ | |||||
asset: '[path].gz[query]', | |||||
algorithm: 'gzip', | |||||
test: new RegExp( | |||||
'\\.(' + | |||||
config.build.productionGzipExtensions.join('|') + | |||||
')$' | |||||
), | |||||
threshold: 10240, | |||||
minRatio: 0.8 | |||||
}) | |||||
) | |||||
} | |||||
if (config.build.bundleAnalyzerReport) { | |||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin | |||||
webpackConfig.plugins.push(new BundleAnalyzerPlugin()) | |||||
} | |||||
module.exports = webpackConfig |
@@ -0,0 +1,8 @@ | |||||
'use strict' | |||||
const merge = require('webpack-merge') | |||||
const prodEnv = require('./prod.env') | |||||
module.exports = merge(prodEnv, { | |||||
NODE_ENV: '"development"' | |||||
}) |
@@ -0,0 +1,10 @@ | |||||
server { | |||||
listen 80; | |||||
server_name nexus-timers.local.tld; | |||||
root /usr/share/nginx/html/dist; | |||||
access_log /var/log/nginx/nexus-timers.access.log; | |||||
error_log /var/log/nginx/nexus-timers.error.log; | |||||
} |
@@ -0,0 +1,40 @@ | |||||
'use strict' | |||||
// see http://vuejs-templates.github.io/webpack for documentation. | |||||
const path = require('path') | |||||
module.exports = { | |||||
build: { | |||||
env: require('./prod.env'), | |||||
index: path.resolve(__dirname, '../dist/index.html'), | |||||
assetsRoot: path.resolve(__dirname, '../dist'), | |||||
assetsSubDirectory: 'static', | |||||
assetsPublicPath: '/', | |||||
productionSourceMap: true, | |||||
// Gzip off by default as many popular static hosts such as | |||||
// Surge or Netlify already gzip all static assets for you. | |||||
// Before setting to `true`, make sure to: | |||||
// npm install --save-dev compression-webpack-plugin | |||||
productionGzip: false, | |||||
productionGzipExtensions: ['js', 'css'], | |||||
// Run the build command with an extra argument to | |||||
// View the bundle analyzer report after build finishes: | |||||
// `npm run build --report` | |||||
// Set to `true` or `false` to always turn it on or off | |||||
bundleAnalyzerReport: process.env.npm_config_report | |||||
}, | |||||
dev: { | |||||
env: require('./dev.env'), | |||||
port: 8080, | |||||
autoOpenBrowser: true, | |||||
assetsSubDirectory: 'static', | |||||
assetsPublicPath: '/', | |||||
proxyTable: {}, | |||||
// CSS Sourcemaps off by default because relative paths are "buggy" | |||||
// with this option, according to the CSS-Loader README | |||||
// (https://github.com/webpack/css-loader#sourcemaps) | |||||
// In our experience, they generally work as expected, | |||||
// just be aware of this issue when enabling this option. | |||||
cssSourceMap: true | |||||
} | |||||
} |
@@ -0,0 +1,3 @@ | |||||
module.exports = { | |||||
NODE_ENV: '"production"' | |||||
} |
@@ -0,0 +1,6 @@ | |||||
nexus-timers: | |||||
build: . | |||||
volumes: | |||||
- .:/usr/share/nginx/html | |||||
ports: | |||||
- 80:80 |
@@ -0,0 +1,39 @@ | |||||
<!DOCTYPE html> | |||||
<html lang="en"> | |||||
<head> | |||||
<meta charset="utf-8"> | |||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
<title>nexus-timers</title> | |||||
<link rel="icon" type="image/png" sizes="32x32" href="<%= htmlWebpackPlugin.files.publicPath %>static/img/icons/favicon-32x32.png"> | |||||
<link rel="icon" type="image/png" sizes="16x16" href="<%= htmlWebpackPlugin.files.publicPath %>static/img/icons/favicon-16x16.png"> | |||||
<!--[if IE]><link rel="shortcut icon" href="/static/img/icons/favicon.ico"><![endif]--> | |||||
<!-- Add to home screen for Android and modern mobile browsers --> | |||||
<link rel="manifest" href="<%= htmlWebpackPlugin.files.publicPath %>static/manifest.json"> | |||||
<meta name="theme-color" content="#4DBA87"> | |||||
<!-- Add to home screen for Safari on iOS --> | |||||
<meta name="apple-mobile-web-app-capable" content="yes"> | |||||
<meta name="apple-mobile-web-app-status-bar-style" content="black"> | |||||
<meta name="apple-mobile-web-app-title" content="nexus-timers"> | |||||
<link rel="apple-touch-icon" href="<%= htmlWebpackPlugin.files.publicPath %>static/img/icons/apple-touch-icon-152x152.png"> | |||||
<link rel="mask-icon" href="<%= htmlWebpackPlugin.files.publicPath %>static/img/icons/safari-pinned-tab.svg" color="#4DBA87"> | |||||
<!-- Add to home screen for Windows --> | |||||
<meta name="msapplication-TileImage" content="<%= htmlWebpackPlugin.files.publicPath %>static/img/icons/msapplication-icon-144x144.png"> | |||||
<meta name="msapplication-TileColor" content="#000000"> | |||||
<% for (var chunk of webpack.chunks) { | |||||
for (var file of chunk.files) { | |||||
if (file.match(/\.(js|css)$/)) { %> | |||||
<link rel="<%= chunk.initial?'preload':'prefetch' %>" href="<%= htmlWebpackPlugin.files.publicPath + file %>" as="<%= file.match(/\.css$/)?'style':'script' %>"><% }}} %> | |||||
</head> | |||||
<body> | |||||
<noscript> | |||||
This application can only work with JavaScript enabled. <br /> | |||||
Please enable JavaScript on your browser. | |||||
</noscript> | |||||
<div id="app"></div> | |||||
<!-- Todo: only include in production --> | |||||
<%= htmlWebpackPlugin.options.serviceWorkerLoader %> | |||||
<!-- built files will be auto injected --> | |||||
</body> | |||||
</html> |
@@ -0,0 +1,74 @@ | |||||
{ | |||||
"name": "nexus-timers", | |||||
"version": "1.0.0", | |||||
"description": "Timers ans other features for Heroes of the Storm", | |||||
"author": "Adrien Agez <adrien.agez@hotmail.fr>", | |||||
"private": true, | |||||
"scripts": { | |||||
"dev": "node build/dev-server.js", | |||||
"start": "node build/dev-server.js", | |||||
"build": "node build/build.js", | |||||
"lint": "eslint --ext .js,.vue src" | |||||
}, | |||||
"dependencies": { | |||||
"vue": "^2.5.2", | |||||
"vue-router": "^3.0.1" | |||||
}, | |||||
"devDependencies": { | |||||
"autoprefixer": "^7.1.5", | |||||
"babel-core": "^6.26.0", | |||||
"sw-precache-webpack-plugin": "^0.11.4", | |||||
"babel-eslint": "^8.0.1", | |||||
"babel-loader": "^7.1.2", | |||||
"babel-plugin-transform-runtime": "^6.23.0", | |||||
"babel-preset-env": "^1.6.0", | |||||
"babel-preset-stage-2": "^6.24.1", | |||||
"babel-register": "^6.26.0", | |||||
"chalk": "^2.1.0", | |||||
"connect-history-api-fallback": "^1.4.0", | |||||
"copy-webpack-plugin": "^4.1.1", | |||||
"css-loader": "^0.28.7", | |||||
"cssnano": "^3.10.0", | |||||
"eslint": "^4.9.0", | |||||
"eslint-friendly-formatter": "^3.0.0", | |||||
"eslint-loader": "^1.9.0", | |||||
"eslint-plugin-html": "^3.2.2", | |||||
"eslint-plugin-import": "^2.7.0", | |||||
"eslint-plugin-node": "^5.2.0", | |||||
"eslint-config-standard": "^10.2.1", | |||||
"eslint-plugin-promise": "^3.6.0", | |||||
"eslint-plugin-standard": "^3.0.1", | |||||
"eventsource-polyfill": "^0.9.6", | |||||
"express": "^4.16.2", | |||||
"extract-text-webpack-plugin": "^3.0.0", | |||||
"file-loader": "^1.1.5", | |||||
"friendly-errors-webpack-plugin": "^1.6.1", | |||||
"html-webpack-plugin": "^2.30.1", | |||||
"http-proxy-middleware": "^0.17.4", | |||||
"webpack-bundle-analyzer": "^2.9.0", | |||||
"semver": "^5.4.1", | |||||
"shelljs": "^0.7.8", | |||||
"opn": "^5.1.0", | |||||
"optimize-css-assets-webpack-plugin": "^3.2.0", | |||||
"ora": "^1.3.0", | |||||
"rimraf": "^2.6.2", | |||||
"url-loader": "^0.6.2", | |||||
"vue-loader": "^13.3.0", | |||||
"vue-style-loader": "^3.0.3", | |||||
"vue-template-compiler": "^2.5.2", | |||||
"webpack": "^3.7.1", | |||||
"webpack-dev-middleware": "^1.12.0", | |||||
"webpack-hot-middleware": "^2.19.1", | |||||
"webpack-merge": "^4.1.0", | |||||
"uglify-es": "^3.1.3" | |||||
}, | |||||
"engines": { | |||||
"node": ">= 4.0.0", | |||||
"npm": ">= 3.0.0" | |||||
}, | |||||
"browserslist": [ | |||||
"> 1%", | |||||
"last 2 versions", | |||||
"not IE <= 11" | |||||
] | |||||
} |
@@ -0,0 +1,54 @@ | |||||
<template> | |||||
<div id="app"> | |||||
<header> | |||||
<span>Vue.js PWA</span> | |||||
</header> | |||||
<main> | |||||
<img src="./assets/logo.png" alt="Vue.js PWA"> | |||||
<router-view></router-view> | |||||
</main> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
export default { | |||||
name: 'app' | |||||
} | |||||
</script> | |||||
<style> | |||||
body { | |||||
margin: 0; | |||||
} | |||||
#app { | |||||
font-family: 'Avenir', Helvetica, Arial, sans-serif; | |||||
-webkit-font-smoothing: antialiased; | |||||
-moz-osx-font-smoothing: grayscale; | |||||
color: #2c3e50; | |||||
} | |||||
main { | |||||
text-align: center; | |||||
margin-top: 40px; | |||||
} | |||||
header { | |||||
margin: 0; | |||||
height: 56px; | |||||
padding: 0 16px 0 24px; | |||||
background-color: #35495E; | |||||
color: #ffffff; | |||||
} | |||||
header span { | |||||
display: block; | |||||
position: relative; | |||||
font-size: 20px; | |||||
line-height: 1; | |||||
letter-spacing: .02em; | |||||
font-weight: 400; | |||||
box-sizing: border-box; | |||||
padding-top: 16px; | |||||
} | |||||
</style> |
@@ -0,0 +1,52 @@ | |||||
<template> | |||||
<div class="hello"> | |||||
<h1>{{ msg }}</h1> | |||||
<h2>Essential Links</h2> | |||||
<ul> | |||||
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li> | |||||
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li> | |||||
<li><a href="http://chat.vuejs.org/" target="_blank" rel="noopener">Vue Community Chat</a></li> | |||||
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li> | |||||
<li><a href="http://vuejs-templates.github.io/webpack/" target="_blank" rel="noopener">Docs for This Template</a></li> | |||||
</ul> | |||||
<h2>Ecosystem</h2> | |||||
<ul> | |||||
<li><a href="http://router.vuejs.org/" target="_blank" rel="noopener">vue-router</a></li> | |||||
<li><a href="http://vuex.vuejs.org/" target="_blank" rel="noopener">vuex</a></li> | |||||
<li><a href="http://vue-loader.vuejs.org/" target="_blank" rel="noopener">vue-loader</a></li> | |||||
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li> | |||||
</ul> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
export default { | |||||
name: 'hello', | |||||
data () { | |||||
return { | |||||
msg: 'Welcome to Your Vue.js PWA' | |||||
} | |||||
} | |||||
} | |||||
</script> | |||||
<!-- Add "scoped" attribute to limit CSS to this component only --> | |||||
<style> | |||||
h1, h2 { | |||||
font-weight: normal; | |||||
} | |||||
ul { | |||||
list-style-type: none; | |||||
padding: 0; | |||||
} | |||||
li { | |||||
display: inline-block; | |||||
margin: 0 10px; | |||||
} | |||||
a { | |||||
color: #35495E; | |||||
} | |||||
</style> |
@@ -0,0 +1,15 @@ | |||||
// The Vue build version to load with the `import` command | |||||
// (runtime-only or standalone) has been set in webpack.base.conf with an alias. | |||||
import Vue from 'vue' | |||||
import App from './App' | |||||
import router from './router' | |||||
Vue.config.productionTip = false | |||||
/* eslint-disable no-new */ | |||||
new Vue({ | |||||
el: '#app', | |||||
router, | |||||
template: '<App/>', | |||||
components: { App } | |||||
}) |
@@ -0,0 +1,15 @@ | |||||
import Vue from 'vue' | |||||
import Router from 'vue-router' | |||||
import Hello from '@/components/Hello' | |||||
Vue.use(Router) | |||||
export default new Router({ | |||||
routes: [ | |||||
{ | |||||
path: '/', | |||||
name: 'Hello', | |||||
component: Hello | |||||
} | |||||
] | |||||
}) |
@@ -0,0 +1,149 @@ | |||||
<?xml version="1.0" standalone="no"?> | |||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" | |||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> | |||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" | |||||
width="16.000000pt" height="16.000000pt" viewBox="0 0 16.000000 16.000000" | |||||
preserveAspectRatio="xMidYMid meet"> | |||||
<metadata> | |||||
Created by potrace 1.11, written by Peter Selinger 2001-2013 | |||||
</metadata> | |||||
<g transform="translate(0.000000,16.000000) scale(0.000320,-0.000320)" | |||||
fill="#000000" stroke="none"> | |||||
<path d="M18 46618 c45 -75 122 -207 122 -211 0 -2 25 -45 55 -95 30 -50 55 | |||||
-96 55 -102 0 -5 5 -10 10 -10 6 0 10 -4 10 -9 0 -5 73 -135 161 -288 89 -153 | |||||
173 -298 187 -323 14 -25 32 -57 41 -72 88 -149 187 -324 189 -335 2 -7 8 -13 | |||||
13 -13 5 0 9 -4 9 -10 0 -5 46 -89 103 -187 175 -302 490 -846 507 -876 8 -16 | |||||
20 -36 25 -45 28 -46 290 -498 339 -585 13 -23 74 -129 136 -236 61 -107 123 | |||||
-215 137 -240 14 -25 29 -50 33 -56 5 -5 23 -37 40 -70 18 -33 38 -67 44 -75 | |||||
11 -16 21 -33 63 -109 14 -25 29 -50 33 -56 4 -5 21 -35 38 -65 55 -100 261 | |||||
-455 269 -465 4 -5 14 -21 20 -35 15 -29 41 -75 103 -180 24 -41 52 -88 60 | |||||
-105 9 -16 57 -100 107 -185 112 -193 362 -626 380 -660 8 -14 23 -38 33 -55 | |||||
11 -16 23 -37 27 -45 4 -8 26 -46 48 -85 23 -38 53 -90 67 -115 46 -81 64 | |||||
-113 178 -310 62 -107 121 -210 132 -227 37 -67 56 -99 85 -148 16 -27 32 -57 | |||||
36 -65 4 -8 15 -27 25 -42 9 -15 53 -89 96 -165 44 -76 177 -307 296 -513 120 | |||||
-206 268 -463 330 -570 131 -227 117 -203 200 -348 36 -62 73 -125 82 -140 10 | |||||
-15 21 -34 25 -42 4 -8 20 -37 36 -65 17 -27 38 -65 48 -82 49 -85 64 -111 87 | |||||
-153 13 -25 28 -49 32 -55 4 -5 78 -134 165 -285 87 -151 166 -288 176 -305 | |||||
10 -16 26 -43 35 -59 9 -17 125 -217 257 -445 132 -229 253 -441 270 -471 17 | |||||
-30 45 -79 64 -108 18 -29 33 -54 33 -57 0 -2 20 -37 44 -77 24 -40 123 -212 | |||||
221 -383 97 -170 190 -330 205 -355 16 -25 39 -65 53 -90 13 -25 81 -144 152 | |||||
-265 70 -121 137 -238 150 -260 12 -22 37 -65 55 -95 18 -30 43 -73 55 -95 12 | |||||
-22 48 -85 80 -140 77 -132 163 -280 190 -330 13 -22 71 -123 130 -225 59 | |||||
-102 116 -199 126 -217 10 -17 29 -50 43 -72 15 -22 26 -43 26 -45 0 -2 27 | |||||
-50 60 -106 33 -56 60 -103 60 -105 0 -2 55 -98 90 -155 8 -14 182 -316 239 | |||||
-414 13 -22 45 -79 72 -124 27 -46 49 -86 49 -89 0 -2 14 -24 30 -48 16 -24 | |||||
30 -46 30 -49 0 -5 74 -135 100 -176 5 -8 24 -42 43 -75 50 -88 58 -101 262 | |||||
-455 104 -179 199 -345 213 -370 14 -25 28 -49 32 -55 4 -5 17 -26 28 -45 10 | |||||
-19 62 -109 114 -200 114 -197 133 -230 170 -295 16 -27 33 -57 38 -65 17 -28 | |||||
96 -165 103 -180 4 -8 16 -28 26 -45 10 -16 77 -131 148 -255 72 -124 181 | |||||
-313 243 -420 62 -107 121 -209 131 -227 35 -62 323 -560 392 -678 38 -66 83 | |||||
-145 100 -175 16 -30 33 -59 37 -65 4 -5 17 -27 29 -47 34 -61 56 -100 90 | |||||
-156 17 -29 31 -55 31 -57 0 -2 17 -32 39 -67 21 -35 134 -229 251 -433 117 | |||||
-203 235 -407 261 -451 27 -45 49 -85 49 -88 0 -4 8 -19 19 -34 15 -21 200 | |||||
-341 309 -533 10 -19 33 -58 51 -87 17 -29 31 -54 31 -56 0 -2 25 -44 55 -94 | |||||
30 -50 55 -95 55 -98 0 -4 6 -15 14 -23 7 -9 27 -41 43 -71 17 -30 170 -297 | |||||
342 -594 171 -296 311 -542 311 -547 0 -5 5 -9 10 -9 6 0 10 -4 10 -10 0 -5 | |||||
22 -47 49 -92 27 -46 58 -99 68 -118 24 -43 81 -140 93 -160 5 -8 66 -114 135 | |||||
-235 69 -121 130 -227 135 -235 12 -21 259 -447 283 -490 10 -19 28 -47 38 | |||||
-62 11 -14 19 -29 19 -32 0 -3 37 -69 83 -148 99 -170 305 -526 337 -583 13 | |||||
-22 31 -53 41 -70 11 -16 22 -37 26 -45 7 -14 82 -146 103 -180 14 -24 181 | |||||
-311 205 -355 13 -22 46 -80 75 -130 29 -49 64 -110 78 -135 14 -25 51 -88 82 | |||||
-140 31 -52 59 -102 63 -110 4 -8 18 -33 31 -55 205 -353 284 -489 309 -535 | |||||
17 -30 45 -78 62 -106 18 -28 36 -60 39 -72 4 -12 12 -22 17 -22 5 0 9 -4 9 | |||||
-10 0 -5 109 -197 241 -427 133 -230 250 -431 259 -448 51 -90 222 -385 280 | |||||
-485 37 -63 78 -135 92 -160 14 -25 67 -117 118 -205 51 -88 101 -175 111 | |||||
-193 34 -58 55 -95 149 -257 51 -88 101 -173 110 -190 9 -16 76 -131 147 -255 | |||||
72 -124 140 -241 151 -260 61 -108 281 -489 355 -615 38 -66 77 -133 87 -150 | |||||
35 -63 91 -161 100 -175 14 -23 99 -169 128 -220 54 -97 135 -235 142 -245 4 | |||||
-5 20 -32 35 -60 26 -48 238 -416 276 -480 10 -16 26 -46 37 -65 30 -53 382 | |||||
-661 403 -695 10 -16 22 -37 26 -45 4 -8 26 -48 50 -88 24 -41 43 -75 43 -77 | |||||
0 -2 22 -40 50 -85 27 -45 50 -84 50 -86 0 -3 38 -69 83 -147 84 -142 302 | |||||
-520 340 -587 10 -19 34 -60 52 -90 18 -30 44 -75 57 -100 14 -25 45 -79 70 | |||||
-120 25 -41 56 -96 70 -121 14 -25 77 -133 138 -240 62 -107 122 -210 132 | |||||
-229 25 -43 310 -535 337 -581 11 -19 26 -45 34 -59 17 -32 238 -414 266 -460 | |||||
11 -19 24 -41 28 -49 3 -7 75 -133 160 -278 84 -146 153 -269 153 -274 0 -5 5 | |||||
-9 10 -9 6 0 10 -4 10 -10 0 -5 82 -150 181 -322 182 -314 201 -346 240 -415 | |||||
12 -21 80 -139 152 -263 71 -124 141 -245 155 -270 14 -25 28 -49 32 -55 6 -8 | |||||
145 -248 220 -380 37 -66 209 -362 229 -395 11 -19 24 -42 28 -49 4 -8 67 | |||||
-118 140 -243 73 -125 133 -230 133 -233 0 -2 15 -28 33 -57 19 -29 47 -78 64 | |||||
-108 17 -30 53 -93 79 -139 53 -90 82 -141 157 -272 82 -142 115 -199 381 | |||||
-659 142 -245 268 -463 281 -485 12 -22 71 -125 132 -230 60 -104 172 -298 | |||||
248 -430 76 -132 146 -253 156 -270 11 -16 22 -36 26 -44 3 -8 30 -54 60 -103 | |||||
29 -49 53 -91 53 -93 0 -3 18 -34 40 -70 22 -36 40 -67 40 -69 0 -2 37 -66 81 | |||||
-142 45 -77 98 -168 119 -204 20 -36 47 -81 58 -100 12 -19 27 -47 33 -62 6 | |||||
-16 15 -28 20 -28 5 0 9 -4 9 -9 0 -6 63 -118 140 -251 77 -133 140 -243 140 | |||||
-245 0 -2 18 -33 41 -70 22 -37 49 -83 60 -101 10 -19 29 -51 40 -71 25 -45 | |||||
109 -189 126 -218 7 -11 17 -29 22 -40 6 -11 22 -38 35 -60 14 -22 37 -62 52 | |||||
-90 14 -27 35 -62 45 -77 11 -14 19 -29 19 -32 0 -3 18 -35 40 -71 22 -36 40 | |||||
-67 40 -69 0 -2 19 -35 42 -72 23 -38 55 -94 72 -124 26 -47 139 -244 171 | |||||
-298 6 -9 21 -36 34 -60 28 -48 37 -51 51 -19 6 12 19 36 29 52 10 17 27 46 | |||||
38 65 11 19 104 181 208 360 103 179 199 345 213 370 14 25 42 74 64 109 21 | |||||
34 38 65 38 67 0 2 18 33 40 69 22 36 40 67 40 69 0 3 177 310 199 346 16 26 | |||||
136 234 140 244 2 5 25 44 52 88 27 44 49 81 49 84 0 2 18 34 40 70 22 36 40 | |||||
67 40 69 0 2 20 36 43 77 35 58 169 289 297 513 9 17 50 86 90 155 40 69 86 | |||||
150 103 180 16 30 35 62 41 70 6 8 16 24 22 35 35 64 72 129 167 293 59 100 | |||||
116 199 127 220 11 20 30 53 41 72 43 72 1070 1850 1121 1940 14 25 65 113 | |||||
113 195 48 83 96 166 107 185 10 19 28 50 38 68 11 18 73 124 137 235 64 111 | |||||
175 303 246 427 71 124 173 299 225 390 52 91 116 202 143 248 27 45 49 85 49 | |||||
89 0 4 6 14 14 22 7 9 28 43 46 76 26 47 251 436 378 655 11 19 29 51 40 70 | |||||
11 19 101 176 201 348 99 172 181 317 181 323 0 5 5 9 10 9 6 0 10 5 10 11 0 | |||||
6 8 23 18 37 11 15 32 52 49 82 16 30 130 228 253 440 122 212 234 405 248 | |||||
430 13 25 39 70 57 100 39 65 69 117 130 225 25 44 50 87 55 95 12 19 78 134 | |||||
220 380 61 107 129 224 150 260 161 277 222 382 246 425 15 28 47 83 71 123 | |||||
24 41 43 78 43 83 0 5 4 9 8 9 4 0 13 12 19 28 7 15 23 45 36 67 66 110 277 | |||||
478 277 483 0 3 6 13 14 21 7 9 27 41 43 71 17 30 45 80 63 110 34 57 375 649 | |||||
394 685 6 11 16 27 22 35 6 8 26 42 44 75 18 33 41 74 51 90 10 17 24 41 32 | |||||
55 54 97 72 128 88 152 11 14 19 28 19 30 0 3 79 141 175 308 96 167 175 305 | |||||
175 308 0 3 6 13 14 21 7 9 26 39 41 66 33 60 276 483 338 587 24 40 46 80 50 | |||||
88 4 8 13 24 20 35 14 23 95 163 125 215 11 19 52 91 92 160 40 69 80 139 90 | |||||
155 9 17 103 179 207 360 105 182 200 346 211 365 103 181 463 802 489 845 7 | |||||
11 15 27 19 35 4 8 29 51 55 95 64 110 828 1433 848 1470 9 17 24 41 33 55 9 | |||||
14 29 48 45 77 15 28 52 93 82 145 30 51 62 107 71 123 17 30 231 398 400 690 | |||||
51 88 103 179 115 202 12 23 26 48 32 55 6 7 24 38 40 68 17 30 61 107 98 170 | |||||
37 63 84 144 103 180 19 36 41 72 48 81 8 8 14 18 14 21 0 4 27 51 59 106 32 | |||||
55 72 124 89 154 16 29 71 125 122 213 51 88 104 180 118 205 13 25 28 50 32 | |||||
55 4 6 17 26 28 45 11 19 45 80 77 135 31 55 66 116 77 135 11 19 88 152 171 | |||||
295 401 694 620 1072 650 1125 11 19 87 152 170 295 83 143 158 273 166 288 9 | |||||
16 21 36 26 45 6 9 31 52 55 96 25 43 54 94 66 115 11 20 95 164 186 321 91 | |||||
157 173 299 182 315 9 17 26 46 37 65 12 19 66 114 121 210 56 96 108 186 117 | |||||
200 8 14 24 40 34 59 24 45 383 664 412 713 5 9 17 29 26 45 15 28 120 210 | |||||
241 419 36 61 68 117 72 125 4 8 12 23 19 34 35 57 245 420 262 453 11 20 35 | |||||
61 53 90 17 29 32 54 32 56 0 3 28 51 62 108 33 57 70 119 80 138 10 19 23 42 | |||||
28 50 5 8 32 53 59 100 27 47 149 258 271 470 122 212 234 405 248 430 30 53 | |||||
62 108 80 135 6 11 15 27 19 35 4 8 85 150 181 315 96 165 187 323 202 350 31 | |||||
56 116 202 130 225 5 8 25 42 43 75 19 33 92 159 162 280 149 257 157 271 202 | |||||
350 19 33 38 67 43 75 9 14 228 392 275 475 12 22 55 96 95 165 40 69 80 139 | |||||
90 155 24 42 202 350 221 383 9 15 27 47 41 72 14 25 75 131 136 236 61 106 | |||||
121 210 134 232 99 172 271 470 279 482 5 8 23 40 40 70 18 30 81 141 142 245 | |||||
60 105 121 210 135 235 14 25 71 124 127 220 56 96 143 247 194 335 51 88 96 | |||||
167 102 175 14 24 180 311 204 355 23 43 340 590 356 615 5 8 50 87 101 175 | |||||
171 301 517 898 582 1008 25 43 46 81 46 83 0 2 12 23 27 47 14 23 40 67 56 | |||||
97 16 30 35 62 42 70 7 8 15 22 18 30 4 8 20 38 37 65 16 28 33 57 37 65 6 12 | |||||
111 196 143 250 5 8 55 95 112 193 57 98 113 195 126 215 12 20 27 46 32 57 6 | |||||
11 14 27 20 35 5 8 76 130 156 270 80 140 165 287 187 325 23 39 52 90 66 115 | |||||
13 25 30 52 37 61 8 8 14 18 14 21 0 4 41 77 92 165 50 87 175 302 276 478 | |||||
101 176 208 360 236 408 28 49 67 117 86 152 19 35 41 70 48 77 6 6 12 15 12 | |||||
19 0 7 124 224 167 291 12 21 23 40 23 42 0 2 21 40 46 83 26 43 55 92 64 109 | |||||
54 95 327 568 354 614 19 30 45 75 59 100 71 128 82 145 89 148 4 2 8 8 8 13 | |||||
0 5 42 82 94 172 311 538 496 858 518 897 14 25 40 70 58 100 18 30 42 71 53 | |||||
90 10 19 79 139 152 265 73 127 142 246 153 265 10 19 43 76 72 125 29 50 63 | |||||
108 75 130 65 116 80 140 87 143 4 2 8 8 8 12 0 8 114 212 140 250 6 8 14 24 | |||||
20 35 5 11 54 97 108 190 l100 170 -9611 3 c-5286 1 -9614 -1 -9618 -5 -5 -6 | |||||
-419 -719 -619 -1068 -89 -155 -267 -463 -323 -560 -38 -66 -81 -140 -95 -165 | |||||
-31 -56 -263 -457 -526 -910 -110 -190 -224 -388 -254 -440 -29 -52 -61 -109 | |||||
-71 -125 -23 -39 -243 -420 -268 -465 -11 -19 -204 -352 -428 -740 -224 -388 | |||||
-477 -826 -563 -975 -85 -148 -185 -322 -222 -385 -37 -63 -120 -207 -185 | |||||
-320 -65 -113 -177 -306 -248 -430 -72 -124 -172 -297 -222 -385 -51 -88 -142 | |||||
-245 -202 -350 -131 -226 -247 -427 -408 -705 -65 -113 -249 -432 -410 -710 | |||||
-160 -278 -388 -673 -506 -877 -118 -205 -216 -373 -219 -373 -3 0 -52 82 | |||||
-109 183 -58 100 -144 250 -192 332 -95 164 -402 696 -647 1120 -85 149 -228 | |||||
396 -317 550 -212 365 -982 1700 -1008 1745 -10 19 -43 76 -72 125 -29 50 -64 | |||||
110 -77 135 -14 25 -63 110 -110 190 -47 80 -96 165 -110 190 -14 25 -99 171 | |||||
-188 325 -89 154 -174 300 -188 325 -13 25 -64 113 -112 195 -48 83 -140 242 | |||||
-205 355 -65 113 -183 317 -263 454 -79 137 -152 264 -163 282 -50 89 -335 | |||||
583 -354 614 -12 19 -34 58 -50 85 -15 28 -129 226 -253 440 -124 215 -235 | |||||
408 -247 430 -12 22 -69 121 -127 220 -58 99 -226 389 -373 645 -148 256 -324 | |||||
561 -392 678 -67 117 -134 232 -147 255 -13 23 -33 59 -46 80 l-22 37 -9615 0 | |||||
-9615 0 20 -32z"/> | |||||
</g> | |||||
</svg> |
@@ -0,0 +1,20 @@ | |||||
{ | |||||
"name": "nexus-timers", | |||||
"short_name": "nexus-timers", | |||||
"icons": [ | |||||
{ | |||||
"src": "/static/img/icons/android-chrome-192x192.png", | |||||
"sizes": "192x192", | |||||
"type": "image/png" | |||||
}, | |||||
{ | |||||
"src": "/static/img/icons/android-chrome-512x512.png", | |||||
"sizes": "512x512", | |||||
"type": "image/png" | |||||
} | |||||
], | |||||
"start_url": "/index.html", | |||||
"display": "standalone", | |||||
"background_color": "#000000", | |||||
"theme_color": "#4DBA87" | |||||
} |