├── .gitignore ├── docs ├── GUIwrapper.png └── README.md ├── assets └── icons │ ├── win │ └── icon.ico │ ├── mac │ └── icon.icns │ ├── png │ ├── 16x16.png │ ├── 24x24.png │ ├── 32x32.png │ ├── 48x48.png │ ├── 64x64.png │ ├── 96x96.png │ ├── 1024x1024.png │ ├── 128x128.png │ ├── 256x256.png │ └── 512x512.png │ └── Icon.svg ├── .gitmodules ├── src ├── javascript │ ├── license.js │ ├── darkMode.js │ ├── dialog.js │ ├── mainmenu.js │ ├── main.js │ └── renderer.js ├── css │ ├── style.css │ ├── roller.css │ └── dark-mode.css └── html │ └── index.html ├── .github └── dependabot.yml ├── LICENSE.md ├── package.json └── Dependencies └── bootstrap-4.6.1-dist ├── css ├── bootstrap-reboot.min.css ├── bootstrap-reboot.css ├── bootstrap-reboot.min.css.map └── bootstrap-grid.min.css └── js └── bootstrap.min.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode -------------------------------------------------------------------------------- /docs/GUIwrapper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frodal/GUIwrapper/HEAD/docs/GUIwrapper.png -------------------------------------------------------------------------------- /assets/icons/win/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frodal/GUIwrapper/HEAD/assets/icons/win/icon.ico -------------------------------------------------------------------------------- /assets/icons/mac/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frodal/GUIwrapper/HEAD/assets/icons/mac/icon.icns -------------------------------------------------------------------------------- /assets/icons/png/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frodal/GUIwrapper/HEAD/assets/icons/png/16x16.png -------------------------------------------------------------------------------- /assets/icons/png/24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frodal/GUIwrapper/HEAD/assets/icons/png/24x24.png -------------------------------------------------------------------------------- /assets/icons/png/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frodal/GUIwrapper/HEAD/assets/icons/png/32x32.png -------------------------------------------------------------------------------- /assets/icons/png/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frodal/GUIwrapper/HEAD/assets/icons/png/48x48.png -------------------------------------------------------------------------------- /assets/icons/png/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frodal/GUIwrapper/HEAD/assets/icons/png/64x64.png -------------------------------------------------------------------------------- /assets/icons/png/96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frodal/GUIwrapper/HEAD/assets/icons/png/96x96.png -------------------------------------------------------------------------------- /assets/icons/png/1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frodal/GUIwrapper/HEAD/assets/icons/png/1024x1024.png -------------------------------------------------------------------------------- /assets/icons/png/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frodal/GUIwrapper/HEAD/assets/icons/png/128x128.png -------------------------------------------------------------------------------- /assets/icons/png/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frodal/GUIwrapper/HEAD/assets/icons/png/256x256.png -------------------------------------------------------------------------------- /assets/icons/png/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frodal/GUIwrapper/HEAD/assets/icons/png/512x512.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Dependencies/Montserrat"] 2 | path = Dependencies/Montserrat 3 | url = https://github.com/JulietaUla/Montserrat.git 4 | -------------------------------------------------------------------------------- /src/javascript/license.js: -------------------------------------------------------------------------------- 1 | 2 | const defaultLicenseString = 'Copyright (c) 2019-2022 Bjørn Håkon Frodal'; 3 | let licenseString = ''; 4 | 5 | function GetLicense() { 6 | if (licenseString === '') { 7 | try { 8 | const fs = require('fs'); 9 | const path = require('path'); 10 | licenseString = fs.readFileSync(path.join(__dirname, '../../LICENSE.md')); 11 | } catch (err) { 12 | licenseString = defaultLicenseString; 13 | } 14 | } 15 | return licenseString; 16 | }; 17 | 18 | exports.GetLicense = GetLicense; -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | - package-ecosystem: "gitsubmodule" # See documentation for possible values 13 | directory: "/" # Location of package manifests 14 | schedule: 15 | interval: "monthly" 16 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2022 Bjørn Håkon Frodal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /src/css/style.css: -------------------------------------------------------------------------------- 1 | /* Import Montserrat font */ 2 | @import url('../../Dependencies/Montserrat/fonts/webfonts/Montserrat.css'); 3 | html { 4 | overflow-y: scroll; 5 | } 6 | /* Main content area */ 7 | #main { 8 | padding: 32px; 9 | padding-top: 80px; 10 | font-family: 'Montserrat'; 11 | } 12 | /* Draggable and selectable regions */ 13 | body { 14 | -webkit-app-region: drag; 15 | user-select: none; 16 | -webkit-user-select: none; 17 | } 18 | .lead{ 19 | margin-bottom: 2.5em; 20 | } 21 | button { 22 | -webkit-app-region: no-drag; 23 | } 24 | input { 25 | -webkit-app-region: no-drag; 26 | } 27 | .textfile { 28 | font-family: monospace; 29 | -webkit-app-region: no-drag; 30 | user-select: text; 31 | -webkit-user-select: text; 32 | white-space: pre; 33 | width: fit-content; 34 | padding-right: 5px; 35 | padding-left: 5px; 36 | margin-bottom: 3em; 37 | } 38 | .btn-container { 39 | display: flex; 40 | align-items: center; 41 | height: 32px; 42 | } 43 | .btn-container button { 44 | margin-right: 6px; 45 | } 46 | /* Scroll bar*/ 47 | ::-webkit-scrollbar { 48 | width: 12px; 49 | height: 12px; 50 | } 51 | ::-webkit-scrollbar-thumb { 52 | background-color: #6c757d; 53 | } 54 | ::-webkit-scrollbar-thumb:hover { 55 | background: #5a6268; 56 | } 57 | -------------------------------------------------------------------------------- /src/css/roller.css: -------------------------------------------------------------------------------- 1 | .lds-roller { 2 | display: inline-block; 3 | position: relative; 4 | width: 32px; 5 | height: 32px; 6 | } 7 | .lds-roller div { 8 | animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; 9 | transform-origin: 16px 16px; 10 | } 11 | .lds-roller div:after { 12 | content: ' '; 13 | display: block; 14 | position: absolute; 15 | width: 3px; 16 | height: 3px; 17 | border-radius: 50%; 18 | background: #000; 19 | margin: -1px 0 0 -1px; 20 | } 21 | .lds-roller div:nth-child(1) { 22 | animation-delay: -0.036s; 23 | } 24 | .lds-roller div:nth-child(1):after { 25 | top: 25px; 26 | left: 25px; 27 | } 28 | .lds-roller div:nth-child(2) { 29 | animation-delay: -0.072s; 30 | } 31 | .lds-roller div:nth-child(2):after { 32 | top: 27px; 33 | left: 22px; 34 | } 35 | .lds-roller div:nth-child(3) { 36 | animation-delay: -0.108s; 37 | } 38 | .lds-roller div:nth-child(3):after { 39 | top: 28px; 40 | left: 19px; 41 | } 42 | .lds-roller div:nth-child(4) { 43 | animation-delay: -0.144s; 44 | } 45 | .lds-roller div:nth-child(4):after { 46 | top: 29px; 47 | left: 16px; 48 | } 49 | .lds-roller div:nth-child(5) { 50 | animation-delay: -0.18s; 51 | } 52 | .lds-roller div:nth-child(5):after { 53 | top: 28px; 54 | left: 13px; 55 | } 56 | .lds-roller div:nth-child(6) { 57 | animation-delay: -0.216s; 58 | } 59 | .lds-roller div:nth-child(6):after { 60 | top: 27px; 61 | left: 10px; 62 | } 63 | .lds-roller div:nth-child(7) { 64 | animation-delay: -0.252s; 65 | } 66 | .lds-roller div:nth-child(7):after { 67 | top: 25px; 68 | left: 7px; 69 | } 70 | .lds-roller div:nth-child(8) { 71 | animation-delay: -0.288s; 72 | } 73 | .lds-roller div:nth-child(8):after { 74 | top: 22px; 75 | left: 5px; 76 | } 77 | @keyframes lds-roller { 78 | 0% { 79 | transform: rotate(0deg); 80 | } 81 | 100% { 82 | transform: rotate(360deg); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/javascript/darkMode.js: -------------------------------------------------------------------------------- 1 | // Initialize the dark mode in the Main process 2 | function Initialize() { 3 | const { ipcMain, nativeTheme } = require('electron'); 4 | ipcMain.handle('dark-mode:switch', (e, shouldUseDarkColors) => { 5 | if (shouldUseDarkColors) { 6 | nativeTheme.themeSource = 'dark'; 7 | } else { 8 | nativeTheme.themeSource = 'light'; 9 | } 10 | return nativeTheme.shouldUseDarkColors; 11 | }); 12 | ipcMain.handle('dark-mode:isDarkMode', () => { 13 | return nativeTheme.shouldUseDarkColors; 14 | }); 15 | } 16 | 17 | // Handle the dark mode in the Renderer process 18 | function HandleDarkMode() { 19 | const { ipcRenderer } = require('electron'); 20 | let darkSwitch = document.getElementById("darkSwitch"); 21 | if (!darkSwitch) 22 | return 23 | initTheme(); 24 | darkSwitch.addEventListener("change", function (event) { 25 | resetTheme(); 26 | }); 27 | 28 | function initTheme() { 29 | if (localStorage.getItem("darkSwitch") === null) { 30 | // Sets the theme based on system preferences 31 | ipcRenderer.invoke('dark-mode:isDarkMode').then((darkThemeSelected) => { 32 | darkSwitch.checked = darkThemeSelected; 33 | ipcRenderer.invoke('dark-mode:switch', darkThemeSelected) 34 | }); 35 | } else { 36 | // Sets the theme based on previously set state 37 | let darkThemeSelected = localStorage.getItem("darkSwitch") === "dark"; 38 | darkSwitch.checked = darkThemeSelected; 39 | ipcRenderer.invoke('dark-mode:switch', darkThemeSelected) 40 | } 41 | } 42 | 43 | function resetTheme() { 44 | let darkThemeSelected = darkSwitch.checked; 45 | ipcRenderer.invoke('dark-mode:switch', darkThemeSelected) 46 | if (darkThemeSelected) { 47 | localStorage.setItem("darkSwitch", "dark"); 48 | } else { 49 | localStorage.setItem("darkSwitch", "light"); 50 | } 51 | } 52 | } 53 | 54 | exports.Initialize = Initialize; 55 | exports.HandleDarkMode = HandleDarkMode; -------------------------------------------------------------------------------- /src/javascript/dialog.js: -------------------------------------------------------------------------------- 1 | const { ipcMain, dialog, BrowserWindow } = require('electron'); 2 | 3 | // Open file dialog to open file 4 | ipcMain.on('open-file-dialog', (event) => { 5 | dialog.showOpenDialog(BrowserWindow.getFocusedWindow(), 6 | { 7 | filters: [{ name: 'All files', extensions: ['*'] }], 8 | properties: ['openFile'] 9 | }).then((files) => { 10 | if (!files.canceled) { 11 | event.sender.send('SelectedFile', files.filePaths); 12 | } 13 | }); 14 | }); 15 | 16 | // Opens an error dialog message 17 | ipcMain.on('open-error-dialog', (event) => { 18 | dialog.showErrorBox('Error', 'Could not execute the selected program!\nPlease select a valid executable program'); 19 | }); 20 | // Opens an error dialog message 21 | ipcMain.on('open-errorEXE-dialog', (event) => { 22 | dialog.showErrorBox('Error', 'Could not execute the selected program!'); 23 | }); 24 | // Opens an error dialog message 25 | ipcMain.on('open-errorKilled-dialog', (event) => { 26 | dialog.showErrorBox('Error', 'An error occured while executing the program!\nSee the ouput for details.'); 27 | }); 28 | 29 | // Opens a warning dialog message 30 | ipcMain.on('open-warning-dialog', (event) => { 31 | const options = 32 | { 33 | type: "info", 34 | title: "Warning", 35 | message: "Please select an executable file first!", 36 | buttons: ['Ok'] 37 | }; 38 | dialog.showMessageBox(BrowserWindow.getFocusedWindow(), options); 39 | }); 40 | 41 | // Opens a warning dialog message 42 | ipcMain.on('open-isRunning-dialog', (event) => { 43 | const options = 44 | { 45 | type: "info", 46 | title: "Warning", 47 | message: "Please terminate the running application before starting a new one", 48 | buttons: ['Ok'] 49 | }; 50 | dialog.showMessageBox(BrowserWindow.getFocusedWindow(), options); 51 | }) 52 | 53 | // Opens a success dialog message 54 | ipcMain.on('open-successfulTermination-dialog', (event) => { 55 | const options = 56 | { 57 | type: "info", 58 | title: "Success", 59 | message: "Application terminated successfully", 60 | buttons: ['Ok'] 61 | }; 62 | dialog.showMessageBox(BrowserWindow.getFocusedWindow(), options); 63 | }) -------------------------------------------------------------------------------- /src/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GUIwrapper 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |

