├── .browserslistrc ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── babel.config.js ├── dist ├── demo.html ├── vue-read-progress.common.js ├── vue-read-progress.common.js.map ├── vue-read-progress.umd.js ├── vue-read-progress.umd.js.map ├── vue-read-progress.umd.min.js └── vue-read-progress.umd.min.js.map ├── docs ├── favicon.ico ├── img │ └── logo.82b9c7a5.png ├── index.html └── js │ ├── app.21d1ab16.js │ ├── app.21d1ab16.js.map │ ├── chunk-vendors.31b5842a.js │ └── chunk-vendors.31b5842a.js.map ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ └── logo.png ├── components │ ├── VueReadProgress.vue │ └── index.js └── main.js └── vue.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | extends: ["plugin:vue/essential", "@vue/prettier"], 7 | rules: { 8 | "no-console": process.env.NODE_ENV === "production" ? "error" : "off", 9 | "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off" 10 | }, 11 | parserOptions: { 12 | parser: "babel-eslint" 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | 4 | # local env files 5 | .env.local 6 | .env.*.local 7 | 8 | # Log files 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | # Editor directories and files 14 | .idea 15 | .vscode 16 | *.suo 17 | *.ntvs* 18 | *.njsproj 19 | *.sln 20 | *.sw* 21 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Alberto Jerez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-read-progress 2 | Vue.js plugin for scroll position with a progress bar indicator 3 | 4 | [![NPM version](https://badgen.net/npm/v/vue-read-progress?color=blue)](https://npmjs.com/package/vue-read-progress) [![NPM downloads](https://badgen.net/npm/dm/vue-read-progress?color=blue)](https://npmjs.com/package/vue-read-progress) [![Size](https://img.shields.io/bundlephobia/minzip/vue-read-progress.svg)](https://bundlephobia.com/result?p=vue-read-progress) [![twitter](https://img.shields.io/static/v1.svg?label=twitter&message=follow&color=blue)](https://twitter.com/alberto_jrz) [![donate](https://badgen.net/badge/support%20me/donate/?color=blue)](https://ko-fi.com/ajerez) 5 | 6 | ## Demo 7 | 8 | https://ajerez.github.io/vue-read-progress/ 9 | 10 | 11 | ## Installation 12 | 13 | #### With npm (Recommended) 14 | ```bash 15 | npm i vue-read-progress 16 | ``` 17 | 18 | #### yarn 19 | ```bash 20 | yarn add vue-read-progress 21 | ``` 22 | 23 | ## Usage 24 | 25 | #### Default style 26 | 27 | ```vue 28 | 32 | 33 | 42 | ``` 43 | 44 | #### Customizing the Look and Feel 45 | 46 | ```vue 47 | 51 | 52 | 61 | ``` 62 | 63 | #### Gridsome (SSR) (https://gridsome.org/) 64 | 65 | ```vue 66 | 72 | 73 | 83 | ``` 84 | 85 | ## Available Options (All optional) 86 | 87 | | Property | Type | Default value | Prop Description | 88 | |----------|--------|---------------|-----------------------------------| 89 | | height | String | 4px | Height of progress bar (optional) | 90 | | color | String | #506888 | Color of progress bar (optional) | 91 | | opacity | [String, Number] | 1 | Set opacity values from 0 to 1 (optional) | 92 | | shadow | Boolean | false | Enable box-shadow for the progress bar (optional) | 93 | 94 | ## License 95 | 96 | This project is licensed under the terms of the MIT license 97 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ["@vue/app", { useBuiltIns: false }] 4 | ] 5 | }; 6 | -------------------------------------------------------------------------------- /dist/demo.html: -------------------------------------------------------------------------------- 1 | 2 | vue-read-progress demo 3 | 4 | 5 | 6 | 9 | -------------------------------------------------------------------------------- /dist/vue-read-progress.common.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (function(modules) { // webpackBootstrap 3 | /******/ // The module cache 4 | /******/ var installedModules = {}; 5 | /******/ 6 | /******/ // The require function 7 | /******/ function __webpack_require__(moduleId) { 8 | /******/ 9 | /******/ // Check if module is in cache 10 | /******/ if(installedModules[moduleId]) { 11 | /******/ return installedModules[moduleId].exports; 12 | /******/ } 13 | /******/ // Create a new module (and put it into the cache) 14 | /******/ var module = installedModules[moduleId] = { 15 | /******/ i: moduleId, 16 | /******/ l: false, 17 | /******/ exports: {} 18 | /******/ }; 19 | /******/ 20 | /******/ // Execute the module function 21 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 22 | /******/ 23 | /******/ // Flag the module as loaded 24 | /******/ module.l = true; 25 | /******/ 26 | /******/ // Return the exports of the module 27 | /******/ return module.exports; 28 | /******/ } 29 | /******/ 30 | /******/ 31 | /******/ // expose the modules object (__webpack_modules__) 32 | /******/ __webpack_require__.m = modules; 33 | /******/ 34 | /******/ // expose the module cache 35 | /******/ __webpack_require__.c = installedModules; 36 | /******/ 37 | /******/ // define getter function for harmony exports 38 | /******/ __webpack_require__.d = function(exports, name, getter) { 39 | /******/ if(!__webpack_require__.o(exports, name)) { 40 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 41 | /******/ } 42 | /******/ }; 43 | /******/ 44 | /******/ // define __esModule on exports 45 | /******/ __webpack_require__.r = function(exports) { 46 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 47 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 48 | /******/ } 49 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 50 | /******/ }; 51 | /******/ 52 | /******/ // create a fake namespace object 53 | /******/ // mode & 1: value is a module id, require it 54 | /******/ // mode & 2: merge all properties of value into the ns 55 | /******/ // mode & 4: return value when already ns object 56 | /******/ // mode & 8|1: behave like require 57 | /******/ __webpack_require__.t = function(value, mode) { 58 | /******/ if(mode & 1) value = __webpack_require__(value); 59 | /******/ if(mode & 8) return value; 60 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 61 | /******/ var ns = Object.create(null); 62 | /******/ __webpack_require__.r(ns); 63 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 64 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 65 | /******/ return ns; 66 | /******/ }; 67 | /******/ 68 | /******/ // getDefaultExport function for compatibility with non-harmony modules 69 | /******/ __webpack_require__.n = function(module) { 70 | /******/ var getter = module && module.__esModule ? 71 | /******/ function getDefault() { return module['default']; } : 72 | /******/ function getModuleExports() { return module; }; 73 | /******/ __webpack_require__.d(getter, 'a', getter); 74 | /******/ return getter; 75 | /******/ }; 76 | /******/ 77 | /******/ // Object.prototype.hasOwnProperty.call 78 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 79 | /******/ 80 | /******/ // __webpack_public_path__ 81 | /******/ __webpack_require__.p = ""; 82 | /******/ 83 | /******/ 84 | /******/ // Load entry module and return exports 85 | /******/ return __webpack_require__(__webpack_require__.s = "fb15"); 86 | /******/ }) 87 | /************************************************************************/ 88 | /******/ ({ 89 | 90 | /***/ "0677": 91 | /***/ (function(module, exports, __webpack_require__) { 92 | 93 | exports = module.exports = __webpack_require__("2350")(false); 94 | // imports 95 | 96 | 97 | // module 98 | exports.push([module.i, ".read-progress-container[data-v-7768ef9e]{width:100%;background-color:transparent;position:fixed;display:block;z-index:9999;top:0;left:0}.read-progress-container .read-progress-bar[data-v-7768ef9e]{display:block;width:0;height:inherit}.read-progress-container .read-progress-bar.with-shadow[data-v-7768ef9e]{-webkit-box-shadow:0 0 4px 0 rgba(0,0,0,.3);box-shadow:0 0 4px 0 rgba(0,0,0,.3)}", ""]); 99 | 100 | // exports 101 | 102 | 103 | /***/ }), 104 | 105 | /***/ "2350": 106 | /***/ (function(module, exports) { 107 | 108 | /* 109 | MIT License http://www.opensource.org/licenses/mit-license.php 110 | Author Tobias Koppers @sokra 111 | */ 112 | // css base code, injected by the css-loader 113 | module.exports = function(useSourceMap) { 114 | var list = []; 115 | 116 | // return the list of modules as css string 117 | list.toString = function toString() { 118 | return this.map(function (item) { 119 | var content = cssWithMappingToString(item, useSourceMap); 120 | if(item[2]) { 121 | return "@media " + item[2] + "{" + content + "}"; 122 | } else { 123 | return content; 124 | } 125 | }).join(""); 126 | }; 127 | 128 | // import a list of modules into the list 129 | list.i = function(modules, mediaQuery) { 130 | if(typeof modules === "string") 131 | modules = [[null, modules, ""]]; 132 | var alreadyImportedModules = {}; 133 | for(var i = 0; i < this.length; i++) { 134 | var id = this[i][0]; 135 | if(typeof id === "number") 136 | alreadyImportedModules[id] = true; 137 | } 138 | for(i = 0; i < modules.length; i++) { 139 | var item = modules[i]; 140 | // skip already imported module 141 | // this implementation is not 100% perfect for weird media query combinations 142 | // when a module is imported multiple times with different media queries. 143 | // I hope this will never occur (Hey this way we have smaller bundles) 144 | if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) { 145 | if(mediaQuery && !item[2]) { 146 | item[2] = mediaQuery; 147 | } else if(mediaQuery) { 148 | item[2] = "(" + item[2] + ") and (" + mediaQuery + ")"; 149 | } 150 | list.push(item); 151 | } 152 | } 153 | }; 154 | return list; 155 | }; 156 | 157 | function cssWithMappingToString(item, useSourceMap) { 158 | var content = item[1] || ''; 159 | var cssMapping = item[3]; 160 | if (!cssMapping) { 161 | return content; 162 | } 163 | 164 | if (useSourceMap && typeof btoa === 'function') { 165 | var sourceMapping = toComment(cssMapping); 166 | var sourceURLs = cssMapping.sources.map(function (source) { 167 | return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */' 168 | }); 169 | 170 | return [content].concat(sourceURLs).concat([sourceMapping]).join('\n'); 171 | } 172 | 173 | return [content].join('\n'); 174 | } 175 | 176 | // Adapted from convert-source-map (MIT) 177 | function toComment(sourceMap) { 178 | // eslint-disable-next-line no-undef 179 | var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); 180 | var data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64; 181 | 182 | return '/*# ' + data + ' */'; 183 | } 184 | 185 | 186 | /***/ }), 187 | 188 | /***/ "47fe": 189 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 190 | 191 | "use strict"; 192 | /* harmony import */ var _node_modules_vue_style_loader_index_js_ref_10_oneOf_1_0_node_modules_css_loader_index_js_ref_10_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_10_oneOf_1_2_node_modules_postcss_loader_src_index_js_ref_10_oneOf_1_3_node_modules_less_loader_dist_cjs_js_ref_10_oneOf_1_4_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_VueReadProgress_vue_vue_type_style_index_0_id_7768ef9e_scoped_true_lang_less___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("c566"); 193 | /* harmony import */ var _node_modules_vue_style_loader_index_js_ref_10_oneOf_1_0_node_modules_css_loader_index_js_ref_10_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_10_oneOf_1_2_node_modules_postcss_loader_src_index_js_ref_10_oneOf_1_3_node_modules_less_loader_dist_cjs_js_ref_10_oneOf_1_4_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_VueReadProgress_vue_vue_type_style_index_0_id_7768ef9e_scoped_true_lang_less___WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_vue_style_loader_index_js_ref_10_oneOf_1_0_node_modules_css_loader_index_js_ref_10_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_10_oneOf_1_2_node_modules_postcss_loader_src_index_js_ref_10_oneOf_1_3_node_modules_less_loader_dist_cjs_js_ref_10_oneOf_1_4_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_VueReadProgress_vue_vue_type_style_index_0_id_7768ef9e_scoped_true_lang_less___WEBPACK_IMPORTED_MODULE_0__); 194 | /* unused harmony reexport * */ 195 | /* unused harmony default export */ var _unused_webpack_default_export = (_node_modules_vue_style_loader_index_js_ref_10_oneOf_1_0_node_modules_css_loader_index_js_ref_10_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_10_oneOf_1_2_node_modules_postcss_loader_src_index_js_ref_10_oneOf_1_3_node_modules_less_loader_dist_cjs_js_ref_10_oneOf_1_4_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_VueReadProgress_vue_vue_type_style_index_0_id_7768ef9e_scoped_true_lang_less___WEBPACK_IMPORTED_MODULE_0___default.a); 196 | 197 | /***/ }), 198 | 199 | /***/ "499e": 200 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 201 | 202 | "use strict"; 203 | __webpack_require__.r(__webpack_exports__); 204 | 205 | // CONCATENATED MODULE: ./node_modules/vue-style-loader/lib/listToStyles.js 206 | /** 207 | * Translates the list format produced by css-loader into something 208 | * easier to manipulate. 209 | */ 210 | function listToStyles (parentId, list) { 211 | var styles = [] 212 | var newStyles = {} 213 | for (var i = 0; i < list.length; i++) { 214 | var item = list[i] 215 | var id = item[0] 216 | var css = item[1] 217 | var media = item[2] 218 | var sourceMap = item[3] 219 | var part = { 220 | id: parentId + ':' + i, 221 | css: css, 222 | media: media, 223 | sourceMap: sourceMap 224 | } 225 | if (!newStyles[id]) { 226 | styles.push(newStyles[id] = { id: id, parts: [part] }) 227 | } else { 228 | newStyles[id].parts.push(part) 229 | } 230 | } 231 | return styles 232 | } 233 | 234 | // CONCATENATED MODULE: ./node_modules/vue-style-loader/lib/addStylesClient.js 235 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return addStylesClient; }); 236 | /* 237 | MIT License http://www.opensource.org/licenses/mit-license.php 238 | Author Tobias Koppers @sokra 239 | Modified by Evan You @yyx990803 240 | */ 241 | 242 | 243 | 244 | var hasDocument = typeof document !== 'undefined' 245 | 246 | if (typeof DEBUG !== 'undefined' && DEBUG) { 247 | if (!hasDocument) { 248 | throw new Error( 249 | 'vue-style-loader cannot be used in a non-browser environment. ' + 250 | "Use { target: 'node' } in your Webpack config to indicate a server-rendering environment." 251 | ) } 252 | } 253 | 254 | /* 255 | type StyleObject = { 256 | id: number; 257 | parts: Array 258 | } 259 | 260 | type StyleObjectPart = { 261 | css: string; 262 | media: string; 263 | sourceMap: ?string 264 | } 265 | */ 266 | 267 | var stylesInDom = {/* 268 | [id: number]: { 269 | id: number, 270 | refs: number, 271 | parts: Array<(obj?: StyleObjectPart) => void> 272 | } 273 | */} 274 | 275 | var head = hasDocument && (document.head || document.getElementsByTagName('head')[0]) 276 | var singletonElement = null 277 | var singletonCounter = 0 278 | var isProduction = false 279 | var noop = function () {} 280 | var options = null 281 | var ssrIdKey = 'data-vue-ssr-id' 282 | 283 | // Force single-tag solution on IE6-9, which has a hard limit on the # of \n","// style-loader: Adds some css to the DOM by adding a \n","// style-loader: Adds some css to the DOM by adding a \n","// style-loader: Adds some css to the DOM by adding a 153 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajerez/vue-read-progress/4c75f2450044b5177540a30b2697ad9fcbcff659/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/VueReadProgress.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 63 | 64 | 84 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | import VueReadProgress from "@/components/VueReadProgress"; 2 | 3 | const install = function(Vue) { 4 | Vue.component(VueReadProgress.name, VueReadProgress); 5 | }; 6 | 7 | if (typeof window !== "undefined" && window.Vue) { 8 | window.VueReadProgress = VueReadProgress; 9 | window.Vue.use(VueReadProgress); 10 | } 11 | 12 | VueReadProgress.install = install; 13 | 14 | export default VueReadProgress; 15 | export { VueReadProgress }; 16 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | 4 | Vue.config.productionTip = false; 5 | 6 | new Vue({ 7 | render: h => h(App) 8 | }).$mount("#app"); 9 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | css: { 3 | extract: false 4 | }, 5 | publicPath: process.env.NODE_ENV === "production" ? "/vue-read-progress/" : "/" 6 | }; 7 | --------------------------------------------------------------------------------