Skip to content

Commit 8dcbbfe

Browse files
authored
Merge pull request scratchfoundation#66 from cwillisf/about-window
About window
2 parents 7121d09 + 9746fc1 commit 8dcbbfe

File tree

4 files changed

+106
-19
lines changed

4 files changed

+106
-19
lines changed

src/main/index.js

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {BrowserWindow, Menu, app, dialog} from 'electron';
1+
import {BrowserWindow, Menu, app, dialog, ipcMain} from 'electron';
22
import * as path from 'path';
33
import {format as formatUrl} from 'url';
44
import {getFilterForExtension} from './FileFilters';
@@ -13,20 +13,17 @@ const defaultSize = {width: 1280, height: 800}; // good for MAS screenshots
1313

1414
const isDevelopment = process.env.NODE_ENV !== 'production';
1515

16-
const createMainWindow = () => {
16+
// global window references prevent them from being garbage-collected
17+
const _windows = {};
18+
19+
const createWindow = ({url, ...browserWindowOptions}) => {
1720
const window = new BrowserWindow({
18-
width: defaultSize.width,
19-
height: defaultSize.height,
2021
useContentSize: true,
21-
show: false
22+
show: false,
23+
...browserWindowOptions
2224
});
2325
const webContents = window.webContents;
2426

25-
if (process.platform === 'darwin') {
26-
const osxMenu = Menu.buildFromTemplate(MacOSMenu(app));
27-
Menu.setApplicationMenu(osxMenu);
28-
}
29-
3027
if (isDevelopment) {
3128
webContents.openDevTools();
3229
import('electron-devtools-installer').then(importedModule => {
@@ -46,15 +43,38 @@ const createMainWindow = () => {
4643
});
4744

4845
if (isDevelopment) {
49-
window.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`);
46+
window.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}/${url}`);
5047
} else {
5148
window.loadURL(formatUrl({
52-
pathname: path.join(__dirname, 'index.html'),
49+
pathname: path.join(__dirname, url),
5350
protocol: 'file',
5451
slashes: true
5552
}));
5653
}
5754

55+
return window;
56+
};
57+
58+
const createAboutWindow = () => {
59+
const window = createWindow({
60+
width: 400,
61+
height: 400,
62+
parent: _windows.main,
63+
title: 'About Scratch Desktop',
64+
url: 'index.html?route=about'
65+
});
66+
return window;
67+
};
68+
69+
const createMainWindow = () => {
70+
const window = createWindow({
71+
width: defaultSize.width,
72+
height: defaultSize.height,
73+
title: 'Scratch Desktop',
74+
url: 'index.html'
75+
});
76+
const webContents = window.webContents;
77+
5878
webContents.session.on('will-download', (ev, item) => {
5979
const itemPath = item.getFilename();
6080
const baseName = path.basename(itemPath);
@@ -104,6 +124,11 @@ const createMainWindow = () => {
104124
return window;
105125
};
106126

127+
if (process.platform === 'darwin') {
128+
const osxMenu = Menu.buildFromTemplate(MacOSMenu(app));
129+
Menu.setApplicationMenu(osxMenu);
130+
}
131+
107132
// quit application when all windows are closed
108133
app.on('window-all-closed', () => {
109134
app.quit();
@@ -113,13 +138,19 @@ app.on('will-quit', () => {
113138
telemetry.appWillClose();
114139
});
115140

116-
// global reference to mainWindow (necessary to prevent window from being garbage collected)
117-
let _mainWindow;
118-
119141
// create main BrowserWindow when electron is ready
120142
app.on('ready', () => {
121-
_mainWindow = createMainWindow();
122-
_mainWindow.on('closed', () => {
123-
_mainWindow = null;
143+
_windows.main = createMainWindow();
144+
_windows.main.on('closed', () => {
145+
delete _windows.main;
124146
});
147+
_windows.about = createAboutWindow();
148+
_windows.about.on('close', event => {
149+
event.preventDefault();
150+
_windows.about.hide();
151+
});
152+
});
153+
154+
ipcMain.on('open-about-window', () => {
155+
_windows.about.show();
125156
});

src/renderer/about.jsx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
import {author, productName, version} from '../../package.json';
4+
5+
import logo from '../icon/ScratchDesktop.svg';
6+
7+
// TODO: localization?
8+
const AboutElement = () => (
9+
<div
10+
style={{
11+
color: 'white',
12+
fontFamily: '"Helvetica Neue", Helvetica, Arial, sans-serif',
13+
fontWeight: 'bolder',
14+
margin: 0,
15+
position: 'absolute',
16+
top: '50%',
17+
left: '50%',
18+
transform: 'translate(-50%, -50%)'
19+
}}
20+
>
21+
<div><img
22+
alt={`${productName} icon`}
23+
src={logo}
24+
style={{
25+
maxWidth: '10rem',
26+
maxHeight: '10rem'
27+
}}
28+
/></div>
29+
<h2>{productName}</h2>
30+
<div>Version {version}</div>
31+
<table style={{fontSize: 'x-small'}}>
32+
{
33+
['Electron', 'Chrome'].map(component => {
34+
const componentVersion = process.versions[component.toLowerCase()];
35+
return <tr key={component}><td>{component}</td><td>{componentVersion}</td></tr>;
36+
})
37+
}
38+
</table>
39+
</div>
40+
);
41+
42+
const appTarget = document.getElementById('app');
43+
ReactDOM.render(<AboutElement />, appTarget);

src/renderer/app.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ const ScratchDesktopHOC = function (WrappedComponent) {
4545
componentWillUnmount () {
4646
ipcRenderer.removeListener('setTitleFromSave', this.handleSetTitleFromSave);
4747
}
48+
handleClickLogo () {
49+
ipcRenderer.send('open-about-window');
50+
}
4851
handleProjectTelemetryEvent (event, metadata) {
4952
ipcRenderer.send(event, metadata);
5053
}
@@ -66,6 +69,7 @@ const ScratchDesktopHOC = function (WrappedComponent) {
6669
isScratchDesktop
6770
projectId={defaultProjectId}
6871
showTelemetryModal={shouldShowTelemetryModal}
72+
onClickLogo={this.handleClickLogo}
6973
onProjectTelemetryEvent={this.handleProjectTelemetryEvent}
7074
onStorageInit={this.handleStorageInit}
7175
onTelemetryModalOptIn={this.handleTelemetryModalOptIn}

src/renderer/index.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
// this is an async import so that it doesn't block the first render
22
// index.html contains a loading/splash screen which will display while this import loads
3-
import('./app.jsx');
3+
4+
const route = new URLSearchParams(window.location.search).get('route') || 'app';
5+
switch (route) {
6+
case 'app':
7+
import('./app.jsx');
8+
break;
9+
case 'about':
10+
import('./about.jsx');
11+
break;
12+
}

0 commit comments

Comments
 (0)