Skip to content

Commit

Permalink
POC
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Varache committed Feb 13, 2018
1 parent 93dbfde commit b1f4582
Show file tree
Hide file tree
Showing 28 changed files with 3,557 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "kano",
"rules": {
"no-param-reassign": ["error", { "props": false }]
}
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
110 changes: 108 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,108 @@
# kano-desktop-shell
Abstraction layer on top of electron to provide common features in a shell ready to use
# Kano Desktop Shell

Abstraction layer on top of electron to provide common features in a shell ready to use.

## Features

- Static SPA content delivery (Through registered custom protocol)
- Window state managment (electron-window-state)
- UWP style titlebar for windows with dropdown menu
- Default menu items (clipboard, selection, help)
- About page (Help/About or AppName/About on macOS)
- Developer mode option (5 clicks on icon in the about page)

### Future Features

- Update checking and menu options

## Style

### Windows

UWP style Titlebar

![Classic](res/uwp.png?raw=true)
![Classic](res/uwp-menu.png?raw=true)

Classic style titlebar (Windows 10)

![Classic](res/classic.png?raw=true)
![Classic](res/classic-menu.png?raw=true)

## API

`Shell`: Use this class to create a new app with a browser window serving content from a local directory

options:
- `root`, (required) Root of the local directory you want to serve in the browser window.
- `scheme`, Scheme that will be used in the server protocol (Default: `shell`)
- `width`, Width of the main window (Default: `800`).
- `height`, Height of the main window (Default: `600`).
- `preload`, path to a preload script (Default: none).
- `titlebar`, Enables the titlebar (Default: `true`).
- `uwpTitlebar`, Enables the UWP style titlebar for windows (Default: `true`).
- `devMode`, Enables developer mode (DevTool options) (Default: `false`).
- `menuTransform`, Function that will receive the shell menu and should return a modified version of it to add custom menu and menu items.
- `windowOptions`, Any option that will be passed down to electron's `BrowserWindow` constructor.

Methods:

- `updateMenu()`: Triggers an update of the menu bar.
- `isDevMode()`: Return a boolean. `true` if in developer mode `false` if not.

## Example

```js
const { app } = require('electron');
const { Shell, Shellmenu } = require('kano-desktop-shell');
const path = require('path');

const CONTENT_SCHEME = 'my-custom-app';
// Location of the static content to serve. This will be served through a custom protocol
const CONTENT_ROOT = path.join(__dirname, './src');

// Custom menu Item added
ShellItem.addItem('my-item', { label: 'My Menu Item', click() { console.log('My Menu Item') } });

// Create new Shell with custom options
// Includes automatic window state managment and UWP style titlebar for windows
// Custom preload as module supported
const shell = new Shell({
root: CONTENT_ROOT,
scheme: CONTENT_SCHEME,
// Can provide custom width and height
width: 1440,
height: 900,
// Supports preload script
preload: path.join(__dirname, 'preload.js'),
titlebar: true,
// Enable UWP style titlebar
uwpTitlebar: true,
devMode: false,
menuTransform(menu) {
const submenu = [ShellMenu.createMenuItem('my-item')];
// Can update when dev mode changes
if (shell.isDevMode()) {
submenu.push(ShellMenu.createMenuItem('separator'));
// Can add custom runtime generated menu items
submenu.push({ label: 'Dev option' });
}
// Inject in list of menus
menu.splice(1, 0, {
label: 'Custom Menu',
submenu,
});
return menu;
},
// Set custom window options through this object
windowOptions: {
icon: path.join(__dirname, 'res/icon_180.png'),
},
});

app.on('ready', () => {
shell.createWindow();
// The main window is accessible through properties
console.log(shell.window);
});
```
52 changes: 52 additions & 0 deletions app/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const { app } = require('electron');
const { Shell, ShellMenu } = require('../lib');
const path = require('path');

const CONTENT_SCHEME = 'kano-shell';
const CONTENT_ROOT = path.join(__dirname, './src');

// Custom menu Item added
ShellMenu.addItem('my-item', { label: 'My Menu Item', click() { console.log('My Menu Item'); } });

app.setName('My app');

