├── dist ├── web │ └── .gitkeep └── electron │ └── .gitkeep ├── static └── .gitkeep ├── src ├── renderer │ ├── assets │ │ ├── .gitkeep │ │ ├── avatar.png │ │ ├── photon │ │ │ ├── fonts │ │ │ │ ├── photon-entypo.eot │ │ │ │ ├── photon-entypo.ttf │ │ │ │ └── photon-entypo.woff │ │ │ └── css │ │ │ │ ├── photon.min.css │ │ │ │ └── photon.css │ │ └── bin-packing │ │ │ ├── packer.js │ │ │ └── packer.growing.js │ ├── store │ │ ├── index.js │ │ └── modules │ │ │ ├── index.js │ │ │ ├── Setting.js │ │ │ ├── App.js │ │ │ └── BMPList.js │ ├── router │ │ └── index.js │ ├── main.js │ ├── components │ │ ├── Help.vue │ │ ├── BMPList.vue │ │ └── Setting.vue │ └── App.vue ├── main │ ├── index.dev.js │ └── index.js └── index.ejs ├── .eslintignore ├── donate.png ├── untitiled.png ├── images └── usage.png ├── .gitignore ├── .vscode └── settings.json ├── .travis.yml ├── appveyor.yml ├── .eslintrc.js ├── README.md ├── untitiled.xml ├── LICENSE ├── .electron-vue ├── dev-client.js ├── webpack.main.config.js ├── build.js ├── webpack.web.config.js ├── dev-runner.js └── webpack.renderer.config.js ├── .babelrc └── package.json /dist/web/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/electron/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/renderer/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | src/renderer/assets/ 2 | -------------------------------------------------------------------------------- /donate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elisaday/bmfont-js/HEAD/donate.png -------------------------------------------------------------------------------- /untitiled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elisaday/bmfont-js/HEAD/untitiled.png -------------------------------------------------------------------------------- /images/usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elisaday/bmfont-js/HEAD/images/usage.png -------------------------------------------------------------------------------- /src/renderer/assets/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elisaday/bmfont-js/HEAD/src/renderer/assets/avatar.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | dist/ 3 | build/* 4 | !build/icons 5 | node_modules/ 6 | npm-debug.log 7 | npm-debug.log.* 8 | thumbs.db 9 | !.gitkeep 10 | -------------------------------------------------------------------------------- /src/renderer/assets/photon/fonts/photon-entypo.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elisaday/bmfont-js/HEAD/src/renderer/assets/photon/fonts/photon-entypo.eot -------------------------------------------------------------------------------- /src/renderer/assets/photon/fonts/photon-entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elisaday/bmfont-js/HEAD/src/renderer/assets/photon/fonts/photon-entypo.ttf -------------------------------------------------------------------------------- /src/renderer/assets/photon/fonts/photon-entypo.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elisaday/bmfont-js/HEAD/src/renderer/assets/photon/fonts/photon-entypo.woff -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.insertSpaces": true, 3 | "editor.tabSize": 2, 4 | 5 | "eslint.validate": [ 6 | "javascript", 7 | "javascriptreact", 8 | "vue" 9 | ], 10 | 11 | "editor.codeActionsOnSave": { 12 | "source.fixAll.eslint": true 13 | } 14 | } -------------------------------------------------------------------------------- /src/renderer/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | import { 5 | createPersistedState 6 | // createSharedMutations 7 | } from 'vuex-electron' 8 | 9 | import modules from './modules' 10 | 11 | Vue.use(Vuex) 12 | 13 | export default new Vuex.Store({ 14 | modules, 15 | plugins: [ 16 | createPersistedState() 17 | // createSharedMutations() 18 | ], 19 | strict: process.env.NODE_ENV !== 'production' 20 | }) 21 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | matrix: 2 | include: 3 | - os: osx 4 | osx_image: xcode12.2 5 | language: node_js 6 | node_js: "14" 7 | 8 | - os: windows 9 | language: node_js 10 | node_js: "14" 11 | 12 | - os: linux 13 | language: node_js 14 | node_js: "14" 15 | 16 | cache: 17 | directories: 18 | - node_modules 19 | - $HOME/.cache/electron 20 | - $HOME/.cache/electron-builder 21 | 22 | script: 23 | npm install 24 | npm run build 25 | 26 | branches: 27 | only: 28 | - master -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/renderer/router/index.js: -------------------------------------------------------------------------------- 1 | 2 | const BMPList = r => require.ensure([], () => r(require('@/components/BMPList')), 'BMPList') 3 | const Setting = r => require.ensure([], () => r(require('@/components/Setting')), 'Setting') 4 | const Help = r => require.ensure([], () => r(require('@/components/Help')), 'Help') 5 | 6 | export default [ 7 | { 8 | path: '/bmp-list', 9 | component: BMPList 10 | }, 11 | { 12 | path: '/setting', 13 | component: Setting 14 | }, 15 | { 16 | path: '/help', 17 | component: Help 18 | }, 19 | { 20 | path: '*', 21 | redirect: '/help' 22 | } 23 | ] 24 | -------------------------------------------------------------------------------- /src/renderer/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | 4 | import App from './App' 5 | import routes from './router' 6 | import store from './store' 7 | 8 | import '@/assets/photon/css/photon.css' 9 | 10 | const process = require('process') 11 | 12 | if (!process.env.IS_WEB) Vue.use(require('vue-electron')) 13 | Vue.config.productionTip = false 14 | 15 | Vue.use(VueRouter) 16 | 17 | const router = new VueRouter({ 18 | routes: routes 19 | }) 20 | 21 | /* eslint-disable no-new */ 22 | new Vue({ 23 | components: { App }, 24 | router, 25 | store, 26 | template: '' 27 | }).$mount('#app') 28 | -------------------------------------------------------------------------------- /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 | require('electron-debug')({ showDevTools: true }) 12 | 13 | // Install `vue-devtools` 14 | require('electron').app.on('ready', () => { 15 | let installExtension = require('electron-devtools-installer') 16 | installExtension.default(installExtension.VUEJS_DEVTOOLS) 17 | .then(() => {}) 18 | .catch(err => { 19 | console.log('Unable to install `vue-devtools`: \n', err) 20 | }) 21 | }) 22 | 23 | // Require `main` process to boot app 24 | require('./index') -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'vue-eslint-parser', 4 | parserOptions: { 5 | parser: 'babel-eslint', 6 | sourceType: 'module' 7 | }, 8 | env: { 9 | browser: true, 10 | node: true 11 | }, 12 | extends: [ 13 | 'plugin:vue/recommended', 14 | 'standard' 15 | ], 16 | globals: { 17 | __static: true 18 | }, 19 | plugins: [ 20 | 'vue' 21 | ], 22 | rules: { 23 | 'no-async-promise-executor': 0, 24 | // "no-new": 0, 25 | // "no-trailing-spaces": 0, 26 | // "comma-dangle": 0, 27 | // allow paren-less arrow functions 28 | 'arrow-parens': 0, 29 | // allow async-await 30 | 'generator-star-spacing': 0, 31 | // allow debugger during development 32 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bmfont-js 2 | 3 | [1]: https://api.travis-ci.org/elisaday/bmfont-js.svg?branch=master 4 | [2]: https://travis-ci.org/elisaday/bmfont-js 5 | [3]: https://img.shields.io/badge/code_style-standard-brightgreen.svg 6 | [4]: https://standardjs.com 7 | 8 | [![Build Status][1]][2] [![JavaScript Style Guide][3]][4] 9 | 10 | 用Electron制作的BMFont,虽然比原版BMFont功能少,但是更加好用。 11 | 12 | --- 13 | 14 | ## 发布包下载 15 | [最新版本](https://github.com/elisaday/bmfont-js/releases/latest) 16 | 17 | 遇到问题欢迎到Issus中讨论。 18 | 19 | --- 20 | 21 | ## 使用方法 22 | 23 | ![使用方法](images/usage.png) 24 | 25 | --- 26 | 27 | ## 运行方法 28 | 29 | ``` bash 30 | # install dependencies 31 | npm install 32 | 33 | # serve with hot reload at localhost:9080 34 | npm run dev 35 | 36 | ``` 37 | 38 | --- 39 | 40 | ![支付宝](donate.png) 41 | 42 | 欢迎使用支付宝扫描上方二维码进行捐赠,捐赠款项将用于后续开发和维护。 43 | 44 | 谢谢关注 45 | -------------------------------------------------------------------------------- /src/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bmfont-js 6 | <% if (htmlWebpackPlugin.options.nodeModules) { %> 7 | 8 | 11 | <% } %> 12 | 13 | 14 |
15 | 16 | <% if (!require('process').browser) { %> 17 | 20 | <% } %> 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /untitiled.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Zeb 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 | -------------------------------------------------------------------------------- /.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/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 | ], 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.(js)$/, 22 | enforce: 'pre', 23 | exclude: /node_modules/, 24 | use: { 25 | loader: 'eslint-loader', 26 | options: { 27 | formatter: require('eslint-friendly-formatter') 28 | } 29 | } 30 | }, 31 | { 32 | test: /\.js$/, 33 | use: 'babel-loader', 34 | exclude: /node_modules/ 35 | }, 36 | { 37 | test: /\.node$/, 38 | use: 'node-loader' 39 | } 40 | ] 41 | }, 42 | node: { 43 | __dirname: process.env.NODE_ENV !== 'production', 44 | __filename: process.env.NODE_ENV !== 'production' 45 | }, 46 | output: { 47 | filename: '[name].js', 48 | libraryTarget: 'commonjs2', 49 | path: path.join(__dirname, '../dist/electron') 50 | }, 51 | plugins: [ 52 | new webpack.NoEmitOnErrorsPlugin() 53 | ], 54 | resolve: { 55 | extensions: ['.js', '.json', '.node'] 56 | }, 57 | target: 'electron-main' 58 | } 59 | 60 | /** 61 | * Adjust mainConfig for development settings 62 | */ 63 | if (process.env.NODE_ENV !== 'production') { 64 | mainConfig.plugins.push( 65 | new webpack.DefinePlugin({ 66 | '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"` 67 | }) 68 | ) 69 | } 70 | 71 | /** 72 | * Adjust mainConfig for production settings 73 | */ 74 | if (process.env.NODE_ENV === 'production') { 75 | mainConfig.plugins.push( 76 | new MinifyPlugin(), 77 | new webpack.DefinePlugin({ 78 | 'process.env.NODE_ENV': '"production"' 79 | }) 80 | ) 81 | } 82 | 83 | module.exports = mainConfig 84 | -------------------------------------------------------------------------------- /src/renderer/store/modules/Setting.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | padding: 1, 3 | NPower2: true, 4 | sameWH: true, 5 | autoSize: true, 6 | textureWidth: 1024, 7 | textureHeight: 1024, 8 | outputPath: 'untitiled.png', 9 | packAlgo: 'Bin-Packing' 10 | } 11 | 12 | const mutations = { 13 | LOAD (state, save) { 14 | save = save.setting 15 | if (save !== undefined) { 16 | if (save.padding !== undefined) state.padding = Number(save.padding) 17 | if (save.NPower2 !== undefined) state.NPower2 = save.NPower2 18 | if (save.sameWH !== undefined) state.sameWH = save.sameWH 19 | if (save.autoSize !== undefined) state.autoSize = save.autoSize 20 | if (save.textureWidth !== undefined) state.textureWidth = save.textureWidth 21 | if (save.textureHeight !== undefined) state.textureHeight = save.textureHeight 22 | if (save.outputPath !== undefined) state.outputPath = save.outputPath 23 | if (save.packAlgo !== undefined) state.packAlgo = save.packAlgo 24 | } 25 | }, 26 | ON_NEW_PROJ (state) { 27 | state.padding = 1 28 | state.NPower2 = true 29 | state.sameWH = true 30 | state.autoSize = true 31 | state.textureWidth = 1024 32 | state.textureHeight = 1024 33 | state.outputPath = 'untitiled.png' 34 | state.packAlgo = 'Bin-Packing' 35 | }, 36 | ENABLE_AUTO_SIZE (state, autoSize) { 37 | state.autoSize = autoSize 38 | }, 39 | SET_TEXTURE_WIDTH (state, width) { 40 | state.textureWidth = Number(width) 41 | }, 42 | SET_TEXTURE_HEIGHT (state, height) { 43 | state.textureHeight = Number(height) 44 | }, 45 | SET_PADDING (state, padding) { 46 | state.padding = Number(padding) 47 | }, 48 | ENABLE_NPOWER2 (state, enabled) { 49 | state.NPower2 = enabled 50 | }, 51 | ENABLE_SAME_WH (state, enabled) { 52 | state.sameWH = enabled 53 | }, 54 | SET_OUTPUT_PATH (state, outputPath) { 55 | state.outputPath = outputPath 56 | }, 57 | SET_PACK_ALGO (state, algo) { 58 | state.packAlgo = algo 59 | } 60 | } 61 | 62 | const actions = { 63 | } 64 | 65 | export default { 66 | state, 67 | mutations, 68 | actions 69 | } 70 | -------------------------------------------------------------------------------- /src/renderer/assets/bin-packing/packer.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | This is a very simple binary tree based bin packing algorithm that is initialized 4 | with a fixed width and height and will fit each block into the first node where 5 | it fits and then split that node into 2 parts (down and right) to track the 6 | remaining whitespace. 7 | 8 | Best results occur when the input blocks are sorted by height, or even better 9 | when sorted by max(width,height). 10 | 11 | Inputs: 12 | ------ 13 | 14 | w: width of target rectangle 15 | h: height of target rectangle 16 | blocks: array of any objects that have .w and .h attributes 17 | 18 | Outputs: 19 | ------- 20 | 21 | marks each block that fits with a .fit attribute pointing to a 22 | node with .x and .y coordinates 23 | 24 | Example: 25 | ------- 26 | 27 | var blocks = [ 28 | { w: 100, h: 100 }, 29 | { w: 100, h: 100 }, 30 | { w: 80, h: 80 }, 31 | { w: 80, h: 80 }, 32 | etc 33 | etc 34 | ]; 35 | 36 | var packer = new Packer(500, 500); 37 | packer.fit(blocks); 38 | 39 | for(var n = 0 ; n < blocks.length ; n++) { 40 | var block = blocks[n]; 41 | if (block.fit) { 42 | Draw(block.fit.x, block.fit.y, block.w, block.h); 43 | } 44 | } 45 | 46 | 47 | ******************************************************************************/ 48 | 49 | Packer = function(w, h) { 50 | this.init(w, h); 51 | }; 52 | 53 | Packer.prototype = { 54 | 55 | init: function(w, h) { 56 | this.root = { x: 0, y: 0, w: w, h: h }; 57 | }, 58 | 59 | fit: function(blocks) { 60 | var n, node, block; 61 | for (n = 0; n < blocks.length; n++) { 62 | block = blocks[n]; 63 | if (node = this.findNode(this.root, block.w, block.h)) 64 | block.fit = this.splitNode(node, block.w, block.h); 65 | } 66 | }, 67 | 68 | findNode: function(root, w, h) { 69 | if (root.used) 70 | return this.findNode(root.right, w, h) || this.findNode(root.down, w, h); 71 | else if ((w <= root.w) && (h <= root.h)) 72 | return root; 73 | else 74 | return null; 75 | }, 76 | 77 | splitNode: function(node, w, h) { 78 | node.used = true; 79 | node.down = { x: node.x, y: node.y + h, w: node.w, h: node.h - h }; 80 | node.right = { x: node.x + w, y: node.y, w: node.w - w, h: h }; 81 | return node; 82 | } 83 | 84 | } 85 | 86 | module.exports = Packer -------------------------------------------------------------------------------- /src/renderer/components/Help.vue: -------------------------------------------------------------------------------- 1 | 63 | 64 | 96 | 97 | 137 | -------------------------------------------------------------------------------- /src/main/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import { app, BrowserWindow, Menu } from 'electron' 4 | const path = require('path') 5 | const ipcMain = require('electron').ipcMain 6 | 7 | /** 8 | * Set `__static` path to static files in production 9 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html 10 | */ 11 | let showDevTools = true 12 | if (process.env.NODE_ENV !== 'development') { 13 | global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\') 14 | showDevTools = false 15 | } 16 | 17 | let mainWindow 18 | const winURL = process.env.NODE_ENV === 'development' 19 | ? 'http://localhost:9080' 20 | : path.join('file://', __dirname, '/index.html') 21 | 22 | if (process.platform === 'darwin') { 23 | const template = [ 24 | { 25 | label: 'Application', 26 | submenu: [ 27 | { label: 'Quit', accelerator: 'Command+Q', click: function () { app.quit() } } 28 | ] 29 | }, 30 | { 31 | label: 'Edit', 32 | submenu: [ 33 | { label: 'Copy', accelerator: 'CmdOrCtrl+C', selector: 'copy:' }, 34 | { label: 'Paste', accelerator: 'CmdOrCtrl+V', selector: 'paste:' } 35 | ] 36 | } 37 | ] 38 | Menu.setApplicationMenu(Menu.buildFromTemplate(template)) 39 | } else { 40 | Menu.setApplicationMenu(null) 41 | } 42 | 43 | function createWindow () { 44 | /** 45 | * Initial window options 46 | */ 47 | mainWindow = new BrowserWindow({ 48 | useContentSize: true, 49 | width: 1440, 50 | height: 800, 51 | minWidth: 600, 52 | minHeight: 400, 53 | acceptFirstMouse: true, 54 | titleBarStyle: 'hidden', 55 | frame: false, 56 | webPreferences: { 57 | nodeIntegration: true, 58 | devTools: showDevTools, 59 | webviewTag: true, 60 | enableRemoteModule: true 61 | } 62 | }) 63 | 64 | mainWindow.loadURL(winURL) 65 | 66 | mainWindow.on('closed', () => { 67 | mainWindow = null 68 | }) 69 | 70 | mainWindow.on('focus', (event) => { 71 | event.sender.send('focus') 72 | }) 73 | } 74 | 75 | app.on('ready', createWindow) 76 | 77 | app.on('window-all-closed', () => { 78 | if (process.platform !== 'darwin') { 79 | app.quit() 80 | } 81 | }) 82 | 83 | app.on('activate', () => { 84 | if (mainWindow === null) { 85 | createWindow() 86 | } 87 | }) 88 | 89 | ipcMain.on('window-min', function () { 90 | mainWindow.minimize() 91 | }) 92 | 93 | // 接收最大化命令 94 | ipcMain.on('window-max', function () { 95 | if (mainWindow.isMaximized()) { 96 | mainWindow.restore() 97 | } else { 98 | mainWindow.maximize() 99 | } 100 | }) 101 | 102 | // 接收关闭命令 103 | ipcMain.on('window-close', function () { 104 | mainWindow.close() 105 | }) 106 | 107 | /** 108 | * Auto Updater 109 | * 110 | * Uncomment the following code below and install `electron-updater` to 111 | * support auto updating. Code Signing with a valid certificate is required. 112 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating 113 | */ 114 | 115 | /* 116 | import { autoUpdater } from 'electron-updater' 117 | 118 | autoUpdater.on('update-downloaded', () => { 119 | autoUpdater.quitAndInstall() 120 | }) 121 | 122 | app.on('ready', () => { 123 | if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates() 124 | }) 125 | */ 126 | -------------------------------------------------------------------------------- /src/renderer/components/BMPList.vue: -------------------------------------------------------------------------------- 1 | 56 | 57 | 115 | 116 | 136 | -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /src/renderer/store/modules/App.js: -------------------------------------------------------------------------------- 1 | import { remote } from 'electron' 2 | import * as fs from 'fs' 3 | import { promisify } from 'util' 4 | 5 | const writeFile = promisify(fs.writeFile) 6 | const readFile = promisify(fs.readFile) 7 | 8 | const state = { 9 | projPathName: null, 10 | modified: false 11 | } 12 | 13 | async function saveProj (rootState, savePath) { 14 | const save = { 15 | setting: rootState.Setting, 16 | bmpList: rootState.BMPList 17 | } 18 | await writeFile(savePath, JSON.stringify(save), { encoding: 'utf8' }) 19 | } 20 | 21 | async function openProj (commit) { 22 | let projPath = remote.dialog.showOpenDialog({ 23 | title: '打开BMFont工程', 24 | properties: [ 25 | 'openFile' 26 | ], 27 | filters: [ 28 | { name: 'BMFont Project File', extensions: ['bfp'] }, 29 | { name: 'All Files', extensions: ['*'] } 30 | ] 31 | }) 32 | if (projPath === undefined) return 33 | 34 | projPath = projPath[0] 35 | 36 | try { 37 | const data = await readFile(projPath, { encoding: 'utf8' }) 38 | const json = JSON.parse(data) 39 | commit('LOAD', json) 40 | commit('ON_PROJ_SAVED', projPath) 41 | } catch (e) { 42 | console.log(e) 43 | } 44 | } 45 | 46 | async function checkProjModified () { 47 | if (state.modified) { 48 | const choice = remote.dialog.showMessageBox({ 49 | type: 'question', 50 | title: 'BMFont.js', 51 | message: '工程已经更改,是否保存当前工程?', 52 | defaultId: 0, 53 | noLink: true, 54 | buttons: ['保存', '不保存', '取消'] 55 | }) 56 | return choice 57 | } else { 58 | return 1 59 | } 60 | } 61 | 62 | function confirmExit () { 63 | const choice = remote.dialog.showMessageBox({ 64 | type: 'question', 65 | title: 'BMFont.js', 66 | message: '确定要退出吗?', 67 | defaultId: 0, 68 | noLink: true, 69 | buttons: ['退出', '取消'] 70 | }) 71 | if (choice === 0) { 72 | remote.getCurrentWindow().close() 73 | } 74 | } 75 | 76 | const mutations = { 77 | ON_NEW_PROJ (state) { 78 | state.projPathName = null 79 | state.modified = false 80 | }, 81 | 82 | ON_PROJ_MODIFIED (state) { 83 | if (state.projPathName === null) { 84 | state.projPathName = '未命名' 85 | } 86 | state.modified = true 87 | }, 88 | 89 | ON_PROJ_SAVED (state, projPathName) { 90 | state.projPathName = projPathName 91 | state.modified = false 92 | } 93 | } 94 | 95 | const actions = { 96 | async NEW_PROJ ({ commit, dispatch }) { 97 | const choice = await checkProjModified() 98 | if (choice === 0) { 99 | await dispatch('SAVE_PROJ') 100 | commit('ON_NEW_PROJ') 101 | } else if (choice === 1) { 102 | commit('ON_NEW_PROJ') 103 | } 104 | }, 105 | 106 | async OPEN_PROJ ({ commit, dispatch }) { 107 | const choice = await checkProjModified() 108 | if (choice === 0) { 109 | await dispatch('SAVE_PROJ') 110 | openProj(commit) 111 | } else if (choice === 1) { 112 | openProj(commit) 113 | } 114 | }, 115 | 116 | async SAVE_PROJ ({ state, commit, rootState }) { 117 | if (state.projPathName === null) return 118 | const savePath = remote.dialog.showSaveDialog({ 119 | title: '保存BMFont工程', 120 | filters: [ 121 | { name: 'BMFont Project File', extensions: ['bfp'] }, 122 | { name: 'All Files', extensions: ['*'] } 123 | ] 124 | }) 125 | if (savePath === undefined) return 126 | await saveProj(rootState, savePath) 127 | commit('ON_PROJ_SAVED', savePath) 128 | }, 129 | 130 | async CONFIRM_EXIT ({ dispatch }) { 131 | const choice = await checkProjModified() 132 | if (choice === 0) { 133 | await dispatch('SAVE_PROJ') 134 | confirmExit() 135 | } else if (choice === 1) { 136 | confirmExit() 137 | } 138 | } 139 | } 140 | 141 | export default { 142 | state, 143 | mutations, 144 | actions 145 | } 146 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "comments": false, 3 | "env": { 4 | "main": { 5 | "presets": [ 6 | [ 7 | "@babel/preset-env", 8 | { 9 | "targets": { 10 | "node": 7 11 | } 12 | } 13 | ] 14 | ], 15 | "plugins": [ 16 | "@babel/plugin-syntax-dynamic-import", 17 | "@babel/plugin-syntax-import-meta", 18 | "@babel/plugin-proposal-class-properties", 19 | "@babel/plugin-proposal-json-strings", 20 | [ 21 | "@babel/plugin-proposal-decorators", 22 | { 23 | "legacy": true 24 | } 25 | ], 26 | "@babel/plugin-proposal-function-sent", 27 | "@babel/plugin-proposal-export-namespace-from", 28 | "@babel/plugin-proposal-numeric-separator", 29 | "@babel/plugin-proposal-throw-expressions", 30 | "@babel/plugin-proposal-export-default-from", 31 | "@babel/plugin-proposal-logical-assignment-operators", 32 | "@babel/plugin-proposal-optional-chaining", 33 | [ 34 | "@babel/plugin-proposal-pipeline-operator", 35 | { 36 | "proposal": "minimal" 37 | } 38 | ], 39 | "@babel/plugin-proposal-nullish-coalescing-operator", 40 | "@babel/plugin-proposal-do-expressions", 41 | "@babel/plugin-proposal-function-bind" 42 | ] 43 | }, 44 | "renderer": { 45 | "presets": [ 46 | [ 47 | "@babel/preset-env", 48 | { 49 | "modules": false 50 | } 51 | ] 52 | ], 53 | "plugins": [ 54 | "@babel/plugin-syntax-dynamic-import", 55 | "@babel/plugin-syntax-import-meta", 56 | "@babel/plugin-proposal-class-properties", 57 | "@babel/plugin-proposal-json-strings", 58 | [ 59 | "@babel/plugin-proposal-decorators", 60 | { 61 | "legacy": true 62 | } 63 | ], 64 | "@babel/plugin-proposal-function-sent", 65 | "@babel/plugin-proposal-export-namespace-from", 66 | "@babel/plugin-proposal-numeric-separator", 67 | "@babel/plugin-proposal-throw-expressions", 68 | "@babel/plugin-proposal-export-default-from", 69 | "@babel/plugin-proposal-logical-assignment-operators", 70 | "@babel/plugin-proposal-optional-chaining", 71 | [ 72 | "@babel/plugin-proposal-pipeline-operator", 73 | { 74 | "proposal": "minimal" 75 | } 76 | ], 77 | "@babel/plugin-proposal-nullish-coalescing-operator", 78 | "@babel/plugin-proposal-do-expressions", 79 | "@babel/plugin-proposal-function-bind" 80 | ] 81 | }, 82 | "web": { 83 | "presets": [ 84 | [ 85 | "@babel/preset-env", 86 | { 87 | "modules": false 88 | } 89 | ] 90 | ], 91 | "plugins": [ 92 | "@babel/plugin-syntax-dynamic-import", 93 | "@babel/plugin-syntax-import-meta", 94 | "@babel/plugin-proposal-class-properties", 95 | "@babel/plugin-proposal-json-strings", 96 | [ 97 | "@babel/plugin-proposal-decorators", 98 | { 99 | "legacy": true 100 | } 101 | ], 102 | "@babel/plugin-proposal-function-sent", 103 | "@babel/plugin-proposal-export-namespace-from", 104 | "@babel/plugin-proposal-numeric-separator", 105 | "@babel/plugin-proposal-throw-expressions", 106 | "@babel/plugin-proposal-export-default-from", 107 | "@babel/plugin-proposal-logical-assignment-operators", 108 | "@babel/plugin-proposal-optional-chaining", 109 | [ 110 | "@babel/plugin-proposal-pipeline-operator", 111 | { 112 | "proposal": "minimal" 113 | } 114 | ], 115 | "@babel/plugin-proposal-nullish-coalescing-operator", 116 | "@babel/plugin-proposal-do-expressions", 117 | "@babel/plugin-proposal-function-bind" 118 | ] 119 | } 120 | }, 121 | "plugins": [ 122 | [ 123 | "@babel/plugin-transform-runtime", 124 | { 125 | "corejs": 2 126 | } 127 | ] 128 | ] 129 | } 130 | -------------------------------------------------------------------------------- /src/renderer/App.vue: -------------------------------------------------------------------------------- 1 | 77 | 78 | 156 | 157 | 168 | -------------------------------------------------------------------------------- /src/renderer/store/modules/BMPList.js: -------------------------------------------------------------------------------- 1 | import { remote } from 'electron' 2 | import GrowingPacker from '@/assets/bin-packing/packer.growing.js' 3 | import Packer from '@/assets/bin-packing/packer.js' 4 | import * as path from 'path' 5 | import * as xmlbuilder from 'xmlbuilder' 6 | import * as fs from 'fs' 7 | import { promisify } from 'util' 8 | import Jimp from 'jimp/es' 9 | 10 | const writeFile = promisify(fs.writeFile) 11 | 12 | const state = { 13 | bmpList: [] 14 | } 15 | 16 | function calculateSize (w, h, setting) { 17 | if (setting.NPower2) { 18 | [w, h] = expandSize(w, h) 19 | } 20 | if (setting.sameWH) { 21 | const s = Math.max(w, h) 22 | w = s 23 | h = s 24 | } 25 | return [w, h] 26 | } 27 | 28 | function packingImages (imgList, setting) { 29 | let packer 30 | let w, h 31 | if (setting.autoSize) { 32 | packer = new GrowingPacker() 33 | } else { 34 | [w, h] = calculateSize(setting.textureWidth, setting.textureHeight, setting) 35 | packer = new Packer(w, h) 36 | } 37 | const blocks = [] 38 | for (const img of imgList) { 39 | blocks.push({ w: img.bitmap.width + setting.padding, h: img.bitmap.height + setting.padding }) 40 | } 41 | packer.fit(blocks) 42 | if (setting.autoSize) { 43 | [w, h] = calculateSize(packer.root.w, packer.root.h, setting) 44 | } 45 | return [blocks, w, h] 46 | } 47 | 48 | function expandSize (w, h) { 49 | w = 2 ** Math.ceil(Math.log(w) / Math.log(2)) 50 | h = 2 ** Math.ceil(Math.log(h) / Math.log(2)) 51 | return [w, h] 52 | } 53 | 54 | function validateBlocks (blocks) { 55 | for (const b of blocks) { 56 | if (!b.fit || !b.fit.used) { 57 | return false 58 | } 59 | } 60 | return true 61 | } 62 | 63 | async function loadAllImages (bmpList) { 64 | const imgList = [] 65 | for (const bmp of bmpList) { 66 | const img = await Jimp.read(bmp.filePath) 67 | imgList.push(img) 68 | } 69 | return imgList 70 | } 71 | 72 | async function saveFNT (blocks, bmpList, imgList, fntPath) { 73 | const doc = xmlbuilder.create('font') 74 | const elem = doc.ele('chars', { count: blocks.length }) 75 | for (const idx in blocks) { 76 | const block = blocks[idx].fit 77 | const char = bmpList[idx].char 78 | const bmp = imgList[idx].bitmap 79 | elem.ele('char', { id: char.charCodeAt(0), x: block.x, y: block.y, width: bmp.width, height: bmp.height, xadvance: bmp.width }) 80 | } 81 | const xml = elem.end({ pretty: true }) 82 | await writeFile(fntPath, xml, { encoding: 'utf8' }) 83 | } 84 | 85 | const mutations = { 86 | LOAD (state, save) { 87 | save = save.bmpList 88 | if (save !== undefined) { 89 | if (save.bmpList !== undefined) { 90 | for (const bmp of save.bmpList) { 91 | if (bmp.filePath !== undefined && bmp.char !== undefined) { 92 | state.bmpList.push({ filePath: bmp.filePath, char: bmp.char }) 93 | } 94 | } 95 | } 96 | } 97 | }, 98 | 99 | ON_NEW_PROJ (state) { 100 | state.bmpList = [] 101 | }, 102 | 103 | APPEND_BMP (state, { filePath, char }) { 104 | state.bmpList.push({ filePath: filePath, char: char }) 105 | }, 106 | 107 | REMOVE_BMP (state, index) { 108 | if (index < 0 || index >= state.bmpList.length) return 109 | state.bmpList.splice(index, 1) 110 | }, 111 | 112 | CHANGE_CHAR (state, { index, char }) { 113 | if (index < 0 || index >= state.bmpList.length) return 114 | state.bmpList[index].char = char 115 | }, 116 | 117 | ORDER_BY_PATH (state) { 118 | state.bmpList.sort((a, b) => { 119 | if (a.filePath < b.filePath) return -1 120 | else if (a.filePath > b.filePath) return 1 121 | return 0 122 | }) 123 | } 124 | } 125 | 126 | const actions = { 127 | async PUBLISH ({ state, rootState }) { 128 | if (state.bmpList.length === 0) return 129 | 130 | const setting = rootState.Setting 131 | try { 132 | const imgList = await loadAllImages(state.bmpList) 133 | const [blocks, w, h] = packingImages(imgList, setting) 134 | if (!validateBlocks(blocks)) { 135 | remote.dialog.showErrorBox('', '贴图太小了,不能容纳所有的字符') 136 | return 137 | } 138 | 139 | const resultImg = await new Jimp(w, h) 140 | for (const idx in blocks) { 141 | const block = blocks[idx] 142 | const img = imgList[idx] 143 | resultImg.composite(img, block.fit.x, block.fit.y) 144 | } 145 | await resultImg.write(setting.outputPath) 146 | const ext = path.extname(setting.outputPath) 147 | const fntPath = setting.outputPath.substring(0, setting.outputPath.length - ext.length) + '.xml' 148 | saveFNT(blocks, state.bmpList, imgList, fntPath) 149 | } catch (e) { 150 | console.dir(e) 151 | remote.dialog.showErrorBox('', '请检查字符图片文件是否正确\n' + e.message) 152 | } 153 | } 154 | } 155 | 156 | export default { 157 | state, 158 | mutations, 159 | actions 160 | } 161 | -------------------------------------------------------------------------------- /.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 | options: { 77 | limit: 10000, 78 | name: 'imgs/[name].[ext]', 79 | esModule: false, 80 | } 81 | } 82 | }, 83 | { 84 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 85 | loader: 'url-loader', 86 | options: { 87 | limit: 10000, 88 | name: 'media/[name]--[folder].[ext]', 89 | esModule: false, 90 | } 91 | }, 92 | { 93 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 94 | use: { 95 | loader: 'url-loader', 96 | options: { 97 | limit: 10000, 98 | name: 'fonts/[name].[ext]', 99 | esModule: false, 100 | } 101 | } 102 | } 103 | ] 104 | }, 105 | plugins: [ 106 | new VueLoaderPlugin(), 107 | new MiniCssExtractPlugin({filename: 'styles.css'}), 108 | new HtmlWebpackPlugin({ 109 | filename: 'index.html', 110 | template: path.resolve(__dirname, '../src/index.ejs'), 111 | minify: { 112 | collapseWhitespace: true, 113 | removeAttributeQuotes: true, 114 | removeComments: true 115 | }, 116 | nodeModules: false 117 | }), 118 | new webpack.DefinePlugin({ 119 | 'process.env.IS_WEB': 'true' 120 | }), 121 | new webpack.HotModuleReplacementPlugin(), 122 | new webpack.NoEmitOnErrorsPlugin() 123 | ], 124 | output: { 125 | filename: '[name].js', 126 | path: path.join(__dirname, '../dist/web') 127 | }, 128 | resolve: { 129 | alias: { 130 | '@': path.join(__dirname, '../src/renderer'), 131 | 'vue$': 'vue/dist/vue.esm.js' 132 | }, 133 | extensions: ['.js', '.vue', '.json', '.css'] 134 | }, 135 | target: 'web' 136 | } 137 | 138 | /** 139 | * Adjust webConfig for production settings 140 | */ 141 | if (process.env.NODE_ENV === 'production') { 142 | webConfig.devtool = '' 143 | 144 | webConfig.plugins.push( 145 | new MinifyPlugin(), 146 | new CopyWebpackPlugin( 147 | { 148 | patterns: [ 149 | { 150 | from: path.join(__dirname, '../static'), 151 | to: path.join(__dirname, '../dist/web/static'), 152 | globOptions: { 153 | dot: true, 154 | gitignore: true, 155 | ignore: [".*"], 156 | }, 157 | } 158 | ] 159 | } 160 | ), 161 | new webpack.DefinePlugin({ 162 | 'process.env.NODE_ENV': '"production"' 163 | }), 164 | new webpack.LoaderOptionsPlugin({ 165 | minimize: true 166 | }) 167 | ) 168 | } 169 | 170 | module.exports = webConfig 171 | -------------------------------------------------------------------------------- /src/renderer/assets/bin-packing/packer.growing.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | This is a binary tree based bin packing algorithm that is more complex than 4 | the simple Packer (packer.js). Instead of starting off with a fixed width and 5 | height, it starts with the width and height of the first block passed and then 6 | grows as necessary to accomodate each subsequent block. As it grows it attempts 7 | to maintain a roughly square ratio by making 'smart' choices about whether to 8 | grow right or down. 9 | 10 | When growing, the algorithm can only grow to the right OR down. Therefore, if 11 | the new block is BOTH wider and taller than the current target then it will be 12 | rejected. This makes it very important to initialize with a sensible starting 13 | width and height. If you are providing sorted input (largest first) then this 14 | will not be an issue. 15 | 16 | A potential way to solve this limitation would be to allow growth in BOTH 17 | directions at once, but this requires maintaining a more complex tree 18 | with 3 children (down, right and center) and that complexity can be avoided 19 | by simply chosing a sensible starting block. 20 | 21 | Best results occur when the input blocks are sorted by height, or even better 22 | when sorted by max(width,height). 23 | 24 | Inputs: 25 | ------ 26 | 27 | blocks: array of any objects that have .w and .h attributes 28 | 29 | Outputs: 30 | ------- 31 | 32 | marks each block that fits with a .fit attribute pointing to a 33 | node with .x and .y coordinates 34 | 35 | Example: 36 | ------- 37 | 38 | var blocks = [ 39 | { w: 100, h: 100 }, 40 | { w: 100, h: 100 }, 41 | { w: 80, h: 80 }, 42 | { w: 80, h: 80 }, 43 | etc 44 | etc 45 | ]; 46 | 47 | var packer = new GrowingPacker(); 48 | packer.fit(blocks); 49 | 50 | for(var n = 0 ; n < blocks.length ; n++) { 51 | var block = blocks[n]; 52 | if (block.fit) { 53 | Draw(block.fit.x, block.fit.y, block.w, block.h); 54 | } 55 | } 56 | 57 | 58 | ******************************************************************************/ 59 | 60 | GrowingPacker = function() { }; 61 | 62 | GrowingPacker.prototype = { 63 | 64 | fit: function(blocks) { 65 | var n, node, block, len = blocks.length; 66 | var w = len > 0 ? blocks[0].w : 0; 67 | var h = len > 0 ? blocks[0].h : 0; 68 | this.root = { x: 0, y: 0, w: w, h: h }; 69 | for (n = 0; n < len ; n++) { 70 | block = blocks[n]; 71 | if (node = this.findNode(this.root, block.w, block.h)) 72 | block.fit = this.splitNode(node, block.w, block.h); 73 | else 74 | block.fit = this.growNode(block.w, block.h); 75 | } 76 | }, 77 | 78 | findNode: function(root, w, h) { 79 | if (root.used) 80 | return this.findNode(root.right, w, h) || this.findNode(root.down, w, h); 81 | else if ((w <= root.w) && (h <= root.h)) 82 | return root; 83 | else 84 | return null; 85 | }, 86 | 87 | splitNode: function(node, w, h) { 88 | node.used = true; 89 | node.down = { x: node.x, y: node.y + h, w: node.w, h: node.h - h }; 90 | node.right = { x: node.x + w, y: node.y, w: node.w - w, h: h }; 91 | return node; 92 | }, 93 | 94 | growNode: function(w, h) { 95 | var canGrowDown = (w <= this.root.w); 96 | var canGrowRight = (h <= this.root.h); 97 | 98 | var shouldGrowRight = canGrowRight && (this.root.h >= (this.root.w + w)); // attempt to keep square-ish by growing right when height is much greater than width 99 | var shouldGrowDown = canGrowDown && (this.root.w >= (this.root.h + h)); // attempt to keep square-ish by growing down when width is much greater than height 100 | 101 | if (shouldGrowRight) 102 | return this.growRight(w, h); 103 | else if (shouldGrowDown) 104 | return this.growDown(w, h); 105 | else if (canGrowRight) 106 | return this.growRight(w, h); 107 | else if (canGrowDown) 108 | return this.growDown(w, h); 109 | else 110 | return null; // need to ensure sensible root starting size to avoid this happening 111 | }, 112 | 113 | growRight: function(w, h) { 114 | this.root = { 115 | used: true, 116 | x: 0, 117 | y: 0, 118 | w: this.root.w + w, 119 | h: this.root.h, 120 | down: this.root, 121 | right: { x: this.root.w, y: 0, w: w, h: this.root.h } 122 | }; 123 | if (node = this.findNode(this.root, w, h)) 124 | return this.splitNode(node, w, h); 125 | else 126 | return null; 127 | }, 128 | 129 | growDown: function(w, h) { 130 | this.root = { 131 | used: true, 132 | x: 0, 133 | y: 0, 134 | w: this.root.w, 135 | h: this.root.h + h, 136 | down: { x: 0, y: this.root.h, w: this.root.w, h: h }, 137 | right: this.root 138 | }; 139 | if (node = this.findNode(this.root, w, h)) 140 | return this.splitNode(node, w, h); 141 | else 142 | return null; 143 | } 144 | 145 | } 146 | 147 | module.exports = GrowingPacker -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bmfont-js", 3 | "version": "1.0.1", 4 | "author": "zeb ", 5 | "description": "bitmap font generator", 6 | "license": "see LICENSE file", 7 | "main": "./dist/electron/main.js", 8 | "scripts": { 9 | "build": "node .electron-vue/build.js && electron-builder", 10 | "build:dir": "node .electron-vue/build.js && electron-builder --dir", 11 | "build:clean": "cross-env BUILD_TARGET=clean node .electron-vue/build.js", 12 | "build:web": "cross-env BUILD_TARGET=web node .electron-vue/build.js", 13 | "dev": "node .electron-vue/dev-runner.js", 14 | "lint": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter src", 15 | "lint:fix": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter --fix src", 16 | "pack": "npm run pack:main && npm run pack:renderer", 17 | "pack:main": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.main.config.js", 18 | "pack:renderer": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.renderer.config.js", 19 | "test": "npm run standard", 20 | "postinstall": "npm run lint:fix", 21 | "standard": "standard --plugin html \"**/*.{js,vue}\"", 22 | "standard:fix": "standard --plugin html \"**/*.{js,vue}\" --fix" 23 | }, 24 | "build": { 25 | "productName": "bmfont-js", 26 | "appId": "com.zebplay.bmfont", 27 | "directories": { 28 | "output": "build" 29 | }, 30 | "files": [ 31 | "dist/electron/**/*" 32 | ], 33 | "dmg": { 34 | "contents": [ 35 | { 36 | "x": 410, 37 | "y": 150, 38 | "type": "link", 39 | "path": "/Applications" 40 | }, 41 | { 42 | "x": 130, 43 | "y": 150, 44 | "type": "file" 45 | } 46 | ] 47 | }, 48 | "mac": { 49 | "icon": "build/icons/icon.icns" 50 | }, 51 | "win": { 52 | "icon": "build/icons/icon.ico" 53 | }, 54 | "linux": { 55 | "icon": "build/icons" 56 | } 57 | }, 58 | "standard": { 59 | "ignore": [ 60 | "src/renderer/assets/**" 61 | ] 62 | }, 63 | "dependencies": { 64 | "jimp": "^0.11.0", 65 | "tar": "^4.4.18", 66 | "vue": "^2.6.14", 67 | "vue-electron": "^1.0.6", 68 | "vue-router": "^3.5.3", 69 | "vuex": "^3.6.2", 70 | "vuex-electron": "^1.0.0", 71 | "xmlbuilder": "^10.0.0" 72 | }, 73 | "devDependencies": { 74 | "@babel/core": "^7.12.16", 75 | "@babel/plugin-proposal-class-properties": "^7.12.13", 76 | "@babel/plugin-proposal-decorators": "^7.12.13", 77 | "@babel/plugin-proposal-do-expressions": "^7.12.13", 78 | "@babel/plugin-proposal-export-default-from": "^7.12.13", 79 | "@babel/plugin-proposal-export-namespace-from": "^7.12.13", 80 | "@babel/plugin-proposal-function-bind": "^7.12.13", 81 | "@babel/plugin-proposal-function-sent": "^7.12.13", 82 | "@babel/plugin-proposal-json-strings": "^7.12.13", 83 | "@babel/plugin-proposal-logical-assignment-operators": "^7.12.13", 84 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.13", 85 | "@babel/plugin-proposal-numeric-separator": "^7.12.13", 86 | "@babel/plugin-proposal-optional-chaining": "^7.12.16", 87 | "@babel/plugin-proposal-pipeline-operator": "^7.12.13", 88 | "@babel/plugin-proposal-throw-expressions": "^7.12.13", 89 | "@babel/plugin-syntax-dynamic-import": "^7.8.3", 90 | "@babel/plugin-syntax-import-meta": "^7.10.4", 91 | "@babel/plugin-transform-runtime": "^7.12.15", 92 | "@babel/preset-env": "^7.12.16", 93 | "@babel/register": "^7.12.13", 94 | "@babel/runtime-corejs2": "^7.12.13", 95 | "ajv": "^7.1.0", 96 | "babel-eslint": "^10.1.0", 97 | "babel-loader": "^8.2.3", 98 | "babel-minify-webpack-plugin": "^0.3.1", 99 | "cfonts": "^2.9.1", 100 | "chalk": "^4.1.2", 101 | "copy-webpack-plugin": "^6.4.1", 102 | "cross-env": "^7.0.3", 103 | "css-loader": "^3.6.0", 104 | "del": "^6.0.0", 105 | "devtron": "^1.4.0", 106 | "electron": "^11.5.0", 107 | "electron-builder": "^22.9.1", 108 | "electron-debug": "^3.2.0", 109 | "electron-devtools-installer": "^3.1.1", 110 | "eslint": "^7.20.0", 111 | "eslint-config-standard": "^16.0.3", 112 | "eslint-friendly-formatter": "^4.0.1", 113 | "eslint-loader": "^4.0.2", 114 | "eslint-plugin-html": "^6.1.1", 115 | "eslint-plugin-import": "^2.22.1", 116 | "eslint-plugin-node": "^11.0.0", 117 | "eslint-plugin-promise": "^4.3.1", 118 | "eslint-plugin-standard": "^5.0.0", 119 | "eslint-plugin-vue": "^7.5.0", 120 | "file-loader": "^6.2.0", 121 | "html-webpack-plugin": "^3.2.0", 122 | "mini-css-extract-plugin": "^1.3.6", 123 | "multispinner": "^0.2.1", 124 | "node-loader": "^1.0.2", 125 | "node-sass": "^5.0.0", 126 | "sass-loader": "^10.1.1", 127 | "style-loader": "^2.0.0", 128 | "url-loader": "^4.1.1", 129 | "vue-html-loader": "^1.2.4", 130 | "vue-loader": "^15.9.8", 131 | "vue-style-loader": "^4.1.3", 132 | "vue-template-compiler": "^2.6.14", 133 | "webpack": "^4.46.0", 134 | "webpack-cli": "^4.5.0", 135 | "webpack-dev-server": "^3.11.2", 136 | "webpack-hot-middleware": "^2.25.1", 137 | "webpack-merge": "^5.7.3" 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /.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() -------------------------------------------------------------------------------- /src/renderer/components/Setting.vue: -------------------------------------------------------------------------------- 1 | 76 | 77 | 166 | 167 | 209 | -------------------------------------------------------------------------------- /.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 | options: { 93 | esModule: false, 94 | limit: 10000, 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 | esModule: false, 106 | } 107 | }, 108 | { 109 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 110 | use: { 111 | loader: 'url-loader', 112 | options: { 113 | limit: 10000, 114 | name: 'fonts/[name]--[folder].[ext]', 115 | esModule: false, 116 | } 117 | } 118 | } 119 | ] 120 | }, 121 | node: { 122 | __dirname: process.env.NODE_ENV !== 'production', 123 | __filename: process.env.NODE_ENV !== 'production' 124 | }, 125 | plugins: [ 126 | new VueLoaderPlugin(), 127 | new MiniCssExtractPlugin({filename: 'styles.css'}), 128 | new HtmlWebpackPlugin({ 129 | filename: 'index.html', 130 | template: path.resolve(__dirname, '../src/index.ejs'), 131 | minify: { 132 | collapseWhitespace: true, 133 | removeAttributeQuotes: true, 134 | removeComments: true 135 | }, 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 | patterns: [ 180 | { 181 | from: path.join(__dirname, '../static'), 182 | to: path.join(__dirname, '../dist/electron/static'), 183 | globOptions: { 184 | dot: true, 185 | gitignore: true, 186 | ignore: [".*"], 187 | }, 188 | }, 189 | ] 190 | } 191 | ), 192 | new webpack.DefinePlugin({ 193 | 'process.env.NODE_ENV': '"production"' 194 | }), 195 | new webpack.LoaderOptionsPlugin({ 196 | minimize: true 197 | }) 198 | ) 199 | } 200 | 201 | module.exports = rendererConfig 202 | -------------------------------------------------------------------------------- /src/renderer/assets/photon/css/photon.min.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";/*! 2 | * ===================================================== 3 | * Photon v0.1.2 4 | * Copyright 2015 Connor Sears 5 | * Licensed under MIT (https://github.com/connors/proton/blob/master/LICENSE) 6 | * 7 | * v0.1.2 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;color:#333;background-color:transparent}.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}label{margin-bottom:5px}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/css/photon.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * ===================================================== 3 | * Photon v0.1.2 4 | * Copyright 2015 Connor Sears 5 | * Licensed under MIT (https://github.com/connors/proton/blob/master/LICENSE) 6 | * 7 | * v0.1.2 designed by @connors. 8 | * ===================================================== 9 | */ 10 | 11 | @charset "UTF-8"; 12 | audio, 13 | canvas, 14 | progress, 15 | video { 16 | vertical-align: baseline; 17 | } 18 | 19 | audio:not([controls]) { 20 | display: none; 21 | } 22 | 23 | a:active, 24 | a:hover { 25 | outline: 0; 26 | } 27 | 28 | abbr[title] { 29 | border-bottom: 1px dotted; 30 | } 31 | 32 | b, 33 | strong { 34 | font-weight: bold; 35 | } 36 | 37 | dfn { 38 | font-style: italic; 39 | } 40 | 41 | h1 { 42 | font-size: 2em; 43 | margin: 0.67em 0; 44 | } 45 | 46 | small { 47 | font-size: 80%; 48 | } 49 | 50 | sub, 51 | sup { 52 | font-size: 75%; 53 | line-height: 0; 54 | position: relative; 55 | vertical-align: baseline; 56 | } 57 | 58 | sup { 59 | top: -0.5em; 60 | } 61 | 62 | sub { 63 | bottom: -0.25em; 64 | } 65 | 66 | pre { 67 | overflow: auto; 68 | } 69 | 70 | code, 71 | kbd, 72 | pre, 73 | samp { 74 | font-family: monospace, monospace; 75 | font-size: 1em; 76 | } 77 | 78 | button, 79 | input, 80 | optgroup, 81 | select, 82 | textarea { 83 | color: inherit; 84 | font: inherit; 85 | margin: 0; 86 | } 87 | 88 | input[type="number"]::-webkit-inner-spin-button, 89 | input[type="number"]::-webkit-outer-spin-button { 90 | height: auto; 91 | } 92 | 93 | input[type="search"] { 94 | -webkit-appearance: textfield; 95 | box-sizing: content-box; 96 | } 97 | 98 | input[type="search"]::-webkit-search-cancel-button, 99 | input[type="search"]::-webkit-search-decoration { 100 | -webkit-appearance: none; 101 | } 102 | 103 | fieldset { 104 | border: 1px solid #c0c0c0; 105 | margin: 0 2px; 106 | padding: 0.35em 0.625em 0.75em; 107 | } 108 | 109 | legend { 110 | border: 0; 111 | padding: 0; 112 | } 113 | 114 | table { 115 | border-collapse: collapse; 116 | border-spacing: 0; 117 | } 118 | 119 | td, 120 | th { 121 | padding: 0; 122 | } 123 | 124 | * { 125 | cursor: default; 126 | -webkit-user-drag: text; 127 | -webkit-user-select: none; 128 | -webkit-box-sizing: border-box; 129 | box-sizing: border-box; 130 | } 131 | 132 | html { 133 | height: 100%; 134 | width: 100%; 135 | overflow: hidden; 136 | } 137 | 138 | body { 139 | height: 100%; 140 | padding: 0; 141 | margin: 0; 142 | font-family: system, -apple-system, ".SFNSDisplay-Regular", "Helvetica Neue", Helvetica, "Segoe UI", sans-serif; 143 | font-size: 13px; 144 | line-height: 1.6; 145 | color: #333; 146 | background-color: transparent; 147 | } 148 | 149 | hr { 150 | margin: 15px 0; 151 | overflow: hidden; 152 | background: transparent; 153 | border: 0; 154 | border-bottom: 1px solid #ddd; 155 | } 156 | 157 | h1, h2, h3, h4, h5, h6 { 158 | margin-top: 20px; 159 | margin-bottom: 10px; 160 | font-weight: 500; 161 | white-space: nowrap; 162 | overflow: hidden; 163 | text-overflow: ellipsis; 164 | } 165 | 166 | h1 { 167 | font-size: 36px; 168 | } 169 | 170 | h2 { 171 | font-size: 30px; 172 | } 173 | 174 | h3 { 175 | font-size: 24px; 176 | } 177 | 178 | h4 { 179 | font-size: 18px; 180 | } 181 | 182 | h5 { 183 | font-size: 14px; 184 | } 185 | 186 | h6 { 187 | font-size: 12px; 188 | } 189 | 190 | .window { 191 | position: absolute; 192 | top: 0; 193 | right: 0; 194 | bottom: 0; 195 | left: 0; 196 | display: flex; 197 | flex-direction: column; 198 | background-color: #fff; 199 | } 200 | 201 | .window-content { 202 | position: relative; 203 | overflow-y: auto; 204 | display: flex; 205 | flex: 1; 206 | } 207 | 208 | .selectable-text { 209 | cursor: text; 210 | -webkit-user-select: text; 211 | } 212 | 213 | .text-center { 214 | text-align: center; 215 | } 216 | 217 | .text-right { 218 | text-align: right; 219 | } 220 | 221 | .text-left { 222 | text-align: left; 223 | } 224 | 225 | .pull-left { 226 | float: left; 227 | } 228 | 229 | .pull-right { 230 | float: right; 231 | } 232 | 233 | .padded { 234 | padding: 10px; 235 | } 236 | 237 | .padded-less { 238 | padding: 5px; 239 | } 240 | 241 | .padded-more { 242 | padding: 20px; 243 | } 244 | 245 | .padded-vertically { 246 | padding-top: 10px; 247 | padding-bottom: 10px; 248 | } 249 | 250 | .padded-vertically-less { 251 | padding-top: 5px; 252 | padding-bottom: 5px; 253 | } 254 | 255 | .padded-vertically-more { 256 | padding-top: 20px; 257 | padding-bottom: 20px; 258 | } 259 | 260 | .padded-horizontally { 261 | padding-right: 10px; 262 | padding-left: 10px; 263 | } 264 | 265 | .padded-horizontally-less { 266 | padding-right: 5px; 267 | padding-left: 5px; 268 | } 269 | 270 | .padded-horizontally-more { 271 | padding-right: 20px; 272 | padding-left: 20px; 273 | } 274 | 275 | .padded-top { 276 | padding-top: 10px; 277 | } 278 | 279 | .padded-top-less { 280 | padding-top: 5px; 281 | } 282 | 283 | .padded-top-more { 284 | padding-top: 20px; 285 | } 286 | 287 | .padded-bottom { 288 | padding-bottom: 10px; 289 | } 290 | 291 | .padded-bottom-less { 292 | padding-bottom: 5px; 293 | } 294 | 295 | .padded-bottom-more { 296 | padding-bottom: 20px; 297 | } 298 | 299 | .sidebar { 300 | background-color: #f5f5f4; 301 | } 302 | 303 | .draggable { 304 | -webkit-app-region: drag; 305 | } 306 | 307 | .clearfix:before, .clearfix:after { 308 | display: table; 309 | content: " "; 310 | } 311 | .clearfix:after { 312 | clear: both; 313 | } 314 | 315 | .btn { 316 | display: inline-block; 317 | padding: 3px 8px; 318 | margin-bottom: 0; 319 | font-size: 12px; 320 | line-height: 1.4; 321 | text-align: center; 322 | white-space: nowrap; 323 | vertical-align: middle; 324 | cursor: default; 325 | background-image: none; 326 | border: 1px solid transparent; 327 | border-radius: 4px; 328 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.06); 329 | -webkit-app-region: no-drag; 330 | } 331 | .btn:focus { 332 | outline: none; 333 | box-shadow: none; 334 | } 335 | 336 | .btn-mini { 337 | padding: 2px 6px; 338 | } 339 | 340 | .btn-large { 341 | padding: 6px 12px; 342 | } 343 | 344 | .btn-form { 345 | padding-right: 20px; 346 | padding-left: 20px; 347 | } 348 | 349 | .btn-default { 350 | color: #333; 351 | border-top-color: #c2c0c2; 352 | border-right-color: #c2c0c2; 353 | border-bottom-color: #a19fa1; 354 | border-left-color: #c2c0c2; 355 | background-color: #fcfcfc; 356 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fcfcfc), color-stop(100%, #f1f1f1)); 357 | background-image: -webkit-linear-gradient(top, #fcfcfc 0%, #f1f1f1 100%); 358 | background-image: linear-gradient(to bottom, #fcfcfc 0%, #f1f1f1 100%); 359 | } 360 | .btn-default:active { 361 | background-color: #ddd; 362 | background-image: none; 363 | } 364 | 365 | .btn-primary, 366 | .btn-positive, 367 | .btn-negative, 368 | .btn-warning { 369 | color: #fff; 370 | text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); 371 | } 372 | 373 | .btn-primary { 374 | border-color: #388df8; 375 | border-bottom-color: #0866dc; 376 | background-color: #6eb4f7; 377 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #6eb4f7), color-stop(100%, #1a82fb)); 378 | background-image: -webkit-linear-gradient(top, #6eb4f7 0%, #1a82fb 100%); 379 | background-image: linear-gradient(to bottom, #6eb4f7 0%, #1a82fb 100%); 380 | } 381 | .btn-primary:active { 382 | background-color: #3e9bf4; 383 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #3e9bf4), color-stop(100%, #0469de)); 384 | background-image: -webkit-linear-gradient(top, #3e9bf4 0%, #0469de 100%); 385 | background-image: linear-gradient(to bottom, #3e9bf4 0%, #0469de 100%); 386 | } 387 | 388 | .btn-positive { 389 | border-color: #29a03b; 390 | border-bottom-color: #248b34; 391 | background-color: #5bd46d; 392 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bd46d), color-stop(100%, #29a03b)); 393 | background-image: -webkit-linear-gradient(top, #5bd46d 0%, #29a03b 100%); 394 | background-image: linear-gradient(to bottom, #5bd46d 0%, #29a03b 100%); 395 | } 396 | .btn-positive:active { 397 | background-color: #34c84a; 398 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #34c84a), color-stop(100%, #248b34)); 399 | background-image: -webkit-linear-gradient(top, #34c84a 0%, #248b34 100%); 400 | background-image: linear-gradient(to bottom, #34c84a 0%, #248b34 100%); 401 | } 402 | 403 | .btn-negative { 404 | border-color: #fb2f29; 405 | border-bottom-color: #fb1710; 406 | background-color: #fd918d; 407 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fd918d), color-stop(100%, #fb2f29)); 408 | background-image: -webkit-linear-gradient(top, #fd918d 0%, #fb2f29 100%); 409 | background-image: linear-gradient(to bottom, #fd918d 0%, #fb2f29 100%); 410 | } 411 | .btn-negative:active { 412 | background-color: #fc605b; 413 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fc605b), color-stop(100%, #fb1710)); 414 | background-image: -webkit-linear-gradient(top, #fc605b 0%, #fb1710 100%); 415 | background-image: linear-gradient(to bottom, #fc605b 0%, #fb1710 100%); 416 | } 417 | 418 | .btn-warning { 419 | border-color: #fcaa0e; 420 | border-bottom-color: #ee9d02; 421 | background-color: #fece72; 422 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fece72), color-stop(100%, #fcaa0e)); 423 | background-image: -webkit-linear-gradient(top, #fece72 0%, #fcaa0e 100%); 424 | background-image: linear-gradient(to bottom, #fece72 0%, #fcaa0e 100%); 425 | } 426 | .btn-warning:active { 427 | background-color: #fdbc40; 428 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fdbc40), color-stop(100%, #ee9d02)); 429 | background-image: -webkit-linear-gradient(top, #fdbc40 0%, #ee9d02 100%); 430 | background-image: linear-gradient(to bottom, #fdbc40 0%, #ee9d02 100%); 431 | } 432 | 433 | .btn .icon { 434 | float: left; 435 | width: 14px; 436 | height: 14px; 437 | margin-top: 1px; 438 | margin-bottom: 1px; 439 | color: #737475; 440 | font-size: 14px; 441 | line-height: 1; 442 | } 443 | 444 | .btn .icon-text { 445 | margin-right: 5px; 446 | } 447 | 448 | .btn-dropdown:after { 449 | font-family: "photon-entypo"; 450 | margin-left: 5px; 451 | content: ""; 452 | } 453 | 454 | .btn-group { 455 | position: relative; 456 | display: inline-block; 457 | vertical-align: middle; 458 | -webkit-app-region: no-drag; 459 | } 460 | .btn-group .btn { 461 | position: relative; 462 | float: left; 463 | } 464 | .btn-group .btn:focus, .btn-group .btn:active { 465 | z-index: 2; 466 | } 467 | .btn-group .btn.active { 468 | z-index: 3; 469 | } 470 | 471 | .btn-group .btn + .btn, 472 | .btn-group .btn + .btn-group, 473 | .btn-group .btn-group + .btn, 474 | .btn-group .btn-group + .btn-group { 475 | margin-left: -1px; 476 | } 477 | .btn-group > .btn:first-child { 478 | border-top-right-radius: 0; 479 | border-bottom-right-radius: 0; 480 | } 481 | .btn-group > .btn:last-child { 482 | border-top-left-radius: 0; 483 | border-bottom-left-radius: 0; 484 | } 485 | .btn-group > .btn:not(:first-child):not(:last-child) { 486 | border-radius: 0; 487 | } 488 | .btn-group .btn + .btn { 489 | border-left: 1px solid #c2c0c2; 490 | } 491 | .btn-group .btn + .btn.active { 492 | border-left: 0; 493 | } 494 | .btn-group .active { 495 | color: #fff; 496 | border: 1px solid transparent; 497 | background-color: #6d6c6d; 498 | background-image: none; 499 | } 500 | .btn-group .active .icon { 501 | color: #fff; 502 | } 503 | 504 | .toolbar { 505 | min-height: 22px; 506 | box-shadow: inset 0 1px 0 #f5f4f5; 507 | background-color: #e8e6e8; 508 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #e8e6e8), color-stop(100%, #d1cfd1)); 509 | background-image: -webkit-linear-gradient(top, #e8e6e8 0%, #d1cfd1 100%); 510 | background-image: linear-gradient(to bottom, #e8e6e8 0%, #d1cfd1 100%); 511 | } 512 | .toolbar:before, .toolbar:after { 513 | display: table; 514 | content: " "; 515 | } 516 | .toolbar:after { 517 | clear: both; 518 | } 519 | 520 | .toolbar-header { 521 | border-bottom: 1px solid #c2c0c2; 522 | } 523 | .toolbar-header .title { 524 | margin-top: 1px; 525 | } 526 | 527 | .toolbar-footer { 528 | border-top: 1px solid #c2c0c2; 529 | -webkit-app-region: drag; 530 | } 531 | 532 | .title { 533 | margin: 0; 534 | font-size: 12px; 535 | font-weight: 400; 536 | text-align: center; 537 | color: #555; 538 | cursor: default; 539 | } 540 | 541 | .toolbar-borderless { 542 | border-top: 0; 543 | border-bottom: 0; 544 | } 545 | 546 | .toolbar-actions { 547 | margin-top: 4px; 548 | margin-bottom: 3px; 549 | padding-right: 3px; 550 | padding-left: 3px; 551 | padding-bottom: 3px; 552 | -webkit-app-region: drag; 553 | } 554 | .toolbar-actions:before, .toolbar-actions:after { 555 | display: table; 556 | content: " "; 557 | } 558 | .toolbar-actions:after { 559 | clear: both; 560 | } 561 | .toolbar-actions > .btn, 562 | .toolbar-actions > .btn-group { 563 | margin-left: 4px; 564 | margin-right: 4px; 565 | } 566 | 567 | label { 568 | display: inline-block; 569 | font-size: 13px; 570 | margin-bottom: 5px; 571 | white-space: nowrap; 572 | overflow: hidden; 573 | text-overflow: ellipsis; 574 | } 575 | 576 | input[type="search"] { 577 | box-sizing: border-box; 578 | } 579 | 580 | input[type="radio"], 581 | input[type="checkbox"] { 582 | margin: 4px 0 0; 583 | line-height: normal; 584 | } 585 | 586 | .form-control { 587 | display: inline-block; 588 | width: 100%; 589 | min-height: 25px; 590 | padding: 5px 10px; 591 | font-size: 13px; 592 | line-height: 1.6; 593 | background-color: #fff; 594 | border: 1px solid #ddd; 595 | border-radius: 4px; 596 | outline: none; 597 | } 598 | .form-control:focus { 599 | border-color: #6db3fd; 600 | box-shadow: 3px 3px 0 #6db3fd, -3px -3px 0 #6db3fd, -3px 3px 0 #6db3fd, 3px -3px 0 #6db3fd; 601 | } 602 | 603 | textarea { 604 | height: auto; 605 | } 606 | 607 | .form-group { 608 | margin-bottom: 10px; 609 | } 610 | 611 | .radio, 612 | .checkbox { 613 | position: relative; 614 | display: block; 615 | margin-top: 10px; 616 | margin-bottom: 10px; 617 | } 618 | .radio label, 619 | .checkbox label { 620 | padding-left: 20px; 621 | margin-bottom: 0; 622 | font-weight: normal; 623 | } 624 | 625 | .radio input[type="radio"], 626 | .radio-inline input[type="radio"], 627 | .checkbox input[type="checkbox"], 628 | .checkbox-inline input[type="checkbox"] { 629 | position: absolute; 630 | margin-left: -20px; 631 | margin-top: 4px; 632 | } 633 | 634 | .form-actions .btn { 635 | margin-right: 10px; 636 | } 637 | .form-actions .btn:last-child { 638 | margin-right: 0; 639 | } 640 | 641 | .pane-group { 642 | position: absolute; 643 | top: 0; 644 | right: 0; 645 | bottom: 0; 646 | left: 0; 647 | display: flex; 648 | } 649 | 650 | .pane { 651 | position: relative; 652 | overflow-y: auto; 653 | flex: 1; 654 | border-left: 1px solid #ddd; 655 | } 656 | .pane:first-child { 657 | border-left: 0; 658 | } 659 | 660 | .pane-sm { 661 | max-width: 220px; 662 | min-width: 150px; 663 | } 664 | 665 | .pane-mini { 666 | width: 80px; 667 | flex: none; 668 | } 669 | 670 | .pane-one-fourth { 671 | width: 25%; 672 | flex: none; 673 | } 674 | 675 | .pane-one-third { 676 | width: 33.3%; 677 | } 678 | 679 | img { 680 | -webkit-user-drag: text; 681 | } 682 | 683 | .img-circle { 684 | border-radius: 50%; 685 | } 686 | 687 | .img-rounded { 688 | border-radius: 4px; 689 | } 690 | 691 | .list-group { 692 | width: 100%; 693 | list-style: none; 694 | margin: 0; 695 | padding: 0; 696 | } 697 | .list-group * { 698 | margin: 0; 699 | white-space: nowrap; 700 | overflow: hidden; 701 | text-overflow: ellipsis; 702 | } 703 | 704 | .list-group-item { 705 | padding: 10px; 706 | font-size: 12px; 707 | color: #414142; 708 | border-top: 1px solid #ddd; 709 | } 710 | .list-group-item:first-child { 711 | border-top: 0; 712 | } 713 | .list-group-item.active, .list-group-item.selected { 714 | color: #fff; 715 | background-color: #116cd6; 716 | } 717 | 718 | .list-group-header { 719 | padding: 10px; 720 | } 721 | 722 | .media-object { 723 | margin-top: 3px; 724 | } 725 | 726 | .media-object.pull-left { 727 | margin-right: 10px; 728 | } 729 | 730 | .media-object.pull-right { 731 | margin-left: 10px; 732 | } 733 | 734 | .media-body { 735 | overflow: hidden; 736 | } 737 | 738 | .nav-group { 739 | font-size: 14px; 740 | } 741 | 742 | .nav-group-item { 743 | padding: 2px 10px 2px 25px; 744 | display: block; 745 | color: #333; 746 | text-decoration: none; 747 | white-space: nowrap; 748 | overflow: hidden; 749 | text-overflow: ellipsis; 750 | } 751 | .nav-group-item:active, .nav-group-item.active { 752 | background-color: #dcdfe1; 753 | } 754 | .nav-group-item .icon { 755 | width: 19px; 756 | height: 18px; 757 | float: left; 758 | color: #737475; 759 | margin-top: -3px; 760 | margin-right: 7px; 761 | font-size: 18px; 762 | text-align: center; 763 | } 764 | 765 | .nav-group-title { 766 | margin: 0; 767 | padding: 10px 10px 2px; 768 | font-size: 12px; 769 | font-weight: 500; 770 | color: #666666; 771 | } 772 | 773 | @font-face { 774 | font-family: "photon-entypo"; 775 | src: url("../fonts/photon-entypo.eot"); 776 | src: url("../fonts/photon-entypo.eot?#iefix") format("eot"), url("../fonts/photon-entypo.woff") format("woff"), url("../fonts/photon-entypo.ttf") format("truetype"); 777 | font-weight: normal; 778 | font-style: normal; 779 | } 780 | .icon:before { 781 | position: relative; 782 | display: inline-block; 783 | font-family: "photon-entypo"; 784 | speak: none; 785 | font-size: 100%; 786 | font-style: normal; 787 | font-weight: normal; 788 | font-variant: normal; 789 | text-transform: none; 790 | line-height: 1; 791 | -webkit-font-smoothing: antialiased; 792 | -moz-osx-font-smoothing: grayscale; 793 | } 794 | 795 | .icon-note:before { 796 | content: '\e800'; 797 | } 798 | 799 | /* '' */ 800 | .icon-note-beamed:before { 801 | content: '\e801'; 802 | } 803 | 804 | /* '' */ 805 | .icon-music:before { 806 | content: '\e802'; 807 | } 808 | 809 | /* '' */ 810 | .icon-search:before { 811 | content: '\e803'; 812 | } 813 | 814 | /* '' */ 815 | .icon-flashlight:before { 816 | content: '\e804'; 817 | } 818 | 819 | /* '' */ 820 | .icon-mail:before { 821 | content: '\e805'; 822 | } 823 | 824 | /* '' */ 825 | .icon-heart:before { 826 | content: '\e806'; 827 | } 828 | 829 | /* '' */ 830 | .icon-heart-empty:before { 831 | content: '\e807'; 832 | } 833 | 834 | /* '' */ 835 | .icon-star:before { 836 | content: '\e808'; 837 | } 838 | 839 | /* '' */ 840 | .icon-star-empty:before { 841 | content: '\e809'; 842 | } 843 | 844 | /* '' */ 845 | .icon-user:before { 846 | content: '\e80a'; 847 | } 848 | 849 | /* '' */ 850 | .icon-users:before { 851 | content: '\e80b'; 852 | } 853 | 854 | /* '' */ 855 | .icon-user-add:before { 856 | content: '\e80c'; 857 | } 858 | 859 | /* '' */ 860 | .icon-video:before { 861 | content: '\e80d'; 862 | } 863 | 864 | /* '' */ 865 | .icon-picture:before { 866 | content: '\e80e'; 867 | } 868 | 869 | /* '' */ 870 | .icon-camera:before { 871 | content: '\e80f'; 872 | } 873 | 874 | /* '' */ 875 | .icon-layout:before { 876 | content: '\e810'; 877 | } 878 | 879 | /* '' */ 880 | .icon-menu:before { 881 | content: '\e811'; 882 | } 883 | 884 | /* '' */ 885 | .icon-check:before { 886 | content: '\e812'; 887 | } 888 | 889 | /* '' */ 890 | .icon-cancel:before { 891 | content: '\e813'; 892 | } 893 | 894 | /* '' */ 895 | .icon-cancel-circled:before { 896 | content: '\e814'; 897 | } 898 | 899 | /* '' */ 900 | .icon-cancel-squared:before { 901 | content: '\e815'; 902 | } 903 | 904 | /* '' */ 905 | .icon-plus:before { 906 | content: '\e816'; 907 | } 908 | 909 | /* '' */ 910 | .icon-plus-circled:before { 911 | content: '\e817'; 912 | } 913 | 914 | /* '' */ 915 | .icon-plus-squared:before { 916 | content: '\e818'; 917 | } 918 | 919 | /* '' */ 920 | .icon-minus:before { 921 | content: '\e819'; 922 | } 923 | 924 | /* '' */ 925 | .icon-minus-circled:before { 926 | content: '\e81a'; 927 | } 928 | 929 | /* '' */ 930 | .icon-minus-squared:before { 931 | content: '\e81b'; 932 | } 933 | 934 | /* '' */ 935 | .icon-help:before { 936 | content: '\e81c'; 937 | } 938 | 939 | /* '' */ 940 | .icon-help-circled:before { 941 | content: '\e81d'; 942 | } 943 | 944 | /* '' */ 945 | .icon-info:before { 946 | content: '\e81e'; 947 | } 948 | 949 | /* '' */ 950 | .icon-info-circled:before { 951 | content: '\e81f'; 952 | } 953 | 954 | /* '' */ 955 | .icon-back:before { 956 | content: '\e820'; 957 | } 958 | 959 | /* '' */ 960 | .icon-home:before { 961 | content: '\e821'; 962 | } 963 | 964 | /* '' */ 965 | .icon-link:before { 966 | content: '\e822'; 967 | } 968 | 969 | /* '' */ 970 | .icon-attach:before { 971 | content: '\e823'; 972 | } 973 | 974 | /* '' */ 975 | .icon-lock:before { 976 | content: '\e824'; 977 | } 978 | 979 | /* '' */ 980 | .icon-lock-open:before { 981 | content: '\e825'; 982 | } 983 | 984 | /* '' */ 985 | .icon-eye:before { 986 | content: '\e826'; 987 | } 988 | 989 | /* '' */ 990 | .icon-tag:before { 991 | content: '\e827'; 992 | } 993 | 994 | /* '' */ 995 | .icon-bookmark:before { 996 | content: '\e828'; 997 | } 998 | 999 | /* '' */ 1000 | .icon-bookmarks:before { 1001 | content: '\e829'; 1002 | } 1003 | 1004 | /* '' */ 1005 | .icon-flag:before { 1006 | content: '\e82a'; 1007 | } 1008 | 1009 | /* '' */ 1010 | .icon-thumbs-up:before { 1011 | content: '\e82b'; 1012 | } 1013 | 1014 | /* '' */ 1015 | .icon-thumbs-down:before { 1016 | content: '\e82c'; 1017 | } 1018 | 1019 | /* '' */ 1020 | .icon-download:before { 1021 | content: '\e82d'; 1022 | } 1023 | 1024 | /* '' */ 1025 | .icon-upload:before { 1026 | content: '\e82e'; 1027 | } 1028 | 1029 | /* '' */ 1030 | .icon-upload-cloud:before { 1031 | content: '\e82f'; 1032 | } 1033 | 1034 | /* '' */ 1035 | .icon-reply:before { 1036 | content: '\e830'; 1037 | } 1038 | 1039 | /* '' */ 1040 | .icon-reply-all:before { 1041 | content: '\e831'; 1042 | } 1043 | 1044 | /* '' */ 1045 | .icon-forward:before { 1046 | content: '\e832'; 1047 | } 1048 | 1049 | /* '' */ 1050 | .icon-quote:before { 1051 | content: '\e833'; 1052 | } 1053 | 1054 | /* '' */ 1055 | .icon-code:before { 1056 | content: '\e834'; 1057 | } 1058 | 1059 | /* '' */ 1060 | .icon-export:before { 1061 | content: '\e835'; 1062 | } 1063 | 1064 | /* '' */ 1065 | .icon-pencil:before { 1066 | content: '\e836'; 1067 | } 1068 | 1069 | /* '' */ 1070 | .icon-feather:before { 1071 | content: '\e837'; 1072 | } 1073 | 1074 | /* '' */ 1075 | .icon-print:before { 1076 | content: '\e838'; 1077 | } 1078 | 1079 | /* '' */ 1080 | .icon-retweet:before { 1081 | content: '\e839'; 1082 | } 1083 | 1084 | /* '' */ 1085 | .icon-keyboard:before { 1086 | content: '\e83a'; 1087 | } 1088 | 1089 | /* '' */ 1090 | .icon-comment:before { 1091 | content: '\e83b'; 1092 | } 1093 | 1094 | /* '' */ 1095 | .icon-chat:before { 1096 | content: '\e83c'; 1097 | } 1098 | 1099 | /* '' */ 1100 | .icon-bell:before { 1101 | content: '\e83d'; 1102 | } 1103 | 1104 | /* '' */ 1105 | .icon-attention:before { 1106 | content: '\e83e'; 1107 | } 1108 | 1109 | /* '' */ 1110 | .icon-alert:before { 1111 | content: '\e83f'; 1112 | } 1113 | 1114 | /* '' */ 1115 | .icon-vcard:before { 1116 | content: '\e840'; 1117 | } 1118 | 1119 | /* '' */ 1120 | .icon-address:before { 1121 | content: '\e841'; 1122 | } 1123 | 1124 | /* '' */ 1125 | .icon-location:before { 1126 | content: '\e842'; 1127 | } 1128 | 1129 | /* '' */ 1130 | .icon-map:before { 1131 | content: '\e843'; 1132 | } 1133 | 1134 | /* '' */ 1135 | .icon-direction:before { 1136 | content: '\e844'; 1137 | } 1138 | 1139 | /* '' */ 1140 | .icon-compass:before { 1141 | content: '\e845'; 1142 | } 1143 | 1144 | /* '' */ 1145 | .icon-cup:before { 1146 | content: '\e846'; 1147 | } 1148 | 1149 | /* '' */ 1150 | .icon-trash:before { 1151 | content: '\e847'; 1152 | } 1153 | 1154 | /* '' */ 1155 | .icon-doc:before { 1156 | content: '\e848'; 1157 | } 1158 | 1159 | /* '' */ 1160 | .icon-docs:before { 1161 | content: '\e849'; 1162 | } 1163 | 1164 | /* '' */ 1165 | .icon-doc-landscape:before { 1166 | content: '\e84a'; 1167 | } 1168 | 1169 | /* '' */ 1170 | .icon-doc-text:before { 1171 | content: '\e84b'; 1172 | } 1173 | 1174 | /* '' */ 1175 | .icon-doc-text-inv:before { 1176 | content: '\e84c'; 1177 | } 1178 | 1179 | /* '' */ 1180 | .icon-newspaper:before { 1181 | content: '\e84d'; 1182 | } 1183 | 1184 | /* '' */ 1185 | .icon-book-open:before { 1186 | content: '\e84e'; 1187 | } 1188 | 1189 | /* '' */ 1190 | .icon-book:before { 1191 | content: '\e84f'; 1192 | } 1193 | 1194 | /* '' */ 1195 | .icon-folder:before { 1196 | content: '\e850'; 1197 | } 1198 | 1199 | /* '' */ 1200 | .icon-archive:before { 1201 | content: '\e851'; 1202 | } 1203 | 1204 | /* '' */ 1205 | .icon-box:before { 1206 | content: '\e852'; 1207 | } 1208 | 1209 | /* '' */ 1210 | .icon-rss:before { 1211 | content: '\e853'; 1212 | } 1213 | 1214 | /* '' */ 1215 | .icon-phone:before { 1216 | content: '\e854'; 1217 | } 1218 | 1219 | /* '' */ 1220 | .icon-cog:before { 1221 | content: '\e855'; 1222 | } 1223 | 1224 | /* '' */ 1225 | .icon-tools:before { 1226 | content: '\e856'; 1227 | } 1228 | 1229 | /* '' */ 1230 | .icon-share:before { 1231 | content: '\e857'; 1232 | } 1233 | 1234 | /* '' */ 1235 | .icon-shareable:before { 1236 | content: '\e858'; 1237 | } 1238 | 1239 | /* '' */ 1240 | .icon-basket:before { 1241 | content: '\e859'; 1242 | } 1243 | 1244 | /* '' */ 1245 | .icon-bag:before { 1246 | content: '\e85a'; 1247 | } 1248 | 1249 | /* '' */ 1250 | .icon-calendar:before { 1251 | content: '\e85b'; 1252 | } 1253 | 1254 | /* '' */ 1255 | .icon-login:before { 1256 | content: '\e85c'; 1257 | } 1258 | 1259 | /* '' */ 1260 | .icon-logout:before { 1261 | content: '\e85d'; 1262 | } 1263 | 1264 | /* '' */ 1265 | .icon-mic:before { 1266 | content: '\e85e'; 1267 | } 1268 | 1269 | /* '' */ 1270 | .icon-mute:before { 1271 | content: '\e85f'; 1272 | } 1273 | 1274 | /* '' */ 1275 | .icon-sound:before { 1276 | content: '\e860'; 1277 | } 1278 | 1279 | /* '' */ 1280 | .icon-volume:before { 1281 | content: '\e861'; 1282 | } 1283 | 1284 | /* '' */ 1285 | .icon-clock:before { 1286 | content: '\e862'; 1287 | } 1288 | 1289 | /* '' */ 1290 | .icon-hourglass:before { 1291 | content: '\e863'; 1292 | } 1293 | 1294 | /* '' */ 1295 | .icon-lamp:before { 1296 | content: '\e864'; 1297 | } 1298 | 1299 | /* '' */ 1300 | .icon-light-down:before { 1301 | content: '\e865'; 1302 | } 1303 | 1304 | /* '' */ 1305 | .icon-light-up:before { 1306 | content: '\e866'; 1307 | } 1308 | 1309 | /* '' */ 1310 | .icon-adjust:before { 1311 | content: '\e867'; 1312 | } 1313 | 1314 | /* '' */ 1315 | .icon-block:before { 1316 | content: '\e868'; 1317 | } 1318 | 1319 | /* '' */ 1320 | .icon-resize-full:before { 1321 | content: '\e869'; 1322 | } 1323 | 1324 | /* '' */ 1325 | .icon-resize-small:before { 1326 | content: '\e86a'; 1327 | } 1328 | 1329 | /* '' */ 1330 | .icon-popup:before { 1331 | content: '\e86b'; 1332 | } 1333 | 1334 | /* '' */ 1335 | .icon-publish:before { 1336 | content: '\e86c'; 1337 | } 1338 | 1339 | /* '' */ 1340 | .icon-window:before { 1341 | content: '\e86d'; 1342 | } 1343 | 1344 | /* '' */ 1345 | .icon-arrow-combo:before { 1346 | content: '\e86e'; 1347 | } 1348 | 1349 | /* '' */ 1350 | .icon-down-circled:before { 1351 | content: '\e86f'; 1352 | } 1353 | 1354 | /* '' */ 1355 | .icon-left-circled:before { 1356 | content: '\e870'; 1357 | } 1358 | 1359 | /* '' */ 1360 | .icon-right-circled:before { 1361 | content: '\e871'; 1362 | } 1363 | 1364 | /* '' */ 1365 | .icon-up-circled:before { 1366 | content: '\e872'; 1367 | } 1368 | 1369 | /* '' */ 1370 | .icon-down-open:before { 1371 | content: '\e873'; 1372 | } 1373 | 1374 | /* '' */ 1375 | .icon-left-open:before { 1376 | content: '\e874'; 1377 | } 1378 | 1379 | /* '' */ 1380 | .icon-right-open:before { 1381 | content: '\e875'; 1382 | } 1383 | 1384 | /* '' */ 1385 | .icon-up-open:before { 1386 | content: '\e876'; 1387 | } 1388 | 1389 | /* '' */ 1390 | .icon-down-open-mini:before { 1391 | content: '\e877'; 1392 | } 1393 | 1394 | /* '' */ 1395 | .icon-left-open-mini:before { 1396 | content: '\e878'; 1397 | } 1398 | 1399 | /* '' */ 1400 | .icon-right-open-mini:before { 1401 | content: '\e879'; 1402 | } 1403 | 1404 | /* '' */ 1405 | .icon-up-open-mini:before { 1406 | content: '\e87a'; 1407 | } 1408 | 1409 | /* '' */ 1410 | .icon-down-open-big:before { 1411 | content: '\e87b'; 1412 | } 1413 | 1414 | /* '' */ 1415 | .icon-left-open-big:before { 1416 | content: '\e87c'; 1417 | } 1418 | 1419 | /* '' */ 1420 | .icon-right-open-big:before { 1421 | content: '\e87d'; 1422 | } 1423 | 1424 | /* '' */ 1425 | .icon-up-open-big:before { 1426 | content: '\e87e'; 1427 | } 1428 | 1429 | /* '' */ 1430 | .icon-down:before { 1431 | content: '\e87f'; 1432 | } 1433 | 1434 | /* '' */ 1435 | .icon-left:before { 1436 | content: '\e880'; 1437 | } 1438 | 1439 | /* '' */ 1440 | .icon-right:before { 1441 | content: '\e881'; 1442 | } 1443 | 1444 | /* '' */ 1445 | .icon-up:before { 1446 | content: '\e882'; 1447 | } 1448 | 1449 | /* '' */ 1450 | .icon-down-dir:before { 1451 | content: '\e883'; 1452 | } 1453 | 1454 | /* '' */ 1455 | .icon-left-dir:before { 1456 | content: '\e884'; 1457 | } 1458 | 1459 | /* '' */ 1460 | .icon-right-dir:before { 1461 | content: '\e885'; 1462 | } 1463 | 1464 | /* '' */ 1465 | .icon-up-dir:before { 1466 | content: '\e886'; 1467 | } 1468 | 1469 | /* '' */ 1470 | .icon-down-bold:before { 1471 | content: '\e887'; 1472 | } 1473 | 1474 | /* '' */ 1475 | .icon-left-bold:before { 1476 | content: '\e888'; 1477 | } 1478 | 1479 | /* '' */ 1480 | .icon-right-bold:before { 1481 | content: '\e889'; 1482 | } 1483 | 1484 | /* '' */ 1485 | .icon-up-bold:before { 1486 | content: '\e88a'; 1487 | } 1488 | 1489 | /* '' */ 1490 | .icon-down-thin:before { 1491 | content: '\e88b'; 1492 | } 1493 | 1494 | /* '' */ 1495 | .icon-left-thin:before { 1496 | content: '\e88c'; 1497 | } 1498 | 1499 | /* '' */ 1500 | .icon-right-thin:before { 1501 | content: '\e88d'; 1502 | } 1503 | 1504 | /* '' */ 1505 | .icon-up-thin:before { 1506 | content: '\e88e'; 1507 | } 1508 | 1509 | /* '' */ 1510 | .icon-ccw:before { 1511 | content: '\e88f'; 1512 | } 1513 | 1514 | /* '' */ 1515 | .icon-cw:before { 1516 | content: '\e890'; 1517 | } 1518 | 1519 | /* '' */ 1520 | .icon-arrows-ccw:before { 1521 | content: '\e891'; 1522 | } 1523 | 1524 | /* '' */ 1525 | .icon-level-down:before { 1526 | content: '\e892'; 1527 | } 1528 | 1529 | /* '' */ 1530 | .icon-level-up:before { 1531 | content: '\e893'; 1532 | } 1533 | 1534 | /* '' */ 1535 | .icon-shuffle:before { 1536 | content: '\e894'; 1537 | } 1538 | 1539 | /* '' */ 1540 | .icon-loop:before { 1541 | content: '\e895'; 1542 | } 1543 | 1544 | /* '' */ 1545 | .icon-switch:before { 1546 | content: '\e896'; 1547 | } 1548 | 1549 | /* '' */ 1550 | .icon-play:before { 1551 | content: '\e897'; 1552 | } 1553 | 1554 | /* '' */ 1555 | .icon-stop:before { 1556 | content: '\e898'; 1557 | } 1558 | 1559 | /* '' */ 1560 | .icon-pause:before { 1561 | content: '\e899'; 1562 | } 1563 | 1564 | /* '' */ 1565 | .icon-record:before { 1566 | content: '\e89a'; 1567 | } 1568 | 1569 | /* '' */ 1570 | .icon-to-end:before { 1571 | content: '\e89b'; 1572 | } 1573 | 1574 | /* '' */ 1575 | .icon-to-start:before { 1576 | content: '\e89c'; 1577 | } 1578 | 1579 | /* '' */ 1580 | .icon-fast-forward:before { 1581 | content: '\e89d'; 1582 | } 1583 | 1584 | /* '' */ 1585 | .icon-fast-backward:before { 1586 | content: '\e89e'; 1587 | } 1588 | 1589 | /* '' */ 1590 | .icon-progress-0:before { 1591 | content: '\e89f'; 1592 | } 1593 | 1594 | /* '' */ 1595 | .icon-progress-1:before { 1596 | content: '\e8a0'; 1597 | } 1598 | 1599 | /* '' */ 1600 | .icon-progress-2:before { 1601 | content: '\e8a1'; 1602 | } 1603 | 1604 | /* '' */ 1605 | .icon-progress-3:before { 1606 | content: '\e8a2'; 1607 | } 1608 | 1609 | /* '' */ 1610 | .icon-target:before { 1611 | content: '\e8a3'; 1612 | } 1613 | 1614 | /* '' */ 1615 | .icon-palette:before { 1616 | content: '\e8a4'; 1617 | } 1618 | 1619 | /* '' */ 1620 | .icon-list:before { 1621 | content: '\e8a5'; 1622 | } 1623 | 1624 | /* '' */ 1625 | .icon-list-add:before { 1626 | content: '\e8a6'; 1627 | } 1628 | 1629 | /* '' */ 1630 | .icon-signal:before { 1631 | content: '\e8a7'; 1632 | } 1633 | 1634 | /* '' */ 1635 | .icon-trophy:before { 1636 | content: '\e8a8'; 1637 | } 1638 | 1639 | /* '' */ 1640 | .icon-battery:before { 1641 | content: '\e8a9'; 1642 | } 1643 | 1644 | /* '' */ 1645 | .icon-back-in-time:before { 1646 | content: '\e8aa'; 1647 | } 1648 | 1649 | /* '' */ 1650 | .icon-monitor:before { 1651 | content: '\e8ab'; 1652 | } 1653 | 1654 | /* '' */ 1655 | .icon-mobile:before { 1656 | content: '\e8ac'; 1657 | } 1658 | 1659 | /* '' */ 1660 | .icon-network:before { 1661 | content: '\e8ad'; 1662 | } 1663 | 1664 | /* '' */ 1665 | .icon-cd:before { 1666 | content: '\e8ae'; 1667 | } 1668 | 1669 | /* '' */ 1670 | .icon-inbox:before { 1671 | content: '\e8af'; 1672 | } 1673 | 1674 | /* '' */ 1675 | .icon-install:before { 1676 | content: '\e8b0'; 1677 | } 1678 | 1679 | /* '' */ 1680 | .icon-globe:before { 1681 | content: '\e8b1'; 1682 | } 1683 | 1684 | /* '' */ 1685 | .icon-cloud:before { 1686 | content: '\e8b2'; 1687 | } 1688 | 1689 | /* '' */ 1690 | .icon-cloud-thunder:before { 1691 | content: '\e8b3'; 1692 | } 1693 | 1694 | /* '' */ 1695 | .icon-flash:before { 1696 | content: '\e8b4'; 1697 | } 1698 | 1699 | /* '' */ 1700 | .icon-moon:before { 1701 | content: '\e8b5'; 1702 | } 1703 | 1704 | /* '' */ 1705 | .icon-flight:before { 1706 | content: '\e8b6'; 1707 | } 1708 | 1709 | /* '' */ 1710 | .icon-paper-plane:before { 1711 | content: '\e8b7'; 1712 | } 1713 | 1714 | /* '' */ 1715 | .icon-leaf:before { 1716 | content: '\e8b8'; 1717 | } 1718 | 1719 | /* '' */ 1720 | .icon-lifebuoy:before { 1721 | content: '\e8b9'; 1722 | } 1723 | 1724 | /* '' */ 1725 | .icon-mouse:before { 1726 | content: '\e8ba'; 1727 | } 1728 | 1729 | /* '' */ 1730 | .icon-briefcase:before { 1731 | content: '\e8bb'; 1732 | } 1733 | 1734 | /* '' */ 1735 | .icon-suitcase:before { 1736 | content: '\e8bc'; 1737 | } 1738 | 1739 | /* '' */ 1740 | .icon-dot:before { 1741 | content: '\e8bd'; 1742 | } 1743 | 1744 | /* '' */ 1745 | .icon-dot-2:before { 1746 | content: '\e8be'; 1747 | } 1748 | 1749 | /* '' */ 1750 | .icon-dot-3:before { 1751 | content: '\e8bf'; 1752 | } 1753 | 1754 | /* '' */ 1755 | .icon-brush:before { 1756 | content: '\e8c0'; 1757 | } 1758 | 1759 | /* '' */ 1760 | .icon-magnet:before { 1761 | content: '\e8c1'; 1762 | } 1763 | 1764 | /* '' */ 1765 | .icon-infinity:before { 1766 | content: '\e8c2'; 1767 | } 1768 | 1769 | /* '' */ 1770 | .icon-erase:before { 1771 | content: '\e8c3'; 1772 | } 1773 | 1774 | /* '' */ 1775 | .icon-chart-pie:before { 1776 | content: '\e8c4'; 1777 | } 1778 | 1779 | /* '' */ 1780 | .icon-chart-line:before { 1781 | content: '\e8c5'; 1782 | } 1783 | 1784 | /* '' */ 1785 | .icon-chart-bar:before { 1786 | content: '\e8c6'; 1787 | } 1788 | 1789 | /* '' */ 1790 | .icon-chart-area:before { 1791 | content: '\e8c7'; 1792 | } 1793 | 1794 | /* '' */ 1795 | .icon-tape:before { 1796 | content: '\e8c8'; 1797 | } 1798 | 1799 | /* '' */ 1800 | .icon-graduation-cap:before { 1801 | content: '\e8c9'; 1802 | } 1803 | 1804 | /* '' */ 1805 | .icon-language:before { 1806 | content: '\e8ca'; 1807 | } 1808 | 1809 | /* '' */ 1810 | .icon-ticket:before { 1811 | content: '\e8cb'; 1812 | } 1813 | 1814 | /* '' */ 1815 | .icon-water:before { 1816 | content: '\e8cc'; 1817 | } 1818 | 1819 | /* '' */ 1820 | .icon-droplet:before { 1821 | content: '\e8cd'; 1822 | } 1823 | 1824 | /* '' */ 1825 | .icon-air:before { 1826 | content: '\e8ce'; 1827 | } 1828 | 1829 | /* '' */ 1830 | .icon-credit-card:before { 1831 | content: '\e8cf'; 1832 | } 1833 | 1834 | /* '' */ 1835 | .icon-floppy:before { 1836 | content: '\e8d0'; 1837 | } 1838 | 1839 | /* '' */ 1840 | .icon-clipboard:before { 1841 | content: '\e8d1'; 1842 | } 1843 | 1844 | /* '' */ 1845 | .icon-megaphone:before { 1846 | content: '\e8d2'; 1847 | } 1848 | 1849 | /* '' */ 1850 | .icon-database:before { 1851 | content: '\e8d3'; 1852 | } 1853 | 1854 | /* '' */ 1855 | .icon-drive:before { 1856 | content: '\e8d4'; 1857 | } 1858 | 1859 | /* '' */ 1860 | .icon-bucket:before { 1861 | content: '\e8d5'; 1862 | } 1863 | 1864 | /* '' */ 1865 | .icon-thermometer:before { 1866 | content: '\e8d6'; 1867 | } 1868 | 1869 | /* '' */ 1870 | .icon-key:before { 1871 | content: '\e8d7'; 1872 | } 1873 | 1874 | /* '' */ 1875 | .icon-flow-cascade:before { 1876 | content: '\e8d8'; 1877 | } 1878 | 1879 | /* '' */ 1880 | .icon-flow-branch:before { 1881 | content: '\e8d9'; 1882 | } 1883 | 1884 | /* '' */ 1885 | .icon-flow-tree:before { 1886 | content: '\e8da'; 1887 | } 1888 | 1889 | /* '' */ 1890 | .icon-flow-line:before { 1891 | content: '\e8db'; 1892 | } 1893 | 1894 | /* '' */ 1895 | .icon-flow-parallel:before { 1896 | content: '\e8dc'; 1897 | } 1898 | 1899 | /* '' */ 1900 | .icon-rocket:before { 1901 | content: '\e8dd'; 1902 | } 1903 | 1904 | /* '' */ 1905 | .icon-gauge:before { 1906 | content: '\e8de'; 1907 | } 1908 | 1909 | /* '' */ 1910 | .icon-traffic-cone:before { 1911 | content: '\e8df'; 1912 | } 1913 | 1914 | /* '' */ 1915 | .icon-cc:before { 1916 | content: '\e8e0'; 1917 | } 1918 | 1919 | /* '' */ 1920 | .icon-cc-by:before { 1921 | content: '\e8e1'; 1922 | } 1923 | 1924 | /* '' */ 1925 | .icon-cc-nc:before { 1926 | content: '\e8e2'; 1927 | } 1928 | 1929 | /* '' */ 1930 | .icon-cc-nc-eu:before { 1931 | content: '\e8e3'; 1932 | } 1933 | 1934 | /* '' */ 1935 | .icon-cc-nc-jp:before { 1936 | content: '\e8e4'; 1937 | } 1938 | 1939 | /* '' */ 1940 | .icon-cc-sa:before { 1941 | content: '\e8e5'; 1942 | } 1943 | 1944 | /* '' */ 1945 | .icon-cc-nd:before { 1946 | content: '\e8e6'; 1947 | } 1948 | 1949 | /* '' */ 1950 | .icon-cc-pd:before { 1951 | content: '\e8e7'; 1952 | } 1953 | 1954 | /* '' */ 1955 | .icon-cc-zero:before { 1956 | content: '\e8e8'; 1957 | } 1958 | 1959 | /* '' */ 1960 | .icon-cc-share:before { 1961 | content: '\e8e9'; 1962 | } 1963 | 1964 | /* '' */ 1965 | .icon-cc-remix:before { 1966 | content: '\e8ea'; 1967 | } 1968 | 1969 | /* '' */ 1970 | .icon-github:before { 1971 | content: '\e8eb'; 1972 | } 1973 | 1974 | /* '' */ 1975 | .icon-github-circled:before { 1976 | content: '\e8ec'; 1977 | } 1978 | 1979 | /* '' */ 1980 | .icon-flickr:before { 1981 | content: '\e8ed'; 1982 | } 1983 | 1984 | /* '' */ 1985 | .icon-flickr-circled:before { 1986 | content: '\e8ee'; 1987 | } 1988 | 1989 | /* '' */ 1990 | .icon-vimeo:before { 1991 | content: '\e8ef'; 1992 | } 1993 | 1994 | /* '' */ 1995 | .icon-vimeo-circled:before { 1996 | content: '\e8f0'; 1997 | } 1998 | 1999 | /* '' */ 2000 | .icon-twitter:before { 2001 | content: '\e8f1'; 2002 | } 2003 | 2004 | /* '' */ 2005 | .icon-twitter-circled:before { 2006 | content: '\e8f2'; 2007 | } 2008 | 2009 | /* '' */ 2010 | .icon-facebook:before { 2011 | content: '\e8f3'; 2012 | } 2013 | 2014 | /* '' */ 2015 | .icon-facebook-circled:before { 2016 | content: '\e8f4'; 2017 | } 2018 | 2019 | /* '' */ 2020 | .icon-facebook-squared:before { 2021 | content: '\e8f5'; 2022 | } 2023 | 2024 | /* '' */ 2025 | .icon-gplus:before { 2026 | content: '\e8f6'; 2027 | } 2028 | 2029 | /* '' */ 2030 | .icon-gplus-circled:before { 2031 | content: '\e8f7'; 2032 | } 2033 | 2034 | /* '' */ 2035 | .icon-pinterest:before { 2036 | content: '\e8f8'; 2037 | } 2038 | 2039 | /* '' */ 2040 | .icon-pinterest-circled:before { 2041 | content: '\e8f9'; 2042 | } 2043 | 2044 | /* '' */ 2045 | .icon-tumblr:before { 2046 | content: '\e8fa'; 2047 | } 2048 | 2049 | /* '' */ 2050 | .icon-tumblr-circled:before { 2051 | content: '\e8fb'; 2052 | } 2053 | 2054 | /* '' */ 2055 | .icon-linkedin:before { 2056 | content: '\e8fc'; 2057 | } 2058 | 2059 | /* '' */ 2060 | .icon-linkedin-circled:before { 2061 | content: '\e8fd'; 2062 | } 2063 | 2064 | /* '' */ 2065 | .icon-dribbble:before { 2066 | content: '\e8fe'; 2067 | } 2068 | 2069 | /* '' */ 2070 | .icon-dribbble-circled:before { 2071 | content: '\e8ff'; 2072 | } 2073 | 2074 | /* '' */ 2075 | .icon-stumbleupon:before { 2076 | content: '\e900'; 2077 | } 2078 | 2079 | /* '' */ 2080 | .icon-stumbleupon-circled:before { 2081 | content: '\e901'; 2082 | } 2083 | 2084 | /* '' */ 2085 | .icon-lastfm:before { 2086 | content: '\e902'; 2087 | } 2088 | 2089 | /* '' */ 2090 | .icon-lastfm-circled:before { 2091 | content: '\e903'; 2092 | } 2093 | 2094 | /* '' */ 2095 | .icon-rdio:before { 2096 | content: '\e904'; 2097 | } 2098 | 2099 | /* '' */ 2100 | .icon-rdio-circled:before { 2101 | content: '\e905'; 2102 | } 2103 | 2104 | /* '' */ 2105 | .icon-spotify:before { 2106 | content: '\e906'; 2107 | } 2108 | 2109 | /* '' */ 2110 | .icon-spotify-circled:before { 2111 | content: '\e907'; 2112 | } 2113 | 2114 | /* '' */ 2115 | .icon-qq:before { 2116 | content: '\e908'; 2117 | } 2118 | 2119 | /* '' */ 2120 | .icon-instagram:before { 2121 | content: '\e909'; 2122 | } 2123 | 2124 | /* '' */ 2125 | .icon-dropbox:before { 2126 | content: '\e90a'; 2127 | } 2128 | 2129 | /* '' */ 2130 | .icon-evernote:before { 2131 | content: '\e90b'; 2132 | } 2133 | 2134 | /* '' */ 2135 | .icon-flattr:before { 2136 | content: '\e90c'; 2137 | } 2138 | 2139 | /* '' */ 2140 | .icon-skype:before { 2141 | content: '\e90d'; 2142 | } 2143 | 2144 | /* '' */ 2145 | .icon-skype-circled:before { 2146 | content: '\e90e'; 2147 | } 2148 | 2149 | /* '' */ 2150 | .icon-renren:before { 2151 | content: '\e90f'; 2152 | } 2153 | 2154 | /* '' */ 2155 | .icon-sina-weibo:before { 2156 | content: '\e910'; 2157 | } 2158 | 2159 | /* '' */ 2160 | .icon-paypal:before { 2161 | content: '\e911'; 2162 | } 2163 | 2164 | /* '' */ 2165 | .icon-picasa:before { 2166 | content: '\e912'; 2167 | } 2168 | 2169 | /* '' */ 2170 | .icon-soundcloud:before { 2171 | content: '\e913'; 2172 | } 2173 | 2174 | /* '' */ 2175 | .icon-mixi:before { 2176 | content: '\e914'; 2177 | } 2178 | 2179 | /* '' */ 2180 | .icon-behance:before { 2181 | content: '\e915'; 2182 | } 2183 | 2184 | /* '' */ 2185 | .icon-google-circles:before { 2186 | content: '\e916'; 2187 | } 2188 | 2189 | /* '' */ 2190 | .icon-vkontakte:before { 2191 | content: '\e917'; 2192 | } 2193 | 2194 | /* '' */ 2195 | .icon-smashing:before { 2196 | content: '\e918'; 2197 | } 2198 | 2199 | /* '' */ 2200 | .icon-sweden:before { 2201 | content: '\e919'; 2202 | } 2203 | 2204 | /* '' */ 2205 | .icon-db-shape:before { 2206 | content: '\e91a'; 2207 | } 2208 | 2209 | /* '' */ 2210 | .icon-logo-db:before { 2211 | content: '\e91b'; 2212 | } 2213 | 2214 | /* '' */ 2215 | table { 2216 | width: 100%; 2217 | border: 0; 2218 | border-collapse: separate; 2219 | font-size: 12px; 2220 | text-align: left; 2221 | } 2222 | 2223 | thead { 2224 | background-color: #f5f5f4; 2225 | } 2226 | 2227 | tbody { 2228 | background-color: #fff; 2229 | } 2230 | 2231 | .table-striped tr:nth-child(even) { 2232 | background-color: #f5f5f4; 2233 | } 2234 | 2235 | tr:active, 2236 | .table-striped tr:active:nth-child(even) { 2237 | color: #fff; 2238 | background-color: #116cd6; 2239 | } 2240 | 2241 | thead tr:active { 2242 | color: #333; 2243 | background-color: #f5f5f4; 2244 | } 2245 | 2246 | th { 2247 | font-weight: normal; 2248 | border-right: 1px solid #ddd; 2249 | border-bottom: 1px solid #ddd; 2250 | } 2251 | 2252 | th, 2253 | td { 2254 | padding: 2px 15px; 2255 | white-space: nowrap; 2256 | overflow: hidden; 2257 | text-overflow: ellipsis; 2258 | } 2259 | th:last-child, 2260 | td:last-child { 2261 | border-right: 0; 2262 | } 2263 | 2264 | .tab-group { 2265 | margin-top: -1px; 2266 | display: flex; 2267 | border-top: 1px solid #989698; 2268 | border-bottom: 1px solid #989698; 2269 | } 2270 | 2271 | .tab-item { 2272 | position: relative; 2273 | flex: 1; 2274 | padding: 3px; 2275 | font-size: 12px; 2276 | text-align: center; 2277 | border-left: 1px solid #989698; 2278 | background-color: #b8b6b8; 2279 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #b8b6b8), color-stop(100%, #b0aeb0)); 2280 | background-image: -webkit-linear-gradient(top, #b8b6b8 0%, #b0aeb0 100%); 2281 | background-image: linear-gradient(to bottom, #b8b6b8 0%, #b0aeb0 100%); 2282 | } 2283 | .tab-item:first-child { 2284 | border-left: 0; 2285 | } 2286 | .tab-item.active { 2287 | background-color: #d4d2d4; 2288 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #d4d2d4), color-stop(100%, #cccacc)); 2289 | background-image: -webkit-linear-gradient(top, #d4d2d4 0%, #cccacc 100%); 2290 | background-image: linear-gradient(to bottom, #d4d2d4 0%, #cccacc 100%); 2291 | } 2292 | .tab-item .icon-close-tab { 2293 | position: absolute; 2294 | top: 50%; 2295 | left: 5px; 2296 | width: 15px; 2297 | height: 15px; 2298 | font-size: 15px; 2299 | line-height: 15px; 2300 | text-align: center; 2301 | color: #666; 2302 | opacity: 0; 2303 | transition: opacity .1s linear, background-color .1s linear; 2304 | border-radius: 3px; 2305 | transform: translateY(-50%); 2306 | z-index: 10; 2307 | } 2308 | .tab-item:after { 2309 | position: absolute; 2310 | top: 0; 2311 | right: 0; 2312 | bottom: 0; 2313 | left: 0; 2314 | content: ""; 2315 | background-color: rgba(0, 0, 0, 0.08); 2316 | opacity: 0; 2317 | transition: opacity .1s linear; 2318 | z-index: 1; 2319 | } 2320 | .tab-item:hover:not(.active):after { 2321 | opacity: 1; 2322 | } 2323 | .tab-item:hover .icon-close-tab { 2324 | opacity: 1; 2325 | } 2326 | .tab-item .icon-close-tab:hover { 2327 | background-color: rgba(0, 0, 0, 0.08); 2328 | } 2329 | 2330 | .tab-item-fixed { 2331 | flex: none; 2332 | padding: 3px 10px; 2333 | } 2334 | --------------------------------------------------------------------------------