Explorar el Código

wip dynamic theme loading

Steven Silvester hace 7 años
padre
commit
79fbae555c

+ 10 - 1
jupyterlab/extension.py

@@ -8,6 +8,9 @@ import os
 from jupyterlab_launcher import add_handlers, LabConfig
 from notebook.utils import url_path_join as ujoin
 
+from notebook.base.handlers import FileFindHandler
+
+
 from .commands import (
     get_app_dir, list_extensions, should_build, get_user_settings_dir
 )
@@ -104,8 +107,14 @@ def load_jupyter_server_extension(nbapp):
         'settings_dir': user_settings_dir
     })
 
+    nbapp.log.error(base_url)
+    nbapp.log.error(here)
+    theme_handler = (base_url + r"lab/api/themes/(.*)", FileFindHandler, {
+        'path': os.path.join(here, 'themes')
+    })
+
     build_url = ujoin(base_url, build_path)
     builder = Builder(nbapp.log, core_mode, app_dir)
     build_handler = (build_url, BuildHandler, {'builder': builder})
 
-    web_app.add_handlers(".*$", [settings_handler, build_handler])
+    web_app.add_handlers(".*$", [settings_handler, build_handler, theme_handler])

+ 0 - 19
jupyterlab/index.js

@@ -54,25 +54,6 @@ function main() {
         mimeExtensions: mimeExtensions
     });
 
