├── .gitignore ├── README.md ├── package.json ├── src └── index.ts ├── style └── index.css └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Distribution / packaging 2 | *.bundle.* 3 | lib/ 4 | node_modules/ 5 | *.egg-info/ 6 | yarn.lock 7 | tsconfig.tsbuildinfo 8 | package-lock.json 9 | 10 | # Jupyter Notebook Checkpoints 11 | .ipynb_checkpoints 12 | 13 | # PyCharm 14 | .idea/ 15 | *.iml 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **This repository has been archived as it is deprecated.** Please refer to the official [extension tutorial](https://jupyterlab.readthedocs.io/en/latest/extension/extension_tutorial.html). 2 | 3 | # JupyterLab xkcd-extension 4 | 5 | Show a random xkcd.com comic in a JupyterLab panel 6 | 7 | 8 | ## Prerequisites 9 | 10 | * JupyterLab 11 | 12 | ## Installation 13 | 14 | ```bash 15 | jupyter labextension install @jupyterlab/xkcd-extension 16 | ``` 17 | 18 | ## Development 19 | 20 | For a development install (requires npm version 4 or later), do the following in the repository directory: 21 | 22 | ```bash 23 | npm install 24 | npm run build 25 | jupyter labextension link . 26 | ``` 27 | 28 | To rebuild the package and the JupyterLab app: 29 | 30 | ```bash 31 | npm run build 32 | jupyter lab build 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jupyterlab/xkcd-extension", 3 | "version": "0.7.0", 4 | "description": "Show a random xkcd.com comic in a JupyterLab panel", 5 | "keywords": [ 6 | "jupyter", 7 | "jupyterlab", 8 | "jupyterlab-extension" 9 | ], 10 | "homepage": "https://github.com/my_name/jupyterlab_xkcd", 11 | "bugs": { 12 | "url": "https://github.com/my_name/jupyterlab_xkcd/issues" 13 | }, 14 | "license": "BSD-3-Clause", 15 | "author": "Your Name", 16 | "files": [ 17 | "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", 18 | "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}" 19 | ], 20 | "main": "lib/index.js", 21 | "types": "lib/index.d.ts", 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/my_name/jupyterlab_xkcd.git" 25 | }, 26 | "scripts": { 27 | "build": "tsc", 28 | "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo", 29 | "prepare": "npm run clean && npm run build", 30 | "watch": "tsc -w" 31 | }, 32 | "dependencies": { 33 | "@jupyterlab/application": "^1.0.0", 34 | "@jupyterlab/apputils": "^1.0.0", 35 | "@phosphor/coreutils": "^1.3.0", 36 | "@phosphor/messaging": "^1.2.2", 37 | "@phosphor/widgets": "^1.7.0" 38 | }, 39 | "devDependencies": { 40 | "rimraf": "^2.6.3", 41 | "typescript": "~3.5.2" 42 | }, 43 | "jupyterlab": { 44 | "extension": true 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | JupyterFrontEnd, JupyterFrontEndPlugin, ILayoutRestorer 3 | } from '@jupyterlab/application'; 4 | 5 | import { 6 | ICommandPalette, WidgetTracker 7 | } from '@jupyterlab/apputils'; 8 | 9 | import { 10 | JSONExt 11 | } from '@phosphor/coreutils'; 12 | 13 | import { 14 | Message 15 | } from '@phosphor/messaging'; 16 | 17 | import { 18 | Widget 19 | } from '@phosphor/widgets'; 20 | 21 | import '../style/index.css'; 22 | 23 | 24 | /** 25 | * An xckd comic viewer. 26 | */ 27 | class XkcdWidget extends Widget { 28 | /** 29 | * Construct a new xkcd widget. 30 | */ 31 | constructor() { 32 | super(); 33 | 34 | this.id = 'xkcd-jupyterlab'; 35 | this.title.label = 'xkcd.com'; 36 | this.title.closable = true; 37 | this.addClass('jp-xkcdWidget'); 38 | 39 | this.img = document.createElement('img'); 40 | this.img.className = 'jp-xkcdCartoon'; 41 | this.node.appendChild(this.img); 42 | 43 | this.img.insertAdjacentHTML('afterend', 44 | `
45 | 46 | 47 | 48 |
` 49 | ); 50 | } 51 | 52 | /** 53 | * The image element associated with the widget. 54 | */ 55 | readonly img: HTMLImageElement; 56 | 57 | /** 58 | * Handle update requests for the widget. 59 | */ 60 | onUpdateRequest(msg: Message): void { 61 | fetch('https://egszlpbmle.execute-api.us-east-1.amazonaws.com/prod').then(response => { 62 | return response.json(); 63 | }).then(data => { 64 | this.img.src = data.img; 65 | this.img.alt = data.title; 66 | this.img.title = data.alt; 67 | }); 68 | } 69 | }; 70 | 71 | 72 | /** 73 | * Activate the xckd widget extension. 74 | */ 75 | function activate(app: JupyterFrontEnd, palette: ICommandPalette, restorer: ILayoutRestorer) { 76 | console.log('JupyterLab extension jupyterlab_xkcd is activated!'); 77 | 78 | // Declare a widget variable 79 | let widget: XkcdWidget; 80 | 81 | // Add an application command 82 | const command: string = 'xkcd:open'; 83 | app.commands.addCommand(command, { 84 | label: 'Random xkcd comic', 85 | execute: () => { 86 | if (!widget) { 87 | // Create a new widget if one does not exist 88 | widget = new XkcdWidget(); 89 | widget.update(); 90 | } 91 | if (!tracker.has(widget)) { 92 | // Track the state of the widget for later restoration 93 | tracker.add(widget); 94 | } 95 | if (!widget.isAttached) { 96 | // Attach the widget to the main work area if it's not there 97 | app.shell.add(widget, 'main'); 98 | } else { 99 | // Refresh the comic in the widget 100 | widget.update(); 101 | } 102 | // Activate the widget 103 | app.shell.activateById(widget.id); 104 | } 105 | }); 106 | 107 | // Add the command to the palette. 108 | palette.addItem({ command, category: 'Tutorial' }); 109 | 110 | // Track and restore the widget state 111 | let tracker = new WidgetTracker({ namespace: 'xkcd' }); 112 | restorer.restore(tracker, { 113 | command, 114 | args: () => JSONExt.emptyObject, 115 | name: () => 'xkcd' 116 | }); 117 | }; 118 | 119 | 120 | /** 121 | * Initialization data for the jupyterlab_xkcd extension. 122 | */ 123 | const extension: JupyterFrontEndPlugin = { 124 | id: 'jupyterlab_xkcd', 125 | autoStart: true, 126 | requires: [ICommandPalette, ILayoutRestorer], 127 | activate: activate 128 | }; 129 | 130 | export default extension; 131 | -------------------------------------------------------------------------------- /style/index.css: -------------------------------------------------------------------------------- 1 | .jp-xkcdWidget { 2 | display: flex; 3 | flex-direction: column; 4 | overflow: auto; 5 | } 6 | 7 | .jp-xkcdCartoon { 8 | margin: auto; 9 | } 10 | 11 | .jp-xkcdAttribution { 12 | margin: 20px auto; 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "composite": true, 5 | "declaration": true, 6 | "esModuleInterop": true, 7 | "incremental": true, 8 | "jsx": "react", 9 | "module": "esnext", 10 | "moduleResolution": "node", 11 | "noEmitOnError": true, 12 | "noImplicitAny": true, 13 | "noUnusedLocals": true, 14 | "preserveWatchOutput": true, 15 | "resolveJsonModule": true, 16 | "outDir": "lib", 17 | "rootDir": "src", 18 | "strict": true, 19 | "strictNullChecks": false, 20 | "target": "es2017", 21 | "types": [] 22 | }, 23 | "include": ["src/*"] 24 | } 25 | --------------------------------------------------------------------------------