Browse Source

fixed up settingsEditor icons

telamonian 5 years ago
parent
commit
dd51b13182

+ 17 - 0
packages/coreutils/src/path.ts

@@ -61,6 +61,23 @@ export namespace PathExt {
     return posix.extname(path);
   }
 
+  /**
+   * Get the last portion of a path, without its extension (if any).
+   *
+   * @param path - The file path.
+   *
+   * @returns the last part of the path, sans extension.
+   */
+  export function stem(path: string): string {
+    return path
+      .split('\\')
+      .pop()
+      .split('/')
+      .pop()
+      .split('.')
+      .shift();
+  }
+
   /**
    * Normalize a string path, reducing '..' and '.' parts.
    * When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used.

+ 23 - 0
packages/coreutils/src/text.ts

@@ -71,6 +71,29 @@ export namespace Text {
     return jsIdx;
   }
 
+  /**
+   * Given a 'snake-case', 'snake_case', or 'snake case' string,
+   * will return the camel case version: 'snakeCase'.
+   *
+   * @param str: the snake-case input string.
+   *
+   * @param upper: default = false. If true, the first letter of the
+   * returned string will be capitalized.
+   *
+   * @returns the camel case version of the input string.
+   */
+  export function camelCase(str: string, upper: boolean = false): string {
+    return str.replace(/(?:^\w|[A-Z]|\b\w|\s+|-+|_+)/g, function(match, index) {
+      if (+match === 0 || match[0] === '-') {
+        return '';
+      } else if (index === 0 && !upper) {
+        return match.toLowerCase();
+      } else {
+        return match.toUpperCase();
+      }
+    });
+  }
+
   /**
    * Given a string, title case the words in the string.
    *

+ 0 - 5
packages/coreutils/src/tokens.ts

@@ -269,11 +269,6 @@ export namespace ISettingRegistry {
      */
     'jupyter.lab.setting-icon-label'?: string;
 
-    /**
-     * The JupyterLab icon name, for loading through IconRegistry.
-     */
-    'jupyter.lab.setting-icon-name'?: string;
-
     /**
      * A flag that indicates plugin should be transformed before being used by
      * the setting registry.

+ 5 - 3
packages/notebook/src/truststatus.tsx

@@ -6,7 +6,7 @@ import { INotebookModel, Notebook } from '.';
 
 import { Cell } from '@jupyterlab/cells';
 
-import { IconReact } from '@jupyterlab/ui-components';
+import { DefaultIconReact } from '@jupyterlab/ui-components';
 
 import { toArray } from '@phosphor/algorithm';
 
@@ -45,9 +45,11 @@ function NotebookTrustComponent(
   props: NotebookTrustComponent.IProps
 ): React.ReactElement<NotebookTrustComponent.IProps> {
   if (props.allCellsTrusted) {
-    return <IconReact name="trusted" top={'2px'} kind={'statusBar'} />;
+    return <DefaultIconReact name="trusted" top={'2px'} kind={'statusBar'} />;
   } else {
-    return <IconReact name="not-trusted" top={'2px'} kind={'statusBar'} />;
+    return (
+      <DefaultIconReact name="not-trusted" top={'2px'} kind={'statusBar'} />
+    );
   }
 }
 

+ 15 - 14
packages/settingeditor/src/pluginlist.tsx

@@ -5,7 +5,11 @@
 
 import { ISettingRegistry } from '@jupyterlab/coreutils';
 
-import { IconReact } from '@jupyterlab/ui-components';
+import {
+  combineClasses,
+  DefaultIconReact,
+  defaultIconRegistry
+} from '@jupyterlab/ui-components';
 
 import { Message } from '@phosphor/messaging';
 
@@ -196,12 +200,6 @@ namespace Private {
    */
   const ICON_LABEL_KEY = 'jupyter.lab.setting-icon-label';
 