// Create new Shell with custom options
// Includes automatic window state managment and UWP style titlebar for windows
// Custom preload as module supported
const shell = new Shell({
root: CONTENT_ROOT,
scheme: CONTENT_SCHEME,
// Can provide custom width and height
width: 1440,
height: 900,
// Supports preload script
preload: path.join(__dirname, 'preload.js'),
titlebar: true,
// Enable UWP style titlebar
uwpTitlebar: true,
devMode: false,
menuTransform(menu) {
const submenu = [ShellMenu.createMenuItem('my-item')];
// Can update when dev mode changes
if (shell.isDevMode()) {
submenu.push(ShellMenu.createMenuItem('separator'));
// Can add custom runtime generated menu items
submenu.push({ label: 'Dev option' });
}
// Inject in list of menus
menu.splice(1, 0, {
label: 'Custom Menu',
submenu,
});
return menu;
},
windowOptions: {
icon: path.join(__dirname, 'res/icon_180.png'),
},
});

app.on('ready', () => {
shell.createWindow();
// The main window is accessible through properties
console.log(shell.window);
});
1 change: 1 addition & 0 deletions app/preload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('CHROMIUM CONTEXT');
Binary file added app/res/icon_180.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions app/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Kano Desktop Shell</title>
<link rel="stylesheet" href="./main.css">
</head>
<body>

</body>
</html>
3 changes: 3 additions & 0 deletions app/src/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
html, body {
margin: 0;
}
63 changes: 63 additions & 0 deletions lib/about/about.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
body,
html {
width: 100%;
height: 100%;
-webkit-user-select: none;
user-select: none;
-webkit-app-region: drag;
}

body {
margin: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #333;
background-color: #eee;
font-size: 12px;
font-family: 'Helvetica', 'Arial', 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', 'メイリオ', Meiryo, 'MS Pゴシック', 'MS PGothic', sans-serif;
}

.logo {
width: 200px;
-webkit-user-select: none;
user-select: none;
}

.title,
.copyright,
.description {
margin: 0.2em;
}

.clickable {
cursor: pointer;
}

.description {
margin-bottom: 1em;
text-align: center;
}

.versions {
border-collapse: collapse;
margin-top: 1em;
}

.copyright,
.versions {
color: #999;
}

.link {
cursor: pointer;
color: #80a0c2;
}

.bug-report-link {
-webkit-app-region: no-drag;
position: absolute;
right: 0.5em;
bottom: 0.5em;
}
12 changes: 12 additions & 0 deletions lib/about/about.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>About</title>
<link rel="stylesheet" href="./about.css">
</head>

<body></body>
</html>
92 changes: 92 additions & 0 deletions lib/about/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
const { EventEmitter } = require('events');
const path = require('path');
const {
BrowserWindow,
remote,
shell,
ipcMain,
} = require('electron');

class About extends EventEmitter {
constructor(opts = {}) {
super();
this.window = null;

this.indexPage = `file://${path.join(__dirname, 'about.html')}`;

this.winOptions = Object.assign(
{
width: 400,
height: 400,
useContentSize: true,
titleBarStyle: 'hidden-inset',
show: !opts.adjustWindowSize,
icon: opts.iconPath,
},
opts.winOptions || {},
);

this.winOptions.webPreferences = Object.assign({}, this.winOptions.webPreferences || {}, {
nodeIntegration: false,
preload: path.join(__dirname, 'preload.js'),
});

this.options = opts;
}
openWindow() {
if (this.window !== null) {
this.window.focus();
return this.window;
}

ipcMain.on('about:enable-dev-mode', (event) => {
if (event.sender === this.window.webContents) {
this.emit('enable-dev-mode');
}
});

this.window = new (BrowserWindow || remote.BrowserWindow)(this.winOptions);

this.window.aboutOptions = this.options;

this.window.once('closed', () => {
this.window = null;
});
this.window.loadURL(this.indexPage);

this.window.webContents.on('will-navigate', (e, url) => {
e.preventDefault();
shell.openExternal(url);
});
this.window.webContents.on('new-window', (e, url) => {
e.preventDefault();
shell.openExternal(url);
});

this.window.webContents.once('dom-ready', () => {
if (this.options.openDevtools) {
if (process.versions.electron >= '1.4') {
this.window.webContents.openDevTools({ mode: 'detach' });
} else {
this.window.webContents.openDevTools();
}
}
});

this.window.once('ready-to-show', () => {
this.window.show();
});

this.window.setMenu(null);

return this.window;
}
close() {
if (!this.window) {
return;
}
this.window.close();
}
}

module.exports = About;
Loading

0 comments on commit b1f4582

Please sign in to comment.