├── .gitignore ├── .github └── FUNDING.yml ├── webpack.config.js ├── package.json ├── LICENSE ├── README.md └── src ├── index.js └── nprogress.css /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [snehilvj] 4 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | entry: "./src/index.js", 5 | output: { 6 | filename: "dash.nprogress.js", 7 | path: path.resolve(__dirname, "dist"), 8 | }, 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.css$/i, 13 | use: ["style-loader", "css-loader"], 14 | }, 15 | ], 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dash.nprogress", 3 | "version": "0.1.2", 4 | "description": "Loading indication in dash apps using nprogress.js library", 5 | "scripts": { 6 | "build": "webpack" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/snehilvj/dash-nprogress.git" 11 | }, 12 | "keywords": [ 13 | "dash", 14 | "plotly-dash", 15 | "plotly", 16 | "nprogress" 17 | ], 18 | "author": "Snehil Vijay ", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/snehilvj/dash-nprogress/issues" 22 | }, 23 | "homepage": "https://github.com/snehilvj/dash-nprogress#readme", 24 | "dependencies": { 25 | "nprogress": "^0.2.0" 26 | }, 27 | "devDependencies": { 28 | "css-loader": "^6.7.1", 29 | "style-loader": "^3.3.1", 30 | "webpack": "^5.74.0", 31 | "webpack-cli": "^4.10.0" 32 | }, 33 | "files": [ 34 | "LICENSE", 35 | "README.md", 36 | "dist/dash.nprogress.js" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Snehil Vijay 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Dash NProgress 2 | ========= 3 | 4 | A very simple port of [nprogress.js](https://github.com/rstacruz/nprogress) library for the Plotly Dash ecosystem. 5 | It adds a slim progress bar and a spinner to indicate loading state in a dash app based on the number of pending callbacks. The color of the progress bar changes if any callback fails. 6 | 7 | https://user-images.githubusercontent.com/91216500/194695704-d4459de3-7084-4285-9c37-738737e08fd9.mov 8 | 9 | Basic Usage 10 | ------------ 11 | 12 | Just include the js library in your dash app and you are good to go. 13 | 14 | ```python 15 | from dash import Dash 16 | 17 | external_scripts = ["https://unpkg.com/dash.nprogress@latest/dist/dash.nprogress.js"] 18 | 19 | app = Dash(__name__, external_scripts=external_scripts) 20 | ``` 21 | 22 | Customization 23 | ------------ 24 | 25 | You can customize the color of normal and with-error progress bar by adding a css file in your dash app with following contents: 26 | 27 | ```css 28 | :root { 29 | --nprogress-color-good: green; 30 | --nprogress-color-bad: #ff00ff 31 | } 32 | ``` 33 | 34 | TODO 35 | ------------ 36 | 37 | * Make it work smoothly with long callbacks. 38 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import "./nprogress.css"; 2 | import NProgress from "nprogress"; 3 | 4 | (function () { 5 | const getColor = (type) => { 6 | return window 7 | .getComputedStyle(document.body) 8 | .getPropertyValue(`--nprogress-color-${type}`); 9 | }; 10 | 11 | const changeColor = (color) => { 12 | const root = document.querySelector(":root"); 13 | root.style.setProperty("--nprogress-color", color); 14 | }; 15 | 16 | const GOOD_COLOR = getColor("good") || "#51CF66"; 17 | const BAD_COLOR = getColor("bad") || "#FF6B6B"; 18 | 19 | changeColor(GOOD_COLOR); 20 | 21 | NProgress.configure({ easing: "ease", speed: 500 }); 22 | 23 | window.intercept = 0; 24 | 25 | const increment = () => { 26 | if (window.intercept === 0) { 27 | changeColor(GOOD_COLOR); 28 | NProgress.start(); 29 | } else { 30 | NProgress.inc(0.05); 31 | } 32 | window.intercept++; 33 | }; 34 | 35 | const decrement = () => { 36 | window.intercept--; 37 | if (window.intercept === 0) { 38 | NProgress.done(); 39 | } 40 | }; 41 | 42 | const { fetch: originalFetch } = window; 43 | 44 | window.fetch = async (...args) => { 45 | let [resource, config] = args; 46 | // request interceptor here 47 | increment(); 48 | const response = await originalFetch(resource, config); 49 | // request interceptor here 50 | if (response.status >= 400) { 51 | changeColor(BAD_COLOR); 52 | } 53 | decrement(); 54 | return response; 55 | }; 56 | })(); 57 | -------------------------------------------------------------------------------- /src/nprogress.css: -------------------------------------------------------------------------------- 1 | /* Make clicks pass-through */ 2 | #nprogress { 3 | pointer-events: none; 4 | } 5 | 6 | #nprogress .bar { 7 | background: var(--nprogress-color); 8 | 9 | position: fixed; 10 | z-index: 1031; 11 | top: 0; 12 | left: 0; 13 | 14 | width: 100%; 15 | height: 2px; 16 | } 17 | 18 | /* Fancy blur effect */ 19 | #nprogress .peg { 20 | display: block; 21 | position: absolute; 22 | right: 0px; 23 | width: 100px; 24 | height: 100%; 25 | box-shadow: 0 0 10px var(--nprogress-color), 0 0 5px var(--nprogress-color); 26 | opacity: 1.0; 27 | 28 | -webkit-transform: rotate(3deg) translate(0px, -4px); 29 | -ms-transform: rotate(3deg) translate(0px, -4px); 30 | transform: rotate(3deg) translate(0px, -4px); 31 | } 32 | 33 | /* Remove these to get rid of the spinner */ 34 | #nprogress .spinner { 35 | display: block; 36 | position: fixed; 37 | z-index: 1031; 38 | top: 15px; 39 | right: 15px; 40 | } 41 | 42 | #nprogress .spinner-icon { 43 | width: 18px; 44 | height: 18px; 45 | box-sizing: border-box; 46 | 47 | border: solid 2px transparent; 48 | border-top-color: var(--nprogress-color); 49 | border-left-color: var(--nprogress-color); 50 | border-radius: 50%; 51 | 52 | -webkit-animation: nprogress-spinner 400ms linear infinite; 53 | animation: nprogress-spinner 400ms linear infinite; 54 | } 55 | 56 | .nprogress-custom-parent { 57 | overflow: hidden; 58 | position: relative; 59 | } 60 | 61 | .nprogress-custom-parent #nprogress .spinner, 62 | .nprogress-custom-parent #nprogress .bar { 63 | position: absolute; 64 | } 65 | 66 | @-webkit-keyframes nprogress-spinner { 67 | 0% { -webkit-transform: rotate(0deg); } 68 | 100% { -webkit-transform: rotate(360deg); } 69 | } 70 | @keyframes nprogress-spinner { 71 | 0% { transform: rotate(0deg); } 72 | 100% { transform: rotate(360deg); } 73 | } 74 | 75 | --------------------------------------------------------------------------------