-    var loader = function(theme) {
-        return require('!css-loader!' + theme).toString();
-    }
-
-    // Add the theme manager extension.
-    lab.registerPlugin({
-      id: 'jupyter.extensions.theme-manager',
-      autoStart: true,
-      activate: function(app) {
-        // Load the theme CSS as strings.
-        var themeCSS = {};
-        themeCSS['@jupyterlab/theme-light-extension'] = require('!css-loader!@jupyterlab/theming/style/variables-light.css').toString();
-        var style = document.createElement('style');
-        style.innerHTML = themeCSS['@jupyterlab/theme-light-extension']
-        document.body.appendChild(style);
-        //return new ThemeManager({ settingRegistry, themeCSS });
-      }
-    })
-
     // Handled the registered standard extensions.
     {{#each jupyterlab_extensions}}
     try {

+ 3 - 4
jupyterlab/package.json

@@ -8,7 +8,7 @@
   "dependencies": {
     "@jupyterlab/application": "^0.9.0",
     "@jupyterlab/application-extension": "^0.9.0",
-    "@jupyterlab/apputils": "^0.9.0",
+    "@jupyterlab/apputils": "0.9.0",
     "@jupyterlab/apputils-extension": "^0.9.0",
     "@jupyterlab/codeeditor": "^0.9.0",
     "@jupyterlab/codemirror": "^0.9.0",
@@ -95,14 +95,13 @@
       "@jupyterlab/shortcuts-extension": "",
       "@jupyterlab/tabmanager-extension": "",
       "@jupyterlab/terminal-extension": "",
+      "@jupyterlab/theme-light-extension": "lib/index.js",
       "@jupyterlab/tooltip-extension": ""
     },
     "mimeExtensions": {
       "@jupyterlab/vega2-extension": ""
     },
-    "themeExtensions": {
-      "@jupyterlab/theme-light-extension": "index.css"
-    },
+    "themeExtensions": {},
     "name": "JupyterLab",
     "singletonPackages": [
       "@jupyterlab/application",

+ 7 - 0
packages/application/src/shell.ts

@@ -532,6 +532,13 @@ class ApplicationShell extends Widget {
     document.body.setAttribute(MODE_ATTRIBUTE, this.mode);
   }
 
+  /**
+   * Handle `fit` messages for the application shell.
+   */
+  protected onFitRequest(msg: Message) {
+    this._dockPanel.fit();
+  }
+
   /*
    * Return the tab bar adjacent to the current TabBar or `null`.
    */

+ 21 - 2
packages/apputils-extension/src/index.ts

@@ -8,7 +8,7 @@ import {
 } from '@jupyterlab/application';
 
 import {
-  ICommandPalette, IMainMenu, MainMenu
+  ICommandPalette, IMainMenu, MainMenu, IThemeManager, ThemeManager
 } from '@jupyterlab/apputils';
 
 import {
@@ -140,6 +140,24 @@ const settingPlugin: JupyterLabPlugin<ISettingRegistry> = {
 };
 
 
+
+/**
+ * The default theme manager provider.
+ */
+const themePlugin: JupyterLabPlugin<IThemeManager> = {
+  id: 'jupyter.services.theme-manger',
+  requires: [ISettingRegistry],
+  activate: (app: JupyterLab, settingRegistry: ISettingRegistry): IThemeManager => {
+    let baseUrl = app.serviceManager.serverSettings.baseUrl;
+    let host = app.shell;
+    return new ThemeManager({ baseUrl,  settingRegistry, host });
+  },
+  autoStart: true,
+  provides: IThemeManager
+};
+
+
+
 /**
  * The default state database for storing application state.
  */
@@ -180,7 +198,8 @@ const plugins: JupyterLabPlugin<any>[] = [
   mainMenuPlugin,
   palettePlugin,
   settingPlugin,
-  stateDBPlugin
+  stateDBPlugin,
+  themePlugin
 ];
 export default plugins;
 

+ 1 - 0
packages/apputils/src/index.ts

@@ -15,5 +15,6 @@ export * from './instancetracker';
 export * from './mainmenu';
 export * from './sanitizer';
 export * from './styling';
+export * from './thememanager';
 export * from './toolbar';
 export * from './vdom';

+ 178 - 0
packages/apputils/src/thememanager.ts

@@ -0,0 +1,178 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import {
+  SettingRegistry
+} from '@jupyterlab/coreutils';
+
+import {
+  ArrayExt
+} from '@phosphor/algorithm';
+
+import {
+  Token
+} from '@phosphor/coreutils';
+
+import {
+  DisposableDelegate, IDisposable
+} from '@phosphor/disposable';
+
+import {
+  Widget
+} from '@phosphor/widgets';
+
+
+
+/* tslint:disable */
+/**
+ * The theme manager token.
+ */
+export
+const IThemeManager = new Token<IThemeManager>('jupyter.services.theme-manager');
+/* tslint:enable */
+
+
+/**
+ * An interface for a theme manager.
+ */
+export
+interface IThemeManager extends ThemeManager {}
+
+
+/**
+ * A class that provides theme management.
+ */
+export
+class ThemeManager {
+  /**
+   * Construct a new theme manager.
+   */
+  constructor(options: ThemeManager.IOptions) {
+    this._baseUrl = options.baseUrl;
+    this._registry = options.settingRegistry;
+    this._host = options.host;
+  }
+
+  /**
+   * Get the name of the current theme.
+   */
+  get theme(): string {
+    return this._theme;
+  }
+
+  /**
+   * The names of the registered themes.
+   */
+  get themes(): ReadonlyArray<string> {
+    return this._themes.map(theme => theme.name);
+  }
+
+  /**
+   * Set the current theme.
+   */
+  setTheme(name: string): Promise<void> {
+    console.log(this._registry);
+    return Promise.resolve(void 0);
+  }
+
+  /**
+   * Register a theme with the theme manager.
+   *
+   * @param theme - The theme to register.
+   *
+   * @returns A disposable that can be used to unregister the theme.
+   */
+  register(theme: ThemeManager.ITheme): IDisposable {
+    this._themes.push(theme);
+    if (theme.name === 'JupyterLab Light') {
+      theme.load().then(paths => {
+        paths.forEach(path => {
+          this._loadFile(path);
+        });
+      });
+    }
+
+    return new DisposableDelegate(() => {
+      ArrayExt.removeFirstOf(this._themes, theme);
+    });
+  }
+
+  /**
+   * Load a theme CSS file by path.
+   *
+   * @param path - The path of the file to load.
+   */
+  private _loadFile(path: string): Promise<void> {
+    let link = document.createElement('link');
+    link.rel = 'stylesheet';
+    link.type = 'text/css';
+    link.href = path;
+    link.onload = () => {
+        this._host.fit();
+    };
+    document.body.appendChild(link);
+    this._links.push(link);
+    return Promise.resolve(void 0);
+  }
+
+  private _baseUrl: string;
+  private _registry: SettingRegistry;
+  private _theme: string;
+  private _themes: ThemeManager.ITheme[] = [];
+  private _links: HTMLLinkElement[] = [];
+  private _host: Widget;
+}
+
+
+/**
+ * A namespace for `ThemeManager` statics.
+ */
+export
+namespace ThemeManager {
+  /**
+   * The options used to create a theme manager.
+   */
+  export
+  interface IOptions {
+    /**
+     * The base url for the theme manager.
+     */
+    baseUrl: string;
+
+    /**
+     * The settings registry.
+     */
+    settingRegistry: SettingRegistry;
+
+    /**
+     * The host widget for the theme manager.
+     */
+    host: Widget;
+  }
+
+  /**
+   * An interface for a theme.
+   */
+  export
+  interface ITheme {
+    /**
+     * The display name of the theme.
+     */
+    name: string;
+
+    /**
+     * Load the theme.
+     *
+     * @returns A promise that resolves with the paths of the CSS
+     * files to load.
+     */
+    load(): Promise<ReadonlyArray<string>>;
+
+    /**
+     * Unload the theme.
+     *
+     * @returns A promise that resolves when the theme is unloaded.
+     */
+    unload(): Promise<void>;
+  }
+}

+ 0 - 1
packages/theme-light-extension/index.css

@@ -1,3 +1,2 @@
 
 
-@import url('~@jupyterlab/theming/style/variables-light.css');

+ 3 - 2
packages/theme-light-extension/package.json

@@ -3,14 +3,15 @@
   "version": "0.9.0",
   "description": "JupyterLab - Default Light Theme",
   "dependencies": {
-    "@jupyterlab/theming": "^0.9.0"
+    "@jupyterlab/application": "0.9.0",
+    "@jupyterlab/apputils": "0.9.0"
   },
   "repository": {
     "type": "git",
     "url": "https://github.com/jupyterlab/jupyterlab.git"
   },
   "jupyterlab": {
-    "themeExtension": "index.css"
+    "extension": "lib/index.js"
   },
   "author": "Project Jupyter",
   "license": "BSD-3-Clause",

+ 31 - 0
packages/theme-light-extension/src/index.ts

@@ -0,0 +1,31 @@
+
+
+import {
+  JupyterLab, JupyterLabPlugin
+} from '@jupyterlab/application';
+
+import {
+  IThemeManager
+} from '@jupyterlab/apputils';
+
+
+
+const plugin: JupyterLabPlugin<void> = {
+    id: 'theme-light-extension',
+    requires: [IThemeManager],
+    activate: function(app: JupyterLab, manager: IThemeManager) {
+        manager.register({
+            name: 'JupyterLab Light',
+            load: function() {
+                return Promise.resolve(['./lab/api/themes/jupyterlab-theme-light-extension/style/index.css']);
+            },
+            unload: function() {
+                return Promise.resolve(void 0);
+            }
+        });
+    },
+    autoStart: true
+};
+
+
+export default plugin;