GUIwrapper

16 |
17 | 18 | 19 |
20 |

21 | A simple cross platform graphical user interface wrapper to launch executable desktop applications 22 |

23 |

24 | 25 |

26 |

27 | Selected file: 28 |

29 |

30 |

31 | Additional input arguments: 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 | Output: 58 |

59 |

60 |
61 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/css/dark-mode.css: -------------------------------------------------------------------------------- 1 | /* CSS variables used in dark mode */ 2 | :root { 3 | --dark-mode-bg-color: rgb(30, 30, 30); 4 | --dark-mode-input-color: rgb(45, 45, 45); 5 | --dark-mode-btn-color: rgb(60, 60, 60); 6 | --dark-mode-text-color: rgb(190, 190, 190); 7 | } 8 | 9 | @media (prefers-color-scheme: dark) { 10 | /* Set the color of the body element in dark mode */ 11 | body { 12 | background-color: var(--dark-mode-bg-color) !important; 13 | color: var(--dark-mode-text-color) !important; 14 | } 15 | 16 | /* Set the color of the bg-dark class in dark mode */ 17 | .bg-dark { 18 | background-color: var(--dark-mode-input-color) !important; 19 | } 20 | 21 | /* Set the color of the text-light class in dark mode */ 22 | .text-light { 23 | color: var(--dark-mode-text-color) !important; 24 | } 25 | 26 | /* Set the color of the text input fields in dark mode */ 27 | input[type='text'] { 28 | background-color: var(--dark-mode-input-color) !important; 29 | border-color: var(--dark-mode-btn-color) !important; 30 | color: var(--dark-mode-text-color) !important; 31 | } 32 | .input-group-text { 33 | background-color: var(--dark-mode-bg-color) !important; 34 | border-color: var(--dark-mode-btn-color) !important; 35 | color: var(--dark-mode-text-color) !important; 36 | } 37 | 38 | /* Set the color of the dropdown menu in dark mode */ 39 | .form-control { 40 | background-color: var(--dark-mode-input-color) !important; 41 | border-color: var(--dark-mode-btn-color) !important; 42 | color: var(--dark-mode-text-color) !important; 43 | } 44 | 45 | /* Set the color of the buttons in dark mode */ 46 | .btn-secondary { 47 | background-color: var(--dark-mode-btn-color) !important; 48 | border-color: var(--dark-mode-btn-color) !important; 49 | color: var(--dark-mode-text-color) !important; 50 | } 51 | .btn-secondary:hover:enabled { 52 | background-color: var(--dark-mode-input-color) !important; 53 | border-color: var(--dark-mode-input-color) !important; 54 | } 55 | 56 | /* Set the color of the GUI badge */ 57 | .badge-secondary { 58 | background-color: var(--dark-mode-btn-color) !important; 59 | color: var(--dark-mode-text-color) !important; 60 | } 61 | 62 | /* Set the color of the roller in dark mode */ 63 | .lds-roller div:after { 64 | background: var(--dark-mode-text-color) !important; 65 | } 66 | 67 | /* Set the scrollbar color in dark mode */ 68 | ::-webkit-scrollbar-thumb { 69 | background-color: var(--dark-mode-btn-color); 70 | } 71 | ::-webkit-scrollbar-thumb:hover { 72 | background: var(--dark-mode-input-color); 73 | } 74 | } 75 | 76 | /* On screens that are 450px or greater */ 77 | @media screen and (min-width: 450px) { 78 | /* Position the dark mode button to the right */ 79 | .custom-switch { 80 | margin-left: 1em; 81 | float: right; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "guiwrapper", 3 | "productName": "GUIwrapper", 4 | "description": "A simple cross platform GUI wrapper to launch executable desktop applications", 5 | "keywords": [ 6 | "GUI", 7 | "wrapper", 8 | "cross platform", 9 | "desktop applications" 10 | ], 11 | "main": "./src/javascript/main.js", 12 | "version": "0.7.4", 13 | "author": "Bjørn Håkon Frodal", 14 | "license": "MIT", 15 | "homepage": "https://github.com/frodal/GUIwrapper", 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/frodal/GUIwrapper.git" 19 | }, 20 | "scripts": { 21 | "start": "electron .", 22 | "build": "npm run build-win && npm run build-linux64 && npm run build-darwin64", 23 | "build-debug": "set DEBUG=electron-packager && npm run build", 24 | "build-win": "electron-packager ./ --overwrite --asar --prune=true --platform=win32 --arch=all --no-tmpdir --icon=assets/icons/win/icon.ico --out=../GUIwrapperBinaries/", 25 | "build-win32": "electron-packager ./ --overwrite --asar --prune=true --platform=win32 --arch=ia32 --no-tmpdir --icon=assets/icons/win/icon.ico --out=../GUIwrapperBinaries/", 26 | "build-win64": "electron-packager ./ --overwrite --asar --prune=true --platform=win32 --arch=x64 --no-tmpdir --icon=assets/icons/win/icon.ico --out=../GUIwrapperBinaries/", 27 | "build-linux64": "electron-packager ./ --overwrite --asar --prune=true --platform=linux --arch=x64 --no-tmpdir --icon=assets/icons/png/1024x1024.png --out=../GUIwrapperBinaries/", 28 | "build-darwin64": "electron-packager ./ --overwrite --asar --prune=true --platform=darwin --arch=x64 --no-tmpdir --icon=assets/icons/mac/icon.icns --out=../GUIwrapperBinaries/ --darwinDarkModeSupport=true", 29 | "setup": "npm run setup-win", 30 | "setup-win": "npm run setup-win32 && npm run setup-win64", 31 | "setup-win32": "electron-installer-windows --src=../GUIwrapperBinaries/GUIwrapper-win32-ia32/ --dest=../GUIwrapperBinaries/installer-ia32/ --icon=./assets/icons/win/icon.ico", 32 | "setup-win64": "electron-installer-windows --src=../GUIwrapperBinaries/GUIwrapper-win32-x64/ --dest=../GUIwrapperBinaries/installer-x64/ --icon=./assets/icons/win/icon.ico", 33 | "setup-debian": "electron-installer-debian --src=../GUIwrapperBinaries/GUIwrapper-linux-x64/ --dest=../GUIwrapperBinaries/debian/ --arch=amd64 --icon=./assets/icons/png/1024x1024.png", 34 | "gen-icons": "npm run gen-icon-win && npm run gen-icon-mac", 35 | "gen-icon-win": "icon-gen --input ./assets/icons/Icon.svg --output ./assets/icons/win --ico name=icon --report", 36 | "gen-icon-mac": "icon-gen --input ./assets/icons/Icon.svg --output ./assets/icons/mac --icns name=icon --report" 37 | }, 38 | "dependencies": { 39 | "about-window": "^1.15.2", 40 | "electron-squirrel-startup": "^1.0.1", 41 | "update-electron-app": "^3.0.0" 42 | }, 43 | "devDependencies": { 44 | "electron": "^31.3.1", 45 | "electron-installer-windows": "^3.0.0", 46 | "electron-packager": "^17.1.2", 47 | "icon-gen": "^5.0.0" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/javascript/mainmenu.js: -------------------------------------------------------------------------------- 1 | const { app, Menu, shell, dialog, nativeImage, BrowserWindow } = require('electron'); 2 | const path = require('path'); 3 | 4 | const appName = app.getName(); 5 | const appIconPath = path.join(__dirname, '../../assets/icons/png/512x512.png'); 6 | const appIcon = nativeImage.createFromPath(appIconPath) 7 | const bugReportURL = 'https://github.com/frodal/GUIwrapper/issues'; 8 | 9 | function CreateMenu() { 10 | const template = [ 11 | { 12 | role: 'window', 13 | submenu: [ 14 | { 15 | role: 'reload' 16 | }, 17 | { 18 | type: 'separator' 19 | }, 20 | { 21 | role: 'togglefullscreen' 22 | }, 23 | { 24 | type: 'separator' 25 | }, 26 | { 27 | role: 'minimize' 28 | }, 29 | { 30 | role: 'close' 31 | } 32 | ] 33 | }, 34 | { 35 | role: 'help', 36 | submenu: [ 37 | { 38 | label: 'Report Issue', 39 | click() { shell.openExternal(bugReportURL) } 40 | }, 41 | { 42 | label: 'View License', 43 | click() { 44 | const { GetLicense } = require('./license'); 45 | dialog.showMessageBox(BrowserWindow.getFocusedWindow(), { 46 | type: "info", 47 | title: 'License', 48 | message: appName + " License\n\n" + 49 | GetLicense(), 50 | buttons: ['Ok'], 51 | icon: appIcon 52 | }); 53 | } 54 | }, 55 | { 56 | type: 'separator' 57 | }, 58 | { 59 | label: 'Learn More', 60 | click() { shell.openExternal('https://github.com/frodal/GUIwrapper#gui-wrapper') } 61 | }, 62 | { 63 | type: 'separator' 64 | }, 65 | { 66 | label: 'Check for Updates', 67 | click() { shell.openExternal('https://github.com/frodal/GUIwrapper/releases/latest') } 68 | }, 69 | { 70 | type: 'separator' 71 | }, 72 | { 73 | label: 'About', 74 | click() { 75 | const openAboutWindow = require('about-window').default; 76 | openAboutWindow({ 77 | icon_path: appIconPath, 78 | bug_report_url: bugReportURL 79 | }); 80 | } 81 | } 82 | ] 83 | } 84 | ]; 85 | const menu = Menu.buildFromTemplate(template); 86 | Menu.setApplicationMenu(menu); 87 | } 88 | 89 | exports.CreateMenu = CreateMenu; -------------------------------------------------------------------------------- /src/javascript/main.js: -------------------------------------------------------------------------------- 1 | // Handle installation, update and uninstall events 2 | if (require('electron-squirrel-startup')) return; 3 | // update application using update-electron-app 4 | const { updateElectronApp } = require('update-electron-app'); 5 | updateElectronApp(); 6 | // Modules to control application life and create native browser window 7 | const { app, BrowserWindow } = require('electron'); 8 | const path = require('path'); 9 | const { CreateMenu } = require('./mainmenu'); 10 | 11 | // Keep a global reference of the window object, if you don't, the window will 12 | // be closed automatically when the JavaScript object is garbage collected. 13 | let mainWindow; 14 | 15 | function createWindow() { 16 | // Create the browser window. 17 | mainWindow = new BrowserWindow( 18 | { 19 | width: 1280, 20 | height: 720, 21 | titleBarStyle: 'default', 22 | icon: path.join(__dirname, '../../assets/icons/png/64x64.png'), 23 | show: false, 24 | backgroundColor: '#FFFFFF', 25 | webPreferences: 26 | { 27 | contextIsolation: false, 28 | nodeIntegration: true 29 | } 30 | }); 31 | 32 | // and load the index.html of the app. 33 | mainWindow.loadFile(path.join(__dirname, '../html/index.html')); 34 | 35 | // Open the DevTools. 36 | // mainWindow.webContents.openDevTools() 37 | 38 | // Emitted when the window is closed. 39 | mainWindow.on('closed', function () { 40 | // Dereference the window object, usually you would store windows 41 | // in an array if your app supports multi windows, this is the time 42 | // when you should delete the corresponding element. 43 | mainWindow = null; 44 | }); 45 | 46 | // Shows the window once it is loaded and ready to be displayed 47 | mainWindow.once('ready-to-show', () => { 48 | mainWindow.show(); 49 | }); 50 | 51 | // Sets the application menu, i.e., 'File', 'Edit' etc. 52 | // Passing null will suppress the default menu. On Windows and Linux, 53 | // this has the additional effect of removing the menu bar from the window. 54 | CreateMenu(); 55 | } 56 | 57 | // This method will be called when Electron has finished 58 | // initialization and is ready to create browser windows. 59 | // Some APIs can only be used after this event occurs. 60 | app.on('ready', createWindow); 61 | 62 | // Quit when all windows are closed. 63 | app.on('window-all-closed', function () { 64 | // On OS X it is common for applications and their menu bar 65 | // to stay active until the user quits explicitly with Cmd + Q 66 | if (process.platform !== 'darwin') { 67 | app.quit(); 68 | } 69 | }); 70 | 71 | app.on('activate', function () { 72 | // On OS X it's common to re-create a window in the app when the 73 | // dock icon is clicked and there are no other windows open. 74 | if (mainWindow === null) { 75 | createWindow(); 76 | } 77 | }); 78 | 79 | // In this file you can include the rest of your app's specific main process 80 | // code. You can also put them in separate files and require them here. 81 | require('./dialog'); 82 | require('./darkMode').Initialize(); 83 | -------------------------------------------------------------------------------- /assets/icons/Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 45 | 47 | 48 | 50 | image/svg+xml 51 | 53 | 54 | 55 | 56 | 57 | 62 | 65 | 73 | GUI 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Dependencies/bootstrap-4.6.1-dist/css/bootstrap-reboot.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.6.1 (https://getbootstrap.com/) 3 | * Copyright 2011-2021 The Bootstrap Authors 4 | * Copyright 2011-2021 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([class]){color:inherit;text-decoration:none}a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit;text-align:-webkit-match-parent}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important} 8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */ -------------------------------------------------------------------------------- /src/javascript/renderer.js: -------------------------------------------------------------------------------- 1 | // This file is required by the index.html file and will 2 | // be executed in the renderer process for that window. 3 | // All of the Node.js APIs are available in this process. 4 | 5 | const { ipcRenderer } = require('electron'); 6 | 7 | const selectProgramBtn = document.getElementById('SelectProgramBtn'); 8 | const startProgramBtn = document.getElementById('StartProgramBtn'); 9 | const terminateProgramBtn = document.getElementById('TerminateProgramBtn'); 10 | const inputArgs = document.getElementById('InputArgs'); 11 | const roller = document.getElementById('lds-roller'); 12 | const runMsg = document.getElementById('running'); 13 | const outArea = document.getElementById('OutputData'); 14 | const filePathArea = document.getElementById('FilePath'); 15 | 16 | let exePath = ''; 17 | let exeCommandArgs = ['']; 18 | let subProcess = null; 19 | let stdoutput = ''; 20 | let killedDueToError = false; 21 | 22 | //////////////////////////////////////////////////////////////////////////////////// 23 | // Select Program // 24 | //////////////////////////////////////////////////////////////////////////////////// 25 | // Sets select program button callback 26 | selectProgramBtn.addEventListener('click', (event) => { 27 | ipcRenderer.send('open-file-dialog'); 28 | }); 29 | // Sets the executable filepath received from the main process (main.js) 30 | ipcRenderer.on('SelectedFile', (event, path) => { 31 | filePathArea.innerHTML = `${path.toString()}`; 32 | exePath = path.toString(); 33 | startProgramBtn.disabled = exePath === ''; 34 | }); 35 | 36 | //////////////////////////////////////////////////////////////////////////////////// 37 | // Start Program // 38 | //////////////////////////////////////////////////////////////////////////////////// 39 | // Sets start program button callback 40 | startProgramBtn.addEventListener('click', (event) => { 41 | if (exePath !== '') { 42 | if (subProcess !== null) // Check if a subprocess is already running 43 | { 44 | ipcRenderer.send('open-isRunning-dialog'); 45 | } else { 46 | // Clear output data field 47 | outArea.innerHTML = ''; 48 | exeCommandArgs = [inputArgs.value]; 49 | // Sets the current working directory of the selected program to be its own directory 50 | const path = require('path'); 51 | options = { cwd: path.dirname(exePath) }; 52 | // disable start button and enable terminate button when program is running 53 | startProgramBtn.disabled = true; 54 | terminateProgramBtn.disabled = false; 55 | roller.classList.add('lds-roller'); 56 | runMsg.innerHTML = 'Running'; 57 | try // Try to execute the program and sets a callback for when the program terminates 58 | { 59 | const { execFile } = require('child_process'); 60 | subProcess = execFile(exePath, exeCommandArgs, options, function (err, data) { 61 | if (err !== null && !subProcess.killed) { 62 | ipcRenderer.send('open-errorEXE-dialog'); 63 | } else if (killedDueToError) { 64 | ipcRenderer.send('open-errorKilled-dialog') 65 | } else { 66 | ipcRenderer.send('open-successfulTermination-dialog'); 67 | } 68 | killedDueToError = false; 69 | subProcess = null; 70 | stdoutput = ''; 71 | startProgramBtn.disabled = exePath === ''; 72 | terminateProgramBtn.disabled = true; 73 | roller.classList.remove('lds-roller'); 74 | runMsg.innerHTML = ''; 75 | }); 76 | // Standard output callback 77 | subProcess.stdout.on('data', function (data) { 78 | stdoutput += data.toString(); 79 | outArea.innerHTML = `${stdoutput}`; 80 | }); 81 | // Standard error callback 82 | subProcess.stderr.on('data', function (data) { 83 | stdoutput += data.toString(); 84 | outArea.innerHTML = `${stdoutput}`; 85 | subProcess.kill(); 86 | killedDueToError = true; 87 | }); 88 | } 89 | catch (err) // Catches the error if the file selected can't be executed correctly 90 | { 91 | subProcess = null; 92 | startProgramBtn.disabled = exePath === ''; 93 | terminateProgramBtn.disabled = true; 94 | roller.classList.remove('lds-roller'); 95 | runMsg.innerHTML = ''; 96 | ipcRenderer.send('open-error-dialog'); 97 | outArea.innerHTML = `${err.toString()}`; 98 | } 99 | } 100 | } else { 101 | // Sends a warning no file path is selected 102 | ipcRenderer.send('open-warning-dialog'); 103 | } 104 | }); 105 | 106 | //////////////////////////////////////////////////////////////////////////////////// 107 | // Terminate Program // 108 | //////////////////////////////////////////////////////////////////////////////////// 109 | // Sets terminate program button callback 110 | terminateProgramBtn.addEventListener('click', (event) => { 111 | if (subProcess !== null) { 112 | subProcess.kill(); 113 | } else { 114 | ipcRenderer.send('open-successfulTermination-dialog'); 115 | } 116 | }); -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # GUI wrapper 2 | 3 | ![GitHub](https://img.shields.io/github/license/frodal/GUIwrapper.svg) 4 | ![GitHub top language](https://img.shields.io/github/languages/top/frodal/GUIwrapper.svg) 5 | ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/frodal/GUIwrapper.svg) 6 | ![GitHub issues](https://img.shields.io/github/issues-raw/frodal/GUIwrapper.svg) 7 | ![GitHub release (latest SemVer including pre-releases)](https://img.shields.io/github/v/release/frodal/GUIwrapper?include_prereleases) 8 | 9 | A simple cross platform graphical user interface (GUI) wrapper to launch executable desktop applications. 10 | Buildt with JavaScript, HTML, and CSS. 11 | Compatible with Windows, Linux and MacOS. 12 | Download the latest version [here](https://github.com/frodal/GUIwrapper/releases). 13 | 14 | ![GUIwrapper image](GUIwrapper.png "GUIwrapper") 15 | 16 | ## Getting Started 17 | 18 | To get a local copy up and running follow these simple steps. 19 | 20 | 1. Clone the project or download from Github (`git clone --recursive https://github.com/frodal/GUIwrapper.git`) 21 | 2. Install [Node.js](https://nodejs.org) and on the screen that allows you to configure the installation, make sure to select the `Node.js runtime`, `npm package manager`, and `Add to PATH` options 22 | 3. Install the required packages/dependencies such as [Electron](https://electronjs.org/docs/tutorial/first-app#installing-electron) and [Electron-packager](https://github.com/electron-userland/electron-packager) by running `npm install` using the command line in the GUIwrapper directory 23 | 4. Then run `npm start` in the GUIwrapper directory to start the GUIwrapper application 24 | 25 | ### Build 26 | 27 | See [releases](https://github.com/frodal/GUIwrapper/releases) for prebuilt binaries, or build it yourself by following these steps 28 | 29 | 1. First, make sure to do steps 1-3 above 30 | 2. Then run `npm run build` in the GUIwrapper directory to build for all suported platforms, i.e., Windows, Linux and MacOS. Note that this will build to a directory outside of the GUIwrapper directory, i.e., `../GUIwrapperBinaries/` 31 | 32 | Note: To build for only one platform and architecture use the following build commands for; Windows ia32 (x86) `npm run build-win32`, Windows x64 `npm run build-win64`, Linux x64 `npm run build-linux64`, and MacOS x64 `npm run build-darwin64` 33 | 34 | ### Windows installer 35 | 36 | See [releases](https://github.com/frodal/GUIwrapper/releases) for prebuilt installers 37 | 38 | 1. First, make sure to do steps 1-2 under the [Build](#Build) section 39 | 2. Then run `npm run setup` in the GUIwrapper directory to build the windows installer. Note that this will build to a directory outside of the GUIwrapper directory, i.e., `../GUIwrapperBinaries/` 40 | 41 | ### Debian package 42 | 43 | A Linux or MacOS system is required for these steps. 44 | 45 | 1. First, make sure to do steps 1-2 under the [Build](#Build) section 46 | 2. To make a Debian package for the GUIwrapper application, install [Electron-installer-debian](https://github.com/electron-userland/electron-installer-debian) by running `npm install --save-dev electron-installer-debian` using the command line in the GUIwrapper directory 47 | 3. Then run `npm run setup-debian` in the GUIwrapper directory to build a Linux x64 debian package. Note that this will build to a directory outside of the GUIwrapper directory, i.e., `../GUIwrapperBinaries/` 48 | 49 | ### Distributable creators 50 | 51 | See also the links below to create other platform specific distributables 52 | 53 | * [electron-installer-zip](https://github.com/electron-userland/electron-installer-zip) - creates symlink-compatible ZIP files 54 | 55 | Windows: 56 | 57 | * [electron-winstaller](https://github.com/electron/windows-installer) - Squirrel.Windows-based installer from the Electron maintainers group 58 | * [electron-windows-store](https://github.com/felixrieseberg/electron-windows-store) - creates an AppX package for the Windows Store 59 | * [electron-wix-msi](https://github.com/felixrieseberg/electron-wix-msi) - creates traditional MSI installers 60 | * [electron-installer-windows](https://github.com/electron-userland/electron-installer-windows) - alternative Squirrel.Windows-based installer 61 | 62 | macOS: 63 | 64 | * [electron-installer-dmg](https://github.com/electron-userland/electron-installer-dmg) - creates a DMG 65 | 66 | Linux: 67 | 68 | * [electron-installer-debian](https://github.com/electron-userland/electron-installer-debian) - creates a DEB file 69 | * [electron-installer-redhat](https://github.com/electron-userland/electron-installer-redhat) - creates an RPM 70 | * [electron-installer-flatpak](https://github.com/endlessm/electron-installer-flatpak) - creates a Flatpak file 71 | * [electron-installer-snap](https://github.com/electron-userland/electron-installer-snap) - creates a Snap file 72 | 73 | ## Update dependencies 74 | 75 | * Update all GUI dependencies by running `npm update` using the command line in the GUIwrapper directory 76 | * Install/update [Electron](https://electronjs.org/docs/tutorial/first-app#installing-electron) by running `npm install --save-dev electron@latest` using the command line in the GUIwrapper directory 77 | * Install/update [Electron-packager](https://github.com/electron-userland/electron-packager) by running `npm install --save-dev electron-packager@latest` using the command line in the GUIwrapper directory 78 | * Install/update [Electron-installer-windows](https://github.com/electron-userland/electron-installer-windows) by running `npm install --save-dev electron-installer-windows@latest` using the command line in the GUIwrapper directory 79 | 80 | ## Contributing 81 | 82 | To contribute: 83 | 84 | 1. Fork the Project 85 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 86 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 87 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 88 | 5. Open a Pull Request 89 | 90 | ## License 91 | 92 | Distributed under the [MIT License](https://mit-license.org/). 93 | See `LICENSE.md` for more information. 94 | 95 | ## Contact 96 | 97 | Bjørn Håkon Frodal - [@frodal](https://github.com/frodal) - bjorn.h.frodal@ntnu.no 98 | 99 | Project Link: [https://github.com/frodal/GUIwrapper](https://github.com/frodal/GUIwrapper) 100 | -------------------------------------------------------------------------------- /Dependencies/bootstrap-4.6.1-dist/css/bootstrap-reboot.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.6.1 (https://getbootstrap.com/) 3 | * Copyright 2011-2021 The Bootstrap Authors 4 | * Copyright 2011-2021 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | html { 15 | font-family: sans-serif; 16 | line-height: 1.15; 17 | -webkit-text-size-adjust: 100%; 18 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 19 | } 20 | 21 | article, aside, figcaption, figure, footer, header, hgroup, main, nav, section { 22 | display: block; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 28 | font-size: 1rem; 29 | font-weight: 400; 30 | line-height: 1.5; 31 | color: #212529; 32 | text-align: left; 33 | background-color: #fff; 34 | } 35 | 36 | [tabindex="-1"]:focus:not(:focus-visible) { 37 | outline: 0 !important; 38 | } 39 | 40 | hr { 41 | box-sizing: content-box; 42 | height: 0; 43 | overflow: visible; 44 | } 45 | 46 | h1, h2, h3, h4, h5, h6 { 47 | margin-top: 0; 48 | margin-bottom: 0.5rem; 49 | } 50 | 51 | p { 52 | margin-top: 0; 53 | margin-bottom: 1rem; 54 | } 55 | 56 | abbr[title], 57 | abbr[data-original-title] { 58 | text-decoration: underline; 59 | -webkit-text-decoration: underline dotted; 60 | text-decoration: underline dotted; 61 | cursor: help; 62 | border-bottom: 0; 63 | -webkit-text-decoration-skip-ink: none; 64 | text-decoration-skip-ink: none; 65 | } 66 | 67 | address { 68 | margin-bottom: 1rem; 69 | font-style: normal; 70 | line-height: inherit; 71 | } 72 | 73 | ol, 74 | ul, 75 | dl { 76 | margin-top: 0; 77 | margin-bottom: 1rem; 78 | } 79 | 80 | ol ol, 81 | ul ul, 82 | ol ul, 83 | ul ol { 84 | margin-bottom: 0; 85 | } 86 | 87 | dt { 88 | font-weight: 700; 89 | } 90 | 91 | dd { 92 | margin-bottom: .5rem; 93 | margin-left: 0; 94 | } 95 | 96 | blockquote { 97 | margin: 0 0 1rem; 98 | } 99 | 100 | b, 101 | strong { 102 | font-weight: bolder; 103 | } 104 | 105 | small { 106 | font-size: 80%; 107 | } 108 | 109 | sub, 110 | sup { 111 | position: relative; 112 | font-size: 75%; 113 | line-height: 0; 114 | vertical-align: baseline; 115 | } 116 | 117 | sub { 118 | bottom: -.25em; 119 | } 120 | 121 | sup { 122 | top: -.5em; 123 | } 124 | 125 | a { 126 | color: #007bff; 127 | text-decoration: none; 128 | background-color: transparent; 129 | } 130 | 131 | a:hover { 132 | color: #0056b3; 133 | text-decoration: underline; 134 | } 135 | 136 | a:not([href]):not([class]) { 137 | color: inherit; 138 | text-decoration: none; 139 | } 140 | 141 | a:not([href]):not([class]):hover { 142 | color: inherit; 143 | text-decoration: none; 144 | } 145 | 146 | pre, 147 | code, 148 | kbd, 149 | samp { 150 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 151 | font-size: 1em; 152 | } 153 | 154 | pre { 155 | margin-top: 0; 156 | margin-bottom: 1rem; 157 | overflow: auto; 158 | -ms-overflow-style: scrollbar; 159 | } 160 | 161 | figure { 162 | margin: 0 0 1rem; 163 | } 164 | 165 | img { 166 | vertical-align: middle; 167 | border-style: none; 168 | } 169 | 170 | svg { 171 | overflow: hidden; 172 | vertical-align: middle; 173 | } 174 | 175 | table { 176 | border-collapse: collapse; 177 | } 178 | 179 | caption { 180 | padding-top: 0.75rem; 181 | padding-bottom: 0.75rem; 182 | color: #6c757d; 183 | text-align: left; 184 | caption-side: bottom; 185 | } 186 | 187 | th { 188 | text-align: inherit; 189 | text-align: -webkit-match-parent; 190 | } 191 | 192 | label { 193 | display: inline-block; 194 | margin-bottom: 0.5rem; 195 | } 196 | 197 | button { 198 | border-radius: 0; 199 | } 200 | 201 | button:focus:not(:focus-visible) { 202 | outline: 0; 203 | } 204 | 205 | input, 206 | button, 207 | select, 208 | optgroup, 209 | textarea { 210 | margin: 0; 211 | font-family: inherit; 212 | font-size: inherit; 213 | line-height: inherit; 214 | } 215 | 216 | button, 217 | input { 218 | overflow: visible; 219 | } 220 | 221 | button, 222 | select { 223 | text-transform: none; 224 | } 225 | 226 | [role="button"] { 227 | cursor: pointer; 228 | } 229 | 230 | select { 231 | word-wrap: normal; 232 | } 233 | 234 | button, 235 | [type="button"], 236 | [type="reset"], 237 | [type="submit"] { 238 | -webkit-appearance: button; 239 | } 240 | 241 | button:not(:disabled), 242 | [type="button"]:not(:disabled), 243 | [type="reset"]:not(:disabled), 244 | [type="submit"]:not(:disabled) { 245 | cursor: pointer; 246 | } 247 | 248 | button::-moz-focus-inner, 249 | [type="button"]::-moz-focus-inner, 250 | [type="reset"]::-moz-focus-inner, 251 | [type="submit"]::-moz-focus-inner { 252 | padding: 0; 253 | border-style: none; 254 | } 255 | 256 | input[type="radio"], 257 | input[type="checkbox"] { 258 | box-sizing: border-box; 259 | padding: 0; 260 | } 261 | 262 | textarea { 263 | overflow: auto; 264 | resize: vertical; 265 | } 266 | 267 | fieldset { 268 | min-width: 0; 269 | padding: 0; 270 | margin: 0; 271 | border: 0; 272 | } 273 | 274 | legend { 275 | display: block; 276 | width: 100%; 277 | max-width: 100%; 278 | padding: 0; 279 | margin-bottom: .5rem; 280 | font-size: 1.5rem; 281 | line-height: inherit; 282 | color: inherit; 283 | white-space: normal; 284 | } 285 | 286 | progress { 287 | vertical-align: baseline; 288 | } 289 | 290 | [type="number"]::-webkit-inner-spin-button, 291 | [type="number"]::-webkit-outer-spin-button { 292 | height: auto; 293 | } 294 | 295 | [type="search"] { 296 | outline-offset: -2px; 297 | -webkit-appearance: none; 298 | } 299 | 300 | [type="search"]::-webkit-search-decoration { 301 | -webkit-appearance: none; 302 | } 303 | 304 | ::-webkit-file-upload-button { 305 | font: inherit; 306 | -webkit-appearance: button; 307 | } 308 | 309 | output { 310 | display: inline-block; 311 | } 312 | 313 | summary { 314 | display: list-item; 315 | cursor: pointer; 316 | } 317 | 318 | template { 319 | display: none; 320 | } 321 | 322 | [hidden] { 323 | display: none !important; 324 | } 325 | /*# sourceMappingURL=bootstrap-reboot.css.map */ -------------------------------------------------------------------------------- /Dependencies/bootstrap-4.6.1-dist/css/bootstrap-reboot.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../scss/bootstrap-reboot.scss","../../scss/_reboot.scss","dist/css/bootstrap-reboot.css","../../scss/vendor/_rfs.scss","bootstrap-reboot.css","../../scss/mixins/_hover.scss"],"names":[],"mappings":"AAAA;;;;;;ACkBA,ECTA,QADA,SDaE,WAAA,WAGF,KACE,YAAA,WACA,YAAA,KACA,yBAAA,KACA,4BAAA,YAMF,QAAA,MAAA,WAAA,OAAA,OAAA,OAAA,OAAA,KAAA,IAAA,QACE,QAAA,MAUF,KACE,OAAA,EACA,YAAA,aAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WAAA,CAAA,iBAAA,CAAA,UAAA,CAAA,mBAAA,CAAA,gBAAA,CAAA,iBAAA,CAAA,mBEqII,UAAA,KFnIJ,YAAA,IACA,YAAA,IACA,MAAA,QACA,WAAA,KACA,iBAAA,KGlBF,0CH+BE,QAAA,YASF,GACE,WAAA,YACA,OAAA,EACA,SAAA,QAaF,GAAA,GAAA,GAAA,GAAA,GAAA,GACE,WAAA,EACA,cAAA,MAOF,EACE,WAAA,EACA,cAAA,KC9CF,0BDyDA,YAEE,gBAAA,UACA,wBAAA,UAAA,OAAA,gBAAA,UAAA,OACA,OAAA,KACA,cAAA,EACA,iCAAA,KAAA,yBAAA,KAGF,QACE,cAAA,KACA,WAAA,OACA,YAAA,QCnDF,GDsDA,GCvDA,GD0DE,WAAA,EACA,cAAA,KAGF,MCtDA,MACA,MAFA,MD2DE,cAAA,EAGF,GACE,YAAA,IAGF,GACE,cAAA,MACA,YAAA,EAGF,WACE,OAAA,EAAA,EAAA,KAGF,ECvDA,ODyDE,YAAA,OAGF,MEII,UAAA,IFKJ,IC5DA,ID8DE,SAAA,SEPE,UAAA,IFSF,YAAA,EACA,eAAA,SAGF,IAAM,OAAA,OACN,IAAM,IAAA,MAON,EACE,MAAA,QACA,gBAAA,KACA,iBAAA,YIhLA,QJmLE,MAAA,QACA,gBAAA,UASJ,2BACE,MAAA,QACA,gBAAA,KI/LA,iCJkME,MAAA,QACA,gBAAA,KC7DJ,KACA,IDqEA,ICpEA,KDwEE,YAAA,cAAA,CAAA,KAAA,CAAA,MAAA,CAAA,QAAA,CAAA,iBAAA,CAAA,aAAA,CAAA,UExDE,UAAA,IF4DJ,IAEE,WAAA,EAEA,cAAA,KAEA,SAAA,KAGA,mBAAA,UAQF,OAEE,OAAA,EAAA,EAAA,KAQF,IACE,eAAA,OACA,aAAA,KAGF,IAGE,SAAA,OACA,eAAA,OAQF,MACE,gBAAA,SAGF,QACE,YAAA,OACA,eAAA,OACA,MAAA,QACA,WAAA,KACA,aAAA,OAOF,GAEE,WAAA,QACA,WAAA,qBAQF,MAEE,QAAA,aACA,cAAA,MAMF,OAEE,cAAA,EAQF,iCACE,QAAA,EC9GF,ODiHA,MC/GA,SADA,OAEA,SDmHE,OAAA,EACA,YAAA,QEhKE,UAAA,QFkKF,YAAA,QAGF,OCjHA,MDmHE,SAAA,QAGF,OCjHA,ODmHE,eAAA,KGjHF,cHwHE,OAAA,QAMF,OACE,UAAA,OCpHF,cACA,aACA,cDyHA,OAIE,mBAAA,OCxHF,6BACA,4BACA,6BD2HE,sBAKI,OAAA,QC3HN,gCACA,+BACA,gCD+HA,yBAIE,QAAA,EACA,aAAA,KC9HF,qBDiIA,kBAEE,WAAA,WACA,QAAA,EAIF,SACE,SAAA,KAEA,OAAA,SAGF,SAME,UAAA,EAEA,QAAA,EACA,OAAA,EACA,OAAA,EAKF,OACE,QAAA,MACA,MAAA,KACA,UAAA,KACA,QAAA,EACA,cAAA,ME9OI,UAAA,OFgPJ,YAAA,QACA,MAAA,QACA,YAAA,OAGF,SACE,eAAA,SG3IF,yCFGA,yCD8IE,OAAA,KG5IF,cHoJE,eAAA,KACA,mBAAA,KGhJF,yCHwJE,mBAAA,KAQF,6BACE,KAAA,QACA,mBAAA,OAOF,OACE,QAAA,aAGF,QACE,QAAA,UACA,OAAA,QAGF,SACE,QAAA,KG7JF,SHmKE,QAAA","sourcesContent":["/*!\n * Bootstrap Reboot v4.6.1 (https://getbootstrap.com/)\n * Copyright 2011-2021 The Bootstrap Authors\n * Copyright 2011-2021 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)\n */\n\n@import \"functions\";\n@import \"variables\";\n@import \"mixins\";\n@import \"reboot\";\n","// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n\n// Document\n//\n// 1. Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n// 2. Change the default font family in all browsers.\n// 3. Correct the line height in all browsers.\n// 4. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS.\n// 5. Change the default tap highlight to be completely transparent in iOS.\n\n*,\n*::before,\n*::after {\n box-sizing: border-box; // 1\n}\n\nhtml {\n font-family: sans-serif; // 2\n line-height: 1.15; // 3\n -webkit-text-size-adjust: 100%; // 4\n -webkit-tap-highlight-color: rgba($black, 0); // 5\n}\n\n// Shim for \"new\" HTML5 structural elements to display correctly (IE10, older browsers)\n// TODO: remove in v5\n// stylelint-disable-next-line selector-list-comma-newline-after\narticle, aside, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n\n// Body\n//\n// 1. Remove the margin in all browsers.\n// 2. As a best practice, apply a default `background-color`.\n// 3. Set an explicit initial text-align value so that we can later use\n// the `inherit` value on things like `` elements.\n\nbody {\n margin: 0; // 1\n font-family: $font-family-base;\n @include font-size($font-size-base);\n font-weight: $font-weight-base;\n line-height: $line-height-base;\n color: $body-color;\n text-align: left; // 3\n background-color: $body-bg; // 2\n}\n\n// Future-proof rule: in browsers that support :focus-visible, suppress the focus outline\n// on elements that programmatically receive focus but wouldn't normally show a visible\n// focus outline. In general, this would mean that the outline is only applied if the\n// interaction that led to the element receiving programmatic focus was a keyboard interaction,\n// or the browser has somehow determined that the user is primarily a keyboard user and/or\n// wants focus outlines to always be presented.\n//\n// See https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible\n// and https://developer.paciellogroup.com/blog/2018/03/focus-visible-and-backwards-compatibility/\n[tabindex=\"-1\"]:focus:not(:focus-visible) {\n outline: 0 !important;\n}\n\n\n// Content grouping\n//\n// 1. Add the correct box sizing in Firefox.\n// 2. Show the overflow in Edge and IE.\n\nhr {\n box-sizing: content-box; // 1\n height: 0; // 1\n overflow: visible; // 2\n}\n\n\n//\n// Typography\n//\n\n// Remove top margins from headings\n//\n// By default, `

`-`

` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\n// stylelint-disable-next-line selector-list-comma-newline-after\nh1, h2, h3, h4, h5, h6 {\n margin-top: 0;\n margin-bottom: $headings-margin-bottom;\n}\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `

`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n// Abbreviations\n//\n// 1. Duplicate behavior to the data-* attribute for our tooltip plugin\n// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n// 3. Add explicit cursor to indicate changed behavior.\n// 4. Remove the bottom border in Firefox 39-.\n// 5. Prevent the text-decoration to be skipped.\n\nabbr[title],\nabbr[data-original-title] { // 1\n text-decoration: underline; // 2\n text-decoration: underline dotted; // 2\n cursor: help; // 3\n border-bottom: 0; // 4\n text-decoration-skip-ink: none; // 5\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // Undo browser default\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\nb,\nstrong {\n font-weight: $font-weight-bolder; // Add the correct font weight in Chrome, Edge, and Safari\n}\n\nsmall {\n @include font-size(80%); // Add the correct font size in all browsers\n}\n\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n//\n\nsub,\nsup {\n position: relative;\n @include font-size(75%);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n//\n// Links\n//\n\na {\n color: $link-color;\n text-decoration: $link-decoration;\n background-color: transparent; // Remove the gray background on active links in IE 10.\n\n @include hover() {\n color: $link-hover-color;\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n color: inherit;\n text-decoration: none;\n\n @include hover() {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n//\n// Code\n//\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-monospace;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n}\n\npre {\n // Remove browser default top margin\n margin-top: 0;\n // Reset browser default of `1em` to use `rem`s\n margin-bottom: 1rem;\n // Don't allow content to break outside\n overflow: auto;\n // Disable auto-hiding scrollbar in IE & legacy Edge to avoid overlap,\n // making it impossible to interact with the content\n -ms-overflow-style: scrollbar;\n}\n\n\n//\n// Figures\n//\n\nfigure {\n // Apply a consistent margin strategy (matches our type styles).\n margin: 0 0 1rem;\n}\n\n\n//\n// Images and content\n//\n\nimg {\n vertical-align: middle;\n border-style: none; // Remove the border on images inside links in IE 10-.\n}\n\nsvg {\n // Workaround for the SVG overflow bug in IE10/11 is still required.\n // See https://github.com/twbs/bootstrap/issues/26878\n overflow: hidden;\n vertical-align: middle;\n}\n\n\n//\n// Tables\n//\n\ntable {\n border-collapse: collapse; // Prevent double borders\n}\n\ncaption {\n padding-top: $table-cell-padding;\n padding-bottom: $table-cell-padding;\n color: $table-caption-color;\n text-align: left;\n caption-side: bottom;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `` alignment by inheriting `text-align`.\n// 3. Fix alignment for Safari\n\nth {\n font-weight: $table-th-font-weight; // 1\n text-align: inherit; // 2\n text-align: -webkit-match-parent; // 3\n}\n\n\n//\n// Forms\n//\n\nlabel {\n // Allow labels to use `margin` for spacing.\n display: inline-block;\n margin-bottom: $label-margin-bottom;\n}\n\n// Remove the default `border-radius` that macOS Chrome adds.\n//\n// Details at https://github.com/twbs/bootstrap/issues/24093\nbutton {\n // stylelint-disable-next-line property-disallowed-list\n border-radius: 0;\n}\n\n// Explicitly remove focus outline in Chromium when it shouldn't be\n// visible (e.g. as result of mouse click or touch tap). It already\n// should be doing this automatically, but seems to currently be\n// confused and applies its very visible two-tone outline anyway.\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0; // Remove the margin in Firefox and Safari\n font-family: inherit;\n @include font-size(inherit);\n line-height: inherit;\n}\n\nbutton,\ninput {\n overflow: visible; // Show the overflow in Edge\n}\n\nbutton,\nselect {\n text-transform: none; // Remove the inheritance of text transform in Firefox\n}\n\n// Set the cursor for non-`