widget.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import {
  4. Message
  5. } from '@phosphor/messaging';
  6. import {
  7. h, VirtualNode
  8. } from '@phosphor/virtualdom';
  9. import {
  10. JupyterLab
  11. } from '@jupyterlab/application';
  12. import {
  13. VDomModel, VDomWidget
  14. } from '@jupyterlab/apputils';
  15. /**
  16. * The class name added to the landing scroll wrapper.
  17. */
  18. const LANDING_WRAPPER_CLASS = 'jp-Landing-wrapper';
  19. /**
  20. * The class name added to the dialog.
  21. */
  22. const LANDING_DIALOG_CLASS = 'jp-Landing-dialog';
  23. /**
  24. * The class name for the JupyterLab icon from default-theme.
  25. */
  26. const JUPYTERLAB_ICON_CLASS = 'jp-ImageJupyterLab';
  27. /**
  28. * The class name added to specify size of the JupyterLab logo.
  29. */
  30. const LANDING_LOGO_CLASS = 'jp-Landing-logo';
  31. /**
  32. * The class name added to the preview message subtitle.
  33. */
  34. const LANDING_SUBTITLE_CLASS = 'jp-Landing-subtitle';
  35. /**
  36. * The class name added for the tour icon from default-theme.
  37. */
  38. const TOUR_ICON_CLASS = 'jp-Landing-tour';
  39. /**
  40. * The class name added to the header text.
  41. */
  42. const LANDING_HEADER_CLASS = 'jp-Landing-header';
  43. /**
  44. * The class name added to the dialog body.
  45. */
  46. const LANDING_BODY_CLASS = 'jp-Landing-body';
  47. /**
  48. * The class name added to the column of the dialog.
  49. */
  50. const LANDING_COLUMN_CLASS = 'jp-Landing-column';
  51. /**
  52. * The class name added to specify size of activity icons.
  53. */
  54. const LANDING_ICON_CLASS = 'jp-Landing-image';
  55. /**
  56. * The class name added to the image text of an activity.
  57. */
  58. const LANDING_TEXT_CLASS = 'jp-Landing-text';
  59. /**
  60. * The class name added to the current working directory.
  61. */
  62. const LANDING_CWD_CLASS = 'jp-Landing-cwd';
  63. /**
  64. * The class name added to Landing folder node.
  65. */
  66. const FOLDER_CLASS = 'jp-Landing-folder';
  67. /**
  68. * The class name added for the folder icon from default-theme.
  69. */
  70. const FOLDER_ICON_CLASS = 'jp-FolderIcon';
  71. /**
  72. * The class name added to the current working directory path.
  73. */
  74. const LANDING_PATH_CLASS = 'jp-Landing-path';
  75. /**
  76. * The list of preview messages.
  77. */
  78. const previewMessages = [
  79. 'super alpha preview',
  80. 'very alpha preview',
  81. 'extremely alpha preview',
  82. 'exceedingly alpha preview',
  83. 'alpha alpha preview'
  84. ];
  85. /**
  86. * LandingModel keeps track of the path to working directory and has text data,
  87. * which the LandingWidget will render.
  88. */
  89. export
  90. class LandingModel extends VDomModel {
  91. /**
  92. * Preview messages.
  93. */
  94. readonly previewMessage: string;
  95. /**
  96. * The `Start a new activity` text.
  97. */
  98. readonly headerText: string;
  99. /**
  100. * The names of activities and their associated commands.
  101. */
  102. readonly activities: string[][];
  103. /**
  104. * Construct a new landing model.
  105. */
  106. constructor(terminalsAvailable = false) {
  107. super();
  108. this.previewMessage = previewMessages[
  109. Math.floor(Math.random() * previewMessages.length)
  110. ];
  111. this.headerText = 'Start a new activity';
  112. this.activities =
  113. [['Notebook', 'file-operations:new-notebook'],
  114. ['Code Console', 'console:create'],
  115. ['Text Editor', 'file-operations:new-text-file']];
  116. if (terminalsAvailable) {
  117. this.activities.push(
  118. ['Terminal', 'terminal:create-new']
  119. );
  120. }
  121. this._path = 'home';
  122. }
  123. /**
  124. * Get the path of the current working directory.
  125. */
  126. get path(): string {
  127. return this._path;
  128. }
  129. /**
  130. * Set the path of the current working directory.
  131. */
  132. set path(value: string) {
  133. this._path = value;
  134. this.stateChanged.emit(void 0);
  135. }
  136. private _path: string;
  137. }
  138. /**
  139. * A virtual-DOM-based widget for the Landing plugin.
  140. */
  141. export
  142. class LandingWidget extends VDomWidget<LandingModel> {
  143. /**
  144. * Construct a new landing widget.
  145. */
  146. constructor(app: JupyterLab) {
  147. super();
  148. this._app = app;
  149. }
  150. /**
  151. * Handle `'activate-request'` messages.
  152. */
  153. protected onActivateRequest(msg: Message): void {
  154. this.node.tabIndex = -1;
  155. this.node.focus();
  156. }
  157. /**
  158. * Handle `'close-request'` messages.
  159. */
  160. protected onCloseRequest(msg: Message): void {
  161. super.onCloseRequest(msg);
  162. this.dispose();
  163. }
  164. /**
  165. * Render the landing plugin to virtual DOM nodes.
  166. */
  167. protected render(): VirtualNode {
  168. let activitiesList: VirtualNode[] = [];
  169. let activites = this.model.activities;
  170. for (let activityName of activites) {
  171. let imgName = activityName[0].replace(' ', '');
  172. let column =
  173. h.div({className: LANDING_COLUMN_CLASS},
  174. h.span({className: LANDING_ICON_CLASS + ` jp-Image${imgName}` ,
  175. onclick: () => {
  176. this._app.commands.execute(activityName[1], void 0);
  177. }}
  178. ),
  179. h.span({className: LANDING_TEXT_CLASS}, activityName[0])
  180. );
  181. activitiesList.push(column);
  182. }
  183. let logo = h.span({className: JUPYTERLAB_ICON_CLASS + ' ' + LANDING_LOGO_CLASS});
  184. let subtitle =
  185. h.span({className: LANDING_SUBTITLE_CLASS},
  186. this.model.previewMessage
  187. );
  188. let tour =
  189. h.span({className: TOUR_ICON_CLASS,
  190. onclick: () => {
  191. this._app.commands.execute('about-jupyterlab:open', void 0);
  192. }}
  193. );
  194. let header = h.span({
  195. className: LANDING_HEADER_CLASS
  196. }, this.model.headerText);
  197. let body = h.div({className: LANDING_BODY_CLASS}, activitiesList);
  198. let dialog = h.div({className: LANDING_DIALOG_CLASS},
  199. logo,
  200. subtitle,
  201. tour,
  202. header,
  203. body,
  204. h.div({className: LANDING_CWD_CLASS},
  205. h.span({className: FOLDER_ICON_CLASS + ' ' + FOLDER_CLASS}),
  206. h.span({className: LANDING_PATH_CLASS}, this.model.path
  207. )
  208. )
  209. );
  210. return h.div({ className: LANDING_WRAPPER_CLASS }, dialog);
  211. }
  212. private _app: JupyterLab;
  213. }