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 |
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 | 
4 | 
5 | 
6 | 
7 | 
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 | 
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-`