jupyter-specta 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -1
- package/lib/app.js +2 -0
- package/lib/document/factory.js +0 -4
- package/lib/document/plugin.js +6 -2
- package/lib/shell.js +1 -0
- package/lib/tool.js +9 -17
- package/lib/topbar/index.js +0 -4
- package/lib/topbar/widget.js +4 -3
- package/package.json +3 -1
- package/style/base.css +6 -8
- package/style/style.css +6 -1
package/README.md
CHANGED
|
@@ -43,7 +43,55 @@ Once installed, you can build your JupyterLite app, a `specta` app will be inclu
|
|
|
43
43
|
jupyter lite build
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
Then serve the contents of the output directory (by default `./_output`) using any static file server. You can access the `
|
|
46
|
+
Then serve the contents of the output directory (by default `./_output`) using any static file server. You can access the `Specta` app at the `/specta/` path.
|
|
47
|
+
|
|
48
|
+
## Specta Configuration
|
|
49
|
+
|
|
50
|
+
### Top-level configuration
|
|
51
|
+
|
|
52
|
+
Specta can be configured using the typicall JupyterLite configuration file: `jupyter-lite.json`. You can add a `spectaConfig` key to the `jupyter-config-data` section of this file to customize the Specta app.
|
|
53
|
+
|
|
54
|
+
The following options are available:
|
|
55
|
+
|
|
56
|
+
- `defaultLayout`: The default layout when opening a file.
|
|
57
|
+
- `hideTopbar`: Boolean flag to show or hide the top bar.
|
|
58
|
+
- `topBar`: Configuration for the top bar.
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
"topBar": {
|
|
62
|
+
"icon": "url to the icon file, it's shown on the left of the top bar",
|
|
63
|
+
"title": "Title on the left of the top bar",
|
|
64
|
+
"themeToggle": "Boolean flag to show/hide the theme selector",
|
|
65
|
+
"textColor": "Color of the text on the top bar",
|
|
66
|
+
"background": "Background color of the top bar"
|
|
67
|
+
},
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- `perFileConfig`: an object with key is the file path and value is the above configuration, it's used to have different layout/top bar config for each files, for example:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
"perFileConfig": {
|
|
74
|
+
"blog.ipynb": {
|
|
75
|
+
"hideTopbar": false,
|
|
76
|
+
"defaultLayout": "article",
|
|
77
|
+
"topBar": {
|
|
78
|
+
"title": "My blog",
|
|
79
|
+
"themeToggle": false
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Notebook specific configuration
|
|
86
|
+
|
|
87
|
+
By default, when you open a notebook in Specta, all code cells are hidden, and placeholder skeletons are shown instead at the position of the cell. You can configure the visibility of each cell by using the Specta cell metadata toolbar.
|
|
88
|
+
|
|
89
|
+

|
|
90
|
+
|
|
91
|
+
By opening the `Property Inspector` panel of JupyterLab and selecting the `Specta Cell Config` section, you can change the visibility of each cell as follows:
|
|
92
|
+
|
|
93
|
+
- `Show cell source`: use this toggle to show or hide the cell source code. Default to `false`
|
|
94
|
+
- `Show output placeholder`: use this toggle to show or hide the output skeleton. Default to `true`
|
|
47
95
|
|
|
48
96
|
## Try it online!
|
|
49
97
|
|
package/lib/app.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { JupyterFrontEnd, createRendermimePlugins } from '@jupyterlab/application';
|
|
2
2
|
import { SpectaShell } from './shell';
|
|
3
3
|
import { PageConfig } from '@jupyterlab/coreutils';
|
|
4
|
+
import { Base64ModelFactory } from '@jupyterlab/docregistry';
|
|
4
5
|
export class SpectaApp extends JupyterFrontEnd {
|
|
5
6
|
constructor(options) {
|
|
6
7
|
var _a;
|
|
@@ -17,6 +18,7 @@ export class SpectaApp extends JupyterFrontEnd {
|
|
|
17
18
|
* The version of the application.
|
|
18
19
|
*/
|
|
19
20
|
this.version = '1.0.0';
|
|
21
|
+
this.docRegistry.addModelFactory(new Base64ModelFactory());
|
|
20
22
|
if (options.mimeExtensions) {
|
|
21
23
|
for (const plugin of createRendermimePlugins(options.mimeExtensions)) {
|
|
22
24
|
this.registerPlugin(plugin);
|
package/lib/document/factory.js
CHANGED
|
@@ -35,10 +35,6 @@ export class NotebookGridWidgetFactory extends ABCWidgetFactory {
|
|
|
35
35
|
// Specta app, add topbar to layout
|
|
36
36
|
topbar.id = 'specta-topbar-widget';
|
|
37
37
|
this._shell.add(topbar, 'top');
|
|
38
|
-
if (topbar.parent) {
|
|
39
|
-
topbar.parent.node.style.boxShadow =
|
|
40
|
-
'rgba(0 0 0 / 20%) 0 2px 4px -1px, rgba(0 0 0 / 14%) 0 4px 5px 0, rgba(0 0 0 / 12%) 0 1px 10px 0';
|
|
41
|
-
}
|
|
42
38
|
}
|
|
43
39
|
}
|
|
44
40
|
else if (isSpecta) {
|
package/lib/document/plugin.js
CHANGED
|
@@ -6,6 +6,7 @@ import { IDefaultFileBrowser } from '@jupyterlab/filebrowser';
|
|
|
6
6
|
import { INotebookTracker, NotebookPanel } from '@jupyterlab/notebook';
|
|
7
7
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
8
8
|
import { IKernelSpecManager } from '@jupyterlab/services';
|
|
9
|
+
import { Widget } from '@lumino/widgets';
|
|
9
10
|
import { ISpectaDocTracker, ISpectaLayoutRegistry } from '../token';
|
|
10
11
|
import { createFileBrowser, hideAppLoadingIndicator, isSpectaApp, registerDocumentFactory } from '../tool';
|
|
11
12
|
const activate = (app, rendermime, tracker, editorServices, contentFactory, spectaLayoutRegistry, themeManager) => {
|
|
@@ -70,7 +71,7 @@ export const spectaOpener = {
|
|
|
70
71
|
else {
|
|
71
72
|
let count = 0;
|
|
72
73
|
const tryOpen = () => {
|
|
73
|
-
const widget = docManager.openOrReveal(path);
|
|
74
|
+
const widget = docManager.openOrReveal(path, 'default');
|
|
74
75
|
if (widget) {
|
|
75
76
|
app.shell.add(widget, 'main');
|
|
76
77
|
hideAppLoadingIndicator();
|
|
@@ -79,7 +80,10 @@ export const spectaOpener = {
|
|
|
79
80
|
count++;
|
|
80
81
|
if (count > 10) {
|
|
81
82
|
console.error('Failed to open file', path);
|
|
82
|
-
|
|
83
|
+
const widget = new Widget();
|
|
84
|
+
widget.node.innerHTML = `<h2 style="text-align: center; margin-top: 200px;">Failed to open file ${path}</h2>`;
|
|
85
|
+
app.shell.add(widget, 'main');
|
|
86
|
+
hideAppLoadingIndicator();
|
|
83
87
|
return;
|
|
84
88
|
}
|
|
85
89
|
setTimeout(tryOpen, 100);
|
package/lib/shell.js
CHANGED
|
@@ -33,6 +33,7 @@ export class SpectaShell extends Widget {
|
|
|
33
33
|
rootLayout.addWidget(topHandler.panel);
|
|
34
34
|
const hboxPanel = (this._mainPanel = new BoxPanel());
|
|
35
35
|
hboxPanel.id = 'jp-main-content-panel';
|
|
36
|
+
hboxPanel.addClass('specta-main-content-panel');
|
|
36
37
|
hboxPanel.direction = 'top-to-bottom';
|
|
37
38
|
BoxLayout.setStretch(hboxPanel, 1);
|
|
38
39
|
rootLayout.addWidget(hboxPanel);
|
package/lib/tool.js
CHANGED
|
@@ -10,7 +10,6 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
|
|
13
|
-
import { NotebookModelFactory } from '@jupyterlab/notebook';
|
|
14
13
|
import { NotebookGridWidgetFactory } from './document/factory';
|
|
15
14
|
import { SpectaWidgetFactory } from './specta_widget_factory';
|
|
16
15
|
export function registerDocumentFactory(options) {
|
|
@@ -27,26 +26,14 @@ export function registerDocumentFactory(options) {
|
|
|
27
26
|
const widgetFactory = new NotebookGridWidgetFactory({
|
|
28
27
|
name: factoryName,
|
|
29
28
|
modelName: 'notebook',
|
|
30
|
-
fileTypes: ['
|
|
31
|
-
spectaWidgetFactory,
|
|
29
|
+
fileTypes: ['notebook'],
|
|
32
30
|
shell: app.shell,
|
|
31
|
+
spectaWidgetFactory,
|
|
33
32
|
themeManager,
|
|
34
33
|
spectaLayoutRegistry
|
|
35
34
|
});
|
|
36
35
|
// Registering the widget factory
|
|
37
36
|
app.docRegistry.addWidgetFactory(widgetFactory);
|
|
38
|
-
// Creating and registering the model factory for our custom DocumentModelAdd commentMore actions
|
|
39
|
-
const modelFactory = new NotebookModelFactory({});
|
|
40
|
-
app.docRegistry.addModelFactory(modelFactory);
|
|
41
|
-
// register the filetype
|
|
42
|
-
app.docRegistry.addFileType({
|
|
43
|
-
name: 'ipynb',
|
|
44
|
-
displayName: 'IPYNB',
|
|
45
|
-
mimeTypes: ['text/json'],
|
|
46
|
-
extensions: ['.ipynb', '.IPYNB'],
|
|
47
|
-
fileFormat: 'json',
|
|
48
|
-
contentType: 'notebook'
|
|
49
|
-
});
|
|
50
37
|
widgetFactory.widgetCreated.connect((sender, widget) => {
|
|
51
38
|
widget.context.pathChanged.connect(() => {
|
|
52
39
|
spectaTracker.save(widget);
|
|
@@ -109,10 +96,15 @@ export function readSpectaConfig({ nbMetadata, nbPath }) {
|
|
|
109
96
|
if (!rawConfig || rawConfig.length === 0) {
|
|
110
97
|
rawConfig = '{}';
|
|
111
98
|
}
|
|
99
|
+
let pathWithoutDrive = nbPath;
|
|
100
|
+
const paths = nbPath === null || nbPath === void 0 ? void 0 : nbPath.split(':');
|
|
101
|
+
if (paths && paths.length > 1) {
|
|
102
|
+
pathWithoutDrive = paths[1];
|
|
103
|
+
}
|
|
112
104
|
const _b = JSON.parse(rawConfig), { perFileConfig } = _b, globalConfig = __rest(_b, ["perFileConfig"]);
|
|
113
105
|
let spectaConfig = Object.assign({}, (globalConfig !== null && globalConfig !== void 0 ? globalConfig : {}));
|
|
114
|
-
if (perFileConfig &&
|
|
115
|
-
spectaConfig = Object.assign(Object.assign({}, spectaConfig), perFileConfig[
|
|
106
|
+
if (perFileConfig && pathWithoutDrive && perFileConfig[pathWithoutDrive]) {
|
|
107
|
+
spectaConfig = Object.assign(Object.assign({}, spectaConfig), perFileConfig[pathWithoutDrive]);
|
|
116
108
|
}
|
|
117
109
|
const spectaMetadata = ((_a = nbMetadata === null || nbMetadata === void 0 ? void 0 : nbMetadata.specta) !== null && _a !== void 0 ? _a : {});
|
|
118
110
|
return Object.assign(Object.assign({}, spectaConfig), spectaMetadata);
|
package/lib/topbar/index.js
CHANGED
|
@@ -30,9 +30,5 @@ export const topbarPlugin = {
|
|
|
30
30
|
widget.id = 'specta-topbar-widget';
|
|
31
31
|
widget.addClass('specta-topbar-element');
|
|
32
32
|
app.shell.add(widget, 'top');
|
|
33
|
-
if (widget.parent) {
|
|
34
|
-
widget.parent.node.style.boxShadow =
|
|
35
|
-
'rgba(0 0 0 / 20%) 0 2px 4px -1px, rgba(0 0 0 / 14%) 0 4px 5px 0, rgba(0 0 0 / 12%) 0 1px 10px 0';
|
|
36
|
-
}
|
|
37
33
|
}
|
|
38
34
|
};
|
package/lib/topbar/widget.js
CHANGED
|
@@ -5,13 +5,14 @@ import { SettingContent } from './settingDialog';
|
|
|
5
5
|
export function TopbarElement(props) {
|
|
6
6
|
var _a, _b;
|
|
7
7
|
const config = React.useMemo(() => {
|
|
8
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
8
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
9
9
|
return {
|
|
10
10
|
background: (_b = (_a = props.config) === null || _a === void 0 ? void 0 : _a.background) !== null && _b !== void 0 ? _b : 'var(--jp-layout-color2)',
|
|
11
11
|
title: (_d = (_c = props.config) === null || _c === void 0 ? void 0 : _c.title) !== null && _d !== void 0 ? _d : 'Specta',
|
|
12
12
|
themeToggle: Boolean((_e = props.config) === null || _e === void 0 ? void 0 : _e.themeToggle),
|
|
13
13
|
kernelActivity: Boolean((_f = props.config) === null || _f === void 0 ? void 0 : _f.kernelActivity),
|
|
14
|
-
textColor: (_h = (_g = props.config) === null || _g === void 0 ? void 0 : _g.textColor) !== null && _h !== void 0 ? _h : 'var(--jp-ui-font-color1)'
|
|
14
|
+
textColor: (_h = (_g = props.config) === null || _g === void 0 ? void 0 : _g.textColor) !== null && _h !== void 0 ? _h : 'var(--jp-ui-font-color1)',
|
|
15
|
+
icon: (_j = props.config) === null || _j === void 0 ? void 0 : _j.icon
|
|
15
16
|
};
|
|
16
17
|
}, [props.config]);
|
|
17
18
|
const [open, setOpen] = useState(false);
|
|
@@ -34,7 +35,7 @@ export function TopbarElement(props) {
|
|
|
34
35
|
React.createElement("div", null, config.icon && React.createElement("img", { style: { width: '50px' }, src: config.icon })),
|
|
35
36
|
React.createElement("div", { className: "specta-topbar-title", style: { color: (_b = config.textColor) !== null && _b !== void 0 ? _b : 'var(--jp-ui-font-color1)' } }, config.title)),
|
|
36
37
|
React.createElement("div", { className: "specta-topbar-right" },
|
|
37
|
-
React.createElement(IconButton, { ref: buttonRef, onClick: () => setOpen(!open), icon: React.createElement(GearIcon, { fill: "var(--jp-ui-font-color2)", height:
|
|
38
|
+
React.createElement(IconButton, { ref: buttonRef, onClick: () => setOpen(!open), icon: React.createElement(GearIcon, { fill: "var(--jp-ui-font-color2)", height: 23, width: 23 }) }),
|
|
38
39
|
open && (React.createElement("div", { ref: dialogRef, className: "jp-Dialog-content specta-config-dialog" },
|
|
39
40
|
React.createElement("div", { className: "specta-config-arrow" }),
|
|
40
41
|
React.createElement(SettingContent, { themeManager: props.themeManager, layoutRegistry: props.layoutRegistry }))))));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jupyter-specta",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"homepage": "https://github.com/trungleduc/specta",
|
|
@@ -60,6 +60,8 @@
|
|
|
60
60
|
"@jupyterlab/docregistry": "^4.4.2",
|
|
61
61
|
"@jupyterlab/filebrowser": "^4.4.2",
|
|
62
62
|
"@jupyterlab/filebrowser-extension": "^4.4.2",
|
|
63
|
+
"@jupyterlab/imageviewer": "^4.4.2",
|
|
64
|
+
"@jupyterlab/imageviewer-extension": "^4.4.2",
|
|
63
65
|
"@jupyterlab/json-extension": "^4.4.2",
|
|
64
66
|
"@jupyterlab/logconsole": "^4.4.2",
|
|
65
67
|
"@jupyterlab/mainmenu": "^4.4.2",
|
package/style/base.css
CHANGED
|
@@ -55,10 +55,11 @@
|
|
|
55
55
|
|
|
56
56
|
.jp-specta-notebook-panel {
|
|
57
57
|
overflow: auto;
|
|
58
|
+
padding: 0 5px 5px 5px;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
#specta-top-panel {
|
|
61
|
-
min-height:
|
|
62
|
+
min-height: 36px;
|
|
62
63
|
display: flex;
|
|
63
64
|
box-shadow: unset !important;
|
|
64
65
|
z-index: 100;
|
|
@@ -73,12 +74,9 @@
|
|
|
73
74
|
.specta-topbar {
|
|
74
75
|
display: flex;
|
|
75
76
|
flex-direction: row;
|
|
76
|
-
height:
|
|
77
|
+
height: 36px;
|
|
77
78
|
width: calc(100% + 20px);
|
|
78
|
-
|
|
79
|
-
rgba(0 0 0 / 20%) 0 2px 4px -1px,
|
|
80
|
-
rgba(0 0 0 / 14%) 0 4px 5px 0,
|
|
81
|
-
rgba(0 0 0 / 12%) 0 1px 10px 0;
|
|
79
|
+
border-bottom: solid 0.5px var(--jp-border-color1);
|
|
82
80
|
gap: 10px;
|
|
83
81
|
align-items: center;
|
|
84
82
|
justify-content: space-between;
|
|
@@ -97,8 +95,8 @@
|
|
|
97
95
|
}
|
|
98
96
|
|
|
99
97
|
.specta-topbar-title {
|
|
100
|
-
line-height:
|
|
101
|
-
font-size: 1.
|
|
98
|
+
line-height: 36px;
|
|
99
|
+
font-size: 1.25rem;
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
.specta-topbar-theme {
|
package/style/style.css
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
background: var(--jp-layout-color1);
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
.specta-document-viewer #jp-main-content-panel jp-toolbar {
|
|
7
|
+
.specta-document-viewer #jp-main-content-panel jp-toolbar:first-of-type {
|
|
8
8
|
display: none;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -26,3 +26,8 @@
|
|
|
26
26
|
background: var(--jp-layout-color1);
|
|
27
27
|
box-shadow: var(--jp-elevation-z4);
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
.specta-main-content-panel {
|
|
31
|
+
padding-left: 5px;
|
|
32
|
+
padding-right: 5px;
|
|
33
|
+
}
|