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