Skip to content

Commit

Permalink
Add top menu and launcher (#140)
Browse files Browse the repository at this point in the history
* Add top menu

* Add launcher

* Filter unused extensions

* Add items to menu

* Update visuals

* Update dependencies

* Relax UI test

* Update packages/jupytercad-app/src/app/plugins/launcher/index.ts

Co-authored-by: martinRenou <[email protected]>

* Update dark theme

---------

Co-authored-by: martinRenou <[email protected]>
  • Loading branch information
trungleduc and martinRenou authored May 24, 2023
1 parent eeee46e commit 2fe750a
Show file tree
Hide file tree
Showing 21 changed files with 1,069 additions and 875 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/QuantStack/jupytercad/main?labpath=lab)

# JupyterCAD - A JupyterLab extension for 3D geometry modeling.

JupyterCAD is a JupyterLab extension for 3D geometry modeling with collaborative editing support. It is designed to allow multiple people to work on the same file at the same time, and to facilitate discussion and collaboration around the 3D shapes being created.
Expand Down
8 changes: 8 additions & 0 deletions jupytercad/cadapp/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,12 @@ def get_page_config(base_url, app_name):
page_config,
gpc(labextensions_path),
)
required_extensions = [
"@jupytercad/jupytercad-extension",
"@jupyter/collaboration-extension",
]
federated_extensions = page_config["federated_extensions"]
page_config["federated_extensions"] = [
x for x in federated_extensions if x["name"] in required_extensions
]
return page_config
6 changes: 6 additions & 0 deletions packages/jupytercad-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@jupyter/collaboration": "^1.0.0-alpha.7",
"@jupyter/docprovider": "^1.0.0-alpha.8",
"@jupyter/ydoc": "^0.3.4 || ^1.0.2",
"@jupytercad/jupytercad-extension": "0.1.0",
"@jupyterlab/application": "^4.0.0",
"@jupyterlab/application-extension": "^4.0.0",
"@jupyterlab/apputils": "^4.0.0",
Expand All @@ -51,10 +52,13 @@
"@jupyterlab/filebrowser": "^4.0.0",
"@jupyterlab/filebrowser-extension": "^4.0.0",
"@jupyterlab/launcher": "^4.0.0",
"@jupyterlab/launcher-extension": "^4.0.0",
"@jupyterlab/logconsole": "^4.0.0",
"@jupyterlab/mainmenu": "^4.0.0",
"@jupyterlab/mainmenu-extension": "^4.0.0",
"@jupyterlab/notebook": "^4.0.0",
"@jupyterlab/observables": "^5.0.0",
"@jupyterlab/outputarea": "^4.0.0",
"@jupyterlab/rendermime": "^4.0.0",
"@jupyterlab/services": "^7.0.0",
"@jupyterlab/settingregistry": "^4.0.0",
Expand All @@ -67,7 +71,9 @@
"@lumino/algorithm": "^2.0.0",
"@lumino/commands": "^2.0.0",
"@lumino/coreutils": "^2.0.0",
"@lumino/disposable": "^2.0.0",
"@lumino/messaging": "^2.0.0",
"@lumino/properties": "^2.0.0",
"@lumino/signaling": "^2.0.0",
"@lumino/virtualdom": "^2.0.0",
"@lumino/widgets": "^2.0.0",
Expand Down
35 changes: 33 additions & 2 deletions packages/jupytercad-app/src/app/plugins/browser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import {
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '@jupyterlab/application';

import { showErrorMessage } from '@jupyterlab/apputils';
import { IDefaultFileBrowser } from '@jupyterlab/filebrowser';
import { ITranslator } from '@jupyterlab/translation';
import { folderIcon } from '@jupyterlab/ui-components';
import { folderIcon, fileUploadIcon } from '@jupyterlab/ui-components';

const browserWidget: JupyterFrontEndPlugin<void> = {
id: '@jupyterlab/filebrowser-extension:widget',
Expand Down Expand Up @@ -34,7 +34,38 @@ const browserWidget: JupyterFrontEndPlugin<void> = {
}
return null;
});
browser.id = 'jcad-file-browser';
labShell.add(browser, 'left', { rank: 100, type: 'File Browser' });
labShell.activateById(browser.id);
browser.model.fileChanged.connect(
async () => await browser.model.refresh()
);
const input = document.createElement('input');
input.type = 'file';
input.multiple = true;
input.accept = '.FCStd, .fcstd,.jcad, .JCAD';
input.onclick = () => void (input.value = '');
input.onchange = () => {
const files = input.files;
if (files) {
const pending = Array.from(files).map(file =>
browser.model.upload(file)
);
void Promise.all(pending)
.catch(error => {
void showErrorMessage('Upload Error', error);
})
.then(async () => await browser.model.refresh());
}
};
app.commands.addCommand('jupytercad:open-file', {
label: 'Open File',
caption: 'Open files from disk',
icon: fileUploadIcon,
execute: args => {
input.click();
}
});
}
};

