فهرست منبع

first working version of IconRegistry

telamonian 6 سال پیش
والد
کامیت
69a6411604

+ 14 - 4
dev_mode/webpack.config.js

@@ -191,17 +191,27 @@ module.exports = [
         {
           // in css files, svg is loaded as a url formatted string
           test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
-          issuer: { test: /\.css?$/ },
+          issuer: { test: /\.css$/ },
           use: {
             loader: 'svg-url-loader',
             options: { encoding: 'none', limit: 10000 }
           }
         },
+        // {
+        //   // in react files, svg is loaded as a react component
+        //   test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
+        //   issuer: { test: /\.jsx$/ },
+        //   use: 'svg-react-loader'
+        // }
         {
-          // in react files, svg is loaded as a react component
+          // in ts and tsx files (both of which compile to js),
+          // svg is loaded as a url formatted string
           test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
-          issuer: { test: /\.jsx?$/ },
-          use: 'svg-react-loader'
+          issuer: { test: /\.js$/ },
+          use: {
+            loader: 'raw-loader'
+            // options: { encoding: 'none', limit: 10000 }
+          }
         }
       ]
     },

+ 11 - 2
jupyterlab/staging/webpack.config.js

@@ -191,7 +191,7 @@ module.exports = [
         {
           // in css files, svg is loaded as a url formatted string
           test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
-          issuer: { test: /\.css?$/ },
+          issuer: { test: /\.css$/ },
           use: {
             loader: 'svg-url-loader',
             options: { encoding: 'none', limit: 10000 }
@@ -200,9 +200,18 @@ module.exports = [
         {
           // in react files, svg is loaded as a react component
           test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
-          issuer: { test: /\.jsx?$/ },
+          issuer: { test: /\.jsx$/ },
           use: 'svg-react-loader'
         }
+        // {
+        //   // in css files, svg is loaded as a url formatted string
+        //   test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
+        //   issuer: { test: /\.js$/ },
+        //   use: {
+        //     loader: 'svg-url-loader',
+        //     options: { encoding: 'none', limit: 10000 }
+        //   }
+        // }
       ]
     },
     watchOptions: {

+ 20 - 9
packages/application/style/images.css

@@ -30,24 +30,35 @@
   stroke: var(--jp-ui-font-color3);
 }
 
-.jp-icon-accent0 {
+.jp-icon-fill-accent0 {
   fill: var(--jp-layout-color0);
-  stroke: var(--jp-layout-color0);
 }
-.jp-icon-accent1 {
+.jp-icon-fill-accent1 {
   fill: var(--jp-layout-color1);
-  stroke: var(--jp-layout-color1);
 }
-.jp-icon-accent2 {
+.jp-icon-fill-accent2 {
   fill: var(--jp-layout-color2);
-  stroke: var(--jp-layout-color2);
 }
-.jp-icon-accent3 {
+.jp-icon-fill-accent3 {
   fill: var(--jp-layout-color3);
-  stroke: var(--jp-layout-color3);
 }
-.jp-icon-accent4 {
+.jp-icon-fill-accent4 {
   fill: var(--jp-layout-color4);
+}
+
+.jp-icon-stroke-accent0 {
+  stroke: var(--jp-layout-color0);
+}
+.jp-icon-stroke-accent1 {
+  stroke: var(--jp-layout-color1);
+}
+.jp-icon-stroke-accent2 {
+  stroke: var(--jp-layout-color2);
+}
+.jp-icon-stroke-accent3 {
+  stroke: var(--jp-layout-color3);
+}
+.jp-icon-stroke-accent4 {
   stroke: var(--jp-layout-color4);
 }
 

+ 3 - 3
packages/docregistry/src/registry.ts

@@ -1103,9 +1103,9 @@ export namespace DocumentRegistry {
     readonly iconLabel?: string;
 
     /**
-     * A parsed inline SVG icon.
+     * Icon name, as per the icon registry.
      */
-    readonly icon?: Document;
+    readonly iconName?: string;
 
     /**
      * The content type of the new file.
@@ -1127,7 +1127,7 @@ export namespace DocumentRegistry {
     mimeTypes: [],
     iconClass: 'jp-MaterialIcon jp-FileIcon',
     iconLabel: '',
-    icon: null,
+    iconName: '',
     contentType: 'file',
     fileFormat: 'text'
   };

+ 3 - 0
packages/filebrowser/src/listing.ts

@@ -1757,6 +1757,9 @@ export namespace DirListing {
       let modified = DOMUtils.findElement(node, ITEM_MODIFIED_CLASS);
 
       if (fileType) {
+        // if (fileType.iconName) {
+        //   icon.appendChild(fileType.icon.documentElement);
+        // }
         icon.textContent = fileType.iconLabel || '';
         icon.className = `${ITEM_ICON_CLASS} ${fileType.iconClass || ''}`;
       } else {

+ 2 - 4
packages/htmlviewer-extension/src/index.tsx

@@ -19,8 +19,6 @@ import {
   IHTMLViewerTracker
 } from '@jupyterlab/htmlviewer';
 
-import { HTML5Icon } from '@jupyterlab/ui-components';
-
 /**
  * The CSS class for an HTML5 icon.
  */
@@ -61,7 +59,7 @@ function activateHTMLViewer(
     extensions: ['.html'],
     mimeTypes: ['text/html'],
     iconClass: CSS_ICON_CLASS,
-    icon: HTML5Icon
+    iconName: 'html5'
   };
   app.docRegistry.addFileType(ft);
 
@@ -101,9 +99,9 @@ function activateHTMLViewer(
       app.commands.notifyCommandChanged(CommandIDs.trustHTML);
     });
 
+    // widget.node.appendChild(HTML5Icon);
     widget.title.iconClass = ft.iconClass;
     widget.title.iconLabel = ft.iconLabel;
-    widget.node.appendChild(HTML5Icon);
   });
 
   // Add a command to trust the active HTML document,

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

@@ -6,7 +6,7 @@ import { INotebookModel, Notebook } from '.';
 
 import { Cell } from '@jupyterlab/cells';
 
-import { NotTrustedIconX, TrustedIconX } from '@jupyterlab/ui-components';
+import { IconX } from '@jupyterlab/ui-components';
 
 import { toArray } from '@phosphor/algorithm';
 
@@ -45,9 +45,9 @@ function NotebookTrustComponent(
   props: NotebookTrustComponent.IProps
 ): React.ReactElement<NotebookTrustComponent.IProps> {
   if (props.allCellsTrusted) {
-    return <TrustedIconX offset={{ x: 0, y: 2 }} />;
+    return <IconX name="trusted" offset={{ x: 0, y: 2 }} />;
   } else {
-    return <NotTrustedIconX offset={{ x: 0, y: 2 }} />;
+    return <IconX name="not-trusted" offset={{ x: 0, y: 2 }} />;
   }
 }
 

+ 47 - 47
packages/statusbar/src/components/lineForm.tsx

@@ -1,49 +1,49 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
-
-import React, { ComponentType, HTMLAttributes } from 'react';
-
-import {
-  lineFormButtonDiv,
-  lineFormButtonIcon,
-  lineFormButton
-} from '../style/lineForm';
-
-/**
- * A namespace for LineFormButtonItem statics.
- */
-export namespace LineFormButtonItem {
-  /**
-   * Props for an LineFormButtonItem
-   */
-  export interface IProps {
-    /**
-     * The inline svg
-     */
-    SVG: ComponentType<HTMLAttributes<SVGElement>>;
-
-    /**
-     * The input type
-     */
-    type: string;
-
-    /**
-     * The input value
-     */
-    value: string;
-  }
-}
-
-export function LineFormButtonItem(
-  props: LineFormButtonItem.IProps &
-    React.HTMLAttributes<SVGElement> &
-    React.HTMLAttributes<HTMLInputElement>
-): React.ReactElement<LineFormButtonItem.IProps> {
-  const { SVG, type, value, ...rest } = props;
-  return (
-    <div className={lineFormButtonDiv}>
-      <SVG className={lineFormButtonIcon} {...rest} />
-      <input type={type} className={lineFormButton} value={value} />
-    </div>
-  );
-}
+//
+// import React, { ComponentType, HTMLAttributes } from 'react';
+//
+// import {
+//   lineFormButtonDiv,
+//   lineFormButtonIcon,
+//   lineFormButton
+// } from '../style/lineForm';
+//
+// /**
+//  * A namespace for LineFormButtonItem statics.
+//  */
+// export namespace LineFormButtonItem {
+//   /**
+//    * Props for an LineFormButtonItem
+//    */
+//   export interface IProps {
+//     /**
+//      * The inline svg
+//      */
+//     SVG: ComponentType<HTMLAttributes<SVGElement>>;
+//
+//     /**
+//      * The input type
+//      */
+//     type: string;
+//
+//     /**
+//      * The input value
+//      */
+//     value: string;
+//   }
+// }
+//
+// export function LineFormButtonItem(
+//   props: LineFormButtonItem.IProps &
+//     React.HTMLAttributes<SVGElement> &
+//     React.HTMLAttributes<HTMLInputElement>
+// ): React.ReactElement<LineFormButtonItem.IProps> {
+//   const { SVG, type, value, ...rest } = props;
+//   return (
+//     <div className={lineFormButtonDiv}>
+//       <SVG className={lineFormButtonIcon} {...rest} />
+//       <input type={type} className={lineFormButton} value={value} />
+//     </div>
+//   );
+// }

+ 9 - 5
packages/statusbar/src/defaults/lineCol.tsx

@@ -7,7 +7,7 @@ import { VDomRenderer, VDomModel, ReactWidget } from '@jupyterlab/apputils';
 
 import { CodeEditor } from '@jupyterlab/codeeditor';
 
-import { LineFormSvgX } from '@jupyterlab/ui-components';
+import { SvgX } from '@jupyterlab/ui-components';
 
 import { classes } from 'typestyle/lib';
 
@@ -18,11 +18,12 @@ import {
   lineFormInput,
   lineFormSearch,
   lineFormWrapperFocusWithin,
-  lineFormCaption
+  lineFormCaption,
+  lineFormButtonDiv,
+  lineFormButtonIcon,
+  lineFormButton
 } from '../style/lineForm';
 
-import { LineFormButtonItem } from '../components/lineForm';
-
 /**
  * A namespace for LineFormComponent statics.
  */
@@ -114,7 +115,10 @@ class LineFormComponent extends React.Component<
                 this._textInput = input;
               }}
             />
-            <LineFormButtonItem SVG={LineFormSvgX} type="submit" value="" />
+            <div className={lineFormButtonDiv}>
+              <SvgX name="line-form" className={lineFormButtonIcon} />
+              <input type="submit" className={lineFormButton} value="" />
+            </div>
           </div>
           <label className={lineFormCaption}>
             Go to line number between 1 and {this.props.maxLine}

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

@@ -13,7 +13,7 @@ import {
   SessionManager
 } from '@jupyterlab/services';
 
-import { KernelIconX, TerminalIconX } from '@jupyterlab/ui-components';
+import { IconX } from '@jupyterlab/ui-components';
 
 import { GroupItem, interactiveItem, TextItem } from '..';
 
@@ -36,11 +36,11 @@ function RunningSessionsComponent(
     <GroupItem spacing={HALF_SPACING} onClick={props.handleClick}>
       <GroupItem spacing={HALF_SPACING}>
         <TextItem source={props.terminals} />
-        <TerminalIconX offset={{ x: 1, y: 3 }} />
+        <IconX name={'terminal'} offset={{ x: 1, y: 3 }} />
       </GroupItem>
       <GroupItem spacing={HALF_SPACING}>
         <TextItem source={props.kernels} />
-        <KernelIconX offset={{ x: 0, y: 2 }} />
+        <IconX name={'kernel'} offset={{ x: 0, y: 2 }} />
       </GroupItem>
     </GroupItem>
   );

+ 56 - 48
packages/ui-components/src/icon/icon-react.tsx

@@ -1,62 +1,70 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
 
-import React, { ComponentType, HTMLAttributes } from 'react';
+// import React, { ComponentType, HTMLAttributes } from 'react';
+import React from 'react';
 
 import { classes, style } from 'typestyle/lib';
 
+// import { IconRegistry, defaultIconRegistry } from './icon';
+import { defaultIconRegistry } from './icon';
 import icon from '../style/icon';
 
-// icon svg imports
-
-import HTML5SvgX from '../../style/icons/html5-icon.svg';
-import KernelSvgX from '../../style/icons/kernel-icon.svg';
-import NotTrustedSvgX from '../../style/icons/not-trusted-icon.svg';
-import TerminalSvgX from '../../style/icons/terminal-icon.svg';
-import TrustedSvgX from '../../style/icons/trusted-icon.svg';
-
-import _LineFormSvgX from '../../style/icons/line-form.svg';
-
-// functions that produce/export React icons
-
-export const HTML5IconX = IconFactory({ Svg: HTML5SvgX });
-export const KernelIconX = IconFactory({ Svg: KernelSvgX });
-export const NotTrustedIconX = IconFactory({ Svg: NotTrustedSvgX });
-export const TerminalIconX = IconFactory({ Svg: TerminalSvgX });
-export const TrustedIconX = IconFactory({ Svg: TrustedSvgX });
-
-export const LineFormSvgX = _LineFormSvgX;
-
 // functions for setting up icons
 
-/**
- * A namespace for SvgIcon statics.
- */
-export namespace SvgIcon {
-  /**
-   * Props for an SvgIcon
-   */
-  export interface IProps {
-    /**
-     * The inline svg
-     */
-    Svg: ComponentType<HTMLAttributes<SVGElement>>;
-  }
-}
-
-type IconProps = React.HTMLAttributes<SVGElement> & {
-  offset: { x: number; y: number };
-};
-type IconElem = React.ReactElement<SvgIcon.IProps>;
+type SvgPropsX = { name: string } & React.HTMLAttributes<SVGElement>;
 
-export function SvgIcon(props: SvgIcon.IProps & IconProps): IconElem {
-  const { Svg, className, offset, ...rest } = props;
-  return <Svg className={classes(className, style(icon(offset)))} {...rest} />;
+export function SvgX(props: SvgPropsX): React.ReactElement {
+  const { name, className } = props;
+  return (
+    <div
+      className={className}
+      dangerouslySetInnerHTML={{ __html: defaultIconRegistry.svg(name) }}
+    />
+  );
+  // return <div className={className}>{defaultIconRegistry.svg(name)}</div>;
 }
 
-export function IconFactory(
-  props: SvgIcon.IProps
-): (props: IconProps) => IconElem {
-  const { Svg } = props;
-  return (props: IconProps) => <SvgIcon Svg={Svg} {...props} />;
+export function IconX(
+  props: { offset: { x: number; y: number } } & SvgPropsX
+): React.ReactElement {
+  const { className, offset, ...rest } = props;
+  return <SvgX className={classes(className, style(icon(offset)))} {...rest} />;
+  // return <div className={ classes(className, style(icon(offset))) }>{defaultIconRegistry.svg(name)}</div>;
 }
+
+// export class IconRegistryX extends IconRegistry {
+//   iconX(props: IconPropsX): React.ReactElement {
+//     const {name, className, offset} = props;
+//     return <div className={ classes(className, style(icon(offset))) }>{this.svg(name)}</div>;
+//   }
+// }
+//
+// export const defaultIconRegistryX: IconRegistryX = new IconRegistryX();
+//
+// /**
+//  * A namespace for SvgIcon statics.
+//  */
+// export namespace SvgIcon {
+//   /**
+//    * Props for an SvgIcon
+//    */
+//   export interface IProps {
+//     /**
+//      * The inline svg
+//      */
+//     Svg: ComponentType<HTMLAttributes<SVGElement>>;
+//   }
+// }
+//
+// export function SvgIcon(props: SvgIcon.IProps & IconPropsX): React.ReactElement<SvgIcon.IProps> {
+//   const { Svg, className, offset, ...rest } = props;
+//   return <Svg className={classes(className, style(icon(offset)))} {...rest} />;
+// }
+//
+// export function IconFactory(
+//   props: SvgIcon.IProps
+// ): (props: IconPropsX) => React.ReactElement<SvgIcon.IProps> {
+//   const { Svg } = props;
+//   return (props: IconPropsX) => <SvgIcon Svg={Svg} {...props} />;
+// }

+ 61 - 8
packages/ui-components/src/icon/icon.ts

@@ -2,17 +2,70 @@
 // Distributed under the terms of the Modified BSD License.
 
 import HTML5Svg from '../../style/icons/html5-icon.svg';
+import KernelSvg from '../../style/icons/kernel-icon.svg';
+import LineFormSvg from '../../style/icons/line-form-icon.svg';
+import NotTrustedSvg from '../../style/icons/not-trusted-icon.svg';
+import TerminalSvg from '../../style/icons/terminal-icon.svg';
+import TrustedSvg from '../../style/icons/trusted-icon.svg';
 
-export function ParseSvg(svg: string): Document {
-  let parser = new DOMParser();
-  return parser.parseFromString(svg, 'image/svg+xml');
+/**
+ * The icon registry.
+ */
+export class IconRegistry {
+  constructor(...icons: IconRegistry.IModel[]) {
+    if (icons.length) {
+      this.addIcon(...icons);
+    } else {
+      this.addIcon(...IconRegistry.defaultIcons);
+    }
+  }
+
+  addIcon(...icons: IconRegistry.IModel[]): void {
+    icons.forEach(
+      (icon: IconRegistry.IModel) => (this._svgs[icon.name] = icon.svg)
+    );
+  }
+
+  icon(name: string): HTMLElement {
+    return Private.parseSvg(this._svgs[name]);
+  }
+
+  svg(name: string): string {
+    return this._svgs[name];
+  }
+
+  attachIcon(name: string, node: HTMLElement) {
+    Private.appendSvg(this._svgs[name], node);
+  }
+
+  private _svgs: { [key: string]: string } = Object.create(null);
 }
 
-export function AttachSvg(node: HTMLElement, svg: string): Document {
-  let img = ParseSvg(svg);
+export namespace IconRegistry {
+  export interface IModel {
+    name: string;
+    svg: string;
+  }
 
-  node.appendChild(img);
-  return img;
+  export const defaultIcons: ReadonlyArray<IModel> = [
+    { name: 'html5-icon', svg: HTML5Svg },
+    { name: 'kernel', svg: KernelSvg },
+    { name: 'line-form', svg: LineFormSvg },
+    { name: 'not-trusted', svg: NotTrustedSvg },
+    { name: 'terminal', svg: TerminalSvg },
+    { name: 'trusted', svg: TrustedSvg }
+  ];
 }
 
-export const HTML5Icon = ParseSvg(HTML5Svg);
+export const defaultIconRegistry: IconRegistry = new IconRegistry();
+
+namespace Private {
+  export function parseSvg(svg: string): HTMLElement {
+    let parser = new DOMParser();
+    return parser.parseFromString(svg, 'image/svg+xml').documentElement;
+  }
+
+  export function appendSvg(svg: string, node: HTMLElement): void {
+    node.appendChild(parseSvg(svg));
+  }
+}

+ 10 - 6
packages/ui-components/src/style/icon.ts

@@ -6,11 +6,15 @@ import { NestedCSSProperties } from 'typestyle/lib/types';
 
 export default ({ x, y }: { x: number; y: number }): NestedCSSProperties => {
   return {
-    backgroundRepeat: 'no-repeat',
-    backgroundSize: vars.iconImageSize,
-    backgroundPositionY: y !== 0 ? `${y}px` : undefined,
-    backgroundPositionX: x !== 0 ? `${x}px` : undefined,
-    minHeight: vars.height,
-    width: vars.iconWidth
+    minHeight: vars.iconMinHeight,
+    $nest: {
+      ['svg']: {
+        height: vars.iconHeight,
+        width: vars.iconWidth,
+        position: 'relative',
+        left: `${x}px`,
+        top: `${y}px`
+      }
+    }
   };
 };

+ 2 - 2
packages/ui-components/src/style/variables.ts

@@ -2,7 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 export default {
-  height: '24px',
-  iconImageSize: '18px',
+  iconMinHeight: '24px',
+  iconHeight: '18px',
   iconWidth: '20px'
 };

+ 1 - 1
packages/ui-components/style/icons/line-form.svg → packages/ui-components/style/icons/line-form-icon.svg

@@ -1,4 +1,4 @@
 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-    <path class="jp-icon" fill="white" d="M5.88 4.12L13.76 12l-7.88 7.88L8 22l10-10L8 2z"/>
+    <path fill="white" d="M5.88 4.12L13.76 12l-7.88 7.88L8 22l10-10L8 2z"/>
     <path fill="none" d="M0 0h24v24H0z"/>
 </svg>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
packages/ui-components/style/icons/terminal-icon.svg


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است