-  /**e
-   * The JupyterLab plugin schema key for IconRegistry name
-   * of the setting editor icon of a plugin
-   */
-  const ICON_NAME_KEY = 'jupyter.lab.setting-icon-name';
-
   /**
    * Check the plugin for a rendering hint's value.
    *
@@ -261,9 +259,12 @@ namespace Private {
       const { id, schema, version } = plugin;
       const itemTitle = `${schema.description}\n${id}\n${version}`;
       const image = getHint(ICON_CLASS_KEY, registry, plugin);
-      const iconClass = `jp-PluginList-icon${image ? ' ' + image : ''}`;
+      const iconClass = combineClasses(
+        image,
+        'jp-PluginList-icon',
+        'jp-MaterialIcon'
+      );
       const iconTitle = getHint(ICON_LABEL_KEY, registry, plugin);
-      const iconName = getHint(ICON_NAME_KEY, registry, plugin);
 
       return (
         <li
@@ -272,13 +273,13 @@ namespace Private {
           key={id}
           title={itemTitle}
         >
-          {iconName ? (
-            <IconReact
-              name={iconName}
+          {defaultIconRegistry.contains(image) ? (
+            <DefaultIconReact
+              name={image}
               title={iconTitle}
-              className={iconClass}
+              className={''}
               tag={'span'}
-              kind={'listing'}
+              kind={'settingsEditor'}
             />
           ) : (
             <span className={iconClass} title={iconTitle} />

+ 0 - 1
packages/statusbar-extension/schema/plugin.json

@@ -1,7 +1,6 @@
 {
   "jupyter.lab.setting-icon-class": "jp-SettingsIcon",
   "jupyter.lab.setting-icon-label": "Status Bar",
-  "jupyter.lab.setting-icon-name": "status-bar",
   "title": "Status Bar",
   "description": "Status Bar settings.",
   "properties": {

+ 2 - 2
packages/statusbar/src/defaults/lineCol.tsx

@@ -7,7 +7,7 @@ import { VDomRenderer, VDomModel, ReactWidget } from '@jupyterlab/apputils';
 
 import { CodeEditor } from '@jupyterlab/codeeditor';
 
-import { IconReact } from '@jupyterlab/ui-components';
+import { DefaultIconReact } from '@jupyterlab/ui-components';
 
 import { classes } from 'typestyle/lib';
 
@@ -116,7 +116,7 @@ class LineFormComponent extends React.Component<
               }}
             />
             <div className={lineFormButtonDiv}>
-              <IconReact
+              <DefaultIconReact
                 name="line-form"
                 className={lineFormButtonIcon}
                 center={true}

+ 3 - 3
packages/statusbar/src/defaults/runningSessions.tsx

@@ -13,7 +13,7 @@ import {
   SessionManager
 } from '@jupyterlab/services';
 
-import { IconReact } from '@jupyterlab/ui-components';
+import { DefaultIconReact } from '@jupyterlab/ui-components';
 
 import { GroupItem, interactiveItem, TextItem } from '..';
 
@@ -36,7 +36,7 @@ function RunningSessionsComponent(
     <GroupItem spacing={HALF_SPACING} onClick={props.handleClick}>
       <GroupItem spacing={HALF_SPACING}>
         <TextItem source={props.terminals} />
-        <IconReact
+        <DefaultIconReact
           name={'terminal'}
           left={'1px'}
           top={'3px'}
@@ -45,7 +45,7 @@ function RunningSessionsComponent(
       </GroupItem>
       <GroupItem spacing={HALF_SPACING}>
         <TextItem source={props.kernels} />
-        <IconReact name={'kernel'} top={'2px'} kind={'statusBar'} />
+        <DefaultIconReact name={'kernel'} top={'2px'} kind={'statusBar'} />
       </GroupItem>
     </GroupItem>
   );

+ 1 - 0
packages/ui-components/package.json

@@ -35,6 +35,7 @@
   "dependencies": {
     "@blueprintjs/core": "^3.9.0",
     "@blueprintjs/select": "^3.3.0",
+    "@jupyterlab/coreutils": "^3.0.0",
     "@phosphor/coreutils": "^1.3.1",
     "@phosphor/messaging": "^1.2.3",
     "@phosphor/virtualdom": "^1.1.3",

+ 6 - 6
packages/ui-components/src/blueprint.tsx

@@ -26,7 +26,7 @@ import {
   Select as BPSelect,
   ISelectProps
 } from '@blueprintjs/select/lib/cjs/components/select/select';
-import { combineClassNames } from './utils';
+import { combineClasses } from './utils';
 
 export { Intent } from '@blueprintjs/core/lib/cjs/common/intent';
 
@@ -44,7 +44,7 @@ type CommonProps<T> = React.DOMAttributes<T>;
 export const Button = (props: IButtonProps & CommonProps<any>) => (
   <BPButton
     {...props}
-    className={combineClassNames(
+    className={combineClasses(
       props.className,
       props.minimal && 'minimal',
       'jp-Button'
@@ -57,7 +57,7 @@ export const InputGroup = (props: IInputGroupProps & CommonProps<any>) => {
     return (
       <BPInputGroup
         {...props}
-        className={combineClassNames(props.className, 'jp-InputGroup')}
+        className={combineClasses(props.className, 'jp-InputGroup')}
         rightElement={
           <div className="jp-InputGroupAction">
             <BPIcon className={'jp-Icon'} icon={props.rightIcon} />
@@ -69,7 +69,7 @@ export const InputGroup = (props: IInputGroupProps & CommonProps<any>) => {
   return (
     <BPInputGroup
       {...props}
-      className={combineClassNames(props.className, 'jp-InputGroup')}
+      className={combineClasses(props.className, 'jp-InputGroup')}
     />
   );
 };
@@ -81,13 +81,13 @@ export const Collapse = (props: ICollapseProps & CommonProps<any>) => (
 export const HTMLSelect = (props: IHTMLSelectProps & CommonProps<any>) => (
   <BPHTMLSelect
     {...props}
-    className={combineClassNames(props.className, 'jp-HTMLSelect')}
+    className={combineClasses(props.className, 'jp-HTMLSelect')}
   />
 );
 
 export const Select = (props: ISelectProps<any> & CommonProps<any>) => (
   <BPSelect
     {...props}
-    className={combineClassNames(props.className, 'jp-Select')}
+    className={combineClasses(props.className, 'jp-Select')}
   />
 );

+ 3 - 2
packages/ui-components/src/icon/icon.ts

@@ -1,6 +1,7 @@
 import { Token } from '@phosphor/coreutils';
 
-import { nameFromPath } from '../utils';
+import { PathExt } from '@jupyterlab/coreutils';
+
 import { IIconStyle } from '../style/icon';
 import React from 'react';
 
@@ -71,7 +72,7 @@ export namespace Icon {
     const excset = new Set(exclude);
 
     return r.keys().reduce((svgs: IModel[], item: string, index: number) => {
-      const name = nameFromPath(item);
+      const name = PathExt.stem(item);
       if (!excset.has(name)) {
         svgs.push({ name: name, svg: r(item).default });
       }

+ 7 - 3
packages/ui-components/src/icon/iconregistry.tsx

@@ -4,8 +4,9 @@
 import React from 'react';
 import { classes } from 'typestyle/lib';
 
+import { Text } from '@jupyterlab/coreutils';
+
 import { IIconRegistry, Icon } from './icon';
-import { camelize } from '../utils';
 import { iconStyle, iconStyleFlat } from '../style/icon';
 
 import badSvg from '../../style/icons/bad.svg';
@@ -40,6 +41,9 @@ export class IconRegistry implements IIconRegistry {
   }
 
   contains(name: string): boolean {
+    // // we may have been handed multiple class names. Just check the first
+    // name = name.split(/\s+/)[0];
+
     return name in this._svg || name in this._classNameToName;
   }
 
@@ -142,7 +146,7 @@ export class IconRegistry implements IIconRegistry {
   }
 
   static iconClassName(name: string): string {
-    return 'jp-' + camelize(name, true) + 'Icon';
+    return 'jp-' + Text.camelCase(name, true) + 'Icon';
   }
 
   private _classNameToName: { [key: string]: string } = Object.create(null);
@@ -159,7 +163,7 @@ export const defaultIconRegistry: IconRegistry = new IconRegistry();
 /**
  * Alias for defaultIconRegistry.iconReact that can be used as a React component
  */
