├── .babelrc ├── .electron-vue ├── build.js ├── dev-client.js ├── dev-runner.js ├── webpack.main.config.js ├── webpack.renderer.config.js └── webpack.web.config.js ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── appveyor.yml ├── build └── icons │ ├── 256x256.png │ ├── icon.icns │ └── icon.ico ├── dist ├── electron │ └── .gitkeep └── web │ └── .gitkeep ├── package-lock.json ├── package.json ├── screenshots ├── loaded.png ├── profiles.png ├── saveas.png ├── search.png └── updateNotice.png ├── src ├── index.ejs ├── main │ ├── index.dev.js │ └── index.js └── renderer │ ├── App.vue │ ├── assets │ ├── .gitkeep │ ├── config.js │ ├── css │ │ ├── bootstrap.css │ │ └── tooltip.css │ ├── fonts │ │ └── source-sans-pro-v13-latin-regular.woff2 │ ├── icon.png │ └── photon │ │ ├── css │ │ └── photon.min.css │ │ └── fonts │ │ ├── photon-entypo.eot │ │ ├── photon-entypo.svg │ │ ├── photon-entypo.ttf │ │ └── photon-entypo.woff │ ├── components │ ├── AppInfo.vue │ ├── LandingPage.vue │ └── LandingPage │ │ ├── FileIngest.vue │ │ └── Modal.vue │ ├── main.js │ ├── router │ └── index.js │ ├── services │ ├── github.js │ └── linuxparse.js │ └── store │ ├── index.js │ └── modules │ ├── Counter.js │ └── index.js └── static └── .gitkeep /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "comments": false, 3 | "env": { 4 | "main": { 5 | "presets": [ 6 | ["env", { 7 | "targets": { "node": 7 } 8 | }], 9 | "stage-0" 10 | ] 11 | }, 12 | "renderer": { 13 | "presets": [ 14 | ["env", { 15 | "modules": false 16 | }], 17 | "stage-0" 18 | ] 19 | }, 20 | "web": { 21 | "presets": [ 22 | ["env", { 23 | "modules": false 24 | }], 25 | "stage-0" 26 | ] 27 | } 28 | }, 29 | "plugins": ["transform-runtime"] 30 | } 31 | -------------------------------------------------------------------------------- /.electron-vue/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.NODE_ENV = 'production' 4 | 5 | const { say } = require('cfonts') 6 | const chalk = require('chalk') 7 | const del = require('del') 8 | const { spawn } = require('child_process') 9 | const webpack = require('webpack') 10 | const Multispinner = require('multispinner') 11 | 12 | 13 | const mainConfig = require('./webpack.main.config') 14 | const rendererConfig = require('./webpack.renderer.config') 15 | const webConfig = require('./webpack.web.config') 16 | 17 | const doneLog = chalk.bgGreen.white(' DONE ') + ' ' 18 | const errorLog = chalk.bgRed.white(' ERROR ') + ' ' 19 | const okayLog = chalk.bgBlue.white(' OKAY ') + ' ' 20 | const isCI = process.env.CI || false 21 | 22 | if (process.env.BUILD_TARGET === 'clean') clean() 23 | else if (process.env.BUILD_TARGET === 'web') web() 24 | else build() 25 | 26 | function clean () { 27 | del.sync(['build/*', '!build/icons', '!build/icons/icon.*']) 28 | console.log(`\n${doneLog}\n`) 29 | process.exit() 30 | } 31 | 32 | function build () { 33 | greeting() 34 | 35 | del.sync(['dist/electron/*', '!.gitkeep']) 36 | 37 | const tasks = ['main', 'renderer'] 38 | const m = new Multispinner(tasks, { 39 | preText: 'building', 40 | postText: 'process' 41 | }) 42 | 43 | let results = '' 44 | 45 | m.on('success', () => { 46 | process.stdout.write('\x1B[2J\x1B[0f') 47 | console.log(`\n\n${results}`) 48 | console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`) 49 | process.exit() 50 | }) 51 | 52 | pack(mainConfig).then(result => { 53 | results += result + '\n\n' 54 | m.success('main') 55 | }).catch(err => { 56 | m.error('main') 57 | console.log(`\n ${errorLog}failed to build main process`) 58 | console.error(`\n${err}\n`) 59 | process.exit(1) 60 | }) 61 | 62 | pack(rendererConfig).then(result => { 63 | results += result + '\n\n' 64 | m.success('renderer') 65 | }).catch(err => { 66 | m.error('renderer') 67 | console.log(`\n ${errorLog}failed to build renderer process`) 68 | console.error(`\n${err}\n`) 69 | process.exit(1) 70 | }) 71 | } 72 | 73 | function pack (config) { 74 | return new Promise((resolve, reject) => { 75 | config.mode = 'production' 76 | webpack(config, (err, stats) => { 77 | if (err) reject(err.stack || err) 78 | else if (stats.hasErrors()) { 79 | let err = '' 80 | 81 | stats.toString({ 82 | chunks: false, 83 | colors: true 84 | }) 85 | .split(/\r?\n/) 86 | .forEach(line => { 87 | err += ` ${line}\n` 88 | }) 89 | 90 | reject(err) 91 | } else { 92 | resolve(stats.toString({ 93 | chunks: false, 94 | colors: true 95 | })) 96 | } 97 | }) 98 | }) 99 | } 100 | 101 | function web () { 102 | del.sync(['dist/web/*', '!.gitkeep']) 103 | webConfig.mode = 'production' 104 | webpack(webConfig, (err, stats) => { 105 | if (err || stats.hasErrors()) console.log(err) 106 | 107 | console.log(stats.toString({ 108 | chunks: false, 109 | colors: true 110 | })) 111 | 112 | process.exit() 113 | }) 114 | } 115 | 116 | function greeting () { 117 | const cols = process.stdout.columns 118 | let text = '' 119 | 120 | if (cols > 85) text = 'lets-build' 121 | else if (cols > 60) text = 'lets-|build' 122 | else text = false 123 | 124 | if (text && !isCI) { 125 | say(text, { 126 | colors: ['yellow'], 127 | font: 'simple3d', 128 | space: false 129 | }) 130 | } else console.log(chalk.yellow.bold('\n lets-build')) 131 | console.log() 132 | } -------------------------------------------------------------------------------- /.electron-vue/dev-client.js: -------------------------------------------------------------------------------- 1 | const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 2 | 3 | hotClient.subscribe(event => { 4 | /** 5 | * Reload browser when HTMLWebpackPlugin emits a new index.html 6 | * 7 | * Currently disabled until jantimon/html-webpack-plugin#680 is resolved. 8 | * https://github.com/SimulatedGREG/electron-vue/issues/437 9 | * https://github.com/jantimon/html-webpack-plugin/issues/680 10 | */ 11 | // if (event.action === 'reload') { 12 | // window.location.reload() 13 | // } 14 | 15 | /** 16 | * Notify `mainWindow` when `main` process is compiling, 17 | * giving notice for an expected reload of the `electron` process 18 | */ 19 | if (event.action === 'compiling') { 20 | document.body.innerHTML += ` 21 | 34 | 35 |
36 | Compiling Main Process... 37 |
38 | ` 39 | } 40 | }) 41 | -------------------------------------------------------------------------------- /.electron-vue/dev-runner.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const chalk = require('chalk') 4 | const electron = require('electron') 5 | const path = require('path') 6 | const { say } = require('cfonts') 7 | const { spawn } = require('child_process') 8 | const webpack = require('webpack') 9 | const WebpackDevServer = require('webpack-dev-server') 10 | const webpackHotMiddleware = require('webpack-hot-middleware') 11 | 12 | const mainConfig = require('./webpack.main.config') 13 | const rendererConfig = require('./webpack.renderer.config') 14 | 15 | let electronProcess = null 16 | let manualRestart = false 17 | let hotMiddleware 18 | 19 | function logStats (proc, data) { 20 | let log = '' 21 | 22 | log += chalk.yellow.bold(`┏ ${proc} Process ${new Array((19 - proc.length) + 1).join('-')}`) 23 | log += '\n\n' 24 | 25 | if (typeof data === 'object') { 26 | data.toString({ 27 | colors: true, 28 | chunks: false 29 | }).split(/\r?\n/).forEach(line => { 30 | log += ' ' + line + '\n' 31 | }) 32 | } else { 33 | log += ` ${data}\n` 34 | } 35 | 36 | log += '\n' + chalk.yellow.bold(`┗ ${new Array(28 + 1).join('-')}`) + '\n' 37 | 38 | console.log(log) 39 | } 40 | 41 | function startRenderer () { 42 | return new Promise((resolve, reject) => { 43 | rendererConfig.entry.renderer = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.renderer) 44 | rendererConfig.mode = 'development' 45 | const compiler = webpack(rendererConfig) 46 | hotMiddleware = webpackHotMiddleware(compiler, { 47 | log: false, 48 | heartbeat: 2500 49 | }) 50 | 51 | compiler.hooks.compilation.tap('compilation', compilation => { 52 | compilation.hooks.htmlWebpackPluginAfterEmit.tapAsync('html-webpack-plugin-after-emit', (data, cb) => { 53 | hotMiddleware.publish({ action: 'reload' }) 54 | cb() 55 | }) 56 | }) 57 | 58 | compiler.hooks.done.tap('done', stats => { 59 | logStats('Renderer', stats) 60 | }) 61 | 62 | const server = new WebpackDevServer( 63 | compiler, 64 | { 65 | contentBase: path.join(__dirname, '../'), 66 | quiet: true, 67 | before (app, ctx) { 68 | app.use(hotMiddleware) 69 | ctx.middleware.waitUntilValid(() => { 70 | resolve() 71 | }) 72 | } 73 | } 74 | ) 75 | 76 | server.listen(9080) 77 | }) 78 | } 79 | 80 | function startMain () { 81 | return new Promise((resolve, reject) => { 82 | mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main) 83 | mainConfig.mode = 'development' 84 | const compiler = webpack(mainConfig) 85 | 86 | compiler.hooks.watchRun.tapAsync('watch-run', (compilation, done) => { 87 | logStats('Main', chalk.white.bold('compiling...')) 88 | hotMiddleware.publish({ action: 'compiling' }) 89 | done() 90 | }) 91 | 92 | compiler.watch({}, (err, stats) => { 93 | if (err) { 94 | console.log(err) 95 | return 96 | } 97 | 98 | logStats('Main', stats) 99 | 100 | if (electronProcess && electronProcess.kill) { 101 | manualRestart = true 102 | process.kill(electronProcess.pid) 103 | electronProcess = null 104 | startElectron() 105 | 106 | setTimeout(() => { 107 | manualRestart = false 108 | }, 5000) 109 | } 110 | 111 | resolve() 112 | }) 113 | }) 114 | } 115 | 116 | function startElectron () { 117 | var args = [ 118 | '--inspect=5858', 119 | path.join(__dirname, '../dist/electron/main.js') 120 | ] 121 | 122 | // detect yarn or npm and process commandline args accordingly 123 | if (process.env.npm_execpath.endsWith('yarn.js')) { 124 | args = args.concat(process.argv.slice(3)) 125 | } else if (process.env.npm_execpath.endsWith('npm-cli.js')) { 126 | args = args.concat(process.argv.slice(2)) 127 | } 128 | 129 | electronProcess = spawn(electron, args) 130 | 131 | electronProcess.stdout.on('data', data => { 132 | electronLog(data, 'blue') 133 | }) 134 | electronProcess.stderr.on('data', data => { 135 | electronLog(data, 'red') 136 | }) 137 | 138 | electronProcess.on('close', () => { 139 | if (!manualRestart) process.exit() 140 | }) 141 | } 142 | 143 | function electronLog (data, color) { 144 | let log = '' 145 | data = data.toString().split(/\r?\n/) 146 | data.forEach(line => { 147 | log += ` ${line}\n` 148 | }) 149 | if (/[0-9A-z]+/.test(log)) { 150 | console.log( 151 | chalk[color].bold('┏ Electron -------------------') + 152 | '\n\n' + 153 | log + 154 | chalk[color].bold('┗ ----------------------------') + 155 | '\n' 156 | ) 157 | } 158 | } 159 | 160 | function greeting () { 161 | const cols = process.stdout.columns 162 | let text = '' 163 | 164 | if (cols > 104) text = 'electron-vue' 165 | else if (cols > 76) text = 'electron-|vue' 166 | else text = false 167 | 168 | if (text) { 169 | say(text, { 170 | colors: ['yellow'], 171 | font: 'simple3d', 172 | space: false 173 | }) 174 | } else console.log(chalk.yellow.bold('\n electron-vue')) 175 | console.log(chalk.blue(' getting ready...') + '\n') 176 | } 177 | 178 | function init () { 179 | greeting() 180 | 181 | Promise.all([startRenderer(), startMain()]) 182 | .then(() => { 183 | startElectron() 184 | }) 185 | .catch(err => { 186 | console.error(err) 187 | }) 188 | } 189 | 190 | init() 191 | -------------------------------------------------------------------------------- /.electron-vue/webpack.main.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'main' 4 | 5 | const path = require('path') 6 | const { dependencies } = require('../package.json') 7 | const webpack = require('webpack') 8 | 9 | const MinifyPlugin = require("babel-minify-webpack-plugin") 10 | 11 | let mainConfig = { 12 | entry: { 13 | main: path.join(__dirname, '../src/main/index.js') 14 | }, 15 | externals: [ 16 | ...Object.keys(dependencies || {}), 17 | {'electron-debug': 'electron-debug'} 18 | ], 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.(js)$/, 23 | enforce: 'pre', 24 | exclude: /node_modules/, 25 | use: { 26 | loader: 'eslint-loader', 27 | options: { 28 | formatter: require('eslint-friendly-formatter') 29 | } 30 | } 31 | }, 32 | { 33 | test: /\.js$/, 34 | use: 'babel-loader', 35 | exclude: /node_modules/ 36 | }, 37 | { 38 | test: /\.node$/, 39 | use: 'node-loader' 40 | } 41 | ] 42 | }, 43 | node: { 44 | __dirname: process.env.NODE_ENV !== 'production', 45 | __filename: process.env.NODE_ENV !== 'production' 46 | }, 47 | output: { 48 | filename: '[name].js', 49 | libraryTarget: 'commonjs2', 50 | path: path.join(__dirname, '../dist/electron') 51 | }, 52 | plugins: [ 53 | new webpack.NoEmitOnErrorsPlugin() 54 | ], 55 | resolve: { 56 | extensions: ['.js', '.json', '.node'] 57 | }, 58 | target: 'electron-main' 59 | } 60 | 61 | /** 62 | * Adjust mainConfig for development settings 63 | */ 64 | if (process.env.NODE_ENV !== 'production') { 65 | mainConfig.plugins.push( 66 | new webpack.DefinePlugin({ 67 | '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"` 68 | }) 69 | ) 70 | } 71 | 72 | /** 73 | * Adjust mainConfig for production settings 74 | */ 75 | if (process.env.NODE_ENV === 'production') { 76 | mainConfig.plugins.push( 77 | new MinifyPlugin(), 78 | new webpack.DefinePlugin({ 79 | 'process.env.NODE_ENV': '"production"' 80 | }) 81 | ) 82 | } 83 | 84 | module.exports = mainConfig 85 | -------------------------------------------------------------------------------- /.electron-vue/webpack.renderer.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'renderer' 4 | 5 | const path = require('path') 6 | const { dependencies } = require('../package.json') 7 | const webpack = require('webpack') 8 | 9 | const MinifyPlugin = require("babel-minify-webpack-plugin") 10 | const CopyWebpackPlugin = require('copy-webpack-plugin') 11 | const MiniCssExtractPlugin = require('mini-css-extract-plugin') 12 | const HtmlWebpackPlugin = require('html-webpack-plugin') 13 | const { VueLoaderPlugin } = require('vue-loader') 14 | 15 | /** 16 | * List of node_modules to include in webpack bundle 17 | * 18 | * Required for specific packages like Vue UI libraries 19 | * that provide pure *.vue files that need compiling 20 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals 21 | */ 22 | let whiteListedModules = ['vue'] 23 | 24 | let rendererConfig = { 25 | devtool: '#cheap-module-eval-source-map', 26 | entry: { 27 | renderer: path.join(__dirname, '../src/renderer/main.js') 28 | }, 29 | externals: [ 30 | ...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d)) 31 | ], 32 | module: { 33 | rules: [ 34 | { 35 | test: /\.(js|vue)$/, 36 | enforce: 'pre', 37 | exclude: /node_modules/, 38 | use: { 39 | loader: 'eslint-loader', 40 | options: { 41 | formatter: require('eslint-friendly-formatter') 42 | } 43 | } 44 | }, 45 | { 46 | test: /\.scss$/, 47 | use: ['vue-style-loader', 'css-loader', 'sass-loader'] 48 | }, 49 | { 50 | test: /\.sass$/, 51 | use: ['vue-style-loader', 'css-loader', 'sass-loader?indentedSyntax'] 52 | }, 53 | { 54 | test: /\.less$/, 55 | use: ['vue-style-loader', 'css-loader', 'less-loader'] 56 | }, 57 | { 58 | test: /\.css$/, 59 | use: ['vue-style-loader', 'css-loader'] 60 | }, 61 | { 62 | test: /\.html$/, 63 | use: 'vue-html-loader' 64 | }, 65 | { 66 | test: /\.js$/, 67 | use: 'babel-loader', 68 | exclude: /node_modules/ 69 | }, 70 | { 71 | test: /\.node$/, 72 | use: 'node-loader' 73 | }, 74 | { 75 | test: /\.vue$/, 76 | use: { 77 | loader: 'vue-loader', 78 | options: { 79 | extractCSS: process.env.NODE_ENV === 'production', 80 | loaders: { 81 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1', 82 | scss: 'vue-style-loader!css-loader!sass-loader', 83 | less: 'vue-style-loader!css-loader!less-loader' 84 | } 85 | } 86 | } 87 | }, 88 | { 89 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 90 | use: [{ 91 | loader: 'url-loader', 92 | query: { 93 | limit: 10000, 94 | esModule: false, 95 | name: 'imgs/[name]--[folder].[ext]' 96 | } 97 | }] 98 | }, 99 | { 100 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 101 | loader: 'url-loader', 102 | options: { 103 | limit: 10000, 104 | name: 'media/[name]--[folder].[ext]' 105 | } 106 | }, 107 | { 108 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 109 | use: { 110 | loader: 'url-loader', 111 | query: { 112 | limit: 10000, 113 | name: 'fonts/[name]--[folder].[ext]' 114 | } 115 | } 116 | } 117 | ] 118 | }, 119 | node: { 120 | __dirname: process.env.NODE_ENV !== 'production', 121 | __filename: process.env.NODE_ENV !== 'production' 122 | }, 123 | plugins: [ 124 | new VueLoaderPlugin(), 125 | new MiniCssExtractPlugin({filename: 'styles.css'}), 126 | new HtmlWebpackPlugin({ 127 | filename: 'index.html', 128 | template: path.resolve(__dirname, '../src/index.ejs'), 129 | minify: { 130 | collapseWhitespace: true, 131 | removeAttributeQuotes: true, 132 | removeComments: true 133 | }, 134 | isBrowser: false, 135 | isDevelopment: process.env.NODE_ENV !== 'production', 136 | nodeModules: process.env.NODE_ENV !== 'production' 137 | ? path.resolve(__dirname, '../node_modules') 138 | : false 139 | }), 140 | new webpack.HotModuleReplacementPlugin(), 141 | new webpack.NoEmitOnErrorsPlugin() 142 | ], 143 | output: { 144 | filename: '[name].js', 145 | libraryTarget: 'commonjs2', 146 | path: path.join(__dirname, '../dist/electron') 147 | }, 148 | resolve: { 149 | alias: { 150 | '@': path.join(__dirname, '../src/renderer'), 151 | 'vue$': 'vue/dist/vue.esm.js' 152 | }, 153 | extensions: ['.js', '.vue', '.json', '.css', '.node'] 154 | }, 155 | target: 'electron-renderer' 156 | } 157 | 158 | /** 159 | * Adjust rendererConfig for development settings 160 | */ 161 | if (process.env.NODE_ENV !== 'production') { 162 | rendererConfig.plugins.push( 163 | new webpack.DefinePlugin({ 164 | '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"` 165 | }) 166 | ) 167 | } 168 | 169 | /** 170 | * Adjust rendererConfig for production settings 171 | */ 172 | if (process.env.NODE_ENV === 'production') { 173 | rendererConfig.devtool = '' 174 | 175 | rendererConfig.plugins.push( 176 | new MinifyPlugin(), 177 | new CopyWebpackPlugin([ 178 | { 179 | from: path.join(__dirname, '../static'), 180 | to: path.join(__dirname, '../dist/electron/static'), 181 | ignore: ['.*'] 182 | } 183 | ]), 184 | new webpack.DefinePlugin({ 185 | 'process.env.NODE_ENV': '"production"' 186 | }), 187 | new webpack.LoaderOptionsPlugin({ 188 | minimize: true 189 | }) 190 | ) 191 | } 192 | 193 | module.exports = rendererConfig 194 | -------------------------------------------------------------------------------- /.electron-vue/webpack.web.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'web' 4 | 5 | const path = require('path') 6 | const webpack = require('webpack') 7 | 8 | const MinifyPlugin = require("babel-minify-webpack-plugin") 9 | const CopyWebpackPlugin = require('copy-webpack-plugin') 10 | const MiniCssExtractPlugin = require('mini-css-extract-plugin') 11 | const HtmlWebpackPlugin = require('html-webpack-plugin') 12 | const { VueLoaderPlugin } = require('vue-loader') 13 | 14 | let webConfig = { 15 | devtool: '#cheap-module-eval-source-map', 16 | entry: { 17 | web: path.join(__dirname, '../src/renderer/main.js') 18 | }, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.(js|vue)$/, 23 | enforce: 'pre', 24 | exclude: /node_modules/, 25 | use: { 26 | loader: 'eslint-loader', 27 | options: { 28 | formatter: require('eslint-friendly-formatter') 29 | } 30 | } 31 | }, 32 | { 33 | test: /\.scss$/, 34 | use: ['vue-style-loader', 'css-loader', 'sass-loader'] 35 | }, 36 | { 37 | test: /\.sass$/, 38 | use: ['vue-style-loader', 'css-loader', 'sass-loader?indentedSyntax'] 39 | }, 40 | { 41 | test: /\.less$/, 42 | use: ['vue-style-loader', 'css-loader', 'less-loader'] 43 | }, 44 | { 45 | test: /\.css$/, 46 | use: ['vue-style-loader', 'css-loader'] 47 | }, 48 | { 49 | test: /\.html$/, 50 | use: 'vue-html-loader' 51 | }, 52 | { 53 | test: /\.js$/, 54 | use: 'babel-loader', 55 | include: [ path.resolve(__dirname, '../src/renderer') ], 56 | exclude: /node_modules/ 57 | }, 58 | { 59 | test: /\.vue$/, 60 | use: { 61 | loader: 'vue-loader', 62 | options: { 63 | extractCSS: true, 64 | loaders: { 65 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1', 66 | scss: 'vue-style-loader!css-loader!sass-loader', 67 | less: 'vue-style-loader!css-loader!less-loader' 68 | } 69 | } 70 | } 71 | }, 72 | { 73 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 74 | use: { 75 | loader: 'url-loader', 76 | query: { 77 | limit: 10000, 78 | name: 'imgs/[name].[ext]' 79 | } 80 | } 81 | }, 82 | { 83 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 84 | use: { 85 | loader: 'url-loader', 86 | query: { 87 | limit: 10000, 88 | name: 'fonts/[name].[ext]' 89 | } 90 | } 91 | } 92 | ] 93 | }, 94 | plugins: [ 95 | new VueLoaderPlugin(), 96 | new MiniCssExtractPlugin({filename: 'styles.css'}), 97 | new HtmlWebpackPlugin({ 98 | filename: 'index.html', 99 | template: path.resolve(__dirname, '../src/index.ejs'), 100 | minify: { 101 | collapseWhitespace: true, 102 | removeAttributeQuotes: true, 103 | removeComments: true 104 | }, 105 | nodeModules: false 106 | }), 107 | new webpack.DefinePlugin({ 108 | 'process.env.IS_WEB': 'true' 109 | }), 110 | new webpack.HotModuleReplacementPlugin(), 111 | new webpack.NoEmitOnErrorsPlugin() 112 | ], 113 | output: { 114 | filename: '[name].js', 115 | path: path.join(__dirname, '../dist/web') 116 | }, 117 | resolve: { 118 | alias: { 119 | '@': path.join(__dirname, '../src/renderer'), 120 | 'vue$': 'vue/dist/vue.esm.js' 121 | }, 122 | extensions: ['.js', '.vue', '.json', '.css'] 123 | }, 124 | target: 'electron' 125 | } 126 | 127 | /** 128 | * Adjust webConfig for production settings 129 | */ 130 | if (process.env.NODE_ENV === 'production') { 131 | webConfig.devtool = '' 132 | 133 | webConfig.plugins.push( 134 | new MinifyPlugin(), 135 | new CopyWebpackPlugin([ 136 | { 137 | from: path.join(__dirname, '../static'), 138 | to: path.join(__dirname, '../dist/web/static'), 139 | ignore: ['.*'] 140 | } 141 | ]), 142 | new webpack.DefinePlugin({ 143 | 'process.env.NODE_ENV': '"production"' 144 | }), 145 | new webpack.LoaderOptionsPlugin({ 146 | minimize: true 147 | }) 148 | ) 149 | } 150 | 151 | module.exports = webConfig 152 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/.eslintignore -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true 6 | }, 7 | parserOptions: { 8 | parser: "babel-eslint", 9 | // specifying a module sourcetype prevent eslint from marking import statements as errors 10 | sourceType: "module", 11 | "ecmaFeatures": { 12 | "legacyDecorators": true 13 | } 14 | }, 15 | extends: [ 16 | // use the recommended rule set for both plain javascript and vue 17 | "eslint:recommended", 18 | "plugin:vue/recommended" 19 | ], 20 | globals: { 21 | "module": "writable", 22 | "process": "writable" 23 | }, 24 | rules: { 25 | "no-unused-vars": ["warn", {"argsIgnorePattern": "^_" }], 26 | "require-atomic-updates": "off", 27 | "indent": ["warn",2], 28 | "quotes": ["warn","double"], 29 | "semi": ["warn","always"], 30 | "spaced-comment": ["warn", "always", {"exceptions": ["-","+"]}], 31 | "template-curly-spacing": ["off"] 32 | } 33 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | dist/electron/* 3 | dist/web/* 4 | build/* 5 | !build/icons 6 | node_modules/ 7 | npm-debug.log 8 | npm-debug.log.* 9 | thumbs.db 10 | !.gitkeep 11 | .vscode/* 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | osx_image: xcode8.3 2 | sudo: required 3 | dist: trusty 4 | language: c 5 | matrix: 6 | include: 7 | - os: osx 8 | - os: linux 9 | env: CC=clang CXX=clang++ npm_config_clang=1 10 | compiler: clang 11 | cache: 12 | directories: 13 | - node_modules 14 | - "$HOME/.electron" 15 | - "$HOME/.cache" 16 | addons: 17 | apt: 18 | packages: 19 | - libgnome-keyring-dev 20 | - icnsutils 21 | before_install: 22 | - mkdir -p /tmp/git-lfs && curl -L https://github.com/github/git-lfs/releases/download/v1.2.1/git-lfs-$([ 23 | "$TRAVIS_OS_NAME" == "linux" ] && echo "linux" || echo "darwin")-amd64-1.2.1.tar.gz 24 | | tar -xz -C /tmp/git-lfs --strip-components 1 && /tmp/git-lfs/git-lfs pull 25 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils; fi 26 | install: 27 | - nvm install 10 28 | - curl -o- -L https://yarnpkg.com/install.sh | bash 29 | - source ~/.bashrc 30 | - npm install -g xvfb-maybe 31 | - yarn 32 | script: 33 | - yarn run build 34 | branches: 35 | only: 36 | - master 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Stephen Thompson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mult App Launcher 2 | 3 | > Cross Platform Multi App Launcher 4 | 5 | [![multi-app-launcher](https://snapcraft.io/multi-app-launcher/badge.svg)](https://snapcraft.io/multi-app-launcher) 6 | 7 | This is a small [electron](https://www.electronjs.org/) application that allows multiple applications to be launched simultaneously. 8 | 9 | ## Install 10 | Go to the [release page](https://github.com/Arges86/multi-app-launcher/releases) and download the latest version. 11 | The portable, or installable .exe file both are available. 12 | The installable instance will be a little faster running. 13 | 14 | For linux with snap: 15 | [![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/multi-app-launcher) 16 | 17 | ## Usage 18 | Simple open the app, then choose as many programs as you would like. 19 | Increase the slider to get access to more program boxes. 20 | 21 | There are three ways to add a program to the list: 22 | * Find the program or shortcut manually by clicking the gear icon. 23 | * Drag and drop the program, or link thereto into `Drag and Drop` field. 24 | * Or search for it with the search dropdown, and find the program on the list. 25 | 26 | ![search](screenshots/search.png) 27 | 28 | Once All your programs are selected, 29 | Simply click the 'Start All Programs' button to launch them all. 30 | ![Screenshot](screenshots/loaded.png) 31 | 32 | Once you have all the programs you like, simple save your profile. 33 | ![SaveAs](screenshots/saveas.png) 34 | 35 | You can have as many profiles as you like. 36 | ![Profile](screenshots/profiles.png) 37 | 38 | Lastly, can you add optional arguments to the startup command. 39 | For instance, to start Chrome in 'Incognito', click the gear icon and type `-incognito` 40 | into the options modal. 41 | Many programs have startup options that can be set. Two examples are: 42 | Firefox's list can be found [here](https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options). 43 | Chrome's list can be found [here](https://peter.sh/experiments/chromium-command-line-switches/). 44 | 45 | ### Updates 46 | The program checks for any updates at launch. 47 | If there are any updates available, a notification will appear on the icon in the top left. 48 | Click the icon, to open the about window with a download link. 49 | ![Notice](screenshots/updateNotice.png) 50 | 51 | ### Theme 52 | The dark and light theme are dependant on the Operating System theme. 53 | 54 | ### How it works 55 | Each application is opened via `Electron.Shell.openItem`, 56 | Which should provide a platform agnostic way of launching each application. 57 | Profiles are saved in `%APPDATA%/`. 58 | 59 | Search looks in the default program list for the OS. 60 | For Windows: `C:\ProgramData\Microsoft\Windows\Start Menu\Programs` 61 | For others: `/usr/share/applications` 62 | 63 | Updates query Github for the newest release. 64 | if the semantic version at Github is greater than installed, a notification appears. 65 | 66 | ### Build Setup 67 | 68 | ``` bash 69 | # install dependencies 70 | npm install 71 | 72 | # serve with hot reload at localhost:9080 73 | npm run dev 74 | 75 | # build electron application for production 76 | npm run build 77 | 78 | # lint all JS/Vue component files in `src/` 79 | npm run lint 80 | 81 | ``` 82 | The build step (for Windows) will create the installable and portable application for deployment. 83 | 84 | --- 85 | 86 | This project was generated with [electron-vue](https://github.com/SimulatedGREG/electron-vue)@[45a3e22](https://github.com/SimulatedGREG/electron-vue/tree/45a3e224e7bb8fc71909021ccfdcfec0f461f634) using [vue-cli](https://github.com/vuejs/vue-cli). Documentation about the original structure can be found [here](https://simulatedgreg.gitbooks.io/electron-vue/content/index.html). 87 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.1.{build} 2 | 3 | branches: 4 | only: 5 | - master 6 | 7 | image: Visual Studio 2017 8 | platform: 9 | - x64 10 | 11 | cache: 12 | - node_modules 13 | - '%APPDATA%\npm-cache' 14 | - '%USERPROFILE%\.electron' 15 | - '%USERPROFILE%\AppData\Local\Yarn\cache' 16 | 17 | init: 18 | - git config --global core.autocrlf input 19 | 20 | install: 21 | - ps: Install-Product node 8 x64 22 | - git reset --hard HEAD 23 | - yarn 24 | - node --version 25 | 26 | build_script: 27 | - yarn build 28 | 29 | test: off 30 | -------------------------------------------------------------------------------- /build/icons/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/build/icons/256x256.png -------------------------------------------------------------------------------- /build/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/build/icons/icon.icns -------------------------------------------------------------------------------- /build/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/build/icons/icon.ico -------------------------------------------------------------------------------- /dist/electron/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/dist/electron/.gitkeep -------------------------------------------------------------------------------- /dist/web/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/dist/web/.gitkeep -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multi-app-launcher", 3 | "version": "0.3.0", 4 | "author": "Stephen Thompson", 5 | "description": "Multi App Launcher", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/Arges86/multi-app-launcher" 9 | }, 10 | "license": "MIT", 11 | "main": "./dist/electron/main.js", 12 | "scripts": { 13 | "build": "node .electron-vue/build.js && electron-builder", 14 | "build:dir": "node .electron-vue/build.js && electron-builder --dir", 15 | "build:clean": "cross-env BUILD_TARGET=clean node .electron-vue/build.js", 16 | "build:web": "cross-env BUILD_TARGET=web node .electron-vue/build.js", 17 | "dev": "node .electron-vue/dev-runner.js", 18 | "lint": "eslint --ext .js,.vue src", 19 | "lint:fix": "eslint --ext .js,.vue --fix src", 20 | "pack": "npm run pack:main && npm run pack:renderer", 21 | "pack:main": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.main.config.js", 22 | "pack:renderer": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.renderer.config.js", 23 | "postinstall": "npm run lint:fix" 24 | }, 25 | "keywords": [ 26 | "Electron", 27 | "Application Launcher" 28 | ], 29 | "build": { 30 | "productName": "Multi App Launcher", 31 | "appId": "multi-app-launcher", 32 | "directories": { 33 | "output": "build" 34 | }, 35 | "files": [ 36 | "dist/electron/**/*" 37 | ], 38 | "dmg": { 39 | "contents": [ 40 | { 41 | "x": 410, 42 | "y": 150, 43 | "type": "link", 44 | "path": "/Applications" 45 | }, 46 | { 47 | "x": 130, 48 | "y": 150, 49 | "type": "file" 50 | } 51 | ] 52 | }, 53 | "mac": { 54 | "icon": "build/icons/icon.icns" 55 | }, 56 | "win": { 57 | "target": [ 58 | "nsis", 59 | "portable" 60 | ], 61 | "icon": "build/icons/icon.ico" 62 | }, 63 | "linux": { 64 | "target": [ 65 | "AppImage", 66 | "snap" 67 | ], 68 | "icon": "build/icons" 69 | } 70 | }, 71 | "dependencies": { 72 | "@electron/remote": "^2.0.1", 73 | "axios": "^0.25.0", 74 | "electron-context-menu": "^3.1.1", 75 | "electron-settings": "^4.0.2", 76 | "ini": "^2.0.0", 77 | "klaw-sync": "^6.0.0", 78 | "vue": "^2.6.14", 79 | "vue-electron": "^1.0.6", 80 | "vue-router": "^3.5.2", 81 | "vuex": "^3.6.2", 82 | "vuex-electron": "^1.0.0" 83 | }, 84 | "devDependencies": { 85 | "@types/semver": "^7.3.8", 86 | "@vue/eslint-config-standard": "^6.1.0", 87 | "ajv": "^6.12.6", 88 | "babel-core": "^6.26.3", 89 | "babel-eslint": "^8.2.3", 90 | "babel-loader": "^7.1.4", 91 | "babel-minify-webpack-plugin": "^0.3.1", 92 | "babel-plugin-transform-runtime": "^6.23.0", 93 | "babel-preset-env": "^1.7.0", 94 | "babel-preset-stage-0": "^6.24.1", 95 | "babel-register": "^6.26.0", 96 | "cfonts": "^2.10.0", 97 | "chalk": "^4.1.2", 98 | "copy-webpack-plugin": "^4.5.1", 99 | "cross-env": "^7.0.3", 100 | "css-loader": "^3.6.0", 101 | "del": "^6.0.0", 102 | "devtron": "^1.4.0", 103 | "electron": "^17.0.0", 104 | "electron-builder": "^22.14.5", 105 | "electron-debug": "^3.2.0", 106 | "electron-devtools-installer": "^3.2.0", 107 | "eslint": "^7.32.0", 108 | "eslint-config-standard": "^16.0.3", 109 | "eslint-friendly-formatter": "^4.0.1", 110 | "eslint-loader": "^4.0.2", 111 | "eslint-plugin-html": "^6.2.0", 112 | "eslint-plugin-import": "^2.24.2", 113 | "eslint-plugin-node": "^11.1.0", 114 | "eslint-plugin-promise": "^5.1.0", 115 | "eslint-plugin-vue": "^7.19.1", 116 | "file-loader": "^6.2.0", 117 | "html-webpack-plugin": "^3.2.0", 118 | "mini-css-extract-plugin": "0.4.0", 119 | "multispinner": "^0.2.1", 120 | "node-loader": "^0.6.0", 121 | "node-sass": "^6.0.1", 122 | "sass-loader": "^8.0.2", 123 | "style-loader": "^1.2.1", 124 | "url-loader": "^4.1.0", 125 | "vue-html-loader": "^1.2.4", 126 | "vue-loader": "^15.9.8", 127 | "vue-style-loader": "^4.1.3", 128 | "vue-template-compiler": "^2.6.14", 129 | "webpack": "^4.46.0", 130 | "webpack-cli": "^3.3.12", 131 | "webpack-dev-server": "^3.11.2", 132 | "webpack-hot-middleware": "^2.25.1", 133 | "webpack-merge": "^4.1.3" 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /screenshots/loaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/screenshots/loaded.png -------------------------------------------------------------------------------- /screenshots/profiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/screenshots/profiles.png -------------------------------------------------------------------------------- /screenshots/saveas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/screenshots/saveas.png -------------------------------------------------------------------------------- /screenshots/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/screenshots/search.png -------------------------------------------------------------------------------- /screenshots/updateNotice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/screenshots/updateNotice.png -------------------------------------------------------------------------------- /src/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MAL (Multi App Launcher) 6 | <% if (htmlWebpackPlugin.options.nodeModules) { %> 7 | 8 | 11 | <% } %> 12 | 13 | 14 |
15 | 16 | <% if (!htmlWebpackPlugin.options.isBrowser && !htmlWebpackPlugin.options.isDevelopment) { %> 17 | 20 | <% } %> 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/main/index.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is used specifically and only for development. It installs 3 | * `electron-debug` & `vue-devtools`. There shouldn't be any need to 4 | * modify this file, but it can be used to extend your development 5 | * environment. 6 | */ 7 | 8 | /* eslint-disable */ 9 | 10 | // Install `electron-debug` with `devtron` 11 | const debug = require('electron-debug'); 12 | 13 | debug(); 14 | 15 | 16 | // Install `vue-devtools` 17 | require('electron').app.on('ready', () => { 18 | let installExtension = require('electron-devtools-installer') 19 | installExtension.default(installExtension.VUEJS_DEVTOOLS) 20 | .then(() => { }) 21 | .catch(err => { 22 | console.log('Unable to install `vue-devtools`: \n', err) 23 | }) 24 | }) 25 | 26 | // Require `main` process to boot app 27 | require('./index') -------------------------------------------------------------------------------- /src/main/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import { app, BrowserWindow, ipcMain, dialog } from "electron"; 4 | import settings from "electron-settings"; 5 | import contextMenu from "electron-context-menu"; 6 | import * as remoteMain from "@electron/remote/main"; 7 | remoteMain.initialize(); 8 | 9 | /** 10 | * Set `__static` path to static files in production 11 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html 12 | */ 13 | if (process.env.NODE_ENV !== "development") { 14 | global.__static = require("path").join(__dirname, "/static").replace(/\\/g, "\\\\"); 15 | } 16 | 17 | ipcMain.handle("get-settings", async () => { 18 | const allSettings = await settings.get(); 19 | return allSettings; 20 | }); 21 | 22 | ipcMain.handle("delete-profile", async (event, profile) => { 23 | return settings.unsetSync(profile); 24 | }); 25 | 26 | ipcMain.handle("set-profile", async (event, name, values) => { 27 | settings.setSync(name, values); 28 | }); 29 | 30 | ipcMain.handle("file-picker", async (event, options) => { 31 | const filePath = await dialog.showOpenDialog(options); 32 | return filePath; 33 | }); 34 | 35 | ipcMain.on("open-info", async (event) => { 36 | const window = createChildWindow(); 37 | 38 | window.on("close", () => { 39 | event.reply("close-info", true); 40 | }); 41 | }); 42 | 43 | let childWindow; 44 | function createChildWindow () { 45 | const winURL = 46 | process.env.NODE_ENV === "development" 47 | ? "http://localhost:9080/#/info" 48 | : `file://${__dirname}/index.html#info`; 49 | const x = mainWindow.getPosition()[0] + 50; 50 | const y = mainWindow.getPosition()[1] + 50; 51 | 52 | childWindow = new BrowserWindow({ 53 | height: 300, 54 | width: 300, 55 | x, 56 | y, 57 | minimizable: false, 58 | maximizable: false, 59 | useContentSize: true, 60 | type: "toolbar", 61 | frame: true, 62 | parent: mainWindow, 63 | modal: true, 64 | webPreferences: { 65 | nodeIntegration: true, 66 | contextIsolation: false, 67 | nodeIntegrationInWorker: true, 68 | enableRemoteModule: true 69 | } 70 | }); 71 | childWindow.setMenu(null); 72 | 73 | remoteMain.enable(childWindow.webContents); 74 | childWindow.loadURL(winURL); 75 | 76 | return childWindow; 77 | } 78 | 79 | let mainWindow; 80 | const winURL = process.env.NODE_ENV === "development" 81 | ? "http://localhost:9080" 82 | : `file://${__dirname}/index.html`; 83 | 84 | function createWindow () { 85 | /** 86 | * Initial window options 87 | */ 88 | mainWindow = new BrowserWindow({ 89 | height: 563, 90 | useContentSize: true, 91 | width: 1000, 92 | transparent: true, 93 | backgroundColor: "#090979fa", 94 | frame: false, 95 | webPreferences: { 96 | nodeIntegration: true, 97 | contextIsolation: false, 98 | nodeIntegrationInWorker: true, 99 | enableRemoteModule: true 100 | } 101 | }); 102 | mainWindow.setMenu(null); 103 | 104 | remoteMain.enable(mainWindow.webContents); 105 | mainWindow.loadURL(winURL); 106 | 107 | mainWindow.on("closed", () => { 108 | mainWindow = null; 109 | }); 110 | 111 | // adds right click menu 112 | contextMenu({ 113 | showInspectElement: false, 114 | showSearchWithGoogle: false 115 | }); 116 | } 117 | 118 | app.on("ready", createWindow); 119 | 120 | app.on("window-all-closed", () => { 121 | app.quit(); 122 | }); 123 | 124 | app.on("activate", () => { 125 | if (mainWindow === null) { 126 | createWindow(); 127 | } 128 | }); 129 | 130 | /** 131 | * Auto Updater 132 | * 133 | * Uncomment the following code below and install `electron-updater` to 134 | * support auto updating. Code Signing with a valid certificate is required. 135 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating 136 | */ 137 | 138 | /* 139 | import { autoUpdater } from 'electron-updater' 140 | 141 | autoUpdater.on('update-downloaded', () => { 142 | autoUpdater.quitAndInstall() 143 | }) 144 | 145 | app.on('ready', () => { 146 | if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates() 147 | }) 148 | */ 149 | -------------------------------------------------------------------------------- /src/renderer/App.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 94 | 95 | 208 | -------------------------------------------------------------------------------- /src/renderer/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/src/renderer/assets/.gitkeep -------------------------------------------------------------------------------- /src/renderer/assets/config.js: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | WindowsPath: "C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs", 4 | LinuxPath: "/usr/share/applications", 5 | defaultIcon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEaSURBVFhH7ZTbCoJAEIaFCCKCCKJnLTpQVBdB14HQ00T0CqUP4AN41puJAVe92F3HRZegHfgQFvH7/1nQMmPmZ+Z8uYJOCm01vJe64PF8cZ+Ftho89DxPC8IAeZ73QpZlJWmattsAfsBavsk0yRsD3Ox7ST3A4uTC/OjC7ODCdO/AZOfAeOvAaPOB4foDg1UVwLZtIUmSqG2AIq9vgNcc5coBKHIWgNec0RhAdAUUOSJrjsRxrLYBihxBMa85QzkARY7ImjOkAURXQJEjKOY1Z0RRpLYBihyRNUe5cgCKHEEprzmjMYDoCqjImiNhGKptgApvA3V57wFkzbUGEMmDIGgfAKH84ShypQBdyn3fFwfQSaE1Y+bvx7K+efsbU5+Ow3MAAAAASUVORK5CYII=" 6 | }; 7 | -------------------------------------------------------------------------------- /src/renderer/assets/css/bootstrap.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Generated using the Bootstrap Customizer (https://getbootstrap.com/docs/3.4/customize/) 3 | */ 4 | /*! 5 | * Bootstrap v3.4.1 (https://getbootstrap.com/) 6 | * Copyright 2011-2019 Twitter, Inc. 7 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 8 | */ 9 | /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ 10 | hr { 11 | -webkit-box-sizing: content-box; 12 | box-sizing: content-box; 13 | height: 0; 14 | } 15 | hr { 16 | border: 0; 17 | border-top: 1px solid #eeeeee; 18 | } 19 | .container { 20 | padding-right: 15px; 21 | padding-left: 15px; 22 | margin-right: auto; 23 | margin-left: auto; 24 | } 25 | @media (min-width: 768px) { 26 | .container { 27 | width: 750px; 28 | } 29 | } 30 | @media (min-width: 992px) { 31 | .container { 32 | width: 970px; 33 | } 34 | } 35 | @media (min-width: 1200px) { 36 | .container { 37 | width: 1170px; 38 | } 39 | } 40 | .container-fluid { 41 | padding-right: 15px; 42 | padding-left: 15px; 43 | margin-right: auto; 44 | margin-left: auto; 45 | } 46 | .row { 47 | margin-right: -15px; 48 | margin-left: -15px; 49 | } 50 | .row-no-gutters { 51 | margin-right: 0; 52 | margin-left: 0; 53 | } 54 | .row-no-gutters [class*="col-"] { 55 | padding-right: 0; 56 | padding-left: 0; 57 | } 58 | .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { 59 | position: relative; 60 | min-height: 1px; 61 | padding-right: 15px; 62 | padding-left: 15px; 63 | } 64 | @media (min-width: 992px) { 65 | .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { 66 | float: left; 67 | } 68 | .col-md-12 { 69 | width: 100%; 70 | } 71 | .col-md-11 { 72 | width: 91.66666667%; 73 | } 74 | .col-md-10 { 75 | width: 83.33333333%; 76 | } 77 | .col-md-9 { 78 | width: 75%; 79 | } 80 | .col-md-8 { 81 | width: 66.66666667%; 82 | } 83 | .col-md-7 { 84 | width: 58.33333333%; 85 | } 86 | .col-md-6 { 87 | width: 50%; 88 | } 89 | .col-md-5 { 90 | width: 41.66666667%; 91 | } 92 | .col-md-4 { 93 | width: 33.33333333%; 94 | } 95 | .col-md-3 { 96 | width: 25%; 97 | } 98 | .col-md-2 { 99 | width: 16.66666667%; 100 | } 101 | .col-md-1 { 102 | width: 8.33333333%; 103 | } 104 | .col-md-pull-12 { 105 | right: 100%; 106 | } 107 | .col-md-pull-11 { 108 | right: 91.66666667%; 109 | } 110 | .col-md-pull-10 { 111 | right: 83.33333333%; 112 | } 113 | .col-md-pull-9 { 114 | right: 75%; 115 | } 116 | .col-md-pull-8 { 117 | right: 66.66666667%; 118 | } 119 | .col-md-pull-7 { 120 | right: 58.33333333%; 121 | } 122 | .col-md-pull-6 { 123 | right: 50%; 124 | } 125 | .col-md-pull-5 { 126 | right: 41.66666667%; 127 | } 128 | .col-md-pull-4 { 129 | right: 33.33333333%; 130 | } 131 | .col-md-pull-3 { 132 | right: 25%; 133 | } 134 | .col-md-pull-2 { 135 | right: 16.66666667%; 136 | } 137 | .col-md-pull-1 { 138 | right: 8.33333333%; 139 | } 140 | .col-md-pull-0 { 141 | right: auto; 142 | } 143 | .col-md-push-12 { 144 | left: 100%; 145 | } 146 | .col-md-push-11 { 147 | left: 91.66666667%; 148 | } 149 | .col-md-push-10 { 150 | left: 83.33333333%; 151 | } 152 | .col-md-push-9 { 153 | left: 75%; 154 | } 155 | .col-md-push-8 { 156 | left: 66.66666667%; 157 | } 158 | .col-md-push-7 { 159 | left: 58.33333333%; 160 | } 161 | .col-md-push-6 { 162 | left: 50%; 163 | } 164 | .col-md-push-5 { 165 | left: 41.66666667%; 166 | } 167 | .col-md-push-4 { 168 | left: 33.33333333%; 169 | } 170 | .col-md-push-3 { 171 | left: 25%; 172 | } 173 | .col-md-push-2 { 174 | left: 16.66666667%; 175 | } 176 | .col-md-push-1 { 177 | left: 8.33333333%; 178 | } 179 | .col-md-push-0 { 180 | left: auto; 181 | } 182 | .col-md-offset-12 { 183 | margin-left: 100%; 184 | } 185 | .col-md-offset-11 { 186 | margin-left: 91.66666667%; 187 | } 188 | .col-md-offset-10 { 189 | margin-left: 83.33333333%; 190 | } 191 | .col-md-offset-9 { 192 | margin-left: 75%; 193 | } 194 | .col-md-offset-8 { 195 | margin-left: 66.66666667%; 196 | } 197 | .col-md-offset-7 { 198 | margin-left: 58.33333333%; 199 | } 200 | .col-md-offset-6 { 201 | margin-left: 50%; 202 | } 203 | .col-md-offset-5 { 204 | margin-left: 41.66666667%; 205 | } 206 | .col-md-offset-4 { 207 | margin-left: 33.33333333%; 208 | } 209 | .col-md-offset-3 { 210 | margin-left: 25%; 211 | } 212 | .col-md-offset-2 { 213 | margin-left: 16.66666667%; 214 | } 215 | .col-md-offset-1 { 216 | margin-left: 8.33333333%; 217 | } 218 | .col-md-offset-0 { 219 | margin-left: 0%; 220 | } 221 | } 222 | .clearfix:before, 223 | .clearfix:after, 224 | .container:before, 225 | .container:after, 226 | .container-fluid:before, 227 | .container-fluid:after, 228 | .row:before, 229 | .row:after { 230 | display: table; 231 | content: " "; 232 | } 233 | .clearfix:after, 234 | .container:after, 235 | .container-fluid:after, 236 | .row:after { 237 | clear: both; 238 | } 239 | .center-block { 240 | display: block; 241 | margin-right: auto; 242 | margin-left: auto; 243 | } 244 | .pull-right { 245 | float: right !important; 246 | } 247 | .pull-left { 248 | float: left !important; 249 | } 250 | .hide { 251 | display: none !important; 252 | } 253 | .show { 254 | display: block !important; 255 | } 256 | .invisible { 257 | visibility: hidden; 258 | } 259 | .text-hide { 260 | font: 0/0 a; 261 | color: transparent; 262 | text-shadow: none; 263 | background-color: transparent; 264 | border: 0; 265 | } 266 | .hidden { 267 | display: none !important; 268 | } 269 | .affix { 270 | position: fixed; 271 | } 272 | -------------------------------------------------------------------------------- /src/renderer/assets/css/tooltip.css: -------------------------------------------------------------------------------- 1 | /* Tooltip container */ 2 | .tooltip { 3 | position: relative; 4 | display: inline-block; 5 | } 6 | 7 | /* Tooltip text */ 8 | .tooltip .tooltiptext { 9 | visibility: hidden; 10 | width: 120px; 11 | background-color: #555; 12 | color: #fff; 13 | text-align: center; 14 | padding: 5px 0; 15 | border-radius: 6px; 16 | 17 | /* Position the tooltip text */ 18 | position: absolute; 19 | z-index: 1; 20 | bottom: 125%; 21 | left: 50%; 22 | margin-left: -60px; 23 | 24 | /* Fade in tooltip */ 25 | opacity: 0; 26 | transition: opacity 0.3s; 27 | } 28 | 29 | /* Tooltip arrow */ 30 | .tooltip .tooltiptext::after { 31 | content: ""; 32 | position: absolute; 33 | top: 100%; 34 | left: 50%; 35 | margin-left: -5px; 36 | border-width: 5px; 37 | border-style: solid; 38 | border-color: #555 transparent transparent transparent; 39 | } 40 | 41 | /* Show the tooltip text when you mouse over the tooltip container */ 42 | .tooltip:hover .tooltiptext { 43 | visibility: visible; 44 | opacity: 1; 45 | } -------------------------------------------------------------------------------- /src/renderer/assets/fonts/source-sans-pro-v13-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/src/renderer/assets/fonts/source-sans-pro-v13-latin-regular.woff2 -------------------------------------------------------------------------------- /src/renderer/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/src/renderer/assets/icon.png -------------------------------------------------------------------------------- /src/renderer/assets/photon/css/photon.min.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";/*! 2 | * ===================================================== 3 | * Photon v0.1.1 4 | * Copyright 2015 Connor Sears 5 | * Licensed under MIT (https://github.com/connors/proton/blob/master/LICENSE) 6 | * 7 | * v0.1.1 designed by @connors. 8 | * ===================================================== 9 | */audio,canvas,progress,sub,sup,video{vertical-align:baseline}body,html{height:100%}hr,html,label{overflow:hidden}.clearfix:after,.toolbar-actions:after,.toolbar:after{clear:both}*,img{-webkit-user-drag:text}.list-group *,.nav-group-item,h1,h2,h3,h4,h5,h6,label,td,th{white-space:nowrap;text-overflow:ellipsis}audio:not([controls]){display:none}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:36px}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sup{top:-.5em}.pane-group,.window{top:0;left:0;right:0}sub{bottom:-.25em}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}*{cursor:default;-webkit-user-select:none;-webkit-box-sizing:border-box;box-sizing:border-box}html{width:100%}body{padding:0;margin:0;font-family:system,-apple-system,".SFNSDisplay-Regular","Helvetica Neue",Helvetica,"Segoe UI",sans-serif;font-size:13px;line-height:1.6;}.btn-dropdown:after,.icon:before{font-family:photon-entypo}hr{margin:15px 0;background:0 0;border:0;border-bottom:1px solid #ddd}h1,h2,h3,h4,h5,h6{margin-top:20px;margin-bottom:10px;font-weight:500;overflow:hidden}.btn .icon,.toolbar-header .title{margin-top:1px}h2{font-size:30px}h3{font-size:24px}h4{font-size:18px}h5{font-size:14px}.btn,h6{font-size:12px}.window{position:absolute;bottom:0;display:flex;flex-direction:column;background-color:#fff}.window-content{position:relative;overflow-y:auto;display:flex;flex:1}.selectable-text{cursor:text;-webkit-user-select:text}.btn,.title{cursor:default}.text-center{text-align:center}.text-right{text-align:right}.text-left{text-align:left}.btn,.title{text-align:center}.pull-left{float:left}.pull-right{float:right}.padded{padding:10px}.padded-less{padding:5px}.padded-more{padding:20px}.padded-vertically{padding-top:10px;padding-bottom:10px}.padded-vertically-less{padding-top:5px;padding-bottom:5px}.padded-vertically-more{padding-top:20px;padding-bottom:20px}.padded-horizontally{padding-right:10px;padding-left:10px}.padded-horizontally-less{padding-right:5px;padding-left:5px}.padded-horizontally-more{padding-right:20px;padding-left:20px}.padded-top{padding-top:10px}.padded-top-less{padding-top:5px}.padded-top-more{padding-top:20px}.padded-bottom{padding-bottom:10px}.padded-bottom-less{padding-bottom:5px}.padded-bottom-more{padding-bottom:20px}.sidebar{background-color:#f5f5f4}.draggable{-webkit-app-region:drag}.btn,.btn-group{vertical-align:middle;-webkit-app-region:no-drag}.clearfix:after,.clearfix:before{display:table;content:" "}.btn{display:inline-block;padding:3px 8px;margin-bottom:0;line-height:1.4;white-space:nowrap;background-image:none;border:1px solid transparent;border-radius:4px;box-shadow:0 1px 1px rgba(0,0,0,.06)}.btn:focus{outline:0;box-shadow:none}.btn-mini{padding:2px 6px}.btn-large{padding:6px 12px}.btn-form{padding-right:20px;padding-left:20px}.btn-default{color:#333;background-color:#fcfcfc;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fcfcfc),color-stop(100%,#f1f1f1));background-image:-webkit-linear-gradient(top,#fcfcfc 0,#f1f1f1 100%);background-image:linear-gradient(to bottom,#fcfcfc 0,#f1f1f1 100%);border-color:#c2c0c2 #c2c0c2 #a19fa1}.btn-default:active{background-color:#ddd;background-image:none}.btn-negative,.btn-positive,.btn-primary,.btn-warning{color:#fff;text-shadow:0 1px 1px rgba(0,0,0,.1)}.btn-primary{border-color:#388df8 #388df8 #0866dc;background-color:#6eb4f7;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#6eb4f7),color-stop(100%,#1a82fb));background-image:-webkit-linear-gradient(top,#6eb4f7 0,#1a82fb 100%);background-image:linear-gradient(to bottom,#6eb4f7 0,#1a82fb 100%)}.btn-primary:active{background-color:#3e9bf4;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#3e9bf4),color-stop(100%,#0469de));background-image:-webkit-linear-gradient(top,#3e9bf4 0,#0469de 100%);background-image:linear-gradient(to bottom,#3e9bf4 0,#0469de 100%)}.btn-positive{border-color:#29a03b #29a03b #248b34;background-color:#5bd46d;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#5bd46d),color-stop(100%,#29a03b));background-image:-webkit-linear-gradient(top,#5bd46d 0,#29a03b 100%);background-image:linear-gradient(to bottom,#5bd46d 0,#29a03b 100%)}.btn-positive:active{background-color:#34c84a;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#34c84a),color-stop(100%,#248b34));background-image:-webkit-linear-gradient(top,#34c84a 0,#248b34 100%);background-image:linear-gradient(to bottom,#34c84a 0,#248b34 100%)}.btn-negative{border-color:#fb2f29 #fb2f29 #fb1710;background-color:#fd918d;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fd918d),color-stop(100%,#fb2f29));background-image:-webkit-linear-gradient(top,#fd918d 0,#fb2f29 100%);background-image:linear-gradient(to bottom,#fd918d 0,#fb2f29 100%)}.btn-negative:active{background-color:#fc605b;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fc605b),color-stop(100%,#fb1710));background-image:-webkit-linear-gradient(top,#fc605b 0,#fb1710 100%);background-image:linear-gradient(to bottom,#fc605b 0,#fb1710 100%)}.btn-warning{border-color:#fcaa0e #fcaa0e #ee9d02;background-color:#fece72;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fece72),color-stop(100%,#fcaa0e));background-image:-webkit-linear-gradient(top,#fece72 0,#fcaa0e 100%);background-image:linear-gradient(to bottom,#fece72 0,#fcaa0e 100%)}.btn-warning:active{background-color:#fdbc40;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fdbc40),color-stop(100%,#ee9d02));background-image:-webkit-linear-gradient(top,#fdbc40 0,#ee9d02 100%);background-image:linear-gradient(to bottom,#fdbc40 0,#ee9d02 100%)}.btn .icon{float:left;width:14px;height:14px;margin-bottom:1px;color:#737475;font-size:14px;line-height:1}.btn .icon-text{margin-right:5px}.btn-dropdown:after{margin-left:5px;content:""}.btn-group{position:relative;display:inline-block}.toolbar-actions:after,.toolbar-actions:before,.toolbar:after,.toolbar:before{display:table;content:" "}.btn-group .btn{position:relative;float:left}.btn-group .btn:active,.btn-group .btn:focus{z-index:2}.btn-group .btn.active{z-index:3}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-group>.btn:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group .btn+.btn{border-left:1px solid #c2c0c2}.btn-group .btn+.btn.active{border-left:0}.btn-group .active{color:#fff;border:1px solid transparent;background-color:#6d6c6d;background-image:none}.btn-group .active .icon{color:#fff}.toolbar{min-height:22px;box-shadow:inset 0 1px 0 #f5f4f5;background-color:#e8e6e8;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#e8e6e8),color-stop(100%,#d1cfd1));background-image:-webkit-linear-gradient(top,#e8e6e8 0,#d1cfd1 100%);background-image:linear-gradient(to bottom,#e8e6e8 0,#d1cfd1 100%)}.toolbar-header{border-bottom:1px solid #c2c0c2}.toolbar-footer{border-top:1px solid #c2c0c2;-webkit-app-region:drag}.title{margin:0;font-size:12px;font-weight:400;color:#555}.toolbar-borderless{border-top:0;border-bottom:0}.toolbar-actions{margin-top:4px;margin-bottom:3px;padding-right:3px;padding-left:3px;padding-bottom:3px;-webkit-app-region:drag}.form-control,label{display:inline-block;font-size:13px}.toolbar-actions>.btn,.toolbar-actions>.btn-group{margin-left:4px;margin-right:4px}input[type=search]{-webkit-appearance:textfield;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;line-height:normal}.checkbox,.form-group,.radio{margin-bottom:10px}.form-control{width:100%;min-height:25px;padding:5px 10px;line-height:1.6;background-color:#fff;border:1px solid #ddd;border-radius:4px;outline:0}.form-control:focus{border-color:#6db3fd;box-shadow:3px 3px 0 #6db3fd,-3px -3px 0 #6db3fd,-3px 3px 0 #6db3fd,3px -3px 0 #6db3fd}textarea{height:auto}.checkbox,.radio{position:relative;display:block;margin-top:10px}.checkbox label,.radio label{padding-left:20px;margin-bottom:0;font-weight:400}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-left:-20px;margin-top:4px}.form-actions .btn{margin-right:10px}.form-actions .btn:last-child{margin-right:0}.pane-group{position:absolute;bottom:0;display:flex}.icon:before,.pane,.tab-item{position:relative}.pane{overflow-y:auto;flex:1;border-left:1px solid #ddd}.list-group *,.media-body,.nav-group-item,td,th{overflow:hidden}.pane:first-child{border-left:0}.pane-sm{max-width:220px;min-width:150px}.pane-mini{width:80px;flex:none}.pane-one-fourth{width:25%;flex:none}.pane-one-third{width:33.3%}.img-circle{border-radius:50%}.img-rounded{border-radius:4px}.list-group{width:100%;list-style:none;margin:0;padding:0}.list-group *{margin:0}.list-group-item{padding:10px;font-size:12px;color:#414142;border-top:1px solid #ddd}.list-group-item:first-child{border-top:0}.list-group-item.active,.list-group-item.selected{color:#fff;background-color:#116cd6}.list-group-header{padding:10px}.media-object{margin-top:3px}.media-object.pull-left{margin-right:10px}.media-object.pull-right{margin-left:10px}.nav-group{font-size:14px}.nav-group-item{padding:2px 10px 2px 25px;display:block;color:#333;text-decoration:none}.nav-group-item.active,.nav-group-item:active{background-color:#dcdfe1}.nav-group-item .icon{width:19px;height:18px;float:left;color:#737475;margin-top:-3px;margin-right:7px;font-size:18px;text-align:center}.nav-group-title{margin:0;padding:10px 10px 2px;font-size:12px;font-weight:500;color:#666}.icon:before,th{font-weight:400}@font-face{font-family:photon-entypo;src:url(../fonts/photon-entypo.eot);src:url(../fonts/photon-entypo.eot?#iefix) format("eot"),url(../fonts/photon-entypo.woff) format("woff"),url(../fonts/photon-entypo.ttf) format("truetype");font-weight:400;font-style:normal}.icon:before{display:inline-block;speak:none;font-size:100%;font-style:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-note:before{content:'\e800'}.icon-note-beamed:before{content:'\e801'}.icon-music:before{content:'\e802'}.icon-search:before{content:'\e803'}.icon-flashlight:before{content:'\e804'}.icon-mail:before{content:'\e805'}.icon-heart:before{content:'\e806'}.icon-heart-empty:before{content:'\e807'}.icon-star:before{content:'\e808'}.icon-star-empty:before{content:'\e809'}.icon-user:before{content:'\e80a'}.icon-users:before{content:'\e80b'}.icon-user-add:before{content:'\e80c'}.icon-video:before{content:'\e80d'}.icon-picture:before{content:'\e80e'}.icon-camera:before{content:'\e80f'}.icon-layout:before{content:'\e810'}.icon-menu:before{content:'\e811'}.icon-check:before{content:'\e812'}.icon-cancel:before{content:'\e813'}.icon-cancel-circled:before{content:'\e814'}.icon-cancel-squared:before{content:'\e815'}.icon-plus:before{content:'\e816'}.icon-plus-circled:before{content:'\e817'}.icon-plus-squared:before{content:'\e818'}.icon-minus:before{content:'\e819'}.icon-minus-circled:before{content:'\e81a'}.icon-minus-squared:before{content:'\e81b'}.icon-help:before{content:'\e81c'}.icon-help-circled:before{content:'\e81d'}.icon-info:before{content:'\e81e'}.icon-info-circled:before{content:'\e81f'}.icon-back:before{content:'\e820'}.icon-home:before{content:'\e821'}.icon-link:before{content:'\e822'}.icon-attach:before{content:'\e823'}.icon-lock:before{content:'\e824'}.icon-lock-open:before{content:'\e825'}.icon-eye:before{content:'\e826'}.icon-tag:before{content:'\e827'}.icon-bookmark:before{content:'\e828'}.icon-bookmarks:before{content:'\e829'}.icon-flag:before{content:'\e82a'}.icon-thumbs-up:before{content:'\e82b'}.icon-thumbs-down:before{content:'\e82c'}.icon-download:before{content:'\e82d'}.icon-upload:before{content:'\e82e'}.icon-upload-cloud:before{content:'\e82f'}.icon-reply:before{content:'\e830'}.icon-reply-all:before{content:'\e831'}.icon-forward:before{content:'\e832'}.icon-quote:before{content:'\e833'}.icon-code:before{content:'\e834'}.icon-export:before{content:'\e835'}.icon-pencil:before{content:'\e836'}.icon-feather:before{content:'\e837'}.icon-print:before{content:'\e838'}.icon-retweet:before{content:'\e839'}.icon-keyboard:before{content:'\e83a'}.icon-comment:before{content:'\e83b'}.icon-chat:before{content:'\e83c'}.icon-bell:before{content:'\e83d'}.icon-attention:before{content:'\e83e'}.icon-alert:before{content:'\e83f'}.icon-vcard:before{content:'\e840'}.icon-address:before{content:'\e841'}.icon-location:before{content:'\e842'}.icon-map:before{content:'\e843'}.icon-direction:before{content:'\e844'}.icon-compass:before{content:'\e845'}.icon-cup:before{content:'\e846'}.icon-trash:before{content:'\e847'}.icon-doc:before{content:'\e848'}.icon-docs:before{content:'\e849'}.icon-doc-landscape:before{content:'\e84a'}.icon-doc-text:before{content:'\e84b'}.icon-doc-text-inv:before{content:'\e84c'}.icon-newspaper:before{content:'\e84d'}.icon-book-open:before{content:'\e84e'}.icon-book:before{content:'\e84f'}.icon-folder:before{content:'\e850'}.icon-archive:before{content:'\e851'}.icon-box:before{content:'\e852'}.icon-rss:before{content:'\e853'}.icon-phone:before{content:'\e854'}.icon-cog:before{content:'\e855'}.icon-tools:before{content:'\e856'}.icon-share:before{content:'\e857'}.icon-shareable:before{content:'\e858'}.icon-basket:before{content:'\e859'}.icon-bag:before{content:'\e85a'}.icon-calendar:before{content:'\e85b'}.icon-login:before{content:'\e85c'}.icon-logout:before{content:'\e85d'}.icon-mic:before{content:'\e85e'}.icon-mute:before{content:'\e85f'}.icon-sound:before{content:'\e860'}.icon-volume:before{content:'\e861'}.icon-clock:before{content:'\e862'}.icon-hourglass:before{content:'\e863'}.icon-lamp:before{content:'\e864'}.icon-light-down:before{content:'\e865'}.icon-light-up:before{content:'\e866'}.icon-adjust:before{content:'\e867'}.icon-block:before{content:'\e868'}.icon-resize-full:before{content:'\e869'}.icon-resize-small:before{content:'\e86a'}.icon-popup:before{content:'\e86b'}.icon-publish:before{content:'\e86c'}.icon-window:before{content:'\e86d'}.icon-arrow-combo:before{content:'\e86e'}.icon-down-circled:before{content:'\e86f'}.icon-left-circled:before{content:'\e870'}.icon-right-circled:before{content:'\e871'}.icon-up-circled:before{content:'\e872'}.icon-down-open:before{content:'\e873'}.icon-left-open:before{content:'\e874'}.icon-right-open:before{content:'\e875'}.icon-up-open:before{content:'\e876'}.icon-down-open-mini:before{content:'\e877'}.icon-left-open-mini:before{content:'\e878'}.icon-right-open-mini:before{content:'\e879'}.icon-up-open-mini:before{content:'\e87a'}.icon-down-open-big:before{content:'\e87b'}.icon-left-open-big:before{content:'\e87c'}.icon-right-open-big:before{content:'\e87d'}.icon-up-open-big:before{content:'\e87e'}.icon-down:before{content:'\e87f'}.icon-left:before{content:'\e880'}.icon-right:before{content:'\e881'}.icon-up:before{content:'\e882'}.icon-down-dir:before{content:'\e883'}.icon-left-dir:before{content:'\e884'}.icon-right-dir:before{content:'\e885'}.icon-up-dir:before{content:'\e886'}.icon-down-bold:before{content:'\e887'}.icon-left-bold:before{content:'\e888'}.icon-right-bold:before{content:'\e889'}.icon-up-bold:before{content:'\e88a'}.icon-down-thin:before{content:'\e88b'}.icon-left-thin:before{content:'\e88c'}.icon-right-thin:before{content:'\e88d'}.icon-up-thin:before{content:'\e88e'}.icon-ccw:before{content:'\e88f'}.icon-cw:before{content:'\e890'}.icon-arrows-ccw:before{content:'\e891'}.icon-level-down:before{content:'\e892'}.icon-level-up:before{content:'\e893'}.icon-shuffle:before{content:'\e894'}.icon-loop:before{content:'\e895'}.icon-switch:before{content:'\e896'}.icon-play:before{content:'\e897'}.icon-stop:before{content:'\e898'}.icon-pause:before{content:'\e899'}.icon-record:before{content:'\e89a'}.icon-to-end:before{content:'\e89b'}.icon-to-start:before{content:'\e89c'}.icon-fast-forward:before{content:'\e89d'}.icon-fast-backward:before{content:'\e89e'}.icon-progress-0:before{content:'\e89f'}.icon-progress-1:before{content:'\e8a0'}.icon-progress-2:before{content:'\e8a1'}.icon-progress-3:before{content:'\e8a2'}.icon-target:before{content:'\e8a3'}.icon-palette:before{content:'\e8a4'}.icon-list:before{content:'\e8a5'}.icon-list-add:before{content:'\e8a6'}.icon-signal:before{content:'\e8a7'}.icon-trophy:before{content:'\e8a8'}.icon-battery:before{content:'\e8a9'}.icon-back-in-time:before{content:'\e8aa'}.icon-monitor:before{content:'\e8ab'}.icon-mobile:before{content:'\e8ac'}.icon-network:before{content:'\e8ad'}.icon-cd:before{content:'\e8ae'}.icon-inbox:before{content:'\e8af'}.icon-install:before{content:'\e8b0'}.icon-globe:before{content:'\e8b1'}.icon-cloud:before{content:'\e8b2'}.icon-cloud-thunder:before{content:'\e8b3'}.icon-flash:before{content:'\e8b4'}.icon-moon:before{content:'\e8b5'}.icon-flight:before{content:'\e8b6'}.icon-paper-plane:before{content:'\e8b7'}.icon-leaf:before{content:'\e8b8'}.icon-lifebuoy:before{content:'\e8b9'}.icon-mouse:before{content:'\e8ba'}.icon-briefcase:before{content:'\e8bb'}.icon-suitcase:before{content:'\e8bc'}.icon-dot:before{content:'\e8bd'}.icon-dot-2:before{content:'\e8be'}.icon-dot-3:before{content:'\e8bf'}.icon-brush:before{content:'\e8c0'}.icon-magnet:before{content:'\e8c1'}.icon-infinity:before{content:'\e8c2'}.icon-erase:before{content:'\e8c3'}.icon-chart-pie:before{content:'\e8c4'}.icon-chart-line:before{content:'\e8c5'}.icon-chart-bar:before{content:'\e8c6'}.icon-chart-area:before{content:'\e8c7'}.icon-tape:before{content:'\e8c8'}.icon-graduation-cap:before{content:'\e8c9'}.icon-language:before{content:'\e8ca'}.icon-ticket:before{content:'\e8cb'}.icon-water:before{content:'\e8cc'}.icon-droplet:before{content:'\e8cd'}.icon-air:before{content:'\e8ce'}.icon-credit-card:before{content:'\e8cf'}.icon-floppy:before{content:'\e8d0'}.icon-clipboard:before{content:'\e8d1'}.icon-megaphone:before{content:'\e8d2'}.icon-database:before{content:'\e8d3'}.icon-drive:before{content:'\e8d4'}.icon-bucket:before{content:'\e8d5'}.icon-thermometer:before{content:'\e8d6'}.icon-key:before{content:'\e8d7'}.icon-flow-cascade:before{content:'\e8d8'}.icon-flow-branch:before{content:'\e8d9'}.icon-flow-tree:before{content:'\e8da'}.icon-flow-line:before{content:'\e8db'}.icon-flow-parallel:before{content:'\e8dc'}.icon-rocket:before{content:'\e8dd'}.icon-gauge:before{content:'\e8de'}.icon-traffic-cone:before{content:'\e8df'}.icon-cc:before{content:'\e8e0'}.icon-cc-by:before{content:'\e8e1'}.icon-cc-nc:before{content:'\e8e2'}.icon-cc-nc-eu:before{content:'\e8e3'}.icon-cc-nc-jp:before{content:'\e8e4'}.icon-cc-sa:before{content:'\e8e5'}.icon-cc-nd:before{content:'\e8e6'}.icon-cc-pd:before{content:'\e8e7'}.icon-cc-zero:before{content:'\e8e8'}.icon-cc-share:before{content:'\e8e9'}.icon-cc-remix:before{content:'\e8ea'}.icon-github:before{content:'\e8eb'}.icon-github-circled:before{content:'\e8ec'}.icon-flickr:before{content:'\e8ed'}.icon-flickr-circled:before{content:'\e8ee'}.icon-vimeo:before{content:'\e8ef'}.icon-vimeo-circled:before{content:'\e8f0'}.icon-twitter:before{content:'\e8f1'}.icon-twitter-circled:before{content:'\e8f2'}.icon-facebook:before{content:'\e8f3'}.icon-facebook-circled:before{content:'\e8f4'}.icon-facebook-squared:before{content:'\e8f5'}.icon-gplus:before{content:'\e8f6'}.icon-gplus-circled:before{content:'\e8f7'}.icon-pinterest:before{content:'\e8f8'}.icon-pinterest-circled:before{content:'\e8f9'}.icon-tumblr:before{content:'\e8fa'}.icon-tumblr-circled:before{content:'\e8fb'}.icon-linkedin:before{content:'\e8fc'}.icon-linkedin-circled:before{content:'\e8fd'}.icon-dribbble:before{content:'\e8fe'}.icon-dribbble-circled:before{content:'\e8ff'}.icon-stumbleupon:before{content:'\e900'}.icon-stumbleupon-circled:before{content:'\e901'}.icon-lastfm:before{content:'\e902'}.icon-lastfm-circled:before{content:'\e903'}.icon-rdio:before{content:'\e904'}.icon-rdio-circled:before{content:'\e905'}.icon-spotify:before{content:'\e906'}.icon-spotify-circled:before{content:'\e907'}.icon-qq:before{content:'\e908'}.icon-instagram:before{content:'\e909'}.icon-dropbox:before{content:'\e90a'}.icon-evernote:before{content:'\e90b'}.icon-flattr:before{content:'\e90c'}.icon-skype:before{content:'\e90d'}.icon-skype-circled:before{content:'\e90e'}.icon-renren:before{content:'\e90f'}.icon-sina-weibo:before{content:'\e910'}.icon-paypal:before{content:'\e911'}.icon-picasa:before{content:'\e912'}.icon-soundcloud:before{content:'\e913'}.icon-mixi:before{content:'\e914'}.icon-behance:before{content:'\e915'}.icon-google-circles:before{content:'\e916'}.icon-vkontakte:before{content:'\e917'}.icon-smashing:before{content:'\e918'}.icon-sweden:before{content:'\e919'}.icon-db-shape:before{content:'\e91a'}.icon-logo-db:before{content:'\e91b'}table{border-spacing:0;width:100%;border:0;border-collapse:separate;font-size:12px;text-align:left}.table-striped tr:nth-child(even),thead{background-color:#f5f5f4}tbody{background-color:#fff}.table-striped tr:active:nth-child(even),tr:active{color:#fff;background-color:#116cd6}thead tr:active{color:#333;background-color:#f5f5f4}th{border-right:1px solid #ddd;border-bottom:1px solid #ddd}td,th{padding:2px 15px}td:last-child,th:last-child{border-right:0}.tab-group{margin-top:-1px;display:flex;border-top:1px solid #989698;border-bottom:1px solid #989698}.tab-item{flex:1;padding:3px;font-size:12px;text-align:center;border-left:1px solid #989698;background-color:#b8b6b8;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#b8b6b8),color-stop(100%,#b0aeb0));background-image:-webkit-linear-gradient(top,#b8b6b8 0,#b0aeb0 100%);background-image:linear-gradient(to bottom,#b8b6b8 0,#b0aeb0 100%)}.tab-item:first-child{border-left:0}.tab-item.active{background-color:#d4d2d4;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#d4d2d4),color-stop(100%,#cccacc));background-image:-webkit-linear-gradient(top,#d4d2d4 0,#cccacc 100%);background-image:linear-gradient(to bottom,#d4d2d4 0,#cccacc 100%)}.tab-item .icon-close-tab:hover,.tab-item:after{background-color:rgba(0,0,0,.08)}.tab-item .icon-close-tab{position:absolute;top:50%;left:5px;width:15px;height:15px;font-size:15px;line-height:15px;text-align:center;color:#666;opacity:0;transition:opacity .1s linear,background-color .1s linear;border-radius:3px;transform:translateY(-50%);z-index:10}.tab-item:after{position:absolute;top:0;right:0;bottom:0;left:0;content:"";opacity:0;transition:opacity .1s linear;z-index:1}.tab-item:hover .icon-close-tab,.tab-item:hover:not(.active):after{opacity:1}.tab-item-fixed{flex:none;padding:3px 10px} -------------------------------------------------------------------------------- /src/renderer/assets/photon/fonts/photon-entypo.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/src/renderer/assets/photon/fonts/photon-entypo.eot -------------------------------------------------------------------------------- /src/renderer/assets/photon/fonts/photon-entypo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright (C) 2015 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | -------------------------------------------------------------------------------- /src/renderer/assets/photon/fonts/photon-entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/src/renderer/assets/photon/fonts/photon-entypo.ttf -------------------------------------------------------------------------------- /src/renderer/assets/photon/fonts/photon-entypo.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/src/renderer/assets/photon/fonts/photon-entypo.woff -------------------------------------------------------------------------------- /src/renderer/components/AppInfo.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 102 | 103 | -------------------------------------------------------------------------------- /src/renderer/components/LandingPage.vue: -------------------------------------------------------------------------------- 1 | 246 | 247 | 667 | 668 | 982 | -------------------------------------------------------------------------------- /src/renderer/components/LandingPage/FileIngest.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 78 | 79 | -------------------------------------------------------------------------------- /src/renderer/components/LandingPage/Modal.vue: -------------------------------------------------------------------------------- 1 | 98 | 99 | 158 | 159 | 232 | -------------------------------------------------------------------------------- /src/renderer/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | 3 | import App from "./App"; 4 | import router from "./router"; 5 | // import store from './store' 6 | 7 | if (!process.env.IS_WEB) Vue.use(require("vue-electron")); 8 | Vue.config.productionTip = false; 9 | 10 | /* eslint-disable no-new */ 11 | new Vue({ 12 | components: { App }, 13 | router, 14 | template: "" 15 | }).$mount("#app"); 16 | -------------------------------------------------------------------------------- /src/renderer/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Router from "vue-router"; 3 | 4 | Vue.use(Router); 5 | 6 | export default new Router({ 7 | // mode: process.env.IS_ELECTRON ? 'hash' : 'history', 8 | // mode: process.env.NODE_ENV === 'development' ? 'hash' : 'history', 9 | routes: [ 10 | { 11 | path: "/", 12 | name: "landing-page", 13 | component: require("@/components/LandingPage").default 14 | }, 15 | { 16 | path: "/info", 17 | name: "app-info", 18 | component: require("@/components/AppInfo").default 19 | }, 20 | { 21 | path: "*", 22 | redirect: "/" 23 | } 24 | ] 25 | }); 26 | -------------------------------------------------------------------------------- /src/renderer/services/github.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | export default { 4 | getReleases () { 5 | return axios.get("https://api.github.com/repos/Arges86/multi-app-launcher/releases") 6 | .then(response => { 7 | return response.data ? response.data.sort((a, b) => (a.published_at < b.published_at) ? 1 : -1) : response; 8 | }); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /src/renderer/services/linuxparse.js: -------------------------------------------------------------------------------- 1 | import config from "../assets/config"; 2 | 3 | export default { 4 | async parseDesktop (data) { 5 | const fs = require("fs"); 6 | const ini = require("ini"); 7 | const util = require("util"); 8 | const exec = util.promisify(require("child_process").exec); 9 | const text = ini.parse(fs.readFileSync(data, "utf-8")); 10 | const command = (text["Desktop Entry"].Exec).toLowerCase().replace(/ %u| %f/, ""); 11 | // console.log(text['Desktop Entry'].Name, command) 12 | let icon = ""; 13 | 14 | try { 15 | const { stdout } = await exec(`dpkg-query -L ${command} | grep png`); 16 | if (stdout) { 17 | // gets first icon from list 18 | icon = (stdout.split("\n"))[0]; 19 | } 20 | // console.log(icon) 21 | const iconBuffer = fs.readFileSync(icon); 22 | const iconBase64 = Buffer.from(iconBuffer).toString("base64"); 23 | 24 | return { 25 | url: command, 26 | icon: `data:image/png;base64,${iconBase64}` 27 | }; 28 | } catch (error) { 29 | // console.log(`dpkg-query error: ${command} : `) 30 | return { 31 | url: command, 32 | icon: config.defaultIcon 33 | }; 34 | } 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /src/renderer/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | 4 | import { createPersistedState, createSharedMutations } from "vuex-electron"; 5 | 6 | import modules from "./modules"; 7 | 8 | Vue.use(Vuex); 9 | 10 | export default new Vuex.Store({ 11 | modules, 12 | plugins: [ 13 | createPersistedState(), 14 | createSharedMutations() 15 | ], 16 | strict: process.env.NODE_ENV !== "production" 17 | }); 18 | -------------------------------------------------------------------------------- /src/renderer/store/modules/Counter.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | main: 0 3 | }; 4 | 5 | const mutations = { 6 | DECREMENT_MAIN_COUNTER (state) { 7 | state.main--; 8 | }, 9 | INCREMENT_MAIN_COUNTER (state) { 10 | state.main++; 11 | } 12 | }; 13 | 14 | const actions = { 15 | someAsyncTask ({ commit }) { 16 | // do something async 17 | commit("INCREMENT_MAIN_COUNTER"); 18 | } 19 | }; 20 | 21 | export default { 22 | state, 23 | mutations, 24 | actions 25 | }; 26 | -------------------------------------------------------------------------------- /src/renderer/store/modules/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The file enables `@/store/index.js` to import all vuex modules 3 | * in a one-shot manner. There should not be any reason to edit this file. 4 | */ 5 | 6 | const files = require.context(".", false, /\.js$/); 7 | const modules = {}; 8 | 9 | files.keys().forEach(key => { 10 | if (key === "./index.js") return; 11 | modules[key.replace(/(\.\/|\.js)/g, "")] = files(key).default; 12 | }); 13 | 14 | export default modules; 15 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arges86/multi-app-launcher/11849d3f7f110b12f717bc21898827085ab6f268/static/.gitkeep --------------------------------------------------------------------------------