Expand Down
25 changes: 25 additions & 0 deletions packages/jupytercad-app/src/app/plugins/launcher/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {
ILabShell,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '@jupyterlab/application';

const launcherPlugin: JupyterFrontEndPlugin<void> = {
id: '@jupyterlab/-custom-launcher-extension',
description: 'Customize the default launcher.',
requires: [ILabShell],
autoStart: true,
activate: (app: JupyterFrontEnd, labShell: ILabShell): void => {
labShell.layoutModified.connect(() => {
const els = document.getElementsByClassName('jp-Launcher-sectionTitle');
const length = els.length;
for (let idx = 0; idx < length; idx++) {
const element = els.item(idx);
if (element) {
element.innerHTML = 'Create New Project';
}
}
});
}
};
export default launcherPlugin;
30 changes: 23 additions & 7 deletions packages/jupytercad-app/src/app/plugins/mainmenu/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,37 @@ import {
JupyterFrontEndPlugin
} from '@jupyterlab/application';

import { MainMenu } from './widget';

import { AppTitle } from './titleWidget';
import { UserMenu } from './userWidget';
import { Toolbar } from '@jupyterlab/ui-components';
import { MainMenu } from './menuWidget';
import { IThemeManager } from '@jupyterlab/apputils';
const PLUGIN_ID = 'jupytercad:topmenu';

/**
* A service providing an interface to the main menu.
*/
const plugin: JupyterFrontEndPlugin<void> = {
id: PLUGIN_ID,
requires: [],
requires: [IThemeManager],
autoStart: true,
activate: (app: JupyterFrontEnd): void => {
const menu = new MainMenu();
menu.id = 'jupytercad-topmenu';
app.shell.add(menu, 'menu', { rank: 100 });
activate: (app: JupyterFrontEnd, themeManager: IThemeManager): void => {
const { user } = app.serviceManager;
const { commands } = app;
const appTitle = new AppTitle();
appTitle.id = 'jupytercad-topmenu';
app.shell.add(appTitle, 'menu', { rank: 100 });
const spacer = Toolbar.createSpacerItem();
spacer.id = 'jupytercad-menu-spacer';
app.shell.add(spacer, 'menu', { rank: 150 });

const mainMenu = new MainMenu({ commands, themeManager });
mainMenu.id = 'jupytercad-menu-mainmenu';
app.shell.add(mainMenu, 'menu', { rank: 175 });

const userMenu = new UserMenu({ user });
userMenu.id = 'jupytercad-usermenu';
app.shell.add(userMenu, 'menu', { rank: 200 });
}
};

Expand Down
182 changes: 182 additions & 0 deletions packages/jupytercad-app/src/app/plugins/mainmenu/menuWidget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { RankedMenu, MenuSvg, homeIcon } from '@jupyterlab/ui-components';
import { CommandRegistry } from '@lumino/commands';
import { MenuBar } from '@lumino/widgets';
import { CommandIDs } from '@jupytercad/jupytercad-extension/lib/commands';
import { IThemeManager } from '@jupyterlab/apputils';
export class MainMenu extends MenuBar {
constructor(options: {
commands: CommandRegistry;
themeManager: IThemeManager;
}) {
super({ forceItemsPosition: { forceX: false, forceY: true } });
this._commands = options.commands;
this._themeManager = options.themeManager;
this.addClass('jc-MainMenu');
this._createFileMenu();
this._createEditMenu();
this._createViewMenu();
this._createHelpMenu();
}

private _createHelpMenu(): void {
this._commands.addCommand('jupytercad:help-menu:documentation', {
label: 'Documentation',
execute: () => {
window.open('https://github.com/QuantStack/jupytercad', '_blank');
},
icon: homeIcon
});
const helpMenu = new MenuSvg({
commands: this._commands
});
helpMenu.title.label = 'Help';
helpMenu.title.mnemonic = 0;
helpMenu.addClass('jc-MenuBar-MenuItem');
this.addMenu(helpMenu);
helpMenu.addItem({
type: 'command',
command: 'jupytercad:help-menu:documentation'
});
}
private _createFileMenu(): void {
const menu = new MenuSvg({
commands: this._commands
});
menu.title.label = 'File';
menu.title.mnemonic = 0;
menu.addClass('jc-MenuBar-FileMenu');
menu.addClass('jc-MenuBar-MenuItem');
this.addMenu(menu);
menu.addItem({
type: 'command',
command: 'jupytercad:create-new-jcad-file'
});
menu.addItem({
type: 'command',
command: 'jupytercad:open-file'
});
}
private _createEditMenu(): void {
const menu = new MenuSvg({
commands: this._commands
});
menu.title.label = 'Edit';
menu.title.mnemonic = 0;
menu.addClass('jc-MenuBar-MenuItem');
this.addMenu(menu);

const shapeMenu = new RankedMenu({
commands: this._commands,
rank: 200
});
shapeMenu.title.label = 'Shape';
shapeMenu.addClass('jc-MenuBar-MenuItem');
shapeMenu.addItem({
type: 'command',
command: CommandIDs.newBox
});
shapeMenu.addItem({
type: 'command',
command: CommandIDs.newCone
});
shapeMenu.addItem({
type: 'command',
command: CommandIDs.newCylinder
});
shapeMenu.addItem({
type: 'command',
command: CommandIDs.newSketch
});
shapeMenu.addItem({
type: 'command',
command: CommandIDs.newSphere
});
shapeMenu.addItem({
type: 'command',
command: CommandIDs.newTorus
});
shapeMenu.addItem({
type: 'command',
command: CommandIDs.newCone
});

menu.addItem({
type: 'submenu',
submenu: shapeMenu
});

const operatorMenu = new RankedMenu({
commands: this._commands,
rank: 200
});
operatorMenu.title.label = 'Operators';
operatorMenu.addClass('jc-MenuBar-MenuItem');
operatorMenu.addItem({
type: 'command',
command: CommandIDs.cut
});
operatorMenu.addItem({
type: 'command',
command: CommandIDs.extrusion
});
operatorMenu.addItem({
type: 'command',
command: CommandIDs.intersection
});
operatorMenu.addItem({
type: 'command',
command: CommandIDs.union
});
menu.addItem({
type: 'submenu',
submenu: operatorMenu
});

menu.addItem({
type: 'command',
command: CommandIDs.undo
});
menu.addItem({
type: 'command',
command: CommandIDs.redo
});
}

private _createViewMenu(): void {
const menu = new MenuSvg({
commands: this._commands
});
menu.title.label = 'View';
menu.title.mnemonic = 0;
menu.addClass('jc-MenuBar-ViewMenu');
menu.addClass('jc-MenuBar-MenuItem');
this.addMenu(menu);
menu.addItem({
type: 'command',
command: CommandIDs.updateExplodedView
});
menu.addItem({
type: 'command',
command: CommandIDs.updateAxes
});

const themeMenu = new RankedMenu({
commands: this._commands,
rank: 200
});
themeMenu.title.label = 'Theme';
themeMenu.addClass('jc-MenuBar-MenuItem');
this._themeManager.themes.forEach((theme, index) => {
themeMenu.insertItem(index, {
command: 'apputils:change-theme',
args: { theme }
});
});
menu.addItem({
type: 'submenu',
submenu: themeMenu
});
}
private _commands: CommandRegistry;
private _themeManager: IThemeManager;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Widget } from '@lumino/widgets';

export class MainMenu extends Widget {
export class AppTitle extends Widget {
constructor() {
super();
this.addClass('jcad-MainMenu');
this.addClass('jc-MainMenu-AppTitle');
this.node.innerHTML = 'JupyterCAD';
}
}
Loading

0 comments on commit 2fe750a

Please sign in to comment.