-export const IconReact = (
+export const DefaultIconReact = (
   props: Icon.INodeOptions & { tag?: 'div' | 'span' }
 ): React.ReactElement => {
   return defaultIconRegistry.iconReact(props);

+ 1 - 0
packages/ui-components/src/index.ts

@@ -3,3 +3,4 @@
 
 export * from './blueprint';
 export * from './icon';
+export * from './utils';

+ 25 - 0
packages/ui-components/src/style/icon.ts

@@ -7,6 +7,7 @@ import { NestedCSSProperties } from 'typestyle/lib/types';
 export type IconKindType =
   | 'dockPanelBar'
   | 'listing'
+  | 'settingsEditor'
   | 'sideBar'
   | 'statusBar'
   | 'unset';
@@ -50,6 +51,11 @@ const iconCSSListing: NestedCSSProperties = {
   width: '16px'
 };
 
+const iconCSSSettingsEditor: NestedCSSProperties = {
+  height: '16px',
+  width: '16px'
+};
+
 const iconCSSSideBar: NestedCSSProperties = {
   width: '20px'
 };
@@ -65,6 +71,7 @@ const iconCSSStatusBar: NestedCSSProperties = {
 const iconCSSKind: { [k in IconKindType]: NestedCSSProperties } = {
   dockPanelBar: iconCSSDockPanelBar,
   listing: iconCSSListing,
+  settingsEditor: iconCSSSettingsEditor,
   sideBar: iconCSSSideBar,
   statusBar: iconCSSStatusBar,
   unset: {}
@@ -83,6 +90,23 @@ const containerCSSListing: NestedCSSProperties = {
   position: 'relative'
 };
 
+// flex: 0 0 20px;
+// margin-right: 1px;
+// position: relative;
+// width: 20px;
+// height: 20px;
+// display: inline-block;
+// margin-left: 2px;
+const containerCSSSettingsEditor: NestedCSSProperties = {
+  display: 'inline-block',
+  flex: '0 0 20px',
+  marginLeft: '2px',
+  marginRight: '1px',
+  position: 'relative',
+  height: '20px',
+  width: '20px'
+};
+
 const containerCSSSideBar: NestedCSSProperties = {
   transform: 'rotate(90deg)'
 };
@@ -90,6 +114,7 @@ const containerCSSSideBar: NestedCSSProperties = {
 const containerCSSKind: { [k in IconKindType]: NestedCSSProperties } = {
   dockPanelBar: containerCSSDockPanelBar,
   listing: containerCSSListing,
+  settingsEditor: containerCSSSettingsEditor,
   sideBar: containerCSSSideBar,
   statusBar: {},
   unset: {}

+ 1 - 23
packages/ui-components/src/utils.ts

@@ -1,28 +1,6 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
 
-export function combineClassNames(...classNames: (string | undefined)[]) {
+export function combineClasses(...classNames: (string | undefined)[]) {
   return classNames.filter(c => !!c).join(' ');
 }
-
-export function camelize(str: string, upper: boolean = false): string {
-  return str.replace(/(?:^\w|[A-Z]|\b\w|\s+|-+)/g, function(match, index) {
-    if (+match === 0 || match[0] === '-') {
-      return '';
-    } else if (index === 0 && !upper) {
-      return match.toLowerCase();
-    } else {
-      return match.toUpperCase();
-    }
-  });
-}
-
-export function nameFromPath(pth: string): string {
-  return pth
-    .split('\\')
-    .pop()
-    .split('/')
-    .pop()
-    .split('.')
-    .shift();
-}

+ 6 - 1
packages/ui-components/tsconfig.json

@@ -5,5 +5,10 @@
     "types": ["webpack-env", "node"],
     "rootDir": "src"
   },
-  "include": ["src/**/*"]
+  "include": ["src/**/*"],
+  "references": [
+    {
+      "path": "../coreutils"
+    }
+  ]
 }