diff --git a/src/main/index.js b/src/main/index.js index 4195197..19aff68 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -1,4 +1,4 @@ -import {BrowserWindow, Menu, app, dialog} from 'electron'; +import {BrowserWindow, Menu, app, dialog, ipcMain} from 'electron'; import * as path from 'path'; import {format as formatUrl} from 'url'; import {getFilterForExtension} from './FileFilters'; @@ -13,20 +13,17 @@ const defaultSize = {width: 1280, height: 800}; // good for MAS screenshots const isDevelopment = process.env.NODE_ENV !== 'production'; -const createMainWindow = () => { +// global window references prevent them from being garbage-collected +const _windows = {}; + +const createWindow = ({url, ...browserWindowOptions}) => { const window = new BrowserWindow({ - width: defaultSize.width, - height: defaultSize.height, useContentSize: true, - show: false + show: false, + ...browserWindowOptions }); const webContents = window.webContents; - if (process.platform === 'darwin') { - const osxMenu = Menu.buildFromTemplate(MacOSMenu(app)); - Menu.setApplicationMenu(osxMenu); - } - if (isDevelopment) { webContents.openDevTools(); import('electron-devtools-installer').then(importedModule => { @@ -46,15 +43,38 @@ const createMainWindow = () => { }); if (isDevelopment) { - window.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`); + window.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}/${url}`); } else { window.loadURL(formatUrl({ - pathname: path.join(__dirname, 'index.html'), + pathname: path.join(__dirname, url), protocol: 'file', slashes: true })); } + return window; +}; + +const createAboutWindow = () => { + const window = createWindow({ + width: 400, + height: 400, + parent: _windows.main, + title: 'About Scratch Desktop', + url: 'index.html?route=about' + }); + return window; +}; + +const createMainWindow = () => { + const window = createWindow({ + width: defaultSize.width, + height: defaultSize.height, + title: 'Scratch Desktop', + url: 'index.html' + }); + const webContents = window.webContents; + webContents.session.on('will-download', (ev, item) => { const itemPath = item.getFilename(); const baseName = path.basename(itemPath); @@ -104,6 +124,11 @@ const createMainWindow = () => { return window; }; +if (process.platform === 'darwin') { + const osxMenu = Menu.buildFromTemplate(MacOSMenu(app)); + Menu.setApplicationMenu(osxMenu); +} + // quit application when all windows are closed app.on('window-all-closed', () => { app.quit(); @@ -113,13 +138,19 @@ app.on('will-quit', () => { telemetry.appWillClose(); }); -// global reference to mainWindow (necessary to prevent window from being garbage collected) -let _mainWindow; - // create main BrowserWindow when electron is ready app.on('ready', () => { - _mainWindow = createMainWindow(); - _mainWindow.on('closed', () => { - _mainWindow = null; + _windows.main = createMainWindow(); + _windows.main.on('closed', () => { + delete _windows.main; + }); + _windows.about = createAboutWindow(); + _windows.about.on('close', event => { + event.preventDefault(); + _windows.about.hide(); }); }); + +ipcMain.on('open-about-window', () => { + _windows.about.show(); +}); diff --git a/src/renderer/about.jsx b/src/renderer/about.jsx new file mode 100644 index 0000000..6abe151 --- /dev/null +++ b/src/renderer/about.jsx @@ -0,0 +1,43 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import {author, productName, version} from '../../package.json'; + +import logo from '../icon/ScratchDesktop.svg'; + +// TODO: localization? +const AboutElement = () => ( +
+
{`${productName}
+

{productName}

+
Version {version}
+ + { + ['Electron', 'Chrome'].map(component => { + const componentVersion = process.versions[component.toLowerCase()]; + return ; + }) + } +
{component}{componentVersion}
+
+); + +const appTarget = document.getElementById('app'); +ReactDOM.render(, appTarget); diff --git a/src/renderer/app.jsx b/src/renderer/app.jsx index 8f57506..d129811 100644 --- a/src/renderer/app.jsx +++ b/src/renderer/app.jsx @@ -45,6 +45,9 @@ const ScratchDesktopHOC = function (WrappedComponent) { componentWillUnmount () { ipcRenderer.removeListener('setTitleFromSave', this.handleSetTitleFromSave); } + handleClickLogo () { + ipcRenderer.send('open-about-window'); + } handleProjectTelemetryEvent (event, metadata) { ipcRenderer.send(event, metadata); } @@ -66,6 +69,7 @@ const ScratchDesktopHOC = function (WrappedComponent) { isScratchDesktop projectId={defaultProjectId} showTelemetryModal={shouldShowTelemetryModal} + onClickLogo={this.handleClickLogo} onProjectTelemetryEvent={this.handleProjectTelemetryEvent} onStorageInit={this.handleStorageInit} onTelemetryModalOptIn={this.handleTelemetryModalOptIn} diff --git a/src/renderer/index.js b/src/renderer/index.js index 4ca0734..36f6843 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -1,3 +1,12 @@ // this is an async import so that it doesn't block the first render // index.html contains a loading/splash screen which will display while this import loads -import('./app.jsx'); + +const route = new URLSearchParams(window.location.search).get('route') || 'app'; +switch (route) { +case 'app': + import('./app.jsx'); + break; +case 'about': + import('./about.jsx'); + break; +}