jupyter-specta 0.1.5 → 0.1.7

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 CHANGED
@@ -1 +1,52 @@
1
- # specta
1
+ <h1 align="center">specta 🌟</h1>
2
+
3
+ [![Github Actions Status](https://github.com/trungleduc/specta/workflows/Build/badge.svg)](https://github.com/trungleduc/specta/actions/workflows/build.yml)
4
+ [![Documentation Status](https://readthedocs.org/projects/specta/badge/?version=latest)](https://specta.readthedocs.io/en/latest/?badge=latest)
5
+ [![Try on lite](https://jupyterlite.rtfd.io/en/latest/_static/badge.svg)](https://trungleduc.github.io/specta/specta/)
6
+
7
+ <h2 align="center"> A JupyterLite app to present your Jupyter documents in different ways</h2>
8
+
9
+ Specta is a custom JupyterLite app for rendering notebooks and Jupyter‑supported files in multiple modes: dashboards, blog‑style articles, fullscreen viewers, and more. It is built on top of [JupyterLite](https://github.com/jupyterlite/jupyterlite), which allows you to share your documents through alternative interfaces to the IDE-like JupyterLab.
10
+
11
+ ## Features
12
+
13
+ ### Multi-mode Notebook Rendering
14
+
15
+ Render notebooks in:
16
+
17
+ - **Dashboard mode** – structured panels for interactive widgets and outputs
18
+ - **Article mode** – a minimal, blog-like reading experience
19
+
20
+ ### Clean Viewer for all Jupyter-supported file types
21
+
22
+ View any Jupyter-supported file using Specta's clean viewer with all Jupyter UI elements removed.
23
+
24
+ ### Preview from JupyterLab
25
+
26
+ A `specta` preview can be launched directly from JupyterLab, letting users verify how their documents will look when published.
27
+
28
+ ## Installation and Usage
29
+
30
+ You can install `specta` using `pip` or `conda`
31
+
32
+ ```bash
33
+ # Install using pip
34
+ pip install specta
35
+
36
+ # Install using conda
37
+ conda install -c conda-forge specta
38
+ ```
39
+
40
+ Once installed, you can build your JupyterLite app, a `specta` app will be included automatically in the output directory of `jupyterlite`:
41
+
42
+ ```
43
+ jupyter lite build
44
+ ```
45
+
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
+ ## Try it online!
49
+
50
+ You can try it online by clicking on this badge:
51
+
52
+ [![Try on lite](https://jupyterlite.rtfd.io/en/latest/_static/badge.svg)](https://trungleduc.github.io/specta/specta/)
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);
@@ -32,7 +32,6 @@ export async function createNotebookContext(options) {
32
32
  path,
33
33
  kernelPreference: kernelPreference
34
34
  });
35
- await context.sessionContext.initialize();
36
35
  return context;
37
36
  }
38
37
  export function createNotebookPanel(options) {
@@ -2,16 +2,21 @@ import { IThemeManager } from '@jupyterlab/apputils';
2
2
  import { ABCWidgetFactory, DocumentRegistry } from '@jupyterlab/docregistry';
3
3
  import { INotebookModel } from '@jupyterlab/notebook';
4
4
  import { SpectaWidgetFactory } from '../specta_widget_factory';
5
- import { ISpectaLayoutRegistry } from '../token';
5
+ import { ISpectaLayoutRegistry, ISpectaShell } from '../token';
6
6
  import { NotebookSpectaDocWidget } from './widget';
7
7
  interface IOptions extends DocumentRegistry.IWidgetFactoryOptions {
8
8
  spectaWidgetFactory: SpectaWidgetFactory;
9
9
  layoutRegistry?: ISpectaLayoutRegistry;
10
10
  themeManager?: IThemeManager;
11
+ shell: ISpectaShell;
12
+ spectaLayoutRegistry: ISpectaLayoutRegistry;
11
13
  }
12
14
  export declare class NotebookGridWidgetFactory extends ABCWidgetFactory<NotebookSpectaDocWidget, INotebookModel> {
13
15
  constructor(options: IOptions);
14
16
  protected createNewWidget(context: DocumentRegistry.IContext<INotebookModel>): NotebookSpectaDocWidget;
15
17
  private _spectaWidgetFactory;
18
+ private _shell;
19
+ private _themeManager?;
20
+ private _layoutRegistry;
16
21
  }
17
22
  export {};
@@ -9,17 +9,41 @@ export class NotebookGridWidgetFactory extends ABCWidgetFactory {
9
9
  constructor(options) {
10
10
  super(options);
11
11
  this._spectaWidgetFactory = options.spectaWidgetFactory;
12
+ this._shell = options.shell;
13
+ this._themeManager = options.themeManager;
14
+ this._layoutRegistry = options.spectaLayoutRegistry;
12
15
  }
13
16
  createNewWidget(context) {
14
17
  const content = new Panel();
15
18
  content.addClass('jp-specta-notebook-panel');
16
- const spectaConfig = readSpectaConfig(context.model.metadata);
17
- if (!isSpectaApp() && !spectaConfig.hideTopbar) {
18
- // Not a specta app, add topbar to document widget
19
- const topbar = ReactWidget.create(React.createElement(TopbarElement, null));
20
- content.addWidget(topbar);
21
- }
22
19
  context.ready.then(async () => {
20
+ var _a;
21
+ const path = (_a = context.contentsModel) === null || _a === void 0 ? void 0 : _a.path;
22
+ const spectaConfig = readSpectaConfig({
23
+ nbMetadata: context.model.metadata,
24
+ nbPath: path
25
+ });
26
+ const isSpecta = isSpectaApp();
27
+ if (!spectaConfig.hideTopbar) {
28
+ const topbar = ReactWidget.create(React.createElement(TopbarElement, { config: spectaConfig.topBar, themeManager: this._themeManager, layoutRegistry: this._layoutRegistry }));
29
+ topbar.addClass('specta-topbar-element');
30
+ if (!isSpecta) {
31
+ // Not a specta app, add topbar to document widget
32
+ content.addWidget(topbar);
33
+ }
34
+ else {
35
+ // Specta app, add topbar to layout
36
+ topbar.id = 'specta-topbar-widget';
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
+ }
43
+ }
44
+ else if (isSpecta) {
45
+ this._shell.hideTopBar();
46
+ }
23
47
  const spectaWidget = await this._spectaWidgetFactory.createNew({
24
48
  context
25
49
  });
@@ -1,4 +1,5 @@
1
1
  import { JupyterFrontEndPlugin } from '@jupyterlab/application';
2
2
  import { IWidgetTracker } from '@jupyterlab/apputils';
3
- export declare const spectaDocument: JupyterFrontEndPlugin<IWidgetTracker>;
3
+ import { ISpectaShell } from '../token';
4
+ export declare const spectaDocument: JupyterFrontEndPlugin<IWidgetTracker, ISpectaShell>;
4
5
  export declare const spectaOpener: JupyterFrontEndPlugin<void>;
@@ -1,4 +1,4 @@
1
- import { WidgetTracker } from '@jupyterlab/apputils';
1
+ import { IThemeManager, WidgetTracker } from '@jupyterlab/apputils';
2
2
  import { IEditorServices } from '@jupyterlab/codeeditor';
3
3
  import { PathExt } from '@jupyterlab/coreutils';
4
4
  import { IDocumentManager } from '@jupyterlab/docmanager';
@@ -6,9 +6,10 @@ 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
- const activate = (app, rendermime, tracker, editorServices, contentFactory, spectaLayoutRegistry) => {
12
+ const activate = (app, rendermime, tracker, editorServices, contentFactory, spectaLayoutRegistry, themeManager) => {
12
13
  const namespace = 'specta';
13
14
  const spectaTracker = new WidgetTracker({ namespace });
14
15
  registerDocumentFactory({
@@ -19,7 +20,8 @@ const activate = (app, rendermime, tracker, editorServices, contentFactory, spec
19
20
  editorServices,
20
21
  contentFactory,
21
22
  spectaTracker,
22
- spectaLayoutRegistry
23
+ spectaLayoutRegistry,
24
+ themeManager
23
25
  });
24
26
  return spectaTracker;
25
27
  };
@@ -31,7 +33,8 @@ export const spectaDocument = {
31
33
  INotebookTracker,
32
34
  IEditorServices,
33
35
  NotebookPanel.IContentFactory,
34
- ISpectaLayoutRegistry
36
+ ISpectaLayoutRegistry,
37
+ IThemeManager
35
38
  ],
36
39
  activate,
37
40
  provides: ISpectaDocTracker
@@ -68,7 +71,7 @@ export const spectaOpener = {
68
71
  else {
69
72
  let count = 0;
70
73
  const tryOpen = () => {
71
- const widget = docManager.openOrReveal(path);
74
+ const widget = docManager.openOrReveal(path, 'default');
72
75
  if (widget) {
73
76
  app.shell.add(widget, 'main');
74
77
  hideAppLoadingIndicator();
@@ -77,7 +80,10 @@ export const spectaOpener = {
77
80
  count++;
78
81
  if (count > 10) {
79
82
  console.error('Failed to open file', path);
80
- //TODO Open in text editor?
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();
81
87
  return;
82
88
  }
83
89
  setTimeout(tryOpen, 100);
@@ -1,4 +1,4 @@
1
1
  export * from './tool';
2
2
  export * from './token';
3
- declare const _default: (import("@jupyterlab/application").JupyterFrontEndPlugin<import("@jupyterlab/apputils").IWidgetTracker<import("@lumino/widgets").Widget>> | import("@jupyterlab/application").JupyterFrontEndPlugin<void> | import("@jupyterlab/application").JupyterFrontEndPlugin<import("./token").ISpectaLayoutRegistry>)[];
3
+ declare const _default: (import("@jupyterlab/application").JupyterFrontEndPlugin<import("@jupyterlab/apputils").IWidgetTracker<import("@lumino/widgets").Widget>, import("./token").ISpectaShell> | import("@jupyterlab/application").JupyterFrontEndPlugin<import("./token").ISpectaLayoutRegistry> | import("@jupyterlab/application").JupyterFrontEndPlugin<void, import("./token").ISpectaShell>)[];
4
4
  export default _default;
@@ -8,7 +8,7 @@ export const spectaLayoutRegistry = {
8
8
  activate: (app) => {
9
9
  var _a;
10
10
  const layoutRegistry = new SpectaLayoutRegistry();
11
- const spectaConfig = readSpectaConfig();
11
+ const spectaConfig = readSpectaConfig({});
12
12
  const defaultLayout = (_a = spectaConfig.defaultLayout) !== null && _a !== void 0 ? _a : 'default';
13
13
  layoutRegistry.setSelectedLayout(defaultLayout);
14
14
  return layoutRegistry;
package/lib/shell.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { JupyterFrontEnd } from '@jupyterlab/application';
2
1
  import { DocumentRegistry } from '@jupyterlab/docregistry';
3
2
  import { Widget } from '@lumino/widgets';
3
+ import { ISpectaShell } from './token';
4
4
  /**
5
5
  * A namespace for Shell statics
6
6
  */
@@ -13,7 +13,7 @@ export declare namespace IShell {
13
13
  /**
14
14
  * The application shell.
15
15
  */
16
- export declare class SpectaShell extends Widget implements JupyterFrontEnd.IShell {
16
+ export declare class SpectaShell extends Widget implements ISpectaShell {
17
17
  constructor();
18
18
  /**
19
19
  * The current widget in the shell's main area.
@@ -30,6 +30,7 @@ export declare class SpectaShell extends Widget implements JupyterFrontEnd.IShel
30
30
  *
31
31
  */
32
32
  add(widget: Widget, area?: IShell.Area, options?: DocumentRegistry.IOpenOptions): void;
33
+ hideTopBar(): void;
33
34
  widgets(area: IShell.Area): IterableIterator<Widget>;
34
35
  /**
35
36
  * Add a widget to the top content area.
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);
@@ -78,6 +79,9 @@ export class SpectaShell extends Widget {
78
79
  break;
79
80
  }
80
81
  }
82
+ hideTopBar() {
83
+ this._topHandler.panel.hide();
84
+ }
81
85
  widgets(area) {
82
86
  switch (area) {
83
87
  case 'top':
@@ -2,7 +2,6 @@ import { CodeCell, MarkdownCell, RawCell } from '@jupyterlab/cells';
2
2
  import { OutputAreaModel, SimplifiedOutputArea } from '@jupyterlab/outputarea';
3
3
  import { createNotebookContext, createNotebookPanel } from './create_notebook_panel';
4
4
  import { SpectaCellOutput } from './specta_cell_output';
5
- import { PromiseDelegate } from '@lumino/coreutils';
6
5
  import { readCellConfig } from './tool';
7
6
  export const VIEW = 'grid_default';
8
7
  export class AppModel {
@@ -49,41 +48,18 @@ export class AppModel {
49
48
  return this._notebookPanel;
50
49
  }
51
50
  async initialize() {
52
- var _a;
53
- const pd = new PromiseDelegate();
54
51
  this._context = await createNotebookContext({
55
52
  manager: this._manager,
56
53
  kernelPreference: this._kernelPreference
57
54
  });
58
55
  this._context.model.fromJSON(this._notebookModelJson);
59
- const connectKernel = () => {
60
- pd.resolve();
61
- this._notebookPanel = createNotebookPanel({
62
- context: this._context,
63
- rendermime: this.options.rendermime,
64
- editorServices: this.options.editorServices
65
- });
66
- this.options.tracker.widgetAdded.emit(this._notebookPanel);
67
- };
68
- const kernel = (_a = this._context.sessionContext.session) === null || _a === void 0 ? void 0 : _a.kernel;
69
- if (kernel) {
70
- const status = kernel.status;
71
- if (status !== 'unknown') {
72
- // Connected to an existing kernel.
73
- connectKernel();
74
- return;
75
- }
76
- }
77
- this._context.sessionContext.connectionStatusChanged.connect((_, status) => {
78
- var _a;
79
- if (status === 'connected') {
80
- const kernel = (_a = this._context.sessionContext.session) === null || _a === void 0 ? void 0 : _a.kernel;
81
- if (kernel) {
82
- connectKernel();
83
- }
84
- }
85
- }, this);
86
- return pd.promise;
56
+ this._notebookPanel = createNotebookPanel({
57
+ context: this._context,
58
+ rendermime: this.options.rendermime,
59
+ editorServices: this.options.editorServices
60
+ });
61
+ this.options.tracker.add(this._notebookPanel);
62
+ await this._context.sessionContext.initialize();
87
63
  }
88
64
  createCell(cellModel) {
89
65
  let item;
@@ -8,6 +8,7 @@ export class SpectaWidgetFactory {
8
8
  this._options = options;
9
9
  }
10
10
  async createNew(options) {
11
+ var _a;
11
12
  const { context } = options;
12
13
  const rendermime = this._options.rendermime.clone({
13
14
  resolver: context.urlResolver
@@ -23,12 +24,16 @@ export class SpectaWidgetFactory {
23
24
  notebookConfig: StaticNotebook.defaultNotebookConfig,
24
25
  editorServices: this._options.editorServices
25
26
  });
27
+ const spectaConfig = readSpectaConfig({
28
+ nbMetadata: context.model.metadata,
29
+ nbPath: (_a = context.contentsModel) === null || _a === void 0 ? void 0 : _a.path
30
+ });
26
31
  const panel = new AppWidget({
27
32
  id: UUID.uuid4(),
28
33
  label: '',
29
34
  model,
30
35
  layoutRegistry: this._options.spectaLayoutRegistry,
31
- spectaConfig: readSpectaConfig(context.model.metadata)
36
+ spectaConfig
32
37
  });
33
38
  return panel;
34
39
  }
package/lib/token.d.ts CHANGED
@@ -4,6 +4,10 @@ import { SpectaCellOutput } from './specta_cell_output';
4
4
  import * as nbformat from '@jupyterlab/nbformat';
5
5
  import { ISignal } from '@lumino/signaling';
6
6
  import { IWidgetTracker } from '@jupyterlab/apputils';
7
+ import { JupyterFrontEnd } from '@jupyterlab/application';
8
+ export interface ISpectaShell extends JupyterFrontEnd.IShell {
9
+ hideTopBar: () => void;
10
+ }
7
11
  export interface ISpectaLayout {
8
12
  render(options: {
9
13
  host: Panel;
package/lib/tool.d.ts CHANGED
@@ -1,25 +1,29 @@
1
1
  import { JupyterFrontEnd } from '@jupyterlab/application';
2
- import { WidgetTracker } from '@jupyterlab/apputils';
2
+ import { IThemeManager, WidgetTracker } from '@jupyterlab/apputils';
3
3
  import { IEditorServices } from '@jupyterlab/codeeditor';
4
4
  import { IDefaultFileBrowser } from '@jupyterlab/filebrowser';
5
5
  import { ICell, INotebookMetadata } from '@jupyterlab/nbformat';
6
6
  import { INotebookTracker, NotebookPanel } from '@jupyterlab/notebook';
7
7
  import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
8
- import { ISpectaAppConfig, ISpectaCellConfig, ISpectaLayoutRegistry } from './token';
8
+ import { ISpectaAppConfig, ISpectaCellConfig, ISpectaLayoutRegistry, ISpectaShell } from './token';
9
9
  export declare function registerDocumentFactory(options: {
10
10
  factoryName: string;
11
- app: JupyterFrontEnd;
11
+ app: JupyterFrontEnd<ISpectaShell>;
12
12
  rendermime: IRenderMimeRegistry;
13
13
  tracker: INotebookTracker;
14
14
  editorServices: IEditorServices;
15
15
  contentFactory: NotebookPanel.IContentFactory;
16
16
  spectaTracker: WidgetTracker;
17
17
  spectaLayoutRegistry: ISpectaLayoutRegistry;
18
+ themeManager?: IThemeManager;
18
19
  }): void;
19
20
  export declare function createFileBrowser(options: {
20
21
  defaultBrowser: IDefaultFileBrowser;
21
22
  }): any;
22
23
  export declare function hideAppLoadingIndicator(): void;
23
24
  export declare function isSpectaApp(): boolean;
24
- export declare function readSpectaConfig(nbMetadata?: INotebookMetadata): ISpectaAppConfig;
25
+ export declare function readSpectaConfig({ nbMetadata, nbPath }: {
26
+ nbMetadata?: INotebookMetadata;
27
+ nbPath?: string | null;
28
+ }): ISpectaAppConfig;
25
29
  export declare function readCellConfig(cell?: ICell): Required<ISpectaCellConfig>;
package/lib/tool.js CHANGED
@@ -1,9 +1,19 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
1
12
  import { PageConfig, URLExt } from '@jupyterlab/coreutils';
2
- import { NotebookModelFactory } from '@jupyterlab/notebook';
3
13
  import { NotebookGridWidgetFactory } from './document/factory';
4
14
  import { SpectaWidgetFactory } from './specta_widget_factory';
5
15
  export function registerDocumentFactory(options) {
6
- const { factoryName, app, rendermime, tracker, editorServices, contentFactory, spectaTracker, spectaLayoutRegistry } = options;
16
+ const { factoryName, app, rendermime, tracker, editorServices, contentFactory, spectaTracker, spectaLayoutRegistry, themeManager } = options;
7
17
  const spectaWidgetFactory = new SpectaWidgetFactory({
8
18
  manager: app.serviceManager,
9
19
  rendermime,
@@ -16,23 +26,14 @@ export function registerDocumentFactory(options) {
16
26
  const widgetFactory = new NotebookGridWidgetFactory({
17
27
  name: factoryName,
18
28
  modelName: 'notebook',
19
- fileTypes: ['ipynb'],
20
- spectaWidgetFactory
29
+ fileTypes: ['notebook'],
30
+ shell: app.shell,
31
+ spectaWidgetFactory,
32
+ themeManager,
33
+ spectaLayoutRegistry
21
34
  });
22
35
  // Registering the widget factory
23
36
  app.docRegistry.addWidgetFactory(widgetFactory);
24
- // Creating and registering the model factory for our custom DocumentModelAdd commentMore actions
25
- const modelFactory = new NotebookModelFactory({});
26
- app.docRegistry.addModelFactory(modelFactory);
27
- // register the filetype
28
- app.docRegistry.addFileType({
29
- name: 'ipynb',
30
- displayName: 'IPYNB',
31
- mimeTypes: ['text/json'],
32
- extensions: ['.ipynb', '.IPYNB'],
33
- fileFormat: 'json',
34
- contentType: 'notebook'
35
- });
36
37
  widgetFactory.widgetCreated.connect((sender, widget) => {
37
38
  widget.context.pathChanged.connect(() => {
38
39
  spectaTracker.save(widget);
@@ -89,13 +90,17 @@ export function hideAppLoadingIndicator() {
89
90
  export function isSpectaApp() {
90
91
  return !!document.querySelector('meta[name="specta-config"]');
91
92
  }
92
- export function readSpectaConfig(nbMetadata) {
93
+ export function readSpectaConfig({ nbMetadata, nbPath }) {
93
94
  var _a;
94
95
  let rawConfig = PageConfig.getOption('spectaConfig');
95
96
  if (!rawConfig || rawConfig.length === 0) {
96
97
  rawConfig = '{}';
97
98
  }
98
- const spectaConfig = JSON.parse(rawConfig);
99
+ const _b = JSON.parse(rawConfig), { perFileConfig } = _b, globalConfig = __rest(_b, ["perFileConfig"]);
100
+ let spectaConfig = Object.assign({}, (globalConfig !== null && globalConfig !== void 0 ? globalConfig : {}));
101
+ if (perFileConfig && nbPath && perFileConfig[nbPath]) {
102
+ spectaConfig = Object.assign(Object.assign({}, spectaConfig), perFileConfig[nbPath]);
103
+ }
99
104
  const spectaMetadata = ((_a = nbMetadata === null || nbMetadata === void 0 ? void 0 : nbMetadata.specta) !== null && _a !== void 0 ? _a : {});
100
105
  return Object.assign(Object.assign({}, spectaConfig), spectaMetadata);
101
106
  }
@@ -1,5 +1,3 @@
1
1
  import { JupyterFrontEndPlugin } from '@jupyterlab/application';
2
- /**
3
- * Initialization data for the voila_topbar extension.
4
- */
5
- export declare const topbarPlugin: JupyterFrontEndPlugin<void>;
2
+ import { ISpectaShell } from '../token';
3
+ export declare const topbarPlugin: JupyterFrontEndPlugin<void, ISpectaShell>;
@@ -4,11 +4,9 @@ import { TopbarElement } from './widget';
4
4
  import * as React from 'react';
5
5
  import { isSpectaApp, readSpectaConfig } from '../tool';
6
6
  import { ISpectaLayoutRegistry } from '../token';
7
- /**
8
- * Initialization data for the voila_topbar extension.
9
- */
7
+ import { PathExt } from '@jupyterlab/coreutils';
10
8
  export const topbarPlugin = {
11
- id: 'specta:topba',
9
+ id: 'specta:topbar',
12
10
  description: 'Specta topbar extension',
13
11
  autoStart: true,
14
12
  requires: [IThemeManager, ISpectaLayoutRegistry],
@@ -17,7 +15,17 @@ export const topbarPlugin = {
17
15
  if (!isSpecta) {
18
16
  return;
19
17
  }
20
- const config = readSpectaConfig();
18
+ const urlParams = new URLSearchParams(window.location.search);
19
+ const path = urlParams.get('path');
20
+ if (path && PathExt.extname(path) === '.ipynb') {
21
+ // Specta document will handle the top bar.
22
+ return;
23
+ }
24
+ const config = readSpectaConfig({ nbPath: path });
25
+ if (config.hideTopbar) {
26
+ app.shell.hideTopBar();
27
+ return;
28
+ }
21
29
  const widget = ReactWidget.create(React.createElement(TopbarElement, { config: config.topBar, themeManager: themeManager, layoutRegistry: layoutRegistry }));
22
30
  widget.id = 'specta-topbar-widget';
23
31
  widget.addClass('specta-topbar-element');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jupyter-specta",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/trungleduc/specta",
@@ -36,6 +36,7 @@
36
36
  "build:all": "npm run build:app && npm run build:labextension",
37
37
  "build:all:dev": "npm run build:app:dev && npm run build:labextension:dev",
38
38
  "build:demo": "cd demo && rm -rf .jupyterlite.doit.db _output && jupyter lite build .",
39
+ "update:demo": "node script/build-dev.mjs",
39
40
  "lint": "npm run lint:prettier && npm run lint:eslint",
40
41
  "lint:prettier": "prettier --no-error-on-unmatched-pattern --write \"**/*{.ts,.tsx,.jsx,.css,.json,.md,.yml}\"",
41
42
  "lint:eslint": "eslint --ext .ts,.tsx .",
@@ -56,9 +57,11 @@
56
57
  "@jupyterlab/coreutils": "^6.4.2",
57
58
  "@jupyterlab/docmanager": "^4.4.2",
58
59
  "@jupyterlab/docmanager-extension": "^4.4.2",
60
+ "@jupyterlab/docregistry": "^4.4.2",
59
61
  "@jupyterlab/filebrowser": "^4.4.2",
60
62
  "@jupyterlab/filebrowser-extension": "^4.4.2",
61
- "@jupyterlab/docregistry": "^4.4.2",
63
+ "@jupyterlab/imageviewer": "^4.4.2",
64
+ "@jupyterlab/imageviewer-extension": "^4.4.2",
62
65
  "@jupyterlab/json-extension": "^4.4.2",
63
66
  "@jupyterlab/logconsole": "^4.4.2",
64
67
  "@jupyterlab/mainmenu": "^4.4.2",
@@ -109,14 +112,15 @@
109
112
  },
110
113
  "devDependencies": {
111
114
  "@jupyterlab/builder": "~4.4.2",
115
+ "@types/react": "^18.0.26",
112
116
  "@typescript-eslint/eslint-plugin": "^6.1.0",
113
117
  "@typescript-eslint/parser": "^6.1.0",
114
- "@types/react": "^18.0.26",
115
118
  "css-loader": "^7.1.2",
116
119
  "eslint": "^8.36.0",
117
120
  "eslint-config-prettier": "^8.8.0",
118
121
  "eslint-plugin-prettier": "^5.0.0",
119
122
  "eslint-plugin-react-hooks": "^5.0.0",
123
+ "fs-extra": "^11.3.0",
120
124
  "handlebars": "^4.7.8",
121
125
  "html-webpack-plugin": "^5.5.3",
122
126
  "ignore-loader": "^0.1.2",
@@ -9,12 +9,6 @@
9
9
  "metadataSchema": {
10
10
  "type": "object",
11
11
  "properties": {
12
- "/specta/hideTopbar": {
13
- "title": "Hide top bar",
14
- "type": "boolean",
15
- "enum": [true, false],
16
- "default": false
17
- },
18
12
  "/specta/defaultLayout": {
19
13
  "title": "Page layout",
20
14
  "type": "string",
package/style/base.css CHANGED
@@ -55,6 +55,7 @@
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 {
@@ -62,6 +63,7 @@
62
63
  display: flex;
63
64
  box-shadow: unset !important;
64
65
  z-index: 100;
66
+ contain: unset !important;
65
67
  }
66
68
 
67
69
  .specta-topbar-element {
package/style/style.css CHANGED
@@ -8,12 +8,6 @@
8
8
  display: none;
9
9
  }
10
10
 
11
- #specta-top-panel {
12
- contain: unset !important;
13
- box-shadow: unset !important;
14
- z-index: 100;
15
- }
16
-
17
11
  .specta-file-browser {
18
12
  max-width: 1200px;
19
13
  margin: 0 auto;
@@ -32,3 +26,8 @@
32
26
  background: var(--jp-layout-color1);
33
27
  box-shadow: var(--jp-elevation-z4);
34
28
  }
29
+
30
+ .specta-main-content-panel {
31
+ padding-left: 5px;
32
+ padding-right: 5px;
33
+ }