├── .gitignore ├── .vscode └── extensions.json ├── README.md ├── README.zh-CN.md ├── description ├── desc 1.png ├── desc 5.png ├── desc 6.png ├── desc 7.png ├── sample.cut-001.mp4 ├── sample.cut-002.mp4 └── sample.mp4 ├── dist ├── assets │ ├── HomeView.2513caef.js │ ├── fa-brands-400.3fe890d0.woff2 │ ├── fa-brands-400.c7ae37d3.ttf │ ├── fa-regular-400.fdc1f753.ttf │ ├── fa-regular-400.fe69d948.woff2 │ ├── fa-solid-900.6d53c706.ttf │ ├── fa-solid-900.d27bc752.woff2 │ ├── fa-v4compatibility.4d73f280.ttf │ ├── fa-v4compatibility.7d1c2ce5.woff2 │ ├── flUhRq6tzZclQEJ-Vdg-IuiaDsNa.fd84f88b.woff │ ├── flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.83be7b2f.woff2 │ ├── index.4ec3466a.css │ └── index.fec58d44.js ├── favicon.ico ├── icons │ ├── icon-128.png │ ├── icon-256.png │ ├── icon-32.png │ ├── icon-512.png │ └── icon-64.png ├── img-default.png ├── index.html ├── manifest.webmanifest ├── registerSW.js ├── sw.js └── workbox-3ea082d2.js ├── env.d.ts ├── index.html ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── icons │ ├── icon-128.png │ ├── icon-256.png │ ├── icon-32.png │ ├── icon-512.png │ └── icon-64.png └── img-default.png ├── src ├── App.vue ├── assets │ ├── base.scss │ ├── logo.svg │ └── main.scss ├── components │ └── icons │ │ ├── IconCommunity.vue │ │ ├── IconDocumentation.vue │ │ ├── IconEcosystem.vue │ │ ├── IconSupport.vue │ │ └── IconTooling.vue ├── main.ts ├── router │ └── index.ts ├── stores │ └── counter.ts └── views │ └── HomeView.vue ├── tsconfig.config.json ├── tsconfig.json └── vite.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist-ssr 13 | dev-dist 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | .idea 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? 29 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] 3 | } 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mangaview 2 | 3 | #漫画阅读器 #本子阅读器 #同人志阅读器 #条漫阅读器\ 4 | #漫画ビューア #同人誌ビューア #漫画リーダー 5 | 6 | Manga explorer reader viewer, only support image files\ 7 | recommended to use [Chrome](https://www.google.com/chrome/) with the latest version 8 | 9 | ### [中文指南](README.zh-CN.md) 10 | ___ 11 | 12 | * ### latest version v1.0 13 | # [load from here 点击此处加载](https://nohnolife.github.io/mangaview/dist/index.html) 14 | 15 | Drag and drop folders into the app, and enjoy it. 16 | 17 | ___ 18 | 19 | ### press `Ctrl+Shift+R` to [update]() the app, you may need to try several times 20 | The installation button is on the right of the address bar. It can be used normally in **offline** state\ 21 | if you want to uninstall it please open this page [[chrome://apps](chrome://apps)]\ 22 | There will be not have history record if you refresh or reopen app\ 23 | 24 | my [twitter](https://twitter.com/mousoug) 25 | ## sample 26 | 27 | ### [video sample](https://github.com/NOHNOLIFE/mangaview/raw/main/description/sample.mp4) 28 | 29 | https://user-images.githubusercontent.com/16075139/221929788-0f7651a5-4539-47b5-9e17-c2a824b879f5.mp4 30 | 31 | https://user-images.githubusercontent.com/16075139/221929967-c6236734-47be-493a-8470-2c4668ae1f27.mp4 32 | 33 | ![](https://github.com/NOHNOLIFE/mangaview/blob/main/description/desc%201.png) 34 | ![](https://github.com/NOHNOLIFE/mangaview/blob/main/description/desc%205.png) 35 | ![](https://github.com/NOHNOLIFE/mangaview/blob/main/description/desc%206.png) 36 | 37 | ___ 38 | ## manual 39 | ### mouse `click` `drag` 40 | 41 | ### keyboard: 42 | * scroll down: `space`\ `↓` 43 | * page down: `F`\ `→`\ `enter` 44 | * 45 | * scroll up: `shift + space`\ `↑` 46 | * page up: `D`\ `←` 47 | * 48 | * page top: `home` 49 | * page end: `end` 50 | * 51 | * next book: `page-down` 52 | * previous book: `page-up` 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # mangaview 2 | 3 | #漫画阅读器 #本子阅读器 #同人志阅读器 #条漫阅读器 4 | 5 | 适用于PC端的本地的漫画阅读器。无需安装,浏览器直接打开网址即可 6 | 7 | * ### 最新版本 v1.0 8 | # [点击此处加载](https://nohnolife.github.io/mangaview/dist/index.html) 9 | 推荐使用最新版的 [Chrome浏览器](https://www.google.com/chrome/)\ 10 | 网页加载完成后拖拽文件到页面区域内即可 11 | ___ 12 | 我的推特 [twitter](https://twitter.com/mousoug) 13 | 14 | **如安装了离线页面,更新软件时需同时按下 `Ctrl+Shift+R` 来刷新APP, 网络不好的情况下请多试几次** 15 | 16 | 安装离线页面的按钮在浏览器地址栏的右边。\ 17 | 安装好后通过浏览器创建的快捷方式就能在不联网的情况下正常打开和使用。\ 18 | 如果想卸载安装的离线应用请打开该地址—— [chrome://apps](chrome://apps) 19 | 20 | 本阅读器只能用于**即时阅读**,关闭或刷新页面后**所有缓存数据均会被清空**。但不会对硬盘上的原始数进行任何操作,请放心使用。 21 | 22 | ## 示例 23 | 24 | ### [示例视频](https://github.com/NOHNOLIFE/mangaview/raw/main/description/sample.mp4) 25 | 26 | 27 | https://user-images.githubusercontent.com/16075139/221929788-0f7651a5-4539-47b5-9e17-c2a824b879f5.mp4 28 | 29 | https://user-images.githubusercontent.com/16075139/221929967-c6236734-47be-493a-8470-2c4668ae1f27.mp4 30 | 31 | ![](https://github.com/NOHNOLIFE/mangaview/blob/main/description/desc%201.png) 32 | ![](https://github.com/NOHNOLIFE/mangaview/blob/main/description/desc%205.png) 33 | ![](https://github.com/NOHNOLIFE/mangaview/blob/main/description/desc%206.png) 34 | 35 | ___ 36 | ## 页面性能 37 | 以我自己的电脑为例: `ryzen 5800x + 3070Ti + 980pro`\ 38 | 一次性放入300+本漫画首次加载时间小于 3秒,内存消耗增加了1G。\ 39 | 因为使用了延迟加载图片,切换或滚动**过快**的时候出现才加载到一半的图属于正常现象。\ 40 | 如果进入视野范围内的图加载过慢,可能是因为`图片尺寸和体积过大`或`硬盘读取速度过慢`。把要阅读的漫画暂时复制到**SSD**硬盘上再打开是最佳实践。 41 | ___ 42 | ## 操作说明 43 | ### 鼠标: `点击` `拖拽` 44 | 45 | ### 键盘: 46 | * 向后滚动: `space`\ `↓` 47 | * 向后翻页: `F`\ `→`\ `enter` 48 | * 49 | * 向前滚动: `shift + space`\ `↑` 50 | * 向前翻页: `D`\ `←` 51 | * 52 | * 第 一 页: `home` 53 | * 最后一页: `end` 54 | * 55 | * 下一本书: `page-down` 56 | * 上一本书: `page-up` 57 | * 58 | * 自动滚动(解放双手): `按下鼠标滚轮` 59 | ___ 60 | ### [LICENCE](https://github.com/NOHNOLIFE/mangaview/blob/main/LICENSE) 61 | -------------------------------------------------------------------------------- /description/desc 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/description/desc 1.png -------------------------------------------------------------------------------- /description/desc 5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/description/desc 5.png -------------------------------------------------------------------------------- /description/desc 6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/description/desc 6.png -------------------------------------------------------------------------------- /description/desc 7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/description/desc 7.png -------------------------------------------------------------------------------- /description/sample.cut-001.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/description/sample.cut-001.mp4 -------------------------------------------------------------------------------- /description/sample.cut-002.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/description/sample.cut-002.mp4 -------------------------------------------------------------------------------- /description/sample.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/description/sample.mp4 -------------------------------------------------------------------------------- /dist/assets/HomeView.2513caef.js: -------------------------------------------------------------------------------- 1 | import{_ as e,o as c,c as o}from"./index.fec58d44.js";const n={};function r(t,a){return c(),o("main")}const _=e(n,[["render",r]]);export{_ as default}; 2 | -------------------------------------------------------------------------------- /dist/assets/fa-brands-400.3fe890d0.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/assets/fa-brands-400.3fe890d0.woff2 -------------------------------------------------------------------------------- /dist/assets/fa-brands-400.c7ae37d3.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/assets/fa-brands-400.c7ae37d3.ttf -------------------------------------------------------------------------------- /dist/assets/fa-regular-400.fdc1f753.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/assets/fa-regular-400.fdc1f753.ttf -------------------------------------------------------------------------------- /dist/assets/fa-regular-400.fe69d948.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/assets/fa-regular-400.fe69d948.woff2 -------------------------------------------------------------------------------- /dist/assets/fa-solid-900.6d53c706.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/assets/fa-solid-900.6d53c706.ttf -------------------------------------------------------------------------------- /dist/assets/fa-solid-900.d27bc752.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/assets/fa-solid-900.d27bc752.woff2 -------------------------------------------------------------------------------- /dist/assets/fa-v4compatibility.4d73f280.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/assets/fa-v4compatibility.4d73f280.ttf -------------------------------------------------------------------------------- /dist/assets/fa-v4compatibility.7d1c2ce5.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/assets/fa-v4compatibility.7d1c2ce5.woff2 -------------------------------------------------------------------------------- /dist/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.fd84f88b.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.fd84f88b.woff -------------------------------------------------------------------------------- /dist/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.83be7b2f.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.83be7b2f.woff2 -------------------------------------------------------------------------------- /dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/favicon.ico -------------------------------------------------------------------------------- /dist/icons/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/icons/icon-128.png -------------------------------------------------------------------------------- /dist/icons/icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/icons/icon-256.png -------------------------------------------------------------------------------- /dist/icons/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/icons/icon-32.png -------------------------------------------------------------------------------- /dist/icons/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/icons/icon-512.png -------------------------------------------------------------------------------- /dist/icons/icon-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/icons/icon-64.png -------------------------------------------------------------------------------- /dist/img-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/dist/img-default.png -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | MangaView 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /dist/manifest.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"MangaView v1.0","short_name":"MangaView ","start_url":"./index.html","display":"fullscreen","background_color":"#212121","lang":"en","scope":"./","description":"Manga explorer reader Viewer. easy view easy fun","icons":[{"src":"./icons/icon-64.png","sizes":"64x64","type":"image/png"},{"src":"./icons/icon-128.png","sizes":"128x128","type":"image/png"},{"src":"./icons/icon-256.png","sizes":"256x256","type":"image/png"},{"src":"./icons/icon-512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#212121"} 2 | -------------------------------------------------------------------------------- /dist/registerSW.js: -------------------------------------------------------------------------------- 1 | if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('./sw.js', { scope: './' })})} -------------------------------------------------------------------------------- /dist/sw.js: -------------------------------------------------------------------------------- 1 | if(!self.define){let e,i={};const s=(s,n)=>(s=new URL(s+".js",n).href,i[s]||new Promise((i=>{if("document"in self){const e=document.createElement("script");e.src=s,e.onload=i,document.head.appendChild(e)}else e=s,importScripts(s),i()})).then((()=>{let e=i[s];if(!e)throw new Error(`Module ${s} didn’t register its module`);return e})));self.define=(n,r)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(i[o])return;let c={};const l=e=>s(e,o),f={module:{uri:o},exports:c,require:l};i[o]=Promise.all(n.map((e=>f[e]||l(e)))).then((e=>(r(...e),c)))}}define(["./workbox-3ea082d2"],(function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"assets/fa-brands-400.3fe890d0.woff2",revision:null},{url:"assets/fa-brands-400.c7ae37d3.ttf",revision:null},{url:"assets/fa-regular-400.fdc1f753.ttf",revision:null},{url:"assets/fa-regular-400.fe69d948.woff2",revision:null},{url:"assets/fa-solid-900.6d53c706.ttf",revision:null},{url:"assets/fa-solid-900.d27bc752.woff2",revision:null},{url:"assets/fa-v4compatibility.4d73f280.ttf",revision:null},{url:"assets/fa-v4compatibility.7d1c2ce5.woff2",revision:null},{url:"assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.83be7b2f.woff2",revision:null},{url:"assets/HomeView.2513caef.js",revision:null},{url:"assets/index.4ec3466a.css",revision:null},{url:"assets/index.fec58d44.js",revision:null},{url:"favicon.ico",revision:"d01d1b73214cf33ab1e8bedcbb30fb6f"},{url:"icons/icon-128.png",revision:"b5cc31bb2927d2a84c43435ac209d985"},{url:"icons/icon-256.png",revision:"ad183e1bd2f93aae1f77e7c681161078"},{url:"icons/icon-32.png",revision:"d01d1b73214cf33ab1e8bedcbb30fb6f"},{url:"icons/icon-512.png",revision:"6ef763054248aa721d0c96084bfc9e08"},{url:"icons/icon-64.png",revision:"72a63aece340d508abfa7631429babe5"},{url:"img-default.png",revision:"b71b2a9cb2b3175526b82bda38bafe1b"},{url:"index.html",revision:"b0d448f1ecc15f3e1d4ed19e0995774e"},{url:"registerSW.js",revision:"402b66900e731ca748771b6fc5e7a068"},{url:"./icons/icon-64.png",revision:"72a63aece340d508abfa7631429babe5"},{url:"./icons/icon-128.png",revision:"b5cc31bb2927d2a84c43435ac209d985"},{url:"./icons/icon-256.png",revision:"ad183e1bd2f93aae1f77e7c681161078"},{url:"./icons/icon-512.png",revision:"6ef763054248aa721d0c96084bfc9e08"},{url:"manifest.webmanifest",revision:"2192c9f066d82c101551d11bf351d3b7"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))})); 2 | -------------------------------------------------------------------------------- /dist/workbox-3ea082d2.js: -------------------------------------------------------------------------------- 1 | define(["exports"],(function(t){"use strict";try{self["workbox:core:6.5.3"]&&_()}catch(t){}const e=(t,...e)=>{let s=t;return e.length>0&&(s+=` :: ${JSON.stringify(e)}`),s};class s extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}try{self["workbox:routing:6.5.3"]&&_()}catch(t){}const n=t=>t&&"object"==typeof t?t:{handle:t};class i{constructor(t,e,s="GET"){this.handler=n(e),this.match=t,this.method=s}setCatchHandler(t){this.catchHandler=n(t)}}class r extends i{constructor(t,e,s){super((({url:e})=>{const s=t.exec(e.href);if(s&&(e.origin===location.origin||0===s.index))return s.slice(1)}),e,s)}}class o{constructor(){this.t=new Map,this.i=new Map}get routes(){return this.t}addFetchListener(){self.addEventListener("fetch",(t=>{const{request:e}=t,s=this.handleRequest({request:e,event:t});s&&t.respondWith(s)}))}addCacheListener(){self.addEventListener("message",(t=>{if(t.data&&"CACHE_URLS"===t.data.type){const{payload:e}=t.data,s=Promise.all(e.urlsToCache.map((e=>{"string"==typeof e&&(e=[e]);const s=new Request(...e);return this.handleRequest({request:s,event:t})})));t.waitUntil(s),t.ports&&t.ports[0]&&s.then((()=>t.ports[0].postMessage(!0)))}}))}handleRequest({request:t,event:e}){const s=new URL(t.url,location.href);if(!s.protocol.startsWith("http"))return;const n=s.origin===location.origin,{params:i,route:r}=this.findMatchingRoute({event:e,request:t,sameOrigin:n,url:s});let o=r&&r.handler;const c=t.method;if(!o&&this.i.has(c)&&(o=this.i.get(c)),!o)return;let a;try{a=o.handle({url:s,request:t,event:e,params:i})}catch(t){a=Promise.reject(t)}const h=r&&r.catchHandler;return a instanceof Promise&&(this.o||h)&&(a=a.catch((async n=>{if(h)try{return await h.handle({url:s,request:t,event:e,params:i})}catch(t){t instanceof Error&&(n=t)}if(this.o)return this.o.handle({url:s,request:t,event:e});throw n}))),a}findMatchingRoute({url:t,sameOrigin:e,request:s,event:n}){const i=this.t.get(s.method)||[];for(const r of i){let i;const o=r.match({url:t,sameOrigin:e,request:s,event:n});if(o)return i=o,(Array.isArray(i)&&0===i.length||o.constructor===Object&&0===Object.keys(o).length||"boolean"==typeof o)&&(i=void 0),{route:r,params:i}}return{}}setDefaultHandler(t,e="GET"){this.i.set(e,n(t))}setCatchHandler(t){this.o=n(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(t){if(!this.t.has(t.method))throw new s("unregister-route-but-not-found-with-method",{method:t.method});const e=this.t.get(t.method).indexOf(t);if(!(e>-1))throw new s("unregister-route-route-not-registered");this.t.get(t.method).splice(e,1)}}let c;const a=()=>(c||(c=new o,c.addFetchListener(),c.addCacheListener()),c);function h(t,e,n){let o;if("string"==typeof t){const s=new URL(t,location.href);o=new i((({url:t})=>t.href===s.href),e,n)}else if(t instanceof RegExp)o=new r(t,e,n);else if("function"==typeof t)o=new i(t,e,n);else{if(!(t instanceof i))throw new s("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});o=t}return a().registerRoute(o),o}const u={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},l=t=>[u.prefix,t,u.suffix].filter((t=>t&&t.length>0)).join("-"),f=t=>t||l(u.precache),w=t=>t||l(u.runtime);function d(t,e){const s=e();return t.waitUntil(s),s}try{self["workbox:precaching:6.5.3"]&&_()}catch(t){}function p(t){if(!t)throw new s("add-to-cache-list-unexpected-type",{entry:t});if("string"==typeof t){const e=new URL(t,location.href);return{cacheKey:e.href,url:e.href}}const{revision:e,url:n}=t;if(!n)throw new s("add-to-cache-list-unexpected-type",{entry:t});if(!e){const t=new URL(n,location.href);return{cacheKey:t.href,url:t.href}}const i=new URL(n,location.href),r=new URL(n,location.href);return i.searchParams.set("__WB_REVISION__",e),{cacheKey:i.href,url:r.href}}class y{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:t,state:e})=>{e&&(e.originalRequest=t)},this.cachedResponseWillBeUsed=async({event:t,state:e,cachedResponse:s})=>{if("install"===t.type&&e&&e.originalRequest&&e.originalRequest instanceof Request){const t=e.originalRequest.url;s?this.notUpdatedURLs.push(t):this.updatedURLs.push(t)}return s}}}class g{constructor({precacheController:t}){this.cacheKeyWillBeUsed=async({request:t,params:e})=>{const s=(null==e?void 0:e.cacheKey)||this.h.getCacheKeyForURL(t.url);return s?new Request(s,{headers:t.headers}):t},this.h=t}}let R;async function m(t,e){let n=null;if(t.url){n=new URL(t.url).origin}if(n!==self.location.origin)throw new s("cross-origin-copy-response",{origin:n});const i=t.clone(),r={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=e?e(r):r,c=function(){if(void 0===R){const t=new Response("");if("body"in t)try{new Response(t.body),R=!0}catch(t){R=!1}R=!1}return R}()?i.body:await i.blob();return new Response(c,o)}function v(t,e){const s=new URL(t);for(const t of e)s.searchParams.delete(t);return s.href}class q{constructor(){this.promise=new Promise(((t,e)=>{this.resolve=t,this.reject=e}))}}const U=new Set;try{self["workbox:strategies:6.5.3"]&&_()}catch(t){}function L(t){return"string"==typeof t?new Request(t):t}class b{constructor(t,e){this.u={},Object.assign(this,e),this.event=e.event,this.l=t,this.p=new q,this.g=[],this.R=[...t.plugins],this.m=new Map;for(const t of this.R)this.m.set(t,{});this.event.waitUntil(this.p.promise)}async fetch(t){const{event:e}=this;let n=L(t);if("navigate"===n.mode&&e instanceof FetchEvent&&e.preloadResponse){const t=await e.preloadResponse;if(t)return t}const i=this.hasCallback("fetchDidFail")?n.clone():null;try{for(const t of this.iterateCallbacks("requestWillFetch"))n=await t({request:n.clone(),event:e})}catch(t){if(t instanceof Error)throw new s("plugin-error-request-will-fetch",{thrownErrorMessage:t.message})}const r=n.clone();try{let t;t=await fetch(n,"navigate"===n.mode?void 0:this.l.fetchOptions);for(const s of this.iterateCallbacks("fetchDidSucceed"))t=await s({event:e,request:r,response:t});return t}catch(t){throw i&&await this.runCallbacks("fetchDidFail",{error:t,event:e,originalRequest:i.clone(),request:r.clone()}),t}}async fetchAndCachePut(t){const e=await this.fetch(t),s=e.clone();return this.waitUntil(this.cachePut(t,s)),e}async cacheMatch(t){const e=L(t);let s;const{cacheName:n,matchOptions:i}=this.l,r=await this.getCacheKey(e,"read"),o=Object.assign(Object.assign({},i),{cacheName:n});s=await caches.match(r,o);for(const t of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await t({cacheName:n,matchOptions:i,cachedResponse:s,request:r,event:this.event})||void 0;return s}async cachePut(t,e){const n=L(t);var i;await(i=0,new Promise((t=>setTimeout(t,i))));const r=await this.getCacheKey(n,"write");if(!e)throw new s("cache-put-with-no-response",{url:(o=r.url,new URL(String(o),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var o;const c=await this.v(e);if(!c)return!1;const{cacheName:a,matchOptions:h}=this.l,u=await self.caches.open(a),l=this.hasCallback("cacheDidUpdate"),f=l?await async function(t,e,s,n){const i=v(e.url,s);if(e.url===i)return t.match(e,n);const r=Object.assign(Object.assign({},n),{ignoreSearch:!0}),o=await t.keys(e,r);for(const e of o)if(i===v(e.url,s))return t.match(e,n)}(u,r.clone(),["__WB_REVISION__"],h):null;try{await u.put(r,l?c.clone():c)}catch(t){if(t instanceof Error)throw"QuotaExceededError"===t.name&&await async function(){for(const t of U)await t()}(),t}for(const t of this.iterateCallbacks("cacheDidUpdate"))await t({cacheName:a,oldResponse:f,newResponse:c.clone(),request:r,event:this.event});return!0}async getCacheKey(t,e){const s=`${t.url} | ${e}`;if(!this.u[s]){let n=t;for(const t of this.iterateCallbacks("cacheKeyWillBeUsed"))n=L(await t({mode:e,request:n,event:this.event,params:this.params}));this.u[s]=n}return this.u[s]}hasCallback(t){for(const e of this.l.plugins)if(t in e)return!0;return!1}async runCallbacks(t,e){for(const s of this.iterateCallbacks(t))await s(e)}*iterateCallbacks(t){for(const e of this.l.plugins)if("function"==typeof e[t]){const s=this.m.get(e),n=n=>{const i=Object.assign(Object.assign({},n),{state:s});return e[t](i)};yield n}}waitUntil(t){return this.g.push(t),t}async doneWaiting(){let t;for(;t=this.g.shift();)await t}destroy(){this.p.resolve(null)}async v(t){let e=t,s=!1;for(const t of this.iterateCallbacks("cacheWillUpdate"))if(e=await t({request:this.request,response:e,event:this.event})||void 0,s=!0,!e)break;return s||e&&200!==e.status&&(e=void 0),e}}class C extends class{constructor(t={}){this.cacheName=w(t.cacheName),this.plugins=t.plugins||[],this.fetchOptions=t.fetchOptions,this.matchOptions=t.matchOptions}handle(t){const[e]=this.handleAll(t);return e}handleAll(t){t instanceof FetchEvent&&(t={event:t,request:t.request});const e=t.event,s="string"==typeof t.request?new Request(t.request):t.request,n="params"in t?t.params:void 0,i=new b(this,{event:e,request:s,params:n}),r=this.q(i,s,e);return[r,this.U(r,i,s,e)]}async q(t,e,n){let i;await t.runCallbacks("handlerWillStart",{event:n,request:e});try{if(i=await this.L(e,t),!i||"error"===i.type)throw new s("no-response",{url:e.url})}catch(s){if(s instanceof Error)for(const r of t.iterateCallbacks("handlerDidError"))if(i=await r({error:s,event:n,request:e}),i)break;if(!i)throw s}for(const s of t.iterateCallbacks("handlerWillRespond"))i=await s({event:n,request:e,response:i});return i}async U(t,e,s,n){let i,r;try{i=await t}catch(r){}try{await e.runCallbacks("handlerDidRespond",{event:n,request:s,response:i}),await e.doneWaiting()}catch(t){t instanceof Error&&(r=t)}if(await e.runCallbacks("handlerDidComplete",{event:n,request:s,response:i,error:r}),e.destroy(),r)throw r}}{constructor(t={}){t.cacheName=f(t.cacheName),super(t),this._=!1!==t.fallbackToNetwork,this.plugins.push(C.copyRedirectedCacheableResponsesPlugin)}async L(t,e){const s=await e.cacheMatch(t);return s||(e.event&&"install"===e.event.type?await this.C(t,e):await this.O(t,e))}async O(t,e){let n;const i=e.params||{};if(!this._)throw new s("missing-precache-entry",{cacheName:this.cacheName,url:t.url});{const s=i.integrity,r=t.integrity,o=!r||r===s;n=await e.fetch(new Request(t,{integrity:"no-cors"!==t.mode?r||s:void 0})),s&&o&&"no-cors"!==t.mode&&(this.N(),await e.cachePut(t,n.clone()))}return n}async C(t,e){this.N();const n=await e.fetch(t);if(!await e.cachePut(t,n.clone()))throw new s("bad-precaching-response",{url:t.url,status:n.status});return n}N(){let t=null,e=0;for(const[s,n]of this.plugins.entries())n!==C.copyRedirectedCacheableResponsesPlugin&&(n===C.defaultPrecacheCacheabilityPlugin&&(t=s),n.cacheWillUpdate&&e++);0===e?this.plugins.push(C.defaultPrecacheCacheabilityPlugin):e>1&&null!==t&&this.plugins.splice(t,1)}}C.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:t})=>!t||t.status>=400?null:t},C.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:t})=>t.redirected?await m(t):t};class E{constructor({cacheName:t,plugins:e=[],fallbackToNetwork:s=!0}={}){this.k=new Map,this.K=new Map,this.P=new Map,this.l=new C({cacheName:f(t),plugins:[...e,new g({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this.l}precache(t){this.addToCacheList(t),this.T||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this.T=!0)}addToCacheList(t){const e=[];for(const n of t){"string"==typeof n?e.push(n):n&&void 0===n.revision&&e.push(n.url);const{cacheKey:t,url:i}=p(n),r="string"!=typeof n&&n.revision?"reload":"default";if(this.k.has(i)&&this.k.get(i)!==t)throw new s("add-to-cache-list-conflicting-entries",{firstEntry:this.k.get(i),secondEntry:t});if("string"!=typeof n&&n.integrity){if(this.P.has(t)&&this.P.get(t)!==n.integrity)throw new s("add-to-cache-list-conflicting-integrities",{url:i});this.P.set(t,n.integrity)}if(this.k.set(i,t),this.K.set(i,r),e.length>0){const t=`Workbox is precaching URLs without revision info: ${e.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(t)}}}install(t){return d(t,(async()=>{const e=new y;this.strategy.plugins.push(e);for(const[e,s]of this.k){const n=this.P.get(s),i=this.K.get(e),r=new Request(e,{integrity:n,cache:i,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:r,event:t}))}const{updatedURLs:s,notUpdatedURLs:n}=e;return{updatedURLs:s,notUpdatedURLs:n}}))}activate(t){return d(t,(async()=>{const t=await self.caches.open(this.strategy.cacheName),e=await t.keys(),s=new Set(this.k.values()),n=[];for(const i of e)s.has(i.url)||(await t.delete(i),n.push(i.url));return{deletedURLs:n}}))}getURLsToCacheKeys(){return this.k}getCachedURLs(){return[...this.k.keys()]}getCacheKeyForURL(t){const e=new URL(t,location.href);return this.k.get(e.href)}getIntegrityForCacheKey(t){return this.P.get(t)}async matchPrecache(t){const e=t instanceof Request?t.url:t,s=this.getCacheKeyForURL(e);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(t){const e=this.getCacheKeyForURL(t);if(!e)throw new s("non-precached-url",{url:t});return s=>(s.request=new Request(t),s.params=Object.assign({cacheKey:e},s.params),this.strategy.handle(s))}}let O;const x=()=>(O||(O=new E),O);class N extends i{constructor(t,e){super((({request:s})=>{const n=t.getURLsToCacheKeys();for(const i of function*(t,{ignoreURLParametersMatching:e=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:n=!0,urlManipulation:i}={}){const r=new URL(t,location.href);r.hash="",yield r.href;const o=function(t,e=[]){for(const s of[...t.searchParams.keys()])e.some((t=>t.test(s)))&&t.searchParams.delete(s);return t}(r,e);if(yield o.href,s&&o.pathname.endsWith("/")){const t=new URL(o.href);t.pathname+=s,yield t.href}if(n){const t=new URL(o.href);t.pathname+=".html",yield t.href}if(i){const t=i({url:r});for(const e of t)yield e.href}}(s.url,e)){const e=n.get(i);if(e){return{cacheKey:e,integrity:t.getIntegrityForCacheKey(e)}}}}),t.strategy)}}t.NavigationRoute=class extends i{constructor(t,{allowlist:e=[/./],denylist:s=[]}={}){super((t=>this.W(t)),t),this.j=e,this.M=s}W({url:t,request:e}){if(e&&"navigate"!==e.mode)return!1;const s=t.pathname+t.search;for(const t of this.M)if(t.test(s))return!1;return!!this.j.some((t=>t.test(s)))}},t.cleanupOutdatedCaches=function(){self.addEventListener("activate",(t=>{const e=f();t.waitUntil((async(t,e="-precache-")=>{const s=(await self.caches.keys()).filter((s=>s.includes(e)&&s.includes(self.registration.scope)&&s!==t));return await Promise.all(s.map((t=>self.caches.delete(t)))),s})(e).then((t=>{})))}))},t.clientsClaim=function(){self.addEventListener("activate",(()=>self.clients.claim()))},t.createHandlerBoundToURL=function(t){return x().createHandlerBoundToURL(t)},t.precacheAndRoute=function(t,e){!function(t){x().precache(t)}(t),function(t){const e=x();h(new N(e,t))}(e)},t.registerRoute=h})); 2 | -------------------------------------------------------------------------------- /env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | MangaView 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mangaview", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "build": "run-p type-check build-only", 6 | "build-only": "vite build", 7 | "dev": "vite", 8 | "preview": "vite preview --port 4173", 9 | "type-check": "vue-tsc --noEmit" 10 | }, 11 | "dependencies": { 12 | "@quasar/extras": "^1.15.4", 13 | "pinia": "^2.0.21", 14 | "quasar": "^2.8.4", 15 | "register-service-worker": "^1.7.2", 16 | "vue": "^3.2.38", 17 | "vue-router": "^4.1.5", 18 | "vue3-dropzone": "^2.0.1" 19 | }, 20 | "devDependencies": { 21 | "@quasar/vite-plugin": "^1.2.3", 22 | "@types/node": "^16.11.56", 23 | "@vitejs/plugin-vue": "^3.0.3", 24 | "@vitejs/plugin-vue-jsx": "^2.0.1", 25 | "@vue/cli-plugin-pwa": "~5.0.0", 26 | "@vue/tsconfig": "^0.1.3", 27 | "npm-run-all": "^4.1.5", 28 | "sass": "^1.32.12", 29 | "typescript": "~4.7.4", 30 | "vite": "^3.0.9", 31 | "vite-plugin-pwa": "^0.13.1", 32 | "vue-tsc": "^0.40.7" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/public/favicon.ico -------------------------------------------------------------------------------- /public/icons/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/public/icons/icon-128.png -------------------------------------------------------------------------------- /public/icons/icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/public/icons/icon-256.png -------------------------------------------------------------------------------- /public/icons/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/public/icons/icon-32.png -------------------------------------------------------------------------------- /public/icons/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/public/icons/icon-512.png -------------------------------------------------------------------------------- /public/icons/icon-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/public/icons/icon-64.png -------------------------------------------------------------------------------- /public/img-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NOHNOLIFE/mangaview/18ce1314634f58e69cc4399f68856b190033660d/public/img-default.png -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 310 | 311 | 492 | 493 | 674 | -------------------------------------------------------------------------------- /src/assets/base.scss: -------------------------------------------------------------------------------- 1 | html,body{ 2 | padding: 0;margin: 0; 3 | } -------------------------------------------------------------------------------- /src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/main.scss: -------------------------------------------------------------------------------- 1 | @import "./base.scss"; 2 | 3 | body { 4 | //font-size: 110%; 5 | position: absolute; 6 | left: 0; 7 | right: 0; 8 | top: 0; 9 | bottom: 0; 10 | -webkit-touch-callout: none; 11 | -webkit-user-select: none; 12 | -moz-user-select: none; 13 | -ms-user-select: none; 14 | user-select: none; 15 | } 16 | 17 | #app { 18 | position: absolute; 19 | left: 0; 20 | right: 0; 21 | top: 0; 22 | bottom: 0; 23 | } 24 | 25 | .q-menu { 26 | &::-webkit-scrollbar { 27 | width: 20px; 28 | } 29 | } 30 | 31 | #title-btn { 32 | .q-btn__content.text-center > * { 33 | width: 100%; 34 | text-overflow: ellipsis; 35 | overflow: hidden; 36 | } 37 | } 38 | 39 | .q-btn { 40 | text-transform: unset; 41 | } 42 | 43 | .smooth { 44 | //scroll-behavior: smooth; 45 | } 46 | 47 | /*---滚动条默认显示样式--*/ 48 | ::-webkit-scrollbar-thumb { 49 | height: 2rem; 50 | outline-offset: -2px; 51 | /*outline:2px solid #fff;*/ 52 | -webkit-border-radius: 0; 53 | /*border: 2px solid #fff;*/ 54 | } 55 | 56 | /*---鼠标点击滚动条显示样式--*/ 57 | ::-webkit-scrollbar-thumb:hover { 58 | height: 2rem; 59 | -webkit-border-radius: 0; 60 | } 61 | 62 | /*---滚动条大小--*/ 63 | ::-webkit-scrollbar { 64 | width: 1rem; 65 | height: 1rem; 66 | } 67 | 68 | /*---滚动框背景样式--*/ 69 | ::-webkit-scrollbar-track-piece { 70 | -webkit-border-radius: 0; 71 | } 72 | 73 | ::-webkit-scrollbar-track { 74 | background-color: #868686; 75 | } 76 | 77 | /* 滚动条的滑轨背景颜色 */ 78 | ::-webkit-scrollbar-thumb { 79 | background-color: rgba(0, 0, 0, 0.5); 80 | } 81 | 82 | /* 滑块颜色 */ 83 | /*::-webkit-scrollbar-button { background-color: #eee; } !* 滑轨两头的监听按钮颜色 *!*/ 84 | ::-webkit-scrollbar-corner { 85 | background-color: rgba(0, 0, 0, 0.1); 86 | } 87 | 88 | /* 横向滚动条和纵向滚动条相交处尖角的颜色 */ 89 | 90 | ::-webkit-scrollbar-thumb:hover { 91 | background-color: rgba(0, 0, 0, 0.7); 92 | } -------------------------------------------------------------------------------- /src/components/icons/IconCommunity.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/components/icons/IconDocumentation.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/components/icons/IconEcosystem.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/components/icons/IconSupport.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/components/icons/IconTooling.vue: -------------------------------------------------------------------------------- 1 | 2 | 20 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import { createPinia } from 'pinia' 3 | import {Quasar,AppFullscreen} from 'quasar' 4 | 5 | 6 | import App from './App.vue' 7 | import router from './router' 8 | 9 | // Import icon libraries 10 | import '@quasar/extras/material-icons/material-icons.css' 11 | import '@quasar/extras/fontawesome-v6/fontawesome-v6.css' 12 | // A few examples for animations from Animate.css: 13 | import "@quasar/extras/animate/fadeIn.css" 14 | import "@quasar/extras/animate/fadeOut.css" 15 | // Import Quasar css 16 | import 'quasar/src/css/index.sass' 17 | import './assets/main.scss' 18 | 19 | const app = createApp(App) 20 | 21 | app.use(createPinia()) 22 | app.use(router) 23 | app.use(Quasar, { 24 | plugins: {AppFullscreen}, // import Quasar plugins and add here 25 | config: {notify: { /* look at QuasarConfOptions from the API card */} 26 | }, 27 | }) 28 | 29 | app.mount('#app') 30 | -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from 'vue-router' 2 | 3 | const router = createRouter({ 4 | history: createWebHistory(import.meta.env.BASE_URL), 5 | routes: [ 6 | { 7 | path: '/', 8 | name: 'home', 9 | component: () => import('../views/HomeView.vue') 10 | }, 11 | ] 12 | }) 13 | 14 | export default router 15 | -------------------------------------------------------------------------------- /src/stores/counter.ts: -------------------------------------------------------------------------------- 1 | import { ref, computed } from 'vue' 2 | import { defineStore } from 'pinia' 3 | 4 | export const useCounterStore = defineStore('counter', () => { 5 | const count = ref(0) 6 | const doubleCount = computed(() => count.value * 2) 7 | function increment() { 8 | count.value++ 9 | } 10 | 11 | return { count, doubleCount, increment } 12 | }) 13 | -------------------------------------------------------------------------------- /src/views/HomeView.vue: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | -------------------------------------------------------------------------------- /tsconfig.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.node.json", 3 | "include": ["vite.config.*", "vitest.config.*", "cypress.config.*"], 4 | "compilerOptions": { 5 | "composite": true, 6 | "types": ["node"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.web.json", 3 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "paths": { 7 | "@/*": ["./src/*"] 8 | } 9 | }, 10 | 11 | "references": [ 12 | { 13 | "path": "./tsconfig.config.json" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import {fileURLToPath, URL} from 'node:url' 2 | 3 | import {defineConfig} from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | import vueJsx from '@vitejs/plugin-vue-jsx' 6 | import {quasar, transformAssetUrls} from '@quasar/vite-plugin' 7 | import {VitePWA} from "vite-plugin-pwa"; 8 | 9 | let showSourceMap = process.env.NODE_ENV === 'development'; 10 | let version='v1.0'; 11 | 12 | export default defineConfig({ 13 | base:'./', 14 | plugins: [vue({ 15 | template: {transformAssetUrls}, 16 | }), 17 | vueJsx(), 18 | quasar({}), 19 | VitePWA({ 20 | registerType: 'autoUpdate', 21 | workbox: { 22 | globPatterns: ['**/*.{js,css,html,ttf,woff2,ico,png,jpg}'], 23 | }, 24 | devOptions: { 25 | enabled: true 26 | }, 27 | manifest: { 28 | "name": "MangaView "+version, 29 | "short_name": "MangaView ", 30 | "description": "Manga explorer reader Viewer. easy view easy fun", 31 | "icons": [ 32 | { 33 | "src": "./icons/icon-64.png", 34 | "sizes": "64x64", 35 | "type": "image/png" 36 | }, 37 | { 38 | "src": "./icons/icon-128.png", 39 | "sizes": "128x128", 40 | "type": "image/png" 41 | }, 42 | { 43 | "src": "./icons/icon-256.png", 44 | "sizes": "256x256", 45 | "type": "image/png" 46 | }, 47 | { 48 | "src": "./icons/icon-512.png", 49 | "sizes": "512x512", 50 | "type": "image/png" 51 | } 52 | ], 53 | "start_url": "./index.html", 54 | "display": "fullscreen", 55 | "theme_color": "#212121", 56 | "background_color": "#212121" 57 | }, 58 | }) 59 | ], 60 | resolve: { 61 | alias: { 62 | '@': fileURLToPath(new URL('./src', import.meta.url)) 63 | } 64 | }, 65 | build: {sourcemap: showSourceMap}, 66 | css: {devSourcemap: showSourceMap} 67 | }) 68 | --------------------------------------------------------------------------------