├── .gitignore ├── .jshintrc ├── README.md ├── app ├── app.js ├── index.html ├── js │ └── lib │ │ └── version.js ├── photon │ ├── css │ │ └── photon.css │ └── fonts │ │ ├── photon-entypo.eot │ │ ├── photon-entypo.svg │ │ ├── photon-entypo.ttf │ │ └── photon-entypo.woff ├── style.css └── template.html ├── build ├── background.png ├── icon.icns └── icon.ico ├── images └── icon.png ├── main.js ├── package.json └── window.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esversion": 6, 3 | "predef" : ["component", "window", "exports"] 4 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Electron image viewer 2 | 3 | A quick and dirty image viewer made in 8 hours over 5 days. 4 | 5 | Uses [Electron](https://github.com/electron/electron) + [Ractive](https://github.com/ractivejs/ractive) + [Photon](https://github.com/connors/photon/). 6 | 7 | Supports only those image formats supported by Chromium: JPG, PNG, GIF, BPM, WEBP and SVG. 8 | 9 | **Shortcuts**: 10 | * left and right arrow for previous/next image 11 | * "f" to toggle fullscreen 12 | * "n" to toggle filename display 13 | * "c" to toggle background color colorpicker 14 | * esc to exit fullscreen or quit the application 15 | * del or command+backspace to trash current image, hold shift for permanent deletion 16 | 17 | ![A screen shot](https://cloud.githubusercontent.com/assets/291348/19836170/9d499500-9e98-11e6-9252-7d68b27d5e2d.PNG) 18 | 19 | A Turkish cat sleeping on a pile of books picture source: http://cuteoverload.com/2013/06/23/turkey-cat/ 20 | 21 | The font used for the app icon is [SF Alien Encounters by ShyFoundry](http://shyfoundry.com/fonts/shareware/sfalienenc.html). 22 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | const { remote, ipcRenderer, shell } = require("electron"); 2 | const path = require("path"); 3 | const Ractive = require("ractive"); 4 | const ractiveEventsTap = require("ractive-events-tap"); 5 | const jetpack = require("fs-jetpack"); 6 | const Mousetrap = require("mousetrap"); 7 | const Hamster = require("hamsterjs"); 8 | const ElectronStore = require("electron-store"); 9 | const trash = require("trash"); 10 | 11 | const store = new ElectronStore(); 12 | 13 | const displayableExtensions = [ 14 | "jpg", "jpeg", "png", "gif", "webp", "bmp", "svg" 15 | ]; 16 | 17 | const cwd = remote.process.cwd(); 18 | const inputArgs = remote.process.argv; 19 | const inputPath = inputArgs.pop(); 20 | const templatePath = path.join(__dirname, "template.html"); 21 | const templateString = jetpack.read(templatePath); 22 | 23 | const app = new Ractive({ 24 | el: "#viewer", 25 | template: templateString, 26 | 27 | events: { 28 | tap: ractiveEventsTap, 29 | }, 30 | 31 | data() { 32 | return { 33 | backgroundColor: "#f8f8f8", 34 | colorPickerVisible: false, 35 | displayFileName: true, 36 | currentIndex: 0, 37 | files: [], 38 | }; 39 | }, 40 | 41 | computed: { 42 | currentImage() { 43 | const files = this.get("files"); 44 | const currentIndex = this.get("currentIndex"); 45 | 46 | return files[currentIndex] || ""; 47 | }, 48 | 49 | previousButtonHidden(){ 50 | return !this.hasPreviousImage() ? "hidden" : ""; 51 | }, 52 | 53 | nextButtonHidden(){ 54 | return !this.hasNextImage() ? "hidden" : ""; 55 | } 56 | }, 57 | 58 | onconfig() { 59 | const self = this; 60 | 61 | this.toggleColorPicker = this.toggleColorPicker.bind(this); 62 | this.toggleFullscreen = this.toggleFullscreen.bind(this); 63 | this.handleMouseWheel = this.handleMouseWheel.bind(this); 64 | this.savePreferences = this.savePreferences.bind(this); 65 | this.toggleFilename = this.toggleFilename.bind(this); 66 | this.deleteFile = this.deleteFile.bind(this); 67 | this.trashFile = this.trashFile.bind(this); 68 | 69 | this.loadPreferences(); 70 | 71 | this.on({ 72 | input(ctx, data) { 73 | const { files, index } = this.parseInput(data); 74 | 75 | this.set("files", files); 76 | this.set("currentIndex", index); 77 | }, 78 | 79 | previousImage() { 80 | if (this.hasPreviousImage()) { 81 | this.subtract("currentIndex"); 82 | } 83 | }, 84 | 85 | nextImage() { 86 | if (this.hasNextImage()) { 87 | this.add("currentIndex"); 88 | } 89 | }, 90 | 91 | escape() { 92 | if (this.get("colorPickerVisible")) { 93 | this.toggle("colorPickerVisible"); 94 | } else if (this.get("maximized")) { 95 | ipcRenderer.send("unmaximize"); 96 | } else { 97 | ipcRenderer.send("quit"); 98 | } 99 | }, 100 | }); 101 | 102 | Mousetrap.bind(["left"], () => this.fire("previousImage")); 103 | Mousetrap.bind(["right"], () => this.fire("nextImage")); 104 | Mousetrap.bind(["escape"], () => this.fire("escape")); 105 | 106 | Mousetrap.bind(["b"], () => this.setBackgroundColor("#000000")); 107 | Mousetrap.bind(["w"], () => this.setBackgroundColor("#ffffff")); 108 | Mousetrap.bind(["g"], () => this.setBackgroundColor("#888888")); 109 | 110 | Mousetrap.bind(["f"], this.toggleFullscreen); 111 | Mousetrap.bind(["n"], this.toggleFilename); 112 | Mousetrap.bind(["c"], this.toggleColorPicker); 113 | 114 | Mousetrap.bind(["del", "command+backspace"], this.trashFile); 115 | Mousetrap.bind(["shift+del", "shift+command+backspace"], this.deleteFile); 116 | 117 | Hamster(document).wheel(this.handleMouseWheel); 118 | 119 | this.fire("input", inputPath); 120 | }, 121 | 122 | loadPreferences() { 123 | const { 124 | backgroundColor, 125 | displayFileName, 126 | } = store.get(); 127 | 128 | if (backgroundColor) { 129 | this.set({ backgroundColor} ); 130 | } 131 | 132 | if (typeof displayFileName === "boolean") { 133 | this.set({ displayFileName }); 134 | } 135 | }, 136 | 137 | calculateNextIndex(currentIndex) { 138 | const files = this.get("files"); 139 | const len = files.length; 140 | const isLastImage = (currentIndex === len-1); 141 | const isFirstImage = (currentIndex === 0); 142 | 143 | let nextIndex = currentIndex; 144 | 145 | if (isLastImage) { 146 | nextIndex = currentIndex - 1; 147 | } else if (isFirstImage) { 148 | nextIndex = 0; 149 | } 150 | 151 | return nextIndex; 152 | }, 153 | 154 | trashFile() { 155 | if (confirm("Move current file to trash/recycle bin?")) { 156 | this._deleteFile(false); 157 | } 158 | }, 159 | 160 | deleteFile() { 161 | if (confirm("Permanently delete current file?")) { 162 | this._deleteFile("permanent"); 163 | } 164 | }, 165 | 166 | _deleteFile(permanent = false) { 167 | const currentImage = this.get("currentImage"); 168 | const currentIndex = this.get("currentIndex"); 169 | const nextIndex = this.calculateNextIndex(currentIndex); 170 | const deleter = permanent ? jetpack.removeAsync : trash; 171 | 172 | deleter(currentImage).then((data) => { 173 | this.splice("files", currentIndex, 1); 174 | this.set("currentIndex", nextIndex); 175 | }); 176 | }, 177 | 178 | setBackgroundColor(color) { 179 | this.set("backgroundColor", color); 180 | }, 181 | 182 | savePreferences(w) { 183 | const { backgroundColor, displayFileName } = this.get(); 184 | 185 | store.set({ 186 | backgroundColor, 187 | displayFileName, 188 | }); 189 | }, 190 | 191 | toggleColorPicker() { 192 | this.toggle("colorPickerVisible"); 193 | }, 194 | 195 | parseInput(inputPath = "", dir = cwd) { 196 | if (!path.isAbsolute(inputPath)) { 197 | inputPath = path.resolve(dir, inputPath); 198 | } 199 | 200 | let files = []; 201 | let index = 0; 202 | let inputFile = ""; 203 | let inputDir = inputPath; 204 | 205 | if (jetpack.exists(inputPath)) { 206 | if (this.isDisplayableImage(inputPath)) { 207 | inputFile = path.basename(inputPath); 208 | inputDir = path.dirname(inputPath); 209 | } 210 | 211 | if (this.isDirectory(inputDir)) { 212 | files = jetpack.list(inputDir) 213 | .filter(this.isDisplayableImage) 214 | .map((fileName) => path.join(inputDir, fileName)); 215 | } 216 | 217 | if (files.length && inputFile) { 218 | index = files.indexOf(path.join(inputDir, inputFile)); 219 | } 220 | } 221 | 222 | return { 223 | files: files.map(this.slash).map(this.encodeChars), 224 | index: index 225 | }; 226 | }, 227 | 228 | isDisplayableImage(inputPath) { 229 | const ext = path.extname(inputPath).slice(1); 230 | return ext && displayableExtensions.indexOf(ext) > -1; 231 | }, 232 | 233 | isDirectory(inputPath) { 234 | return jetpack.exists(inputPath) === "dir"; 235 | }, 236 | 237 | slash(str) { 238 | return str.replace(/\\/g, "/"); 239 | }, 240 | 241 | encodeChars(str) { 242 | return str.replace(/\s/g, "%20"); 243 | }, 244 | 245 | handleMouseWheel(e, d, dx, dy){ 246 | const cmd = (dy === 1) ? "previousImage" : "nextImage"; 247 | 248 | this.fire(cmd); 249 | }, 250 | 251 | toggleFullscreen() { 252 | const maximized = this.get("maximized"); 253 | const cmd = maximized ? "unmaximize" : "maximize"; 254 | 255 | ipcRenderer.send(cmd); 256 | }, 257 | 258 | toggleFilename() { 259 | this.toggle("displayFileName"); 260 | }, 261 | 262 | hasNextImage() { 263 | const i = this.get("currentIndex"); 264 | const files = this.get("files"); 265 | const len = files.length - 1; 266 | 267 | return i < len; 268 | }, 269 | 270 | hasPreviousImage() { 271 | const i = this.get("currentIndex"); 272 | 273 | return i > 0; 274 | } 275 | }); 276 | 277 | 278 | 279 | remote.getCurrentWindow().on("close", app.savePreferences); 280 | 281 | 282 | 283 | /* Handle messages from BrowserWindow processes */ 284 | ipcRenderer.on("maximize", () => { 285 | app.set("maximized", true); 286 | }); 287 | 288 | ipcRenderer.on("unmaximize", () => { 289 | app.set("maximized", false); 290 | }); 291 | 292 | 293 | 294 | /* Drag&drop to open a file/folder */ 295 | document.ondragover = document.ondrop = (e) => { 296 | e.preventDefault(); 297 | }; 298 | 299 | document.ondragover = (e) => { 300 | e.preventDefault(); 301 | app.set("dragover", true); 302 | }; 303 | 304 | document.ondragleave = document.ondragexit = document.ondragend = (e) => { 305 | e.preventDefault(); 306 | app.set("dragover", false); 307 | }; 308 | 309 | document.body.ondrop = (e) => { 310 | e.preventDefault(); 311 | 312 | const inputPath = e.dataTransfer.files[0].path; 313 | 314 | app.fire("input", inputPath); 315 | app.set("dragover", false); 316 | }; 317 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SVG Viewer 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/js/lib/version.js: -------------------------------------------------------------------------------- 1 | // generated by genversion 2 | module.exports = '0.3.0'; 3 | -------------------------------------------------------------------------------- /app/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 | -------------------------------------------------------------------------------- /app/photon/fonts/photon-entypo.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesqe/electron-image-viewer/e856f4d28e09979c85bcf5840b0a938bd26e6fb9/app/photon/fonts/photon-entypo.eot -------------------------------------------------------------------------------- /app/photon/fonts/photon-entypo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright (C) 2015 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | -------------------------------------------------------------------------------- /app/photon/fonts/photon-entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesqe/electron-image-viewer/e856f4d28e09979c85bcf5840b0a938bd26e6fb9/app/photon/fonts/photon-entypo.ttf -------------------------------------------------------------------------------- /app/photon/fonts/photon-entypo.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesqe/electron-image-viewer/e856f4d28e09979c85bcf5840b0a938bd26e6fb9/app/photon/fonts/photon-entypo.woff -------------------------------------------------------------------------------- /app/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | } 4 | 5 | [disabled] { 6 | opacity: 0.75; 7 | pointer-events: none; 8 | } 9 | 10 | .window { 11 | background-color: #fff; 12 | transition: background-color 0.2s; 13 | box-shadow: inset 0 0 2px rgba(125, 74, 74, 0.22) 14 | } 15 | 16 | .maximized { 17 | background-color: #000; 18 | } 19 | 20 | .window::after { 21 | content: ""; 22 | width: 100%; 23 | height: 100%; 24 | position: absolute; 25 | top: 0; 26 | left: 0; 27 | background-color: transparent; 28 | transition: background-color 0.25s; 29 | } 30 | 31 | .dragover::after { 32 | z-index: 10; 33 | background-color: rgba(211, 211, 211, 0.85); 34 | } 35 | 36 | #display { 37 | width: 100vw; 38 | height: calc(100vh - 35px); 39 | margin-top: 35px; 40 | background-repeat: no-repeat; 41 | background-size: contain; 42 | background-position: center; 43 | } 44 | 45 | .maximized #display { 46 | height: 100vh; 47 | margin-top: 0; 48 | } 49 | 50 | header { 51 | position: fixed; 52 | z-index: 2; 53 | width: 100%; 54 | top: 0; 55 | } 56 | 57 | .maximized header { 58 | display: none; 59 | -webkit-drag: none; 60 | } 61 | 62 | #current-of-display { 63 | min-width: 100px; 64 | box-shadow: none; 65 | } 66 | 67 | #drag-drop { 68 | display: flex; 69 | align-items: center; 70 | text-align: center; 71 | width: 100%; 72 | } 73 | 74 | #drag-drop p { 75 | width: 100%; 76 | color: darkgray; 77 | transition: color 0.25s; 78 | } 79 | 80 | .dragover #drag-drop p { 81 | color: black; 82 | } 83 | 84 | .color-picker { 85 | position: absolute; 86 | left: 0; 87 | top: 0; 88 | z-index: -1; 89 | width: 100%; 90 | height: 100%; 91 | opacity: 0; 92 | transition: opacity 0.2s; 93 | } 94 | 95 | .color-picker-visible .color-picker { 96 | z-index: 3; 97 | opacity: 1; 98 | } 99 | 100 | .color-picker input { 101 | width: 100px; 102 | height: 100px; 103 | position: absolute; 104 | left: calc(50% - 50px); 105 | top: calc(50% - 50px); 106 | padding: 3px 5px; 107 | } 108 | 109 | .filename { 110 | color: #00FF00; 111 | padding: 2px 5px; 112 | } 113 | -------------------------------------------------------------------------------- /app/template.html: -------------------------------------------------------------------------------- 1 |
7 | 8 | {{#if files.length}} 9 |
10 |
11 |
12 | 19 | 20 | {{currentIndex+1}} of {{files.length}} 21 | 22 | 29 |
30 |
31 |
32 | {{/if}} 33 | 34 |
35 | {{#if files.length}} 36 |
40 | {{#if displayFileName}} 41 |
42 | {{currentImage}} 43 |
44 | {{/if}} 45 |
46 | {{else}} 47 |
48 |

49 | Drag and drop a file or folder onto this window to start 50 |

51 |
52 | {{/if}} 53 |
54 | 55 |
56 | 57 |
58 | 59 |
60 | -------------------------------------------------------------------------------- /build/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesqe/electron-image-viewer/e856f4d28e09979c85bcf5840b0a938bd26e6fb9/build/background.png -------------------------------------------------------------------------------- /build/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesqe/electron-image-viewer/e856f4d28e09979c85bcf5840b0a938bd26e6fb9/build/icon.icns -------------------------------------------------------------------------------- /build/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesqe/electron-image-viewer/e856f4d28e09979c85bcf5840b0a938bd26e6fb9/build/icon.ico -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesqe/electron-image-viewer/e856f4d28e09979c85bcf5840b0a938bd26e6fb9/images/icon.png -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | const { app, BrowserWindow } = require("electron"); 2 | const { createMainWindow } = require("./window.js"); 3 | 4 | let mainWindow = null; 5 | 6 | app.on("window-all-closed", function () { 7 | if (process.platform !== "darwin") { 8 | app.quit(); 9 | } 10 | }); 11 | 12 | app.on("activate-with-no-open-windows", function () { 13 | if (!mainWindow) { 14 | mainWindow = createMainWindow(); 15 | } 16 | }); 17 | 18 | app.on("ready", function () { 19 | mainWindow = createMainWindow(); 20 | 21 | if (process.env.NODE_ENV === "development") { 22 | mainWindow.openDevTools(); 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-image-viewer", 3 | "productName": "electron-image-viewer", 4 | "version": "0.3.0", 5 | "description": "Image viewer", 6 | "main": "main.js", 7 | "author": "aesqe", 8 | "license": "ISC", 9 | "scripts": { 10 | "genver": "genversion app/js/lib/version.js", 11 | "start": "cross-env NODE_ENV=production electron .", 12 | "dev": "npm run genver && cross-env NODE_ENV=development electron .", 13 | "pack": "npm run genver && electron-builder --dir", 14 | "dist": "npm run genver && electron-builder", 15 | "postinstall": "electron-builder install-app-deps" 16 | }, 17 | "dependencies": { 18 | "electron-store": "1.3.0", 19 | "fs-jetpack": "1.3.0", 20 | "hamsterjs": "1.1.2", 21 | "mousetrap": "1.6.0", 22 | "ractive": "^0.9.13", 23 | "ractive-events-tap": "0.3.1", 24 | "trash": "4.2.1" 25 | }, 26 | "devDependencies": { 27 | "cross-env": "5.1.3", 28 | "electron": "1.8.2", 29 | "electron-builder": "20.2.0", 30 | "electron-packager": "11.0.1", 31 | "genversion": "2.0.1" 32 | }, 33 | "build": { 34 | "appId": "electronImageViewer", 35 | "directories": { 36 | "output": "dist" 37 | }, 38 | "mac": { 39 | "target": [ 40 | "zip" 41 | ], 42 | "category": "public.app-category.utilities" 43 | }, 44 | "win": { 45 | "target": [ 46 | "nsis", 47 | "zip" 48 | ] 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /window.js: -------------------------------------------------------------------------------- 1 | const { app, BrowserWindow } = require("electron"); 2 | const ElectronStore = require("electron-store"); 3 | const { ipcMain } = require("electron"); 4 | 5 | module.exports = { 6 | createMainWindow() { 7 | const store = new ElectronStore(); 8 | 9 | let lastWindowState = store.get("lastWindowState"); 10 | 11 | if (!lastWindowState) { 12 | lastWindowState = { 13 | x: 0, 14 | y: 0, 15 | width: 800, 16 | height: 600, 17 | maximized: false, 18 | }; 19 | 20 | store.set("lastWindowState", lastWindowState); 21 | } 22 | 23 | let win = new BrowserWindow({ 24 | title: "Electron image viewer", 25 | icon: "images/icon.png", 26 | position: "center", 27 | x: lastWindowState.x, 28 | y: lastWindowState.y, 29 | width: lastWindowState.width, 30 | height: lastWindowState.height, 31 | overlayScrollbars: true, 32 | resizable: true, 33 | toolbar: true, 34 | transparent: false, 35 | fullscreen: false, 36 | frame: false, 37 | show: false, 38 | }); 39 | 40 | win.setMenu(null); 41 | 42 | if (lastWindowState.maximized) { 43 | win.maximize(); 44 | } 45 | 46 | win.on("close", () => { 47 | const maximized = win.isMaximized(); 48 | 49 | // avoid setting width and height to screen w/h values 50 | win.unmaximize(); 51 | 52 | const bounds = win.getBounds(); 53 | const { x, y, width, height } = bounds; 54 | const windowState = { 55 | maximized, 56 | width, 57 | height, 58 | x, 59 | y, 60 | }; 61 | 62 | store.set("lastWindowState", windowState); 63 | }); 64 | 65 | win.on("unresponsive", (e) => console.log(e)); 66 | win.webContents.on("crashed", (e) => console.log(e)); 67 | process.on("uncaughtException", (e) => console.log(e)); 68 | 69 | win.webContents.on("did-finish-load", () => win.show()); 70 | 71 | win.on("maximize", () => win.webContents.send("maximize")); 72 | win.on("unmaximize", () => win.webContents.send("unmaximize")); 73 | 74 | ipcMain.on("maximize", () => win.maximize()); 75 | ipcMain.on("unmaximize", () => win.unmaximize()); 76 | 77 | win.on("closed", () => setTimeout(() => (win = null), 250)); 78 | ipcMain.on("quit", () => { 79 | win.closeDevTools(); 80 | app.quit(); 81 | }); 82 | 83 | win.loadURL("file://" + __dirname + "/app/index.html"); 84 | 85 | return win; 86 | } 87 | }; 88 | --------------------------------------------------------------------------------