Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/document/factory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export class NotebookGridWidgetFactory extends ABCWidgetFactory<
} else {
topbarWidget = this._spectaTopbar;
}
const topbar = topbarWidget as TopbarWidget | undefined;

const menu = (
<MenuComponent
Expand All @@ -75,6 +76,8 @@ export class NotebookGridWidgetFactory extends ABCWidgetFactory<
uiSwitcher={this._uiSwitcher}
currentPath={path}
currentUi={isSpecta ? 'specta' : 'lab'}
settingsIconChanged={topbar?.settingsIconChanged}
customIcon={topbarWidget?.customIcon}
/>
);

Expand Down
3 changes: 3 additions & 0 deletions src/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export type ISpectaUrlFactory = (path: string, ui?: string) => string;
export interface ISpectaUiSwitcher {
uis: IUiOption[];
switchTo: (path: string, ui: string) => void;
label?: string;
}
export const ISpectaLayoutRegistry = new Token<ISpectaLayoutRegistry>(
'specta:ISpectaLayoutRegistry'
Expand Down Expand Up @@ -108,6 +109,8 @@ export interface ISpectaTopbarWidget {
) => Widget;
addSettingsWidget?: (widget: ISpectaWidget) => void;
settingsWidgets?: ISpectaWidget[];
setSettingsIcon?: (icon: JSX.Element) => void;
customIcon?: JSX.Element;
}
export const ISpectaTopbarWidgetToken = new Token<ISpectaTopbarWidget>(
'specta:ISpectaTopbarWidget'
Expand Down
2 changes: 2 additions & 0 deletions src/topbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export const topbarPlugin: JupyterFrontEndPlugin<
uiSwitcher={uiSwitcher}
currentPath={path}
currentUi={isSpecta ? 'specta' : 'lab'}
settingsIconChanged={widget.settingsIconChanged}
customIcon={widget.customIcon}
/>
);
widget.addReactWidget(menu, 'right', 10000);
Expand Down
33 changes: 30 additions & 3 deletions src/topbar/menuComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IThemeManager } from '@jupyterlab/apputils';
import React, { useState, useRef, useEffect } from 'react';
import { ISignal } from '@lumino/signaling';

import { GearIcon } from '../components/icon/gear';
import { IconButton } from '../components/iconButton';
Expand All @@ -13,12 +14,21 @@ interface IProps {
uiSwitcher?: ISpectaUiSwitcher | null;
currentPath?: string | null;
currentUi?: string;
settingsIconChanged?: ISignal<any, JSX.Element>;
customIcon?: JSX.Element;
}

export function MenuComponent(props: IProps): JSX.Element {
const [open, setOpen] = useState(false);
const buttonRef = useRef<HTMLButtonElement>(null);
const dialogRef = useRef<HTMLDivElement>(null);
const [customIcon, setCustomIcon] = useState<JSX.Element | undefined>(
props.customIcon
);

useEffect(() => {
setCustomIcon(props.customIcon);
}, [props.customIcon]);

useEffect(() => {
const handleClickOutside = (e: any) => {
Expand All @@ -34,14 +44,31 @@ export function MenuComponent(props: IProps): JSX.Element {
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);

useEffect(() => {
const signal = props.settingsIconChanged;
if (!signal) {
return;
}
const handler = (_sender: any, icon: JSX.Element) => {
setCustomIcon(icon);
};
signal.connect(handler);
return () => {
signal.disconnect(handler);
};
}, [props.settingsIconChanged]);

const menuIcon = customIcon || (
<GearIcon fill="var(--jp-ui-font-color2)" height={23} width={23} />
);

return (
<div className="specta-topbar-right">
<IconButton
ref={buttonRef}
onClick={() => setOpen(!open)}
icon={
<GearIcon fill="var(--jp-ui-font-color2)" height={23} width={23} />
}
icon={menuIcon}
/>

{open && (
Expand Down
2 changes: 1 addition & 1 deletion src/topbar/settingDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export const SettingContent = (props: {
)}
{currentPath && uiSwitcher && uiSwitcher.uis.length > 0 && (
<div>
<label htmlFor="">Select UI</label>
<label htmlFor="">{uiSwitcher.label ?? 'Select UI'}</label>
<div className="jp-select-wrapper">
<select
className=" jp-mod-styled specta-topbar-theme"
Expand Down
16 changes: 16 additions & 0 deletions src/topbar/topbarWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ReactWidget } from '@jupyterlab/apputils';
import { Panel, Widget } from '@lumino/widgets';
import { Signal, ISignal } from '@lumino/signaling';

import { ITopbarConfig, ISpectaWidget } from '../token';
import { RankedPanel } from './rankedPanel';
Expand Down Expand Up @@ -55,9 +56,24 @@ export class TopbarWidget extends Panel {
return this._settingsWidgets;
}

setSettingsIcon(icon: JSX.Element): void {
this._customIcon = icon;
this._settingsIconChanged.emit(icon);
}

get settingsIconChanged(): ISignal<this, JSX.Element> {
return this._settingsIconChanged;
}

get customIcon(): JSX.Element | undefined {
return this._customIcon;
}

private _leftSide = new RankedPanel();
private _rightSide = new RankedPanel();
private _settingsWidgets: ISpectaWidget[] = [];
private _settingsIconChanged = new Signal<this, JSX.Element>(this);
private _customIcon: JSX.Element | undefined;

private _config: ITopbarConfig;
}
Expand Down
Loading