diff --git a/.travis.yml b/.travis.yml index 7d7082cf3..d9bd2b87e 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,22 @@ language: node_js -os: osx node_js: 12 -osx_image: xcode10.2 +matrix: + fast_finish: true + include: + - os: osx + osx_image: xcode10.2 + - os: linux + env: + - CC=clang CXX=clang++ npm_config_clang=1 + compiler: clang + addons: + apt: + packages: + - python3 + - python3-pip + - python3-setuptools + - libxkbfile-dev + - libx11-dev cache: yarn before_script: - npm install -g npx @@ -9,8 +24,8 @@ before_script: - yarn lint script: - yarn dist -- yarn catalog:install && yarn catalog:test -- if [ "$TRAVIS_BRANCH" == "master" -a "$TRAVIS_PULL_REQUEST" == "false" ]; then yarn +- if [ "$TRAVIS_OS_NAME" == "linux" ]; then yarn catalog:install && yarn catalog:test; fi +- if [ "$TRAVIS_OS_NAME" == "linux" -a "$TRAVIS_BRANCH" == "master" -a "$TRAVIS_PULL_REQUEST" == "false" ]; then yarn catalog:install && yarn catalog:pack && yarn catalog:publish; fi notifications: email: false diff --git a/dist.js b/dist.js index 5016891ec..c553ee1b7 100755 --- a/dist.js +++ b/dist.js @@ -2,7 +2,7 @@ const fs = require('fs-extra'); const builder = require('electron-builder'); -const { Platform } = builder; +const { Arch, Platform } = builder; console.log(`Machine: ${process.platform}`); @@ -23,8 +23,25 @@ fs.writeJSONSync(TEMPLATE_JSON_PATH, { version: templatePackageJson.version, }); +let targets; +switch (process.platform) { + case 'darwin': { + targets = Platform.MAC.createTarget(); + break; + } + case 'win32': { + targets = Platform.WINDOWS.createTarget(['nsis'], Arch.x64); + break; + } + default: + case 'linux': { + targets = Platform.LINUX.createTarget(['AppImage'], Arch.x64); + break; + } +} + const opts = { - targets: Platform.MAC.createTarget(), + targets, config: { appId: 'com.webcatalog.jordan', productName: 'WebCatalog', @@ -43,6 +60,10 @@ const opts = { mac: { category: 'public.app-category.utilities', }, + linux: { + category: 'Utility', + packageCategory: 'utils', + }, afterAllArtifactBuild: () => [TEMPLATE_JSON_PATH], }, }; diff --git a/docs/_layouts/download.html b/docs/_layouts/download.html new file mode 100644 index 000000000..f7f2fbeed --- /dev/null +++ b/docs/_layouts/download.html @@ -0,0 +1,156 @@ +--- +layout: default +--- +
+
+
+

+ Run Web Apps like Real Apps +

+

+ Boost your productivity & protect your privacy with WebCatalog. +

+ + {% if page.platform == "mac" %} + +

Version {{ site.webcatalog_version }} (Release Notes). Also available on Linux.

+ {% elsif page.platform == "linux" %} + +

Version {{ site.webcatalog_version }} (Release Notes). Also available on macOS.

+ {% else %} +
+ +

Version {{ site.webcatalog_version }} (Release Notes). Also available on Linux.

+
+ + + {% endif %} +
+ +

*You can install up to two apps for free.

+ +

+ + WebCatalog + +

+
+
+
+

How It Works

+

WebCatalog lets you turn any web apps into native-like Mac apps (also called site-specific browsers). Now, with WebCatalog, you can launch your favorite apps quickly in self-contained, distraction-free windows. Each app's data is stored separately, protecting you from cross-website trackers and preserving your privacy.

+
+

Featured Apps

+ See more +
+ {% for item in site.catalog %} + {% if item.featured == true %} + + {% endif %} + {% endfor %} +
+
+

Notable Features

+
+
+ + Catalog + +

Catalog - Install apps quickly from our curated catalog.

+
+
+ + App View + +

AppView - Run any website like a real Mac app.

+
+
+ + Workspace + +

Workspaces - Switch between multiple accounts/projects.

+
+
+ + Menubar + +

Menubar - Access your apps anytime and anywhere.

+
+
+ + Customization + +

Customization - Customize everything to suite your taste.

+
+
+
+
+
+ -
-
-

- Run Web Apps like Real Apps -

-

- Boost your productivity & protect your privacy with WebCatalog. -

- - - -

Version {{ site.webcatalog_version }} (Release Notes). WebCatalog requires macOS 10.10 or later.

- -
- -

*You can install up to two apps for free.

- -

- - WebCatalog - -

-
-
-
-

How It Works

-

WebCatalog lets you turn any web apps into native-like Mac apps (also called site-specific browsers). Now, with WebCatalog, you can launch your favorite apps quickly in self-contained, distraction-free windows. Each app's data is stored separately, protecting you from cross-website trackers and preserving your privacy.

-
-

Featured Apps

- See more -
- {% for item in site.catalog %} - {% if item.featured == true %} - - {% endif %} - {% endfor %} -
-
-

Notable Features

-
-
- - Catalog - -

Catalog - Install apps quickly from our curated catalog.

-
-
- - App View - -

AppView - Run any website like a real Mac app.

-
-
- - Workspace - -

Workspaces - Switch between multiple accounts/projects.

-
-
- - Menubar - -

Menubar - Access your apps anytime and anywhere.

-
-
- - Customization - -

Customization - Customize everything to suite your taste.

-
-
-
-
- +layout: download +--- \ No newline at end of file diff --git a/public/libs/app-management/get-installed-apps-async.js b/public/libs/app-management/get-installed-apps-async.js index 8877444a4..b6ab454a4 100644 --- a/public/libs/app-management/get-installed-apps-async.js +++ b/public/libs/app-management/get-installed-apps-async.js @@ -20,13 +20,17 @@ const getInstalledAppsAsync = () => { files.forEach((fileName) => { if (fileName === '.DS_Store') return; - const packageJsonPath = path.join(installationPath, fileName, 'Contents', 'Resources', 'app.asar.unpacked', 'package.json'); + const resourcesPath = process.platform === 'darwin' + ? path.join(installationPath, fileName, 'Contents', 'Resources') + : path.join(installationPath, fileName, 'resources'); - const legacyAppJsonPath = path.join(installationPath, fileName, 'Contents', 'Resources', 'app.asar.unpacked', 'public', 'app.json'); - const legacyIconPath = path.join(installationPath, fileName, 'Contents', 'Resources', 'app.asar.unpacked', 'public', 'icon.png'); + const packageJsonPath = path.join(resourcesPath, 'app.asar.unpacked', 'package.json'); - const appJsonPath = path.join(installationPath, fileName, 'Contents', 'Resources', 'app.asar.unpacked', 'build', 'app.json'); - const iconPath = path.join(installationPath, fileName, 'Contents', 'Resources', 'app.asar.unpacked', 'build', 'icon.png'); + const legacyAppJsonPath = path.join(resourcesPath, 'app.asar.unpacked', 'public', 'app.json'); + const legacyIconPath = path.join(resourcesPath, 'app.asar.unpacked', 'public', 'icon.png'); + + const appJsonPath = path.join(resourcesPath, 'app.asar.unpacked', 'build', 'app.json'); + const iconPath = path.join(resourcesPath, 'app.asar.unpacked', 'build', 'icon.png'); let packageJson; let appJson; diff --git a/public/libs/app-management/install-app-async/forked-script.js b/public/libs/app-management/install-app-async/forked-script.js index 30751657d..61fc251b2 100644 --- a/public/libs/app-management/install-app-async/forked-script.js +++ b/public/libs/app-management/install-app-async/forked-script.js @@ -28,8 +28,8 @@ const tmpObj = tmp.dirSync(); const tmpPath = tmpObj.name; const appPath = path.join(tmpPath, 'template'); const buildResourcesPath = path.join(tmpPath, 'build-resources'); -const iconIcnsPath = path.join(buildResourcesPath, 'icon.icns'); -const iconPngPath = path.join(buildResourcesPath, 'icon.png'); +const iconIcnsPath = path.join(buildResourcesPath, 'e.icns'); +const iconPngPath = path.join(buildResourcesPath, 'e.png'); const appJsonPath = path.join(appPath, 'build', 'app.json'); const publicIconPngPath = path.join(appPath, 'build', 'icon.png'); const packageJsonPath = path.join(appPath, 'package.json'); @@ -38,11 +38,11 @@ const outputPath = path.join(tmpPath, 'dist'); const menubarIconPath = path.join(appPath, 'build', 'menubar-icon.png'); const menubarIcon2xPath = path.join(appPath, 'build', 'menubar-icon@2x.png'); -const dotAppPath = path.join(outputPath, `${name}-darwin-x64`, `${name}.app`); +const dotAppPath = process.platform === 'darwin' ? path.join(outputPath, `${name}-darwin-x64`, `${name}.app`) : path.join(outputPath, `${name}-linux-x64`); const allAppsPath = installationPath.replace('~', homePath); -const finalPath = path.join(allAppsPath, `${name}.app`); +const finalPath = process.platform === 'darwin' ? path.join(allAppsPath, `${name}.app`) : path.join(allAppsPath, `${name}`); const sizes = [16, 32, 64, 128, 256, 512, 1024]; @@ -67,7 +67,7 @@ decompress(templatePath, tmpPath) .then(() => { if (isUrl(icon)) { return download(icon, buildResourcesPath, { - filename: 'icon.png', + filename: 'e.png', }); } @@ -101,14 +101,18 @@ decompress(templatePath, tmpPath) return Promise.all(p); }) - .then(() => icongen(buildResourcesPath, buildResourcesPath, { - report: true, - icns: { - name: 'icon', - sizes, - }, - })) - .then(results => results[0]) + .then(() => { + if (process.platform === 'darwin') { + return icongen(buildResourcesPath, buildResourcesPath, { + report: true, + icns: { + name: 'icon', + sizes, + }, + }); + } + return null; + }) .then(() => fsExtra.copy(iconPngPath, publicIconPngPath)) .then(() => { const appJson = JSON.stringify({ @@ -129,8 +133,8 @@ decompress(templatePath, tmpPath) const opts = { name, appBundleId: `com.webcatalog.juli.${id}`, - icon: iconIcnsPath, - platform: 'darwin', + icon: process.platform === 'darwin' ? iconIcnsPath : iconPngPath, + platform: process.platform, dir: appPath, out: outputPath, overwrite: true, @@ -165,19 +169,40 @@ decompress(templatePath, tmpPath) if (requireAdmin === 'true') { return sudoAsync(`mkdir -p "${allAppsPath}" && rm -rf "${finalPath}" && mv "${dotAppPath}" "${finalPath}"`); } - return fsExtra.move(dotAppPath, finalPath, { overwrite: true }); }) + .then(() => { + // create desktop file for linux + if (process.platform === 'linux') { + const execFilePath = path.join(finalPath, name); + const iconPath = path.join(finalPath, 'resources', 'app.asar.unpacked', 'build', 'icon.png'); + const desktopFilePath = path.join(homePath, '.local', 'share', 'applications', `webcatalog-${id}.desktop`); + const desktopFileContent = `[Desktop Entry] + Version=1.0 + Type=Application + Name=${name} + GenericName=${name} + Icon=${iconPath} + Exec=${execFilePath} + Terminal=false; + `; + return fsExtra.writeFileSync(desktopFilePath, desktopFileContent); + } + return null; + }) .then(() => { process.exit(0); }) .catch((e) => { /* eslint-disable-next-line */ + console.log(e); process.send(e); process.exit(1); }); process.on('uncaughtException', (e) => { + /* eslint-disable-next-line */ + console.log(e); process.exit(1); process.send(e); }); diff --git a/public/libs/app-management/open-app.js b/public/libs/app-management/open-app.js index 2f2ee63a0..81b1ecf5e 100755 --- a/public/libs/app-management/open-app.js +++ b/public/libs/app-management/open-app.js @@ -1,11 +1,17 @@ const { app, shell } = require('electron'); const path = require('path'); +const { exec } = require('child_process'); const { getPreference } = require('../preferences'); const openApp = (id, name) => { - const appPath = path.join(getPreference('installationPath').replace('~', app.getPath('home')), `${name}.app`); - shell.openItem(appPath); + let appPath; + if (process.platform === 'darwin') { + appPath = path.join(getPreference('installationPath').replace('~', app.getPath('home')), `${name}.app`); + shell.openItem(appPath); + } else if (process.platform === 'linux') { + exec(`gtk-launch webcatalog-${id}`); + } }; module.exports = openApp; diff --git a/public/libs/app-management/uninstall-app-async/forked-script.js b/public/libs/app-management/uninstall-app-async/forked-script.js index 28dfd5205..aefa4dc22 100644 --- a/public/libs/app-management/uninstall-app-async/forked-script.js +++ b/public/libs/app-management/uninstall-app-async/forked-script.js @@ -4,6 +4,7 @@ const argv = require('yargs-parser')(process.argv.slice(1)); const sudo = require('sudo-prompt'); const { + id, name, installationPath, requireAdmin, @@ -40,8 +41,9 @@ const checkExistsAndRemoveWithSudo = dirPath => fsExtra.exists(dirPath) return null; }); -const dotAppPath = path.join(installationPath.replace('~', homePath), `${name}.app`); -const appDataPath = path.join(homePath, 'Library', 'Application Support', name); +const dotAppPath = process.platform === 'darwin' + ? path.join(installationPath.replace('~', homePath), `${name}.app`) + : path.join(installationPath.replace('~', homePath), `${name}`); Promise.resolve() .then(() => { @@ -50,7 +52,19 @@ Promise.resolve() } return checkExistsAndRemove(dotAppPath); }) - .then(() => checkExistsAndRemove(appDataPath)) + .then(() => { + if (process.platform === 'darwin') { + const appDataPath = path.join(homePath, 'Library', 'Application Support', name); + return checkExistsAndRemove(appDataPath); + } + + if (process.platform === 'linux') { + const desktopFilePath = path.join(homePath, '.local', 'share', 'applications', `webcatalog-${id}.desktop`); + return checkExistsAndRemove(desktopFilePath); + } + + return null; + }) .then(() => { process.exit(0); }) diff --git a/public/libs/create-menu.js b/public/libs/create-menu.js index ec298d460..adad61318 100755 --- a/public/libs/create-menu.js +++ b/public/libs/create-menu.js @@ -109,6 +109,39 @@ const createMenu = () => { { type: 'separator' }, { role: 'front' }, ]; + } else { + // File menu for Windows & Linux + template.unshift({ + label: 'File', + submenu: [ + { + role: 'about', + click: () => app.showAboutPanel(), + }, + { type: 'separator' }, + { + label: registered ? 'Registered' : 'Registration...', + enabled: !registered, + click: registered ? null : () => sendToAllWindows('open-license-registration-dialog'), + }, + { type: 'separator' }, + { + label: 'Check for Updates...', + click: () => { + global.updateSilent = false; + autoUpdater.checkForUpdates(); + }, + }, + { type: 'separator' }, + { + label: 'Preferences...', + accelerator: 'Ctrl+,', + click: () => sendToAllWindows('go-to-preferences'), + }, + { type: 'separator' }, + { role: 'quit', label: 'Exit' }, + ], + }); } const menu = Menu.buildFromTemplate(template); diff --git a/public/libs/preferences.js b/public/libs/preferences.js index e4b9c735f..7bafab0b4 100644 --- a/public/libs/preferences.js +++ b/public/libs/preferences.js @@ -8,9 +8,9 @@ const moveAllAppsAsync = require('../libs/app-management/move-all-apps-async'); const v = '2018'; const defaultPreferences = { - theme: 'automatic', + theme: process.platform === 'darwin' ? 'automatic' : 'light', registered: false, - installationPath: '~/Applications/WebCatalog Apps', + installationPath: process.platform === 'darwin' ? '~/Applications/WebCatalog Apps' : '~/.webcatalog', requireAdmin: false, }; @@ -18,7 +18,7 @@ const getPreferences = () => Object.assign({}, defaultPreferences, settings.get( const getPreference = (name) => { // ensure compatiblity with old version - if (name === 'installationPath' || name === 'requireAdmin') { + if (process.platform === 'darwin' && (name === 'installationPath' || name === 'requireAdmin')) { // old pref, home or root if (settings.get('preferences.2018.installLocation', null) === 'root') { settings.delete('preferences.2018.installLocation'); diff --git a/src/components/app-wrapper.js b/src/components/app-wrapper.js index 0d0bdcb24..9f9ac1bf5 100755 --- a/src/components/app-wrapper.js +++ b/src/components/app-wrapper.js @@ -28,17 +28,25 @@ class AppWrapper extends React.Component { componentDidMount() { remote.getCurrentWindow().on('enter-full-screen', this.handleEnterFullScreen); remote.getCurrentWindow().on('leave-full-screen', this.handleLeaveFullScreen); - this.appleInterfaceThemeChangedNotificationId = remote.systemPreferences - .subscribeNotification( - 'AppleInterfaceThemeChangedNotification', - this.handleChangeTheme, - ); + + if (window.process.platform === 'darwin') { + this.appleInterfaceThemeChangedNotificationId = remote.systemPreferences + .subscribeNotification( + 'AppleInterfaceThemeChangedNotification', + this.handleChangeTheme, + ); + } } componentWillUnmount() { remote.getCurrentWindow().removeListener('enter-full-screen', this.handleEnterFullScreen); remote.getCurrentWindow().removeListener('leave-full-screen', this.handleLeaveFullScreen); - remote.systemPreferences.unsubscribeNotification(this.appleInterfaceThemeChangedNotificationId); + + if (window.process.platform === 'darwin') { + remote.systemPreferences.unsubscribeNotification( + this.appleInterfaceThemeChangedNotificationId, + ); + } } handleEnterFullScreen() { diff --git a/src/components/pages/preferences/index.js b/src/components/pages/preferences/index.js index ebbc1df12..eb42175e7 100644 --- a/src/components/pages/preferences/index.js +++ b/src/components/pages/preferences/index.js @@ -68,6 +68,12 @@ const getThemeString = (theme) => { return 'Automatic'; }; +const getFileManagerName = () => { + if (window.process.platform === 'darwin') return 'Finder'; + if (window.process.platform === 'win32') return 'FIle Explorer'; + return 'file manager'; +}; + const Preferences = ({ theme, classes, @@ -100,7 +106,9 @@ const Preferences = ({ )} > - requestSetPreference('theme', 'automatic')}>Automatic + {window.process.platform === 'darwin' && ( + requestSetPreference('theme', 'automatic')}>Automatic + )} requestSetPreference('theme', 'light')}>Light requestSetPreference('theme', 'dark')}>Dark @@ -143,27 +151,48 @@ const Preferences = ({ )} > - {(installationPath !== '~/Applications/WebCatalog Apps' && installationPath !== '/Applications/WebCatalog Apps') && ( - - {installationPath} - + {window.process.platform === 'darwin' && ( + + {(installationPath !== '~/Applications/WebCatalog Apps' && installationPath !== '/Applications/WebCatalog Apps') && ( + + {installationPath} + + )} + { + requestSetPreference('requireAdmin', false); + requestSetPreference('installationPath', '~/Applications/WebCatalog Apps'); + }} + > + ~/Applications/WebCatalog Apps (default) + + { + requestSetPreference('requireAdmin', true); + requestSetPreference('installationPath', '/Applications/WebCatalog Apps'); + }} + > + /Applications/WebCatalog Apps (requires sudo) + + + )} + {window.process.platform === 'linux' && ( + + {(installationPath !== '~/.webcatalog') && ( + + {installationPath} + + )} + { + requestSetPreference('requireAdmin', false); + requestSetPreference('installationPath', '~/.webcatalog'); + }} + > + ~/.webcatalog (default) + + )} - { - requestSetPreference('requireAdmin', false); - requestSetPreference('installationPath', '~/Applications/WebCatalog Apps'); - }} - > - ~/Applications/WebCatalog Apps (default) - - { - requestSetPreference('requireAdmin', true); - requestSetPreference('installationPath', '/Applications/WebCatalog Apps'); - }} - > - /Applications/WebCatalog Apps (requires sudo) - Custom @@ -171,7 +200,7 @@ const Preferences = ({ )} - + diff --git a/template/public/icon.png b/template/public/icon.png new file mode 100644 index 000000000..16352aab8 Binary files /dev/null and b/template/public/icon.png differ diff --git a/template/public/libs/create-menu.js b/template/public/libs/create-menu.js index 70fad41d9..7dfe30c90 100755 --- a/template/public/libs/create-menu.js +++ b/template/public/libs/create-menu.js @@ -43,47 +43,6 @@ function createMenu() { }); const template = [ - { - label: appJson.name, - submenu: [ - { role: 'about' }, - { - label: 'Check for Updates...', - click: () => checkForUpdates(), - }, - { type: 'separator' }, - { - label: 'Preferences...', - accelerator: 'Cmd+,', - click: () => preferencesWindow.show(), - }, - { type: 'separator' }, - { - label: 'Clear Browsing Data...', - accelerator: 'CmdOrCtrl+Shift+Delete', - click: () => { - dialog.showMessageBox(preferencesWindow.get() || mainWindow.get(), { - type: 'question', - buttons: ['Clear Now', 'Cancel'], - message: 'Are you sure? All browsing data will be cleared. This action cannot be undone.', - cancelId: 1, - }, (response) => { - if (response === 0) { - clearBrowsingData(); - } - }); - }, - }, - { type: 'separator' }, - { role: 'services', submenu: [] }, - { type: 'separator' }, - { role: 'hide' }, - { role: 'hideothers' }, - { role: 'unhide' }, - { type: 'separator' }, - { role: 'quit' }, - ], - }, { label: 'Edit', submenu: [ @@ -108,7 +67,7 @@ function createMenu() { const contentSize = win.getContentSize(); const view = win.getBrowserView(); - const offsetTitlebar = global.showSidebar || global.attachToMenubar ? 0 : 22; + const offsetTitlebar = process.platform !== 'darwin' || global.showSidebar || global.attachToMenubar ? 0 : 22; const x = global.showSidebar ? 68 : 0; const y = global.showNavigationBar ? 36 + offsetTitlebar : 0 + offsetTitlebar; @@ -309,6 +268,89 @@ function createMenu() { }, ]; + if (process.platform === 'darwin') { + template.unshift({ + label: appJson.name, + submenu: [ + { role: 'about' }, + { + label: 'Check for Updates...', + click: () => checkForUpdates(), + }, + { type: 'separator' }, + { + label: 'Preferences...', + accelerator: 'Cmd+,', + click: () => preferencesWindow.show(), + }, + { type: 'separator' }, + { + label: 'Clear Browsing Data...', + accelerator: 'CmdOrCtrl+Shift+Delete', + click: () => { + dialog.showMessageBox(preferencesWindow.get() || mainWindow.get(), { + type: 'question', + buttons: ['Clear Now', 'Cancel'], + message: 'Are you sure? All browsing data will be cleared. This action cannot be undone.', + cancelId: 1, + }, (response) => { + if (response === 0) { + clearBrowsingData(); + } + }); + }, + }, + { type: 'separator' }, + { role: 'services', submenu: [] }, + { type: 'separator' }, + { role: 'hide' }, + { role: 'hideothers' }, + { role: 'unhide' }, + { type: 'separator' }, + { role: 'quit' }, + ], + }); + } else { + template.unshift({ + label: 'File', + submenu: [ + { + role: 'about', + click: () => app.showAboutPanel(), + }, + { + label: 'Check for Updates...', + click: () => checkForUpdates(), + }, + { type: 'separator' }, + { + label: 'Preferences...', + accelerator: 'Ctrl+,', + click: () => preferencesWindow.show(), + }, + { type: 'separator' }, + { + label: 'Clear Browsing Data...', + accelerator: 'CmdOrCtrl+Shift+Delete', + click: () => { + dialog.showMessageBox(preferencesWindow.get() || mainWindow.get(), { + type: 'question', + buttons: ['Clear Now', 'Cancel'], + message: 'Are you sure? All browsing data will be cleared. This action cannot be undone.', + cancelId: 1, + }, (response) => { + if (response === 0) { + clearBrowsingData(); + } + }); + }, + }, + { type: 'separator' }, + { role: 'quit', label: 'Exit' }, + ], + }); + } + Object.values(getWorkspaces()) .sort((a, b) => a.order - b.order) .forEach((workspace, i) => { diff --git a/template/public/libs/preferences.js b/template/public/libs/preferences.js index 377addb69..be362a163 100755 --- a/template/public/libs/preferences.js +++ b/template/public/libs/preferences.js @@ -17,7 +17,7 @@ const defaultPreferences = { sidebar: Boolean(appJson.mailtoHandler), spellChecker: true, swipeToNavigate: true, - theme: 'automatic', + theme: process.platform === 'darwin' ? 'automatic' : 'light', unreadCountBadge: true, }; diff --git a/template/public/libs/views.js b/template/public/libs/views.js index 973ba7c35..00ea516d2 100644 --- a/template/public/libs/views.js +++ b/template/public/libs/views.js @@ -47,7 +47,7 @@ const addView = (browserWindow, workspace) => { const contentSize = browserWindow.getContentSize(); - const offsetTitlebar = global.showSidebar || global.attachToMenubar ? 0 : 22; + const offsetTitlebar = process.platform !== 'darwin' || global.showSidebar || global.attachToMenubar ? 0 : 22; const x = global.showSidebar ? 68 : 0; const y = global.showNavigationBar ? 36 + offsetTitlebar : 0 + offsetTitlebar; @@ -196,7 +196,7 @@ const setActiveView = (browserWindow, id) => { const contentSize = browserWindow.getContentSize(); - const offsetTitlebar = global.showSidebar || global.attachToMenubar ? 0 : 22; + const offsetTitlebar = process.platform !== 'darwin' || global.showSidebar || global.attachToMenubar ? 0 : 22; const x = global.showSidebar ? 68 : 0; const y = global.showNavigationBar ? 36 + offsetTitlebar : 0 + offsetTitlebar; diff --git a/template/public/listeners/index.js b/template/public/listeners/index.js index 63b9bfe6a..e98e006b5 100755 --- a/template/public/listeners/index.js +++ b/template/public/listeners/index.js @@ -67,7 +67,7 @@ const loadListeners = () => { if (close) { const contentSize = win.getContentSize(); - const offsetTitlebar = global.showSidebar || global.attachToMenubar ? 0 : 22; + const offsetTitlebar = process.platform !== 'darwin' || global.showSidebar || global.attachToMenubar ? 0 : 22; const x = global.showSidebar ? 68 : 0; const y = global.showNavigationBar ? 36 + offsetTitlebar : 0 + offsetTitlebar; diff --git a/template/public/windows/auth.js b/template/public/windows/auth.js index 270204444..945ef302d 100644 --- a/template/public/windows/auth.js +++ b/template/public/windows/auth.js @@ -25,6 +25,7 @@ const create = (id) => { maximizable: false, minimizable: false, fullscreenable: false, + autoHideMenuBar: true, webPreferences: { nodeIntegration: true, preload: path.join(__dirname, '..', 'preload', 'auth.js'), diff --git a/template/public/windows/code-injection.js b/template/public/windows/code-injection.js index d6d845357..7bfd75613 100644 --- a/template/public/windows/code-injection.js +++ b/template/public/windows/code-injection.js @@ -25,6 +25,7 @@ const create = (type) => { maximizable: false, minimizable: false, fullscreenable: false, + autoHideMenuBar: true, webPreferences: { nodeIntegration: true, preload: path.join(__dirname, '..', 'preload', 'code-injection.js'), diff --git a/template/public/windows/edit-workspace.js b/template/public/windows/edit-workspace.js index d57611374..0c22e59e2 100644 --- a/template/public/windows/edit-workspace.js +++ b/template/public/windows/edit-workspace.js @@ -25,6 +25,7 @@ const create = (id) => { maximizable: false, minimizable: false, fullscreenable: false, + autoHideMenuBar: true, webPreferences: { nodeIntegration: true, preload: path.join(__dirname, '..', 'preload', 'edit-workspace.js'), diff --git a/template/public/windows/main.js b/template/public/windows/main.js index 48682a429..5043a2506 100644 --- a/template/public/windows/main.js +++ b/template/public/windows/main.js @@ -90,6 +90,7 @@ const createAsync = () => { title: global.appJson.name, titleBarStyle: 'hidden', show: !wasOpenedAsHidden, + icon: process.platform === 'linux' ? path.resolve(__dirname, '..', 'icon.png') : null, webPreferences: { nodeIntegration: true, }, diff --git a/template/public/windows/open-url-with.js b/template/public/windows/open-url-with.js index 270b4318a..b550c9184 100644 --- a/template/public/windows/open-url-with.js +++ b/template/public/windows/open-url-with.js @@ -22,6 +22,7 @@ const create = (url) => { maximizable: false, minimizable: false, fullscreenable: false, + autoHideMenuBar: true, webPreferences: { nodeIntegration: true, preload: path.join(__dirname, '..', 'preload', 'open-url-with.js'), diff --git a/template/public/windows/preferences.js b/template/public/windows/preferences.js index 363ce4175..cac78c03f 100644 --- a/template/public/windows/preferences.js +++ b/template/public/windows/preferences.js @@ -20,6 +20,7 @@ const create = () => { maximizable: false, minimizable: false, fullscreenable: false, + autoHideMenuBar: true, webPreferences: { nodeIntegration: true, preload: path.join(__dirname, '..', 'preload', 'preferences.js'), diff --git a/template/src/components/app-wrapper.js b/template/src/components/app-wrapper.js index dc1f6ad15..db5736881 100644 --- a/template/src/components/app-wrapper.js +++ b/template/src/components/app-wrapper.js @@ -26,17 +26,25 @@ class AppWrapper extends React.Component { componentDidMount() { remote.getCurrentWindow().on('enter-full-screen', this.handleEnterFullScreen); remote.getCurrentWindow().on('leave-full-screen', this.handleLeaveFullScreen); - this.appleInterfaceThemeChangedNotificationId = remote.systemPreferences - .subscribeNotification( - 'AppleInterfaceThemeChangedNotification', - this.handleChangeTheme, - ); + + if (window.process.platform === 'darwin') { + this.appleInterfaceThemeChangedNotificationId = remote.systemPreferences + .subscribeNotification( + 'AppleInterfaceThemeChangedNotification', + this.handleChangeTheme, + ); + } } componentWillUnmount() { remote.getCurrentWindow().removeListener('enter-full-screen', this.handleEnterFullScreen); remote.getCurrentWindow().removeListener('leave-full-screen', this.handleLeaveFullScreen); - remote.systemPreferences.unsubscribeNotification(this.appleInterfaceThemeChangedNotificationId); + + if (window.process.platform === 'darwin') { + remote.systemPreferences.unsubscribeNotification( + this.appleInterfaceThemeChangedNotificationId, + ); + } } handleEnterFullScreen() { @@ -90,7 +98,11 @@ class AppWrapper extends React.Component { } AppWrapper.propTypes = { - children: PropTypes.element.isRequired, + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.element), + PropTypes.element, + PropTypes.string, + ]).isRequired, shouldUseDarkMode: PropTypes.bool.isRequired, onUpdateIsDarkMode: PropTypes.func.isRequired, onUpdateIsFullScreen: PropTypes.func.isRequired, diff --git a/template/src/components/main/fake-title-bar.js b/template/src/components/main/fake-title-bar.js index b52f0189b..04b296727 100644 --- a/template/src/components/main/fake-title-bar.js +++ b/template/src/components/main/fake-title-bar.js @@ -4,7 +4,7 @@ import classnames from 'classnames'; import connectComponent from '../../helpers/connect-component'; -const titleBarHeight = window.process.platform === 'darwin' ? 22 : 0; +const titleBarHeight = 22; const { remote } = window.require('electron'); @@ -32,6 +32,8 @@ const FakeTitleBar = (props) => { theme, } = props; + if (window.process.platform !== 'darwin') return null; + return (
({ }, sidebarTop: { flex: 1, - paddingTop: theme.spacing.unit * 3, + paddingTop: window.process.platform === 'darwin' ? theme.spacing.unit * 3 : 0, }, sidebarTopFullScreen: { paddingTop: 0, diff --git a/template/src/components/preferences/index.js b/template/src/components/preferences/index.js index 1af799cb2..698e9da95 100644 --- a/template/src/components/preferences/index.js +++ b/template/src/components/preferences/index.js @@ -140,62 +140,68 @@ const Preferences = ({ - - - { - requestSetPreference('attachToMenubar', e.target.checked); - requestShowRequireRestartDialog(); - }} - classes={{ - switchBase: classes.switchBase, - }} - /> - - - - - { - requestSetPreference('unreadCountBadge', e.target.checked); - requestShowRequireRestartDialog(); - }} - classes={{ - switchBase: classes.switchBase, - }} - /> - - - - - Navigate between pages with 3-finger gestures. -
- To enable it, you also need to change - macOS Preferences > Trackpad > More Gestures > Swipe between page - to - Swipe with three fingers - or - Swipe with two or three fingers. - - )} - /> - { - requestSetPreference('swipeToNavigate', e.target.checked); - requestShowRequireRestartDialog(); - }} - classes={{ - switchBase: classes.switchBase, - }} - /> -
- + {window.process.platform === 'darwin' && ( + + + + { + requestSetPreference('attachToMenubar', e.target.checked); + requestShowRequireRestartDialog(); + }} + classes={{ + switchBase: classes.switchBase, + }} + /> + + + + + { + requestSetPreference('unreadCountBadge', e.target.checked); + requestShowRequireRestartDialog(); + }} + classes={{ + switchBase: classes.switchBase, + }} + /> + + + + + Navigate between pages with 3-finger gestures. +
+ To enable it, you also need to change + + macOS Preferences > Trackpad > More Gestures > Swipe between page + + to + Swipe with three fingers + or + Swipe with two or three fingers. +
+ )} + /> + { + requestSetPreference('swipeToNavigate', e.target.checked); + requestShowRequireRestartDialog(); + }} + classes={{ + switchBase: classes.switchBase, + }} + /> + + + + )}
- - System - - - - - - - - )} - > - requestSetSystemPreference('openAtLogin', 'yes')}>Yes - requestSetSystemPreference('openAtLogin', 'yes-hidden')}>Yes, but minimized - requestSetSystemPreference('openAtLogin', 'no')}>No - - - + {window.process.platform !== 'linux' && ( + + + System + + + + + + + + )} + > + requestSetSystemPreference('openAtLogin', 'yes')}>Yes + requestSetSystemPreference('openAtLogin', 'yes-hidden')}>Yes, but minimized + requestSetSystemPreference('openAtLogin', 'no')}>No + + + + + )} Reset